Finished getPage method (wrapper around getPageBreak) and did some basic code improvements
This commit is contained in:
parent
5ad6f7ddc5
commit
e00c9ca6f5
@ -9,7 +9,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"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",
|
"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",
|
"test": "jest --config jestconfig.json --passWithNoTests",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"prepublishOnly": "npm test && npm run lint",
|
"prepublishOnly": "npm test && npm run lint",
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.appContainer {
|
.appContainer {
|
||||||
height: 200px;
|
height: 300px;
|
||||||
width: 200px;
|
width: 300px;
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 1px black solid;
|
border: 1px black solid;
|
||||||
}
|
}
|
||||||
@ -26,18 +26,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<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>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="appContainer">
|
<div class="appContainer">
|
||||||
<div id="container"></div>
|
<div id="container"></div>
|
||||||
@ -58,18 +47,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const pg = new HTMLPagination(content, container, ci);
|
window.pg = new HTMLPagination(content, container, ci, 500);
|
||||||
|
|
||||||
const r = async (prev) => {
|
|
||||||
try {
|
|
||||||
const res = pg.getPageBreak(prev, 100);
|
|
||||||
await setTimeout(() => r(res), 1000);
|
|
||||||
} catch (e) {
|
|
||||||
r(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
r(0);
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -24,7 +24,7 @@ describe("Text position stuff", () => {
|
|||||||
|
|
||||||
container.innerHTML = "";
|
container.innerHTML = "";
|
||||||
|
|
||||||
hp = new HTMLPagination(content, container, new Cache());
|
hp = new HTMLPagination(content, container, new Cache(), 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("computes positions for each text node", () => {
|
it("computes positions for each text node", () => {
|
||||||
|
87
src/index.ts
87
src/index.ts
@ -6,39 +6,77 @@ class HTMLPagination {
|
|||||||
content: HTMLElement;
|
content: HTMLElement;
|
||||||
container: HTMLElement;
|
container: HTMLElement;
|
||||||
cache: CacheInterface;
|
cache: CacheInterface;
|
||||||
|
initialJump: number;
|
||||||
|
|
||||||
elementPositions: [number, Node][];
|
elementPositions: [number, Node][];
|
||||||
idPositions: Map<string, number>;
|
idPositions: Map<string, number>;
|
||||||
|
pages: number[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* /**
|
||||||
* @param content HTML element with html content to display paginationly
|
* @param content HTML element with html content to display paginationly
|
||||||
* @param container HTML element which will store content to display
|
* @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(
|
constructor(
|
||||||
content: HTMLElement,
|
content: HTMLElement,
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
cache: CacheInterface
|
cache: CacheInterface,
|
||||||
|
initialJump: number
|
||||||
) {
|
) {
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
|
this.initialJump = initialJump;
|
||||||
|
|
||||||
this.elementPositions = new Array();
|
this.elementPositions = new Array();
|
||||||
this.idPositions = new Map();
|
this.idPositions = new Map();
|
||||||
|
this.pages = [0];
|
||||||
|
|
||||||
this.computeElementsPositions();
|
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 {
|
getPage(n: number): string {
|
||||||
const from = 0;
|
if (
|
||||||
const to = 1;
|
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);
|
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 {
|
computeElementsPositions(): void {
|
||||||
const recursive = (currentPosition: number, root: Node): number => {
|
const recursive = (currentPosition: number, root: Node): number => {
|
||||||
@ -60,27 +98,40 @@ class HTMLPagination {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds position for next page break
|
* Finds position for next page break
|
||||||
* initialJump may be computed in a clever way
|
|
||||||
*/
|
*/
|
||||||
getPageBreak(start: number, initialJump: number) {
|
getPageBreak(start: number) {
|
||||||
let previousEnd = this.getMaxPosition();
|
let previousEnd = this.getMaxPosition;
|
||||||
let end = this.getNextSpaceForPosition(start + initialJump);
|
let end = this.getNextSpaceForPosition(
|
||||||
|
Math.min(start + this.initialJump, this.getMaxPosition)
|
||||||
|
);
|
||||||
|
|
||||||
this.getContentFromRange(start, end);
|
this.getContentFromRange(start, end);
|
||||||
while (!this.scrollNecessary() && end < this.getMaxPosition()) {
|
while (!this.scrollNecessary && end < this.getMaxPosition) {
|
||||||
previousEnd = end;
|
previousEnd = end;
|
||||||
end = this.getNextSpaceForPosition(end + 1);
|
end = this.getNextSpaceForPosition(end + 1);
|
||||||
this.getContentFromRange(start, end);
|
this.getContentFromRange(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (this.scrollNecessary() && end > start) {
|
while (this.scrollNecessary && end > start) {
|
||||||
previousEnd = end;
|
previousEnd = end;
|
||||||
end = this.getPreviousSpaceForPosition(end - 1);
|
end = this.getPreviousSpaceForPosition(end - 1);
|
||||||
this.getContentFromRange(start, end);
|
this.getContentFromRange(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start === end) return previousEnd;
|
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 (nodeOffset === str.length) {
|
||||||
if (nodeIndex === this.elementPositions.length - 1)
|
if (nodeIndex === this.elementPositions.length - 1)
|
||||||
return this.getMaxPosition();
|
return this.getMaxPosition;
|
||||||
else return this.elementPositions[nodeIndex + 1][0];
|
else return this.elementPositions[nodeIndex + 1][0];
|
||||||
} else {
|
} else {
|
||||||
return this.elementPositions[nodeIndex][0] + nodeOffset;
|
return this.elementPositions[nodeIndex][0] + nodeOffset;
|
||||||
@ -121,14 +172,14 @@ class HTMLPagination {
|
|||||||
/**
|
/**
|
||||||
* Checks if container is overflowing with content
|
* Checks if container is overflowing with content
|
||||||
*/
|
*/
|
||||||
scrollNecessary(): boolean {
|
get scrollNecessary(): boolean {
|
||||||
return this.container.clientHeight < this.container.scrollHeight;
|
return this.container.clientHeight < this.container.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns end position of content
|
* Returns end position of content
|
||||||
*/
|
*/
|
||||||
getMaxPosition(): number {
|
get getMaxPosition(): number {
|
||||||
const [offset, element] =
|
const [offset, element] =
|
||||||
this.elementPositions[this.elementPositions.length - 1];
|
this.elementPositions[this.elementPositions.length - 1];
|
||||||
return offset + (element.nodeValue?.length || 0);
|
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] {
|
getElementForPosition(pos: number): [number, Node] {
|
||||||
const elementIndex = this.getElementIndexForPosition(pos);
|
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 {
|
getContentFromRange(from: number, to: number): string {
|
||||||
this.container.innerHTML = "";
|
this.container.innerHTML = "";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user