drf-to-mkdoc 0.2.3__py3-none-any.whl → 0.2.4__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.

Files changed (33) hide show
  1. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/field-sections-loader.js +29 -0
  2. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/query-parameters-loader.js +16 -0
  3. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/field-extractor.js +200 -0
  4. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +307 -14
  5. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +39 -11
  6. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +298 -18
  7. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/query-parameters-extractor.js +94 -0
  8. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +278 -62
  9. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/response-modal.js +173 -0
  10. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +59 -152
  11. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +52 -9
  12. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +13 -5
  13. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +297 -25
  14. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/fab.css +204 -0
  15. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/response.css +323 -0
  16. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/variables.css +139 -0
  17. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/field-sections.css +136 -0
  18. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +539 -0
  19. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +239 -17
  20. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +503 -43
  21. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +71 -19
  22. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +71 -15
  23. drf_to_mkdoc/templates/endpoints/detail/request_body.html +2 -0
  24. drf_to_mkdoc/templates/try-out/fab.html +67 -3
  25. drf_to_mkdoc/templates/try-out/form.html +221 -74
  26. drf_to_mkdoc/templates/try-out/modal.html +75 -7
  27. drf_to_mkdoc/templates/try-out/response-modal.html +138 -9
  28. drf_to_mkdoc/utils/endpoint_detail_generator.py +1 -0
  29. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.2.4.dist-info}/METADATA +68 -9
  30. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.2.4.dist-info}/RECORD +33 -24
  31. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.2.4.dist-info}/WHEEL +0 -0
  32. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.2.4.dist-info}/licenses/LICENSE +0 -0
  33. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.2.4.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,55 @@
1
1
  // Modal management functionality
2
2
  const ModalManager = {
3
+ init: function() {
4
+ this.setupKeyboardTraps();
5
+ this.setupEventListeners();
6
+ },
7
+
8
+ setupKeyboardTraps: function() {
9
+ const modal = document.getElementById('tryOutModal');
10
+ if (!modal) return;
11
+
12
+ // Trap focus within modal when open
13
+ modal.addEventListener('keydown', (e) => {
14
+ if (e.key === 'Escape') {
15
+ this.closeTryOut();
16
+ }
17
+
18
+ if (e.key === 'Tab') {
19
+ const focusableElements = modal.querySelectorAll(
20
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
21
+ );
22
+ const firstFocusable = focusableElements[0];
23
+ const lastFocusable = focusableElements[focusableElements.length - 1];
24
+
25
+ if (e.shiftKey) {
26
+ if (document.activeElement === firstFocusable) {
27
+ lastFocusable.focus();
28
+ e.preventDefault();
29
+ }
30
+ } else {
31
+ if (document.activeElement === lastFocusable) {
32
+ firstFocusable.focus();
33
+ e.preventDefault();
34
+ }
35
+ }
36
+ }
37
+ });
38
+ },
39
+
40
+ setupEventListeners: function() {
41
+ // Close modal when clicking overlay
42
+ const overlay = document.querySelector('.modal-overlay');
43
+ if (overlay) {
44
+ overlay.addEventListener('click', () => this.closeTryOut());
45
+ }
46
+
47
+ // Close modal with close button
48
+ const closeButtons = document.querySelectorAll('.modal-close');
49
+ closeButtons.forEach(btn => {
50
+ btn.addEventListener('click', () => this.closeTryOut());
51
+ });
52
+ },
3
53
  openTryOut: function() {
4
54
  const modal = document.getElementById('tryOutModal');
5
55
  if (modal) {
@@ -8,10 +58,22 @@ const ModalManager = {
8
58
  document.body.classList.add('modal-open');
9
59
 
10
60
  // Focus management
11
- const firstInput = modal.querySelector('input, button');
12
- if (firstInput) {
13
- firstInput.focus();
14
- }
61
+ setTimeout(() => {
62
+ const firstInput = modal.querySelector('input, button');
63
+ if (firstInput) {
64
+ firstInput.focus();
65
+ }
66
+ }, 100);
67
+
68
+ // Reinitialize components for dynamic content
69
+ setTimeout(() => {
70
+ if (window.FormManager) {
71
+ window.FormManager.init();
72
+ }
73
+ if (window.TryOutSuggestions) {
74
+ window.TryOutSuggestions.init();
75
+ }
76
+ }, 150);
15
77
  }
16
78
  },
17
79
 
@@ -21,6 +83,12 @@ const ModalManager = {
21
83
  modal.classList.remove('show');
22
84
  modal.style.display = 'none';
23
85
  document.body.classList.remove('modal-open');
86
+
87
+ // Hide response section
88
+ const responseSection = document.querySelector('.response-section');
89
+ if (responseSection) {
90
+ responseSection.hidden = true;
91
+ }
24
92
  }
25
93
  },
26
94
 
@@ -29,6 +97,13 @@ const ModalManager = {
29
97
  if (modal) {
30
98
  modal.classList.add('show');
31
99
  modal.style.display = 'flex';
100
+
101
+ // Reinitialize tabs for response modal
102
+ setTimeout(() => {
103
+ if (window.TabManager) {
104
+ window.TabManager.init();
105
+ }
106
+ }, 100);
32
107
  }
33
108
  },
34
109
 
@@ -40,40 +115,245 @@ const ModalManager = {
40
115
  }
41
116
  },
