Skip to content

Commit 0c351a0

Browse files
authored
Merge pull request #45 from RWS/Release-2026.03.R1
Release 2026.03.r1
2 parents 7c618b1 + fad34d1 commit 0c351a0

File tree

4 files changed

+163
-158
lines changed

4 files changed

+163
-158
lines changed

RWSTemplate/styles/custom-scripts.js

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -130,59 +130,107 @@ document.addEventListener('DOMContentLoaded', function () {
130130
const operationId = operationMap[key];
131131

132132
if (operationId) {
133+
// path (operationPath) used by copy button
134+
const operationPath = path;
133135
// 1. Create a wrapper
134136
const wrapper = document.createElement('span');
135137
wrapper.style.display = 'inline-flex';
136138
wrapper.style.alignItems = 'center';
137139

138-
// 2. Operation ID Badge
139-
const idSpan = document.createElement('span');
140-
idSpan.textContent = ` [${operationId}]`;
141-
idSpan.style.fontSize = '12px';
142-
idSpan.style.color = '#555';
143-
idSpan.style.marginLeft = '12px';
144-
idSpan.style.fontFamily = 'monospace';
145-
idSpan.style.backgroundColor = 'rgba(0,0,0,0.05)';
146-
idSpan.style.padding = '2px 6px';
147-
idSpan.style.borderRadius = '4px';
148-
idSpan.style.border = '1px solid #ddd';
149-
idSpan.className = 'inserted-operation-id';
150-
idSpan.title = 'Operation ID';
151-
152-
// 3. Anchor Link
153-
const anchorId = `/operations/${operationId}`;
154-
const anchorLink = document.createElement('a');
155-
anchorLink.href = `#${anchorId}`;
156-
anchorLink.textContent = '🔗';
157-
anchorLink.style.marginLeft = '8px';
158-
anchorLink.style.textDecoration = 'none';
159-
anchorLink.style.fontSize = '14px';
160-
anchorLink.style.cursor = 'pointer';
161-
anchorLink.title = `Permalink to ${operationId}`;
162-
163-
// Add click handler to always trigger navigation
164-
anchorLink.addEventListener('click', (e) => {
140+
// 2. Operation ID Badge (badge contains copy button and inline copy button)
141+
const badge = document.createElement('span');
142+
badge.style.display = 'inline-flex';
143+
badge.style.alignItems = 'center';
144+
badge.style.fontSize = '12px';
145+
badge.style.color = '#555';
146+
badge.style.marginLeft = '0';
147+
badge.style.fontFamily = 'monospace';
148+
badge.style.backgroundColor = '#ffffff';
149+
badge.style.boxShadow = '0 1px 4px rgba(0,0,0,0.08)';
150+
badge.style.padding = '2px';
151+
badge.style.borderRadius = '4px';
152+
badge.style.border = '1px solid #ddd';
153+
badge.className = 'inserted-operation-id-badge';
154+
155+
// Copy button (click copies the operation path)
156+
const copyBtn = document.createElement('button');
157+
copyBtn.type = 'button';
158+
copyBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="80%" height="80%" fill="none" viewBox="0 0 24 24" stroke-width="1.6" stroke="currentColor" style="display:block;width:80%;height:80%"> <path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244" /> </svg>';
159+
copyBtn.title = `Copy path: ${operationPath}`;
160+
copyBtn.setAttribute('aria-label', `Copy path ${operationPath}`);
161+
copyBtn.style.font = 'inherit';
162+
copyBtn.style.color = 'inherit';
163+
copyBtn.style.background = 'transparent';
164+
copyBtn.style.border = 'none';
165+
copyBtn.style.padding = '0';
166+
copyBtn.style.margin = '0';
167+
copyBtn.style.cursor = 'pointer';
168+
copyBtn.style.display = 'inline-flex';
169+
copyBtn.style.alignItems = 'center';
170+
copyBtn.style.justifyContent = 'center';
171+
copyBtn.style.boxSizing = 'border-box';
172+
copyBtn.style.backgroundClip = 'padding-box';
173+
copyBtn.style.borderRadius = '4px';
174+
copyBtn.className = 'inserted-operation-id';
175+
176+
// Copy-to-clipboard behavior (copies the operation path, e.g. "/resource/{id}")
177+
copyBtn.addEventListener('click', async (e) => {
165178
e.preventDefault();
166-
console.log(`Direct click on operation link: ${operationId}`);
167-
navigateToOperation(operationId);
179+
// Prevent the click from bubbling to the collapsible header
180+
e.stopPropagation();
181+
const textToCopy = operationPath;
182+
try {
183+
if (navigator.clipboard && navigator.clipboard.writeText) {
184+
await navigator.clipboard.writeText(textToCopy);
185+
} else {
186+
// Fallback for older browsers
187+
const ta = document.createElement('textarea');
188+
ta.value = textToCopy;
189+
ta.style.position = 'fixed';
190+
ta.style.opacity = '0';
191+
document.body.appendChild(ta);
192+
ta.select();
193+
document.execCommand('copy');
194+
document.body.removeChild(ta);
195+
}
196+
197+
// Temporary feedback (show SVG checkmark briefly)
198+
const original = copyBtn.innerHTML;
199+
copyBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="80%" height="80%" fill="none" viewBox="0 0 24 24" stroke-width="1.6" stroke="currentColor" style="display:block;width:80%;height:80%"> <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" /> </svg>';
200+
setTimeout(() => { copyBtn.innerHTML = original; }, 1000);
201+
} catch (err) {
202+
console.error('Copy failed', err);
203+
}
168204
});
169205

170-
wrapper.appendChild(idSpan);
171-
wrapper.appendChild(anchorLink);
172-
container.appendChild(wrapper);
206+
badge.appendChild(copyBtn);
207+
208+
// 3. Anchor ID
209+
const anchorId = `/operations/${operationId}`;
210+
211+
wrapper.appendChild(badge);
173212

174-
// 4. Set the ID on the container for scrolling
213+
const parent = container.parentElement || container;
214+
if (parent) {
215+
if (getComputedStyle(parent).position === 'static') {
216+
parent.style.position = 'relative';
217+
}
218+
wrapper.style.position = 'absolute';
219+
wrapper.style.top = '6px';
220+
wrapper.style.right = '12px';
221+
wrapper.style.zIndex = '9999';
222+
wrapper.style.pointerEvents = 'auto';
223+
try { parent.style.overflow = 'visible'; } catch (e) { /* ignore */ }
224+
copyBtn.style.width = '20px';
225+
copyBtn.style.height = '20px';
226+
227+
parent.appendChild(wrapper);
228+
} else {
229+
// fallback to previous behavior
230+
container.appendChild(wrapper);
231+
}
175232
if (!container.id) {
176233
container.id = anchorId;
177-
} else {
178-
// Append invisible anchor target
179-
const anchorTarget = document.createElement('a');
180-
anchorTarget.id = anchorId;
181-
anchorTarget.style.position = 'absolute';
182-
anchorTarget.style.top = '-100px'; // Offset for bad headers
183-
anchorTarget.style.visibility = 'hidden';
184-
container.style.position = 'relative'; // Ensure absolute positioning is relative to container
185-
container.appendChild(anchorTarget);
186234
}
187235

188236
container.dataset.opIdInjected = 'true';

articles/LCPublicAPI/api/Public-API.v1.json

Lines changed: 47 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -2464,14 +2464,26 @@
24642464
"Folder"
24652465
],
24662466
"summary": "List Folders",
2467-
"description": "Retrieves a list of all the folders in an account. Max 500.",
2467+
"description": "Retrieves a list of all the folders in an account.",
24682468
"parameters": [
24692469
{
24702470
"$ref": "#/components/parameters/Authorization"
24712471
},
24722472
{
24732473
"$ref": "#/components/parameters/X-LC-Tenant"
24742474
},
2475+
{
2476+
"$ref": "#/components/parameters/top"
2477+
},
2478+
{
2479+
"$ref": "#/components/parameters/skip"
2480+
},
2481+
{
2482+
"$ref": "#/components/parameters/location"
2483+
},
2484+
{
2485+
"$ref": "#/components/parameters/location-strategy"
2486+
},
24752487
{
24762488
"name": "name",
24772489
"in": "query",
@@ -2529,6 +2541,16 @@
25292541
"$ref": "#/components/headers/X-LC-TraceId"
25302542
}
25312543
}
2544+
},
2545+
"416": {
2546+
"description": "Error codes:\n* \"requestedRangeNotSatisfiable\": The requested entity or one of it's dependencies attempted to retrieve data outside the allowed range. Skip+Top might be outside the supported range.",
2547+
"content": {
2548+
"application/json": {
2549+
"schema": {
2550+
"$ref": "#/components/schemas/error-response"
2551+
}
2552+
}
2553+
}
25322554
}
25332555
},
25342556
"operationId": "ListFolders"
@@ -21163,38 +21185,6 @@
2116321185
}
2116421186
}
2116521187
},
21166-
"group-request": {
21167-
"title": "Group Request",
21168-
"type": "object",
21169-
"description": "Group of users.",
21170-
"properties": {
21171-
"id": {
21172-
"type": "string",
21173-
"description": "The group identifier."
21174-
},
21175-
"name": {
21176-
"type": "string",
21177-
"description": "The group name."
21178-
},
21179-
"description": {
21180-
"type": "string",
21181-
"description": "The group description."
21182-
},
21183-
"location": {
21184-
"$ref": "#/components/schemas/resource-folder-request"
21185-
},
21186-
"users": {
21187-
"type": "array",
21188-
"description": "The group users.",
21189-
"items": {
21190-
"$ref": "#/components/schemas/user-request"
21191-
}
21192-
}
21193-
},
21194-
"required": [
21195-
"id"
21196-
]
21197-
},
2119821188
"group-create-request": {
2119921189
"title": "Group Create Request",
2120021190
"type": "object",
@@ -24353,6 +24343,12 @@
2435324343
},
2435424344
"settings": {
2435524345
"$ref": "#/components/schemas/project-template-settings-response"
24346+
},
24347+
"lastModifiedAt": {
24348+
"type": "string",
24349+
"example": "2022-01-12T12:00:00Z",
24350+
"description": "The date and time when the project template was modified. <br> UTC Timezone <br> Allowed formats: <br> \"YYYY-MM-DDThh:mmZ\" <br> \"YYYY-MM-DDThh:mm:ssZ\" <br> \"YYYY-MM-DDThh:mm:ss.sZ\" <br> \"YYYY-MM-DDThh:mm:ss.ssZ\" <br> \"YYYY-MM-DDThh:mm:ss.sss",
24351+
"format": "date-time"
2435624352
}
2435724353
}
2435824354
},
@@ -26315,24 +26311,6 @@
2631526311
"remainingQuota"
2631626312
]
2631726313
},
26318-
"resource-folder-request": {
26319-
"title": "Resource Folder Request",
26320-
"type": "object",
26321-
"description": "Resource folder.",
26322-
"properties": {
26323-
"id": {
26324-
"type": "string",
26325-
"description": "The folder identifier."
26326-
},
26327-
"name": {
26328-
"type": "string",
26329-
"description": "The name of the folder."
26330-
}
26331-
},
26332-
"required": [
26333-
"id"
26334-
]
26335-
},
2633626314
"reschedule-tasks-request": {
2633726315
"description": "Reschedule tasks.",
2633826316
"properties": {
@@ -29630,6 +29608,12 @@
2963029608
},
2963129609
"sequence": {
2963229610
"$ref": "#/components/schemas/remote-translation-engine-sequence"
29611+
},
29612+
"adjacentLanguagePenalty": {
29613+
"type": "integer",
29614+
"minimum": 0,
29615+
"maximum": 30,
29616+
"default": 0
2963329617
}
2963429618
}
2963529619
},
@@ -29679,11 +29663,18 @@
2967929663
"items": {
2968029664
"$ref": "#/components/schemas/language-pair-resource"
2968129665
}
29666+
},
29667+
"adjacentLanguagePairs": {
29668+
"type": "array",
29669+
"items": {
29670+
"$ref": "#/components/schemas/language-pair"
29671+
}
2968229672
}
2968329673
},
2968429674
"required": [
2968529675
"languagePair",
29686-
"resources"
29676+
"resources",
29677+
"adjacentLanguagePair"
2968729678
]
2968829679
},
2968929680
"translation-memory-field": {
@@ -30708,51 +30699,6 @@
3070830699
}
3070930700
}
3071030701
},
30711-
"user-request": {
30712-
"title": "User Request",
30713-
"type": "object",
30714-
"description": "User in the account.",
30715-
"properties": {
30716-
"id": {
30717-
"type": "string",
30718-
"description": "The user identifier."
30719-
},
30720-
"email": {
30721-
"type": "string",
30722-
"description": "User’s email. Retrieved only for RWS ID (formerly SDL ID) users (not service users) that the authenticated entity is authorized to read."
30723-
},
30724-
"firstName": {
30725-
"type": "string",
30726-
"description": "User’s first name. Retrieved only for RWS ID (formerly SDL ID) users (not service users) that the authenticated entity is authorized to read."
30727-
},
30728-
"lastName": {
30729-
"type": "string",
30730-
"description": "User’s last name. Retrieved only for RWS ID (formerly SDL ID) users (not service users) that the authenticated entity is authorized to read."
30731-
},
30732-
"location": {
30733-
"$ref": "#/components/schemas/resource-folder-request"
30734-
},
30735-
"groups": {
30736-
"type": "array",
30737-
"description": "The groups.",
30738-
"items": {
30739-
"$ref": "#/components/schemas/group-request"
30740-
}
30741-
},
30742-
"anonymized": {
30743-
"type": "boolean",
30744-
"description": "Shows if the authenticated entity has access to read the details of the user or not. If true then the ‘anonymizedUserName’ should be retrieved.",
30745-
"nullable": true
30746-
},
30747-
"anonymizedUserName": {
30748-
"type": "string",
30749-
"description": "Retrieved if the authenticated entity does not have access to read the User."
30750-
}
30751-
},
30752-
"required": [
30753-
"id"
30754-
]
30755-
},
3075630702
"user-create-request": {
3075730703
"title": "User Create Request",
3075830704
"type": "object",
@@ -30919,18 +30865,6 @@
3091930865
],
3092030866
"description": "A vendor order resource."
3092130867
},
30922-
"vendor-order-template-request": {
30923-
"title": "Vendor Order Template Request",
30924-
"type": "object",
30925-
"properties": {
30926-
"id": {
30927-
"type": "string"
30928-
}
30929-
},
30930-
"required": [
30931-
"id"
30932-
]
30933-
},
3093430868
"vendor-order-template": {
3093530869
"title": "Vendor Order Template",
3093630870
"description": "The vendor order template.",
@@ -31044,13 +30978,13 @@
3104430978
]
3104530979
},
3104630980
"user": {
31047-
"$ref": "#/components/schemas/user-request"
30981+
"$ref": "#/components/schemas/object-id-request"
3104830982
},
3104930983
"group": {
31050-
"$ref": "#/components/schemas/group-request"
30984+
"$ref": "#/components/schemas/object-id-request"
3105130985
},
3105230986
"vendorOrderTemplate": {
31053-
"$ref": "#/components/schemas/vendor-order-template-request"
30987+
"$ref": "#/components/schemas/object-id-request"
3105430988
}
3105530989
},
3105630990
"required": [
@@ -32144,4 +32078,4 @@
3214432078
}
3214532079
}
3214632080
}
32147-
}
32081+
}

0 commit comments

Comments
 (0)