diff --git a/news/changelog-1.9.md b/news/changelog-1.9.md
index 363661d1ac9..d95cf48c063 100644
--- a/news/changelog-1.9.md
+++ b/news/changelog-1.9.md
@@ -94,6 +94,7 @@ All changes included in 1.9:
- ([#13716](https://github.com/quarto-dev/quarto-cli/issues/13716)): Fix draft pages showing blank during preview when pre-render scripts are configured.
- ([#13847](https://github.com/quarto-dev/quarto-cli/pull/13847)): Open graph title with markdown is now processed correctly. (author: @mcanouil)
- ([#13910](https://github.com/quarto-dev/quarto-cli/issues/13910)): Add support for `logo: false` to disable sidebar and navbar logos when using `_brand.yml`. Works in website projects (`sidebar.logo: false`, `navbar.logo: false`) and book projects (`book.sidebar.logo: false`, `book.navbar.logo: false`).
+- ([#13951](https://github.com/quarto-dev/quarto-cli/issues/13951)): Fix `image-lazy-loading` not applying `loading="lazy"` attribute to auto-detected listing images.
### `book`
diff --git a/src/project/types/website/listing/website-listing-read.ts b/src/project/types/website/listing/website-listing-read.ts
index c8aacd50096..05b8ff153c4 100644
--- a/src/project/types/website/listing/website-listing-read.ts
+++ b/src/project/types/website/listing/website-listing-read.ts
@@ -393,14 +393,16 @@ export function completeListingItems(
debug(`[listing] Processing image match`);
const progressive = imgMatch[1] === "true";
const imgHeight = imgMatch[2];
- const listingId = imgMatch[3];
- const docRelativePath = imgMatch[4];
+ const lazy = imgMatch[3] !== "false";
+ const listingId = imgMatch[4];
+ const docRelativePath = imgMatch[5];
const docAbsPath = join(projectOutputDir(context), docRelativePath);
const imgPlaceholder = imagePlaceholder(
listingId,
docRelativePath,
progressive,
imgHeight,
+ lazy,
);
debug(`[listing] ${docAbsPath}`);
debug(`[listing] ${imgPlaceholder}`);
@@ -435,6 +437,7 @@ export function completeListingItems(
},
progressive,
imgHeight,
+ lazy,
);
debug(`[listing] replacing: ${docAbsPath}`);
@@ -454,7 +457,7 @@ export function completeListingItems(
};
fileContents = fileContents.replace(
imgPlaceholder,
- imageSrc(imagePreview, progressive, imgHeight),
+ imageSrc(imagePreview, progressive, imgHeight, lazy),
);
} else {
debug(`[listing] using empty div: ${docAbsPath}`);
@@ -501,11 +504,14 @@ export function imagePlaceholder(
file: string,
progressive: boolean,
height?: string,
+ lazy?: boolean,
): string {
return file
? ``
+ }, height=${height ? height : ""}, lazy=${
+ lazy === false ? "false" : "true"
+ }]:${id}:${file} -->`
: "";
}
@@ -517,7 +523,7 @@ const descriptionPlaceholderRegex =
//;
const imagePlaceholderRegex =
- //;
+ //;
function hydrateListing(
format: Format,
@@ -1202,8 +1208,14 @@ async function listItemFromFile(
}
}
-function imageSrc(image: PreviewImage, progressive: boolean, height?: string) {
- return `
![]()
{
const pageSize = listing[kPageSize];
return imagePlaceholder(
@@ -454,6 +455,7 @@ export function reshapeListing(
itemPath,
itemNumber > pageSize,
listing[kImageHeight] as string,
+ lazy,
);
};
diff --git a/src/resources/projects/website/listing/item-default.ejs.md b/src/resources/projects/website/listing/item-default.ejs.md
index 91114a7867f..823f32c18d3 100644
--- a/src/resources/projects/website/listing/item-default.ejs.md
+++ b/src/resources/projects/website/listing/item-default.ejs.md
@@ -45,7 +45,7 @@ print(`
${listing.utilities.outputLi
<% if (item.image) { %>
<%= listing.utilities.img(itemNumber, item.image, "thumbnail-image", item['image-alt'], item['image-lazy-loading'] ?? listing['image-lazy-loading']) %>
<% } else { %>
-<%= listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref) %>
+<%= listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref, item['image-lazy-loading'] ?? listing['image-lazy-loading']) %>
<% } %>
```
diff --git a/src/resources/projects/website/listing/item-grid.ejs.md b/src/resources/projects/website/listing/item-grid.ejs.md
index e19307988d9..94fd1251c39 100644
--- a/src/resources/projects/website/listing/item-grid.ejs.md
+++ b/src/resources/projects/website/listing/item-grid.ejs.md
@@ -57,7 +57,7 @@ return !["title", "image", "image-alt", "date", "author", "subtitle", "descripti
<% } else { %>
```{=html}
-<%= listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref) %>
+<%= listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref, item['image-lazy-loading'] ?? listing['image-lazy-loading']) %>
```
<% } %>
diff --git a/src/resources/projects/website/listing/listing-table.ejs.md b/src/resources/projects/website/listing/listing-table.ejs.md
index d45de6ccf91..d3ae5836490 100644
--- a/src/resources/projects/website/listing/listing-table.ejs.md
+++ b/src/resources/projects/website/listing/listing-table.ejs.md
@@ -57,7 +57,7 @@ if (field === "image") {
if (item.image) {
value = listing.utilities.img(itemNumber, item[field], "", item['image-alt'], item['image-lazy-loading'] ?? listing['image-lazy-loading']);
} else {
-value = listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref);
+value = listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref, item['image-lazy-loading'] ?? listing['image-lazy-loading']);
}
}
return listing.utilities.outputLink(item, field, value, `listing-${field}`);
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default-eager.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default-eager.qmd
index 5cc4b4c6db6..70e2bbe8a20 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default-eager.qmd
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default-eager.qmd
@@ -7,15 +7,22 @@ listing:
- image
image-lazy-loading: false
_quarto:
- html:
- ensureHtmlElements:
- -
- - "img[src='https://placeholder.co/100/100.png']"
- - "img[src='https://placeholder.co/200/200.png']"
- - "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
- -
- - "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
- - "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ render-project: true
+ tests:
+ html:
+ ensureHtmlElements:
+ -
+ - "img[src='https://placeholder.co/100/100.png']"
+ - "img[src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
+ - "img[src='https://placeholder.co/400/400.png']"
+ - "img[src='https://placeholder.co/500/500.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/600/600.png']"
+ -
+ - "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/400/400.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/500/500.png']"
---
## Hello, here's some listings with `image-lazy-loading: false`
\ No newline at end of file
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default.qmd
index ee27fb7c520..4d07cd0d114 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default.qmd
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-default.qmd
@@ -6,15 +6,20 @@ listing:
- title
- image
_quarto:
+ render-project: true
tests:
html:
ensureHtmlElements:
- -
+ -
- "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
- "img[src='https://placeholder.co/200/200.png']"
- "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/400/400.png']"
+ - "img[src='https://placeholder.co/500/500.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/600/600.png']"
-
- "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/500/500.png']"
---
## Hello, here's some listings
\ No newline at end of file
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid-eager.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid-eager.qmd
index d1ea4c15d4c..918b04e81da 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid-eager.qmd
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid-eager.qmd
@@ -7,15 +7,22 @@ listing:
- image
image-lazy-loading: false
_quarto:
- html:
- ensureHtmlElements:
- -
- - "img[src='https://placeholder.co/100/100.png']"
- - "img[src='https://placeholder.co/200/200.png']"
- - "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
- -
- - "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
- - "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ render-project: true
+ tests:
+ html:
+ ensureHtmlElements:
+ -
+ - "img[src='https://placeholder.co/100/100.png']"
+ - "img[src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
+ - "img[src='https://placeholder.co/400/400.png']"
+ - "img[src='https://placeholder.co/500/500.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/600/600.png']"
+ -
+ - "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/400/400.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/500/500.png']"
---
## Hello, here's some listings with `image-lazy-loading: false`
\ No newline at end of file
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid.qmd
index f569e99da16..d7652b8fca6 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid.qmd
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-grid.qmd
@@ -6,15 +6,20 @@ listing:
- title
- image
_quarto:
+ render-project: true
tests:
html:
ensureHtmlElements:
- -
+ -
- "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
- "img[src='https://placeholder.co/200/200.png']"
- "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/400/400.png']"
+ - "img[src='https://placeholder.co/500/500.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/600/600.png']"
-
- "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/500/500.png']"
---
## Hello, here's some listings
\ No newline at end of file
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table-eager.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table-eager.qmd
index c41648c2d52..c4d7ce1b9e8 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table-eager.qmd
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table-eager.qmd
@@ -7,15 +7,22 @@ listing:
- image
image-lazy-loading: false
_quarto:
- html:
- ensureHtmlElements:
- -
- - "img[src='https://placeholder.co/100/100.png']"
- - "img[src='https://placeholder.co/200/200.png']"
- - "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
- -
- - "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
- - "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ render-project: true
+ tests:
+ html:
+ ensureHtmlElements:
+ -
+ - "img[src='https://placeholder.co/100/100.png']"
+ - "img[src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
+ - "img[src='https://placeholder.co/400/400.png']"
+ - "img[src='https://placeholder.co/500/500.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/600/600.png']"
+ -
+ - "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/400/400.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/500/500.png']"
---
## Hello, here's some listings with `image-lazy-loading: false`
\ No newline at end of file
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table.qmd
index 1c5e8d98838..f504bd6ee36 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table.qmd
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/index-table.qmd
@@ -6,15 +6,20 @@ listing:
- title
- image
_quarto:
+ render-project: true
tests:
html:
ensureHtmlElements:
- -
+ -
- "img[loading='lazy'][src='https://placeholder.co/100/100.png']"
- "img[src='https://placeholder.co/200/200.png']"
- "img[loading='lazy'][src='https://placeholder.co/300/300.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/400/400.png']"
+ - "img[src='https://placeholder.co/500/500.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/600/600.png']"
-
- "img[loading='lazy'][src='https://placeholder.co/200/200.png']"
+ - "img[loading='lazy'][src='https://placeholder.co/500/500.png']"
---
## Hello, here's some listings
\ No newline at end of file
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-4.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-4.qmd
new file mode 100644
index 00000000000..5a1e7bb96d3
--- /dev/null
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-4.qmd
@@ -0,0 +1,7 @@
+---
+title: Post 4
+---
+
+This is 4.
+
+{.preview-image}
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-5.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-5.qmd
new file mode 100644
index 00000000000..e1a772a976a
--- /dev/null
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-5.qmd
@@ -0,0 +1,8 @@
+---
+title: Post 5
+image-lazy-loading: false
+---
+
+This is 5.
+
+{.preview-image}
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-6.qmd b/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-6.qmd
new file mode 100644
index 00000000000..d51d708229e
--- /dev/null
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/blog/post-6.qmd
@@ -0,0 +1,8 @@
+---
+title: Post 6
+image-lazy-loading: true
+---
+
+This is 6.
+
+{.preview-image}
diff --git a/tests/docs/smoke-all/listings/image-lazy-loading/listings.json b/tests/docs/smoke-all/listings/image-lazy-loading/listings.json
index 6dc84bf4c9b..20cd44cf11e 100644
--- a/tests/docs/smoke-all/listings/image-lazy-loading/listings.json
+++ b/tests/docs/smoke-all/listings/image-lazy-loading/listings.json
@@ -1,18 +1,68 @@
[
{
- "listing": "/blog/index.html",
+ "listing": "/blog/index-grid-eager.html",
"items": [
"/blog/post-1.html",
"/blog/post-2.html",
- "/blog/post-3.html"
+ "/blog/post-3.html",
+ "/blog/post-4.html",
+ "/blog/post-5.html",
+ "/blog/post-6.html"
]
},
{
- "listing": "/blog/index-eager.html",
+ "listing": "/blog/index-default.html",
"items": [
"/blog/post-1.html",
"/blog/post-2.html",
- "/blog/post-3.html"
+ "/blog/post-3.html",
+ "/blog/post-4.html",
+ "/blog/post-5.html",
+ "/blog/post-6.html"
+ ]
+ },
+ {
+ "listing": "/blog/index-table-eager.html",
+ "items": [
+ "/blog/post-1.html",
+ "/blog/post-2.html",
+ "/blog/post-3.html",
+ "/blog/post-4.html",
+ "/blog/post-5.html",
+ "/blog/post-6.html"
+ ]
+ },
+ {
+ "listing": "/blog/index-grid.html",
+ "items": [
+ "/blog/post-1.html",
+ "/blog/post-2.html",
+ "/blog/post-3.html",
+ "/blog/post-4.html",
+ "/blog/post-5.html",
+ "/blog/post-6.html"
+ ]
+ },
+ {
+ "listing": "/blog/index-default-eager.html",
+ "items": [
+ "/blog/post-1.html",
+ "/blog/post-2.html",
+ "/blog/post-3.html",
+ "/blog/post-4.html",
+ "/blog/post-5.html",
+ "/blog/post-6.html"
+ ]
+ },
+ {
+ "listing": "/blog/index-table.html",
+ "items": [
+ "/blog/post-1.html",
+ "/blog/post-2.html",
+ "/blog/post-3.html",
+ "/blog/post-4.html",
+ "/blog/post-5.html",
+ "/blog/post-6.html"
]
}
]
\ No newline at end of file