From 35e2ef02648c2d40bf3ec321357d2623717c1eb4 Mon Sep 17 00:00:00 2001 From: fieg Date: Mon, 11 Apr 2022 15:22:39 +0200 Subject: [PATCH 01/24] run npm install in examples as lock files are excluded from vcs --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0749d346..4e4c9305 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ install: update: npm ci npm run build - $(foreach ex,$(EXAMPLES),(cd $(ex) && npm ci) || exit $$?;) + $(foreach ex,$(EXAMPLES),(cd $(ex) && npm install) || exit $$?;) .PHONY: update up: From e1e4d945d613c42aa97525178d5bc080f9fa692f Mon Sep 17 00:00:00 2001 From: fieg Date: Mon, 11 Apr 2022 15:23:34 +0200 Subject: [PATCH 02/24] copied article as base for upwards scroll --- examples/upwards/.gitignore | 5 ++ examples/upwards/index.html | 42 +++++++++ examples/upwards/index.js | 23 +++++ examples/upwards/loader.svg | 20 +++++ examples/upwards/package.json | 37 ++++++++ examples/upwards/page2.html | 44 ++++++++++ examples/upwards/page3.html | 42 +++++++++ examples/upwards/style.css | 158 ++++++++++++++++++++++++++++++++++ 8 files changed, 371 insertions(+) create mode 100644 examples/upwards/.gitignore create mode 100644 examples/upwards/index.html create mode 100644 examples/upwards/index.js create mode 100644 examples/upwards/loader.svg create mode 100644 examples/upwards/package.json create mode 100644 examples/upwards/page2.html create mode 100644 examples/upwards/page3.html create mode 100644 examples/upwards/style.css diff --git a/examples/upwards/.gitignore b/examples/upwards/.gitignore new file mode 100644 index 00000000..b5dd6d68 --- /dev/null +++ b/examples/upwards/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +.cache +package-lock.json +.npmrc diff --git a/examples/upwards/index.html b/examples/upwards/index.html new file mode 100644 index 00000000..2c40a26c --- /dev/null +++ b/examples/upwards/index.html @@ -0,0 +1,42 @@ + + + + + + + Infinite Scroll Example Blog - Infinite Ajax Scroll Example + + + + + + +
+
+

Infinite Scroll Example Blog

+

Rhoncus dolor purus non enim praesent elementum facilisis. Molestie a iaculis at erat pellentesque adipiscing commodo. Vulputate sapien nec sagittis aliquam malesuada bibendum arcu. Convallis tellus id interdum velit laoreet id donec ultrices tincidunt. Quis commodo odio aenean sed. Turpis massa tincidunt dui ut ornare lectus sit.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Orci a scelerisque purus semper eget duis. Justo laoreet sit amet cursus sit amet dictum sit amet. Pellentesque dignissim enim sit amet. Enim blandit volutpat maecenas volutpat blandit. Vestibulum rhoncus est pellentesque elit ullamcorper. Est ultricies integer quis auctor elit sed vulputate mi.

+

Aliquet lectus proin nibh nisl condimentum id. Amet porttitor eget dolor morbi. In metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Sed euismod nisi porta lorem. Vulputate eu scelerisque felis imperdiet proin.

+ +
+ +
Amet porttitor eget dolor morbi.
+
+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Orci a scelerisque purus semper eget duis. Justo laoreet sit amet cursus sit amet dictum sit amet. Pellentesque dignissim enim sit amet. Enim blandit volutpat maecenas volutpat blandit. Vestibulum rhoncus est pellentesque elit ullamcorper. Est ultricies integer quis auctor elit sed vulputate mi.

+

Aliquet lectus proin nibh nisl condimentum id. Amet porttitor eget dolor morbi. In metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Sed euismod nisi porta lorem. Vulputate eu scelerisque felis imperdiet proin.

+
+ +
+
+
No more pages
+
+ + +
+ + + + diff --git a/examples/upwards/index.js b/examples/upwards/index.js new file mode 100644 index 00000000..d1da4e44 --- /dev/null +++ b/examples/upwards/index.js @@ -0,0 +1,23 @@ +import InfiniteAjaxScroll from '@webcreate/infinite-ajax-scroll'; + +window.ias = new InfiniteAjaxScroll('.surface-container', { + item: '.article', + next: '.pager__next', + pagination: '.pager', + spinner: '.loader' +}); + +ias.on('last', function() { + let el = document.querySelector('.no-more'); + + el.style.opacity = '1'; +}); + +// update title and url then scrolling through pages +ias.on('page', (e) => { + document.title = e.title; + + let state = history.state; + + history.replaceState(state, e.title, e.url); +}); diff --git a/examples/upwards/loader.svg b/examples/upwards/loader.svg new file mode 100644 index 00000000..b8c9763c --- /dev/null +++ b/examples/upwards/loader.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/examples/upwards/package.json b/examples/upwards/package.json new file mode 100644 index 00000000..56c8dba5 --- /dev/null +++ b/examples/upwards/package.json @@ -0,0 +1,37 @@ +{ + "name": "infinite-ajax-scroll-upwards", + "description": "An example of an upwards infinite scroll", + "version": "1.0.0", + "homepage": "https://infiniteajaxscroll.com", + "repository": "github:webcreate/infinite-ajax-scroll", + "bugs": "https://github.com/webcreate/infinite-ajax-scroll/issues", + "author": { + "company": "Webcreate", + "name": "Jeroen Fiege", + "web": "https://webcreate.nl" + }, + "private": true, + "scripts": { + "build": "parcel build *.html --public-url ./", + "watch": "parcel watch * --public-url ./", + "link": "npm link ../../" + }, + "keywords": [ + "infinite-ajax-scroll", + "infinite-scroll", + "infinite", + "endless", + "scroll", + "scrolling", + "ajax", + "pagination", + "ias", + "jquery-ias" + ], + "dependencies": { + "@webcreate/infinite-ajax-scroll": "^3.0.0" + }, + "devDependencies": { + "parcel-bundler": "^1.12.4" + } +} diff --git a/examples/upwards/page2.html b/examples/upwards/page2.html new file mode 100644 index 00000000..9664c45f --- /dev/null +++ b/examples/upwards/page2.html @@ -0,0 +1,44 @@ + + + + + + + + Pellentesque habitant morbi senectus - Infinite Ajax Scroll Example + + + + + +
+
+

Pellentesque habitant morbi senectus

+

At augue eget arcu dictum varius. Tempus iaculis urna id volutpat lacus. Blandit massa enim nec dui nunc mattis. Fames ac turpis egestas maecenas pharetra convallis posuere. Facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum dui. Euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis. Aliquet risus feugiat in ante. Amet tellus cras adipiscing enim eu turpis egestas pretium.

+ +
+ +
At tempor commodo ullamcorper.
+
+ +

Non curabitur gravida arcu ac tortor dignissim convallis. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt dui ut ornare lectus sit amet est placerat. Maecenas accumsan lacus vel facilisis. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed.

+

Vitae auctor eu augue ut lectus arcu bibendum at varius. Amet consectetur adipiscing elit pellentesque habitant morbi tristique. Elementum integer enim neque volutpat ac. At tempor commodo ullamcorper a. Diam quam nulla porttitor massa id neque aliquam vestibulum. Velit sed ullamcorper morbi tincidunt ornare massa. Urna duis convallis convallis tellus id.

+ +

Sit amet volutpat consequat mauris nunc congue. Mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Proin libero nunc consequat interdum varius sit amet. Vitae semper quis lectus nulla at volutpat diam ut venenatis. Orci ac auctor augue mauris. Gravida rutrum quisque non tellus orci ac. Ornare arcu odio ut sem nulla pharetra diam sit. Vestibulum lectus mauris ultrices eros in cursus turpis massa.

+
+ +
+
+
No more pages
+
+ + +
+ + + + + diff --git a/examples/upwards/page3.html b/examples/upwards/page3.html new file mode 100644 index 00000000..39fada39 --- /dev/null +++ b/examples/upwards/page3.html @@ -0,0 +1,42 @@ + + + + + + + + Diam sollicitudin tempor id eu nisl - Infinite Ajax Scroll Example + + + + + +
+
+

