2020-05-01 15:01:56 +02:00
import * as lazyLoader from 'lazyLoader' ;
import * as userSettings from 'userSettings' ;
2020-05-23 18:35:34 +02:00
import * as blurhash from 'blurhash' ;
2020-04-12 05:47:41 +02:00
import 'css!./style' ;
/* eslint-disable indent */
2019-01-10 15:39:37 +03:00
2020-04-12 14:29:42 +02:00
export function lazyImage ( elem , source = elem . getAttribute ( 'data-src' ) ) {
2020-04-12 14:25:12 +02:00
if ( ! source ) {
return ;
}
2020-04-12 14:29:42 +02:00
fillImageElement ( elem , source ) ;
2020-04-12 14:25:12 +02:00
}
2020-05-23 18:35:34 +02:00
// function destroyBlurhash(target) {
// let canvas = target.getElementsByClassName('blurhash-canvas')[0];
// target.removeChild(canvas);
// target.classList.remove('blurhashed');
// }
2020-05-26 14:05:34 +02:00
async function itemBlurhashing ( entry ) {
2020-05-23 18:35:34 +02:00
// This intersection ratio ensures that items that are near the borders are also blurhashed, alongside items that are outside the viewport
// if (entry.intersectionRation <= 0.025)
if ( entry . target ) {
let target = entry . target ;
// We only keep max 80 items blurhashed in screen to save memory
// if (document.getElementsByClassName('blurhashed').length <= 80) {
//} else {
// destroyBlurhash(target);
//}
let blurhashstr = target . getAttribute ( 'data-blurhash' ) ;
if ( blurhash . isBlurhashValid ( blurhashstr ) && target . getElementsByClassName ( 'blurhash-canvas' ) . length === 0 ) {
console . log ( 'Blurhashing item ' + target . parentElement . parentElement . parentElement . getAttribute ( 'data-index' ) + ' with intersection ratio ' + entry . intersectionRatio ) ;
2020-05-25 18:31:51 +02:00
// let width = target.offsetWidth;
// let height = target.offsetHeight;
let width = 18 ;
let height = 18 ;
2020-05-23 18:35:34 +02:00
if ( width && height ) {
let pixels ;
try {
pixels = blurhash . decode ( blurhashstr , width , height ) ;
} catch ( err ) {
console . log ( 'Blurhash decode error: ' + err . toString ( ) ) ;
return ;
}
let canvas = document . createElement ( 'canvas' ) ;
canvas . width = width ;
canvas . height = height ;
let ctx = canvas . getContext ( '2d' ) ;
let imgData = ctx . createImageData ( width , height ) ;
imgData . data . set ( pixels ) ;
// Values taken from https://www.npmjs.com/package/blurhash
2020-05-23 19:58:03 +02:00
ctx . putImageData ( imgData , 0 , 0 ) ;
2020-05-23 18:35:34 +02:00
let child = target . appendChild ( canvas ) ;
child . classList . add ( 'blurhash-canvas' ) ;
child . style . opacity = 1 ;
if ( userSettings . enableFastFadein ( ) ) {
child . classList . add ( 'lazy-blurhash-fadein-fast' ) ;
} else {
child . classList . add ( 'lazy-blurhash-fadein' ) ;
}
target . classList . add ( 'blurhashed' ) ;
}
}
}
return ;
}
function switchCanvas ( elem ) {
let child = elem . getElementsByClassName ( 'blurhash-canvas' ) [ 0 ] ;
if ( child ) {
if ( elem . getAttribute ( 'data-src' ) ) {
child . style . opacity = 1 ;
} else {
child . style . opacity = 0 ;
}
}
return ;
}
2020-04-12 05:47:41 +02:00
export function fillImage ( entry ) {
2020-04-11 22:51:11 +02:00
if ( ! entry ) {
throw new Error ( 'entry cannot be null' ) ;
2019-01-10 15:39:37 +03:00
}
2020-04-12 14:34:51 +02:00
var source = undefined ;
2020-04-12 14:25:12 +02:00
if ( entry . target ) {
2020-04-12 14:34:51 +02:00
source = entry . target . getAttribute ( 'data-src' ) ;
2020-04-12 14:25:12 +02:00
} else {
2020-04-12 14:34:51 +02:00
source = entry ;
2020-04-12 14:25:12 +02:00
}
2019-01-10 15:39:37 +03:00
2020-05-23 18:35:34 +02:00
if ( ! entry . target . classList . contains ( 'blurhashed' ) ) {
itemBlurhashing ( entry ) ;
}
2020-05-01 17:06:50 +02:00
if ( entry . intersectionRatio > 0 ) {
2020-05-02 19:44:27 +02:00
if ( source ) fillImageElement ( entry . target , source ) ;
2020-04-11 22:51:11 +02:00
} else if ( ! source ) {
emptyImageElement ( entry . target ) ;
2019-01-10 15:39:37 +03:00
}
2018-10-23 01:05:09 +03:00
}
2020-04-12 03:49:42 +02:00
function fillImageElement ( elem , url ) {
2020-04-12 14:34:51 +02:00
if ( url === undefined ) {
throw new Error ( 'url cannot be undefined' ) ;
}
2020-04-12 03:49:42 +02:00
let preloaderImg = new Image ( ) ;
preloaderImg . src = url ;
2020-04-12 14:25:12 +02:00
preloaderImg . addEventListener ( 'load' , ( ) => {
2020-05-07 11:01:14 +02:00
if ( elem . tagName !== 'IMG' ) {
2020-04-12 03:49:42 +02:00
elem . style . backgroundImage = "url('" + url + "')" ;
} else {
2020-05-07 11:01:14 +02:00
elem . setAttribute ( 'src' , url ) ;
2020-04-12 03:49:42 +02:00
}
2020-05-04 12:44:12 +02:00
elem . removeAttribute ( 'data-src' ) ;
2020-05-23 18:35:34 +02:00
switchCanvas ( elem ) ;
2019-01-10 15:39:37 +03:00
} ) ;
}
2020-04-11 22:51:11 +02:00
function emptyImageElement ( elem ) {
2020-04-12 03:49:42 +02:00
var url ;
2020-05-07 11:01:14 +02:00
if ( elem . tagName !== 'IMG' ) {
url = elem . style . backgroundImage . slice ( 4 , - 1 ) . replace ( /"/g , '' ) ;
2020-04-12 03:49:42 +02:00
elem . style . backgroundImage = 'none' ;
} else {
2020-05-07 11:01:14 +02:00
url = elem . getAttribute ( 'src' ) ;
elem . setAttribute ( 'src' , '' ) ;
2020-04-12 03:49:42 +02:00
}
2020-05-07 11:01:14 +02:00
elem . setAttribute ( 'data-src' , url ) ;
2020-05-23 18:35:34 +02:00
switchCanvas ( elem ) ;
2018-10-23 01:05:09 +03:00
}
2020-04-12 05:47:41 +02:00
export function lazyChildren ( elem ) {
2019-01-10 15:39:37 +03:00
lazyLoader . lazyChildren ( elem , fillImage ) ;
2018-10-23 01:05:09 +03:00
}
2020-04-12 05:47:41 +02:00
export function getPrimaryImageAspectRatio ( items ) {
2019-01-10 15:39:37 +03:00
var values = [ ] ;
for ( var i = 0 , length = items . length ; i < length ; i ++ ) {
2018-10-23 01:05:09 +03:00
var ratio = items [ i ] . PrimaryImageAspectRatio || 0 ;
2019-01-10 15:39:37 +03:00
if ( ! ratio ) {
continue ;
}
values [ values . length ] = ratio ;
2018-10-23 01:05:09 +03:00
}
2019-01-10 15:39:37 +03:00
if ( ! values . length ) {
return null ;
}
// Use the median
2019-11-23 00:29:38 +09:00
values . sort ( function ( a , b ) {
return a - b ;
} ) ;
2019-01-10 15:39:37 +03:00
var half = Math . floor ( values . length / 2 ) ;
var result ;
if ( values . length % 2 ) {
result = values [ half ] ;
2019-11-23 00:29:38 +09:00
} else {
2019-01-10 15:39:37 +03:00
result = ( values [ half - 1 ] + values [ half ] ) / 2.0 ;
}
// If really close to 2:3 (poster image), just return 2:3
var aspect2x3 = 2 / 3 ;
if ( Math . abs ( aspect2x3 - result ) <= 0.15 ) {
return aspect2x3 ;
}
// If really close to 16:9 (episode image), just return 16:9
var aspect16x9 = 16 / 9 ;
if ( Math . abs ( aspect16x9 - result ) <= 0.2 ) {
return aspect16x9 ;
}
// If really close to 1 (square image), just return 1
if ( Math . abs ( 1 - result ) <= 0.15 ) {
return 1 ;
}
// If really close to 4:3 (poster image), just return 2:3
var aspect4x3 = 4 / 3 ;
if ( Math . abs ( aspect4x3 - result ) <= 0.15 ) {
return aspect4x3 ;
}
return result ;
2018-10-23 01:05:09 +03:00
}
2020-04-12 05:47:41 +02:00
export function fillImages ( elems ) {
2019-01-10 15:39:37 +03:00
2018-10-23 01:05:09 +03:00
for ( var i = 0 , length = elems . length ; i < length ; i ++ ) {
2019-01-10 15:39:37 +03:00
var elem = elems [ 0 ] ;
fillImage ( elem ) ;
2018-10-23 01:05:09 +03:00
}
}
2019-01-10 15:39:37 +03:00
2020-04-12 05:47:41 +02:00
/* eslint-enable indent */
export default {
fillImages : fillImages ,
2020-04-12 14:25:12 +02:00
fillImage : fillImage ,
lazyImage : lazyImage ,
2020-04-12 05:47:41 +02:00
lazyChildren : lazyChildren ,
getPrimaryImageAspectRatio : getPrimaryImageAspectRatio
} ;