@@ -10,6 +10,8 @@ import registry from "../../core/registry";
10
10
import utils from "../../core/utils" ;
11
11
12
12
const log = logging . getLogger ( "pat.inject" ) ;
13
+ //log.setLevel(logging.Level.DEBUG);
14
+
13
15
const TEXT_NODE = 3 ;
14
16
const COMMENT_NODE = 8 ;
15
17
@@ -136,7 +138,7 @@ const inject = {
136
138
}
137
139
break ;
138
140
case "autoload-visible" :
139
- this . _initAutoloadVisible ( $el , cfgs ) ;
141
+ this . _initAutoloadVisible ( $el ) ;
140
142
break ;
141
143
case "idle" :
142
144
this . _initIdleTrigger ( $el , cfgs [ 0 ] . delay ) ;
@@ -960,102 +962,53 @@ const inject = {
960
962
return $html ;
961
963
} ,
962
964
963
- // XXX: hack
964
- _initAutoloadVisible ( $el , cfgs ) {
965
+ _initAutoloadVisible ( $el ) {
965
966
if ( $el . data ( "pat-inject-autoloaded" ) ) {
966
967
// ignore executed autoloads
967
968
return false ;
968
969
}
969
- const $scrollable = $el . parents ( ":scrollable" ) ;
970
+
971
+ const el = $el [ 0 ] ;
970
972
971
973
// function to trigger the autoload and mark as triggered
972
974
const trigger = ( event ) => {
973
975
if ( $el . data ( "pat-inject-autoloaded" ) ) {
976
+ log . debug ( `autoload-visible trigger skipped ${ el } ` ) ;
974
977
return false ;
975
978
}
976
979
$el . data ( "pat-inject-autoloaded" , true ) ;
977
- this . onTrigger ( { currentTarget : $el [ 0 ] } ) ;
980
+ this . onTrigger ( { currentTarget : el } ) ;
978
981
event && event . preventDefault ( ) ;
982
+ log . debug ( `autoload-visible trigger run ${ el } ` ) ;
979
983
return true ;
980
984
} ;
981
- $el . click ( trigger ) ;
982
985
983
- // Use case 1: a (heigh-constrained) scrollable parent
984
- if ( $scrollable . length ) {
985
- // if scrollable parent and visible -> trigger it
986
- // we only look at the closest scrollable parent, no nesting
987
- // Check visibility for scrollable
988
- const checkVisibility = utils . debounce ( ( ) => {
989
- if ( $el . data ( "patterns.autoload" ) || ! $ . contains ( document , $el [ 0 ] ) ) {
990
- return false ;
991
- }
992
- if ( ! $el . is ( ":visible" ) ) {
993
- return false ;
994
- }
995
- if ( ! utils . elementInViewport ( $el [ 0 ] ) ) {
996
- return false ;
997
- }
998
- // check if the target element still exists. Otherwise halt and catch fire
999
- const target = (
1000
- $el . data ( "pat-inject" ) [ 0 ] . target || cfgs [ 0 ] . defaultSelector
1001
- ) . replace ( / : : e l e m e n t / , "" ) ;
1002
- if ( target && target !== "self" && $ ( target ) . length === 0 ) {
1003
- return false ;
1004
- }
986
+ // Config see: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
987
+ const intersection_observer_config = {
988
+ threshold : 0 , // If even one pixel is visible, the callback will be run.
989
+ root : null , // Root is browser viewport. If the element is visible to the user, the callback will be run.
990
+ margin : "0px" , // No margins. The element is not preloaded.
991
+ } ;
1005
992
1006
- // checkVisibility was possibly installed as a scroll
1007
- // handler and has now served its purpose -> remove
1008
- $ ( $scrollable [ 0 ] ) . off ( "scroll" , checkVisibility ) ;
1009
- $ ( window ) . off ( "resize.pat-autoload" , checkVisibility ) ;
1010
- return trigger ( ) ;
1011
- } , 100 ) ;
1012
- if ( checkVisibility ( ) ) {
1013
- return true ;
1014
- }
1015
- // wait to become visible - again only immediate scrollable parent
1016
- $ ( $scrollable [ 0 ] ) . on ( "scroll" , checkVisibility ) ;
1017
- $ ( window ) . on ( "resize.pat-autoload" , checkVisibility ) ;
1018
- } else {
1019
- // Use case 2: scrolling the entire page
1020
- // Check visibility for non-scrollable
1021
- const checkVisibility = utils . debounce ( ( ) => {
1022
- if ( $el . parents ( ":scrollable" ) . length ) {
1023
- // Because of a resize the element has now a scrollable parent
1024
- // and we should reset the correct event
1025
- $ ( window ) . off ( ".pat-autoload" , checkVisibility ) ;
1026
- return this . _initAutoloadVisible ( $el ) ;
1027
- }
1028
- if ( $el . data ( "patterns.autoload" ) ) {
1029
- return false ;
1030
- }
1031
- if ( ! $el . is ( ":visible" ) ) {
1032
- return false ;
1033
- }
1034
- if ( ! utils . elementInViewport ( $el [ 0 ] ) ) {
1035
- return false ;
1036
- }
1037
- // check if the target element still exists. Otherwise halt and catch fire
1038
- const target = (
1039
- $el . data ( "pat-inject" ) [ 0 ] . target || cfgs [ 0 ] . defaultSelector
1040
- ) . replace ( / : : e l e m e n t / , "" ) ;
1041
- if ( target && target !== "self" && $ ( target ) . length === 0 ) {
1042
- return false ;
993
+ let timeout_id = null ;
994
+ const observer = new IntersectionObserver ( ( entries ) => {
995
+ for ( const entry of entries ) {
996
+ if ( entry . isIntersecting ) {
997
+ // Run the callback after 200ms to prevent loading all
998
+ // visible elements when scrolling over.
999
+ timeout_id = window . setTimeout ( ( ) => {
1000
+ observer . unobserve ( entry . target ) ; // Stop observing loaded elements.
1001
+ trigger ( ) ;
1002
+ } , 200 ) ;
1003
+ log . debug ( `autoload-visible intersecting ${ el } ` ) ;
1004
+ } else {
1005
+ window . clearTimeout ( timeout_id ) ;
1006
+ log . debug ( `autoload-visible not intersecting ${ el } ` ) ;
1043
1007
}
1044
- $ ( window ) . off ( ".pat-autoload" , checkVisibility ) ;
1045
- return trigger ( ) ;
1046
- } , 100 ) ;
1047
- if ( checkVisibility ( ) ) {
1048
- return true ;
1049
1008
}
1050
- // https://github.com/w3c/IntersectionObserver/tree/master/polyfill
1051
- if ( IntersectionObserver ) {
1052
- const observer = new IntersectionObserver ( checkVisibility ) ;
1053
- $el . each ( ( idx , el ) => observer . observe ( el ) ) ;
1054
- } else {
1055
- $ ( window ) . on ( "resize.pat-autoload scroll.pat-autoload" , checkVisibility ) ;
1056
- }
1057
- }
1058
- return false ;
1009
+ } , intersection_observer_config ) ;
1010
+ observer . observe ( el ) ;
1011
+ $el . click ( trigger ) ;
1059
1012
} ,
1060
1013
1061
1014
_initIdleTrigger ( $el , delay ) {
0 commit comments