Diam sollicitudin tempor id eu nisl

+

Maecenas accumsan lacus vel facilisis. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. Vitae suscipit tellus mauris a diam maecenas sed enim. Odio euismod lacinia at quis risus sed vulputate odio.

+

Urna cursus eget nunc scelerisque viverra. Dignissim enim sit amet venenatis. Eu facilisis sed odio morbi quis commodo odio aenean. Diam sollicitudin tempor id eu nisl nunc mi ipsum. Vulputate dignissim suspendisse in est ante. Eget mauris pharetra et ultrices neque ornare aenean. Augue mauris augue neque gravida in fermentum et sollicitudin ac. In nibh mauris cursus mattis. Morbi non arcu risus quis varius quam quisque id.

+

Enim lobortis scelerisque fermentum dui faucibus. Dolor sit amet consectetur adipiscing elit. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique. Vitae turpis massa sed elementum. Aliquet bibendum enim facilisis gravida neque convallis. Morbi tristique senectus et netus. Eleifend donec pretium vulputate sapien nec sagittis. Venenatis lectus magna fringilla urna porttitor rhoncus dolor. Aliquam purus sit amet luctus venenatis.

+ +
+ +
Feugiat in ante metus dictum at.
+
+ +

Lorem dolor sed viverra ipsum nunc aliquet bibendum enim. In pellentesque massa placerat duis. Imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper. Feugiat in ante metus dictum at. Aenean sed adipiscing diam donec adipiscing tristique risus. Nulla at volutpat diam ut venenatis tellus in metus vulputate. Enim ut tellus elementum sagittis. Egestas pretium aenean pharetra magna ac placerat. Nunc non blandit massa enim.

