drf-to-mkdoc 0.2.3__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of drf-to-mkdoc might be problematic. Click here for more details.
- drf_to_mkdoc/conf/defaults.py +1 -0
- drf_to_mkdoc/conf/settings.py +1 -0
- drf_to_mkdoc/management/commands/build_model_docs.py +10 -1
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/field-sections-loader.js +29 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/query-parameters-loader.js +16 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/field-extractor.js +200 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +307 -14
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +39 -11
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +298 -18
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/query-parameters-extractor.js +94 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +278 -62
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/response-modal.js +173 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +59 -152
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +52 -9
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +13 -5
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +297 -25
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/fab.css +204 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/response.css +323 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/variables.css +139 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/field-sections.css +136 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +539 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +239 -17
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +503 -43
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +71 -19
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +71 -15
- drf_to_mkdoc/templates/endpoints/detail/request_body.html +2 -0
- drf_to_mkdoc/templates/er_diagrams/app.html +26 -0
- drf_to_mkdoc/templates/er_diagrams/index.html +14 -0
- drf_to_mkdoc/templates/er_diagrams/main.html +22 -0
- drf_to_mkdoc/templates/try-out/fab.html +67 -3
- drf_to_mkdoc/templates/try-out/form.html +221 -74
- drf_to_mkdoc/templates/try-out/modal.html +75 -7
- drf_to_mkdoc/templates/try-out/response-modal.html +138 -9
- drf_to_mkdoc/utils/endpoint_detail_generator.py +1 -0
- drf_to_mkdoc/utils/er_diagram_generator.py +230 -0
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/METADATA +89 -10
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/RECORD +40 -27
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,61 +1,259 @@
|
|
|
1
1
|
// Request execution functionality
|
|
2
2
|
const RequestExecutor = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
// Show validation error in the appropriate section
|
|
4
|
+
showValidationError: function(message, section) {
|
|
5
|
+
let errorContainer;
|
|
6
|
+
|
|
7
|
+
if (section === 'json') {
|
|
8
|
+
// Show error in JSON validation status
|
|
9
|
+
errorContainer = document.querySelector('.validation-status');
|
|
10
|
+
if (errorContainer) {
|
|
11
|
+
errorContainer.textContent = '✗ ' + message;
|
|
12
|
+
errorContainer.className = 'validation-status invalid';
|
|
13
|
+
}
|
|
14
|
+
} else if (section === 'parameters') {
|
|
15
|
+
// Show error in parameters section
|
|
16
|
+
const parametersTab = document.querySelector('[data-tab="parameters"]');
|
|
14
17
|
if (parametersTab) {
|
|
15
|
-
|
|
16
|
-
}
|
|
18
|
+
window.TabManager?.switchTab(parametersTab);
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
// Create or update error message
|
|
22
|
+
errorContainer = document.querySelector('#parametersError');
|
|
23
|
+
if (!errorContainer) {
|
|
24
|
+
errorContainer = document.createElement('div');
|
|
25
|
+
errorContainer.id = 'parametersError';
|
|
26
|
+
errorContainer.className = 'error-message';
|
|
27
|
+
const parametersSection = document.querySelector('#parametersTab .form-section');
|
|
28
|
+
if (parametersSection) {
|
|
29
|
+
parametersSection.insertBefore(errorContainer, parametersSection.firstChild);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
errorContainer.textContent = message;
|
|
33
|
+
errorContainer.style.display = 'block';
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Clear validation errors
|
|
38
|
+
clearValidationErrors: function() {
|
|
39
|
+
// Clear JSON validation status
|
|
40
|
+
const jsonStatus = document.querySelector('.validation-status');
|
|
41
|
+
if (jsonStatus) {
|
|
42
|
+
jsonStatus.textContent = '';
|
|
43
|
+
jsonStatus.className = 'validation-status';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Clear parameters error
|
|
47
|
+
const paramsError = document.querySelector('#parametersError');
|
|
48
|
+
if (paramsError) {
|
|
49
|
+
paramsError.style.display = 'none';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Clear all input validation states
|
|
53
|
+
document.querySelectorAll('.error').forEach(el => {
|
|
54
|
+
el.classList.remove('error');
|
|
55
|
+
});
|
|
56
|
+
document.querySelectorAll('.validation-message').forEach(msg => {
|
|
57
|
+
msg.style.display = 'none';
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// Form validation
|
|
62
|
+
validateInput: function(input) {
|
|
63
|
+
const isValid = input.value.trim() !== '';
|
|
64
|
+
const validationMessage = input.parentElement.querySelector('.validation-message');
|
|
65
|
+
|
|
66
|
+
if (!isValid) {
|
|
67
|
+
input.classList.add('error');
|
|
68
|
+
if (validationMessage) {
|
|
69
|
+
validationMessage.textContent = 'This field is required';
|
|
70
|
+
validationMessage.style.display = 'block';
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
input.classList.remove('error');
|
|
74
|
+
if (validationMessage) {
|
|
75
|
+
validationMessage.textContent = '';
|
|
76
|
+
validationMessage.style.display = 'none';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return isValid;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Build complete request data
|
|
84
|
+
buildRequestData: function() {
|
|
85
|
+
const baseUrl = document.getElementById('baseUrl')?.value || '';
|
|
86
|
+
const pathDisplay = document.querySelector('.path-display')?.textContent || '';
|
|
87
|
+
|
|
88
|
+
// Build full URL
|
|
89
|
+
let fullUrl = baseUrl + pathDisplay;
|
|
90
|
+
|
|
91
|
+
// Replace path parameters
|
|
92
|
+
const pathParams = {};
|
|
93
|
+
document.querySelectorAll('#pathParams input').forEach(input => {
|
|
94
|
+
const param = input.dataset.param;
|
|
95
|
+
if (param && input.value) {
|
|
96
|
+
pathParams[param] = input.value;
|
|
97
|
+
fullUrl = fullUrl.replace(`{${param}}`, encodeURIComponent(input.value));
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Collect query parameters
|
|
102
|
+
const queryParams = {};
|
|
103
|
+
document.querySelectorAll('#queryParams .parameter-item').forEach(item => {
|
|
104
|
+
const nameInput = item.querySelector('.name-input');
|
|
105
|
+
const valueInput = item.querySelector('.value-input');
|
|
106
|
+
if (nameInput?.value && valueInput?.value) {
|
|
107
|
+
queryParams[nameInput.value] = valueInput.value;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Add query parameters to URL
|
|
112
|
+
if (Object.keys(queryParams).length > 0) {
|
|
113
|
+
const queryString = new URLSearchParams(queryParams).toString();
|
|
114
|
+
fullUrl += (fullUrl.includes('?') ? '&' : '?') + queryString;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Collect headers
|
|
118
|
+
const headers = {};
|
|
119
|
+
document.querySelectorAll('#requestHeaders .header-item').forEach(item => {
|
|
120
|
+
const nameInput = item.querySelector('.name-input');
|
|
121
|
+
const valueInput = item.querySelector('.value-input');
|
|
122
|
+
if (nameInput?.value && valueInput?.value) {
|
|
123
|
+
headers[nameInput.value] = valueInput.value;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Add default headers if not already set
|
|
128
|
+
if (!headers['Accept']) {
|
|
129
|
+
headers['Accept'] = '*/*';
|
|
130
|
+
}
|
|
131
|
+
if (!headers['User-Agent']) {
|
|
132
|
+
headers['User-Agent'] = navigator.userAgent;
|
|
133
|
+
}
|
|
134
|
+
if (!headers['Accept-Language']) {
|
|
135
|
+
headers['Accept-Language'] = navigator.language || 'en-US,en;q=0.9';
|
|
136
|
+
}
|
|
137
|
+
if (!headers['Accept-Encoding']) {
|
|
138
|
+
headers['Accept-Encoding'] = 'gzip, deflate, br';
|
|
139
|
+
}
|
|
140
|
+
if (!headers['Connection']) {
|
|
141
|
+
headers['Connection'] = 'keep-alive';
|
|
142
|
+
}
|
|
143
|
+
if (!headers['Cache-Control']) {
|
|
144
|
+
headers['Cache-Control'] = 'no-cache';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Add cookies if available
|
|
148
|
+
if (document.cookie) {
|
|
149
|
+
headers['Cookie'] = document.cookie;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Get request body
|
|
153
|
+
const bodyEditor = document.getElementById('requestBody');
|
|
154
|
+
let body = null;
|
|
155
|
+
if (bodyEditor?.value.trim()) {
|
|
156
|
+
try {
|
|
157
|
+
body = JSON.parse(bodyEditor.value);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
body = bodyEditor.value;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Get method
|
|
164
|
+
const methodBadge = document.querySelector('.method-badge');
|
|
165
|
+
const method = methodBadge?.dataset.method || 'GET';
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
url: fullUrl,
|
|
169
|
+
method,
|
|
170
|
+
headers,
|
|
171
|
+
body,
|
|
172
|
+
pathParams,
|
|
173
|
+
queryParams
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
async executeRequest() {
|
|
177
|
+
const executeBtn = document.querySelector('[data-action="send"], .primary-button, .primary-btn, #executeBtn');
|
|
178
|
+
if (!executeBtn) {
|
|
179
|
+
console.warn('Execute button not found');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Validate required fields
|
|
184
|
+
const requiredInputs = document.querySelectorAll('#pathParams input[required]');
|
|
185
|
+
let emptyFields = [];
|
|
186
|
+
|
|
187
|
+
requiredInputs.forEach(input => {
|
|
188
|
+
if (!input.value.trim()) {
|
|
189
|
+
const paramName = input.dataset.param || 'parameter';
|
|
190
|
+
emptyFields.push(paramName);
|
|
191
|
+
this.validateInput(input);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (emptyFields.length > 0) {
|
|
196
|
+
this.showValidationError(`Please fill in required fields: ${emptyFields.join(', ')}`, 'parameters');
|
|
20
197
|
return;
|
|
21
198
|
}
|
|
22
199
|
|
|
23
200
|
// Show loading state
|
|
24
201
|
this.setLoadingState(executeBtn, true);
|
|
25
202
|
|
|
203
|
+
const startTime = Date.now();
|
|
204
|
+
|
|
26
205
|
try {
|
|
27
|
-
const
|
|
28
|
-
const url = FormManager.buildRequestUrl();
|
|
29
|
-
const headers = FormManager.getRequestHeaders();
|
|
30
|
-
const body = FormManager.getRequestBody();
|
|
31
|
-
const method = document.querySelector('.try-out-form')?.getAttribute('data-method') || 'GET';
|
|
206
|
+
const requestData = this.buildRequestData();
|
|
32
207
|
|
|
33
208
|
const requestOptions = {
|
|
34
|
-
method: method.toUpperCase(),
|
|
35
|
-
headers: headers
|
|
209
|
+
method: requestData.method.toUpperCase(),
|
|
210
|
+
headers: requestData.headers
|
|
36
211
|
};
|
|
37
212
|
|
|
38
213
|
// Add body for non-GET requests
|
|
39
|
-
if (body && !['GET', 'HEAD'].includes(method.toUpperCase())) {
|
|
40
|
-
if (typeof body === 'string') {
|
|
41
|
-
requestOptions.body = body;
|
|
214
|
+
if (requestData.body && !['GET', 'HEAD'].includes(requestData.method.toUpperCase())) {
|
|
215
|
+
if (typeof requestData.body === 'string') {
|
|
216
|
+
requestOptions.body = requestData.body;
|
|
42
217
|
} else {
|
|
43
|
-
requestOptions.body = JSON.stringify(body);
|
|
44
|
-
if (!headers['Content-Type']) {
|
|
218
|
+
requestOptions.body = JSON.stringify(requestData.body);
|
|
219
|
+
if (!requestData.headers['Content-Type']) {
|
|
45
220
|
requestOptions.headers['Content-Type'] = 'application/json';
|
|
46
221
|
}
|
|
47
222
|
}
|
|
48
223
|
}
|
|
49
224
|
|
|
50
|
-
|
|
225
|
+
// Show response section
|
|
226
|
+
const responseSection = document.querySelector('.response-section');
|
|
227
|
+
if (responseSection) {
|
|
228
|
+
responseSection.hidden = false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const response = await fetch(requestData.url, requestOptions);
|
|
51
232
|
const responseTime = Date.now() - startTime;
|
|
52
233
|
const responseText = await response.text();
|
|
53
234
|
|
|
54
|
-
|
|
235
|
+
// Convert response headers to object
|
|
236
|
+
const responseHeaders = {};
|
|
237
|
+
response.headers.forEach((value, key) => {
|
|
238
|
+
// Handle multiple headers with the same name (like Set-Cookie)
|
|
239
|
+
if (responseHeaders[key]) {
|
|
240
|
+
if (Array.isArray(responseHeaders[key])) {
|
|
241
|
+
responseHeaders[key].push(value);
|
|
242
|
+
} else {
|
|
243
|
+
responseHeaders[key] = [responseHeaders[key], value];
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
responseHeaders[key] = value;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
ModalManager.showResponseModal(response.status, responseText, responseTime, responseHeaders, requestData.headers);
|
|
55
251
|
|
|
56
252
|
} catch (error) {
|
|
57
|
-
|
|
58
|
-
|
|
253
|
+
console.error('Request failed:', error);
|
|
254
|
+
const requestData = this.buildRequestData();
|
|
255
|
+
const errorTime = Date.now() - startTime;
|
|
256
|
+
ModalManager.showResponseModal('Error', error.message || 'Unknown error occurred', errorTime, null, requestData.headers);
|
|
59
257
|
} finally {
|
|
60
258
|
this.setLoadingState(executeBtn, false);
|
|
61
259
|
}
|
|
@@ -63,49 +261,67 @@ const RequestExecutor = {
|
|
|
63
261
|
|
|
64
262
|
setLoadingState(button, loading) {
|
|
65
263
|
button.disabled = loading;
|
|
66
|
-
button.innerHTML = '';
|
|
67
264
|
|
|
68
265
|
if (loading) {
|
|
69
|
-
|
|
70
|
-
spinner
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
266
|
+
button.classList.add('loading');
|
|
267
|
+
const spinner = button.querySelector('.loading-spinner');
|
|
268
|
+
if (spinner) {
|
|
269
|
+
spinner.style.display = 'inline-block';
|
|
270
|
+
}
|
|
74
271
|
} else {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
272
|
+
button.classList.remove('loading');
|
|
273
|
+
const spinner = button.querySelector('.loading-spinner');
|
|
274
|
+
if (spinner) {
|
|
275
|
+
spinner.style.display = 'none';
|
|
276
|
+
}
|
|
80
277
|
}
|
|
81
278
|
},
|
|
82
279
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (!
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
280
|
+
// JSON formatting and validation
|
|
281
|
+
formatJson: function() {
|
|
282
|
+
const editor = document.getElementById('requestBody');
|
|
283
|
+
if (!editor) return;
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
const formatted = JSON.stringify(JSON.parse(editor.value), null, 2);
|
|
287
|
+
editor.value = formatted;
|
|
288
|
+
this.validateJson();
|
|
289
|
+
} catch (e) {
|
|
290
|
+
this.showValidationError('Invalid JSON format', 'json');
|
|
95
291
|
}
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
validateJson: function() {
|
|
295
|
+
const editor = document.getElementById('requestBody');
|
|
296
|
+
const status = document.querySelector('.validation-status');
|
|
96
297
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
298
|
+
if (!editor || !status) return true;
|
|
299
|
+
|
|
300
|
+
if (!editor.value.trim()) {
|
|
301
|
+
status.textContent = '';
|
|
302
|
+
status.className = 'validation-status';
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
JSON.parse(editor.value);
|
|
308
|
+
status.textContent = '✓ Valid JSON';
|
|
309
|
+
status.className = 'validation-status valid';
|
|
310
|
+
return true;
|
|
311
|
+
} catch (e) {
|
|
312
|
+
status.textContent = '✗ ' + e.message;
|
|
313
|
+
status.className = 'validation-status invalid';
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
// This method is now handled by the main showValidationError method above
|
|
105
319
|
};
|
|
106
320
|
|
|
107
|
-
// Global
|
|
321
|
+
// Global functions for onclick handlers and backward compatibility
|
|
108
322
|
window.executeRequest = () => RequestExecutor.executeRequest();
|
|
323
|
+
window.formatJson = () => RequestExecutor.formatJson();
|
|
324
|
+
window.validateJson = () => RequestExecutor.validateJson();
|
|
109
325
|
|
|
110
326
|
// Export for global access
|
|
111
327
|
window.RequestExecutor = RequestExecutor;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Response modal functionality
|
|
2
|
+
const ResponseModalManager = {
|
|
3
|
+
init: function() {
|
|
4
|
+
// Tab switching
|
|
5
|
+
const tabs = document.querySelectorAll('.response-tabs .tab');
|
|
6
|
+
tabs.forEach(tab => {
|
|
7
|
+
tab.addEventListener('click', () => this.switchTab(tab));
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// Initialize syntax highlighting
|
|
11
|
+
this.initializePrism();
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
switchTab: function(tab) {
|
|
15
|
+
if (!tab) return;
|
|
16
|
+
|
|
17
|
+
// Remove active class from all tabs and content
|
|
18
|
+
document.querySelectorAll('.response-tabs .tab').forEach(t => {
|
|
19
|
+
if (t && t.classList) {
|
|
20
|
+
t.classList.remove('active');
|
|
21
|
+
t.setAttribute('aria-selected', 'false');
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
document.querySelectorAll('.tab-content').forEach(c => {
|
|
25
|
+
if (c && c.classList) {
|
|
26
|
+
c.classList.remove('active');
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Add active class to clicked tab and its content
|
|
31
|
+
if (tab.classList) {
|
|
32
|
+
tab.classList.add('active');
|
|
33
|
+
tab.setAttribute('aria-selected', 'true');
|
|
34
|
+
}
|
|
35
|
+
const contentId = tab.getAttribute('aria-controls');
|
|
36
|
+
const contentElement = document.getElementById(contentId);
|
|
37
|
+
if (contentElement && contentElement.classList) {
|
|
38
|
+
contentElement.classList.add('active');
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
copyResponse: function() {
|
|
43
|
+
const responseBody = document.getElementById('modalResponseBody');
|
|
44
|
+
if (!responseBody) return;
|
|
45
|
+
|
|
46
|
+
const responseText = responseBody.textContent;
|
|
47
|
+
if (navigator.clipboard) {
|
|
48
|
+
navigator.clipboard.writeText(responseText).then(() => {
|
|
49
|
+
this.showToast('Response copied to clipboard');
|
|
50
|
+
}).catch(() => {
|
|
51
|
+
this.showToast('Failed to copy response');
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
this.showToast('Clipboard not supported');
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
downloadResponse: function() {
|
|
59
|
+
const responseBody = document.getElementById('modalResponseBody');
|
|
60
|
+
if (!responseBody) return;
|
|
61
|
+
|
|
62
|
+
const responseText = responseBody.textContent;
|
|
63
|
+
const blob = new Blob([responseText], { type: 'application/json' });
|
|
64
|
+
const url = URL.createObjectURL(blob);
|
|
65
|
+
const a = document.createElement('a');
|
|
66
|
+
a.href = url;
|
|
67
|
+
a.download = 'response.json';
|
|
68
|
+
document.body.appendChild(a);
|
|
69
|
+
a.click();
|
|
70
|
+
document.body.removeChild(a);
|
|
71
|
+
URL.revokeObjectURL(url);
|
|
72
|
+
this.showToast('Response downloaded');
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
formatResponse: function() {
|
|
76
|
+
try {
|
|
77
|
+
const responseBody = document.getElementById('modalResponseBody');
|
|
78
|
+
if (!responseBody) return;
|
|
79
|
+
|
|
80
|
+
const content = responseBody.textContent;
|
|
81
|
+
if (!content.trim()) return;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const parsed = JSON.parse(content);
|
|
85
|
+
responseBody.textContent = JSON.stringify(parsed, null, 2);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
// If not JSON, just return as is
|
|
88
|
+
console.log('Response is not valid JSON, skipping formatting');
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Error formatting response:', error);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
collapseAll: function() {
|
|
96
|
+
const responseBody = document.getElementById('modalResponseBody');
|
|
97
|
+
if (!responseBody) return;
|
|
98
|
+
|
|
99
|
+
// Simple collapse - replace newlines with spaces for basic collapse
|
|
100
|
+
const content = responseBody.textContent;
|
|
101
|
+
if (content) {
|
|
102
|
+
responseBody.textContent = content.replace(/\n\s*/g, ' ').trim();
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
expandAll: function() {
|
|
107
|
+
const responseBody = document.getElementById('modalResponseBody');
|
|
108
|
+
if (!responseBody) return;
|
|
109
|
+
|
|
110
|
+
const content = responseBody.textContent;
|
|
111
|
+
if (!content.trim()) return;
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Try to format as JSON first
|
|
115
|
+
const parsed = JSON.parse(content);
|
|
116
|
+
responseBody.textContent = JSON.stringify(parsed, null, 2);
|
|
117
|
+
} catch (e) {
|
|
118
|
+
// If not JSON, just restore original formatting
|
|
119
|
+
responseBody.textContent = content;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
showToast: function(message) {
|
|
124
|
+
// Create toast element
|
|
125
|
+
const toast = document.createElement('div');
|
|
126
|
+
toast.className = 'toast';
|
|
127
|
+
toast.textContent = message;
|
|
128
|
+
toast.style.cssText = `
|
|
129
|
+
position: fixed;
|
|
130
|
+
top: 20px;
|
|
131
|
+
right: 20px;
|
|
132
|
+
background: #333;
|
|
133
|
+
color: white;
|
|
134
|
+
padding: 12px 20px;
|
|
135
|
+
border-radius: 4px;
|
|
136
|
+
z-index: 10000;
|
|
137
|
+
font-size: 14px;
|
|
138
|
+
opacity: 0;
|
|
139
|
+
transition: opacity 0.3s ease;
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
document.body.appendChild(toast);
|
|
143
|
+
|
|
144
|
+
// Show toast
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
toast.style.opacity = '1';
|
|
147
|
+
}, 10);
|
|
148
|
+
|
|
149
|
+
// Hide toast after 3 seconds
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
toast.style.opacity = '0';
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
if (toast.parentNode) {
|
|
154
|
+
toast.parentNode.removeChild(toast);
|
|
155
|
+
}
|
|
156
|
+
}, 300);
|
|
157
|
+
}, 3000);
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
initializePrism: function() {
|
|
161
|
+
// Basic syntax highlighting placeholder
|
|
162
|
+
// This would integrate with Prism.js if available
|
|
163
|
+
console.log('Syntax highlighting initialized');
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Export for global access
|
|
168
|
+
window.ResponseModalManager = ResponseModalManager;
|
|
169
|
+
|
|
170
|
+
// Initialize when DOM is loaded
|
|
171
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
172
|
+
ResponseModalManager.init();
|
|
173
|
+
});
|