Finished getPage method (wrapper around getPageBreak) and did some basic code improvements

This commit is contained in:
Dmitriy Shishkov 2021-08-06 14:20:48 +03:00
parent 5ad6f7ddc5
commit e00c9ca6f5
No known key found for this signature in database
GPG Key ID: 14358F96FCDD8060
4 changed files with 76 additions and 45 deletions

View File

@ -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",

View File

@ -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 @@
}
</style>
<div id="content">
<div>
<h1>Hello, my dear friend</h1>
<p>
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.
</p>
</div>
<main><h1>About me</h1><p>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. </p><p>My specialization is frontend web development. All web services and application I deploy on my own. For it I've used <a href="https://www.docker.com">Docker</a>and <a href="https://docs.docker.com/compose">docker-compose</a>for deployment on my VPS. Currently my server is powered with <a href="https://dokku.com">Dokku</a>. For smaller projects I also used some PaaS like <a href="https://heroku.com">Heroku</a>and <a href="https://vercel.com">Vercel Now</a>. </p><p>I also do in for C development. In <a href="/projects">projects</a>section you can see some of my developments in this langualge. Even this site is powered by page generator written in C. </p><p>More formally, this is my stack:</p><ul><li>JS <ul><li><a href="https://nodejs.org">NodeJS</a></li><li><a href="https://www.typescriptlang.org">TypeScript</a></li><li><a href="https://reactjs.org">React</a>: <ul><li><a href="https://reactrouter.com">React Router</a></li><li><a href="https://github.com/molefrog/wouter">Wouter</a></li><li><a href="https://www.framer.com/motion">Framer Motion</a></li><li><a href="https://styled-components.com" >Styled Components</a ></li></ul></li><li><a href="https://nextjs.org">Next.js</a></li><li><a href="https://graphql.org">Graphql</a>: <ul><li><a href="https://www.apollographql.com">Apollo</a></li></ul></li><li><a href="https://www.prisma.io">Prisma</a></li><li><a href="https://www.mongodb.com">MongoDB</a><ul><li><a href="https://mongoosejs.com">Mongoose</a></li></ul></li><li><a href="https://www.postgresql.org">PostgreSQL</a><ul><li><a href="https://node-postgres.com">Node-postgres</a></li></ul></li><li><a href="https://www.npmjs.com/package/jsonwebtoken" >jsonwebtoken</a ></li><li><a href="https://sendgrid.com">SendGrid</a></li><li><a href="https://github.com/jakearchibald/idb">IndexedDB</a></li><li><a href="https://immerjs.github.io/immer">Immer</a></li><li><a href="https://expressjs.com">ExpressJS</a></li><li>Dev environment: <ul><li><a href="https://eslint.org">ESLint</a></li><li><a href="https://prettier.io">Prettier</a></li><li><a href="https://jestjs.io">Jest</a></li><li><a href="https://mochajs.org">Mocha</a></li><li><a href="https://webpack.js.org">Webpack</a></li><li><a href="https://www.snowpack.dev">Snowpack</a></li><li><a href="https://esbuild.github.io">Esbuild</a></li><li><a href="https://storybook.js.org">Storybook</a></li><li><a href="https://babeljs.io">Babel</a></li></ul></li></ul></li><li>Deployment: <ul><li><a href="https://www.docker.com">Docker</a></li><li><a href="https://docs.docker.com/compose">docker-compose</a></li><li><a href="https://dokku.com">Dokku</a></li><li><a href="https://heroku.com">Heroku</a></li><li><a href="https://www.oracle.com/cloud" >Oracle Cloud Infrastructure</a ></li><li><a href="https://vercel.com">Vercel Now</a></li></ul></li><li>C</li><li><a href="https://www.python.org">Python</a><ul><li><a href="https://fastapi.tiangolo.com">FastAPI</a></li></ul></li><li><a href="http://www.lua.org">Lua</a></li></ul><p>See <a href="/contacts">contacts</a>to get in touch with me.</p><p>You can reach my resume following <a href="https://github.com/dm1sh/dm1sh/blob/main/resume.md" >this link</a ></p></main>
</div>
<div class="appContainer">
<div id="container"></div>
@ -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);
</script>
</body>
</html>

View File

@ -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", () => {

View File

@ -6,39 +6,77 @@ class HTMLPagination {
content: HTMLElement;
container: HTMLElement;
cache: CacheInterface;
initialJump: number;
elementPositions: [number, Node][];
idPositions: Map<string, number>;
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 = "";