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": {
|
||||
"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",
|
||||
|
@ -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>
|
||||
|
@ -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", () => {
|
||||
|
87
src/index.ts
87
src/index.ts
@ -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 = "";
|
||||
|
Loading…
x
Reference in New Issue
Block a user