Created
August 26, 2019 18:10
-
-
Save derekshirk/0e4c7abd7b31e19a128e66ea703b0dc7 to your computer and use it in GitHub Desktop.
Image Swapping with data attributes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import $ from 'jquery'; | |
const NAME = 'swapImage'; | |
const DATA_KEY = `decathlon.${NAME}`; | |
const EVENT_KEY = `.${DATA_KEY}`; | |
const ClassName = { | |
CURRENT: 'is-current', | |
LOADING: 'is-loading' | |
}; | |
const EventName = { | |
LOAD: `load${EVENT_KEY}` | |
}; | |
const AttrName = { | |
ALT: 'data-swap-image-alt', | |
SIZES: 'data-swap-image-sizes', | |
SRC: 'data-swap-image-src', | |
SRCSET: 'data-swap-image-srcset', | |
TARGET: 'data-swap-image-target', | |
ZOOM: 'data-swap-image-zoom' | |
}; | |
/** | |
* Class representing an image or image container that will have its src | |
* (and other related attributes) swapped. | |
*/ | |
export default class SwapImage { | |
/** | |
* Create a SwapImage. Does not actually swap any images until explicitly | |
* asked to do so. | |
* | |
* @param {*} element - A valid jQuery element or selector, either an `<img>` | |
* element or a close parent. | |
*/ | |
constructor (element) { | |
this._element = $(element); | |
this._elementId = this._element.attr('id'); | |
this._imageElement = this._element.is('img') ? | |
this._element : this._element.find('img'); | |
this._originalAttr = this._lastAttr = this._currentAttr = { | |
src: this._imageElement.attr('src'), | |
alt: this._imageElement.attr('alt') || '', | |
srcset: this._imageElement.attr('srcset'), | |
sizes: this._imageElement.attr('sizes'), | |
'data-zoom-src': this._imageElement.attr('data-zoom-src') | |
}; | |
} | |
/** | |
* Swap the current image attributes for new ones. The attributes will only | |
* swap once the new image assets have loaded. Prior to that event, the target | |
* element will be given a class of `is-loaded` which can be used to style | |
* the appearance in this state. | |
* | |
* @param {Object} [attr] - The attributes to replace, for example `src`, | |
* `alt`, `srcset` and/or `sizes`. | |
*/ | |
swap (attr = {}) { | |
attr = $.extend({}, { | |
src: '', | |
alt: '' | |
}, attr); | |
if (attr === this._currentAttr) { | |
return; | |
} | |
if (this._preloadElement) { | |
this._preloadElement.remove(); | |
} | |
this._preloadElement = $('<img/>').one(EventName.LOAD, () => { | |
this._element.removeClass(ClassName.LOADING); | |
this._imageElement.attr(attr); | |
}); | |
this._element.addClass(ClassName.LOADING); | |
this._preloadElement.attr(attr); | |
if (this._elementId) { | |
$(`[${AttrName.TARGET}="${this._elementId}"]`) | |
.removeClass(ClassName.CURRENT) | |
.filter(`[${AttrName.SRC}="${attr.src}"]`) | |
.addClass(ClassName.CURRENT); | |
} | |
this._lastAttr = this._currentAttr; | |
this._currentAttr = attr; | |
} | |
/** | |
* Revert the image asset's attributes to what they were originally. | |
*/ | |
revert () { | |
return this.swap(this._originalAttr); | |
} | |
/** | |
* Undo the last image swap only. This is preferable to revert when multiple | |
* swaps may happen in sequence, for example alternate angles in an image | |
* gallery. | |
*/ | |
undo () { | |
return this.swap(this._lastAttr); | |
} | |
/** | |
* A jQuery interface to enable usage of this class as a plugin. Checks for | |
* an existing class instance and only creates a new one if it isn't present. | |
* | |
* @static | |
* @protected | |
* @param {(Object|String)} [attr] - Either attributes to pass directly to the | |
* `swap` method, a string representing the name of a different method, or a | |
* string representing a `src` value to swap. | |
* @returns {jQuery} | |
* @example | |
* // Swap one image for another | |
* $(img).swapImage('example/image.jpg'); | |
* // Swap more attributes | |
* $(img).swapImage({ | |
* src: 'example/image.jpg', | |
* alt: 'Accessibility is important', | |
* srcset: '...', | |
* sizes: '...' | |
* }); | |
* // Undo the most recent swap | |
* $(img).swapImage('undo'); | |
* // Revert to what it was before we swapped anything | |
* $(img).swapImage('revert'); | |
*/ | |
static _jQueryInterface (attr) { | |
return this.each(function () { | |
const $this = $(this); | |
let data = $this.data(DATA_KEY); | |
// If this is a new instance, we instantiate and attach to both the | |
// called element and its associated image. This makes the swap easier | |
// to manipulate from other plugins and scripts without losing state. | |
if (!data) { | |
data = new SwapImage(this); | |
$this.add(data._imageElement).data(DATA_KEY, data); | |
} | |
if (attr) { | |
if (typeof attr === 'string') { | |
if (data[attr] === undefined) { | |
attr = { | |
src: attr | |
}; | |
} else { | |
return data[attr](); | |
} | |
} | |
data.swap(attr); | |
} | |
}); | |
} | |
/** | |
* A function to call from an event that will trigger a swap from a different | |
* element. Used to enable a Bootstrap-style delegated data API. | |
* | |
* @static | |
* @protected | |
* @param {*} triggerElement - A valid jQuery element or selector representing | |
* whatever element triggered the event. | |
* @param {String} [revertOn] - Optional event to revert the change on. | |
* @returns {jQuery} | |
*/ | |
static _dataApiAction (triggerElement, revertOn) { | |
triggerElement = $(triggerElement); | |
const attr = { | |
src: triggerElement.attr(AttrName.SRC), | |
alt: triggerElement.attr(AttrName.ALT), | |
srcset: triggerElement.attr(AttrName.SRCSET), | |
sizes: triggerElement.attr(AttrName.SIZES), | |
'data-zoom-src': triggerElement.attr(AttrName.ZOOM) | |
}; | |
const targetId = triggerElement.attr(AttrName.TARGET); | |
let targetElement = triggerElement; | |
if (targetId) { | |
targetElement = $(`#${targetId}`); | |
} | |
if (revertOn) { | |
targetElement.one(revertOn, () => { | |
targetElement.swapImage('revert'); | |
}); | |
} | |
targetElement.swapImage(attr); | |
} | |
} | |
$.fn[NAME] = SwapImage._jQueryInterface; | |
/** | |
* SwapImage Data API | |
* | |
* Makes image-swap effects for product tiles and hover-based previews easier to | |
* implement within templates. | |
*/ | |
$(document) | |
.on('click.decathlon', '[data-swap-image-on="click"]', function (event) { | |
event.preventDefault(); | |
SwapImage._dataApiAction(this); | |
}) | |
.on('mouseover.decathlon', '[data-swap-image-on="hover"]', function (event) { | |
SwapImage._dataApiAction(this, 'mouseout.decathlon'); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment