Skip to content

Instantly share code, notes, and snippets.

@Dosant
Created March 12, 2017 07:23
Show Gist options
  • Save Dosant/4c29ecccdc5602e930f092af54e4582e to your computer and use it in GitHub Desktop.
Save Dosant/4c29ecccdc5602e930f092af54e4582e to your computer and use it in GitHub Desktop.
Handle Pagination
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="header">
<div class="logo">
Logo
</div>
</div>
<div class="content">
<div class="filter-bar">
<div class="filter-item filter-date">Фильтр по дате: от: <input type="date" /> до: <input type="date" /></div>
<div class="filter-item filter-author">Фильтр по автору: <select><option>Все</option><option>Досов Антон</option></select></div>
<button>Применить</button>
</div>
<div class="article-list">
</div>
<div class="pagination-bar">
<button id="pagination-show-more">Показать ещё</button>
</div>
</div>
<div class="footer">
<div class="footer-content">
Автор: Досов Антон
</div>
</div>
<!-- templates -->
<template id="template-article-list-item">
<div class="article-list-item" data-id="id">
<h3 class="article-list-item-title">
Заголовок статьи
</h3>
<p class="article-list-item-summary">
Краткое описание для статьи. Тут краткое описание
</p>
<div class="article-list-item-meta">
<span>Автор: <span class="article-list-item-author">Досов Антон</span></span>
<span>Опубликована: <span class="article-list-item-date">12.12.1995 04:35</span></span>
</div>
</div>
</template>
<!-- scripts -->
<script src="index.js" type="text/javascript"></script>
</body>
</html>
var articleModel = (function () {
var GLOBAL_ARTICLES = [{
"id": "news/2017/02/28/rossiya-snimet-zapret-na-import-moldavskih-vin",
"title": "Россия снимет запрет на импорт молдавских вин",
"author": "Meduza",
"createdAt": new Date("2017-02-28T05:24:23.856Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/28/tramp-obvinil-obamu-v-organizatsii-protestov-po-vsey-strane-i-utechek-v-smi",
"title": "Трамп обвинил Обаму в организации протестов по всей стране и утечек в СМИ",
"author": "Meduza",
"createdAt": new Date("2017-02-27T05:24:23.316Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/28/rosneft-zainteresovalas-dobychey-v-meksikanskom-zalive",
"title": "«Роснефть» заинтересовалась добычей в Мексиканском заливе",
"author": "Meduza",
"createdAt": new Date("2017-02-26T05:24:22.818Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/28/amerikanskiy-senator-predlozhil-nazvat-imenem-nemtsova-ulitsu-pered-posolstvom-rossii",
"title": "Американский сенатор предложил назвать именем Немцова улицу перед посольством России",
"author": "Meduza",
"createdAt": new Date("2017-02-25T05:24:21.043Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/28/rossiya-otkazalas-zaderzhat-podozrevaemyh-v-ubiystve-kim-chen-nama",
"title": "Россия отказалась задержать подозреваемых в убийстве Ким Чен Нама",
"author": "Meduza",
"createdAt": new Date("2017-02-24T05:24:19.591Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/28/spacex-anonsiroval-polet-kosmicheskih-turistov-k-lune-v-2018-godu",
"title": "SpaceX пообещала отправить космических туристов к Луне в 2018 году",
"author": "Meduza",
"createdAt": new Date("2017-02-22T05:23:51.252Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/27/v-avstrii-vyhodtsa-iz-chechni-prigovorili-k-2-5-godam-tyurmy-za-uchastie-v-boyah-na-storone-ig",
"title": "В Австрии выходца из Чечни приговорили к 2,5 годам тюрьмы за участие в боях на стороне ИГ",
"author": "Meduza",
"createdAt": new Date("2017-02-21T05:23:47.871Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/27/v-peterburge-zaderzhali-uchastnika-aktsii-lgbt-spetsnaza-proshedshey-23-fevralya",
"title": "В Петербурге задержали участника акции «ЛГБТ-спецназа», прошедшей 23 февраля",
"author": "Meduza",
"createdAt": new Date("2017-01-18T05:23:45.059Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/27/nikolay-karachentsov-gospitalizirovan-posle-dtp-v-podmoskovie",
"title": "Николай Караченцов госпитализирован после ДТП в Подмосковье",
"author": "Meduza",
"createdAt": new Date("2017-01-16T05:23:41.378Z"),
"content": "Content of post",
"summary": "Summary of post"
}, {
"id": "news/2017/02/27/id-kommersant-nachnet-vypuskat-pod-nazvaniem-dengi-reklamnoe-prilozhenie",
"title": "ИД «Коммерсант» начнет выпускать под названием «Деньги» рекламное приложение",
"author": "Meduza",
"createdAt": new Date("2017-01-15T05:23:36.803Z"),
"content": "Content of post",
"summary": "Summary of post"
}];
function getArticles(skip, top) {
skip = skip || 0;
top = top || 10;
return GLOBAL_ARTICLES.slice(skip, skip + top);
}
function getArticlesCount() {
/* Тут надо учесть текущие фильтры */
return GLOBAL_ARTICLES.length;
}
return {
getArticles: getArticles,
getArticlesCount: getArticlesCount
};
}())
var articleRenderer = (function () {
var ARTICLE_TEMPLATE;
var ARTICLE_LIST_NODE;
function init() {
/* DOM Загрузился.
Можно найти в нем нужные элементы и сохранить в переменные */
ARTICLE_TEMPLATE = document.querySelector('#template-article-list-item');
ARTICLE_LIST_NODE = document.querySelector('.article-list');
}
function insertArticlesInDOM(articles) {
/* для массива объектов статей получим соотвествующие HTML элементы */
var articlesNodes = renderArticles(articles);
/* вставим HTML элементы в '.article-list' элемент в DOM. */
articlesNodes.forEach(function (node) {
ARTICLE_LIST_NODE.appendChild(node);
});
}
function removeArticlesFromDom() {
ARTICLE_LIST_NODE.innerHTML = '';
}
function renderArticles(articles) {
/* каждый объект article из массива преобразуем в HTML элемент */
return articles.map(function (article) {
return renderArticle(article);
});
}
function renderArticle(article) {
/*
Используем template из DOM, заполним его данными конкретной статьи - article.
Этот код можно сделать лучше ...
*/
var template = ARTICLE_TEMPLATE;
template.content.querySelector('.article-list-item').dataset.id = article.id;
template.content.querySelector('.article-list-item-title').textContent = article.title;
template.content.querySelector('.article-list-item-summary').textContent = article.summary;
template.content.querySelector('.article-list-item-author').textContent = article.author;
template.content.querySelector('.article-list-item-date').textContent = formatDate(article.createdAt);
/*
Склонируем полученный контент из template и вернем как результат
*/
return template.content.querySelector('.article-list-item').cloneNode(true);
}
/* Date -> 16/05/2015 09:50 */
function formatDate(d) {
return d.getDate() + '/' + (d.getMonth() + 1) + '/' + d.getFullYear() + ' ' +
d.getHours() + ':' + d.getMinutes();
}
return {
init: init,
insertArticlesInDOM: insertArticlesInDOM,
removeArticlesFromDom: removeArticlesFromDom
};
}());
/*
Этот модуль будет использоваться для пагинации:
1. Содержит в себе данные о текущей странице, сколько всего статей на странице
2. Содержит ссылку на кнопку "Показать еще", отбрабатывает клики на кнопку. Прячет кнопку, если больше статей начнет
*/
var pagination = (function () {
var TOTAL; // всего статей
var PER_PAGE = 3; // статей на 1-ой странице
var CURRENT_PAGE = 1; // текущая страница
var SHOW_MORE_BUTTON;
var SHOW_MORE_CALLBACK; // функция, которую вызывать, когда произошел клик по кнопке
/*
Total: Всего статей в ArticleModel. (Надо будет еще учесть, что total меняется при применении фильтров)
showMoreCb: функция, которую надо вызвать при клике на кнопку "Показать Еще"
*/
function init(total, showMoreCb) {
TOTAL = total;
SHOW_MORE_CALLBACK = showMoreCb;
SHOW_MORE_BUTTON = document.getElementById('pagination-show-more');
SHOW_MORE_BUTTON.addEventListener('click', handleShowMoreClick)
/* Не показывать кнопку если статей нет */
if (getTotalPages() <= CURRENT_PAGE) {
hideShowMoreButton();
}
/* Вернуть skip, top для начальной отрисовки статей */
return getParams();
}
function handleShowMoreClick() {
var paginationParams = nextPage();
SHOW_MORE_CALLBACK(paginationParams.skip, paginationParams.top);
}
function getTotalPages() {
return Math.ceil(TOTAL / PER_PAGE);
}
function nextPage() {
CURRENT_PAGE++;
if (getTotalPages() <= CURRENT_PAGE) {
hideShowMoreButton();
}
return getParams();
}
function getParams() {
return {
top: PER_PAGE,
skip: (CURRENT_PAGE - 1) * PER_PAGE
};
}
function hideShowMoreButton() {
SHOW_MORE_BUTTON.hidden = true;
}
return {
init: init
}
}());
/*
Функция startApp вызовется, когда браузер полностью загрузит и распарсит исходный HTML (index.html)
DOMContentLoaded – означает, что все DOM-элементы разметки уже созданы,
можно их искать, вешать обработчики, создавать интерфейс, но при этом, возможно,
ещё не догрузились какие-то картинки или стили.
*/
document.addEventListener('DOMContentLoaded', startApp);
function startApp() {
/* DOM Загрузился.
Можно найти в нем нужные элементы и сохранить в переменные */
articleRenderer.init();
/*
Инициализируем пагинацию.
Для это передаем сколько всего статей: total
и функцию, которую вызывать при клике на кнопку "Показать Еще": renderArticles
*/
var total = articleModel.getArticlesCount();
var paginationParams = pagination.init(total, renderArticles);
/* Нарисуем статьи из массива GLOBAL_ARTICLES в DOM */
renderArticles(paginationParams.skip, paginationParams.top);
}
/* Глобальная Функция для проверки. Свяжет модель и отображение */
function renderArticles(skip, top) {
// 1. Достанем нужные статьи из модели
var articles = articleModel.getArticles(skip, top);
// 2. Отобразим статьи
articleRenderer.insertArticlesInDOM(articles);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment