From e00c9ca6f5f7353b3ceb8bf97f5ccce0c2e1996c Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 6 Aug 2021 14:20:48 +0300 Subject: [PATCH] Finished getPage method (wrapper around getPageBreak) and did some basic code improvements --- package.json | 2 +- src/__tests__/index.html | 30 ++----------- src/__tests__/index.test.ts | 2 +- src/index.ts | 87 +++++++++++++++++++++++++++++-------- 4 files changed, 76 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index c20e82a..509a551 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ ], "scripts": { "test:browser": "npm run build -- --module 'esnext' && cp ./src/__tests__/index.html ./lib/ && bash -c 'for module in \".\\/cache\" \".\\/types\" \".\\/utils\"; do sed -i \"s/$module/$module.js/g\" ./lib/index.js; done' && serve -s lib", - "build": "tsc", + "build": "rm -rf lib && tsc", "test": "jest --config jestconfig.json --passWithNoTests", "prepare": "npm run build", "prepublishOnly": "npm test && npm run lint", diff --git a/src/__tests__/index.html b/src/__tests__/index.html index fbc497f..ed8d8e6 100644 --- a/src/__tests__/index.html +++ b/src/__tests__/index.html @@ -16,8 +16,8 @@ display: none; } .appContainer { - height: 200px; - width: 200px; + height: 300px; + width: 300px; display: flex; border: 1px black solid; } @@ -26,18 +26,7 @@ }
-
-

Hello, my dear friend

-

- You can run npm list -g to see which global libraries are installed - and where they're located. Use npm list -g | head -1 for truncated - output showing just the path. If you want to display only main - packages not its sub-packages which installs along with it - you can - use - npm list --depth=0 which will show all packages and for getting - only globally installed packages, just add -g i.e. npm list -g - --depth=0. -

-
+

About me

Hello, I'm Shishkov Dmitriy. I'm 17 years old computer programmer. I'm also do photography as a hobby. As for spring 2021, I'm studying in "Ugra physico-mathematical boarding school" in Khanty-Mansiysk.

My specialization is frontend web development. All web services and application I deploy on my own. For it I've used Dockerand docker-composefor deployment on my VPS. Currently my server is powered with Dokku. For smaller projects I also used some PaaS like Herokuand Vercel Now.

I also do in for C development. In projectssection you can see some of my developments in this langualge. Even this site is powered by page generator written in C.

More formally, this is my stack:

See contactsto get in touch with me.

You can reach my resume following this link

