Skip to content

Instantly share code, notes, and snippets.

@dlueth
Last active May 22, 2020 19:51
Show Gist options
  • Save dlueth/f224cd8b5e6a8a80ae417c631597c69e to your computer and use it in GitHub Desktop.
Save dlueth/f224cd8b5e6a8a80ae417c631597c69e to your computer and use it in GitHub Desktop.
<figure itemprop="image" itemscope itemtype="http://schema.org/ImageObject">
<meta itemprop="caption" content="Apple - AirPods 2nd Gen. (2019) Stereo Bluetooth Kopfhörer Headset (MV7N2ZM/A) - Weiss" />
<meta itemprop="contentUrl" content="https://www.apfelkiste.ch/media/catalog/product/a/p/apple-airpods-2nd-gen-2019-stereo-bluetooth-kopfhorer-mv7n2zm-a5.jpg" />
<div></div>
</figure>
/* global global, document, version, cache, hostname, demand, provide, Weakmap */
(function(navigator) {
function definition(MediaObject) {
var storage = new Weakmap(),
hostname = location.hostname,
base = '//' + global.application.hostname + '/resize',
resolver = document.createElement('a'),
matchLeadingSlash = /^\//,
matchSuffix = /^(.+?)(\.(?:gif|jpe?g|png|webp))?$/,
transparent = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
fallback = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzcxIDI4MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSI+CiAgICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTM3MSAuNUgxdjI4MGgzNzBWLjV6IiBmaWxsPSIjRjBGMEYwIi8+CiAgICA8ZyBmaWxsPSIjQTdBN0E3Ij4KICAgICAgICA8cGF0aCBkPSJNMTM1LjQ3NCAxMDEuMDQzbC4wODcuMDQzLjA4Ni4wNDMuMDQzLjA0My4xNzIuMDQzLjA4Ni4wNDQuMDg2LjA0My4wODcuMDQzLjAyOC4wNDMuMjE2LjA0My4wODYuMDQzLjA4Ni4wNDMuMDU4LjA1OC4wODYuMDQzYzMuMDYyLjYxNSA1LjAyNyAyLjgyNyA4LjA1NyAzLjg2NyAyLjY2My45MTQgNS43MDUuNSA4LjI1OSAxLjcyNCA3LjY1OCAzLjYyNiAxMy43ODggMTAuMzk5IDE0Ljk5NyAxOS44MjZsLjA0LjQuMDQ0LjM0NC4wNDMuNzc2di4yNThoLS4zNzRsLS4wODYtLjA0M2MtMS4xODYtLjU5NC0xLjc4NC0xLjY1OC0zLjAzLTIuMjY0LTMuODY3LTEuODctNy41MTItMy4zNS0xMi4xOTEtNS41NzctNy43MDItMy42NzUtMTEuNjcyLTYuMTM3LTE1LjU0NC0xMy44OTVsLS4wNDMtLjA4Ni0uMDQzLS4wNDMtLjA0My0uMTU4LS4wNDMtLjA1NS0uMDQzLS4wODYtLjA0My0uMDQzLS4wNDMtLjA4Ny0uMDQzLS4wNDMtLjA0NC0uMDg2LS4wNDMtLjA4Ni0uMDQzLS4xMy0uMDQzLS4xMjktLjA0My0uMDg2LS4wNDMtLjEzLS4wNDMtLjA4NS0uMDQzLS4wODYtLjA1OC0uMDg3LS4wNDMtLjA0My0uMDI4LS4xNzUtLjA0NC0uMDg2LS4wNDMtLjA4Ni0uMDQzLS4wODctLjA0My0uMDg2LS4wNDMtLjEyNi0uMDQzLS4xMy0uMDQzLS4wODYtLjA0My0uMTMtLjA0My0uMDg1LS4wNDMtLjEzLS4wNDMtLjIxNS0uMDQzLS4wODYtLjA0NC0uMTMyLS4wNDMtLjEzLS4wNDMtLjEyOS0uMDQzLS4yMTYtLjA0My0uMDcxLS4wNTctLjEtLjAzLS4xMy0uMDQyLS4xMy0uMDQzLS4zMDEtLjA0My0uMDg2LS4wNDMtLjExNS0uMDQ0LS4xNzMtLjA0My0uMTg3VjEwMWguMzg4bC4wODYuMDQzeiIgLz4KICAgICAgICA8cGF0aCBkPSJNMTY5LjY3MyAxMzguNzQxYzIuNzA5LTUuNDMgNS40MjYtMTEuNDU2IDEyLjY4OC0xMS42NTEgNC42OTEtLjEyNyA5Ljg4MiAxLjc3OCAxMi44OTUgNS4xMTRoLS4xODFjLTUuMzYtMi45NTMtOC44Ny01LjA4My0xNC4yMTYtMy41NjMtNS4xNDggMS40NjYtOS4wOCA3LjM3Ni0xMC4yNTIgMTIuMDY4bC0uNDY2LS4xMTUuMTc2LjA3Yy01LjY2LTEuODg4LTYuMTQ4LTkuOTQ4LTExLjgwNC0xMS4zNDctMTQuMjI0LTMuNTE0LTE5LjA1MyAxNy40NTgtMTguNDEgMjcuMjk2LjQ5NCA3LjU2OCAzLjMzOCAxNC4zMTggNS43OTEgMTkuMjI4bC4wNDMuMDg2LjA0My4xNzMuMDQ0LjA4Ni4wNDMuMDQzLjA0My4wNDMuMDQzLjA4Ni4wNDMuMDg2LjA0My4wNDMuMDQzLjA4N3YuMDg2aC4wODZsLjA0My4xNzIuMDQzLjA0My4wNDQuMDg3LjA0My4wNDMuMDQzLjA0My4wNDMuMDg2LjA0My4wODYuMDQzLjEzLjA0My4wNDMuMDQzLjA4Ni4wNDMuMDQzLjA0My4xMy4wNDMuMDg1LjA0NC4wNDMuMDQzLjA0NC4wNDMuMDg2di4xMjloLS4zNDVsLS4wNDMtLjA0My0uMDQzLS4wNDMtLjA0My0uMDQzLS4wNDMtLjA0My0uMDg3LS4wNDMtLjA0My0uMDQ0LS4wNDMtLjA0My0uMDQzLS4wNDN2LS4wODZoLS4xM2wtLjA0Mi0uMDQzLS4wNDMtLjA0M3YtLjA4NmgtLjA4NmwtLjEzLS4wNDN2LS4wODdoLS4wODZsLS4wNDMtLjA4Ni0uMDQzLS4wNDMtLjA0My0uMDQzLS4wNDMtLjA0My0uMDg2LS4wNDMtLjA0My0uMDQzLS4wNDQtLjA0M2MtNC40OC00LjQ5MS02LjMyLTEwLjA1Ny04LjI3LTE1Ljk1M2wtLjA0My0uMTMtLjA0My0uMTcyLS4wNTctLjEzMi0uMDQzLS4yNTgtLjA0My0uMTMtLjA0My0uMTcyLS4wNDQtLjE3My0uMDQzLS4xMjktLjA0My0uMzAxLS4wMjgtLjE0MS0uMDQ0LS4yMTYtLjA0My0uMTcyLS4wNDMtLjE3My0uMDQzLS4xMjktLjA0My0uMzg4LS4wNDMtLjE3Mi0uMDQzLS4zMDItLjA0My0uMjg3LS4wNDMtLjIxNi0uMDQzLS40My0uMDQzLS4yMTYtLjA0NC0uMjU5LS4wNDMtLjI4Ny0uMDQzLS4zNDUtLjA0My0uNjQ2YTI2LjY2NyAyNi42NjcgMCAwMS4xNzMtNy40MTZsLjA0My0uMzAyLjA0My0uNDMxYzcuNDg4LTI4Ljg5NCAyNy4xMDItMjQuOTQgMzMuMjk4LTguMTQzeiIgLz4KICAgICAgICA8cGF0aCBkPSJNMTc4LjQ0IDExOS4xMDR2LjgxOWwtLjA0My4yMTYtLjA0My4wODYtLjA0My4wODYtLjA0My4wNDMtLjA0My4wNDMtLjA0My4xMy0uMDQzLjA0My0uMDg3LjA0M2MtMi41MDcgMi41MDgtNS4wMyA0Ljg4NC02LjE1OCA4LjI3OGwtLjA0My4xNzItLjA0My4xMy0uMDQzLjIxNS0uMDQ0LjIxNS0uMDQzLjIxNi0uMDQzLjQ3NC0xLjE3MiAyLjIyN2MtLjA5Mi4xNzItMi44MTgtOS43MDYgMi4wNzctMTQuNjAybC4wNDMtLjA0NC4wNDMtLjA0My4wNDMtLjA0My4wNDMtLjA0My4wODctLjA0My4wNDMtLjA0My4wNDMtLjA0M2MxLjc5Mi0xLjc5NiA1LjAxNS0xLjIzOSA1LjU1NSAxLjQ2NXYuMDAzeiIgLz4KICAgICAgICA8cGF0aCBkPSJNMTU4LjcwNSAxNTMuMjJoMS44NzNsLS45MDctOC4zNy0uOTY2IDguMzd6bS00Ljk5IDcuMzA2bDIuNjQtMTcuNzI4aDYuNjA4bDIuNzA4IDE3LjcyOGgtNC4yM2wtLjQ5LTQuMzU2aC0yLjYxM2wtLjQ4OSA0LjM1NmgtNC4xMzR6bTE5LjU3Ny01LjA0djUuMDRoLTQuMTN2LTE3LjcyOGg0LjE1M2MyLjUzOCAwIDQuMjE4LjMyNSA1LjA0MS45NzQuODIyLjY0NyAxLjIzNiAxLjg0MiAxLjIzNiAzLjU3NHYzLjU5NWMwIDEuNzAzLS40MDMgMi44ODYtMS4yMDcgMy41NDgtLjgwNC42NjMtMi4yNzYuOTk2LTQuNDE1Ljk5N2gtLjY3OHptMi4xNDYtNC41MjJ2LTMuNzYxYzAtLjQ5NC0uMDgtLjgyOC0uMjQ3LTEuMDA2LS4xNjctLjE3OC0uNDk0LS4yNy0uOTgyLS4yN2gtLjkxN3Y2LjMyMWguOTAyYy40ODggMCAuODE2LS4wODkuOTgzLS4yNy4xNjYtLjE4LjI0Ny0uNTE0LjI0Ny0xLjAwNWwuMDE0LS4wMXYuMDAxem03Ljg5NCA5LjU2MnYtMTcuNzI4aDcuNzU2djMuMTZoLTMuNjI2djQuNDA4aDMuMjkydjMuMTZoLTMuMjkydjYuOTcxbC00LjEzLjAzdi0uMDAxem0xMS41NTkgMHYtMTcuNzI4aDcuNzkzdjMuMTZoLTMuNjYzdjMuOTE3aDMuNDQ3djMuMDU3aC0zLjQ0N3Y0LjQwOGg0LjAyMnYzLjE2bC04LjE1Mi4wMjZ6bTExLjk1IDB2LTE3LjcyOGg0LjEyMnYxNC41NTNoMy45djMuMTZsLTguMDIzLjAxNWguMDAxem0tNTMuMTI1IDIwLjE4MlYxNjIuOThoMS43NTV2Ny42MjVoLjkwOGw1LjY2Ny03LjYyNWgxLjk2bC02LjI1NCA4LjQxOCA3LjA2MyA5LjMxaC0yLjE5NGwtNi4zNzQtOC40MjhoLS43Njd2OC40MmwtMS43NjQuMDA4em0xNS43MTggMFYxNjIuOThoMS43NTV2MTcuNzI4aC0xLjc1NXptMTguMDMxLTYuMTZ2Mi41NDJjMCAxLjMwOS0uMzQzIDIuMjc0LTEuMDMxIDIuODk3LS42OS42MjMtMS43Ni45MzYtMy4yMDYuOTM2aC0xLjU4OGMtMS42MTMgMC0yLjczMS0uMzU0LTMuMzU1LTEuMDYzLS42MjUtLjcwOS0uOTM3LTIuMDQtLjkzNy0zLjk5N3YtLjg5NmgxLjgyNHYxLjQ5MWMwIDEuMDM1LjE3NiAxLjc1LjUyOSAyLjE0NC4zNTIuMzk0Ljk4My41OTIgMS44OTMuNTkyaDEuNzM4Yy44NDQgMCAxLjQzNi0uMTczIDEuNzU1LS41MDkuMzE5LS4zMzYuNDg4LS45NTcuNDg4LTEuODY1di0xLjUxN2E2LjEyNiA2LjEyNiAwIDAwLS4wNi0xLjAzMSAyLjA1IDIuMDUgMCAwMC0uMTk4LS42MDRjLS4yNDItLjQ4LTEuMjQ3LS44NjItMy4wMi0xLjE1bC0uODQ3LS4xMjhhMy4xNDEgMy4xNDEgMCAwMC0uMjUzLS4wNWMtMS4xNDktLjE5LTEuODcyLS4zODItMi4xNzEtLjU3NGEyLjU4OSAyLjU4OSAwIDAxLTEuMDE0LTEuMTUgNC40OSA0LjQ5IDAgMDEtLjMyMi0xLjgxNXYtMi4yMWMwLTEuMzA0LjM0NC0yLjI2OSAxLjAzMS0yLjg5My42ODgtLjYyNSAxLjc1My0uOTM3IDMuMTk1LS45MzdoMS4yNjNjMS41NDQgMCAyLjY0NC4zNDcgMy4zMDEgMS4wNC42NTcuNjk0Ljk4NSAxLjg2My45ODUgMy41MDl2LjUxNGgtMS44MzV2LS41NzVjMC0xLjA0NC0uMTcyLTEuNzU4LS41MTQtMi4xNDMtLjM0Mi0uMzg4LS45NjktLjU3NS0xLjg4OC0uNTc1aC0xLjQzNmMtLjg2MiAwLTEuNDM2LjE2Ny0xLjc2Ny41LS4zMy4zMzMtLjQ4OC45NDgtLjQ4OCAxLjg1djEuOTA4YzAgLjk4My44MTYgMS41ODYgMi40NDUgMS44MTZsLjg4NC4xM2MxLjg1NC4zIDMuMDgzLjcyIDMuNjg2IDEuMjU4LjYwMy41MzguOTA2IDEuMzkyLjkwOCAyLjU2bC4wMDUtLjAwNnYuMDAxem04Ljc3OSA2LjE2di0xNS45ODRoLTMuNzg2VjE2M2g5LjM0N3YxLjcyNGgtMy43OTV2MTUuOTg0aC0xLjc2NnpNMjE1LjAxMyAxNzl2MS43MDdoLTcuOTE0VjE2Mi45OGg3LjkyMnYxLjcyNGgtNi4xNTJ2NS45MzNoNS43NDV2MS43MjRoLTUuNzQ1djYuNjQ5bDYuMTQ0LS4wMDlWMTc5eiIgLz4KICAgICAgICA8cGF0aCBkPSJNMjMwLjA3OCAxNDMuMTFhNi4zOTIgNi4zOTIgMCAwMTYuMzcyIDYuMzczdjI1LjE0NGE2LjM5NCA2LjM5NCAwIDAxLTYuMzcyIDYuMzczaC00LjQ4N2E2LjM4OCA2LjM4OCAwIDAxLTYuMzctNi4zNzN2LTI1LjE0NGE2LjM5NCA2LjM5NCAwIDAxNi4zNy02LjM3M2g0LjQ4N3ptMi42NzUgMzQuMjdoLTEuMjM4di45NDVoMS4yMzh2LS45NDV6bS02LjI1LTcuOTY4aC0uNDMyYy0uOTUgMC0xLjYzLjE4MS0yLjA0Mi41NDMtLjQxMi4zNjItLjYxOC45NjMtLjYxOCAxLjgwMnYuNDc3Yy0uMDAyLjgzNy4yNDIgMS40NDcuNzMzIDEuODMuNDkuMzgzIDEuMjkuNTc1IDIuMzk4LjU3NWgzLjQwMWMuNDQ4LjAxMS44OTYtLjAxOSAxLjMzOS0uMDlhMi4yNyAyLjI3IDAgMDAuNzY0LS4zMDRjLjI2My0uMTczLjQ3LS40MTguNTk1LS43MDcuMTQyLS4zMzIuMjEzLS42OS4yMDYtMS4wNTJ2LS44ODdjLS4wMDUtLjczOC0uMjIzLTEuMjgzLS42NTItMS42MzUtLjQyOS0uMzUzLTEuMDk5LS41MjktMi4wMS0uNTI5aC0uNTR2LjkzN2guMjI3Yy45MDIgMCAxLjQ3OS4wODkgMS43MjMuMjcuMjQ0LjE4LjM2OC41NDkuMzY4IDEuMTAzdi41YzAgLjU2LS4xMy45MzQtLjM4MiAxLjExNS0uMjUzLjE4LS45MDIuMjctMS45MzYuMjdoLTMuMWMtLjg4MiAwLTEuNDgyLS4wOS0xLjc3LS4yODctLjI5OC0uMTk4LS40NDctLjU2LS40NDctMS4wODZ2LS41Yy4wMDMtLjUyNS4xNDgtLjg4My40MzMtMS4wNzUuMjg2LS4xOTIuODI5LS4yODcgMS42MjktLjI4N2guMTEydi0uOTgzaC4wMDF6bTYuMjUzLTcuNTk3aC05LjIzM3YuOTIyaDQuMDIydjMuNjc4aC00LjAyMnYuOTE0aDkuMjI0bC4wMDYuMDAzdi0uOTE0aC00LjMyNnYtMy42OGg0LjMyOXYtLjkyM3oiIC8+CiAgICA8L2c+Cjwvc3ZnPg==',
placeholder = transparent,
internal, device, recommended;
/******************************************
* Private methods
******************************************/
internal = {
transformUrl: function(url) {
resolver.href = url;
// fallback to hostname because IE11 returns an empty
// hostname if none is contained in the url given
if((resolver.hostname || hostname) === 'apfelkiste.local') {
resolver.hostname = global.application.hostname;
}
return resolver.href;
},
isLocal: function(url) {
resolver.href = url;
return resolver.hostname === global.application.hostname;
},
getPath: function(url) {
resolver.href = url;
return resolver.pathname.replace(matchLeadingSlash, '');
}
};
/******************************************
* Device helper properties and methods
******************************************/
device = {
get downlink() {
// https://kenstechtips.com/index.php/download-speeds-2g-3g-and-4g-actual-meaning#2G_3G_4G_5G_Download_Speeds
if('connection' in navigator && 'downlink' in navigator.connection) {
return navigator.connection.downlink;
} else {
return Number.POSITIVE_INFINITY;
}
},
get devicePixelRatio() {
return Math.max(Math.floor(global.devicePixelRatio || 1), 1);
},
get saveDataState() {
return 'connection' in navigator && navigator.connection.saveData === true;
},
get memory() {
return ('deviceMemory' in navigator && navigator.deviceMemory) || Number.POSITIVE_INFINITY;
},
get connection() {
if('connection' in navigator && 'effectiveType' in navigator.connection) {
if(/2g/i.test(navigator.connection.effectiveType)) {
return 1;
}
if(navigator.connection.effectiveType === '3g') {
return 2;
}
}
return 3;
},
};
/******************************************
* Recommended helper properties and methods
******************************************/
recommended = {
get quality() {
var connection = device.connection,
downlink = device.downlink;
if(device.memory < 1 || connection < 2 || downlink < 1.5 || device.saveDataState) {
return 'low';
}
if(connection < 3 || downlink < 8) {
return 'medium';
}
return 'high';
},
get devicePixelRatio() {
if(recommended.quality === 'low' || device.connection < 3 || device.downlink < 8) {
return 1;
}
return device.devicePixelRatio;
}
};
/******************************************
* Module class
******************************************/
function ImageObject(node, url) {
var self = MediaObject.call(this, node),
caption = node.querySelector('[itemprop="caption"]'),
image = self.container.querySelector('img') || document.createElement('img');
url = url || node.querySelector('[itemprop="contentUrl"]').getAttribute('content');
image.onerror = function() {
image.src = fallback;
};
image.onload = function() {
image.style.opacity = 1;
};
image.style.opacity = 0;
image.src = placeholder;
image.decoding = 'async';
image.draggable = false;
if(caption) {
image.alt = caption.getAttribute('content');
}
self.container.appendChild(image);
self.url = url ? internal.transformUrl(url) : null;
self.image = image;
self.caption = caption;
return self;
}
ImageObject.prototype = {
/* reference
url: null,
image: null,
caption: null,
*/
load: function() {
var self = this,
url = self.url,
boundingbox, width, height, suffix, matches, target;
if(url) {
boundingbox = self.image.getBoundingClientRect();
width = Math.ceil(boundingbox.width * recommended.devicePixelRatio);
height = Math.ceil(boundingbox.height * recommended.devicePixelRatio);
if(width && height) {
suffix = width + 'x' + height + '.' + recommended.quality;
if(internal.isLocal(url)) {
target = base + '/' + internal.getPath(url).replace(matchSuffix, '$1.' + suffix + '$2');
} else {
matches = url.match(matchSuffix);
target = base + '/external/' + btoa(matches[1]) + '.' + suffix + matches[2];
}
self.image.src = target;
MediaObject.prototype.load.call(self);
}
} else {
self.image.src = fallback;
MediaObject.prototype.load.call(self);
}
return self;
}
};
ImageObject.obtain = function(node) {
return storage.get(node) || storage.set(node, new ImageObject(node)).get(node);
};
/******************************************
* return module
******************************************/
return ImageObject.extends(MediaObject);
}
/******************************************
* Provide module
******************************************/
provide('/module/imageobject', [ '/module/mediaobject' ], definition);
}(navigator));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment