Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

listing - decode encoded category everywhere #11771

Merged
merged 5 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/changelog-1.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All changes included in 1.7:
- ([#11532](https://github.com/quarto-dev/quarto-cli/issues/11532)): Fix regression for [#660](https://github.com/quarto-dev/quarto-cli/issues/660), which causes files to have incorrect permissions when Quarto is installed in a location not writable by the current user.
- ([#11549](https://github.com/quarto-dev/quarto-cli/issues/11549)): Fix regression in rendering `dashboard` tabsets into cards without titles.
- ([#11580](https://github.com/quarto-dev/quarto-cli/issues/11580)): Fix regression with documents containing `categories` fields that are not strings.
- ([#11752](https://github.com/quarto-dev/quarto-cli/issues/11752)): Fix regression with non-alphanumeric characters in `categories` preventing correct filtering of listing.

## YAML validation

Expand Down
3 changes: 2 additions & 1 deletion src/resources/projects/website/listing/quarto-listing.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const kProgressiveAttr = "data-src";
let categoriesLoaded = false;

window.quartoListingCategory = (category) => {
category = atob(category);
// category is URI encoded in EJS template for UTF-8 support
category = decodeURIComponent(atob(category));
if (categoriesLoaded) {
activateCategory(category);
setCategoryHash(category);
Expand Down
10 changes: 10 additions & 0 deletions tests/docs/playwright/blog/simple-blog/_quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,15 @@ project:

website:
title: "Testing listing search"
navbar:
left:
- href: index.qmd
text: Home
- href: default.qmd
text: Default
- href: grid.qmd
text: Grid
- href: table.qmd
text: Table

format: html
13 changes: 13 additions & 0 deletions tests/docs/playwright/blog/simple-blog/default.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: "Testing listing default"
listing:
contents: posts2
sort: "date desc"
type: default
categories: true
filter-ui: true
page-layout: full
title-block-banner: true
---


13 changes: 13 additions & 0 deletions tests/docs/playwright/blog/simple-blog/grid.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: "Testing listing grid"
listing:
contents: posts3
sort: "date desc"
type: grid
categories: true
filter-ui: true
page-layout: full
title-block-banner: true
---


11 changes: 2 additions & 9 deletions tests/docs/playwright/blog/simple-blog/index.qmd
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
---
title: "Testing listing search"
listing:
contents: posts
sort: "date desc"
type: table
categories: true
filter-ui: true
page-layout: full
title-block-banner: true
title: "Testing listings"
---

This website is for testing listings

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions tests/docs/playwright/blog/simple-blog/posts2/_metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# options specified here will apply to all posts in this folder

# Enable banner style title blocks
title-block-banner: true
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: "Post With Code"
author: "Harlow Malloc"
date: "2024-09-06"
categories: [news, code, analysis, apos'trophe]
image: "image.jpg"
---

This is a post with executable code.
14 changes: 14 additions & 0 deletions tests/docs/playwright/blog/simple-blog/posts2/welcome/index.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: "Welcome To My Blog"
author: "Tristan O'Malley"
date: "2024-09-03"
categories: [news, 'euros (€)', 免疫]
---

This is the first post in a Quarto blog. Welcome!

![](thumbnail.jpg)

## About image listing {#img-lst}

Since this post doesn't specify an explicit `image`, the first image in the post will be used in the listing page of posts.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions tests/docs/playwright/blog/simple-blog/posts3/_metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# options specified here will apply to all posts in this folder

# Enable banner style title blocks
title-block-banner: true
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: "Post With Code"
author: "Harlow Malloc"
date: "2024-09-06"
categories: [news, code, analysis, apos'trophe]
image: "image.jpg"
---

This is a post with executable code.
14 changes: 14 additions & 0 deletions tests/docs/playwright/blog/simple-blog/posts3/welcome/index.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: "Welcome To My Blog"
author: "Tristan O'Malley"
date: "2024-09-03"
categories: [news, 'euros (€)', 免疫]
---

This is the first post in a Quarto blog. Welcome!

![](thumbnail.jpg)

## About image listing {#img-lst}

Since this post doesn't specify an explicit `image`, the first image in the post will be used in the listing page of posts.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions tests/docs/playwright/blog/simple-blog/table.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: "Testing listing table"
listing:
contents: posts
sort: "date desc"
type: table
categories: true
filter-ui: true
page-layout: full
title-block-banner: true
---


2 changes: 1 addition & 1 deletion tests/integration/playwright/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default defineConfig({
/* Run your local dev server before starting the tests */
/* We use python for this but we could also try using another tool */
webServer: {
command: 'python -m http.server 8080',
command: 'uv run python -m http.server 8080',
url: 'http://127.0.0.1:8080',
reuseExistingServer: !isCI,
cwd: '../../docs/playwright',
Expand Down
109 changes: 62 additions & 47 deletions tests/integration/playwright/tests/blog-simple-blog.spec.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,69 @@
import { expect, test } from "@playwright/test";
import { expect, Page, test } from "@playwright/test";
import { getUrl } from "../src/utils";

test('List.js is correctly patch to allow searching with lowercase and uppercase',
async ({ page }) => {
await page.goto('./blog/simple-blog/_site/');
await page.getByPlaceholder('Filter').click();
await page.getByPlaceholder('Filter').fill('Code');
await page.getByPlaceholder('Filter').press('Enter');
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeHidden();
await page.getByPlaceholder('Filter').click();
await page.getByPlaceholder('Filter').fill('');
await page.getByPlaceholder('Filter').press('Enter');
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeVisible();
await page.getByPlaceholder('Filter').click();
await page.getByPlaceholder('Filter').fill('CODE');
await page.getByPlaceholder('Filter').press('Enter');
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeHidden();
});
const testPages = {
'posts': 'table.html',
'posts2': 'default.html',
'posts3': 'grid.html'
};

test('Categories link are clickable', async ({ page }) => {
await page.goto('./blog/simple-blog/_site/posts/welcome/');
await page.locator('div').filter({ hasText: /^news$/ }).click();
await expect(page).toHaveURL(/_site\/index\.html#category=news$/);
await expect(page.locator(`div.category[data-category="${btoa('news')}"]`)).toHaveClass(/active/);
await page.goto('./blog/simple-blog/_site/posts/welcome/#img-lst');
await page.locator('div').filter({ hasText: /^news$/ }).click();
await expect(page).toHaveURL(/_site\/index\.html#category=news$/);
await expect(page.locator(`div.category[data-category="${btoa('news')}"]`)).toHaveClass(/active/);
});
Object.entries(testPages).forEach(([postDir, pageName]) => {
test(`List.js is correctly patched to allow searching with lowercase and uppercase on ${pageName}`,
async ({ page }) => {
await page.goto(`./blog/simple-blog/_site/${pageName}`);
await page.getByPlaceholder('Filter').click();
await page.getByPlaceholder('Filter').fill('Code');
await page.getByPlaceholder('Filter').press('Enter');
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeHidden();
await page.getByPlaceholder('Filter').click();
await page.getByPlaceholder('Filter').fill('');
await page.getByPlaceholder('Filter').press('Enter');
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeVisible();
await page.getByPlaceholder('Filter').click();
await page.getByPlaceholder('Filter').fill('CODE');
await page.getByPlaceholder('Filter').press('Enter');
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeHidden();
});

test('Categories links are clickable', async ({ page }) => {
const checkCategoryLink = async (category: string) => {
await page.getByRole('link', { name: category }).click();
await expect(page).toHaveURL(getUrl(`blog/simple-blog/_site/index.html#category=${encodeURIComponent(category)}`));
const checkCategoryLink = async (page: Page, category: string, pageName: string) => {
await page.getByText(category, { exact: true }).click();
await expect(page).toHaveURL(getUrl(`blog/simple-blog/_site/${pageName}#category=${encodeURIComponent(category)}`));
await expect(page.locator(`div.category[data-category="${btoa(encodeURIComponent(category))}"]`)).toHaveClass(/active/);
};
// Checking link is working
await page.goto('./blog/simple-blog/_site/posts/welcome/');
await checkCategoryLink('news');
// Including for special characters
await page.getByRole('link', { name: 'Welcome To My Blog' }).click();
await checkCategoryLink('euros (€)');
await page.getByRole('link', { name: 'Welcome To My Blog' }).click();
await checkCategoryLink('免疫');
await page.goto('./blog/simple-blog/_site/posts/post-with-code/');
await checkCategoryLink("apos'trophe");
// special check for when a page is not loaded from non root path
await page.goto('./blog/simple-blog/_site/posts/welcome/#img-lst');
await checkCategoryLink('news');

test(`All Categories links are clickable ${postDir} pages`,
async ({ page }) => {
// Checking link is working
await page.goto(`./blog/simple-blog/_site/${postDir}/welcome/`);
await checkCategoryLink(page, 'news', pageName);
// Including for special characters
await page.getByRole('link', { name: 'Welcome To My Blog' }).click();
await checkCategoryLink(page, 'euros (€)', pageName);
await page.getByRole('link', { name: 'Welcome To My Blog' }).click();
await checkCategoryLink(page, '免疫', pageName);
await page.goto(`./blog/simple-blog/_site/${postDir}/post-with-code/`);
await checkCategoryLink(page, "apos'trophe", pageName);
// special check for when a page is not loaded from non root path
await page.goto(`./blog/simple-blog/_site/${postDir}/welcome/#img-lst`);
await checkCategoryLink(page, 'news', pageName);
});

if (pageName !== 'table.html') {
test(`Categories link on listing page works for ${pageName}`, async ({ page }) => {
await page.goto(`./blog/simple-blog/_site/${pageName}`);
await checkCategoryLink(page, 'apos\'trophe', pageName);
await expect(page.getByRole('link', { name: 'Post With Code' })).toBeVisible();
await page.goto(`./blog/simple-blog/_site/${pageName}`);
await checkCategoryLink(page, 'euros (€)', pageName);
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeVisible();
await page.goto(`./blog/simple-blog/_site/${pageName}`);
await checkCategoryLink(page, '免疫', pageName);
await expect(page.getByRole('link', { name: 'Welcome To My Blog' })).toBeVisible();
});
}
});


Loading