@@ -58,18 +47,7 @@ } } - const pg = new HTMLPagination(content, container, ci); - - const r = async (prev) => { - try { - const res = pg.getPageBreak(prev, 100); - await setTimeout(() => r(res), 1000); - } catch (e) { - r(0); - } - }; - - r(0); + window.pg = new HTMLPagination(content, container, ci, 500); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index aafab4a..6ebd736 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -24,7 +24,7 @@ describe("Text position stuff", () => { container.innerHTML = ""; - hp = new HTMLPagination(content, container, new Cache()); + hp = new HTMLPagination(content, container, new Cache(), 100); }); it("computes positions for each text node", () => { diff --git a/src/index.ts b/src/index.ts index 5a26ffe..30e0f45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,39 +6,77 @@ class HTMLPagination { content: HTMLElement; container: HTMLElement; cache: CacheInterface; + initialJump: number; elementPositions: [number, Node][]; idPositions: Map; + pages: number[]; /** + * /** * @param content HTML element with html content to display paginationly * @param container HTML element which will store content to display - * @param cache Class implementing `g` and `s` methods for getting and setting elements of KV storage + * @param cache Class implementing `g` and `s` methods for getting and + * setting elements of KV storage + * @param initialJump Initial estimated number of characrers and + * elements per page. Good value migth icreace pages calculation speed and + * page number accuracy before full book is processed */ constructor( content: HTMLElement, container: HTMLElement, - cache: CacheInterface + cache: CacheInterface, + initialJump: number ) { this.content = content; this.container = container; this.cache = cache; + this.initialJump = initialJump; this.elementPositions = new Array(); this.idPositions = new Map(); + this.pages = [0]; this.computeElementsPositions(); } + /** + * Method computes book's pages till specified number, + * sets container's content to `n`th page and returns it as string + * `n` starts from 1 + */ getPage(n: number): string { - const from = 0; - const to = 1; + if ( + n < 1 || + (n > this.pages.length - 1 && + this.pages[this.pages.length - 1] === this.getMaxPosition) + ) + return ""; + + let from: number = 0, + to: number = 0; + + if (n <= this.pages.length - 1) { + from = this.pages[n - 1]; + to = this.pages[n]; + } else { + for ( + let i = this.pages.length - 1; + i < n && this.pages[this.pages.length - 1] !== this.getMaxPosition; + i++ + ) { + from = this.pages[i]; + to = this.getPageBreak(from); + this.pages.push(to); + } + } return this.getContentFromRange(from, to); } /** - * Computes html elements and text nodes positions. Must be run only on first setup + * Computes html elements and text nodes positions. + * Must be run only on first setup */ computeElementsPositions(): void { const recursive = (currentPosition: number, root: Node): number => { @@ -60,27 +98,40 @@ class HTMLPagination { /** * Finds position for next page break - * initialJump may be computed in a clever way */ - getPageBreak(start: number, initialJump: number) { - let previousEnd = this.getMaxPosition(); - let end = this.getNextSpaceForPosition(start + initialJump); + getPageBreak(start: number) { + let previousEnd = this.getMaxPosition; + let end = this.getNextSpaceForPosition( + Math.min(start + this.initialJump, this.getMaxPosition) + ); this.getContentFromRange(start, end); - while (!this.scrollNecessary() && end < this.getMaxPosition()) { + while (!this.scrollNecessary && end < this.getMaxPosition) { previousEnd = end; end = this.getNextSpaceForPosition(end + 1); this.getContentFromRange(start, end); } - while (this.scrollNecessary() && end > start) { + while (this.scrollNecessary && end > start) { previousEnd = end; end = this.getPreviousSpaceForPosition(end - 1); this.getContentFromRange(start, end); } if (start === end) return previousEnd; - else return end; + else { + this.initialJump = end - start; + return end; + } + } + + /** + * Tries to predict number of pages if not calculated exaclty yet + */ + get pagesNumber() { + if (this.pages[this.pages.length - 1] === this.getMaxPosition) + return this.pages.length - 1; + else return Math.round(this.getMaxPosition / this.initialJump); } /** @@ -97,7 +148,7 @@ class HTMLPagination { if (nodeOffset === str.length) { if (nodeIndex === this.elementPositions.length - 1) - return this.getMaxPosition(); + return this.getMaxPosition; else return this.elementPositions[nodeIndex + 1][0]; } else { return this.elementPositions[nodeIndex][0] + nodeOffset; @@ -121,14 +172,14 @@ class HTMLPagination { /** * Checks if container is overflowing with content */ - scrollNecessary(): boolean { + get scrollNecessary(): boolean { return this.container.clientHeight < this.container.scrollHeight; } /** * Returns end position of content */ - getMaxPosition(): number { + get getMaxPosition(): number { const [offset, element] = this.elementPositions[this.elementPositions.length - 1]; return offset + (element.nodeValue?.length || 0); @@ -146,7 +197,8 @@ class HTMLPagination { } /** - * Finds node inside which `pos` is located. Returns node positions and itself + * Finds node inside which `pos` is located. + * @returns node positions and itself */ getElementForPosition(pos: number): [number, Node] { const elementIndex = this.getElementIndexForPosition(pos); @@ -155,7 +207,8 @@ class HTMLPagination { } /** - * Sets `container` element content and return as string html content between `from` and `to` + * Sets `container` element content and + * return as string html content between `from` and `to` */ getContentFromRange(from: number, to: number): string { this.container.innerHTML = "";