+
+ +
+
+
No more pages
+
+ + +
+ + + + + diff --git a/examples/upwards/style.css b/examples/upwards/style.css new file mode 100644 index 00000000..8c244ea2 --- /dev/null +++ b/examples/upwards/style.css @@ -0,0 +1,158 @@ +@import "https://fonts.googleapis.com/css?family=Source+Serif+Pro"; + +body { + margin: 0; + padding: 80px 0; +} + +.article { + margin: 80px auto 0; + padding: 0 20px; + max-width: 740px; +} + +.article h1 { + font-size: 38px; + color: rgba(0, 0, 0, .84); + + margin: 0; + padding: 0; + font-weight: 600; + + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; +} + +.article .article__p--first { + margin-top: 10px; +} + +.article p { + margin: 29px 0 0 0; + + font-family: 'Source Serif Pro', Georgia, Cambria, "Times New Roman", Times, serif; + font-weight: 400; + font-style: normal; + font-size: 21px; + line-height: 1.58; + letter-spacing: -.003em; + + color: rgba(0, 0, 0, .84); + color: #333; + + -webkit-font-smoothing: antialiased; +} + +.article figure { + width: 100vw; + position: relative; + left: 50%; + right: 50%; + margin-left: -50vw; + margin-right: -50vw; + text-align: center; + + overflow: hidden; + margin-top: 29px; +} + +.article figure img { + height: 600px; + background-color: #efefef; +} + +@media (max-width: 1400px) { + .article figure img { + display: block; + width: 100%; + max-width: 1400px; + object-fit: cover; + } +} + +.article figure figcaption { + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; + color: #999; + font-size: 13px; + font-weight: normal; + line-height: 2em; +} + +.pager { + margin: 29px 0 0; + text-align: center; + + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; + font-size: 14px; + font-weight: normal; + line-height: 2em; +} + +.pager a, +.pager a:link, +.pager a:visited { + color: #999; + text-decoration: none; +} + +.pager a:hover, +.pager a:active { + color: #999; + text-decoration: underline; +} + +.status { + text-align: center; + margin-top: 29px; + min-height: 40px; +} + +.loader { + height: 40px; + margin-top: 0; + text-align: center; + background: transparent url('loader.svg') no-repeat center center; + background-size: 40px 19px; + opacity: 0; + animation: flipAnimation 1s infinite; + transition: opacity 300ms; +} + +/* @see https://medium.com/designer-recipes/understanding-card-flip-animation-using-css-391c40ed3136 */ +@keyframes flipAnimation { + 0% { + -ms-transform: rotateY(-180deg); /* IE 9 */ + -webkit-transform: rotateY(-180deg); /* Safari Chrome */ + transform: rotateY(-180deg); + } + 50% { + -ms-transform: rotateY(0deg); /* IE 9 */ + -webkit-transform: rotateY(0deg); /* Safari Chrome */ + transform: rotateY(0deg); + } + 100% { + -ms-transform: rotateY(-180deg); /* IE 9 */ + -webkit-transform: rotateY(-180deg); /* Safari Chrome */ + transform: rotateY(-180deg); + } +} + +.no-more { + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; + font-size: 14px; + font-weight: normal; + + color: #999; + display: inline-block; + vertical-align: middle; + + height: 32px; + line-height: 30px; + padding: 0 16px; + border: 1px solid #eee; + border-radius: 4px; + + text-decoration: none; + + opacity: 0; + transition: opacity 400ms; +} From 324bb5d08cdc64c07422bc444cfd7394fb6b5ab9 Mon Sep 17 00:00:00 2001 From: fieg Date: Wed, 13 Apr 2022 17:17:24 +0200 Subject: [PATCH 03/24] added prev default --- src/defaults.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/defaults.js b/src/defaults.js index 4a80994d..c9a37001 100644 --- a/src/defaults.js +++ b/src/defaults.js @@ -1,6 +1,7 @@ export default { item: undefined, next: undefined, + prev: undefined, pagination: undefined, responseType: 'document', bind: true, From dc59d24896a67d95fd461fe9b7dfcdb6ce3fc86e Mon Sep 17 00:00:00 2001 From: fieg Date: Wed, 13 Apr 2022 17:17:49 +0200 Subject: [PATCH 04/24] added events for upwards scroll --- src/events.js | 10 ++++++++++ src/logger.js | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/events.js b/src/events.js index 736cdcd4..72d03a5a 100644 --- a/src/events.js +++ b/src/events.js @@ -1,14 +1,19 @@ export const APPEND = 'append'; export const APPENDED = 'appended'; +export const PREPEND = 'prepend'; +export const PREPENDED = 'prepended'; export const BINDED = 'binded'; export const UNBINDED = 'unbinded'; export const HIT = 'hit'; export const LOAD = 'load'; export const LOADED = 'loaded'; export const ERROR = 'error'; +export const FIRST = 'first'; export const LAST = 'last'; export const NEXT = 'next'; export const NEXTED = 'nexted'; +export const PREV = 'prev'; +export const PREVED = 'preved'; export const READY = 'ready'; export const SCROLLED = 'scrolled'; export const RESIZED = 'resized'; @@ -19,15 +24,20 @@ export const PREFILLED = 'prefilled'; const events = { APPEND, APPENDED, + PREPEND, + PREPENDED, BINDED, UNBINDED, HIT, LOAD, LOADED, ERROR, + FIRST, LAST, NEXT, NEXTED, + PREV, + PREVED, READY, SCROLLED, RESIZED, diff --git a/src/logger.js b/src/logger.js index 6003b6f1..1e78c8eb 100644 --- a/src/logger.js +++ b/src/logger.js @@ -22,6 +22,12 @@ const defaultLogger = { nexted: (event) => { console.log(`Next page completed [pageIndex=${event.pageIndex}]`); }, + prev: (event) => { + console.log(`Previous page triggered [pageIndex=${event.pageIndex}]`); + }, + preved: (event) => { + console.log(`Previous page completed [pageIndex=${event.pageIndex}]`); + }, load: (event) => { console.log(`Start loading ${event.url}`); }, @@ -34,9 +40,18 @@ const defaultLogger = { appended: (event) => { console.log(`Finished appending ${event.items.length} item(s)`); }, + prepend: () => { + console.log(`Start prepending items`); + }, + prepended: (event) => { + console.log(`Finished prepending ${event.items.length} item(s)`); + }, last: () => { console.log(`No more pages left to load`); }, + first: () => { + console.log(`Reached first page`); + }, page: (event) => { console.log(`Page changed [pageIndex=${event.pageIndex}]`); }, From 755850c3d3eac5a55d97e58c7699107b8a3d7fc4 Mon Sep 17 00:00:00 2001 From: fieg Date: Wed, 13 Apr 2022 17:18:09 +0200 Subject: [PATCH 05/24] prev and prepend handling --- src/paging.js | 29 +++++++++++++++++++++++++++++ src/prepend.js | 9 +++++++++ src/prev-handler.js | 27 +++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 src/prepend.js create mode 100644 src/prev-handler.js diff --git a/src/paging.js b/src/paging.js index 9a82856b..6e20e639 100644 --- a/src/paging.js +++ b/src/paging.js @@ -27,6 +27,7 @@ export default class Paging { ias.on(Events.BINDED, this.binded.bind(this)); ias.on(Events.NEXT, this.next.bind(this)); + ias.on(Events.PREV, this.prev.bind(this)); ias.on(Events.SCROLLED, this.scrolled.bind(this)); ias.on(Events.RESIZED, this.scrolled.bind(this)); } @@ -73,6 +74,34 @@ export default class Paging { }); } + prev() { + let url = document.location.toString(); + let title = document.title; + + let loaded = (event) => { + url = event.url; + + if (event.xhr.response) { + title = event.xhr.response.title + } + }; + + this.ias.once(Events.LOADED, loaded); + + this.ias.once(Events.PREVED, (event) => { + this.pageBreaks.unshift({ + pageIndex: event.pageIndex, + url, + title, + sentinel: this.ias.first() + }); + + this.update(); + + this.ias.off(Events.LOADED, loaded); + }); + } + scrolled(event) { this.update(event.scroll.y); } diff --git a/src/prepend.js b/src/prepend.js new file mode 100644 index 00000000..77a4f789 --- /dev/null +++ b/src/prepend.js @@ -0,0 +1,9 @@ +export function prependFn(items, parent, first) { + let insert = document.createDocumentFragment(); + + items.forEach((item) => { + insert.appendChild(item); + }); + + parent.insertBefore(insert, first); +} diff --git a/src/prev-handler.js b/src/prev-handler.js new file mode 100644 index 00000000..b34c5d88 --- /dev/null +++ b/src/prev-handler.js @@ -0,0 +1,27 @@ +import $ from 'tealight'; +import Assert from './assert'; + +export function prevHandler(pageIndex) { + let ias = this; + let lastResponse = document; // TODO: evaluate if this is correct + + let prevEl = $(ias.options.prev, lastResponse)[0]; + + if (!prevEl) { + Assert.warn(Assert.singleElement, ias.options.prev, 'options.prev'); + + return; + } + + let prevUrl = prevEl.href; + + return ias.load(prevUrl) + .then((data) => { + lastResponse = data.xhr.response; + + let prevEl = $(ias.options.prev, lastResponse)[0]; + + return ias.prepend(data.items) + .then(() => !!prevEl) // TODO: evaluate if this makes sense + }); +} From 795202b19bc4201a7413b53b70dd7308955781cb Mon Sep 17 00:00:00 2001 From: fieg Date: Fri, 15 Apr 2022 16:12:56 +0200 Subject: [PATCH 06/24] keep track of last prev element --- src/prev-handler.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/prev-handler.js b/src/prev-handler.js index b34c5d88..596bbc54 100644 --- a/src/prev-handler.js +++ b/src/prev-handler.js @@ -3,9 +3,7 @@ import Assert from './assert'; export function prevHandler(pageIndex) { let ias = this; - let lastResponse = document; // TODO: evaluate if this is correct - - let prevEl = $(ias.options.prev, lastResponse)[0]; + let prevEl = ias._prevEl || $(ias.options.prev, document)[0]; if (!prevEl) { Assert.warn(Assert.singleElement, ias.options.prev, 'options.prev'); @@ -17,9 +15,7 @@ export function prevHandler(pageIndex) { return ias.load(prevUrl) .then((data) => { - lastResponse = data.xhr.response; - - let prevEl = $(ias.options.prev, lastResponse)[0]; + let prevEl = ias._prevEl = $(ias.options.prev, data.xhr.response)[0]; return ias.prepend(data.items) .then(() => !!prevEl) // TODO: evaluate if this makes sense From d78f853d2c7e0296f36f87fbe86e51fcca8818c8 Mon Sep 17 00:00:00 2001 From: fieg Date: Fri, 15 Apr 2022 16:17:58 +0200 Subject: [PATCH 07/24] configure prev element --- examples/upwards/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/upwards/index.js b/examples/upwards/index.js index d1da4e44..3881a2b5 100644 --- a/examples/upwards/index.js +++ b/examples/upwards/index.js @@ -3,6 +3,7 @@ import InfiniteAjaxScroll from '@webcreate/infinite-ajax-scroll'; window.ias = new InfiniteAjaxScroll('.surface-container', { item: '.article', next: '.pager__next', + prev: '.pager__prev', pagination: '.pager', spinner: '.loader' }); From 72d360681d5b119ad5bbcf37a03bfea9271780b6 Mon Sep 17 00:00:00 2001 From: fieg Date: Fri, 15 Apr 2022 17:12:55 +0200 Subject: [PATCH 08/24] added top event --- src/events.js | 2 ++ src/logger.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/events.js b/src/events.js index 72d03a5a..140c6507 100644 --- a/src/events.js +++ b/src/events.js @@ -5,6 +5,7 @@ export const PREPENDED = 'prepended'; export const BINDED = 'binded'; export const UNBINDED = 'unbinded'; export const HIT = 'hit'; +export const TOP = 'top'; export const LOAD = 'load'; export const LOADED = 'loaded'; export const ERROR = 'error'; @@ -29,6 +30,7 @@ const events = { BINDED, UNBINDED, HIT, + TOP, LOAD, LOADED, ERROR, diff --git a/src/logger.js b/src/logger.js index 1e78c8eb..7bbdc62b 100644 --- a/src/logger.js +++ b/src/logger.js @@ -4,6 +4,9 @@ const defaultLogger = { hit: () => { console.log(`Hit scroll threshold`); }, + top: () => { + console.log(`Hit top scroll threshold`); + }, binded: () => { console.log(`Binded event handlers`); }, From e7313d1dfac45c22bbbfeaa7948a3bbe37839eba Mon Sep 17 00:00:00 2001 From: fieg Date: Fri, 15 Apr 2022 18:00:08 +0200 Subject: [PATCH 09/24] added upwards scroll logic --- src/infinite-ajax-scroll.js | 148 ++++++++++++++++++++++++++++++++---- 1 file changed, 135 insertions(+), 13 deletions(-) diff --git a/src/infinite-ajax-scroll.js b/src/infinite-ajax-scroll.js index 46e58b7b..0605a79c 100644 --- a/src/infinite-ajax-scroll.js +++ b/src/infinite-ajax-scroll.js @@ -7,12 +7,14 @@ import {scrollHandler} from "./event-handlers"; import Emitter from "tiny-emitter"; import {getDistanceToFold, getRootRect, getScrollPosition} from "./dimensions"; import {nextHandler} from './next-handler'; +import {prevHandler} from './prev-handler'; import Pagination from './pagination'; import Spinner from './spinner'; import Logger from './logger'; import Paging from './paging'; import Trigger from './trigger'; import {appendFn} from './append'; +import {prependFn} from './prepend'; import * as Events from './events'; import ResizeObserverFactory from './resize-observer'; import Prefill from "./prefill"; @@ -36,6 +38,7 @@ export default class InfiniteAjaxScroll { } this.nextHandler = nextHandler; + this.prevHandler = prevHandler; if (this.options.next === false) { this.nextHandler = function() {} @@ -43,6 +46,12 @@ export default class InfiniteAjaxScroll { this.nextHandler = this.options.next; } + if (this.options.prev === false) { + this.prevHandler = function() {} + } else if (typeof this.options.prev === 'function') { + this.prevHandler = this.options.prev; + } + this.resizeObserver = ResizeObserverFactory(this, this.scrollContainer); this._scrollListener = throttle(scrollHandler, 200).bind(this); @@ -50,7 +59,8 @@ export default class InfiniteAjaxScroll { this.bindOnReady = true; this.binded = false; this.paused = false; - this.pageIndex = this.sentinel() ? 0 : -1; + this.pageIndexPrev = 0; + this.pageIndex = this.pageIndexNext = this.sentinel() ? 0 : -1; this.on(Events.HIT, () => { if (!this.loadOnScroll) { @@ -60,6 +70,14 @@ export default class InfiniteAjaxScroll { this.next(); }); + this.on(Events.TOP, () => { + if (!this.loadOnScroll) { + return; + } + + this.prev(); + }); + this.on(Events.SCROLLED, this.measure); this.on(Events.RESIZED, this.measure); @@ -74,6 +92,11 @@ export default class InfiniteAjaxScroll { // prefill/measure after all plugins are done binding this.on(Events.BINDED, this.prefill.prefill.bind(this.prefill)); + this.hitFirst = this.hitLast = false; + + this.on(Events.LAST, () => this.hitLast = true); + this.on(Events.FIRST, () => this.hitFirst = true); + let ready = () => { if (this.ready) { return; @@ -132,6 +155,10 @@ export default class InfiniteAjaxScroll { } next() { + if (this.hitLast) { + return; + } + if (!this.binded) { if (!this.ready) { return this.once(Events.BINDED, this.next); @@ -142,23 +169,46 @@ export default class InfiniteAjaxScroll { this.pause(); - const pageIndex = this.pageIndex + 1; + const pageIndex = this.pageIndexNext + 1; - this.emitter.emit(Events.NEXT, {pageIndex: this.pageIndex + 1}); + this.emitter.emit(Events.NEXT, {pageIndex: this.pageIndexNext + 1}); return Promise.resolve(this.nextHandler(pageIndex)) .then((hasNextUrl) => { - this.pageIndex = pageIndex; + this.pageIndexNext = pageIndex; if (!hasNextUrl) { this.emitter.emit(Events.LAST); - - return; } this.resume(); }).then(() => { - this.emitter.emit(Events.NEXTED, {pageIndex: this.pageIndex}); + this.emitter.emit(Events.NEXTED, {pageIndex: this.pageIndexNext}); + }); + } + + prev() { + if (!this.binded || this.hitFirst) { + return; + } + + this.pause(); + + const pageIndex = this.pageIndexPrev - 1; + + this.emitter.emit(Events.PREV, {pageIndex: this.pageIndexPrev - 1}); + + return Promise.resolve(this.prevHandler(pageIndex)) + .then((hasPrevUrl) => { + this.pageIndexPrev = pageIndex; + + this.resume(); + + if (!hasPrevUrl) { + this.emitter.emit(Events.FIRST); + } + }).then(() => { + this.emitter.emit(Events.PREVED, {pageIndex: this.pageIndexPrev}); }); } @@ -272,6 +322,48 @@ export default class InfiniteAjaxScroll { }); } + /** + * @param {array} items + * @param {Element|null} parent + */ + prepend(items, parent) { + let ias = this; + parent = parent || ias.container; + + let event = { + items, + parent, + prependFn + }; + + ias.emitter.emit(Events.PREPEND, event); + + let executor = (resolve) => { + window.requestAnimationFrame(() => { + const first = ias.first(); + const scrollPositionStart = getScrollPosition(this.scrollContainer); + const topStart = first.getBoundingClientRect().top + scrollPositionStart.y; + + Promise.resolve(event.prependFn(event.items, event.parent, ias.first())) + .then(() => { + const scrollPositionEnd = getScrollPosition(this.scrollContainer); + const topEnd = first.getBoundingClientRect().top + scrollPositionEnd.y; + + let deltaY = topEnd - topStart; + + this.scrollContainer.scrollTo(scrollPositionEnd.x, deltaY); + }) + .then(() => { + resolve({items, parent}); + }); + }); + }; + + return (new Promise(executor)).then((event) => { + ias.emitter.emit(Events.PREPENDED, event); + }); + } + sentinel() { const items = $(this.options.item, this.container); @@ -282,6 +374,16 @@ export default class InfiniteAjaxScroll { return items[items.length-1]; } + first() { + const items = $(this.options.item, this.container); + + if (!items.length) { + return null; + } + + return items[0]; + } + pause() { this.paused = true; } @@ -298,9 +400,15 @@ export default class InfiniteAjaxScroll { this.loadOnScroll = false; } + /** + * @deprecated replaced by distanceBottom + */ distance(rootRect, sentinel) { - const _rootRect = rootRect || getRootRect(this.scrollContainer); + return this.distanceBottom(rootRect, sentinel); + } + distanceBottom(rootRect, sentinel) { + const _rootRect = rootRect || getRootRect(this.scrollContainer); const _sentinel = sentinel || this.sentinel(); const scrollPosition = getScrollPosition(this.scrollContainer); @@ -313,8 +421,14 @@ export default class InfiniteAjaxScroll { return distance; } + distanceTop() { + const scrollPosition = getScrollPosition(this.scrollContainer); + + return scrollPosition.y - this.negativeMargin; + } + measure() { - if (this.paused) { + if (this.paused || (this.hitFirst && this.hitLast)) { return; } @@ -330,12 +444,20 @@ export default class InfiniteAjaxScroll { return; } - const sentinel = this.sentinel(); + if (!this.hitFirst) { + let distanceTop = this.distanceTop(); - let distance = this.distance(rootRect, sentinel); + if (distanceTop <= 0) { + this.emitter.emit(Events.TOP, {distance: distanceTop}); + } + } - if (distance <= 0) { - this.emitter.emit(Events.HIT, {distance}); + if (!this.hitLast) { + let distanceBottom = this.distanceBottom(rootRect, this.sentinel()); + + if (distanceBottom <= 0) { + this.emitter.emit(Events.HIT, {distance: distanceBottom}); + } } } From 6aa8c75e90a12530879019fb671ef389addae740 Mon Sep 17 00:00:00 2001 From: fieg Date: Fri, 15 Apr 2022 18:00:25 +0200 Subject: [PATCH 10/24] prefill previous page --- src/prefill.js | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/prefill.js b/src/prefill.js index 6188b2c0..292c75d4 100644 --- a/src/prefill.js +++ b/src/prefill.js @@ -11,15 +11,9 @@ export default class Prefill { return; } - let distance = this.ias.distance(); - - if (distance > 0) { - return; - } - this.ias.emitter.emit(Events.PREFILL); - return this._prefill().then(() => { + return Promise.all([this._prefillNext(), this._prefillPrev()]).then(() => { this.ias.emitter.emit(Events.PREFILLED); // @todo reevaluate if we should actually call `measure` here. @@ -27,17 +21,33 @@ export default class Prefill { }); } - _prefill() { - return this.ias.next().then((hasNextUrl) => { - if (!hasNextUrl) { - return; - } + _prefillNext() { + let distance = this.ias.distance(); + + if (distance > 0) { + return; + } + + return this.ias.next() + .then((hasNextUrl) => { + if (!hasNextUrl) { + return; + } - let distance = this.ias.distance(); + let distance = this.ias.distance(); - if (distance < 0) { - return this._prefill(); - } - }); + if (distance < 0) { + return this._prefillNext(); + } + }) + ; + } + + _prefillPrev() { + if (!this.ias.options.prev) { + return; + } + + return this.ias.prev(); } } From d1d029aac7e016426f4671c2fd731fc8717eb4dd Mon Sep 17 00:00:00 2001 From: fieg Date: Mon, 18 Apr 2022 16:17:45 +0200 Subject: [PATCH 11/24] use document.body --- src/next-handler.js | 2 +- src/prev-handler.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/next-handler.js b/src/next-handler.js index 52188833..29077650 100644 --- a/src/next-handler.js +++ b/src/next-handler.js @@ -3,7 +3,7 @@ import Assert from './assert'; export function nextHandler(pageIndex) { let ias = this; - let lastResponse = ias._lastResponse || document; + let lastResponse = ias._lastResponse || document.body; let nextEl = $(ias.options.next, lastResponse)[0]; diff --git a/src/prev-handler.js b/src/prev-handler.js index 596bbc54..1003f533 100644 --- a/src/prev-handler.js +++ b/src/prev-handler.js @@ -3,7 +3,7 @@ import Assert from './assert'; export function prevHandler(pageIndex) { let ias = this; - let prevEl = ias._prevEl || $(ias.options.prev, document)[0]; + let prevEl = ias._prevEl || $(ias.options.prev, document.body)[0]; if (!prevEl) { Assert.warn(Assert.singleElement, ias.options.prev, 'options.prev'); From 8ff4df16ec6d93dbf11032911461811bdbedb2ac Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 12:34:53 +0200 Subject: [PATCH 12/24] merged upwards example to articles example --- examples/articles/index.js | 1 + examples/upwards/.gitignore | 5 -- examples/upwards/index.html | 42 --------- examples/upwards/index.js | 24 ------ examples/upwards/loader.svg | 20 ----- examples/upwards/package.json | 37 -------- examples/upwards/page2.html | 44 ---------- examples/upwards/page3.html | 42 --------- examples/upwards/style.css | 158 ---------------------------------- 9 files changed, 1 insertion(+), 372 deletions(-) delete mode 100644 examples/upwards/.gitignore delete mode 100644 examples/upwards/index.html delete mode 100644 examples/upwards/index.js delete mode 100644 examples/upwards/loader.svg delete mode 100644 examples/upwards/package.json delete mode 100644 examples/upwards/page2.html delete mode 100644 examples/upwards/page3.html delete mode 100644 examples/upwards/style.css diff --git a/examples/articles/index.js b/examples/articles/index.js index d1da4e44..3881a2b5 100644 --- a/examples/articles/index.js +++ b/examples/articles/index.js @@ -3,6 +3,7 @@ import InfiniteAjaxScroll from '@webcreate/infinite-ajax-scroll'; window.ias = new InfiniteAjaxScroll('.surface-container', { item: '.article', next: '.pager__next', + prev: '.pager__prev', pagination: '.pager', spinner: '.loader' }); diff --git a/examples/upwards/.gitignore b/examples/upwards/.gitignore deleted file mode 100644 index b5dd6d68..00000000 --- a/examples/upwards/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -dist -.cache -package-lock.json -.npmrc diff --git a/examples/upwards/index.html b/examples/upwards/index.html deleted file mode 100644 index 2c40a26c..00000000 --- a/examples/upwards/index.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - Infinite Scroll Example Blog - Infinite Ajax Scroll Example - - - - - - -
-
-

Infinite Scroll Example Blog

-

Rhoncus dolor purus non enim praesent elementum facilisis. Molestie a iaculis at erat pellentesque adipiscing commodo. Vulputate sapien nec sagittis aliquam malesuada bibendum arcu. Convallis tellus id interdum velit laoreet id donec ultrices tincidunt. Quis commodo odio aenean sed. Turpis massa tincidunt dui ut ornare lectus sit.

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Orci a scelerisque purus semper eget duis. Justo laoreet sit amet cursus sit amet dictum sit amet. Pellentesque dignissim enim sit amet. Enim blandit volutpat maecenas volutpat blandit. Vestibulum rhoncus est pellentesque elit ullamcorper. Est ultricies integer quis auctor elit sed vulputate mi.

-

Aliquet lectus proin nibh nisl condimentum id. Amet porttitor eget dolor morbi. In metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Sed euismod nisi porta lorem. Vulputate eu scelerisque felis imperdiet proin.

- -
- -
Amet porttitor eget dolor morbi.
-
- -

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Orci a scelerisque purus semper eget duis. Justo laoreet sit amet cursus sit amet dictum sit amet. Pellentesque dignissim enim sit amet. Enim blandit volutpat maecenas volutpat blandit. Vestibulum rhoncus est pellentesque elit ullamcorper. Est ultricies integer quis auctor elit sed vulputate mi.

-

Aliquet lectus proin nibh nisl condimentum id. Amet porttitor eget dolor morbi. In metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Sed euismod nisi porta lorem. Vulputate eu scelerisque felis imperdiet proin.

-
- -
-
-
No more pages
-
- - -
- - - - diff --git a/examples/upwards/index.js b/examples/upwards/index.js deleted file mode 100644 index 3881a2b5..00000000 --- a/examples/upwards/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import InfiniteAjaxScroll from '@webcreate/infinite-ajax-scroll'; - -window.ias = new InfiniteAjaxScroll('.surface-container', { - item: '.article', - next: '.pager__next', - prev: '.pager__prev', - pagination: '.pager', - spinner: '.loader' -}); - -ias.on('last', function() { - let el = document.querySelector('.no-more'); - - el.style.opacity = '1'; -}); - -// update title and url then scrolling through pages -ias.on('page', (e) => { - document.title = e.title; - - let state = history.state; - - history.replaceState(state, e.title, e.url); -}); diff --git a/examples/upwards/loader.svg b/examples/upwards/loader.svg deleted file mode 100644 index b8c9763c..00000000 --- a/examples/upwards/loader.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - diff --git a/examples/upwards/package.json b/examples/upwards/package.json deleted file mode 100644 index 56c8dba5..00000000 --- a/examples/upwards/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "infinite-ajax-scroll-upwards", - "description": "An example of an upwards infinite scroll", - "version": "1.0.0", - "homepage": "https://infiniteajaxscroll.com", - "repository": "github:webcreate/infinite-ajax-scroll", - "bugs": "https://github.com/webcreate/infinite-ajax-scroll/issues", - "author": { - "company": "Webcreate", - "name": "Jeroen Fiege", - "web": "https://webcreate.nl" - }, - "private": true, - "scripts": { - "build": "parcel build *.html --public-url ./", - "watch": "parcel watch * --public-url ./", - "link": "npm link ../../" - }, - "keywords": [ - "infinite-ajax-scroll", - "infinite-scroll", - "infinite", - "endless", - "scroll", - "scrolling", - "ajax", - "pagination", - "ias", - "jquery-ias" - ], - "dependencies": { - "@webcreate/infinite-ajax-scroll": "^3.0.0" - }, - "devDependencies": { - "parcel-bundler": "^1.12.4" - } -} diff --git a/examples/upwards/page2.html b/examples/upwards/page2.html deleted file mode 100644 index 9664c45f..00000000 --- a/examples/upwards/page2.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - Pellentesque habitant morbi senectus - Infinite Ajax Scroll Example - - - - - -
-
-

Pellentesque habitant morbi senectus

-

At augue eget arcu dictum varius. Tempus iaculis urna id volutpat lacus. Blandit massa enim nec dui nunc mattis. Fames ac turpis egestas maecenas pharetra convallis posuere. Facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum dui. Euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis. Aliquet risus feugiat in ante. Amet tellus cras adipiscing enim eu turpis egestas pretium.

- -
- -
At tempor commodo ullamcorper.
-
- -

Non curabitur gravida arcu ac tortor dignissim convallis. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt dui ut ornare lectus sit amet est placerat. Maecenas accumsan lacus vel facilisis. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed.

-

Vitae auctor eu augue ut lectus arcu bibendum at varius. Amet consectetur adipiscing elit pellentesque habitant morbi tristique. Elementum integer enim neque volutpat ac. At tempor commodo ullamcorper a. Diam quam nulla porttitor massa id neque aliquam vestibulum. Velit sed ullamcorper morbi tincidunt ornare massa. Urna duis convallis convallis tellus id.

- -

Sit amet volutpat consequat mauris nunc congue. Mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Proin libero nunc consequat interdum varius sit amet. Vitae semper quis lectus nulla at volutpat diam ut venenatis. Orci ac auctor augue mauris. Gravida rutrum quisque non tellus orci ac. Ornare arcu odio ut sem nulla pharetra diam sit. Vestibulum lectus mauris ultrices eros in cursus turpis massa.

-
- -
-
-
No more pages
-
- - -
- - - - - diff --git a/examples/upwards/page3.html b/examples/upwards/page3.html deleted file mode 100644 index 39fada39..00000000 --- a/examples/upwards/page3.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - Diam sollicitudin tempor id eu nisl - Infinite Ajax Scroll Example - - - - - -
-
-

Diam sollicitudin tempor id eu nisl

-

Maecenas accumsan lacus vel facilisis. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. Vitae suscipit tellus mauris a diam maecenas sed enim. Odio euismod lacinia at quis risus sed vulputate odio.

-

Urna cursus eget nunc scelerisque viverra. Dignissim enim sit amet venenatis. Eu facilisis sed odio morbi quis commodo odio aenean. Diam sollicitudin tempor id eu nisl nunc mi ipsum. Vulputate dignissim suspendisse in est ante. Eget mauris pharetra et ultrices neque ornare aenean. Augue mauris augue neque gravida in fermentum et sollicitudin ac. In nibh mauris cursus mattis. Morbi non arcu risus quis varius quam quisque id.

-

Enim lobortis scelerisque fermentum dui faucibus. Dolor sit amet consectetur adipiscing elit. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique. Vitae turpis massa sed elementum. Aliquet bibendum enim facilisis gravida neque convallis. Morbi tristique senectus et netus. Eleifend donec pretium vulputate sapien nec sagittis. Venenatis lectus magna fringilla urna porttitor rhoncus dolor. Aliquam purus sit amet luctus venenatis.

- -
- -
Feugiat in ante metus dictum at.
-
- -

Lorem dolor sed viverra ipsum nunc aliquet bibendum enim. In pellentesque massa placerat duis. Imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper. Feugiat in ante metus dictum at. Aenean sed adipiscing diam donec adipiscing tristique risus. Nulla at volutpat diam ut venenatis tellus in metus vulputate. Enim ut tellus elementum sagittis. Egestas pretium aenean pharetra magna ac placerat. Nunc non blandit massa enim.

-
- -
-
-
No more pages
-
- - -
- - - - - diff --git a/examples/upwards/style.css b/examples/upwards/style.css deleted file mode 100644 index 8c244ea2..00000000 --- a/examples/upwards/style.css +++ /dev/null @@ -1,158 +0,0 @@ -@import "https://fonts.googleapis.com/css?family=Source+Serif+Pro"; - -body { - margin: 0; - padding: 80px 0; -} - -.article { - margin: 80px auto 0; - padding: 0 20px; - max-width: 740px; -} - -.article h1 { - font-size: 38px; - color: rgba(0, 0, 0, .84); - - margin: 0; - padding: 0; - font-weight: 600; - - font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; -} - -.article .article__p--first { - margin-top: 10px; -} - -.article p { - margin: 29px 0 0 0; - - font-family: 'Source Serif Pro', Georgia, Cambria, "Times New Roman", Times, serif; - font-weight: 400; - font-style: normal; - font-size: 21px; - line-height: 1.58; - letter-spacing: -.003em; - - color: rgba(0, 0, 0, .84); - color: #333; - - -webkit-font-smoothing: antialiased; -} - -.article figure { - width: 100vw; - position: relative; - left: 50%; - right: 50%; - margin-left: -50vw; - margin-right: -50vw; - text-align: center; - - overflow: hidden; - margin-top: 29px; -} - -.article figure img { - height: 600px; - background-color: #efefef; -} - -@media (max-width: 1400px) { - .article figure img { - display: block; - width: 100%; - max-width: 1400px; - object-fit: cover; - } -} - -.article figure figcaption { - font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; - color: #999; - font-size: 13px; - font-weight: normal; - line-height: 2em; -} - -.pager { - margin: 29px 0 0; - text-align: center; - - font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; - font-size: 14px; - font-weight: normal; - line-height: 2em; -} - -.pager a, -.pager a:link, -.pager a:visited { - color: #999; - text-decoration: none; -} - -.pager a:hover, -.pager a:active { - color: #999; - text-decoration: underline; -} - -.status { - text-align: center; - margin-top: 29px; - min-height: 40px; -} - -.loader { - height: 40px; - margin-top: 0; - text-align: center; - background: transparent url('loader.svg') no-repeat center center; - background-size: 40px 19px; - opacity: 0; - animation: flipAnimation 1s infinite; - transition: opacity 300ms; -} - -/* @see https://medium.com/designer-recipes/understanding-card-flip-animation-using-css-391c40ed3136 */ -@keyframes flipAnimation { - 0% { - -ms-transform: rotateY(-180deg); /* IE 9 */ - -webkit-transform: rotateY(-180deg); /* Safari Chrome */ - transform: rotateY(-180deg); - } - 50% { - -ms-transform: rotateY(0deg); /* IE 9 */ - -webkit-transform: rotateY(0deg); /* Safari Chrome */ - transform: rotateY(0deg); - } - 100% { - -ms-transform: rotateY(-180deg); /* IE 9 */ - -webkit-transform: rotateY(-180deg); /* Safari Chrome */ - transform: rotateY(-180deg); - } -} - -.no-more { - font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Arial, sans-serif; - font-size: 14px; - font-weight: normal; - - color: #999; - display: inline-block; - vertical-align: middle; - - height: 32px; - line-height: 30px; - padding: 0 16px; - border: 1px solid #eee; - border-radius: 4px; - - text-decoration: none; - - opacity: 0; - transition: opacity 400ms; -} From 31ec302b6bc293594dcd9062cc1cfcc0853a4ed2 Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 12:35:04 +0200 Subject: [PATCH 13/24] disabled cache busting --- examples/articles/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/articles/index.js b/examples/articles/index.js index 3881a2b5..dfc81d27 100644 --- a/examples/articles/index.js +++ b/examples/articles/index.js @@ -22,3 +22,8 @@ ias.on('page', (e) => { history.replaceState(state, e.title, e.url); }); + +// disable cache busting +ias.on('load', function(event) { + event.nocache = true; +}); From f9da60d39de3f822421b5d37aff22f091d86b3c1 Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 12:43:51 +0200 Subject: [PATCH 14/24] documented events and option --- docs/events.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- docs/options.md | 18 +++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/docs/events.md b/docs/events.md index 6852983e..3c1482f6 100644 --- a/docs/events.md +++ b/docs/events.md @@ -63,6 +63,14 @@ Triggered when the user has hit the scroll threshold for the next page due to sc | :--- | :--- | :--- | | distance | int | The distance to the scroll threshold in pixels | +### top + +Triggered when the user has hit the top of the scroll area for the previous page due to scrolling or resizing. + +| property | type | description | +| :--- | :--- |:---------------------------------------| +| distance | int | The distance to the scroll top in pixels | + ### next Triggered right after the `hit` event. Indicating that the next page will be loaded. @@ -93,6 +101,36 @@ Trigger when loading and appending the next page is completed. | :--- | :--- | :--- | | pageIndex | int | The page index of the next page (the page that is finished loading) | +### prev + +Triggered right after the `top` event. Indicating that the previous page will be loaded. + +| property | type | description | +| :--- | :--- | :--- | +| pageIndex | int | The page index of the next page (the page that is about to be loaded) | + +> pageIndex is zero indexed. This means the index starts at 0 on the first page. + +For example to notify the user about loading the next page, you can do: + +```js +ias.on('prev', function(event) { + // pageIndex is 0-indexed, so we add 1 + alert(`Page ${event.pageIndex+1} is loading...`); +}); +ias.on('preved', function(event) { + alert(`Page ${event.pageIndex+1} is loaded and prepended to the page.`); +}); +``` + +### preved + +Trigger when loading and prepending the previous page is completed. + +| property | type | description | +| :--- | :--- | :--- | +| pageIndex | int | The page index of the next page (the page that is finished loading) | + ### load This event is triggered before the next page is requested from the server. @@ -158,18 +196,49 @@ This event is triggered after the items have been appended. | items | array | Array of items that have been appended | | parent | Element | The element to which the items have been appended | +### prepend + +This event is triggered before the items are about to be prepended. + +| property | type | description | +| :--- | :--- |:-------------------------------------------------| +| items | array | Array of items that will be prepended | +| parent | Element | The element to which the items will be prepended | +| prependFn | function | Function used to append items to the container | + +See [src/append.js](../src/append.js) for the default append function. + +### prepended + +This event is triggered after the items have been prepended. + +| property | type | description | +| :--- | :--- |:---------------------------------------------------| +| items | array | Array of items that have been prepended | +| parent | Element | The element to which the items have been prepended | + ### last Triggered when the last page is appended. ```javascript ias.on('last', () => { - console.log('Users has reached the last page'); + console.log('User has reached the last page'); }) ``` [Read more on how we can inform the user about reaching the last page](advanced/last-page-message.md) +### first + +Triggered when the last page is appended. + +```javascript +ias.on('first', () => { + console.log('User has reached the first page'); +}) +``` + ### page Triggered when the user scrolls past a page break. The event provides information about the page in view. diff --git a/docs/options.md b/docs/options.md index 2d26bf6e..0be959fe 100644 --- a/docs/options.md +++ b/docs/options.md @@ -44,6 +44,24 @@ let ias = new InfiniteAjaxScroll(/*..*/, { }) ``` +## prev + +**Type:** `string`
+**Default:** `undefined`
+**Required:** no + +Selector of the previous link. The `href` attribute will be used for the url of the previous page. Only a single element should match this selector. + +```html +Prev +``` + +```javascript +let ias = new InfiniteAjaxScroll(/*..*/, { + prev: '.pager__prev' +}) +``` + ## pagination **Type:** `boolean|string|Element`
From 1ff1d82b6989472ff341df47baf8914ed60d6a4e Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 13:09:37 +0200 Subject: [PATCH 15/24] removed calledOnce check as other events are triggered as well --- test/logger_spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/logger_spec.js b/test/logger_spec.js index 848d099e..a428333d 100644 --- a/test/logger_spec.js +++ b/test/logger_spec.js @@ -20,7 +20,6 @@ describe('Logger', () => { }); cy.get('@spy').should((consoleSpy) => { - expect(consoleSpy).to.have.been.calledOnce; expect(consoleSpy).to.have.been.calledWith( "Binded event handlers" ); From 78ab07ffdcdeb46be00b83520bb368c9fb8637e4 Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 13:10:02 +0200 Subject: [PATCH 16/24] return early when prev not configured --- src/prev-handler.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/prev-handler.js b/src/prev-handler.js index 1003f533..5e0c5a7a 100644 --- a/src/prev-handler.js +++ b/src/prev-handler.js @@ -5,6 +5,10 @@ export function prevHandler(pageIndex) { let ias = this; let prevEl = ias._prevEl || $(ias.options.prev, document.body)[0]; + if (ias.options.prev === undefined) { + return; + } + if (!prevEl) { Assert.warn(Assert.singleElement, ias.options.prev, 'options.prev'); From 76d31363c16d7756e446ab28bc9d873ef6b97282 Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 13:18:18 +0200 Subject: [PATCH 17/24] updated changelog --- CHANGELOG.md | 13 +++++++++++++ docs/options.md | 3 +++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4f424e9..410d0c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.1.0-beta.1] + +This version introduces upwards scroll support. See documentation on the [`prev`](docs/options.md#prev) option on how to enabled this feature. + +* Added [`prev`](docs/options.md#prev) option +* Added [`prev`](docs/events.md#prev) event +* Added [`preved`](docs/events.md#preved) event +* Added [`top`](docs/events.md#top) event +* Added [`first`](docs/events.md#first) event +* Added [`prepend`](docs/events.md#prepend) event +* Added [`prepended`](docs/events.md#prepended) event + ## [3.0.0] Changes since 3.0.0-rc.1: @@ -107,6 +119,7 @@ See [LICENSE](LICENSE) for more details. * Extensible through events * Added an extensive test suite +[3.1.0-beta.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.0...3.1.0-beta.1 [3.0.0]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.0-rc.1...3.0.0 [3.0.0-rc.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/v2.3.1...3.0.0-rc.1 [2.3.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/v2.3.0...v2.3.1 diff --git a/docs/options.md b/docs/options.md index 0be959fe..b4df5577 100644 --- a/docs/options.md +++ b/docs/options.md @@ -54,10 +54,13 @@ Selector of the previous link. The `href` attribute will be used for the url of ```html Prev +2 +Next ``` ```javascript let ias = new InfiniteAjaxScroll(/*..*/, { + next: '.pager__next', prev: '.pager__prev' }) ``` From d917981d140915d0f925c590a0ffbc09d9ff8615 Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 13:19:58 +0200 Subject: [PATCH 18/24] updated readme to include prev option in example --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bc434de..a692b7e3 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,9 @@ Infinite Ajax Scroll works on a container with item elements which get appended. ``` @@ -62,6 +64,7 @@ import InfiniteAjaxScroll from '@webcreate/infinite-ajax-scroll'; let ias = new InfiniteAjaxScroll('.container', { item: '.item', next: '.next', + prev: '.prev', pagination: '.pagination' }); ``` From b7b7995c4feca3f131141ef643e6603f02b7b77f Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 13:21:29 +0200 Subject: [PATCH 19/24] linked to issue in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 410d0c80..ae68da71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.1.0-beta.1] -This version introduces upwards scroll support. See documentation on the [`prev`](docs/options.md#prev) option on how to enabled this feature. +This version introduces upwards scroll support (fixes [#466](https://github.com/webcreate/infinite-ajax-scroll/issues/466)). See documentation on the [`prev`](docs/options.md#prev) option on how to enable this feature. * Added [`prev`](docs/options.md#prev) option * Added [`prev`](docs/events.md#prev) event From 4b39bd85bafbfe4f75545e63b560678ce4f8e182 Mon Sep 17 00:00:00 2001 From: fieg Date: Tue, 30 Aug 2022 13:39:16 +0200 Subject: [PATCH 20/24] bumped version to 3.1.0-beta.1 --- examples/articles/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/articles/package.json b/examples/articles/package.json index 106488bb..0e397a25 100644 --- a/examples/articles/package.json +++ b/examples/articles/package.json @@ -29,7 +29,7 @@ "jquery-ias" ], "dependencies": { - "@webcreate/infinite-ajax-scroll": "^3.0.0" + "@webcreate/infinite-ajax-scroll": "^3.1.0-beta.1" }, "devDependencies": { "parcel-bundler": "^1.12.4" diff --git a/package.json b/package.json index 9dbfdd22..346087fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@webcreate/infinite-ajax-scroll", - "version": "3.0.0", + "version": "3.1.0-beta.1", "title": "Infinite Ajax Scroll", "description": "Turn your existing pagination into infinite scrolling pages with ease", "license": "AGPL-3.0-only", From fafadea2d9d32bf3dff5167735006603a619f9d4 Mon Sep 17 00:00:00 2001 From: fieg Date: Thu, 8 Sep 2022 17:20:11 +0200 Subject: [PATCH 21/24] pass along hasPrevUrl --- src/infinite-ajax-scroll.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/infinite-ajax-scroll.js b/src/infinite-ajax-scroll.js index 8fec88ee..33569cee 100644 --- a/src/infinite-ajax-scroll.js +++ b/src/infinite-ajax-scroll.js @@ -211,8 +211,12 @@ export default class InfiniteAjaxScroll { if (!hasPrevUrl) { this.emitter.emit(Events.FIRST); } - }).then(() => { + + return hasPrevUrl; + }).then((hasPrevUrl) => { this.emitter.emit(Events.PREVED, {pageIndex: this.pageIndexPrev}); + + return hasPrevUrl; }); } From 1ef31f6b1a22de5181b86d6807a04f05af0d36ff Mon Sep 17 00:00:00 2001 From: fieg Date: Sun, 9 Apr 2023 15:31:01 +0200 Subject: [PATCH 22/24] Preparation for 3.1.0 release * Added upwards scroll documentation * Updated changelog and upgrade docs * Other documentation fixes * Bumped versions --- CHANGELOG.md | 8 ++++- README.md | 2 +- UPGRADE.md | 5 +++ docs/README.md | 1 + docs/advanced/history.md | 7 ++-- docs/advanced/upwards.md | 61 ++++++++++++++++++++++++++++++++++ docs/events.md | 24 +++++++++---- docs/options.md | 2 ++ examples/articles/package.json | 2 +- package.json | 2 +- 10 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 docs/advanced/upwards.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b09ce60..83c04792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.1.0] + +* Adds all features from 3.1.0-beta.1 +* Added [`upwards`](docs/advanced/upwards.md) documentation + ## [3.1.0-beta.1] This version introduces upwards scroll support (fixes [#466](https://github.com/webcreate/infinite-ajax-scroll/issues/466)). See documentation on the [`prev`](docs/options.md#prev) option on how to enable this feature. @@ -123,7 +128,8 @@ See [LICENSE](LICENSE) for more details. * Extensible through events * Added an extensive test suite -[3.1.0-beta.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.0...3.1.0-beta.1 +[3.1.0]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.1...3.1.0 +[3.1.0-beta.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.1...3.1.0-beta.1 [3.0.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/webcreate/infinite-ajax-scroll/compare/3.0.0-rc.1...3.0.0 [3.0.0-rc.1]: https://github.com/webcreate/infinite-ajax-scroll/compare/v2.3.1...3.0.0-rc.1 diff --git a/README.md b/README.md index d7f978d4..cb54c9b1 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Infinite Ajax Scroll works on a container with item elements which get appended. ``` diff --git a/UPGRADE.md b/UPGRADE.md index 2db5b755..7144ce78 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,3 +1,8 @@ +Upgrade from 3.0.x to 3.1.0 +=========================== + +Version 3.1.0 is backwards-compatible with 3.0.x. + Upgrade from 2.3.x to 3.0 ========================= diff --git a/docs/README.md b/docs/README.md index 717ab8c2..b9fa2b79 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,3 +18,4 @@ * [Last page message](advanced/last-page-message.md) * [History](advanced/history.md) * [Overflow](advanced/overflow.md) +* [Upward scroll](advanced/upwards.md) diff --git a/docs/advanced/history.md b/docs/advanced/history.md index 6e00e827..1fd27b25 100644 --- a/docs/advanced/history.md +++ b/docs/advanced/history.md @@ -23,6 +23,7 @@ ias.on('page', (event) => { ## Loading previous pages -{% hint style='working' %} -This feature is still work in progress -{% endhint %} +Infinite Ajax Scroll can also be used to load items above the current scroll position. This is useful when you want to load older items first. + +[View upwards infinite scroll documentation](upwards.md) + diff --git a/docs/advanced/upwards.md b/docs/advanced/upwards.md new file mode 100644 index 00000000..0185e513 --- /dev/null +++ b/docs/advanced/upwards.md @@ -0,0 +1,61 @@ +# Upward Infinite Scroll + +Infinite Ajax Scroll can also be used to load items above the current scroll position. This is useful when you want to load older items first. + +*Introduced in Infinite Ajax Scroll 3.1.0* + +## Caveats + +### Fixed height images + +Upward scroll works by calculation screen height and content height. Due to they way browser load content, especially images, this could cause incorrect measurements. This can be solved by using fixed height images. + +## Setup + +1. Add a previous page link to your pagination. + + ```html + + ``` + +2. Configure the [`prev`](../options.md#prev) option. + + ```javascript + // import if you use the NPM package + import InfiniteAjaxScroll from '@webcreate/infinite-ajax-scroll'; + + let ias = new InfiniteAjaxScroll('.container', { + item: '.item', + next: '.next', + prev: '.prev', + pagination: '.pagination' + }); + ``` + +## Hook into upward scroll with events + +In this example we notify the user about loading the previous page. + +```js +ias.on('prev', function(event) { + // pageIndex is 0-indexed, so we add 1 + alert(`Page ${event.pageIndex+1} is loading...`); +}); +ias.on('preved', function(event) { + alert(`Page ${event.pageIndex+1} is loaded and prepended to the page.`); +}); +``` + +## Inform user about first page reached + +In this example we notify the user when the first page is reached. + +```javascript +ias.on('first', () => { + console.log('User has reached the first page'); +}) +``` diff --git a/docs/events.md b/docs/events.md index 3c1482f6..51483d1f 100644 --- a/docs/events.md +++ b/docs/events.md @@ -65,6 +65,8 @@ Triggered when the user has hit the scroll threshold for the next page due to sc ### top +*Introduced in Infinite Ajax Scroll 3.1.0* + Triggered when the user has hit the top of the scroll area for the previous page due to scrolling or resizing. | property | type | description | @@ -103,15 +105,17 @@ Trigger when loading and appending the next page is completed. ### prev +*Introduced in Infinite Ajax Scroll 3.1.0* + Triggered right after the `top` event. Indicating that the previous page will be loaded. -| property | type | description | -| :--- | :--- | :--- | -| pageIndex | int | The page index of the next page (the page that is about to be loaded) | +| property | type | description | +| :--- | :--- |:----------------------------------------------------------------------| +| pageIndex | int | The page index of the prev page (the page that is about to be loaded) | > pageIndex is zero indexed. This means the index starts at 0 on the first page. -For example to notify the user about loading the next page, you can do: +For example to notify the user about loading the previous page, you can do: ```js ias.on('prev', function(event) { @@ -125,6 +129,8 @@ ias.on('preved', function(event) { ### preved +*Introduced in Infinite Ajax Scroll 3.1.0* + Trigger when loading and prepending the previous page is completed. | property | type | description | @@ -198,18 +204,22 @@ This event is triggered after the items have been appended. ### prepend +*Introduced in Infinite Ajax Scroll 3.1.0* + This event is triggered before the items are about to be prepended. | property | type | description | | :--- | :--- |:-------------------------------------------------| | items | array | Array of items that will be prepended | | parent | Element | The element to which the items will be prepended | -| prependFn | function | Function used to append items to the container | +| prependFn | function | Function used to prepend items to the container | -See [src/append.js](../src/append.js) for the default append function. +See [src/prepend.js](../src/prepend.js) for the default prepend function. ### prepended +*Introduced in Infinite Ajax Scroll 3.1.0* + This event is triggered after the items have been prepended. | property | type | description | @@ -231,6 +241,8 @@ ias.on('last', () => { ### first +*Introduced in Infinite Ajax Scroll 3.1.0* + Triggered when the last page is appended. ```javascript diff --git a/docs/options.md b/docs/options.md index b4df5577..2f728ee8 100644 --- a/docs/options.md +++ b/docs/options.md @@ -46,6 +46,8 @@ let ias = new InfiniteAjaxScroll(/*..*/, { ## prev +*Introduced in Infinite Ajax Scroll 3.1.0* + **Type:** `string`
**Default:** `undefined`
**Required:** no diff --git a/examples/articles/package.json b/examples/articles/package.json index 7656adc6..906fcb2c 100644 --- a/examples/articles/package.json +++ b/examples/articles/package.json @@ -29,7 +29,7 @@ "jquery-ias" ], "dependencies": { - "@webcreate/infinite-ajax-scroll": "^3.1.0-beta.1" + "@webcreate/infinite-ajax-scroll": "^3.1.0" }, "devDependencies": { "parcel": "^2.0.0" diff --git a/package.json b/package.json index 346087fb..c4c680ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@webcreate/infinite-ajax-scroll", - "version": "3.1.0-beta.1", + "version": "3.1.0", "title": "Infinite Ajax Scroll", "description": "Turn your existing pagination into infinite scrolling pages with ease", "license": "AGPL-3.0-only", From 207a356f18ae3cf79351ca9237083a041d08bda5 Mon Sep 17 00:00:00 2001 From: fieg Date: Sun, 9 Apr 2023 15:35:46 +0200 Subject: [PATCH 23/24] removed merge conflict residue --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1743b0ee..83c04792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,6 @@ This version introduces upwards scroll support (fixes [#466](https://github.com/ ## [3.0.1] * Fixed prefill not filling past the scroll threshold ->>>>>>>>> Temporary merge branch 2 ## [3.0.0] From d19b00a656c5593e63ddc55ac5ee52274692a225 Mon Sep 17 00:00:00 2001 From: fieg Date: Sun, 9 Apr 2023 15:43:16 +0200 Subject: [PATCH 24/24] added descriptive text to 3.1.0 version in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c04792..11f687c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.1.0] +This version introduces upwards scroll support (fixes [#466](https://github.com/webcreate/infinite-ajax-scroll/issues/466)). See [`upwards scroll`](docs/advanced/upwards.md) documentation on how to use this feature. + * Adds all features from 3.1.0-beta.1 * Added [`upwards`](docs/advanced/upwards.md) documentation