diff --git a/RWSTemplate/styles/custom-scripts.js b/RWSTemplate/styles/custom-scripts.js
index f7857b5..d6c9167 100644
--- a/RWSTemplate/styles/custom-scripts.js
+++ b/RWSTemplate/styles/custom-scripts.js
@@ -130,59 +130,108 @@ document.addEventListener('DOMContentLoaded', function () {
const operationId = operationMap[key];
if (operationId) {
+ // path (operationPath) used by copy button
+ const operationPath = path;
// 1. Create a wrapper
const wrapper = document.createElement('span');
wrapper.style.display = 'inline-flex';
wrapper.style.alignItems = 'center';
- // 2. Operation ID Badge
- const idSpan = document.createElement('span');
- idSpan.textContent = ` [${operationId}]`;
- idSpan.style.fontSize = '12px';
- idSpan.style.color = '#555';
- idSpan.style.marginLeft = '12px';
- idSpan.style.fontFamily = 'monospace';
- idSpan.style.backgroundColor = 'rgba(0,0,0,0.05)';
- idSpan.style.padding = '2px 6px';
- idSpan.style.borderRadius = '4px';
- idSpan.style.border = '1px solid #ddd';
- idSpan.className = 'inserted-operation-id';
- idSpan.title = 'Operation ID';
-
- // 3. Anchor Link
- const anchorId = `/operations/${operationId}`;
- const anchorLink = document.createElement('a');
- anchorLink.href = `#${anchorId}`;
- anchorLink.textContent = '🔗';
- anchorLink.style.marginLeft = '8px';
- anchorLink.style.textDecoration = 'none';
- anchorLink.style.fontSize = '14px';
- anchorLink.style.cursor = 'pointer';
- anchorLink.title = `Permalink to ${operationId}`;
-
- // Add click handler to always trigger navigation
- anchorLink.addEventListener('click', (e) => {
+ // 2. Operation ID Badge (badge contains copy button and inline copy button)
+ const badge = document.createElement('span');
+ badge.style.display = 'inline-flex';
+ badge.style.alignItems = 'center';
+ badge.style.fontSize = '12px';
+ badge.style.color = '#555';
+ badge.style.marginLeft = '0';
+ badge.style.fontFamily = 'monospace';
+ badge.style.backgroundColor = '#ffffff';
+ badge.style.boxShadow = '0 1px 4px rgba(0,0,0,0.08)';
+ badge.style.padding = '2px';
+ badge.style.borderRadius = '4px';
+ badge.style.border = '1px solid #ddd';
+ badge.className = 'inserted-operation-id-badge';
+
+ // Copy button (click copies the operation path)
+ const copyBtn = document.createElement('button');
+ copyBtn.type = 'button';
+ copyBtn.innerHTML = '';
+ copyBtn.title = `Copy path: ${operationPath}`;
+ copyBtn.setAttribute('aria-label', `Copy path ${operationPath}`);
+ copyBtn.style.font = 'inherit';
+ copyBtn.style.color = 'inherit';
+ copyBtn.style.background = 'transparent';
+ copyBtn.style.border = 'none';
+ copyBtn.style.padding = '0';
+ copyBtn.style.margin = '0';
+ copyBtn.style.cursor = 'pointer';
+ copyBtn.style.display = 'inline-flex';
+ copyBtn.style.alignItems = 'center';
+ copyBtn.style.justifyContent = 'center';
+ copyBtn.style.boxSizing = 'border-box';
+ copyBtn.style.backgroundClip = 'padding-box';
+ copyBtn.style.borderRadius = '4px';
+ copyBtn.className = 'inserted-operation-id';
+
+ // Copy-to-clipboard behavior (copies the operation path, e.g. "/resource/{id}")
+ copyBtn.addEventListener('click', async (e) => {
e.preventDefault();
- console.log(`Direct click on operation link: ${operationId}`);
- navigateToOperation(operationId);
+ // Prevent the click from bubbling to the collapsible header
+ e.stopPropagation();
+ const textToCopy = operationPath;
+ try {
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ await navigator.clipboard.writeText(textToCopy);
+ } else {
+ // Fallback for older browsers
+ const ta = document.createElement('textarea');
+ ta.value = textToCopy;
+ ta.style.position = 'fixed';
+ ta.style.opacity = '0';
+ document.body.appendChild(ta);
+ ta.select();
+ document.execCommand('copy');
+ document.body.removeChild(ta);
+ }
+
+ // Temporary feedback (show SVG checkmark briefly)
+ const original = copyBtn.innerHTML;
+ copyBtn.innerHTML = '';
+ setTimeout(() => { copyBtn.innerHTML = original; }, 1000);
+ } catch (err) {
+ console.error('Copy failed', err);
+ }
});
- wrapper.appendChild(idSpan);
- wrapper.appendChild(anchorLink);
- container.appendChild(wrapper);
+ badge.appendChild(copyBtn);
+
+ // 3. Anchor ID
+ const anchorId = `/operations/${operationId}`;
+
+ wrapper.appendChild(badge);
- // 4. Set the ID on the container for scrolling
+ const parent = container.parentElement || container;
+ if (parent) {
+ if (getComputedStyle(parent).position === 'static') {
+ parent.style.position = 'relative';
+ }
+ wrapper.style.position = 'absolute';
+ wrapper.style.top = '50%';
+ wrapper.style.transform = 'translateY(-50%)';
+ wrapper.style.right = '12px';
+ wrapper.style.zIndex = '9999';
+ wrapper.style.pointerEvents = 'auto';
+ try { parent.style.overflow = 'visible'; } catch (e) { /* ignore */ }
+ copyBtn.style.width = '20px';
+ copyBtn.style.height = '20px';
+
+ parent.appendChild(wrapper);
+ } else {
+ // fallback to previous behavior
+ container.appendChild(wrapper);
+ }
if (!container.id) {
container.id = anchorId;
- } else {
- // Append invisible anchor target
- const anchorTarget = document.createElement('a');
- anchorTarget.id = anchorId;
- anchorTarget.style.position = 'absolute';
- anchorTarget.style.top = '-100px'; // Offset for bad headers
- anchorTarget.style.visibility = 'hidden';
- container.style.position = 'relative'; // Ensure absolute positioning is relative to container
- container.appendChild(anchorTarget);
}
container.dataset.opIdInjected = 'true';
diff --git a/docfx.json b/docfx.json
index f6a94a3..ccef19e 100644
--- a/docfx.json
+++ b/docfx.json
@@ -19,6 +19,9 @@
{
"files": [
"api/**.yml"
+ ],
+ "exclude": [
+ "_site/**"
]
},
{
@@ -27,6 +30,9 @@
"articles/**/toc.yml",
"toc.yml",
"*.md"
+ ],
+ "exclude": [
+ "_site/**"
]
}
],
@@ -37,6 +43,9 @@
"**/*.json",
"**/*.html",
"**/*.js"
+ ],
+ "exclude": [
+ "_site/**"
]
}
],
@@ -56,13 +65,21 @@
"fileMetadataFiles": [],
"filemetadata": {
"langs": {
- "api/**.yml": [ "csharp", "vb", "fsharp", "cpp" ]
+ "api/**.yml": [
+ "csharp",
+ "vb",
+ "fsharp",
+ "cpp"
+ ]
}
},
"template": [
"RWSTemplate"
],
- "postProcessors": [ "ExtractSearchIndex", "EnvironmentVariableProcessor" ],
+ "postProcessors": [
+ "ExtractSearchIndex",
+ "EnvironmentVariableProcessor"
+ ],
"globalMetadata": {
"_enableSearch": true
},