Skip to content
Open
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
60 changes: 50 additions & 10 deletions src/command/render/codetools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import { Format } from "../../config/types.ts";
import {
kCodeTools,
kCodeToolsHideAllCode,
kCodeToolsHideAllSections,
kCodeToolsMenuCaption,
kCodeToolsShowAllCode,
kCodeToolsShowAllSections,
kCodeToolsSourceCode,
kCodeToolsViewSource,
kKeepSource,
Expand All @@ -29,9 +31,12 @@ import { isHtmlOutput } from "../../config/format.ts";
import { executionEngineCanKeepSource } from "../../execute/engine-info.ts";
import { formatHasBootstrap } from "../../format/html/format-html-info.ts";
import { withTiming } from "../../core/timing.ts";
import { kSectionCollapse } from "../../format/html/format-html-shared.ts";

const kHideAllCodeLinkId = "quarto-hide-all-code";
const kShowAllCodeLinkId = "quarto-show-all-code";
const kShowAllSectionsLinkId = "quarto-show-all-sections";
const kHideAllSectionsLinkId = "quarto-hide-all-sections";
const kViewSourceLinkId = "quarto-view-source";
const kEmbeddedSourceClass = "quarto-embedded-source-code";
export const kEmbeddedSourceModalId = kEmbeddedSourceClass + "-modal";
Expand Down Expand Up @@ -140,7 +145,7 @@ export function codeToolsPostprocessor(format: Format) {
if (formatHasCodeTools(format)) {
// resolve what sort of code tools we will present
const codeTools = resolveCodeTools(format, doc);
if (codeTools.source || codeTools.toggle) {
if (codeTools.source || codeTools.toggle || codeTools.section) {
const title = doc.querySelector("#title-block-header h1");
const header = title !== null
? (title as Element).parentElement
Expand Down Expand Up @@ -178,7 +183,7 @@ export function codeToolsPostprocessor(format: Format) {
header!.prepend(titleDiv);
}

if (codeTools.toggle) {
if (codeTools.toggle || codeTools.section) {
button.setAttribute("id", kCodeToolsMenuButtonId);
button.classList.add("dropdown-toggle");
button.setAttribute("data-bs-toggle", "dropdown");
Expand Down Expand Up @@ -206,14 +211,29 @@ export function codeToolsPostprocessor(format: Format) {
li.appendChild(hr);
ul.appendChild(li);
};
addListItem(
kShowAllCodeLinkId,
format.language[kCodeToolsShowAllCode]!,
);
addListItem(
kHideAllCodeLinkId,
format.language[kCodeToolsHideAllCode]!,
);
if (codeTools.toggle) {
addListItem(
kShowAllCodeLinkId,
format.language[kCodeToolsShowAllCode]!,
);
addListItem(
kHideAllCodeLinkId,
format.language[kCodeToolsHideAllCode]!,
);
}
if (codeTools.section) {
if (codeTools.toggle) {
addDivider();
}
addListItem(
kShowAllSectionsLinkId,
format.language[kCodeToolsShowAllSections]!,
);
addListItem(
kHideAllSectionsLinkId,
format.language[kCodeToolsHideAllSections]!,
);
}
if (codeTools.source) {
addDivider();
const vsLi = addListItem(
Expand Down Expand Up @@ -323,6 +343,7 @@ interface CodeTools {
source: boolean | string;
toggle: boolean;
caption: string;
section: boolean;
}

function resolveCodeTools(format: Format, doc: Document): CodeTools {
Expand All @@ -343,6 +364,11 @@ function resolveCodeTools(format: Format, doc: Document): CodeTools {
caption: typeof codeTools === "boolean"
? kCodeCaption
: codeTools?.caption || kCodeCaption,
section: typeof codeTools === "boolean"
? codeTools
: codeTools?.section !== undefined
? codeTools?.section
: true,
};

// if we have request source without an external url,
Expand All @@ -362,6 +388,20 @@ function resolveCodeTools(format: Format, doc: Document): CodeTools {
codeToolsResolved.toggle = !!codeDetails || !!codeHidden;
}

// if we have requested section, make sure there are things to collapse
if (codeToolsResolved.section === true) {
codeToolsResolved.section = !!format.metadata[kSectionCollapse];
}

// Change the default caption based on what tools are shown
if (
codeToolsResolved.section &&
(codeTools === true ||
(typeof codeTools !== "boolean" && codeTools?.caption === undefined))
) {
codeToolsResolved.caption = "Tools";
}

// return resolved
return codeToolsResolved;
}
4 changes: 4 additions & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ export const kCodeLines = "code-lines";
export const kCodeToolsMenuCaption = "code-tools-menu-caption";
export const kCodeToolsShowAllCode = "code-tools-show-all-code";
export const kCodeToolsHideAllCode = "code-tools-hide-all-code";
export const kCodeToolsShowAllSections = "code-tools-show-all-sections";
export const kCodeToolsHideAllSections = "code-tools-hide-all-sections";
export const kCodeToolsViewSource = "code-tools-view-source";
export const kCodeToolsSourceCode = "code-tools-source-code";
export const kSearchNoResultsText = "search-no-results-text";
Expand Down Expand Up @@ -410,6 +412,8 @@ export const kLanguageDefaultsKeys = [
kCodeToolsMenuCaption,
kCodeToolsShowAllCode,
kCodeToolsHideAllCode,
kCodeToolsHideAllSections,
kCodeToolsShowAllSections,
kCodeToolsViewSource,
kCodeToolsSourceCode,
kToolsShare,
Expand Down
5 changes: 5 additions & 0 deletions src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ import {
kCodeSummary,
kCodeTools,
kCodeToolsHideAllCode,
kCodeToolsHideAllSections,
kCodeToolsMenuCaption,
kCodeToolsShowAllCode,
kCodeToolsShowAllSections,
kCodeToolsSourceCode,
kCodeToolsViewSource,
kColumns,
Expand Down Expand Up @@ -481,6 +483,7 @@ export interface FormatRender {
source?: boolean;
toggle?: boolean;
caption?: string;
section?: boolean;
};
[kTblColwidths]?: "auto" | boolean | number[];
[kShortcodes]?: string[];
Expand Down Expand Up @@ -680,6 +683,8 @@ export interface FormatLanguage {
[kCodeToolsMenuCaption]?: string;
[kCodeToolsShowAllCode]?: string;
[kCodeToolsHideAllCode]?: string;
[kCodeToolsShowAllSections]?: string;
[kCodeToolsHideAllSections]?: string;
[kCodeToolsViewSource]?: string;
[kCodeToolsSourceCode]?: string;
[kToolsDownload]?: string;
Expand Down
2 changes: 2 additions & 0 deletions src/format/html/format-html-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export const kUtterances = "utterances";
export const kGiscus = "giscus";
export const kAxe = "axe";

export const kSectionCollapse = "section-collapse";

export const kGiscusRepoId = "repo-id";
export const kGiscusCategoryId = "category-id";

Expand Down
1 change: 1 addition & 0 deletions src/format/html/format-html-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface HtmlFormatFeatureDefaults {
figResponsive?: boolean;
codeAnnotations?: boolean;
hoverXrefs?: boolean;
sectionCollapse?: boolean | 'closed';
}

export interface HtmlFormatTippyOptions {
Expand Down
16 changes: 16 additions & 0 deletions src/format/html/format-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import {
kXrefsHover,
quartoBaseLayer,
quartoGlobalCssVariableRules,
kSectionCollapse,
} from "./format-html-shared.ts";
import {
kSiteUrl,
Expand Down Expand Up @@ -327,6 +328,13 @@ export async function htmlFormatExtras(
options.hoverFootnotes = format.metadata[kFootnotesHover] || false;
}

if (featureDefaults.sectionCollapse) {
options.sectionCollapse = format.metadata[kSectionCollapse] !== false;
} else {
options.sectionCollapse = format.metadata[kSectionCollapse] || false;
}
options.sectionCollapseClosed = format.metadata[kSectionCollapse] === 'closed';

// Books don't currently support hover xrefs (since the content to preview in the xref
// is likely to be on another page and we don't want to do a full fetch of that page
// to get the preview)
Expand Down Expand Up @@ -413,6 +421,14 @@ export async function htmlFormatExtras(
});
}

// sectionCollapse if required
if (options.sectionCollapse) {
stylesheets.push({
name: "sectionCollapse.css",
path: formatResourcePath("html", "sectionCollapse.css"),
})
}

// tippy if required
if (options.tippy) {
scripts.push({
Expand Down
2 changes: 2 additions & 0 deletions src/resources/editor/tools/vs-code.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10344,6 +10344,8 @@ var require_yaml_intelligence_resources = __commonJS({
"section-title-appendices": "string",
"code-summary": "string",
"code-tools-menu-caption": "string",
"code-tools-show-all-sections": "string",
"code-tools-hide-all-sections": "string",
"code-tools-show-all-code": "string",
"code-tools-hide-all-code": "string",
"code-tools-view-source": "string",
Expand Down
22 changes: 22 additions & 0 deletions src/resources/formats/html/sectionCollapse.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.sc-carret {
font-family: "Courier New", Courier, monospace;
opacity: 0.7;
float: right;
cursor: pointer;
transform: rotate(-90deg);
transition: transform 0.15s ease;
user-select: none;

&:hover {
opacity: 0.8;
}

&.closed {
transform: rotate(0deg);
}
}

/* section:not(.cell-output):has(h1, h2, h3, h4, h5, h6 > div.sc-carret.closed) > :not(:first-child) */
section:not(.cell-output):has(> :is(h1,h2,h3,h4,h5,h6) > div.sc-carret.closed)> :not(:first-child) {
display: none;
}
48 changes: 45 additions & 3 deletions src/resources/formats/html/templates/quarto-html-after-body.ejs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<% if (darkMode !== undefined || tabby || anchors || copyCode || codeTools || tippy || hoverFootnotes || hoverCitations || linkExternalIcon || linkExternalNewwindow || hoverXrefs) { %>
<% if (darkMode !== undefined || tabby || anchors || copyCode || codeTools || tippy || hoverFootnotes || hoverCitations || linkExternalIcon || linkExternalNewwindow || hoverXrefs || sectionCollapse) { %>
<script id = "quarto-html-after-body" type="application/javascript">


Expand Down Expand Up @@ -678,7 +678,49 @@
<% } %>

});


<% if (sectionCollapse) { %>

const onClickCollapse = (e) => {
e.target.classList.toggle('closed');
};
const sectionSelector = "section:not(.cell-output) > :is(h1, h2, h3, h4, h5, h6)";
document.querySelectorAll(sectionSelector).forEach(heading => {
const carret = document.createElement("div");
carret.innerHTML = "‹";
carret.classList.add("sc-carret");

<% if(sectionCollapseClosed) { %>
carret.classList.add("closed");
<% } %>

carret.addEventListener('click', onClickCollapse.bind(heading));
heading.appendChild(carret);
});

<% if (codeTools) { %>

const toggleSectionHandler = (show) => () => {
const els = document.querySelectorAll(sectionSelector + " .sc-carret");
if (show) {
els.forEach(e => e.classList.remove('closed'));
} else {
els.forEach(e => e.classList.add('closed'));
}
}

const hideAllSections = window.document.getElementById("quarto-hide-all-sections");
if (hideAllSections) {
hideAllSections.addEventListener("click", toggleSectionHandler(false));
}
const showAllSections = window.document.getElementById("quarto-show-all-sections");
if (showAllSections) {
showAllSections.addEventListener("click", toggleSectionHandler(true));
}

<% } %>

<% } %>
</script>
<% } %>


2 changes: 2 additions & 0 deletions src/resources/language/_language.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ code-summary: "Code"
code-tools-menu-caption: "Code"
code-tools-show-all-code: "Show All Code"
code-tools-hide-all-code: "Hide All Code"
code-tools-show-all-sections: "Expand Sections"
code-tools-hide-all-sections: "Collapse Sections"
code-tools-view-source: "View Source"
code-tools-source-code: "Source Code"

Expand Down
2 changes: 2 additions & 0 deletions src/resources/schema/definitions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,8 @@
section-title-appendices: string
code-summary: string
code-tools-menu-caption: string
code-tools-show-all-sections: string
code-tools-hide-all-sections: string
code-tools-show-all-code: string
code-tools-hide-all-code: string
code-tools-view-source: string
Expand Down
1 change: 1 addition & 0 deletions src/resources/schema/document-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
- string
toggle: boolean
caption: string
section: boolean
default: false
description:
short: "Include a code tools menu (for hiding and showing code)."
Expand Down
8 changes: 8 additions & 0 deletions src/resources/schema/document-options.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@
formats: [$html-doc]
description: Enables hover over a section title to see an anchor link.

- name: section-collapse
schema:
enum: [true, false, "closed"]
default: false
tags:
formats: [$html-doc]
description: Add a button that collapses the content below a header

- name: tabsets
schema: boolean
default: true
Expand Down
8 changes: 7 additions & 1 deletion src/resources/schema/json-schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,12 @@
"code-tools-menu-caption": {
"type": "string"
},
"code-tools-show-all-sections": {
"type": "string"
},
"code-tools-hide-all-sections": {
"type": "string"
},
"code-tools-show-all-code": {
"type": "string"
},
Expand Down Expand Up @@ -4354,4 +4360,4 @@
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/resources/types/schema-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,8 @@ export type FormatLanguage = {
"code-tools-menu-caption"?: string;
"code-tools-show-all-code"?: string;
"code-tools-hide-all-code"?: string;
"code-tools-show-all-sections"?: string;
"code-tools-hide-all-sections"?: string;
"code-tools-view-source"?: string;
"code-tools-source-code"?: string;
"search-no-results-text"?: string;
Expand Down
Loading