diff --git a/README.md b/README.md index eb017a6..58d5729 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Copy config config/config.json.example -> config/config.json -Use mysql +Use Mariadb
 cd gostexplr
 npm i
diff --git a/package.json b/package.json
index 44cfcb2..eeeae22 100644
--- a/package.json
+++ b/package.json
@@ -18,17 +18,17 @@
   },
   "dependencies": {
     "body-parser": "~1.18.2",
-    "cookie-parser": "~1.4.3",
+    "cookie-parser": "^1.4.5",
     "debug": "~2.6.9",
-    "express": "^4.16.4",
+    "express": "^4.17.1",
     "forever": "^0.15.3",
-    "fs-ext": "^1.2.1",
-    "moment": "^2.24.0",
+    "fs-ext": "^1.3.0",
+    "moment": "^2.29.1",
     "morgan": "~1.9.0",
-    "mysql": "^2.15.0",
-    "mysql2": "^1.5.1",
-    "pug": "^2.0.0-rc.4",
-    "sequelize": "^5.1.0",
+    "mysql": "^2.18.1",
+    "mysql2": "^1.7.0",
+    "pug": "^2.0.4",
+    "sequelize": "^5.22.3",
     "sequelize-cli": "^3.2.0",
     "serve-favicon": "~2.4.5"
   }
diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css
index b14d9d4..97101a6 100644
--- a/public/stylesheets/style.css
+++ b/public/stylesheets/style.css
@@ -85,3 +85,13 @@ div.pagination {
   overflow: hidden;
   margin-top: .5em;
 }
+
+div.pagination-wrapper {
+  margin-top: .5em;
+  text-align: center;
+}
+
+div.pagination-wrapper .paginator {
+  margin-left: .5em;
+  display: inline-block;
+}
diff --git a/routes/index.js b/routes/index.js
index 91a9a12..75d5929 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -3,6 +3,9 @@ var express = require('express');
 var router = express.Router();
 var HeightOffset = require('../config/config')['syncHeightOffset'] || 0;
 
+const BLOCKS_PER_PAGE = 50;
+const PAGINATION_LIMIT = 5;
+
 function formatRate(hashrate, decimals = 2) {
     if (hashrate === 0) return '0 H/s';
 
@@ -20,23 +23,90 @@ function shorterHash(hash) {
     return parts[0] + '...' + parts[parts.length-1];
 }
 
+function formatRate(bytes, decimals = 2) {
+    if (bytes === 0) return '0 Bytes';
+
+    const k = 1000;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['H/s', 'KH/s', 'MH/s', 'GH/s', 'TH/s', 'PH/s', 'EH/s', 'ZH/s', 'YH/s'];
+
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+}
+
+function getMaxPage(blockCount) {
+  return blockCount > BLOCKS_PER_PAGE ? Math.ceil(blockCount / BLOCKS_PER_PAGE) : 0;
+}
+
+function getPagination(blockCount, page) {
+  const pagesCount = getMaxPage(blockCount)
+  let pagination = null;
+  if (pagesCount) {
+    pagination = {
+      'left': null,
+      'range': [],
+      'right': null,
+    }
+
+    const pagLimitHalf = Math.ceil(PAGINATION_LIMIT / 2);
+
+    const pagRangeLeft = page - pagLimitHalf;
+    if (pagRangeLeft < 3) {
+      pagination.range[0] = 1;
+    } else {
+      pagination.left = 1;
+      pagination.range[0] = pagRangeLeft;
+    }
+
+    const pagRangeRight = page + pagLimitHalf;
+    if (pagRangeRight > pagesCount - 3) {
+      pagination.range[1] = pagesCount;
+    } else {
+      pagination.right = pagesCount;
+      pagination.range[1] = pagRangeRight;
+    }
+  }
+  return pagination;
+}
+
 /* GET home page. */
-router.get('/', async function(req, res, next) {
+router.get('/:page(\\d+)?', async function(req, res, next) {
+
+  const paramPage = parseInt(req.params.page);
+  const blockCount = await models.Block.count();
+  const maxPage = getMaxPage(blockCount)
+
+  let page = isNaN(paramPage) || paramPage < 1 ? 1 : paramPage;
+  if (page > maxPage) {
+    page = maxPage;
+    res.redirect(`/${page}/`);
+    return;
+  }
+
+  const pagination = getPagination(blockCount, page);
+
+  const offset = BLOCKS_PER_PAGE * (page - 1);
 
   const blocks = await models.Block.findAll({
     attributes: ['height', 'hash', 'time', 'difficulty', 'hashrate'],
     order: [['height', 'DESC']],
-    limit: 50,
+    limit: BLOCKS_PER_PAGE,
+    offset,
   });
-  blocks.forEach(function(arrayItem) {
+
+  blocks.forEach((arrayItem) => {
     arrayItem.ago = arrayItem.time.toUTCString().substring(5);
     arrayItem.difficulty = parseFloat(arrayItem.difficulty).toFixed(8);
     arrayItem.hashrate = formatRate(arrayItem.hashrate, 4);
     arrayItem.hash_short = shorterHash(arrayItem.hash);
   });
+
   res.render('index', {
     HeightOffset,
+    pagination,
     blocks,
+    page,
   });
 });
 
diff --git a/views/index.pug b/views/index.pug
index d0eb013..f74e869 100644
--- a/views/index.pug
+++ b/views/index.pug
@@ -23,3 +23,22 @@ block content
         td #{block.hashrate}
         td
           a(href='/block/' + block.hash + '/') #{block.hash_short}
+
+block pagination
+  if pagination
+    if pagination.left
+      a.paginator(href='/' + pagination.left + '/') #{pagination.left}
+      span.paginator ...
+
+
+    - var n = pagination.range[0]
+    - var m = pagination.range[1]
+    while n <= m
+      if n != page
+        a.paginator(href='/' + n + '/') #{n++}
+      else
+        span.paginator #{n++}
+
+    if pagination.right
+      span.paginator ...
+      a.paginator(href='/' + pagination.right + '/') #{pagination.right}
diff --git a/views/layout.pug b/views/layout.pug
index 409e7f3..fde1f17 100644
--- a/views/layout.pug
+++ b/views/layout.pug
@@ -19,3 +19,5 @@ html(lang='en')
           input(type="submit", value=">>")
       div.content
         block content
+      div.pagination-wrapper
+        block pagination