Last active
May 22, 2020 19:51
-
-
Save dlueth/f224cd8b5e6a8a80ae417c631597c69e to your computer and use it in GitHub Desktop.
This file contains 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
<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> |
This file contains 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
/* 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