@@ -20,6 +20,9 @@ let sharedStrings = null
20
20
const entities = [ ]
21
21
const entityData = { }
22
22
23
+ let readyResolver
24
+ const ready = new Promise ( resolve => { readyResolver = resolve } )
25
+
23
26
/*********************************************************
24
27
* Widget Replacement logic
25
28
*********************************************************/
@@ -364,22 +367,6 @@ class DuckWidget {
364
367
}
365
368
}
366
369
367
- /**
368
- * Initialise the Click to Load feature, once the necessary details have been
369
- * returned by the platform.
370
- * @returns {Promise }
371
- */
372
- async function initCTL ( ) {
373
- await replaceClickToLoadElements ( )
374
-
375
- window . addEventListener ( 'ddg-ctp-replace-element' , ( { target } ) => {
376
- replaceClickToLoadElements ( target )
377
- } , { capture : true } )
378
-
379
- // Inform surrogate scripts that CTP is ready
380
- originalWindowDispatchEvent ( createCustomEvent ( 'ddg-ctp-ready' ) )
381
- }
382
-
383
370
function replaceTrackingElement ( widget , trackingElement , placeholderElement , hideTrackingElement = false , currentPlaceholder = null ) {
384
371
widget . dispatchEvent ( trackingElement , 'ddg-ctp-tracking-element' )
385
372
@@ -537,6 +524,8 @@ function showExtraUnblockIfShortPlaceholder (shadowRoot, placeholder) {
537
524
* in the document will be replaced instead.
538
525
*/
539
526
async function replaceClickToLoadElements ( targetElement ) {
527
+ await ready
528
+
540
529
for ( const entity of Object . keys ( config ) ) {
541
530
for ( const widgetData of Object . values ( config [ entity ] . elementData ) ) {
542
531
const selector = widgetData . selectors . join ( )
@@ -1312,7 +1301,7 @@ async function createYouTubePreview (originalElement, widget) {
1312
1301
// Convention is that each function should be named the same as the sendMessage
1313
1302
// method we are calling into eg. calling `sendMessage('getClickToLoadState')`
1314
1303
// will result in a response routed to `updateHandlers.getClickToLoadState()`.
1315
- const updateHandlers = {
1304
+ const messageResponseHandlers = {
1316
1305
getClickToLoadState ( response ) {
1317
1306
devMode = response . devMode
1318
1307
isYoutubePreviewsEnabled = response . youtubePreviewsEnabled
@@ -1322,14 +1311,15 @@ const updateHandlers = {
1322
1311
// first.
1323
1312
1324
1313
// Start Click to Load
1325
- if ( document . readyState === 'complete' ) {
1326
- initCTL ( )
1327
- } else {
1328
- // Content script loaded before page content, so wait for load.
1329
- window . addEventListener ( 'load' , ( event ) => {
1330
- initCTL ( )
1331
- } )
1332
- }
1314
+ window . addEventListener ( 'ddg-ctp-replace-element' , ( { target } ) => {
1315
+ replaceClickToLoadElements ( target )
1316
+ } , { capture : true } )
1317
+
1318
+ // Inform surrogate scripts that CTP is ready
1319
+ originalWindowDispatchEvent ( createCustomEvent ( 'ddg-ctp-ready' ) )
1320
+
1321
+ // Mark the feature as ready, to allow placeholder replacements.
1322
+ readyResolver ( )
1333
1323
} ,
1334
1324
setYoutubePreviewsEnabled : function ( resp ) {
1335
1325
if ( resp ?. messageType && typeof resp ?. value === 'boolean' ) {
@@ -1346,6 +1336,8 @@ const updateHandlers = {
1346
1336
}
1347
1337
}
1348
1338
1339
+ const knownMessage = Object . prototype . hasOwnProperty . bind ( messageResponseHandlers )
1340
+
1349
1341
export function init ( args ) {
1350
1342
const websiteOwner = args ?. site ?. parentEntity
1351
1343
const settings = args ?. featureSettings ?. clickToPlay || { }
@@ -1411,17 +1403,25 @@ export function init (args) {
1411
1403
} )
1412
1404
1413
1405
// Request the current state of Click to Load from the platform.
1414
- // Note: When the response is received, initCTL() is then called by the
1415
- // response handler to finish starting up the feature.
1406
+ // Note: When the response is received, the response handler finishes
1407
+ // starting up the feature.
1416
1408
sendMessage ( 'getClickToLoadState' )
1417
1409
}
1418
1410
1419
1411
export function update ( args ) {
1420
- const detail = args && args . detail
1421
- if ( ! ( detail && detail . func ) ) { return }
1412
+ // Unsupported update message.
1413
+ if ( ! args ?. detail ) return
1422
1414
1423
- const fn = updateHandlers [ detail . func ]
1424
- if ( typeof fn !== 'function' ) { return }
1415
+ // Message response.
1416
+ if ( typeof args ?. detail ?. func === 'string' && knownMessage ( args . detail . func ) ) {
1417
+ return messageResponseHandlers [ args . detail . func ] ( args . detail . response )
1418
+ }
1425
1419
1426
- fn ( detail . response )
1420
+ // Other known update messages.
1421
+ if ( args ?. detail ?. type === 'displayClickToLoadPlaceholders' ) {
1422
+ // TODO: Pass `args.detail.ruleAction` through, that way only content
1423
+ // corresponding to the entity for that ruleAction need to be
1424
+ // replaced with a placeholder.
1425
+ return replaceClickToLoadElements ( )
1426
+ }
1427
1427
}
0 commit comments