html2pdf4doc 0.0.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ # HTML2PDF4Doc JS file.
2
+ # html2pdf4doc/html2pdf4doc_js/
3
+
4
+ .idea/
5
+ **/.wdm/
6
+ build/
7
+ dist/
8
+ tests/integration/.lit_test_times.txt
9
+ tests/integration/**/Output/
10
+ output/
11
+
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: html2pdf4doc
3
+ Version: 0.0.17
4
+ Summary: Python client for HTML2PDF4Doc JavaScript library.
5
+ Project-URL: Changelog, https://github.com/mettta/html2pdf_python/releases/
6
+ Project-URL: Homepage, https://github.com/mettta/html2pdf_python/
7
+ Project-URL: Source, https://github.com/mettta/html2pdf_python/
8
+ Author-email: Stanislav Pankevich <s.pankevich@gmail.com>, Maryna Balioura <mettta@gmail.com>
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
18
+ Requires-Python: >=3.8
19
+ Requires-Dist: requests
20
+ Requires-Dist: selenium
21
+ Requires-Dist: webdriver-manager
22
+ Provides-Extra: development
23
+ Requires-Dist: invoke>=1.4.1; extra == 'development'
24
+ Requires-Dist: tox>=4.4.8; extra == 'development'
File without changes
@@ -0,0 +1,533 @@
1
+ import argparse
2
+ import atexit
3
+ import base64
4
+ import os.path
5
+ import platform
6
+ import re
7
+ import subprocess
8
+ import sys
9
+ import zipfile
10
+ from datetime import datetime
11
+ from pathlib import Path
12
+ from time import sleep
13
+ from typing import Dict, List, Optional
14
+
15
+ import requests
16
+ from requests import Response
17
+ from selenium import webdriver
18
+ from selenium.webdriver.chrome.options import Options
19
+ from selenium.webdriver.chrome.service import Service
20
+ from webdriver_manager.core.os_manager import ChromeType, OperationSystemManager
21
+
22
+ __version__ = "0.0.17"
23
+
24
+ PATH_TO_HTML2PDF4DOC_JS = os.path.join(
25
+ os.path.dirname(os.path.join(__file__)),
26
+ "html2pdf4doc_js",
27
+ "html2pdf4doc.min.js",
28
+ )
29
+
30
+ DEFAULT_CACHE_DIR = os.path.join(Path.home(), ".html2pdf4doc", "chromedriver")
31
+
32
+ PATH_TO_CHROME_DRIVER_DEBUG_LOG = "/tmp/chromedriver.log"
33
+
34
+ # HTML2PDF4Doc.js prints unicode symbols to console. The following makes it work on
35
+ # Windows which otherwise complains:
36
+ # UnicodeEncodeError: 'charmap' codec can't encode characters in position 129-130: character maps to <undefined>
37
+ # How to make python 3 print() utf8
38
+ # https://stackoverflow.com/questions/3597480/how-to-make-python-3-print-utf8
39
+ sys.stdout = open(sys.stdout.fileno(), mode="w", encoding="utf8", closefd=False)
40
+
41
+
42
+ class ChromeDriverManager:
43
+ def get_chrome_driver(self, path_to_cache_dir: str) -> str:
44
+ chrome_version: Optional[str] = self.get_chrome_version()
45
+
46
+ # If Web Driver Manager cannot detect Chrome, it returns None.
47
+ if chrome_version is None:
48
+ raise RuntimeError(
49
+ "html2pdf4doc: "
50
+ "Web Driver Manager could not detect an existing Chrome installation."
51
+ )
52
+
53
+ chrome_major_version = chrome_version.split(".")[0]
54
+
55
+ print( # noqa: T201
56
+ f"html2pdf4doc: Installed Chrome version: {chrome_version}"
57
+ )
58
+
59
+ system_map = {
60
+ "Windows": "win32",
61
+ "Darwin": "mac-arm64"
62
+ if platform.machine() == "arm64"
63
+ else "mac-x64",
64
+ "Linux": "linux64",
65
+ }
66
+ os_type = system_map[platform.system()]
67
+ is_windows = platform.system() == "Windows"
68
+
69
+ print( # noqa: T201
70
+ f"html2pdf4doc: OS system: {platform.system()}, OS type: {os_type}."
71
+ )
72
+
73
+ path_to_cached_chrome_driver_dir = os.path.join(
74
+ path_to_cache_dir, chrome_major_version
75
+ )
76
+ path_to_cached_chrome_driver = os.path.join(
77
+ path_to_cached_chrome_driver_dir,
78
+ f"chromedriver-{os_type}",
79
+ "chromedriver",
80
+ )
81
+ if is_windows:
82
+ path_to_cached_chrome_driver += ".exe"
83
+
84
+ if os.path.isfile(path_to_cached_chrome_driver):
85
+ print( # noqa: T201
86
+ f"html2pdf4doc: ChromeDriver exists in the local cache: "
87
+ f"{path_to_cached_chrome_driver}"
88
+ )
89
+ return path_to_cached_chrome_driver
90
+ print( # noqa: T201
91
+ f"html2pdf4doc: ChromeDriver does not exist in the local cache: "
92
+ f"{path_to_cached_chrome_driver}"
93
+ )
94
+
95
+ path_to_downloaded_chrome_driver = self._download_chromedriver(
96
+ chrome_major_version,
97
+ os_type,
98
+ path_to_cached_chrome_driver_dir,
99
+ path_to_cached_chrome_driver,
100
+ )
101
+ assert os.path.isfile(path_to_downloaded_chrome_driver)
102
+ os.chmod(path_to_downloaded_chrome_driver, 0o755)
103
+
104
+ return path_to_downloaded_chrome_driver
105
+
106
+ @staticmethod
107
+ def _download_chromedriver(
108
+ chrome_major_version: str,
109
+ os_type: str,
110
+ path_to_driver_cache_dir: str,
111
+ path_to_cached_chrome_driver: str,
112
+ ) -> str:
113
+ url = "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"
114
+ response = ChromeDriverManager.send_http_get_request(url)
115
+ if response is None:
116
+ raise RuntimeError(
117
+ "Could not download known-good-versions-with-downloads.json"
118
+ )
119
+
120
+ response = response.json()
121
+ if response is None:
122
+ raise RuntimeError(
123
+ "Could not parse known-good-versions-with-downloads.json"
124
+ )
125
+ assert isinstance(response, dict)
126
+
127
+ matching_versions = [
128
+ item
129
+ for item in response["versions"]
130
+ if item["version"].startswith(chrome_major_version)
131
+ ]
132
+
133
+ if not matching_versions:
134
+ raise RuntimeError(
135
+ f"No compatible ChromeDriver found for Chrome version {chrome_major_version}"
136
+ )
137
+
138
+ latest_version = matching_versions[-1]
139
+
140
+ driver_url: str
141
+ chrome_downloadable_versions = latest_version["downloads"][
142
+ "chromedriver"
143
+ ]
144
+ for chrome_downloadable_version_ in chrome_downloadable_versions:
145
+ if chrome_downloadable_version_["platform"] == os_type:
146
+ driver_url = chrome_downloadable_version_["url"]
147
+ break
148
+ else:
149
+ raise RuntimeError(
150
+ f"Could not find a downloadable URL from downloadable versions: {chrome_downloadable_versions}"
151
+ )
152
+
153
+ print( # noqa: T201
154
+ f"html2pdf4doc: downloading ChromeDriver from: {driver_url}"
155
+ )
156
+ response = ChromeDriverManager.send_http_get_request(driver_url)
157
+
158
+ if response is None:
159
+ raise RuntimeError(
160
+ f"Could not download ChromeDriver from {driver_url}"
161
+ )
162
+
163
+ Path(path_to_driver_cache_dir).mkdir(parents=True, exist_ok=True)
164
+ zip_path = os.path.join(path_to_driver_cache_dir, "chromedriver.zip")
165
+ print( # noqa: T201
166
+ f"html2pdf4doc: saving downloaded ChromeDriver to path: {zip_path}"
167
+ )
168
+ with open(zip_path, "wb") as file:
169
+ file.write(response.content)
170
+
171
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
172
+ zip_ref.extractall(path_to_driver_cache_dir)
173
+
174
+ print( # noqa: T201
175
+ f"html2pdf4doc: ChromeDriver downloaded to: {path_to_cached_chrome_driver}"
176
+ )
177
+ return path_to_cached_chrome_driver
178
+
179
+ @staticmethod
180
+ def send_http_get_request(url: str) -> Response:
181
+ last_error: Optional[Exception] = None
182
+ for attempt in range(1, 4):
183
+ print( # noqa: T201
184
+ f"html2pdf4doc: sending GET request attempt {attempt}: {url}"
185
+ )
186
+ try:
187
+ return requests.get(url, timeout=(5, 5))
188
+ except requests.exceptions.ConnectTimeout as connect_timeout_:
189
+ last_error = connect_timeout_
190
+ except requests.exceptions.ReadTimeout as read_timeout_:
191
+ last_error = read_timeout_
192
+ except Exception as exception_:
193
+ raise AssertionError(
194
+ "html2pdf4doc: unknown exception", exception_
195
+ ) from None
196
+ print( # noqa: T201
197
+ f"html2pdf4doc: "
198
+ f"failed to get response for URL: {url} with error: {last_error}"
199
+ )
200
+ raise RuntimeError(
201
+ f"GET request failed after 3 attempts: {url}"
202
+ ) from last_error
203
+
204
+ @staticmethod
205
+ def get_chrome_version() -> Optional[str]:
206
+ # Special case: GitHub Actions macOS CI machines have both
207
+ # Google Chrome for Testing and normal Google Chrome installed, and
208
+ # sometimes their versions are of different major version families.
209
+ # The solution is to check if the Google Chrome for Testing is available,
210
+ # and use its version instead of the normal one.
211
+ if platform.system() == "Darwin":
212
+ chrome_path = "/Applications/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing"
213
+ try:
214
+ print( # noqa: T201
215
+ "html2pdf4doc: "
216
+ "checking if there is Google Chrome for Testing instead of "
217
+ "a normal Chrome available."
218
+ )
219
+
220
+ version_output = subprocess.run(
221
+ [chrome_path, "--version"],
222
+ capture_output=True,
223
+ text=True,
224
+ check=True,
225
+ )
226
+ chrome_version = version_output.stdout.strip()
227
+ match = re.search(r"\d+(\.\d+)+", chrome_version)
228
+ if not match:
229
+ raise RuntimeError(
230
+ "Cannot extract the version part using regex."
231
+ )
232
+
233
+ chrome_version = match.group(0)
234
+
235
+ print( # noqa: T201
236
+ f"html2pdf4doc: Google Chrome for Testing Version: {chrome_version}"
237
+ )
238
+
239
+ return chrome_version
240
+ except FileNotFoundError:
241
+ print("html2pdf4doc: Chrome for Testing not available.") # noqa: T201
242
+ except Exception as e:
243
+ print( # noqa: T201
244
+ f"html2pdf4doc: Error getting Google Chrome for Testing version: {e}"
245
+ )
246
+
247
+ os_manager = OperationSystemManager(os_type=None) # type: ignore[no-untyped-call]
248
+ version: str = os_manager.get_browser_version_from_os(ChromeType.GOOGLE) # type: ignore[no-untyped-call]
249
+ return version
250
+
251
+
252
+ def get_inches_from_millimeters(mm: float) -> float:
253
+ return mm / 25.4
254
+
255
+
256
+ def get_pdf_from_html(driver: webdriver.Chrome, url: str) -> bytes:
257
+ print(f"html2pdf4doc: opening URL with ChromeDriver: {url}") # noqa: T201
258
+
259
+ driver.get(url)
260
+
261
+ # https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
262
+ calculated_print_options = {
263
+ "landscape": False,
264
+ "displayHeaderFooter": False,
265
+ "printBackground": True,
266
+ # This is an experimental feature that generates a document outline
267
+ # (table of contents).
268
+ "generateDocumentOutline": True,
269
+ # Whether to prefer page size as defined by css. Defaults to
270
+ # false, in which case the content will be scaled to fit the paper size.
271
+ "preferCSSPageSize": True,
272
+ # Paper width in inches. Defaults to 8.5 inches.
273
+ "paperWidth": get_inches_from_millimeters(210),
274
+ # Paper height in inches. Defaults to 11 inches.
275
+ "paperHeight": get_inches_from_millimeters(297),
276
+ # WIP: Changing the margin settings has no effect.
277
+ # Top margin in inches. Defaults to 1cm (~0.4 inches).
278
+ "marginTop": get_inches_from_millimeters(12),
279
+ # Bottom margin in inches. Defaults to 1cm (~0.4 inches).
280
+ "marginBottom": get_inches_from_millimeters(12),
281
+ # Left margin in inches. Defaults to 1cm (~0.4 inches).
282
+ "marginLeft": get_inches_from_millimeters(21),
283
+ # Right margin in inches. Defaults to 1cm (~0.4 inches).
284
+ "marginRight": get_inches_from_millimeters(21),
285
+ }
286
+
287
+ class Done(Exception):
288
+ pass
289
+
290
+ datetime_start = datetime.today()
291
+
292
+ logs: List[Dict[str, str]] = []
293
+ try:
294
+ while True:
295
+ logs = driver.get_log("browser") # type: ignore[no-untyped-call]
296
+ for entry_ in logs:
297
+ if "[HTML2PDF4DOC] Total time:" in entry_["message"]:
298
+ print("success: HTML2PDF4Doc completed its job.") # noqa: T201
299
+ raise Done
300
+ if (datetime.today() - datetime_start).total_seconds() > 60:
301
+ raise TimeoutError
302
+ sleep(0.5)
303
+ except Done:
304
+ pass
305
+ except TimeoutError:
306
+ print( # noqa: T201
307
+ "error: html2pdf4doc: "
308
+ "could not receive a successful completion status from HTML2PDF4Doc."
309
+ )
310
+ sys.exit(1)
311
+
312
+ print("html2pdf4doc: JS logs from the print session:") # noqa: T201
313
+ print('"""') # noqa: T201
314
+ for entry in logs:
315
+ print(entry) # noqa: T201
316
+ print('"""') # noqa: T201
317
+
318
+ #
319
+ # Execute Print command with ChromeDriver.
320
+ #
321
+ print("html2pdf4doc: executing print command with ChromeDriver.") # noqa: T201
322
+ result = driver.execute_cdp_cmd("Page.printToPDF", calculated_print_options)
323
+
324
+ data = base64.b64decode(result["data"])
325
+ return data
326
+
327
+
328
+ def create_webdriver(
329
+ chromedriver_argument: Optional[str],
330
+ path_to_cache_dir: str,
331
+ page_load_timeout: int,
332
+ debug: bool = False,
333
+ ) -> webdriver.Chrome:
334
+ print("html2pdf4doc: creating ChromeDriver service.", flush=True) # noqa: T201
335
+
336
+ path_to_chrome_driver: str
337
+ if chromedriver_argument is None:
338
+ path_to_chrome_driver = ChromeDriverManager().get_chrome_driver(
339
+ path_to_cache_dir
340
+ )
341
+ else:
342
+ path_to_chrome_driver = chromedriver_argument
343
+ print( # noqa: T201
344
+ f"html2pdf4doc: ChromeDriver available at path: {path_to_chrome_driver}"
345
+ )
346
+
347
+ if debug:
348
+ service = Service(
349
+ path_to_chrome_driver, log_output=PATH_TO_CHROME_DRIVER_DEBUG_LOG
350
+ )
351
+ else:
352
+ service = Service(path_to_chrome_driver)
353
+
354
+ webdriver_options = Options()
355
+ webdriver_options.add_argument("start-maximized")
356
+ webdriver_options.add_argument("disable-infobars")
357
+ # Doesn't seem to be needed.
358
+ # webdriver_options.add_argument('--disable-gpu') # noqa: ERA001
359
+ webdriver_options.add_argument("--disable-extensions")
360
+
361
+ # Use --headless=new, as it seems to be more stable on Windows (available since Chrome 109).
362
+ # see https://www.selenium.dev/blog/2023/headless-is-going-away/
363
+ webdriver_options.add_argument("--headless=new")
364
+
365
+ # Docker disables some syscalls that are required for Chrome's sandbox to work.
366
+ # https://stackoverflow.com/questions/68855734/how-to-setup-chrome-sandbox-on-docker-container
367
+ # We prefer isolation of the container over isolation of tabs within Chrome,
368
+ # and thus disable the sandbox.
369
+ # See also:
370
+ # https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2689287561
371
+ webdriver_options.add_argument("--no-sandbox")
372
+
373
+ # The Chrome option --disable-dev-shm-usage disables the use of /dev/shm
374
+ # (shared memory) for temporary storage in Chrome.
375
+ # By default, Chrome uses /dev/shm for storing temporary files to improve
376
+ # performance. However, in environments with limited shared memory (such as
377
+ # Docker containers), this can lead to crashes or issues due to insufficient
378
+ # space.
379
+ webdriver_options.add_argument("--disable-dev-shm-usage")
380
+
381
+ webdriver_options.add_experimental_option("useAutomationExtension", False)
382
+ webdriver_options.add_experimental_option(
383
+ "excludeSwitches", ["enable-automation"]
384
+ )
385
+
386
+ # Enable the capturing of everything in JS console.
387
+ webdriver_options.set_capability("goog:loggingPrefs", {"browser": "ALL"})
388
+
389
+ print("html2pdf4doc: creating ChromeDriver.", flush=True) # noqa: T201
390
+
391
+ driver = webdriver.Chrome(
392
+ options=webdriver_options,
393
+ service=service,
394
+ )
395
+ driver.set_page_load_timeout(page_load_timeout)
396
+
397
+ return driver
398
+
399
+
400
+ def main() -> None:
401
+ if not os.path.isfile(PATH_TO_HTML2PDF4DOC_JS):
402
+ raise RuntimeError(
403
+ f"Corrupted html2pdf4doc package bundle. "
404
+ f"The html2pdf4doc JS file is missing at path: "
405
+ f"{PATH_TO_HTML2PDF4DOC_JS}."
406
+ )
407
+
408
+ parser = argparse.ArgumentParser(description="html2pdf4doc printer script.")
409
+
410
+ parser.add_argument(
411
+ "-v", "--version", action="version", version=__version__
412
+ )
413
+
414
+ command_subparsers = parser.add_subparsers(title="command", dest="command")
415
+ command_subparsers.required = True
416
+
417
+ print(f"html2pdf4doc: version {__version__}") # noqa: T201
418
+
419
+ #
420
+ # Get driver command.
421
+ #
422
+ command_parser_get_driver = command_subparsers.add_parser(
423
+ "get_driver",
424
+ help="Check if ChromeDriver already exists locally. If not, download it.",
425
+ description="",
426
+ )
427
+ command_parser_get_driver.add_argument(
428
+ "--cache-dir",
429
+ type=str,
430
+ help="Optional path to a cache directory whereto the ChromeDriver is downloaded.",
431
+ )
432
+
433
+ #
434
+ # Print command.
435
+ #
436
+ command_parser_print = command_subparsers.add_parser(
437
+ "print",
438
+ help="Main print command",
439
+ description="",
440
+ )
441
+ command_parser_print.add_argument(
442
+ "--chromedriver",
443
+ type=str,
444
+ help="Optional chromedriver path. Downloaded if not given.",
445
+ )
446
+ command_parser_print.add_argument(
447
+ "--cache-dir",
448
+ type=str,
449
+ help="Optional path to a cache directory whereto the ChromeDriver is downloaded.",
450
+ )
451
+ command_parser_print.add_argument(
452
+ "--page-load-timeout",
453
+ type=int,
454
+ default=2 * 60,
455
+ # 10 minutes should be enough to print even the largest documents.
456
+ choices=range(0, 10 * 60),
457
+ help=(
458
+ "How long shall html2pdf4doc Python driver wait while the "
459
+ "Chrome Driver is printing a given HTML page to PDF. "
460
+ "This is mainly driven by the time it takes for Chrome to open an "
461
+ "HTML file, load it, and let HTML2PDF4Doc.js finish its job."
462
+ ),
463
+ )
464
+ command_parser_print.add_argument(
465
+ "--debug",
466
+ action="store_true",
467
+ help=(
468
+ f"Enables ChromeDriver logging to a file: "
469
+ f"{PATH_TO_CHROME_DRIVER_DEBUG_LOG}."
470
+ ),
471
+ )
472
+ command_parser_print.add_argument(
473
+ "paths", nargs="+", help="Paths to input HTML file."
474
+ )
475
+
476
+ args = parser.parse_args()
477
+
478
+ path_to_cache_dir: str
479
+ if args.command == "get_driver":
480
+ path_to_cache_dir = (
481
+ args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
482
+ )
483
+
484
+ path_to_chrome = ChromeDriverManager().get_chrome_driver(
485
+ path_to_cache_dir
486
+ )
487
+ print(f"html2pdf4doc: ChromeDriver available at path: {path_to_chrome}") # noqa: T201
488
+ sys.exit(0)
489
+
490
+ elif args.command == "print":
491
+ paths: List[str] = args.paths
492
+
493
+ page_load_timeout: int = args.page_load_timeout
494
+
495
+ path_to_cache_dir = (
496
+ args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
497
+ )
498
+ driver: webdriver.Chrome = create_webdriver(
499
+ args.chromedriver,
500
+ path_to_cache_dir,
501
+ page_load_timeout,
502
+ debug=args.debug,
503
+ )
504
+
505
+ @atexit.register
506
+ def exit_handler() -> None:
507
+ print("html2pdf4doc: exit handler: quitting the ChromeDriver.") # noqa: T201
508
+ driver.quit()
509
+
510
+ assert len(paths) % 2 == 0, (
511
+ f"Expecting an even number of input/output path arguments: {paths}."
512
+ )
513
+ for current_pair_idx in range(0, len(paths), 2):
514
+ path_to_input_html = paths[current_pair_idx]
515
+ path_to_output_pdf = paths[current_pair_idx + 1]
516
+
517
+ assert os.path.isfile(path_to_input_html), path_to_input_html
518
+
519
+ path_to_output_pdf_dir = os.path.dirname(path_to_output_pdf)
520
+ Path(path_to_output_pdf_dir).mkdir(parents=True, exist_ok=True)
521
+
522
+ url = Path(os.path.abspath(path_to_input_html)).as_uri()
523
+
524
+ pdf_bytes = get_pdf_from_html(driver, url)
525
+ with open(path_to_output_pdf, "wb") as f:
526
+ f.write(pdf_bytes)
527
+ else:
528
+ print("html2pdf4doc: unknown command.") # noqa: T201
529
+ sys.exit(1)
530
+
531
+
532
+ if __name__ == "__main__":
533
+ main()
@@ -0,0 +1,2 @@
1
+ /*! Version: 0.2.2 */
2
+ var HTML2PDF4DOC;(()=>{"use strict";var e={d:(t,o)=>{for(var n in o)e.o(o,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:o[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{init:()=>k});const o={init:"[html2pdf]",pageDivider:"html2pdf-page",pageStartMarker:"[html2pdf-page-start]",contentFlowStart:"html2pdf-content-flow-start",contentFlowEnd:"html2pdf-content-flow-end",style:"[html2pdf-style]",footerTemplate:"[html2pdf-footer]",headerTemplate:"[html2pdf-header]",frontpageTemplate:"[html2pdf-frontpage]",frontpageContent:"html2pdf-frontpage",headerContent:"html2pdf-header",footerContent:"html2pdf-footer",pageNumberRoot:"[html2pdf-page-number]",pageNumberCurrent:"[html2pdf-page-number-current]",pageNumberTotal:"[html2pdf-page-number-total]",root:"html2pdf-root",paperFlow:"html2pdf-paper-flow",contentFlow:"html2pdf-content-flow",virtualPaper:"html2pdf-virtual-paper",virtualPaperTopMargin:"html2pdf-virtual-paper-margin-top",virtualPaperBottomMargin:"html2pdf-virtual-paper-margin-bottom",virtualPaperGap:"html2pdf-virtual-paper-gap",paperBody:"html2pdf-paper-body",paperHeader:"html2pdf-paper-header",paperFooter:"html2pdf-paper-footer",runningSafety:"html2pdf-print-running",printPageBreak:"html2pdf-print-page-break",printIgnore:"[html2pdf-print-ignore]",printHide:"[html2pdf-print-hide]",neutral:"html2pdf-neutral",word:"html2pdf-word",textNode:"html2pdf-text-node",textLine:"html2pdf-text-line",textGroup:"html2pdf-text-group",complexTextBlock:"html2pdf-complex-text-block",printForcedPageBreak:"html2pdf-print-forced-page-break",splitted:"[html2pdf-splitted]",processed:"[html2pdf-processed]",flagNoBreak:"[html2pdf-flag-no-break]",flagNoHanging:"[html2pdf-flag-no-hanging]",topCutPart:".html2pdf-top-cut",bottomCutPart:".html2pdf-bottom-cut",tocPageNumber:"html2pdf-toc-page-number"};function n(e){let t={debugMode:!1,preloader:!1,preloaderTarget:"",preloaderBackground:"",mask:!0,noHangingSelectors:"",forcedPageBreakSelectors:"",pageBreakBeforeSelectors:"",pageBreakAfterSelectors:"",noBreakSelectors:"",tocPageNumberSelector:"html2pdf-toc-page-number",printLeftMargin:"21mm",printRightMargin:"21mm",printTopMargin:"12mm",printBottomMargin:"12mm",printFontSize:"12pt",printWidth:"210mm",printHeight:"297mm",headerMargin:"16px",footerMargin:"16px",virtualPagesGap:"16px"};const n={printWidth:"210mm",printHeight:"297mm"},i={printWidth:"148.5mm",printHeight:"210mm"};switch(e.printPaperSize){case"A5":case"a5":t={...t,...i};break;default:t={...t,...n}}t={...t,initialRoot:o.init,tocPageNumberSelector:o.tocPageNumber,...e},console.info("[HTML2PDF4DOC] Config:",t);const s={printLeftMargin:t.printLeftMargin,printRightMargin:t.printRightMargin,printTopMargin:t.printTopMargin,printBottomMargin:t.printBottomMargin,printFontSize:t.printFontSize,printWidth:t.printWidth,printHeight:t.printHeight,headerMargin:t.headerMargin,footerMargin:t.footerMargin,virtualPagesGap:t.virtualPagesGap},r=document.createElement("div");return r.style="\n position:absolute;\n z-index:1000;\n left: 200%;\n ",document.body.append(r),Object.entries(s).forEach((([e,t])=>{r.style.width=t,s[e]=`${Math.trunc(r.getBoundingClientRect().width)}px`})),r.remove(),t={...t,...s},t.noHangingSelectors=t.noHangingSelectors+" H1 H2 H3 H4 H5 H6",t.forcedPageBreakSelectors=t.forcedPageBreakSelectors+" "+o.printForcedPageBreak,t.debugMode&&console.info("Config with converted units:",t),t}const i={DOM:{_:!1},layout:{_:!0},pages:{_:!0,_parseNode:!1,_parseNodes:!1,_registerPageStart:!1,_getProcessedChildren:!1,_splitPreNode:!1,_splitTableNode:!1,_splitTableLikeNode:!1,_splitTableRow:!1,_splitGridNode:!1,_createSlicesBySplitFlag:!1,_getInternalBlockSplitters:!1},paragraph:{_:!1},node:{_:!1},paper:{_:!1},preview:{_:!1},toc:{_:!1}};class s{constructor({DOM:e,config:t}){this.document=e,this.body=e.body,this._debugMode=t.debugMode,this._debug=t.debugMode?{...t.debugConfig.DOM}:{}}createElement(e){return this.document.createElement(e)}createDocumentFragment(){return this.document.createDocumentFragment()}cloneNode(e){return e?.cloneNode(!0)}cloneNodeWrapper(e){return e?.cloneNode(!1)}insertBefore(e,...t){e.before(...t)}insertAfter(e,...t){e.after(...t)}insertAtEnd(e,...t){e.append(...t)}insertAtStart(e,...t){e.prepend(...t)}insertInsteadOf(e,...t){e.before(...t),e.remove()}moveContent(e,t){for(;e.firstChild;)t.append(e.firstChild);console.assert(""===this.getInnerHTML(e))}removeNode(e){e.remove()}getElement(e,t=this.document){return t.querySelector(e)}getAllElements(e,t=this.document){return t.querySelectorAll(e)}getElementById(e,t=this.document){return t.getElementById(e)}getRightNeighbor(e){return e.nextElementSibling}getLeftNeighbor(e){return e.previousElementSibling}getParentNode(e){return e.parentElement}getNodeValue(e){return e.nodeValue}getLastElementChild(e){return e.lastElementChild}getFirstElementChild(e){return e.firstElementChild}getChildNodes(e){return e.childNodes}getChildren(e){return e.children}getElementOffsetParent(e){return e.offsetParent}getComputedStyle(e){return window.getComputedStyle(e)}getElementBCR(e){return e.getBoundingClientRect()}getElementOffsetLeft(e){return e?.offsetLeft}getElementOffsetHeight(e){return e?.offsetHeight}getElementOffsetWidth(e){return e?.offsetWidth}getElementOffsetTop(e){return e?.offsetTop}getElementOffsetBottom(e){return e.offsetTop+e.offsetHeight||void 0}getElementTagName(e){return e.tagName}getDataId(e){return e.dataset.id}getAttribute(e,t){if(!e||!t)return void(this._debug._&&console.warn("getAttribute() must have 2 params"));const o=t.charAt(0);if("."!==o&&"#"!==o||this._debug._&&console.log(`you're really sure ${t} is attribute selector?`),"["===o){this._debug._&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const o=t.substring(1,t.length-1);return e.getAttribute(o)}e.getAttribute(t)}setAttribute(e,t,o){if(!e||!t)return void(this._debug._&&console.warn("setAttribute() must have 2 params"));const n=t.charAt(0);if("."!==n)if("#"!==n)if("["!==n)this._debug._&&console.log(`you're really sure ${t} is a selector?`);else{this._debug._&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const n=t.substring(1,t.length-1);e.setAttribute(n,o||"")}else{const o=t.substring(1);e.id=o}else{const o=t.substring(1);e.classList.add(o)}}setStyles(e,t){Object.entries(t).forEach((([t,o])=>e.style[t]=o))}addClasses(e,...t){e.classList.add(...t)}removeAttribute(e,t){if(!e||!t)return void(this._debug._&&console.warn("removeAttribute() must have 2 params"));const o=t.charAt(0);if(console.assert(o.match(/[a-zA-Z#\[\.]/),`removeAttribute() expects a valid selector, but received ${t}`),"."!==o)if("#"!==o)if("["!==o)e.removeAttribute(attr);else{this._debug._&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const o=t.substring(1,t.length-1);e.removeAttribute(o)}else{const o=t.substring(1);e.removeAttribute(o)}else{const o=t.substring(1);e.classList.remove(o)}}removeAllAttributes(e){for(;e.attributes.length>0;)e.removeAttribute(e.attributes[0].name)}removeClasses(e,...t){e.classList.remove(...t)}removeAllClasses(e){e.classList=""}removeAllStyles(e){e.style=""}getInnerHTML(e){if("string"==typeof e){const t=this.document.querySelector(e);return t?t.innerHTML:void 0}return e.innerHTML}setInnerHTML(e,t){if("string"==typeof e){const o=this.document.querySelector(e);o&&(o.innerHTML=t)}e.innerHTML=t}isDocumentBody(e){return"BODY"===e.tagName}isTextNode(e){return e.nodeType===Node.TEXT_NODE}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}hasClass(e,t){return e.classList.contains(t)}hasID(e,t){return e.id===t}hasAttribute(e,t){return e.hasAttribute(t)}}class r{constructor(e){this.config=e,this.charWidth="10px"}create(){return this._baseStyle()+this._testStyle()}_baseStyle(){return`\n\n@page {\n size: A4;\n /* 2 values: width then height */\n size: ${this.config.printWidth} ${this.config.printHeight};\n\n margin-left: ${this.config.printLeftMargin};\n margin-right: ${this.config.printRightMargin};\n margin-top: ${this.config.printTopMargin};\n margin-bottom: 0; /* hack */\n}\n\n${o.root} {\n /* reset user styles */\n display: block;\n\n /* for proper printable flow positioning */\n position: relative;\n\n /* to compensate for possible BG in the parent node */\n z-index: 1;\n\n /* set print styles: affects previews */\n margin: 0 auto;\n width: calc(${this.config.printWidth} - ${this.config.printLeftMargin} - ${this.config.printRightMargin});\n font-size: ${this.config.printFontSize};\n\n /* protection against unpredictability of margins */\n padding-top: .1px;\n padding-bottom: calc(2 * ${this.config.virtualPagesGap});\n}\n\n${o.contentFlowStart},\n${o.contentFlowEnd},\n${o.pageDivider} {\n display: block;\n}\n\n${o.virtualPaper} {\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: minmax(min-content, max-content) minmax(min-content, max-content) 1fr minmax(min-content, max-content) minmax(min-content, max-content);\n place-items: stretch stretch;\n place-content: stretch stretch;\n width: calc(${this.config.printWidth} - ${this.config.printLeftMargin} - ${this.config.printRightMargin});\n height: ${this.config.printHeight};\n font-size: ${this.config.printFontSize};\n}\n\n${o.virtualPaper}::before {\n position: absolute;\n content: '';\n width: ${this.config.printWidth};\n height: ${this.config.printHeight};\n left: -${this.config.printLeftMargin};\n background-color: #fff;\n box-shadow: rgba(0, 0, 0, 0.1) 2px 2px 12px 0px;\n z-index: -1;\n}\n\n${o.paperFooter},\n${o.paperHeader} {\n display: block;\n position: relative;\n}\n\n${o.headerContent},\n${o.footerContent} {\n display: block;\n font-size: small;\n}\n\n${o.headerContent} p,\n${o.footerContent} p {\n margin: 0;\n}\n\n${o.headerContent} {\n padding-bottom: ${this.config.headerMargin};\n /* padding-top: 1px; */\n /* Page numbers: */\n padding-top: 10px;\n}\n\n${o.footerContent} {\n padding-top: ${this.config.footerMargin};\n /* padding-bottom: 1px; */\n /* Page numbers: */\n min-height: 32px;\n}\n\n${o.tocPageNumber} {\n min-width: 3ch;\n display: flex;\n justify-content: flex-end;\n align-items: baseline;\n}\n\n${o.pageNumberRoot} {\n display: flex;\n column-gap: 2px;\n position: absolute;\n /* left: 100%; */\n right: 0;\n text-align: right;\n line-height: 1;\n}\n\n${o.headerContent} ${o.pageNumberRoot} {\n top: 0;\n}\n\n${o.footerContent} ${o.pageNumberRoot} {\n bottom: 0;\n}\n\n${o.paperFlow} {\n display: block;\n position: absolute;\n width: 100%;\n z-index: -1;\n /* affect only screen */\n padding-bottom: 100px;\n}\n\n${o.contentFlow} {\n display: block;\n}\n\n${o.runningSafety} {\n display: block;\n /* ? should be checked and updated,\n but in the meantime, bring back the common solution:\n firefox ignores 0.1px size, so it's necessary to make a full-size pixel\n and take it into account in the calculations:\n padding-top: 1px;\n */\n padding-top: .1px;\n}\n\n${o.virtualPaperTopMargin} {\n display: block;\n height: ${this.config.printTopMargin};\n}\n\n${o.virtualPaperBottomMargin} {\n display: block;\n height: ${this.config.printBottomMargin};\n}\n\n${o.virtualPaperGap} {\n display: block;\n padding-top: ${this.config.virtualPagesGap};\n}\n\n${o.paperBody} {\n display: block;\n}\n\n${o.frontpageContent} {\n display: block;\n transform-origin: top center;\n padding: .1px;\n height: 100%;\n}\n\n.null {\n display: inline;\n padding: 0;\n margin: 0;\n font: 0;\n color: transparent;\n line-height: 0;\n border: none;\n outline: none;\n background: none;\n background-color: transparent;\n}\n\n${o.word},\n${o.textNode},\n${o.textLine},\n${o.textGroup},\n${o.neutral},\n${o.neutral} span {\n display: inline;\n padding: 0;\n margin: 0;\n font: inherit;\n color: inherit;\n line-height: inherit;\n background: none;\n background-color: transparent;\n}\n\n${o.textGroup} {\n display: block;\n}\n\n/*${o.splitted} ${o.textGroup} {\n display: inline;\n}*/\n\n${o.complexTextBlock} > ${o.textLine} {\n /* Firefox and inconsistent values of offset top for inline element */\n display: inline-block;\n}\n\n${o.textGroup} ${o.textLine} {\n display: inline;\n}\n\n${o.complexTextBlock} {\n display: block;\n}\n\n${o.complexTextBlock} ${o.complexTextBlock} {\n display: inline;\n}\n\n${o.printPageBreak} {\n display: block;\n}\n\n${o.printForcedPageBreak} {\n display: block;\n visibility: hidden;\n height: 0;\n overflow: hidden;\n}\n\n@media print {\n ${o.root} {\n /* to prevent a blank last page */\n padding: 0;\n }\n\n ${o.paperFlow} {\n padding-bottom: 0;\n }\n\n ${o.contentFlow} {\n -webkit-mask-image: none !important;\n mask-image: none !important;\n }\n\n ${o.printIgnore} {\n display: contents;\n }\n\n ${o.printHide},\n ${o.virtualPaper}::before,\n ${o.virtualPaperTopMargin},\n ${o.virtualPaperBottomMargin},\n ${o.virtualPaperGap} {\n display: none;\n }\n\n ${o.virtualPaper} {\n break-inside: avoid;\n height: auto;\n }\n\n ${o.paperBody} {\n break-inside: avoid;\n }\n\n ${o.printPageBreak} {\n break-after: page;\n padding: .1px;\n }\n\n ${o.printForcedPageBreak} {\n /* JUST MANUAL! */\n /* break-after: page; */\n }\n\n ${o.flagNoBreak} {\n /*\n TODO: temporary commented!\n When splitting blocks, printPageBreak falls INTO this element,\n and in Firefox it causes a blank page.\n FIX the split of complex blocks and check in Firefox.\n */\n /* break-inside: avoid-page; */\n }\n}\n\n/* arrangement */\n${o.topCutPart} {\n margin-top: 0 !important;\n border-top: none !important;\n}\n${o.bottomCutPart} {\n margin-bottom: 0 !important;\n border-bottom: none !important;\n}\n `}_testStyle(){return this.config.debugMode?`\n/* FOR TEST */\n${o.contentFlow} {\n background:repeating-linear-gradient(\n -45deg,\n rgba(222, 222, 222, .1),\n rgba(222, 222, 222, .1) 10px,\n rgba(222, 222, 222, .2) 10px,\n rgba(222, 222, 222, .2) 20px\n );\n}\n\n${o.virtualPaperGap} {\n background: #ff000020;\n}\n\n${o.paperFooter},\n${o.paperHeader} {\n background: #fa96ff20;\n}\n${o.paperBody} {\n background: #ffee0020;\n}\n${o.runningSafety} {\n background: #f200ff;\n}\n${o.frontpageContent} {\n background: #00fcff20;\n}\n\n${o.neutral} {\n background: #00ffee10;\n}\n\n${o.textNode} {\n background: #00ff0010;\n}\n\n${o.textGroup},\n${o.textLine} {\n background: #0000ff08;\n}\n\n `:""}}class l{constructor({config:e,DOM:t,node:o,selector:n}){this.success=!1,this.root,this.paperFlow,this.contentFlow,this.frontpageTemplate,this.headerTemplate,this.footerTemplate,this._initialRoot,this._contentRoot,this._config=e,this._debug=e.debugMode?{...e.debugConfig.layout}:{},this._DOM=t,this._selector=n,this._node=o,this._customInitialRootSelector=e.initialRoot,this._defaultInitialRootSelector=n.init}create(){if(this._getTemplates(),this._insertStyle(),this._DOM.getElement(`style${this._selector.style}`)){if(this._createLayout(),this._DOM.getParentNode(this.root)!==this._initialRoot||this._DOM.getElementOffsetParent(this.paperFlow)!==this.root||this._DOM.getElementOffsetParent(this.contentFlow)!==this.root)return console.assert(this._DOM.getParentNode(this.root)===this._initialRoot,"Failed to insert the layout root into the DOM."),console.assert(this._DOM.getElementOffsetParent(this.paperFlow)===this.root,"Failed to insert the paperFlow element into the DOM."),void console.assert(this._DOM.getElementOffsetParent(this.contentFlow)===this.root,"Failed to insert the contentFlow element into the DOM.");this.success=!0}else console.error("Failed to add print styles into the DOM.")}_getTemplates(){console.assert(this._selector.frontpageTemplate,"frontpageTemplate selector is missing"),console.assert(this._selector.headerTemplate,"headerTemplate selector is missing"),console.assert(this._selector.footerTemplate,"footerTemplate selector is missing"),this.frontpageTemplate=this._DOM.getInnerHTML(this._selector.frontpageTemplate),this.headerTemplate=this._DOM.getInnerHTML(this._selector.headerTemplate),this.footerTemplate=this._DOM.getInnerHTML(this._selector.footerTemplate)}_insertStyle(){const e=this._DOM.getElement("head"),t=this._DOM.body;if(!e&&!t)return void console.error("Check the structure of your document. We didn`t find HEAD and BODY tags. HTML2PDF4DOC expects valid HTML.");const o=this._node.create("style",new r(this._config).create());o?(this._DOM.setAttribute(o,this._selector.style,""),e?this._DOM.insertAtEnd(e,o):t?this._DOM.insertBefore(t,o):console.assert(!1,"We expected to find the HEAD and BODY tags.")):console.error("Failed to create print styles")}_createLayout(){this._getInitialRoot(),this._initialRoot?(this._debug._&&console.log("initial root:",this._initialRoot),this._createRoot(),this._createPaperFlow(),this._createContentFlow(),this._DOM.moveContent(this._initialRoot,this.contentFlow),this._DOM.insertAtEnd(this._initialRoot,this.root),this._DOM.insertAtEnd(this.root,this.paperFlow,this.contentFlow),this._insertContentFlowStartAndEnd(this.contentFlow),this._ignoreUnprintableEnvironment(this.root)):console.error("Failed to initialize the root element.")}_insertContentFlowStartAndEnd(e){const t=this._node.create(this._selector.contentFlowStart),o=this._node.create(this._selector.contentFlowEnd);return this._DOM.insertAtStart(e,t),this._DOM.insertAtEnd(e,o),{contentFlowStart:t,contentFlowEnd:o}}_getInitialRoot(){let e=this._customInitialRootSelector?this._DOM.getElement(this._customInitialRootSelector):this._DOM.getElement(this._defaultInitialRootSelector);if(!e){if(!this._DOM.body)return void console.error("We expected to find the BODY tag.");e=this._DOM.body,console.warn(`The printable area is currently unspecified and encompasses the entire contents of the BODY tag. To restrict the printed content to a specific area, include ${this._defaultInitialRootSelector} in the root element of the desired printing area.`)}return this._initialRoot=e,e}_createRoot(){const e=this._node.create(this._selector.root);return this.root=e,e}_createPaperFlow(){const e=this._node.create(this._selector.paperFlow);return this.paperFlow=e,e}_createContentFlow(){const e=this._node.create(this._selector.contentFlow);return this.contentFlow=e,e}_ignoreUnprintableEnvironment(e){if(e===this._DOM.body)return void console.assert(!1,"misshapen root");let t=this._DOM.getParentNode(e);this._DOM.setAttribute(t,this._selector.printIgnore),this._DOM.getChildNodes(t).forEach((t=>{if(t!==e&&this._DOM.isElementNode(t))this._DOM.setAttribute(t,this._selector.printHide);else{if(!this._node.isSignificantTextNode(t))return;this._DOM.setAttribute(this._node.wrapTextNode(t),this._selector.printHide)}})),this._DOM.isDocumentBody(t)||this._ignoreUnprintableEnvironment(t)}}class a{constructor({config:e,DOM:t,selector:o}){this._config=e,this._DOM=t,this._selector=o,this._debug=e.debugMode?{...e.debugConfig.node}:{},this._markupDebugMode=this._config.markupDebugMode}get(e,t=this._DOM){return console.assert(e),this._DOM.getElement(e,t)}getAll(e,t=this._DOM){return console.assert(e),"string"==typeof e&&(e=e.split(",").filter(Boolean)),console.assert(Array.isArray(e),"Selectors must be provided as an array or string (one selector or multiple selectors, separated by commas). Now the selectors are:",e),console.assert(e.length>0,"getAll(selectors), selectors:",e),1===e.length?[...this._DOM.getAllElements(e[0],t)]:[...e].flatMap((e=>[...this._DOM.getAllElements(e,t)]))}getTableEntries(e){const t=[...e.children].reduce(((e,t)=>{const o=t.tagName;return"TBODY"===o?{...e,rows:[...e.rows,...t.children]}:"CAPTION"===o?(this.setFlagNoBreak(t),{...e,caption:t}):"COLGROUP"===o?(this.setFlagNoBreak(t),{...e,colgroup:t}):"THEAD"===o?(this.setFlagNoBreak(t),{...e,thead:t}):"TFOOT"===o?(this.setFlagNoBreak(t),{...e,tfoot:t}):"TR"===o?{...e,rows:[...e.rows,...t]}:{...e,unexpected:[...e.unexpected,...t]}}),{caption:null,thead:null,tfoot:null,rows:[],unexpected:[]});return t.unexpected.length>0&&this._debug._&&console.warn(`something unexpected is found in the table ${e}`),t}getPreparedChildren(e){if(this.isComplexTextBlock(e))return[...this._DOM.getChildren(e)];{let t=[...this._DOM.getChildNodes(e)].reduce(((e,t)=>{if(this.isSTYLE(t))return e;if(this.isSignificantTextNode(t))return e.push(this.wrapTextNode(t)),e;if(!this._DOM.getElementOffsetParent(t)){const o=this.getPreparedChildren(t);return o.length>0&&e.push(...o),e}return this._DOM.isElementNode(t)?(e.push(t),e):void 0}),[]);return this.isVerticalFlowDisrupted(t)&&(t=this._processInlineChildren(t)),t}}_processInlineChildren(e){let t=null;const o=[];return e.forEach((e=>{this.isInline(this._DOM.getComputedStyle(e))?(t||(t=this.createComplexTextBlock(),this.wrapNode(e,t),o.push(t)),this._DOM.insertAtEnd(t,e)):(t=null,o.push(e))})),o}clearTemplates(e){this.getAll("template",e).forEach((e=>this._DOM.removeNode(e)))}isSelectorMatching(e,t){if(!e||!t)return void(this._debug._&&console.warn("isSelectorMatching() must have 2 params","\n element: ",e,"\n selector: ",t));const o=t.charAt(0);if("."===o){const o=t.substring(1);return this._DOM.hasClass(e,o)}if("#"===o){const o=t.substring(1);return this._DOM.hasID(e,o)}if("["===o){this._debug._&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const o=t.substring(1,t.length-1);return this._DOM.hasAttribute(e,o)}return this._DOM.getElementTagName(e)===t.toUpperCase()}isSignificantTextNode(e){return!!this._DOM.isTextNode(e)&&this._DOM.getNodeValue(e).trim().length>0}isSTYLE(e){return"STYLE"===this._DOM.getElementTagName(e)}isIMG(e){return"IMG"===this._DOM.getElementTagName(e)}isSVG(e){return"svg"===this._DOM.getElementTagName(e)}isOBJECT(e){return"OBJECT"===this._DOM.getElementTagName(e)}isLiNode(e){return"LI"===this._DOM.getElementTagName(e)}isNeutral(e){return this.isSelectorMatching(e,this._selector.neutral)}isWrappedTextNode(e){return this.isSelectorMatching(e,this._selector.textNode)}isWrappedTextLine(e){return this.isSelectorMatching(e,this._selector.textLine)}isWrappedTextGroup(e){return this.isSelectorMatching(e,this._selector.textGroup)}isPageStartElement(e){return this.isSelectorMatching(e,this._selector.pageStartMarker)}isContentFlowStart(e){return this.isSelectorMatching(e,this._selector.contentFlowStart)}isContentFlowEnd(e){return this.isSelectorMatching(e,this._selector.contentFlowEnd)}isComplexTextBlock(e){return this.isSelectorMatching(e,this._selector.complexTextBlock)}isNoBreak(e,t=this._DOM.getComputedStyle(e)){return this.isSelectorMatching(e,this._selector.flagNoBreak)||this.isWrappedTextLine(e)||this.isWrappedTextGroup(e)||this.isInlineBlock(t)||this.notSolved(e)}isNoHanging(e){return this.isSelectorMatching(e,this._selector.flagNoHanging)}isForcedPageBreak(e){return this.isSelectorMatching(e,this._selector.printForcedPageBreak)}isInline(e){const t=e.display;return"inline"===t||"inline-block"===t||"inline-table"===t||"inline-flex"===t||"inline-grid"===t}isInlineBlock(e){const t=e.display;return"inline-block"===t||"inline-table"===t||"inline-flex"===t||"inline-grid"===t}isGrid(e){return"grid"===e.display}isTableLikeNode(e,t=this._DOM.getComputedStyle(e)){return"TABLE"!==this._DOM.getElementTagName(e)&&["table"].includes(t.display)}isTableNode(e,t=this._DOM.getComputedStyle(e)){return"TABLE"===this._DOM.getElementTagName(e)||["table"].includes(t.display)}isPRE(e,t=this._DOM.getComputedStyle(e)){return["block"].includes(t.display)&&["pre","pre-wrap","pre-line","break-spaces","nowrap"].includes(t.whiteSpace)}isGridAutoFlowRow(e){const t=e.display,o=e.gridAutoFlow;return("grid"===t||"inline-grid"===t)&&"row"===o}isFullySPlitted(e){const t=this._DOM.getComputedStyle(e);return this.isPRE(e,t)||this.isTableNode(e,t)||this.isTableLikeNode(e,t)||this.isGridAutoFlowRow(t)}isSlough(e){return this._DOM.hasAttribute(e,"slough-node")}isFirstChildOfFirstChild(e,t){if(!e||!this._DOM.getParentNode(e))return!1;let o=e;for(;this._DOM.getParentNode(o)&&o!==t;){if(this._DOM.getFirstElementChild(this._DOM.getParentNode(o))!==o)return!1;o=this._DOM.getParentNode(o)}return o===t}isLastChildOfLastChild(e,t){if(!e||!this._DOM.getParentNode(e))return!1;let o=e;for(;this._DOM.getParentNode(o)&&o!==t;){if(this._DOM.getParentNode(o)===t){let e=this._DOM.getRightNeighbor(o);for(;!this._DOM.getElementOffsetHeight(e)&&!this._DOM.getElementOffsetWidth(e);)if(e=this._DOM.getRightNeighbor(e),this.isContentFlowEnd(e))return!0;return this.isContentFlowEnd(e)}if(this._DOM.getLastElementChild(this._DOM.getParentNode(o))!==o)return!1;o=this._DOM.getParentNode(o)}return o===t}isLineChanged(e,t){return this._DOM.getElementOffsetTop(t)-this._DOM.getElementOffsetBottom(e)>-2}isLineKept(e,t,o){const n=this._DOM.getElementOffsetBottom(e),i=this._DOM.getElementOffsetTop(t),s=n-i,r=s>=2;return o&&console.group("isLineKept?"),o&&console.log("\n",r,"\n","\n currentBottom",n,[e],"\n nextTop",i,[t],"\n delta",s),o&&console.groupEnd("isLineKept?"),r}findFirstChildParent(e,t){let o=this._DOM.getParentNode(e),n=null;for(;o&&o!==t;){if(e!==this._DOM.getFirstElementChild(o))return n;n=o,e=o,o=this._DOM.getParentNode(e)}return n}findLastChildParent(e,t){let o=this._DOM.getParentNode(e),n=null;for(;o&&o!==t;){if(e!==this._DOM.getLastElementChild(o))return n;n=o,e=o,o=this._DOM.getParentNode(e)}return n}isVerticalFlowDisrupted(e){return e.some(((e,t,o)=>{const n=e,i=o[t+1];if(!i)return!1;return this._DOM.getElementOffsetBottom(n)>this._DOM.getElementOffsetTop(i)}))}findBetterPageStart(e,t,o,n){let i=e;const s=this.getTop(t,n);for(;;){const e=this.findFirstChildParent(i,o);if(e&&e!==i){i=e;continue}const t=this.findPreviousNonHangingsFromPage(i,s,n);if(!t||t===i)break;i=t}return i}findAllForcedPageBreakInside(e){return this.getAll(this._selector.printForcedPageBreak,e)}findPreviousNonHangingsFromPage(e,t,o){let n=null,i=this._DOM.getLeftNeighbor(e);for(;i&&this.getTop(i,o)>t;){if(!this.isNoHanging(i))return n;if(this.isPageStartElement(i))return e;n=i,e=i,i=this._DOM.getLeftNeighbor(e)}return n}findSuitableNonHangingPageStart(e,t){let o=e,n=null;for(;;){const e=this._DOM.getLastElementChild(o);if(!e)break;if(this.isNoHanging(e)){n=e;break}o=e}if(n)for(o=n;o&&o!==e;){const t=o.parentElement;if(!t||t===e)break;if(this._DOM.getFirstElementChild(t)!==o)break;n=t,o=t}else n=e;return this.getTop(n)>t?n:null}insertForcedPageBreakBefore(e){const t=this.create(this._selector.printForcedPageBreak);return this._DOM.insertBefore(e,t),t}insertForcedPageBreakAfter(e){const t=this.create(this._selector.printForcedPageBreak);return this._DOM.insertAfter(e,t),t}replaceNodeContentsWith(e,...t){this._DOM.setInnerHTML(e,""),this._DOM.insertAtEnd(e,...t)}fitElementWithinBoundaries({element:e,height:t,width:o,vspace:n,hspace:i}){const s=n/t,r=i/o,l=s<r?s:r,a=Math.trunc(t*l),h=Math.trunc(o*l);this._DOM.setStyles(e,{height:a+"px",width:h+"px"}),this._DOM.setAttribute(e,"height",`${a}px`),this._DOM.setAttribute(e,"width",`${h}px`)}create(e,t){let o;if(e){const t=e.charAt(0);if(t.match(/[#\[\.]/))o=this._DOM.createElement("div"),this._DOM.setAttribute(o,e);else{if(!t.match(/[a-zA-Z]/))return void console.assert(!1,"Expected valid html selector ot tag name, but received:",e);o=this._DOM.createElement(e)}}else o=this._DOM.createElement("div");return t&&this._DOM.setInnerHTML(o,t),o}createNeutral(){return this.create(this._selector.neutral)}createTextLine(){return this.create(this._selector.textLine)}createTextGroup(){return this.create(this._selector.textGroup)}createWithFlagNoBreak(e){const t=this.create(this._selector.flagNoBreak);return e&&this._DOM.setStyles(t,e),t}createPrintPageBreak(){return this.create(this._selector.printPageBreak)}createComplexTextBlock(){return this.create(this._selector.complexTextBlock)}createTestNodeFrom(e){const t=this._DOM.cloneNodeWrapper(e);return this._DOM.setAttribute(t,".test-node"),this._DOM.setStyles(t,{position:"absolute",background:"rgb(255 239 177)",width:this.getMaxWidth(e)+"px"}),t}createWord(e,t){const o=this.create(this._selector.word);return this._DOM.setInnerHTML(o,e),o.dataset.index=t,o}createSignpost(e,t=24){const o=this.create();return this._DOM.setStyles(o,{display:"flex",flexWrap:"nowrap",alignItems:"center",justifyContent:"center",textAlign:"center",fontSize:"8px",fontFamily:"sans-serif",letterSpacing:"1px",textTransform:"uppercase",height:t+"px"}),e&&this._DOM.setInnerHTML(o,e),o}createTable({wrapper:e,caption:t,colgroup:o,thead:n,tfoot:i,tbody:s}){const r=e||this.create("table"),l=this.create("TBODY");return t&&this._DOM.insertAtEnd(r,t),o&&this._DOM.insertAtEnd(r,o),n&&this._DOM.insertAtEnd(r,n),s&&this._DOM.insertAtEnd(l,...s),this._DOM.insertAtEnd(r,l),i&&this._DOM.insertAtEnd(r,i),r}markProcessed(e,t){this._markupDebugMode&&this._DOM.setAttribute(e,this._selector.processed,"🏷️ "+t)}setFlagNoBreak(e){this._DOM.setAttribute(e,this._selector.flagNoBreak)}setFlagNoHanging(e,t){this._DOM.setAttribute(e,this._selector.flagNoHanging,t)}markPageStartElement(e,t){this._DOM.setAttribute(e,this._selector.pageStartMarker,t)}unmarkPageStartElement(e){this._DOM.removeAttribute(e,this._selector.pageStartMarker)}markPartNodesWithClass(e){e.forEach((e=>{this._DOM.setAttribute(e,this._selector.topCutPart),this._DOM.setAttribute(e,this._selector.bottomCutPart)})),this._DOM.removeAttribute(e.at(0),this._selector.topCutPart),this._DOM.removeAttribute(e.at(-1),this._selector.bottomCutPart)}wrapNode(e,t){this._DOM.insertBefore(e,t),this._DOM.insertAtEnd(t,e)}wrapTextNode(e){if(!this.isSignificantTextNode(e))return;const t=this.create(this._selector.textNode);return this._DOM.insertBefore(e,t),this._DOM.insertAtEnd(t,e),t}getTop(e,t=null,o=0){if(!e)return void(this._debug._&&console.warn("element must be provided, but was received:",e,"\nThe function returned:",void 0));if(null===t)return this._DOM.getElementOffsetTop(e);if(!t)return void(this._debug._&&console.warn("root must be provided, but was received:",t,"\nThe function returned:",void 0));const n=this._DOM.getElementOffsetParent(e);if(!n)return void(this._debug._&&console.warn("Element has no offset parent.","\n element:",[e],"\n offsetParent:",n,"\n The function returned:",void 0));const i=this._DOM.getElementOffsetTop(e);return n===t?i+o:this.getTop(n,t,o+i)}getBottom(e,t=null){if(e){if(null===t)return this._DOM.getElementOffsetBottom(e);if(t)return this.getTop(e,t)+this._DOM.getElementOffsetHeight(e);this._debug._&&console.warn("root must be provided, but was received:",t,"\nThe function returned:",void 0)}else this._debug._&&console.warn("element must be provided, but was received:",e,"\nThe function returned:",void 0)}getHeightWithMargin(e){const t=parseInt(this._DOM.getComputedStyle(e).marginTop),o=parseInt(this._DOM.getComputedStyle(e).marginBottom);return this._DOM.getElementOffsetHeight(e)+t+o}getBottomWithMargin(e,t){const o=this.create();e&&this._DOM.insertAfter(e,o);const n=e?this.getTop(o,t):void 0;return this._DOM.removeNode(o),n}getTopWithMargin(e,t){const o=parseInt(this._DOM.getComputedStyle(e).marginTop);return this.getTop(e,t)-o}getMaxWidth(e){const t=this.create();this._DOM.insertAtEnd(e,t);const o=this._DOM.getElementOffsetWidth(t);return this._DOM.removeNode(t),o}getEmptyNodeHeight(e,t=!0){const o=this.create();t&&this._DOM.setStyles(o,{padding:"0.1px"});const n=this._DOM.cloneNodeWrapper(e);"TABLE"===this._DOM.getElementTagName(e)&&this._DOM.setInnerHTML(n,"<tr><td></td></tr>"),this._DOM.insertAtEnd(o,n),this._DOM.insertBefore(e,o);const i=this._DOM.getElementOffsetHeight(o);return this._DOM.removeNode(o),i}getLineHeight(e){const t=this.createNeutral();this._DOM.setInnerHTML(t,"!"),this._DOM.setStyles(t,{display:"block"}),this._DOM.insertAtEnd(e,t);const o=this._DOM.getElementOffsetHeight(t);return this._DOM.removeNode(t),o}getTableRowHeight(e,t=0){const o=this._DOM.getElementOffsetTop(e),n=this._DOM.cloneNode(e),i="!<br />".repeat(t);[...n.children].forEach((e=>this._DOM.setInnerHTML(e,i))),this._DOM.insertBefore(e,n);const s=this._DOM.getElementOffsetTop(e);return this._DOM.removeNode(n),s-o}copyNodeWidth(e,t){this._DOM.setStyles(e,{width:`${this._DOM.getElementOffsetWidth(t)}px`,"min-width":`${this._DOM.getElementOffsetWidth(t)}px`})}lockTableWidths(e){this.copyNodeWidth(e,e),this.getAll("td",e).forEach((e=>this.copyNodeWidth(e,e)))}prepareSplittedNode(e){const t=e,o=this.splitByWordsGreedy(e),n=o.map((e=>{const t=this._DOM.createElement("span");return this._DOM.setInnerHTML(t,e+" "),t})),i=this.createTestNodeFrom(e);return this._DOM.insertAtEnd(i,...n),this._DOM.insertAtEnd(e,i),{splittedNode:t,nodeWords:o,nodeWordItems:n}}splitByLinesGreedy(e){return e.split(/(?<=\n)/)}splitByWordsGreedy(e){return(this._DOM.getNodeValue(e)||this._DOM.getInnerHTML(e)).split(/(?<=\s|-)/)}splitByWordsGreedyWithSpacesFilter(e){return(this._DOM.getNodeValue(e)||this._DOM.getInnerHTML(e)).trim().split(/(?<=\s|-)/).filter((e=>" "!=e))}notSolved(e){this._DOM.getElementTagName(e);return!1}}function h(e){return e?.length?e?.split(/\s+/).filter(Boolean):[]}class d{constructor({config:e,DOM:t,node:o,selector:n}){this._debug=e.debugMode?{...e.debugConfig.paragraph}:{},this._DOM=t,this._selector=n,this._node=o,this._minParagraphLeftLines=2,this._minParagraphDanglingLines=2,this._minParagraphBreakableLines=this._minParagraphLeftLines+this._minParagraphDanglingLines||2}init(){this._debug._&&console.log("🚨 init Paragraph")}split(e){return this._splitComplexTextBlockIntoLines(e)}_getLines(e){return Math.ceil(this._DOM.getElementOffsetHeight(e)/this._node.getLineHeight(e))}_splitComplexTextBlockIntoLines(e){if(this._debug._&&console.group("_splitComplexTextBlockIntoLines",[e]),this._node.isSelectorMatching(e,this._selector.splitted))return this._end(this._selector.splitted),this._DOM.getChildren(e);const t=this._node.getPreparedChildren(e),o=t.map((e=>{const t=this._node.getLineHeight(e),o=this._DOM.getElementOffsetHeight(e),n=this._DOM.getElementOffsetLeft(e),i=this._DOM.getElementOffsetTop(e);return{element:e,lines:Math.ceil(o/t),left:n,top:i,height:o,lineHeight:t,text:this._DOM.getInnerHTML(e)}}));this._debug._&&console.log("\n🚸 nodeChildren",[...t],"\n🚸 extendedChildrenArray",[...o]);const n=o.flatMap((e=>e.lines>1&&!this._node.isNoBreak(e.element)?this._breakItIntoLines(e.element):e.element));this._debug._&&console.log("\n🚸🚸🚸\n partiallyLinedChildren",[...n]);const i=n.reduce(((e,t,o,n)=>(e||(e=[]),"BR"===this._DOM.getElementTagName(t)?(e.at(-1).push(t),e.push([]),this._debug._&&console.log("br; push:",t),e):!e.length||this._node.isLineChanged(e.at(-1).at(-1),t)?(e.push([t]),this._debug._&&console.log("◼️ start new line:",t),e):0===e.at(-1).length||e.length&&this._node.isLineKept(e.at(-1).at(-1),t)?(this._debug._&&console.log("⬆ add to line:",t),e.at(-1).push(t),e):void(this._debug._&&console.assert(!0,"groupedPartiallyLinedChildren: An unexpected case of splitting a complex paragraph into lines.","\nOn the element:",t)))),[]);if(this._debug._&&console.log("🟡🟡🟡 groupedPartiallyLinedChildren \n",i.length,[...i]),i.length<this._minParagraphBreakableLines)return this._debug._&&console.log("groupedPartiallyLinedChildren.length < this._minParagraphBreakableLines",i.length,"<",this._minParagraphBreakableLines),this._end("NOT _splitComplexTextBlockIntoLines"),[];const s=i.slice(0,this._minParagraphLeftLines).flat(),r=i.slice(-this._minParagraphDanglingLines).flat();this._debug._&&console.log("groupedPartiallyLinedChildren",[...i],"\n","minLeftLines =",this._minParagraphLeftLines,"\n",s,"\n","minDanglingLines =",this._minParagraphDanglingLines,"\n",r),i.splice(0,this._minParagraphLeftLines,s),i.splice(-this._minParagraphDanglingLines,this._minParagraphDanglingLines,r);const l=i.map(((e,t)=>{let o;if(0==e.length)o=e[0],o.setAttribute("role","🚫"),console.assert(0==e.length,"The string cannot be empty (_splitComplexTextBlockIntoLines)");else if(1==e.length)o=e[0];else{o=this._node.createTextGroup(),this._DOM.insertBefore(e[0],o),this._DOM.insertAtEnd(o,...e)}return o.dataset.child=t,o}));return this._end("OK _splitComplexTextBlockIntoLines"),this._DOM.setAttribute(e,this._selector.splitted),l}_breakItIntoLines(e){if(this._debug._&&console.group("_breakItIntoLines",[e]),this._node.isNoBreak(e))return this._end("isNoBreak"),e;if(this._node.isWrappedTextNode(e)){const t=this._breakWrappedTextNodeIntoLines(e);return this._end("TextNode newLines"),t}return this._end("(recursive _breakItIntoLines)"),this._processNestedInlineElements(e)}_processNestedInlineElements(e){this._debug._&&console.group("_processNestedInlineElements",[e]);const t=this._getNestedInlineChildren(e).flatMap((e=>this._getLines(e)>1?this._breakItIntoLines(e):e)),o=this._findNewLineStarts(t),n=o.map(((n,i)=>{const s=t[n],r=t[o[i+1]];return this._cloneAndCleanOutsideRange(e,s,r)}));return this._DOM.insertInsteadOf(e,...n),this._end("Nested Inline parts"),n}_cloneAndCleanOutsideRange(e,t,o){t&&t.setAttribute("split","start"),o&&o.setAttribute("split","end");let n=e.cloneNode(!0);if(t){let t=n.querySelector('[split="start"]'),o=t.previousElementSibling;for(;o;){let e=o;o=o.previousElementSibling,e.remove()}let i=t.parentElement;for(;i&&i!==e;){let e=i.previousElementSibling;for(;e;){let t=e;e=e.previousElementSibling,t.remove()}i=i.parentElement}t.removeAttribute("split")}if(o){let t=n.querySelector('[split="end"]'),o=t.nextElementSibling;for(;o;){let e=o;o=o.nextElementSibling,e.remove()}let i=t.parentElement;for(;i&&i!==e;){let e=i.nextElementSibling;for(;e;){let t=e;e=e.nextElementSibling,t.remove()}i=i.parentElement}t.remove()}return t&&t.removeAttribute("split"),o&&o.removeAttribute("split"),n}_getNestedInlineChildren(e){return[...this._DOM.getChildNodes(e)].reduce(((e,t)=>{if(this._node.isSignificantTextNode(t))return e.push(this._node.wrapTextNode(t)),e;if(!this._DOM.getElementOffsetParent(t)){const o=this._node.getPreparedChildren(t);return o.length>0&&e.push(...o),e}if(this._DOM.isElementNode(t)){return this._getNestedInlineChildren(t).forEach((t=>e.push(t))),e}}),[])}_makeWordsFromTextNode(e){const t=this._node.splitByWordsGreedy(e);this._debug._&&console.log("wordArray",t);const o=t.map(((e,t)=>this._node.createWord(e+"",t)));return this._debug._&&console.log("wrappedWordArray",o),{wordArray:t,wrappedWordArray:o}}_breakWrappedTextNodeIntoLines(e){e.classList.add("🔠_breakItIntoLines");const{wordArray:t,wrappedWordArray:o}=this._makeWordsFromTextNode(e);this._DOM.setInnerHTML(e,""),this._DOM.insertAtEnd(e,...o);const n=this._findNewLineStarts(o),i=n.reduce(((o,i,s)=>{const r=this._node.createTextLine(),l=n[s],a=n[s+1],h=t.slice(l,a).join("")+"";return this._DOM.setInnerHTML(r,h),this._DOM.insertBefore(e,r),o.push(r),o}),[]);return e.remove(),i}_findNewLineStarts(e){return e.reduce(((t,o,n)=>(n>0&&e[n-1].offsetTop+e[n-1].offsetHeight<=o.offsetTop&&t.push(n),t)),[0])}_end(e){this._debug._&&console.log(`%c ▲ ${e} `,"background:#eee;color:#888;padding: 0 1px 0 0;"),this._debug._&&console.groupEnd()}}const g="#66CC00",c=`color: ${g};font-weight:bold`,p=`border:1px solid ${g};background:#EEEEEE;color:${g};`,_="background:#999;color:#FFF;padding: 0 4px;";class u{constructor({config:e,DOM:t,node:o,selector:n,layout:i,referenceWidth:s,referenceHeight:r}){this._debug=e.debugMode?{...e.debugConfig.pages}:{},this._selector=n,this._node=o,this._noHangingSelectors=h(e.noHangingSelectors),this._pageBreakBeforeSelectors=h(e.pageBreakBeforeSelectors),this._pageBreakAfterSelectors=h(e.pageBreakAfterSelectors),this._forcedPageBreakSelectors=h(e.forcedPageBreakSelectors),this._noBreakSelectors=h(e.noBreakSelectors),this._garbageSelectors=h(e.garbageSelectors),this._DOM=t,this._paragraph=new d({config:e,DOM:t,node:o,selector:n}),this._paragraph.init(),this._root=i.root,this._contentFlow=i.contentFlow,this._referenceWidth=s,this._referenceHeight=r,this._minLeftLines=2,this._minDanglingLines=2,this._minBreakableLines=this._minLeftLines+this._minDanglingLines,this._minLeftRows=1,this._minDanglingRows=1,this._minBreakableRows=this._minLeftRows+this._minDanglingRows,this._minPreFirstBlockLines=3,this._minPreLastBlockLines=3,this._minPreBreakableLines=this._minPreFirstBlockLines+this._minPreLastBlockLines,this._minBreakableGridRows=4,this._imageReductionRatio=.8,this._signpostHeight=24,this._commonLineHeight=this._node.getLineHeight(this._root),this._minimumBreakableHeight=this._commonLineHeight*this._minBreakableLines,this._isFirefox="undefined"!=typeof InstallTrigger,this.pages=[]}calculate(){return this._removeGarbageElements(),this._prepareForcedPageBreakElements(),this._prepareNoBreakElements(),this._prepareNoHangingElements(),this._calculate(),this._debug._&&console.log("%c ✔ Pages.calculate()",p,this.pages),this.pages}_removeGarbageElements(){if(this._garbageSelectors.length){this._node.getAll(this._garbageSelectors,this._contentFlow).forEach((e=>{this._DOM.removeNode(e)}))}}_prepareNoHangingElements(){if(this._noHangingSelectors.length){this._node.getAll(this._noHangingSelectors,this._contentFlow).forEach((e=>{this._node.setFlagNoHanging(e);const t=this._node.findLastChildParent(e,this._contentFlow);t&&this._node.setFlagNoHanging(t,"parent")}))}}_prepareNoBreakElements(){if(this._noBreakSelectors.length){this._node.getAll(this._noBreakSelectors,this._contentFlow).forEach((e=>this._node.setFlagNoBreak(e)))}}_prepareForcedPageBreakElements(){const e=this._pageBreakBeforeSelectors.length?this._node.getAll(this._pageBreakBeforeSelectors,this._contentFlow):[],t=this._pageBreakAfterSelectors.length?this._node.getAll(this._pageBreakAfterSelectors,this._contentFlow):[],o=this._node.getAll(this._forcedPageBreakSelectors,this._contentFlow);if(e.length){const t=e[0],o=this._node.findFirstChildParent(t,this._contentFlow)||t,n=this._DOM.getLeftNeighbor(o);this._node.isContentFlowStart(n)&&(console.log(e[0]),e.shift())}if(t.length){const e=t.at(-1),o=this._node.findLastChildParent(e,this._contentFlow)||e,n=this._DOM.getRightNeighbor(o);this._node.isContentFlowEnd(n)&&t.pop()}e.length&&e.forEach((e=>{const t=this._node.findFirstChildParent(e,this._contentFlow);t&&(e=t),this._node.insertForcedPageBreakBefore(e)})),o&&o.forEach((e=>{if(!this._node.isForcedPageBreak(e)){const t=this._node.findFirstChildParent(e,this._contentFlow);t&&(e=t),this._node.insertForcedPageBreakBefore(e)}})),t.length&&t.forEach((e=>{const t=this._node.findLastChildParent(e,this._contentFlow);t&&(e=t),this._node.isForcedPageBreak(e.nextElementSibling)||this._node.insertForcedPageBreakAfter(e)}))}_calculate(){this._debug._&&console.groupCollapsed("•• init data ••"),this._debug._&&console.log("this._referenceHeight",this._referenceHeight,"\n","this._noHangingSelectors",this._noHangingSelectors,"\n","this._pageBreakBeforeSelectors",this._pageBreakBeforeSelectors,"\n","this._pageBreakAfterSelectors",this._pageBreakAfterSelectors,"\n","this._forcedPageBreakSelectors",this._forcedPageBreakSelectors,"\n","this._noBreakSelectors",this._noBreakSelectors,"\n","isFirefox",this._isFirefox),this._debug._&&console.groupEnd("•• init data ••"),this._registerPageStart(this._node.get(this._selector.contentFlowStart,this._contentFlow));const e=this._node.getBottomWithMargin(this._contentFlow,this._root);if(e<this._referenceHeight)return this._debug._&&console.log(`contentFlow (${e}) fits on the page (${this._referenceHeight})`),void this._node.findAllForcedPageBreakInside(this._contentFlow).forEach((e=>this._registerPageStart(e)));const t=this._node.getPreparedChildren(this._contentFlow);this._debug._&&console.groupCollapsed("%c🚸 children(contentFlow)",p),this._debug._&&console.log(t),this._debug._&&console.groupEnd("%c🚸 children(contentFlow)",p),this._parseNodes({array:t})}_registerPageStart(e,t=!1){t&&(e=this._node.findBetterPageStart(e,this.pages.at(-1)?.pageStart,this._contentFlow,this._root));const o=this._node.getTopWithMargin(e,this._root)+this._referenceHeight;this.pages.push({pageStart:e,pageBottom:o}),this._node.markPageStartElement(e,this.pages.length),this._debug._registerPageStart&&console.log(`%c📍register page ${this.pages.length}`,"background:yellow;font-weight:bold","\n pageBottom:",o,"\n pageStart:",e)}_parseNodes({array:e,previous:t,next:o,parent:n,parentBottom:i}){this._debug._parseNodes&&console.log("🔵 _parseNodes","\narray:",[...e],"\ntracedParent:",n);for(let s=0;s<e.length;s++)this._parseNode({previousElement:e[s-1]||t,currentElement:e[s],nextElement:e[s+1]||o,isCurrentFirst:0==s&&!e[s-1],parent:n,parentBottom:s===e.length-1?i:void 0})}_parseNode({isCurrentFirst:e,previousElement:t,currentElement:o,nextElement:n,parent:i,parentBottom:s}){const r=["%c_parseNode\n","color:white"];if(this._debug._parseNode&&console.group("%c_parseNode",c,""+(s?"★last★":"regular")),this._debug._parseNode&&console.log(...r,"3 nodes: ",{previousElement:t,currentElement:o,nextElement:n},"\n","\ncurrent: ",o,"\nparent: ",i,"\nisCurrentFirst: ",e),this._debug._parseNode&&console.log(...r,"parent:",i,"\n","parentBottom:",s,"\n","isCurrentFirst:",e,"\n","parent:",i,"\n"),!n)return this._node.markProcessed(o,"content-flow-end"),this._debug._parseNode&&console.log("%c END _parseNode (!nextElement)",_),void(this._debug._parseNode&&console.groupEnd());const l=s||this._node.getBottomWithMargin(o,this._root),a=this.pages.at(-1).pageBottom;if(this.pages.at(-1).pageStart===o&&(this._node.isNoBreak(o)||l<=a))return this._node.markProcessed(o,"node is already registered and fits in the page"),this._debug._parseNode&&console.log("%c END _parseNode (node is already registered and fits in the next page)",_),void(this._debug._parseNode&&console.groupEnd());if(this._node.isForcedPageBreak(o))return this._registerPageStart(o),this._node.markProcessed(o,"node is ForcedPageBreak"),this._debug._parseNode&&console.log("%c END _parseNode (isForcedPageBreak)",_),void(this._debug._parseNode&&console.groupEnd());this._debug._&&console.assert(this._DOM.getElementOffsetParent(o),"it is expected that the element has an offset parent",o);const h=this._node.getTop(n,this._root);if(this._debug._parseNode&&console.log(...r,"• newPageBottom",a,"\n","• nextElementTop",h),h<=a)this._debug._parseNode&&console.log("nextElementTop <= newPageBottom",h,"<=",a),this._node.markProcessed(o,"node fits"),this._node.findAllForcedPageBreakInside(o).forEach((e=>{this._node.markProcessed(e,"node is ForcedPageBreak (inside a node that fits)"),this._registerPageStart(e)}));else{if(this._debug._parseNode&&console.log("nextElementTop > newPageBottom",h,">",a),this._node.isSVG(o)||this._node.isIMG(o)||this._node.isOBJECT(o)){const e=this._node.isSVG(o)?this._node.createSignpost(o):o;let t=i?a-this._node.getTop(e,this._root):a-this._node.getTop(i,this._root);t-=s?s-this._node.getBottom(e,this._root):0;let r=this._referenceHeight-(i?this._node.getTop(e,this._root)-this._node.getTop(i,this._root):0);const l=this._DOM.getElementOffsetHeight(e),h=this._DOM.getElementOffsetWidth(e);if(this._debug._parseNode&&console.log("🖼️🖼️🖼️🖼️🖼️🖼️\n",`H-space: ${t}, image Height: ${l}, image Width: ${h}`,o,"\n parent",i,"parentBottom",s),l<this._referenceWidth&&this._debug._parseNode&&console.warn("%c IMAGE is too wide","color: red"),l<t)return this._node.markProcessed(o,"IMG that fits, and next starts on next"),this._registerPageStart(n),this._debug._parseNode&&console.log("Register next elements; 🖼️🖼️🖼️ IMG fits:",o),this._debug._parseNode&&console.log("%c END _parseNode 🖼️ IMG fits",_),void(this._debug._parseNode&&console.groupEnd());const d=t/l;return d>this._imageReductionRatio?(this._debug._parseNode&&console.log("Register next elements; 🖼️🖼️🖼️ IMG RESIZE to availableImageNodeSpace:",t,o),this._node.markProcessed(o,`IMG with ratio ${d}, and next starts on next`),this._node.fitElementWithinBoundaries({element:o,height:l,width:h,vspace:t,hspace:this._referenceWidth}),this._registerPageStart(n),this._debug._parseNode&&console.log("%c END _parseNode 🖼️ IMG scaled",_),void(this._debug._parseNode&&console.groupEnd())):(this._node.markProcessed(o,"IMG starts on next"),this._registerPageStart(e,!0),this._debug._parseNode&&console.log("🖼️ register Page Start",o),l>r&&(this._node.fitElementWithinBoundaries({element:o,height:l,width:h,vspace:r,hspace:this._referenceWidth}),this._node.markProcessed(o,"IMG starts on next and resized"),this._debug._parseNode&&console.log("🖼️ ..and fit it to full page",o)),this._debug._parseNode&&console.log("%c END",_),void(this._debug._parseNode&&console.groupEnd()))}if(o.style.height){this._debug._parseNode&&console.log("🥁 currentElement has HEIGHT",o.style.height);const e=this._node.getTop(o,this._root),t=a-e,i=h-e,s=t/i,r=this._referenceHeight/i;return this._debug._parseNode&&console.log("\n🥁 currentElementTop",e,"\n🥁 newPageBottom",a,"\n🥁 availableSpace",t,"\n🥁 currentElementContextualHeight",i,"\n🥁 availableSpaceFactor",s,"\n🥁 fullPageFactor",r),console.assert(s<1),s>.8?(this._debug._parseNode&&console.log("🥁 availableSpaceFactor > 0.8: ",s),this._DOM.setStyles(o,{transform:`scale(${s})`}),this._registerPageStart(n),this._node.markProcessed(o,"processed as a image, has been scaled down within 20%, the next one starts a new page"),this._node.markProcessed(n,"the previous one was scaled down within 20%, and this one starts a new page."),this._debug._parseNode&&console.log("%c END _parseNode (has height & scale)",_),void(this._debug._parseNode&&console.groupEnd())):(r<1&&(this._debug._parseNode&&console.log("🥁 fullPageFactor < 1: ",r),this._node.markProcessed(o,"processed as a image, has been scaled down, and starts new page"),this._DOM.setStyles(o,{transform:`scale(${r})`})),this._debug._parseNode&&console.log("🥁 _registerPageStart",o),this._registerPageStart(o),this._node.markProcessed(o,"processed as a image, starts new page"),this._debug._parseNode&&console.log("%c END _parseNode (has height & put on next page)",_),void(this._debug._parseNode&&console.groupEnd()))}if(this._debug._parseNode&&console.log("split or not? \n","currentElementBottom",l),l<=a)return this._debug._parseNode&&console.log("currentElementBottom <= newPageBottom",l,"<=",a,"\n register nextElement as pageStart"),this._node.isNoHanging(o)?(this._debug._parseNode&&console.log("currentElement fits / last, and _isNoHanging => move it to the next page"),this._node.markProcessed(o,"it fits & last & _isNoHanging => move it to the next page"),this._registerPageStart(o,!0),this._debug._parseNode&&console.log("%c END _parseNode (isNoHanging)",_),void(this._debug._parseNode&&console.groupEnd())):(this._registerPageStart(n),this._node.markProcessed(o,"fits, its bottom falls exactly on the cut"),this._node.markProcessed(n,"starts new page, its top is exactly on the cut"),this._debug._parseNode&&console.log("%c END _parseNode (currentElement fits, register the next element)",_),void(this._debug._parseNode&&console.groupEnd()));this._debug._parseNode&&console.log("currentElementBottom > newPageBottom",l,">",a);const d=this._getProcessedChildren(o,a,this._referenceHeight);this._debug._parseNode&&console.log("try to break it and loop the children:",d);const g=d.length;this._debug._parseNode&&console.log(...r,"childrenNumber ",g),this._debug._parseNode&&console.log(...r,"currentElement ",o);const c=e&&i||o;if(g){const e=this._node.isFullySPlitted(o)||this._node.isSlough(o);this._parseNodes({array:d,previous:t,next:n,parent:e?void 0:c,parentBottom:e?void 0:l}),this._node.markProcessed(o,"getProcessedChildren and _parseNodes")}else if(this._node.isNoHanging(t)){const e=this._node.findSuitableNonHangingPageStart(t,this.pages.at(-2)?.pageBottom)||o;this._registerPageStart(e,!0),this._node.markProcessed(o,"doesn't fit, has no children, isNoHanging(previousElement)"),this._node.markProcessed(t,"isNoHanging - register it or parents")}else this._debug._parseNode&&console.log(...r,"_registerPageStart (from _parseNode): \n",o),this._registerPageStart(o,!0),this._node.markProcessed(o,"doesn't fit, has no children, register it or parents")}this._debug._parseNode&&console.log("%c END _parseNode",_),this._debug._parseNode&&console.groupEnd()}_getProcessedChildren(e,t,o){const n=["%c_getProcessedChildren\n","color:white"];let i=[];if(this._node.isNoBreak(e))return this._debug._getProcessedChildren&&console.info(...n,"🧡 isNoBreak",e),[];if(this._node.isComplexTextBlock(e))return this._debug._getProcessedChildren&&console.info(...n,"💚 ComplexTextBlock",e),this._paragraph.split(e)||[];if(this._node.isWrappedTextNode(e))return this._debug._getProcessedChildren&&console.info(...n,"💚 TextNode",e),this._paragraph.split(e)||[];const s=this._DOM.getComputedStyle(e);return this._node.isTableLikeNode(e,s)?(this._debug._getProcessedChildren&&console.info(...n,"💚 TABLE like",e),i=this._splitTableLikeNode(e,t,o,s)||[]):this._node.isTableNode(e,s)?(this._debug._getProcessedChildren&&console.info(...n,"💚 TABLE",e),i=this._splitTableNode(e,t,o,s)||[]):this._node.isPRE(e,s)?(this._debug._getProcessedChildren&&console.info(...n,"💚 PRE",e),i=this._splitPreNode(e,t,o)||[]):this._node.isGridAutoFlowRow(this._DOM.getComputedStyle(e))?(this._debug._getProcessedChildren&&console.info(...n,"💜 GRID"),i=this._splitGridNode(e,t,o)||[]):(this._debug._getProcessedChildren&&console.info(...n,"💚 some node",e),i=this._node.getPreparedChildren(e),this._debug._getProcessedChildren&&console.info(...n,"🚸 get element children ",i)),i}_splitPreNode(e,t,o,n){const i=n||this._DOM.getComputedStyle(e),s=["%c_splitPreNode\n","color:white"];this._debug._splitPreNode&&console.group("%c_splitPreNode","background:cyan"),this._debug._splitPreNode&&console.log(...s,"node",e);const r=this._node.getTop(e,this._root),l=this._DOM.getElementOffsetHeight(e),a=this._node.getLineHeight(e),h=this._node.getEmptyNodeHeight(e,!1);if(l<h+a*this._minPreBreakableLines)return this._debug._splitPreNode&&console.log("%c END _splitPreNode (small node)",_),[];const d=this._DOM.getChildNodes(e);if(this._debug._splitPreNode&&console.log("_children:",d.length),0==d.length)return this._debug._splitPreNode&&console.log("%c END _splitPreNode (not breakable)",_),[];if(d.length>1)return this._debug._splitPreNode&&console.log("%c END _splitPreNode TODO!",_),[];{if(this._DOM.isElementNode(d[0])){const e=d[0];return this._debug._splitPreNode&&console.warn("is Element Node",e),this._debug._splitPreNode&&console.log("%c END _splitPreNode ???????",_),[]}this._node.isWrappedTextNode(d[0])&&this._debug._splitPreNode&&console.warn(`is TEXT Node: ${d[0]}`);const n=d[0].wholeText,l=this._node.splitByLinesGreedy(n);if(l.length<this._minPreBreakableLines)return this._debug._splitPreNode&&console.log("%c END _splitPreNode few lines",_),[];const a=l.splice(0,this._minPreFirstBlockLines).join(""),g=l.splice(-this._minPreLastBlockLines).join("");l.unshift(a),l.push(g);const c=l.map((e=>{const t=this._node.createWithFlagNoBreak();return this._DOM.setInnerHTML(t,e),t}));this._debug._splitPreNode&&console.log("linesFromNode",c),this._node.replaceNodeContentsWith(e,...c);const p=o-h;let u=0,m=[],f=t-r-h;const b=i.position;"relative"!=b&&this._DOM.setStyles(e,{position:"relative"});for(let t=0;t<c.length;t++){const o=c[t];this._node.getBottom(o,e)>f&&(t&&m.push(t),t&&(u+=1),f=t?this._node.getTop(o,e)+p:p)}if(this._DOM.setStyles(e,{position:b}),!m.length)return this._debug._splitPreNode&&console.log("%c END _splitPreNode NO SPLIITERS",_),[];m.push(null),this._debug._splitPreNode&&console.log(...s,"splitters",m);const M=m.map(((t,o,n)=>{const i=this._DOM.cloneNodeWrapper(e);this._node.setFlagNoBreak(i);const s=n[o-1]||0,r=t||n[n.length];return this._DOM.insertAtEnd(i,...c.slice(s,r)),i}));return this._node.markPartNodesWithClass(M),this._debug._splitPreNode&&console.log(...s,"newPreElementsArray",M),this._node.replaceNodeContentsWith(e,...M),this._DOM.setStyles(e,{display:"contents"}),this._DOM.setAttribute(e,"[slough-node]",""),this._DOM.removeAllClasses(e),this._debug._splitPreNode&&console.log("%c END _splitPreNode",_),this._debug._splitPreNode&&console.groupEnd(),M}}_insertTableSplit({startId:e,endId:t,table:o,tableEntries:n}){const i=this._DOM.cloneNodeWrapper(o),s=n.rows.slice(e,t),r=this._node.createWithFlagNoBreak();return o.before(r),e&&this._DOM.insertAtEnd(r,this._node.createSignpost("(table continued)",this._signpostHeight)),this._DOM.insertAtEnd(r,this._node.createTable({wrapper:i,colgroup:this._DOM.cloneNode(n.colgroup),caption:this._DOM.cloneNode(n.caption),thead:this._DOM.cloneNode(n.thead),tbody:s}),this._node.createSignpost("(table continues on the next page)",this._signpostHeight)),r}_splitTableLikeNode(e,t,o,n){const i=n||this._DOM.getComputedStyle(e),s=this._node.getPreparedChildren(e),r=this._node.getTop(e,this._root),l=this._node.getEmptyNodeHeight(e),a=o-l;let h=s,d=0,g=[],c=t-r-l;const p=i.position;"relative"!=p&&this._DOM.setStyles(e,{position:"relative"});for(let t=0;t<h.length;t++){const o=h[t];this._node.getBottom(o,e)>c&&(t&&g.push(t),t&&(d+=1),c=t?this._node.getTop(o,e)+a:a)}if(this._DOM.setStyles(e,{position:p}),!g.length)return this._debug._splitTableLikeNode&&console.log("splitters.length",g.length),[];g.push(null);const _=g.map(((t,o,n)=>{const i=this._DOM.cloneNodeWrapper(e);this._node.setFlagNoBreak(i),this._node.unmarkPageStartElement(i);const s=n[o-1]||0,r=t||n[n.length];return this._DOM.insertAtEnd(i,...h.slice(s,r)),i}));return this._node.markPartNodesWithClass(_),this._node.replaceNodeContentsWith(e,..._),this._DOM.removeAllClasses(e),this._DOM.removeAllStyles(e),this._DOM.setStyles(e,{display:"contents"}),this._DOM.setAttribute(e,"[slough-node]",""),_}_splitTableNode(e,t,o){const n=["%c_splitTableNode\n","color:white"];this._debug._splitTableNode&&console.time("_splitTableNode"),this._debug._splitTableNode&&console.group("%c_splitTableNode","background:cyan"),this._node.lockTableWidths(e);const i=this._node.getEmptyNodeHeight(e),s=this._node.getTableEntries(e);this._debug._splitTableNode&&console.log(...n,e,"\ntableEntries",s);const r=this._node.getTopWithMargin(e,this._root),l=this._DOM.getElementOffsetHeight(s.caption)||0,a=this._DOM.getElementOffsetHeight(s.thead)||0,h=this._DOM.getElementOffsetHeight(s.tfoot)||0,d=(l??0)*(this._isFirefox??0),g=t-r-i-this._signpostHeight,c=o-l-a-h-i-2*this._signpostHeight;this._debug._splitTableNode&&console.log(...n,"\n • tableFirstPartBottom",g,"\n","\n pageBottom",t,"\n - tableTop",r,"\n - tableCaptionHeight",l,"\n - tableTheadHeight",a,"\n - tableWrapperHeight",i,"\n - this._signpostHeight",this._signpostHeight,"\n","\n fullPageHeight",o,"\n - tableCaptionHeight",l,"\n - tableTheadHeight",a,"\n - tableTfootHeight",h,"\n - 2 * this._signpostHeight",2*this._signpostHeight,"\n - tableWrapperHeight",i,"\n = tableFullPartContentHeight",c);const p=e=>[...e.rows,...e.tfoot?[e.tfoot]:[]];let u=p(s),m=[],f=g;this._debug._splitTableNode&&console.log(this._node.getTop(u[1],e)-this._node.getBottom(u[0],e),"(row[1].top - row[0].bottom)"),this._node.getTop(u[0],e)>f&&(f=c,this._debug._splitTableNode&&console.log("The Row 0 goes to the 2nd page"));for(let o=0;o<u.length;o++){this._debug._splitTableNode&&console.log(`%c 🟪 Check the Row # ${o}`,"color:blueviolet",[u[o]]);const n=u[o],i=this._node.getBottom(n,e)+d,r=this._node.getTop(n,e)+d,l=u[o+1];if((l?this._node.getTop(l,e)+d:i)>f){const i=o,l=n,a=this._DOM.getElementOffsetHeight(l),h=this._node.getTableRowHeight(l,this._minBreakableLines),g=this._node.getTableRowHeight(l),b=r,M=this._node.isNoBreak(l),O=a>=h&&!M;if(this._debug._splitTableNode&&console.log(`%c • Row # ${o}: try to split`,"color:blueviolet"),O){this._debug._splitTableRow&&console.groupCollapsed(`Split The ROW.${i}`);const e=f-b-g,n=c-g,r=this._DOM.getChildren(l);let a;a=[...r].map(((o,s)=>{const r=this._node.getPreparedChildren(o);this._debug._splitTableRow&&console.groupCollapsed(`Split TD.${s} in ROW.${i}`);const l=this._getInternalBlockSplitters({rootNode:o,children:r,pageBottom:t,firstPartHeight:e,fullPageHeight:n});return this._debug._splitTableRow&&console.groupEnd(`Split TD.${s} in ROW.${i}`),l})),this._debug._splitTableRow&&console.log("🟣 \ntheRowContentSlicesByTD",a);const h=a.some((e=>(this._debug._splitTableRow&&console.log("🟣","\nobj.result.length",e.result.length,"\nobj.result[0]",e.result[0]),e.result.length&&null===e.result[0])));this._debug._splitTableRow&&console.log("🟣","\nshouldFirstPartBeSkipped",h),h&&(a=[...r].map((e=>{const o=this._node.getPreparedChildren(e);return this._getInternalBlockSplitters({rootNode:e,children:o,pageBottom:t,firstPartHeight:n,fullPageHeight:n})}))),this._debug._splitTableRow&&console.log("🟣","\n theRowContentSlicesByTD",a);const d=a.some((e=>e.result.length));if(this._debug._splitTableRow&&console.log("🟣 ifThereIsSplit",d),d){const e=a.map((e=>{if(e.result.length)return this._createSlicesBySplitFlag(e.trail);{const t=this._node.createWithFlagNoBreak();t.classList.add("🟣"),this._DOM.setStyles(t,{display:"contents"});const o=e.trail.map((e=>e.element));return this._DOM.insertAtEnd(t,...o),[t]}}));this._debug._splitTableRow&&console.log("🟣 theTdContentElements",e);const t=Math.max(...e.map((e=>e.length)));this._debug._splitTableRow&&console.log("🟣 theNewTrCount",t);const n=[];for(let o=0;o<t;o++){const t=this._DOM.cloneNodeWrapper(l);this._node.setFlagNoBreak(t),this._DOM.setAttribute(t,`.splitted_row_${i}_part_${o}`),[...r].forEach(((n,i)=>{const s=this._DOM.cloneNodeWrapper(n);e[i][o]&&this._DOM.insertAtEnd(s,e[i][o]),this._DOM.insertAtEnd(t,s)})),n.push(t)}this._debug._splitTableRow&&console.log("🟣","\n theNewRows",n),this._DOM.setAttribute(l,".🚫_must_be_removed"),this._debug._splitTableRow&&console.log("🟣 splittingRow",l),this._DOM.insertInsteadOf(l,...n),s.rows.splice(i,1,...n),u=p(s),o-=1}this._debug._splitTableRow&&console.log(`%c END 🟪 Split The ROW.${i}`,_),this._debug._splitTableRow&&console.groupEnd("END OF 'if makesSenseToSplitTheRow'")}else this._debug._splitTableNode&&console.log(`%c • Row # ${o}: small or noBreak`,"color:blueviolet"),o>=this._minLeftRows&&(m.push(o),this._debug._splitTableNode&&console.log(`%c • Row # ${o}: REGISTER as start, index >= ${this._minLeftRows} (_minLeftRows) `,"color:blueviolet")),f=this._node.getTop(u[o],e)+d+c}else this._debug._splitTableNode&&console.log(`%c • Row # ${o}: PASS ...`,"color:blueviolet")}if(this._debug._splitTableNode&&console.log(...n,"splitsIds",m),!m.length)return this._debug._splitTableNode&&console.log("%c END _splitTableNode !splitsIds.length",_),this._debug._splitTableNode&&console.groupEnd(),[];const b=u.length-1-this._minDanglingRows;m[m.length-1]>b&&(m[m.length-1]=b);const M=m.map(((t,o,n)=>this._insertTableSplit({startId:n[o-1]||0,endId:t,table:e,tableEntries:s})));this._debug._splitTableNode&&console.log(...n,"splits",M);const O=this._node.createWithFlagNoBreak();return e.before(O),this._DOM.insertAtEnd(O,this._node.createSignpost("(table continued)",this._signpostHeight),e),this._debug._splitTableNode&&console.timeEnd("_splitTableNode"),this._debug._splitTableNode&&console.log("%c END _splitTableNode",_),this._debug._splitTableNode&&console.groupEnd(),[...M,O]}_createSlicesBySplitFlag(e){this._debug._createSlicesBySplitFlag&&console.group("_createSlicesBySplitFlag");const t=this._node.createWithFlagNoBreak();this._DOM.setStyles(t,{display:"contents"}),t.classList.add("🧰");const o=[t];let n=[t],i=t;const s=e=>{if(0===e.length)return null;const t=e[0];let o=t;for(let t=1;t<e.length;t++){const n=e[t];this._DOM.insertAtEnd(o,n),o=n}return this._debug._createSlicesBySplitFlag&&console.log(" createWrapperFromArray:",t),t},r=(e,t=null)=>{this._debug._createSlicesBySplitFlag&&console.group("processChildren"),this._debug._createSlicesBySplitFlag&&console.log("*start* children",e);for(let t=0;t<e.length;t++)l(e[t]);this._debug._createSlicesBySplitFlag&&console.log("- wrappers BEFORE pop:",[...n]);const o=n.pop();this._debug._createSlicesBySplitFlag&&console.log("- wrappers.pop()",o),this._debug._createSlicesBySplitFlag&&console.log("- parent",t),this._debug._createSlicesBySplitFlag&&console.log("- wrappers AFTER pop:",[...n]),i=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("🎯🎯 currentTargetInSlice",i),this._debug._createSlicesBySplitFlag&&console.log("🎯 wrappers.at(-1)",n.at(-1)),this._debug._createSlicesBySplitFlag&&console.log("*END* children",e),this._debug._createSlicesBySplitFlag&&console.log("%c END processChildren",_),this._debug._createSlicesBySplitFlag&&console.groupEnd()},l=e=>{const t=e.children?.length>0,l=e.split,a=e.element,h=e.id;if(this._debug._createSlicesBySplitFlag&&console.group(`processObj # ${h}`),this._debug._createSlicesBySplitFlag&&console.log("currentElement",a),a&&this._DOM.removeNode(a),l){this._debug._createSlicesBySplitFlag&&console.log("••• hasSplitFlag"),n=n.map((e=>{const t=this._DOM.cloneNodeWrapper(e);return t.classList.add("🚩"),t})),this._debug._createSlicesBySplitFlag&&console.log("• hasSplitFlag: NEW wrappers.map:",[...n]);const e=s(n);o.push(e),this._debug._createSlicesBySplitFlag&&console.log("• hasSplitFlag: slices.push(nextWrapper):",[...o]),i=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("• hasSplitFlag: currentTargetInSlice:",i)}if(t){this._debug._createSlicesBySplitFlag&&console.log("••• hasChildren");const t=this._DOM.cloneNodeWrapper(a);n.push(t),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: wrappers.push(cloneCurrentElementWrapper)",t,[...n]),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice (check):",i),i?(this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice","TRUE, add to existing",t),this._DOM.insertAtEnd(i,t)):(this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice","FALSE, init the first",t),t.classList.add("🏁first"),this._DOM.setStyles(t,{background:"yellow"}),o.push(t),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: slices.push(cloneCurrentElementWrapper)",t,[...o])),i=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice (=):",i),r(e.children,a)}else i=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("insert currentElement",a,"to target",i),this._DOM.insertAtEnd(i,a);this._debug._createSlicesBySplitFlag&&console.log(`%c END processObj # ${h}`,_),this._debug._createSlicesBySplitFlag&&console.groupEnd()};return this._debug._createSlicesBySplitFlag&&console.log("####### currentTargetInSlice (=):",i),r(e),this._debug._createSlicesBySplitFlag&&console.log("slices:",o),this._debug._createSlicesBySplitFlag&&o.forEach((e=>console.log("slice:",e))),this._debug._createSlicesBySplitFlag&&console.log("%c END _createSlicesBySplitFlag",_),this._debug._createSlicesBySplitFlag&&console.groupEnd(),o}_getInternalBlockSplitters({rootNode:e,rootComputedStyle:t,children:o,pageBottom:n,firstPartHeight:i,fullPageHeight:s,result:r=[],trail:l=[],indexTracker:a=[],stack:h=[]}){const d=t||this._DOM.getComputedStyle(e),g=d.position;"relative"!=g&&this._DOM.setStyles(e,{position:"relative"}),this._debug._getInternalBlockSplitters&&console.group("💟 _getInternalBlockSplitters");const c=e=>{e>=0?a.push(e):a.pop()},p=(e,t)=>{this._debug._getInternalBlockSplitters&&console.assert(t>=0,"registerResult: ID mast be provided",e);let o,n=l[t];if(this._debug._getInternalBlockSplitters&&console.groupCollapsed("💜💜💜 registerResult(element, id)"),this._debug._getInternalBlockSplitters&&console.log("\n element",e,"\n id",t,"\n theElementObject (trail[id])",n,"\n theElementIndexInStack",o),0==t){const e=(e=>{let t,o=null;for(let n=e.length-1;n>=0;n--){if(0!==e[n].id)return{item:o,index:t};o=e[n],t=n}return{item:o,index:t}})(h);this._debug._getInternalBlockSplitters&&console.log("💜💜 id == 0","\n💜 [...stack]",[...h],"\n💜 topParentElementFromStack",e),e.item&&(n=e.item,o=e.index)}this._debug._getInternalBlockSplitters&&console.log("💜","\n theElementObject",n,"\n theElementIndexInStack",o,"\n [...indexTracker]",[...a]),0===o?(r.push(null),this._debug._getInternalBlockSplitters&&console.log("result.push(null)","\n\n💜💜💜")):(r.push(n.element),n&&(n.split=!0),this._debug._getInternalBlockSplitters&&console.log("\n theElementObject",n,"\n theElementObject.element",n.element,"\n result.push(theElementObject.element)","\n\n💜💜💜 ")),this._debug._getInternalBlockSplitters&&console.log("%c END _getInternalBlockSplitters registerResult",_),this._debug._getInternalBlockSplitters&&console.groupEnd()};this._debug._getInternalBlockSplitters&&console.log("💟 result 💟",r,"\n\n","\n rootNode:",e,"\n children:",o,"\n pageBottom:",n,"\n firstPartHeight:",i,"\n fullPageHeight:",s,"\n\n\n","💟 stack",[...h]);for(let t=0;t<o.length;t++){const g=o[t-1],_=o[t],u=o[t+1],m=u?this._node.getTop(u,e):void 0,f={id:t,element:o[t]},b={id:t+1,element:o[t+1]};t!==(l.length?l.at(-1).id:void 0)&&l.push(f);const M=0===r.length?i:null===r.at(-1)?s:s+this._node.getTop(r.at(-1),e);if(this._node.isForcedPageBreak(_)&&this._debug._getInternalBlockSplitters&&console.warn(_,"💟 is isForcedPageBreak"),m<=M)this._node.isNoHanging(_)&&(this._debug._getInternalBlockSplitters&&console.log("💟💟 currentElement _isNoHanging"),p(_,t));else{this._debug._getInternalBlockSplitters&&console.log("💟💟",_,`nextElementTop > floater \n ${m} > ${M} `),(this._node.isSVG(_)||this._node.isIMG(_))&&this._debug._getInternalBlockSplitters&&console.log("%cIMAGE 💟💟","color:red;text-weight:bold");const o=this._node.getBottomWithMargin(_,e);if(this._debug._getInternalBlockSplitters&&console.log("💟💟 current ???","\n currentElement",_,"\n currentElementBottom",o,"\n floater",M),o<=M)this._debug._getInternalBlockSplitters&&console.log("💟💟💟 currentElementBottom <= floater"),u&&(this._debug._getInternalBlockSplitters&&console.log("💟💟💟💟 register nextElement"),l.push(b),p(u,t+1));else{this._debug._getInternalBlockSplitters&&console.log("💟💟💟 currentElementBottom > floater,\ntry to split",_);const o=this._getProcessedChildren(_,n,s);if(o.length)c(t),h.push(f),this._getInternalBlockSplitters({rootNode:e,rootComputedStyle:d,children:o,pageBottom:n,firstPartHeight:i,fullPageHeight:s,result:r,trail:l[t].children=[],indexTracker:a,stack:h}),h.pop(),this._debug._getInternalBlockSplitters&&console.log("🟪 back from _getInternalBlockSplitters;\n trail[i]",l[t]);else if(g&&this._node.isNoHanging(g)){console.warn("tst improveResult",g);let e=g;e=this._node.findFirstChildParent(e,this._contentFlow)||e;e=this._node.findPreviousNonHangingsFromPage(e,this.pages.at(-2)?.pageBottom,this._root)||e,this._debug._getInternalBlockSplitters&&console.log("previousElement _isNoHanging"),p(e,t-1)}else this._debug._getInternalBlockSplitters&&console.log(_,"currentElement has no children"),p(_,t)}}}return c(),this._DOM.setStyles(e,{position:g}),this._debug._getInternalBlockSplitters&&console.log("%c END _getInternalBlockSplitters",_),this._debug._getInternalBlockSplitters&&console.groupEnd(),{result:r,trail:l}}_splitGridNode(e,t,o){this._debug._splitGridNode&&console.group("%c_splitGridNode","background:#00FFFF");const n=this._node.getPreparedChildren(e);this._debug._splitGridNode&&console.log("💠 children",n),this._debug._splitGridNode&&console.groupCollapsed("make childrenGroups");const i=n.reduce(((e,t,o,n)=>{const i=this._DOM.getComputedStyle(t),s=i.getPropertyValue("grid-column-start"),r=i.getPropertyValue("grid-column-end"),l={element:t,start:"auto"===s?"auto":parseInt(i.getPropertyValue("grid-column-start")),end:"auto"===r?"auto":parseInt(i.getPropertyValue("grid-column-end")),top:this._DOM.getElementOffsetTop(t)};return!e.length||e.at(-1).at(-1).start>=l.start||"auto"===e.at(-1).at(-1).start||"auto"===l.start?(e.at(-1)&&this._node.isNoHanging(e.at(-1).at(-1).element)?(e.at(-1).push(l),this._debug._splitGridNode&&console.log("Add to group (after no-hang.)",l)):(e.push([l]),this._debug._splitGridNode&&console.log("Start new group:",l)),this._debug._splitGridNode&&console.log("result:",[...e]),e):e.length&&e.at(-1).at(-1).start<l.start?(e.at(-1).push(l),this._debug._splitGridNode&&console.log("Add to group:",l,[...e]),e):void(this._debug._&&console.assert(!0,"_splitGridNode: An unexpected case of splitting a grid.","\nOn the element:",t))}),[]);this._debug._splitGridNode&&console.groupEnd("make childrenGroups"),this._debug._splitGridNode&&console.log("%c childrenGroups","font-weight:bold",i);const s=i.length,r=this._DOM.getElementOffsetHeight(e);if(s<this._minBreakableGridRows&&r<o)return this._debug._splitGridNode&&console.log("%c END DONT _splitGridNode",_),this._debug._splitGridNode&&console.groupEnd(),[];const l=[...i.map((e=>e.map((e=>e.top)).sort())).map((e=>e[0])),r];this._debug._splitGridNode&&console.log("gridPseudoRowsTopPoints",l);const a=this._node.getTop(e,this._root),h=this._node.getEmptyNodeHeight(e),d=t-a-h,g=o-h;this._debug._splitGridNode&&console.log("\n • firstPartHeight",d,"\n • fullPagePartHeight",g);const c=l;let p=[],u=d;for(let e=0;e<c.length;e++)c[e]>u&&(e>this._minLeftRows&&p.push(e-1),u=c[e-1]+g);this._debug._splitGridNode&&console.log("splitsIds",p);const m=(t,o)=>{this._debug._splitGridNode&&console.log(`=> insertGridSplit(${t}, ${o})`);const n=i.slice(t,o).flat().map((e=>e.element));this._debug._splitGridNode&&console.log("partEntries",n);const s=this._DOM.cloneNodeWrapper(e);return this._node.copyNodeWidth(s,e),this._node.setFlagNoBreak(s),e.before(s),this._DOM.insertAtEnd(s,...n),s},f=[...p.map(((e,t,o)=>m(o[t-1]||0,e))),e];return this._debug._splitGridNode&&console.log("splits",f),f.forEach(((e,t)=>this._DOM.setAttribute(e,"[part]",`${t}`))),this._node.setFlagNoBreak(e),this._debug._splitGridNode&&console.log("%c END _splitGridNode",_),this._debug._splitGridNode&&console.groupEnd(),f}}class m{constructor({config:e,DOM:t,node:o,selector:n,layout:i}){this._DOM=t,this._selector=n,this._node=o,this._frontpageTemplate=i.frontpageTemplate,this._headerTemplate=i.headerTemplate,this._footerTemplate=i.footerTemplate,this._paperBodySelector=n?.paperBody||".paperBody",this._paperHeaderSelector=n?.paperHeader||".paperHeader",this._paperFooterSelector=n?.paperFooter||".paperFooter",this._headerContentSelector=n?.headerContent||".headerContent",this._footerContentSelector=n?.footerContent||".footerContent",this._frontpageContentSelector=n?.frontpageContent||".frontpageContent",this._virtualPaperSelector=n?.virtualPaper||".virtualPaper",this._virtualPaperTopMarginSelector=n?.virtualPaperTopMargin||".virtualPaperTopMargin",this._virtualPaperBottomMarginSelector=n?.virtualPaperBottomMargin||".virtualPaperBottomMargin",this._pageNumberRootSelector=n?.pageNumberRoot||void 0,this._pageNumberCurrentSelector=n?.pageNumberCurrent||void 0,this._pageNumberTotalSelector=n?.pageNumberTotal||void 0,this._paperHeight,this._frontpageFactor,this.headerHeight,this.footerHeight,this.bodyHeight,this.bodyWidth,this._calculatePaperParams()}create({currentPage:e,totalPages:t}){const o=this._createPaperBody(this.bodyHeight),n=this._createPaperHeader(this._headerTemplate),i=this._createPaperFooter(this._footerTemplate);return this._createPaper({header:n,body:o,footer:i,currentPage:e,totalPages:t})}createFrontpage({currentPage:e,totalPages:t}){const o=this._createFrontpageContent(this._frontpageTemplate,this._frontpageFactor),n=this._createPaperBody(this.bodyHeight,o),i=this._createPaperHeader(this._headerTemplate),s=this._createPaperFooter(this._footerTemplate);return this._createPaper({header:i,body:n,footer:s,currentPage:e,totalPages:t})}createVirtualTopMargin(){return this._node.create(this._virtualPaperTopMarginSelector)}createVirtualBottomMargin(){return this._node.create(this._virtualPaperBottomMarginSelector)}_createPaper({header:e,body:t,footer:o,currentPage:n,totalPages:i}){const s=this._node.create(this._virtualPaperSelector);return this._DOM.insertAtEnd(s,this.createVirtualTopMargin(),e,t,o,this.createVirtualBottomMargin()),n&&i&&(this._setPageNumber(e,n,i),this._setPageNumber(o,n,i)),s}_createFrontpageContent(e,t){const o=this._node.create(this._frontpageContentSelector);return e&&this._DOM.setInnerHTML(o,e),t&&this._DOM.setStyles(o,{transform:`scale(${t})`}),o}_createPaperBody(e,t){const o=this._node.create(this._paperBodySelector);return this._DOM.setStyles(o,{height:e+"px"}),t&&this._DOM.insertAtEnd(o,t),o}_createPaperHeader(e){const t=this._node.create(this._paperHeaderSelector);if(e){const o=this._node.create(this._headerContentSelector);this._DOM.setInnerHTML(o,e),this._DOM.insertAtEnd(t,o)}return t}_createPaperFooter(e){const t=this._node.create(this._paperFooterSelector);if(e){const o=this._node.create(this._footerContentSelector);this._DOM.setInnerHTML(o,e),this._DOM.insertAtEnd(t,o)}return t}_setPageNumber(e,t,o){const n=this._pageNumberRootSelector?this._DOM.getElement(this._pageNumberRootSelector,e):this._pageNumberRootSelector;if(n){const e=this._DOM.getElement(this._pageNumberCurrentSelector,n),i=this._DOM.getElement(this._pageNumberTotalSelector,n);this._DOM.setInnerHTML(e,t),this._DOM.setInnerHTML(i,o)}}_calculatePaperParams(){const e=this._createPaperBody(),t=this._createFrontpageContent(this._frontpageTemplate),o=this._createPaperHeader(this._headerTemplate),n=this._createPaperFooter(this._footerTemplate),i=this._createPaper({header:o,body:e,footer:n}),s=this._node.create("#workbench");this._DOM.setStyles(s,{position:"absolute",left:"-3000px"}),this._DOM.insertAtEnd(s,i),this._DOM.insertAtStart(this._DOM.body,s);const r=this._DOM.getElementBCR(i).height,l=this._DOM.getElementOffsetHeight(o)||0,a=this._DOM.getElementOffsetHeight(n)||0,h=this._DOM.getElementOffsetHeight(e),d=this._DOM.getElementOffsetWidth(e);this._DOM.insertAtStart(e,t);const g=this._DOM.getElementOffsetHeight(e),c=g>h?h/g:1;this._DOM.removeNode(s),l>.2*r&&console.warn("It seems that your custom header is too high"),a>.15*r&&console.warn("It seems that your custom footer is too high"),c<1&&console.warn("It seems that your frontpage content is too large. We made it smaller to fit on the page. Check out how it looks! It might make sense to fix this with styles or reduce the text amount."),this._paperHeight=r,this.headerHeight=l,this.footerHeight=a,this.bodyHeight=h,this.bodyWidth=d,this._frontpageFactor=c}}class f{constructor({config:e,DOM:t,selector:o,node:n,pages:i,layout:s,paper:r}){this._config=e,this._debug=e.debugMode?{...e.debugConfig.preview}:{},this._DOM=t,this._selector=o,this._node=n,this._virtualPaperGapSelector=o.virtualPaperGap,this._runningSafetySelector=o.runningSafety,this._printPageBreakSelector=o.printPageBreak,this._pageDivider=o.pageDivider,this._virtualPaper=o.virtualPaper,this._virtualPaperTopMargin=o.virtualPaperTopMargin,this._paperBody=o.paperBody,this._pages=i,this._root=s.root,this._contentFlow=s.contentFlow,this._paperFlow=s.paperFlow,this._paper=r,this._hasFrontPage=!!s.frontpageTemplate}create(){this._processFirstPage(),this._processOtherPages(),(!0===this._config.mask||"true"===this._config.mask)&&this._addMask()}_addMask(){const e=parseInt(this._config.virtualPagesGap),t=parseInt(this._config.printHeight),o=parseInt(this._config.printTopMargin),n=parseInt(this._config.printBottomMargin),i=parseInt(this._config.headerMargin),s=parseInt(this._config.footerMargin),r=this._paper.headerHeight,l=this._paper.footerHeight,a=this._paper.bodyHeight,h=r?Math.ceil(i/2):0,d=l?Math.ceil(s/2):0,g=r-h,c=l-d,p=a+h+d,_=o+g,u=t+e;console.assert(t===p+g+o+c+n,"Paper size calculation params do not match"),function({targetElement:e,maskStep:t,maskWindow:o,maskFirstShift:n}){e.style=`\n -webkit-mask-image: linear-gradient(\n black 0,\n black ${o}px,\n transparent ${o}px,\n transparent ${t}px\n );\n mask-image: linear-gradient(\n black 0,\n black ${o}px,\n transparent ${o}px,\n transparent ${t}px\n );\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n -webkit-mask-size: 100% ${t}px;\n mask-size: 100% ${t}px;\n -webkit-mask-position: 100% ${n}px;\n mask-position: 100% ${n}px;\n -webkit-mask-repeat: repeat-y;\n mask-repeat: repeat-y;\n -webkit-mask-origin: border-box;\n mask-origin: border-box;\n `}({targetElement:this._contentFlow,maskStep:u,maskWindow:p,maskFirstShift:_})}_processFirstPage(){let e;if(this._hasFrontPage){const t=this._insertFrontpageSpacer(this._contentFlow,this._paper.bodyHeight);this._pages.unshift({pageStart:t}),e=this._paper.createFrontpage({currentPage:1,totalPages:this._pages.length})}else e=this._paper.create({currentPage:1,totalPages:this._pages.length});this._insertIntoPaperFlow(e),this._insertIntoContentFlow(0)}_processOtherPages(){for(let e=1;e<this._pages.length;e++){const t=this._paper.create({currentPage:e+1,totalPages:this._pages.length}),o=this._createVirtualPaperGap();this._insertIntoPaperFlow(t,o),this._insertIntoContentFlow(e,o)}}_insertIntoPaperFlow(e,t){this._insertPaper(this._paperFlow,e,t)}_insertIntoContentFlow(e,t){const o=this._pages[e].pageStart,n=this._createPageBreaker(e,t);this._DOM.insertBefore(o,n),t&&this._insertFooterSpacer(n,this._paper.footerHeight,t),this._insertHeaderSpacer(n,this._paper.headerHeight),this._updatePageStartElementAttrValue(o,e)}_createPageBreaker(e,t){const o=this._node.create(this._pageDivider);return this._DOM.setAttribute(o,"[page]",`${e+1}`),t&&this._paper.footerHeight&&this._DOM.setStyles(o,{marginTop:this._paper.footerHeight-1+"px"}),this._paper.headerHeight&&this._DOM.setStyles(o,{marginBottom:this._paper.headerHeight-1+"px"}),o}_updatePageStartElementAttrValue(e,t){this._hasFrontPage&&this._node.markPageStartElement(e,`${t+1}`)}_insertPaper(e,t,o){o?this._DOM.insertAtEnd(e,o,t):this._DOM.insertAtEnd(e,t)}_createVirtualPaperGap(){return this._node.create(this._virtualPaperGapSelector)}_createVirtualPaperTopMargin(){return this._paper.createVirtualTopMargin()}_createVirtualPaperBottomMargin(){return this._paper.createVirtualBottomMargin()}_insertFrontpageSpacer(e,t){const o=this._node.create();return this._DOM.setStyles(o,{paddingBottom:t+"px"}),this._DOM.setAttribute(o,".printFrontpageSpacer"),this._DOM.insertAtStart(e,o),o}_insertHeaderSpacer(e,t){const o=this._DOM.createDocumentFragment(),n=this._node.create(this._runningSafetySelector);this._DOM.insertAtEnd(o,this._createVirtualPaperTopMargin(),n),this._DOM.insertAtEnd(e,o)}_insertFooterSpacer(e,t,o){const n=this._DOM.createDocumentFragment(),i=this._createVirtualPaperGap(),s=this._node.create(this._runningSafetySelector);this._DOM.insertAtEnd(n,s,this._createVirtualPaperBottomMargin(),this._node.create(this._printPageBreakSelector),i),this._DOM.insertAtStart(e,n),this._balanceFooter(s,i,o)}_balanceFooter(e,t,o){const n=this._node.getTop(o,this._root)-this._node.getTop(t,this._root);this._DOM.setStyles(e,{marginBottom:n+"px"}),this._debug._&&console.assert(n>=0,`balancer is negative: ${n} < 0`,t)}}class b{constructor({config:e,DOM:t,selector:o,node:n,layout:i}){this._debugMode=e.debugMode,this._debug=e.debugMode?{...e.debugConfig.toc}:{},this._DOM=t,this._node=n,this._tocPageNumberSelector=e.tocPageNumberSelector,this._root=i.root,this._contentFlow=i.contentFlow,this._pageDividerSelector=o.pageDivider}render(){this._debugMode&&console.time("Processing TOC"),this._debug._&&console.log(`\n📑 TOC: I am here!\n\ntocPageNumberSelector:\n • ${this._tocPageNumberSelector}\n pageDividerSelector:\n • ${this._pageDividerSelector}\n `);const e=this._node.getAll(this._tocPageNumberSelector,this._contentFlow);if(this._debug._&&console.log("📑 tocPageNumberBoxes",e.length),!e.length)return void(this._debug._&&console.log("📑 no valid toc"));const t=this._node.getAll(this._pageDividerSelector,this._contentFlow).reduce(((e,t,o)=>{const n=this._node.getTop(t,this._root)-1,i=this._DOM.getAttribute(t,"[page]");return e[n]=i,e}),{});this._debug._&&console.log("📑 dataFromPagesMarkers",t);const o=e.reduce(((e,t)=>{const o=this._DOM.getDataId(t),n=this._DOM.getElementById(o),i=this._node.getTop(n,this._root);return e[i]={box:t,id:o,targetTop:i},e}),{});this._debug._&&console.log("📑 dataFromTOC",o);const n={...t,...o};let i=0;this._debug._&&console.groupCollapsed("Processing obj");for(const e in n){const t=n[e];this._debug._&&console.log(`Processing ${e}: ${t}`),"string"==typeof t?i=t:(t.page=i,this._DOM.setInnerHTML(t.box,i))}this._debug._&&console.groupEnd("Processing obj"),this._debug._&&console.log("📑 tocObject",n),this._debugMode&&console.timeEnd("Processing TOC")}}class M{constructor({config:e,DOM:t,selector:o,node:n,layout:i}){this._config=e,this._selector=o,this._DOM=t,this._node=n,this._layout=i,this._root=i.root}init(){this._config.debugMode&&console.log("🐙 i am Validator!");const e=`${this._selector.paperFlow} ${this._selector.virtualPaperGap}`,t=`${this._selector.contentFlow} ${this._selector.virtualPaperGap}`,o=[...this._DOM.getAllElements(e)],n=[...this._DOM.getAllElements(t)],i=o.map((e=>this._node.getTop(e))),s=n.map((e=>this._node.getTop(e,this._root))),r=i.reduce(((e,t,o)=>(t!==s[o]&&e.push(o+1),e)),[]);console.assert(!r.length,"Problems with preview generation on the following pages: ",r)}}const O="border:1px dashed #cccccc;background:#ffffff;color:#cccccc;";class S{constructor(e){this._debugMode=e.debugMode,this._preloader,this._preloaderTarget=document.querySelector(e.preloaderTarget)||document.body,this._preloaderBackground=e.preloaderBackground||"white"}create(){this._debugMode&&console.groupCollapsed("%c Preloader ",O),this._insertStyle(),this._preloader=document.createElement("div"),this._preloader.classList.add("lds-dual-ring"),this._preloaderTarget.append(this._preloader),this._debugMode&&console.groupEnd("%c Preloader ",O)}remove(){if(!this._preloader)return;let e=1;const t=setInterval((()=>{e<=.1&&(clearInterval(t),this._preloader.remove()),this._preloader.style.opacity=e,e-=.1*e}),50);this._debugMode&&console.log("%c Preloader removed ",O)}_insertStyle(){const e=document.querySelector("head"),t=document.createElement("style");t.append(document.createTextNode(this._css())),t.setAttribute("data-preloader-style",""),e.append(t)}_css(){return`\n /* PRELOADER */\n .lds-dual-ring {\n position: absolute;\n z-index: 99999;\n top: 0; left: 0; bottom: 0; right: 0;\n background: ${this._preloaderBackground};\n display: flex;\n justify-content: center;\n align-items: center;\n }\n /*\n .lds-dual-ring:after {\n content: " ";\n display: block;\n width: 64px;\n height: 64px;\n margin: 8px;\n border-radius: 50%;\n border: 6px solid #eee;\n border-color: #eee transparent #eee transparent;\n animation: lds-dual-ring 1.2s linear infinite;\n }\n @keyframes lds-dual-ring {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n */\n `}}class D{constructor(e){this._debugMode=e.debugMode}run(){let e=[...document.querySelectorAll("object")];this._debugMode&&console.log(e);let t=[];return e.forEach((e=>{const o=new Promise((t=>{e.addEventListener("load",(o=>{this._debugMode&&console.log("⏰ EVENT: object load",e.clientHeight,e.clientWidth,e),t()}))}));t.push(o)})),Promise.all(t)}}const N="color:Gray;border:1px solid;";console.info("[HTML2PDF4DOC] Version:","0.2.2");const P=document.currentScript.dataset,E=new class{constructor(e){this.params=e,this.debugMode=e.debugMode,this.preloader=e.preloader,this.selector=o,this.config}async render(){console.time("[HTML2PDF4DOC] Total time"),this.debugMode&&console.log("🏁 document.readyState",document.readyState),document.addEventListener("readystatechange",(e=>{this.debugMode&&console.log("🏁 readystatechange",document.readyState)})),this.debugMode&&console.time("⏱️ await DOMContentLoaded time"),await new Promise((e=>{window.addEventListener("DOMContentLoaded",(t=>{this.debugMode&&console.log("⏰ EVENT: DOMContentLoaded"),e()}))})),this.debugMode&&console.timeEnd("⏱️ await DOMContentLoaded time"),this.debugMode&&console.time("⏱️ create Preloader time");const e=new S(this.params);"true"===this.preloader&&e.create(),this.debugMode&&console.timeEnd("⏱️ create Preloader time"),this.debugMode&&console.time("⏱️ Config time"),this.debugMode&&console.groupCollapsed("%c config ",N+"color:LightGray"),this.config={...n(this.params),debugConfig:i},this.debugMode&&console.groupEnd(),this.debugMode&&console.info("⚙️ Current config with debugConfig:",this.config),this.debugMode&&console.timeEnd("⏱️ Config time"),this.debugMode&&console.time("⏱️ DOM helpers init time");const t=new s({DOM:window.document,config:this.config});this.debugMode&&console.timeEnd("⏱️ DOM helpers init time"),this.debugMode&&console.time("⏱️ node helpers init time");const o=new a({config:this.config,DOM:t,selector:this.selector});this.debugMode&&console.timeEnd("⏱️ node helpers init time"),this.debugMode&&console.time("⏱️ await window load time"),await new Promise((e=>{window.addEventListener("load",(t=>{this.debugMode&&console.log("⏰ EVENT: window load"),e()}))})),this.debugMode&&console.timeEnd("⏱️ await window load time"),this.debugMode&&console.time("⏱️ Layout time"),this.debugMode&&console.groupCollapsed("%c Layout ",N);const r=new l({config:this.config,DOM:t,selector:this.selector,node:o});if(r.create(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Layout time"),!r.success)return void(this.debugMode&&console.error("Failed to create layout.\n\nWe have to interrupt the process of creating PDF preview."));this.debugMode&&console.info("%c calculate Paper params ",N),this.debugMode&&console.time("⏱️ Paper time");const h=new m({config:this.config,DOM:t,selector:this.selector,node:o,layout:r});if(this.debugMode&&console.timeEnd("⏱️ Paper time"),!h||!h.bodyHeight||!h.bodyWidth)return void(this.debugMode&&console.error("Failed to create paper calculations.\n\nWe have to interrupt the process of creating PDF preview."));this.debugMode&&console.time("⏱️ Preprocess time"),this.debugMode&&console.groupCollapsed("%c Preprocess ",N),await new D(this.config).run(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Preprocess time"),this.debugMode&&console.time("⏱️ Pages time"),this.debugMode&&console.groupCollapsed("%c Pages ",N);const d=new u({config:this.config,DOM:t,selector:this.selector,node:o,layout:r,referenceHeight:h.bodyHeight,referenceWidth:h.bodyWidth}).calculate();this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Pages time"),this.debugMode&&console.time("⏱️ Preview time"),this.debugMode&&console.groupCollapsed("%c Preview ",N),new f({config:this.config,DOM:t,selector:this.selector,node:o,layout:r,paper:h,pages:d}).create(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Preview time"),this.debugMode&&console.time("⏱️ Toc time"),new b({config:this.config,DOM:t,selector:this.selector,node:o,layout:r}).render(),this.debugMode&&console.timeEnd("⏱️ Toc time"),this.debugMode&&console.time("⏱️ Validator time"),new M({config:this.config,DOM:t,selector:this.selector,node:o,layout:r}).init(),this.debugMode&&console.timeEnd("⏱️ Validator time"),t.setAttribute(r.root,"[success]"),t.setAttribute(r.root,"[pages]",d.length),e.remove(),console.info("[HTML2PDF4DOC] Page count:",d.length),console.timeEnd("[HTML2PDF4DOC] Total time")}}(P),T="manual"===P.init;function k(){T&&E.render()}T&&console.info("HTML2PDF4DOC in manual initialization mode"),!T&&E.render(),HTML2PDF4DOC=t})();
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [tool.hatch.version]
6
+ path = "html2pdf4doc/html2pdf4doc.py"
7
+
8
+ [tool.hatch.build]
9
+ # Currently unused:
10
+ # We want html2pdf4doc.min.js to be gitignored, but we want it to make into the dist/
11
+ # folder, into both tar.gz and .whl when the Pip package is built.
12
+ # This option prevents Hatch from using .gitignore to exclude files.
13
+ # ignore-vcs = true
14
+
15
+ include = [
16
+ "html2pdf4doc/html2pdf4doc.py",
17
+ "html2pdf4doc/html2pdf4doc_js/html2pdf4doc.min.js",
18
+ ]
19
+
20
+ exclude = [
21
+ "/submodules",
22
+ "/tests",
23
+ ]
24
+
25
+ [project]
26
+ name = "html2pdf4doc"
27
+ dynamic = ["version"]
28
+ description = "Python client for HTML2PDF4Doc JavaScript library."
29
+ readme = "README.md"
30
+ # https://github.com/pypa/twine/issues/1216 license-files is broken as of 2025-02-03
31
+ # Using [] as a suggested workaround.
32
+ # license-files = [ "LICENSE" ]
33
+ license-files = []
34
+ requires-python = ">=3.8"
35
+ authors = [
36
+ { name = "Stanislav Pankevich", email = "s.pankevich@gmail.com" },
37
+ { name = "Maryna Balioura", email = "mettta@gmail.com" },
38
+ ]
39
+ classifiers = [
40
+ "License :: OSI Approved :: Apache Software License",
41
+ "Operating System :: OS Independent",
42
+ "Programming Language :: Python :: 3",
43
+ "Programming Language :: Python :: 3.8",
44
+ "Programming Language :: Python :: 3.9",
45
+ "Programming Language :: Python :: 3.10",
46
+ "Programming Language :: Python :: 3.11",
47
+ "Programming Language :: Python :: Implementation :: CPython",
48
+ "Programming Language :: Python :: Implementation :: PyPy",
49
+ ]
50
+
51
+ dependencies = [
52
+ "selenium",
53
+
54
+ # Currently only used for detecting a local Chrome installation.
55
+ "webdriver-manager",
56
+
57
+ # requests is used for downloading the Chrome driver.
58
+ "requests",
59
+ ]
60
+
61
+ [project.optional-dependencies]
62
+ development = [
63
+ # Development tasks
64
+ "invoke>=1.4.1",
65
+ "tox>=4.4.8",
66
+ ]
67
+
68
+ [project.scripts]
69
+ html2pdf4doc = "html2pdf4doc.html2pdf4doc:main"
70
+
71
+ [project.urls]
72
+ Changelog = "https://github.com/mettta/html2pdf_python/releases/"
73
+ # Funding = "https://..."
74
+ Homepage = "https://github.com/mettta/html2pdf_python/"
75
+ Source = "https://github.com/mettta/html2pdf_python/"
76
+
77
+ [tool.pytest.ini_options]
78
+ addopts = "--import-mode=importlib"
79
+ pythonpath = [
80
+ "."
81
+ ]