Skip to content

Commit

Permalink
Merge pull request #52 from Elkfox/v3.0
Browse files Browse the repository at this point in the history
v3.0.0
  • Loading branch information
Cam authored Jan 30, 2020
2 parents a2a2a04 + f259508 commit 601c638
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 83 deletions.
11 changes: 6 additions & 5 deletions docs/book/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ $ npm i ajaxinate
```

```javascript
import Ajaxinate from 'ajaxinate';
import {Ajaxinate} from 'ajaxinate';

const endlessScroll = new Ajaxinate();

endlessScroll();
new Ajaxinate({
container: '#AjaxinateContainer',
pagination: '#AjaxinatePagination',
loadingText: 'Loading more...',
});
```

### Manual installation
Expand Down Expand Up @@ -54,4 +56,3 @@ endlessScroll();
```

5. Configure your settings as desired.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "ajaxinate",
"license": "MIT",
"description": "Ajax Pagination Javascript Plugin",
"version": "2.0.11",
"version": "3.0.0",
"author": "Elkfox <[email protected]> (https://elkfox.io)",
"repository": {
"type": "git",
Expand Down
184 changes: 107 additions & 77 deletions src/ajaxinate.js
Original file line number Diff line number Diff line change
@@ -1,143 +1,173 @@
/* ===================================================================================== @preserve =
___ _ _ _
/ || | | | | |
\__ | | | | | | __
/ |/ |/_) |/ / \_/\/
\___/|__/| \_/|__/\__/ /\_/
|\
|/
Ajaxinate
version v2.0.11
https://github.com/Elkfox/Ajaxinate
Copyright (c) 2017 Elkfox Co Pty Ltd
https://elkfox.com
MIT License
================================================================================================= */

export const Ajaxinate = function ajaxinateConstructor(config) {
/* @preserve
* https://github.com/Elkfox/Ajaxinate
* Copyright (c) 2017 Elkfox Co Pty Ltd (elkfox.com)
* MIT License (do not remove above copyright!)
*/

/* Configurable options;
*
* method: scroll or click
* container: selector of repeating content
* pagination: selector of pagination container
* offset: number of pixels before the bottom to start loading more on scroll
* loadingText: 'Loading', The text shown during when appending new content
* callback: null, callback function after new content is appended
*
* Usage;
*
* import {Ajaxinate} from 'ajaxinate';
*
* new Ajaxinate({
* offset: 5000,
* loadingText: 'Loading more...',
* });
*/

/* eslint-env browser */
export function Ajaxinate(config) {
const settings = config || {};
/*
pagination: Selector of pagination container
method: [options are 'scroll', 'click']
container: Selector of repeating content
offset: 0, offset the number of pixels before the bottom to start loading more on scroll
loadingText: 'Loading', The text changed during loading
callback: null, function to callback after a new page is loaded
*/
const defaultSettings = {
pagination: '#AjaxinatePagination',

const defaults = {
method: 'scroll',
container: '#AjaxinateLoop',
container: '#AjaxinateContainer',
pagination: '#AjaxinatePagination',
offset: 0,
loadingText: 'Loading',
callback: null,
};
// Merge configs
this.settings = Object.assign(defaultSettings, settings);

// Bind 'this' to applicable prototype functions
// Merge custom configs with defaults
this.settings = Object.assign(defaults, settings);

// Functions
this.addScrollListeners = this.addScrollListeners.bind(this);
this.addClickListener = this.addClickListener.bind(this);
this.checkIfPaginationInView = this.checkIfPaginationInView.bind(this);
this.stopMultipleClicks = this.stopMultipleClicks.bind(this);
this.preventMultipleClicks = this.preventMultipleClicks.bind(this);
this.removeClickListener = this.removeClickListener.bind(this);
this.removeScrollListener = this.removeScrollListener.bind(this);
this.removePaginationElement = this.removePaginationElement.bind(this);
this.destroy = this.destroy.bind(this);

// Set up our element selectors
// Selectors
this.containerElement = document.querySelector(this.settings.container);
this.paginationElement = document.querySelector(this.settings.pagination);

this.initialize();
};
}

Ajaxinate.prototype.initialize = function initializeTheCorrectFunctionsBasedOnTheMethod() {
// Find and initialise the correct function based on the method set in the config
if (this.containerElement) {
const initializers = {
click: this.addClickListener,
scroll: this.addScrollListeners,
};
initializers[this.settings.method]();
}
Ajaxinate.prototype.initialize = function initialize() {
if (!this.containerElement) { return; }

const initializers = {
click: this.addClickListener,
scroll: this.addScrollListeners,
};

initializers[this.settings.method]();
};

Ajaxinate.prototype.addScrollListeners = function addEventListenersForScrolling() {
if (this.paginationElement) {
document.addEventListener('scroll', this.checkIfPaginationInView);
window.addEventListener('resize', this.checkIfPaginationInView);
window.addEventListener('orientationchange', this.checkIfPaginationInView);
}
Ajaxinate.prototype.addScrollListeners = function addScrollListeners() {
if (!this.paginationElement) { return; }

document.addEventListener('scroll', this.checkIfPaginationInView);
window.addEventListener('resize', this.checkIfPaginationInView);
window.addEventListener('orientationchange', this.checkIfPaginationInView);
};

Ajaxinate.prototype.addClickListener = function addEventListenerForClicking() {
if (this.paginationElement) {
this.nextPageLinkElement = this.paginationElement.querySelector('a');
this.clickActive = true;
if (this.nextPageLinkElement !== null) {
this.nextPageLinkElement.addEventListener('click', this.stopMultipleClicks);
}
Ajaxinate.prototype.addClickListener = function addClickListener() {
if (!this.paginationElement) { return; }

this.nextPageLinkElement = this.paginationElement.querySelector('a');
this.clickActive = true;

if (typeof this.nextPageLinkElement !== 'undefined') {
this.nextPageLinkElement.addEventListener('click', this.preventMultipleClicks);
}
};

Ajaxinate.prototype.stopMultipleClicks = function handleClickEvent(event) {
Ajaxinate.prototype.preventMultipleClicks = function preventMultipleClicks(event) {
event.preventDefault();
if (this.clickActive) {
this.nextPageLinkElement.innerHTML = this.settings.loadingText;
this.nextPageUrl = this.nextPageLinkElement.href;
this.clickActive = false;
this.loadMore();
}

if (!this.clickActive) { return; }

this.nextPageLinkElement.innerText = this.settings.loadingText;
this.nextPageUrl = this.nextPageLinkElement.href;
this.clickActive = false;

this.loadMore();
};

Ajaxinate.prototype.checkIfPaginationInView = function handleScrollEvent() {
Ajaxinate.prototype.checkIfPaginationInView = function checkIfPaginationInView() {
const top = this.paginationElement.getBoundingClientRect().top - this.settings.offset;
const bottom = this.paginationElement.getBoundingClientRect().bottom + this.settings.offset;

if (top <= window.innerHeight && bottom >= 0) {
this.nextPageLinkElement = this.paginationElement.querySelector('a');
this.removeScrollListener();

if (this.nextPageLinkElement) {
this.nextPageLinkElement.innerHTML = this.settings.loadingText;
this.nextPageLinkElement.innerText = this.settings.loadingText;
this.nextPageUrl = this.nextPageLinkElement.href;

this.loadMore();
}
}
};

Ajaxinate.prototype.loadMore = function getTheHtmlOfTheNextPageWithAnAjaxRequest() {
Ajaxinate.prototype.loadMore = function loadMore() {
this.request = new XMLHttpRequest();

this.request.onreadystatechange = function success() {
if (this.request.readyState === 4 && this.request.status === 200) {
const newContainer = this.request.responseXML.querySelectorAll(this.settings.container)[0];
const newPagination = this.request.responseXML.querySelectorAll(this.settings.pagination)[0];
this.containerElement.insertAdjacentHTML('beforeend', newContainer.innerHTML);
if (!this.request.responseXML) { return; }
if (!this.request.readyState === 4 || !this.request.status === 200) { return; }

const newContainer = this.request.responseXML.querySelectorAll(this.settings.container)[0];
const newPagination = this.request.responseXML.querySelectorAll(this.settings.pagination)[0];

this.containerElement.insertAdjacentHTML('beforeend', newContainer.innerHTML);

if (typeof newPagination === 'undefined') {
this.removePaginationElement();
} else {
this.paginationElement.innerHTML = newPagination.innerHTML;

if (this.settings.callback && typeof this.settings.callback === 'function') {
this.settings.callback(this.request.responseXML);
}

this.initialize();
}
}.bind(this);

this.request.open('GET', this.nextPageUrl);
this.request.responseType = 'document';
this.request.send();
};

Ajaxinate.prototype.removeClickListener = function removeClickEventListener() {
this.nextPageLinkElement.addEventListener('click', this.stopMultipleClicks);
Ajaxinate.prototype.removeClickListener = function removeClickListener() {
this.nextPageLinkElement.removeEventListener('click', this.preventMultipleClicks);
};

Ajaxinate.prototype.removeScrollListener = function removeScrollEventListener() {
Ajaxinate.prototype.removePaginationElement = function removePaginationElement() {
this.paginationElement.innerHTML = '';
this.destroy();
};

Ajaxinate.prototype.removeScrollListener = function removeScrollListener() {
document.removeEventListener('scroll', this.checkIfPaginationInView);
window.removeEventListener('resize', this.checkIfPaginationInView);
window.removeEventListener('orientationchange', this.checkIfPaginationInView);
};

Ajaxinate.prototype.destroy = function removeEventListenersAndReturnThis() {
// This method is used to unbind event listeners from the DOM
// This function is called manually to destroy "this" Ajaxinate instance
Ajaxinate.prototype.destroy = function destroy() {
const destroyers = {
click: this.removeClickListener,
scroll: this.removeScrollListener,
};

destroyers[this.settings.method]();

return this;
};

export default Ajaxinate;

0 comments on commit 601c638

Please sign in to comment.