@@ -1316,6 +1316,61 @@ Readability.prototype = {
13161316 return metadata ;
13171317 } ,
13181318
1319+ /**
1320+ * Find all <noscript> that located after <img> node, and contains exactly
1321+ * single <img> element. Once it found, this method will replace the previous <img>
1322+ * with <img> inside <noscript>, then finally remove the <noscript> tag. This is
1323+ * done because in some website (e.g. Medium), they use lazy load method like this.
1324+ *
1325+ * @param Element
1326+ **/
1327+ _unwrapNoscriptImages : function ( doc ) {
1328+ // First, find div which only contains single img element, then put it out.
1329+ var divs = doc . getElementsByTagName ( "div" ) ;
1330+ this . _forEachNode ( divs , function ( div ) {
1331+ if ( div . children . length == 1 && div . children [ 0 ] . tagName === "IMG" ) {
1332+ div . parentNode . replaceChild ( div . children [ 0 ] , div ) ;
1333+ }
1334+ } ) ;
1335+
1336+ // Next find img without source, and remove it. This is done to
1337+ // prevent a placeholder img is replaced by img from noscript in next step.
1338+ var imgs = doc . getElementsByTagName ( "img" ) ;
1339+ this . _forEachNode ( imgs , function ( img ) {
1340+ var src = img . getAttribute ( "src" ) || "" ,
1341+ srcset = img . getAttribute ( "srcset" ) || "" ,
1342+ dataSrc = img . getAttribute ( "data-src" ) || "" ,
1343+ dataSrcset = img . getAttribute ( "data-srcset" ) || "" ;
1344+
1345+ if ( src === "" && srcset === "" && dataSrc === "" && dataSrcset === "" ) {
1346+ img . parentNode . removeChild ( img ) ;
1347+ }
1348+ } ) ;
1349+
1350+ // Next find noscript and try to extract its image
1351+ var noscripts = doc . getElementsByTagName ( "noscript" ) ;
1352+ this . _forEachNode ( noscripts , function ( noscript ) {
1353+ // Make sure prev sibling is exist and it's image
1354+ var prevElement = noscript . previousElementSibling ;
1355+ if ( prevElement == null || prevElement . tagName !== "IMG" ) {
1356+ return ;
1357+ }
1358+
1359+ // In jsdom content of noscript is treated as string, so here we parse it.
1360+ var tmp = doc . createElement ( "div" ) ;
1361+ tmp . innerHTML = noscript . innerHTML ;
1362+
1363+ // Make sure noscript only has one children, and it's <img> element
1364+ var children = tmp . children ;
1365+ if ( children . length != 1 || children [ 0 ] . tagName !== "IMG" ) {
1366+ return ;
1367+ }
1368+
1369+ // At this point, just replace the previous img with img from noscript.
1370+ noscript . parentNode . replaceChild ( children [ 0 ] , prevElement ) ;
1371+ } ) ;
1372+ } ,
1373+
13191374 /**
13201375 * Removes script tags from the document.
13211376 *
@@ -1828,6 +1883,9 @@ Readability.prototype = {
18281883 }
18291884 }
18301885
1886+ // Unwrap image from noscript
1887+ this . _unwrapNoscriptImages ( this . _doc ) ;
1888+
18311889 // Remove script tags from the document.
18321890 this . _removeScripts ( this . _doc ) ;
18331891
0 commit comments