Skip to content

Commit

Permalink
🎉 Add loaded callback (ApoorvSaxena#86)
Browse files Browse the repository at this point in the history
* 🎉 Add loaded callback

* 📝 Add documentation

* 🐛 Fix overwriting of markAsLoaded method

`markAsLoaded` is required to run for the `isLoaded` method to be useful.

Also added a negative test for when a custom `load` option is passed in.

* 🚿 Remove commented out code
  • Loading branch information
joshwhatk authored and ApoorvSaxena committed Feb 15, 2018
1 parent 4cb5593 commit c2c9e67
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 11 deletions.
12 changes: 12 additions & 0 deletions README.md
Expand Up @@ -112,6 +112,18 @@ lozad('.lozad', {
});
```

If you would like to extend the `loaded` state of elements, you can add the loaded option:

> **Note**: The `"data-loaded"="true"` attribute is used by lozad to determine if an element has been previously loaded.
```js
lozad('.lozad', {
loaded: function(el) {
// Custom implementation on a loaded element
el.classList.add('loaded');
}
});
```

If you want to lazy load dynamically added elements:

```js
Expand Down
15 changes: 10 additions & 5 deletions dist/lozad.js
@@ -1,4 +1,4 @@
/*! lozad.js - v1.2.0 - 2018-01-24
/*! lozad.js - v1.2.0 - 2018-02-10
* https://github.com/ApoorvSaxena/lozad.js
* Copyright (c) 2018 Apoorv Saxena; Licensed MIT */

Expand Down Expand Up @@ -38,7 +38,8 @@ var defaultConfig = {
if (element.getAttribute('data-background-image')) {
element.style.backgroundImage = 'url(' + element.getAttribute('data-background-image') + ')';
}
}
},
loaded: function loaded() {}
};

function markAsLoaded(element) {
Expand All @@ -49,7 +50,7 @@ var isLoaded = function isLoaded(element) {
return element.getAttribute('data-loaded') === 'true';
};

var onIntersection = function onIntersection(load) {
var onIntersection = function onIntersection(load, loaded) {
return function (entries, observer) {
entries.forEach(function (entry) {
if (entry.intersectionRatio > 0) {
Expand All @@ -58,6 +59,7 @@ var onIntersection = function onIntersection(load) {
if (!isLoaded(entry.target)) {
load(entry.target);
markAsLoaded(entry.target);
loaded(entry.target);
}
}
});
Expand All @@ -81,12 +83,13 @@ var lozad = function () {
var _defaultConfig$option = _extends({}, defaultConfig, options),
rootMargin = _defaultConfig$option.rootMargin,
threshold = _defaultConfig$option.threshold,
load = _defaultConfig$option.load;
load = _defaultConfig$option.load,
loaded = _defaultConfig$option.loaded;

var observer = void 0;

if (window.IntersectionObserver) {
observer = new IntersectionObserver(onIntersection(load), {
observer = new IntersectionObserver(onIntersection(load, loaded), {
rootMargin: rootMargin,
threshold: threshold
});
Expand All @@ -106,6 +109,7 @@ var lozad = function () {
}
load(elements[i]);
markAsLoaded(elements[i]);
loaded(elements[i]);
}
},
triggerLoad: function triggerLoad(element) {
Expand All @@ -115,6 +119,7 @@ var lozad = function () {

load(element);
markAsLoaded(element);
loaded(element);
}
};
};
Expand Down
4 changes: 2 additions & 2 deletions dist/lozad.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions src/lozad.js
Expand Up @@ -25,7 +25,8 @@ const defaultConfig = {
if (element.getAttribute('data-background-image')) {
element.style.backgroundImage = `url(${element.getAttribute('data-background-image')})`
}
}
},
loaded() {}
}

function markAsLoaded(element) {
Expand All @@ -34,14 +35,15 @@ function markAsLoaded(element) {

const isLoaded = element => element.getAttribute('data-loaded') === 'true'

const onIntersection = load => (entries, observer) => {
const onIntersection = (load, loaded) => (entries, observer) => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
observer.unobserve(entry.target)

if (!isLoaded(entry.target)) {
load(entry.target)
markAsLoaded(entry.target)
loaded(entry.target)
}
}
})
Expand All @@ -58,11 +60,11 @@ const getElements = selector => {
}

export default function (selector = '.lozad', options = {}) {
const {rootMargin, threshold, load} = {...defaultConfig, ...options}
const {rootMargin, threshold, load, loaded} = {...defaultConfig, ...options}
let observer

if (window.IntersectionObserver) {
observer = new IntersectionObserver(onIntersection(load), {
observer = new IntersectionObserver(onIntersection(load, loaded), {
rootMargin,
threshold
})
Expand All @@ -82,6 +84,7 @@ export default function (selector = '.lozad', options = {}) {
}
load(elements[i])
markAsLoaded(elements[i])
loaded(elements[i])
}
},
triggerLoad(element) {
Expand All @@ -91,6 +94,7 @@ export default function (selector = '.lozad', options = {}) {

load(element)
markAsLoaded(element)
loaded(element)
}
}
}
49 changes: 49 additions & 0 deletions test/index.js
Expand Up @@ -162,6 +162,55 @@ describe('lozad', () => {
})
})

describe('when passing options', () => {
beforeEach(() => {
document.body.innerHTML = ''
const image = document.createElement('img')
image.dataset.src = Math.random()
.toString(36)
.substring(7)
document.body.appendChild(image)
})

it('should not load elements by default when custom load option is passed in', () => {
const observer = lozad('.lozad', {
load(element) {
element.classList.add('loaded')
}
})
const image = document.getElementsByTagName('img')[0]
image.setAttribute('class', 'lozad')
observer.observe()
assert.equal(true, image.classList.contains('loaded'))
assert.equal(null, image.getAttribute('src'))
})

it('should run loaded option after loading an element', () => {
const observer = lozad('.lozad', {
loaded(element) {
element.classList.add('loaded')
}
})
const image = document.getElementsByTagName('img')[0]
image.setAttribute('class', 'lozad')
observer.observe()
assert.equal(true, image.classList.contains('loaded'))
})

it('should set data attribute when loaded option is passed in', () => {
const observer = lozad('.lozad', {
loaded(element) {
element.classList.add('loaded')
}
})
const image = document.getElementsByTagName('img')[0]
image.setAttribute('class', 'lozad')
observer.observe()
assert.equal(true, image.classList.contains('loaded'))
assert.equal('true', image.dataset.loaded)
})
})

describe('public API functions', () => {
beforeEach(() => {
document.body.innerHTML = ''
Expand Down

0 comments on commit c2c9e67

Please sign in to comment.