42
117
 
43
- showResponseModal: function(status, responseText, responseTime) {
118
+ showResponseModal: function(status, responseText, responseTime, responseHeaders, requestHeaders) {
44
119
  const modal = document.getElementById('responseModal');
45
120
  const statusBadge = document.getElementById('modalStatusBadge');
46
121
  const responseBody = document.getElementById('modalResponseBody');
47
122
  const responseInfo = document.getElementById('responseInfo');
123
+ const headersList = document.getElementById('responseHeadersList');
124
+ const timeElement = document.getElementById('responseTime');
125
+ const sizeElement = document.getElementById('responseSize');
48
126
 
49
127
  if (modal && statusBadge && responseBody) {
50
- statusBadge.textContent = String(status);
51
- const code = Number(status);
52
- statusBadge.className = 'status-badge' + (Number.isFinite(code) ? ` status-${Math.floor(code/100)*100}` : '');
53
-
54
- try {
55
- const jsonResponse = JSON.parse(responseText);
56
- responseBody.textContent = JSON.stringify(jsonResponse, null, 2);
57
- } catch (e) {
128
+ // Update time and size stats
129
+ if (timeElement && responseTime !== null && responseTime !== undefined) {
130
+ timeElement.textContent = `${responseTime} ms`;
131
+ }
132
+
133
+ if (sizeElement && responseText) {
134
+ const sizeInBytes = new Blob([responseText]).size;
135
+ const formattedSize = this.formatSize(sizeInBytes);
136
+ sizeElement.textContent = formattedSize;
137
+ }
138
+
139
+ // Handle error status
140
+ if (status === 'Error') {
141
+ statusBadge.textContent = 'Error';
142
+ statusBadge.className = 'status-badge status-error';
58
143
  responseBody.textContent = responseText;
144
+ if (responseInfo) {
145
+ responseInfo.textContent = 'Request failed';
146
+ }
147
+ } else {
148
+ // Handle regular response
149
+ statusBadge.textContent = String(status);
150
+ const code = Number(status);
151
+ statusBadge.className = 'status-badge' + (Number.isFinite(code) ? ` status-${Math.floor(code/100)}xx` : '');
152
+
153
+ try {
154
+ const jsonResponse = JSON.parse(responseText);
155
+
156
+ // Show formatted JSON response
157
+ responseBody.textContent = JSON.stringify(jsonResponse, null, 2);
158
+ } catch (e) {
159
+ // Handle non-JSON response
160
+ if (code >= 400) {
161
+ responseBody.innerHTML = `<div class="error-message">
162
+ <div class="error-title">Error Response</div>
163
+ <pre class="error-content">${responseText}</pre>
164
+ </div>`;
165
+ } else {
166
+ responseBody.innerHTML = `<pre class="error-content">${responseText}</pre>`;
167
+ }
168
+ }
169
+
170
+ if (responseInfo) {
171
+ responseInfo.textContent = '';
172
+ }
59
173
  }
60
174
 
61
- if (responseInfo && responseTime) {
62
- responseInfo.textContent = `Response time: ${responseTime}ms`;
175
+ // Display headers
176
+ if (headersList) {
177
+ this.displayHeaders(headersList, responseHeaders, requestHeaders);
63
178
  }
64
179
 
65
180
  this.openResponseModal();
66
181
  }
182
+ },
183
+
184
+ displayHeaders: function(headersList, responseHeaders, requestHeaders) {
185
+ headersList.innerHTML = '';
186
+
187
+ // Create response headers section
188
+ if (responseHeaders && Object.keys(responseHeaders).length > 0) {
189
+ const responseSection = document.createElement('div');
190
+ responseSection.className = 'headers-section';
191
+
192
+ const responseTitle = document.createElement('h4');
193
+ responseTitle.textContent = `Response Headers (${Object.keys(responseHeaders).length})`;
194
+ responseTitle.className = 'headers-title';
195
+ responseSection.appendChild(responseTitle);
196
+
197
+ const responseList = document.createElement('div');
198
+ responseList.className = 'headers-grid';
199
+
200
+ // Sort headers alphabetically
201
+ const sortedResponseHeaders = Object.entries(responseHeaders).sort(([a], [b]) => a.toLowerCase().localeCompare(b.toLowerCase()));
202
+
203
+ sortedResponseHeaders.forEach(([key, value]) => {
204
+ const headerItem = document.createElement('div');
205
+ headerItem.className = 'header-item';
206
+
207
+ const headerKey = document.createElement('div');
208
+ headerKey.className = 'header-key';
209
+ headerKey.textContent = key;
210
+
211
+ const headerValue = document.createElement('div');
212
+ headerValue.className = 'header-value';
213
+
214
+ // Special formatting for cookies
215
+ if (key.toLowerCase() === 'set-cookie') {
216
+ const cookieList = document.createElement('div');
217
+ cookieList.className = 'cookie-list';
218
+
219
+ // Handle multiple Set-Cookie headers
220
+ const cookies = Array.isArray(value) ? value : [value];
221
+ cookies.forEach(cookie => {
222
+ const cookieItem = document.createElement('div');
223
+ cookieItem.className = 'cookie-item';
224
+ cookieItem.textContent = cookie;
225
+ cookieList.appendChild(cookieItem);
226
+ });
227
+
228
+ headerValue.appendChild(cookieList);
229
+ } else {
230
+ headerValue.textContent = value;
231
+ }
232
+
233
+ headerItem.appendChild(headerKey);
234
+ headerItem.appendChild(headerValue);
235
+ responseList.appendChild(headerItem);
236
+ });
237
+
238
+ responseSection.appendChild(responseList);
239
+ headersList.appendChild(responseSection);
240
+ }
241
+
242
+ // Create request headers section
243
+ if (requestHeaders && Object.keys(requestHeaders).length > 0) {
244
+ const requestSection = document.createElement('div');
245
+ requestSection.className = 'headers-section';
246
+
247
+ const requestTitle = document.createElement('h4');
248
+ requestTitle.textContent = `Request Headers (${Object.keys(requestHeaders).length})`;
249
+ requestTitle.className = 'headers-title';
250
+ requestSection.appendChild(requestTitle);
251
+
252
+ const requestList = document.createElement('div');
253
+ requestList.className = 'headers-grid';
254
+
255
+ // Sort headers alphabetically
256
+ const sortedRequestHeaders = Object.entries(requestHeaders).sort(([a], [b]) => a.toLowerCase().localeCompare(b.toLowerCase()));
257
+
258
+ sortedRequestHeaders.forEach(([key, value]) => {
259
+ const headerItem = document.createElement('div');
260
+ headerItem.className = 'header-item';
261
+
262
+ const headerKey = document.createElement('div');
263
+ headerKey.className = 'header-key';
264
+ headerKey.textContent = key;
265
+
266
+ const headerValue = document.createElement('div');
267
+ headerValue.className = 'header-value';
268
+
269
+ // Special formatting for cookies
270
+ if (key.toLowerCase() === 'cookie') {
271
+ const cookieList = document.createElement('div');
272
+ cookieList.className = 'cookie-list';
273
+
274
+ // Split cookies by semicolon and display each on a new line
275
+ const cookies = value.split(';').map(c => c.trim()).filter(c => c);
276
+ cookies.forEach(cookie => {
277
+ const cookieItem = document.createElement('div');
278
+ cookieItem.className = 'cookie-item';
279
+ cookieItem.textContent = cookie;
280
+ cookieList.appendChild(cookieItem);
281
+ });
282
+
283
+ headerValue.appendChild(cookieList);
284
+ } else {
285
+ headerValue.textContent = value;
286
+ }
287
+
288
+ headerItem.appendChild(headerKey);
289
+ headerItem.appendChild(headerValue);
290
+ requestList.appendChild(headerItem);
291
+ });
292
+
293
+ requestSection.appendChild(requestList);
294
+ headersList.appendChild(requestSection);
295
+ }
296
+
297
+ // Show message if no headers
298
+ if ((!responseHeaders || Object.keys(responseHeaders).length === 0) &&
299
+ (!requestHeaders || Object.keys(requestHeaders).length === 0)) {
300
+ const noHeadersMsg = document.createElement('div');
301
+ noHeadersMsg.className = 'no-headers-message';
302
+ noHeadersMsg.textContent = 'No headers available';
303
+ headersList.appendChild(noHeadersMsg);
304
+ }
305
+ },
306
+
307
+ formatSize: function(bytes) {
308
+ if (bytes === 0) return '0 B';
309
+
310
+ const k = 1024;
311
+ const sizes = ['B', 'KB', 'MB', 'GB'];
312
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
313
+
314
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
67
315
  }
68
316
  };
69
317
 
70
- // Keyboard navigation
318
+ // Initialize modal functionality when DOM is loaded
319
+ document.addEventListener('DOMContentLoaded', function() {
320
+ ModalManager.init();
321
+ });
322
+
323
+ // Global keyboard navigation
71
324
  document.addEventListener('keydown', function(e) {
72
325
  if (e.key === 'Escape') {
73
- ModalManager.closeTryOut();
74
- ModalManager.closeResponseModal();
326
+ // Only close if not already handled by modal's keyboard trap
327
+ const modal = document.getElementById('tryOutModal');
328
+ const responseModal = document.getElementById('responseModal');
329
+
330
+ if (modal && !modal.contains(document.activeElement)) {
331
+ ModalManager.closeTryOut();
332
+ }
333
+ if (responseModal && !responseModal.contains(document.activeElement)) {
334
+ ModalManager.closeResponseModal();
335
+ }
75
336
  }
76
337
  });
77
338
 
78
339
  // Export for global access
79
340
  window.ModalManager = ModalManager;
341
+
342
+ // Create TryOutSidebar alias for backward compatibility
343
+ window.TryOutSidebar = {
344
+ closeResponseModal: function() {
345
+ ModalManager.closeResponseModal();
346
+ },
347
+
348
+ addQueryParam: function(paramName) {
349
+ if (window.FormManager && window.FormManager.addQueryParam) {
350
+ return window.FormManager.addQueryParam(paramName);
351
+ }
352
+ },
353
+
354
+ removeKvItem: function(button) {
355
+ if (window.FormManager && window.FormManager.removeKvItem) {
356
+ return window.FormManager.removeKvItem(button);
357
+ }
358
+ }
359
+ };
@@ -0,0 +1,94 @@
1
+ // Query parameters extractor
2
+ document.addEventListener('DOMContentLoaded', function() {
3
+ const QueryParametersExtractor = {
4
+ init: function() {
5
+ // Extract parameters directly from HTML content
6
+ const parameters = this.extractParametersFromHTML();
7
+
8
+ // Make parameters available for suggestions
9
+ if (parameters) {
10
+ window.queryParametersData = parameters;
11
+
12
+ // Initialize suggestions if TryOutSuggestions is available
13
+ if (window.TryOutSuggestions) {
14
+ window.TryOutSuggestions.init();
15
+ }
16
+ }
17
+ },
18
+
19
+ extractParametersFromHTML: function() {
20
+ const data = {
21
+ filter_fields: [],
22
+ search_fields: [],
23
+ ordering_fields: [],
24
+ pagination_fields: [],
25
+ special_keys: []
26
+ };
27
+
28
+ // Extract filter fields
29
+ this.extractFieldsFromSection('filter-fields', data.filter_fields);
30
+
31
+ // Extract search fields
32
+ this.extractFieldsFromSection('search-fields', data.search_fields);
33
+
34
+ // Extract ordering fields
35
+ this.extractFieldsFromSection('ordering-fields', data.ordering_fields);
36
+
37
+ // Extract pagination fields
38
+ this.extractFieldsFromSection('pagination-fields', data.pagination_fields);
39
+
40
+ // Add special keys
41
+ this.addSpecialKeys(data);
42
+
43
+ return data;
44
+ },
45
+
46
+ extractFieldsFromSection: function(sectionId, targetArray) {
47
+ const heading = document.querySelector(`h3#${sectionId}`);
48
+ if (!heading) return;
49
+
50
+ // Find the next UL element after the heading
51
+ let currentElement = heading.nextElementSibling;
52
+ while (currentElement && currentElement.tagName !== 'UL') {
53
+ currentElement = currentElement.nextElementSibling;
54
+ }
55
+
56
+ if (!currentElement || currentElement.tagName !== 'UL') return;
57
+
58
+ // Extract field names from code elements
59
+ const codeElements = currentElement.querySelectorAll('code');
60
+ codeElements.forEach(code => {
61
+ const fieldName = code.textContent.trim();
62
+ if (fieldName && !targetArray.includes(fieldName)) {
63
+ targetArray.push(fieldName);
64
+ }
65
+ });
66
+ },
67
+
68
+ addSpecialKeys: function(data) {
69
+ // Add special keys for common query parameter types
70
+
71
+ // Add special keys for each parameter type
72
+ if (data) {
73
+ // Special keys for search fields
74
+ if (data.search_fields && data.search_fields.length > 0) {
75
+ if (!data.special_keys.includes('search')) {
76
+ data.special_keys.push('search');
77
+ }
78
+ }
79
+
80
+ // Special keys for ordering fields
81
+ if (data.ordering_fields && data.ordering_fields.length > 0) {
82
+ if (!data.special_keys.includes('ordering')) {
83
+ data.special_keys.push('ordering');
84
+ }
85
+ }
86
+ }
87
+
88
+ return data;
89
+ }
90
+ };
91
+
92
+ // Initialize extractor
93
+ QueryParametersExtractor.init();
94
+ });