drf-to-mkdoc 0.2.2__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 (47) hide show
  1. drf_to_mkdoc/conf/defaults.py +1 -0
  2. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/field-sections-loader.js +29 -0
  3. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/query-parameters-loader.js +16 -0
  4. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/field-extractor.js +200 -0
  5. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +465 -0
  6. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +50 -0
  7. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +359 -0
  8. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/query-parameters-extractor.js +94 -0
  9. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +327 -0
  10. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/response-modal.js +173 -0
  11. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +123 -0
  12. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +77 -0
  13. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +13 -5
  14. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +297 -25
  15. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/fab.css +204 -0
  16. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/response.css +323 -0
  17. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/variables.css +139 -0
  18. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/field-sections.css +136 -0
  19. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/buttons.css +71 -0
  20. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/fab.css +47 -0
  21. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +663 -0
  22. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/key-value.css +161 -0
  23. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/main.css +57 -0
  24. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +334 -0
  25. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +618 -0
  26. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +114 -0
  27. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +94 -0
  28. drf_to_mkdoc/templates/endpoints/detail/base.html +3 -1
  29. drf_to_mkdoc/templates/endpoints/detail/query_parameters.html +1 -8
  30. drf_to_mkdoc/templates/endpoints/detail/request_body.html +2 -0
  31. drf_to_mkdoc/templates/endpoints/detail/responses.html +4 -4
  32. drf_to_mkdoc/templates/try-out/fab.html +68 -0
  33. drf_to_mkdoc/templates/try-out/form.html +260 -0
  34. drf_to_mkdoc/templates/try-out/main.html +4 -0
  35. drf_to_mkdoc/templates/try-out/modal.html +82 -0
  36. drf_to_mkdoc/templates/try-out/response-modal.html +149 -0
  37. drf_to_mkdoc/templatetags/custom_filters.py +33 -1
  38. drf_to_mkdoc/utils/commons/schema_utils.py +5 -14
  39. drf_to_mkdoc/utils/endpoint_detail_generator.py +141 -21
  40. drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +0 -15
  41. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.4.dist-info}/METADATA +68 -9
  42. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.4.dist-info}/RECORD +45 -18
  43. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out-sidebar.js +0 -879
  44. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out-sidebar.css +0 -728
  45. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.4.dist-info}/WHEEL +0 -0
  46. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.4.dist-info}/licenses/LICENSE +0 -0
  47. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,465 @@
1
+ // Form management functionality
2
+ const FormManager = {
3
+ // Initialize form functionality
4
+ init: function() {
5
+ this.setupEventListeners();
6
+ this.setupFormValidation();
7
+ this.initializeRequestBody();
8
+ },
9
+
10
+ initializeRequestBody: function() {
11
+ const requestExample = document.querySelector('.request-example');
12
+ const requestBody = document.getElementById('requestBody');
13
+ let example = null;
14
+ if (requestExample && requestBody) {
15
+ try {
16
+ example = requestExample.getAttribute('data-example');
17
+ if (example) {
18
+ // Remove markdown code block syntax if present
19
+ example = example.replace(/^```json\n/, '').replace(/```$/, '');
20
+ // Remove any leading/trailing whitespace
21
+ example = example.trim();
22
+
23
+ // Try to parse and format the JSON
24
+ const formattedJson = JSON.stringify(JSON.parse(example), null, 2);
25
+ requestBody.value = formattedJson;
26
+
27
+ // Validate the JSON after setting it
28
+ if (window.RequestExecutor) {
29
+ window.RequestExecutor.validateJson();
30
+ }
31
+ }
32
+ } catch (e) {
33
+ console.warn('Failed to parse request example:', e);
34
+ // If parsing fails, try to at least show the raw example
35
+ if (example) {
36
+ requestBody.value = example;
37
+ }
38
+ }
39
+ }
40
+ },
41
+
42
+ setupEventListeners: function() {
43
+ // Form reset functionality
44
+ const resetButtons = document.querySelectorAll('[data-action="reset"], .secondary-btn, .secondary-button');
45
+ resetButtons.forEach(btn => {
46
+ if (btn.textContent.toLowerCase().includes('reset')) {
47
+ btn.addEventListener('click', (e) => {
48
+ e.preventDefault();
49
+ this.resetForm();
50
+ });
51
+ }
52
+ });
53
+
54
+ // Parameter filtering
55
+ const searchInput = document.querySelector('.parameter-search');
56
+ if (searchInput) {
57
+ searchInput.addEventListener('input', this.debounce((e) => {
58
+ this.filterParameters(e.target.value);
59
+ }, 300));
60
+ }
61
+
62
+ // Copy URL functionality
63
+ const copyBtn = document.querySelector('.copy-btn');
64
+ if (copyBtn) {
65
+ copyBtn.addEventListener('click', () => this.copyToClipboard());
66
+ }
67
+
68
+ // JSON validation on input
69
+ const editor = document.getElementById('requestBody');
70
+ if (editor) {
71
+ editor.addEventListener('input', this.debounce(() => {
72
+ if (window.RequestExecutor) {
73
+ window.RequestExecutor.validateJson();
74
+ }
75
+ }, 500));
76
+ }
77
+
78
+ // Format and validate buttons
79
+ const formatBtn = document.querySelector('.format-btn');
80
+ const validateBtn = document.querySelector('.validate-btn');
81
+
82
+ if (formatBtn) {
83
+ formatBtn.addEventListener('click', () => {
84
+ if (window.RequestExecutor) {
85
+ window.RequestExecutor.formatJson();
86
+ }
87
+ });
88
+ }
89
+ if (validateBtn) {
90
+ validateBtn.addEventListener('click', () => {
91
+ if (window.RequestExecutor) {
92
+ window.RequestExecutor.validateJson();
93
+ }
94
+ });
95
+ }
96
+ },
97
+
98
+ setupFormValidation: function() {
99
+ // Add validation to required inputs
100
+ const requiredInputs = document.querySelectorAll('input[required]');
101
+ requiredInputs.forEach(input => {
102
+ input.addEventListener('blur', () => {
103
+ if (window.RequestExecutor) {
104
+ window.RequestExecutor.validateInput(input);
105
+ }
106
+ });
107
+ input.addEventListener('input', () => this.clearValidationError(input));
108
+ });
109
+ },
110
+
111
+ clearValidationError: function(input) {
112
+ input.classList.remove('error');
113
+ const validationMessage = input.parentElement.querySelector('.validation-message');
114
+ if (validationMessage) {
115
+ validationMessage.textContent = '';
116
+ validationMessage.style.display = 'none';
117
+ }
118
+ },
119
+
120
+ // Debounce utility function
121
+ debounce: function(func, wait) {
122
+ let timeout;
123
+ return function executedFunction(...args) {
124
+ const later = () => {
125
+ clearTimeout(timeout);
126
+ func(...args);
127
+ };
128
+ clearTimeout(timeout);
129
+ timeout = setTimeout(later, wait);
130
+ };
131
+ },
132
+ addQueryParam: function(paramName) {
133
+ const container = document.querySelector('#queryParams .parameter-list');
134
+ if (!container) return;
135
+
136
+ const paramItem = this.createParameterItem();
137
+ container.appendChild(paramItem);
138
+
139
+ // If a parameter name was provided, set it
140
+ const nameInput = paramItem.querySelector('.name-input');
141
+ if (nameInput && paramName) {
142
+ nameInput.value = paramName;
143
+
144
+ // Focus on the value input instead
145
+ const valueInput = paramItem.querySelector('.value-input');
146
+ if (valueInput) {
147
+ valueInput.focus();
148
+ }
149
+ } else if (nameInput) {
150
+ // Otherwise focus on the name input
151
+ nameInput.focus();
152
+ }
153
+
154
+ // Setup suggestions for new input if available
155
+ if (window.TryOutSuggestions) {
156
+ setTimeout(() => {
157
+ window.TryOutSuggestions.setupExistingInputs();
158
+ }, 10);
159
+ }
160
+
161
+ return paramItem;
162
+ },
163
+
164
+ createParameterItem: function() {
165
+ const paramItem = document.createElement('div');
166
+ paramItem.className = 'parameter-item';
167
+
168
+ paramItem.innerHTML = `
169
+ <div class="parameter-inputs">
170
+ <input type="text"
171
+ class="modern-input name-input"
172
+ placeholder="Parameter name"
173
+ list="paramSuggestions">
174
+ <input type="text"
175
+ class="modern-input value-input"
176
+ placeholder="Value">
177
+ <button class="remove-btn"
178
+ onclick="FormManager.removeKvItem(this)"
179
+ aria-label="Remove parameter">
180
+ <span class="icon">✕</span>
181
+ </button>
182
+ </div>
183
+ `;
184
+
185
+ return paramItem;
186
+ },
187
+
188
+ addHeader: function() {
189
+ const container = document.querySelector('#requestHeaders .header-list');
190
+ if (!container) return;
191
+
192
+ const headerItem = this.createHeaderItem();
193
+ container.appendChild(headerItem);
194
+
195
+ // Focus on the first input
196
+ const firstInput = headerItem.querySelector('.name-input');
197
+ if (firstInput) {
198
+ firstInput.focus();
199
+ }
200
+ },
201
+
202
+ createHeaderItem: function() {
203
+ const headerItem = document.createElement('div');
204
+ headerItem.className = 'header-item';
205
+
206
+ headerItem.innerHTML = `
207
+ <div class="header-inputs">
208
+ <input type="text"
209
+ class="modern-input name-input"
210
+ placeholder="Header name"
211
+ list="headerSuggestions">
212
+ <input type="text"
213
+ class="modern-input value-input"
214
+ placeholder="Header value">
215
+ <button class="remove-btn"
216
+ aria-label="Remove header">
217
+ <span class="icon">✕</span>
218
+ </button>
219
+ </div>
220
+ `;
221
+
222
+ // Attach the removal handler programmatically
223
+ const removeBtn = headerItem.querySelector('.remove-btn');
224
+ removeBtn.addEventListener('click', (e) => FormManager.removeKvItem(e.currentTarget));
225
+
226
+ return headerItem;
227
+ },
228
+
229
+ createKvItem: function(namePlaceholder, valuePlaceholder, removable = true) {
230
+ const kvItem = document.createElement('div');
231
+ kvItem.className = 'kv-item';
232
+
233
+ const nameInput = document.createElement('input');
234
+ nameInput.type = 'text';
235
+ nameInput.placeholder = namePlaceholder;
236
+
237
+ const valueInput = document.createElement('input');
238
+ valueInput.type = 'text';
239
+ valueInput.placeholder = valuePlaceholder;
240
+
241
+ kvItem.appendChild(nameInput);
242
+ kvItem.appendChild(valueInput);
243
+
244
+ if (removable) {
245
+ const removeBtn = document.createElement('button');
246
+ removeBtn.className = 'remove-btn';
247
+ removeBtn.textContent = '✕';
248
+ removeBtn.addEventListener('click', () => this.removeKvItem(removeBtn));
249
+ kvItem.appendChild(removeBtn);
250
+ }
251
+
252
+ return kvItem;
253
+ },
254
+
255
+ removeKvItem: function(button) {
256
+ if (button && button.closest('.parameter-item, .header-item')) {
257
+ button.closest('.parameter-item, .header-item').remove();
258
+ }
259
+ },
260
+
261
+ validateRequiredParams: function() {
262
+ const requiredInputs = document.querySelectorAll('#pathParams input[required]');
263
+ const errors = [];
264
+
265
+ requiredInputs.forEach(input => {
266
+ const errorElement = input.parentElement.querySelector('.error-message');
267
+
268
+ if (!input.value.trim()) {
269
+ const paramName = input.getAttribute('data-param');
270
+ errors.push(paramName);
271
+ input.classList.add('error');
272
+
273
+ if (errorElement) {
274
+ errorElement.textContent = `${paramName} is required`;
275
+ errorElement.classList.add('show');
276
+ }
277
+
278
+ // Remove error on input
279
+ input.addEventListener('input', () => {
280
+ input.classList.remove('error');
281
+ if (errorElement) {
282
+ errorElement.classList.remove('show');
283
+ }
284
+ }, { once: true });
285
+ } else {
286
+ input.classList.remove('error');
287
+ if (errorElement) {
288
+ errorElement.classList.remove('show');
289
+ }
290
+ }
291
+ });
292
+
293
+ return errors;
294
+ },
295
+
296
+ addSuggestion: function(input, suggestion) {
297
+ input.value = suggestion;
298
+ input.focus();
299
+ },
300
+
301
+ buildRequestUrl: function() {
302
+ const baseUrl = document.getElementById('baseUrl').value.trim();
303
+ const pathDisplay = document.querySelector('.path-display').textContent.trim();
304
+
305
+ let url = baseUrl + pathDisplay;
306
+
307
+ // Replace path parameters
308
+ const pathParams = document.querySelectorAll('#pathParams input');
309
+ pathParams.forEach(input => {
310
+ const paramName = input.getAttribute('data-param');
311
+ const paramValue = input.value.trim();
312
+ if (paramName && paramValue) {
313
+ url = url.replace(`{${paramName}}`, encodeURIComponent(paramValue));
314
+ }
315
+ });
316
+
317
+ // Add query parameters
318
+ const queryParams = [];
319
+ const queryInputs = document.querySelectorAll('#queryParams .kv-item');
320
+ queryInputs.forEach(item => {
321
+ const inputs = item.querySelectorAll('input');
322
+ if (inputs.length === 2) {
323
+ const name = inputs[0].value.trim();
324
+ const value = inputs[1].value.trim();
325
+ if (name && value) {
326
+ queryParams.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);
327
+ }
328
+ }
329
+ });
330
+
331
+ if (queryParams.length > 0) {
332
+ url += '?' + queryParams.join('&');
333
+ }
334
+
335
+ return url;
336
+ },
337
+
338
+ getRequestHeaders: function() {
339
+ const headers = {};
340
+ const headerInputs = document.querySelectorAll('#requestHeaders .kv-item');
341
+
342
+ headerInputs.forEach(item => {
343
+ const inputs = item.querySelectorAll('input');
344
+ if (inputs.length === 2) {
345
+ const name = inputs[0].value.trim();
346
+ const value = inputs[1].value.trim();
347
+ if (name && value) {
348
+ headers[name] = value;
349
+ }
350
+ }
351
+ });
352
+
353
+ return headers;
354
+ },
355
+
356
+ getRequestBody: function() {
357
+ const bodyTextarea = document.getElementById('requestBody');
358
+ if (bodyTextarea && bodyTextarea.value.trim()) {
359
+ try {
360
+ return JSON.parse(bodyTextarea.value);
361
+ } catch (e) {
362
+ return bodyTextarea.value;
363
+ }
364
+ }
365
+ return null;
366
+ },
367
+
368
+ // Form reset functionality
369
+ resetForm: function() {
370
+ const form = document.querySelector('.try-out-form');
371
+ if (form) {
372
+ // Reset text inputs except base URL
373
+ form.querySelectorAll('input[type="text"], textarea').forEach(input => {
374
+ if (!input.id || input.id !== 'baseUrl') {
375
+ input.value = '';
376
+ }
377
+ });
378
+
379
+ // Reset validation states
380
+ form.querySelectorAll('.error').forEach(el => {
381
+ el.classList.remove('error');
382
+ });
383
+
384
+ form.querySelectorAll('.validation-message').forEach(msg => {
385
+ msg.textContent = '';
386
+ msg.style.display = 'none';
387
+ });
388
+
389
+ // Reset JSON editor
390
+ const editor = document.getElementById('requestBody');
391
+ if (editor) {
392
+ editor.value = '';
393
+ }
394
+
395
+ // Reset validation status
396
+ const status = document.querySelector('.validation-status');
397
+ if (status) {
398
+ status.textContent = '';
399
+ status.className = 'validation-status';
400
+ }
401
+
402
+ // Reset to first tab
403
+ const firstTab = document.querySelector('.tab');
404
+ if (firstTab && window.TabManager) {
405
+ window.TabManager.switchTab(firstTab);
406
+ }
407
+
408
+ // Clear any error messages
409
+ if (window.RequestExecutor) {
410
+ window.RequestExecutor.clearValidationErrors();
411
+ }
412
+ }
413
+ },
414
+
415
+ // Parameter filtering
416
+ filterParameters: function(query) {
417
+ const items = document.querySelectorAll('.parameter-item');
418
+ query = query.toLowerCase();
419
+
420
+ items.forEach(item => {
421
+ const nameInput = item.querySelector('.name-input');
422
+ const name = nameInput?.value.toLowerCase() || '';
423
+
424
+ if (name.includes(query) || query === '') {
425
+ item.style.display = '';
426
+ } else {
427
+ item.style.display = 'none';
428
+ }
429
+ });
430
+ },
431
+
432
+ // Copy URL to clipboard
433
+ copyToClipboard: function() {
434
+ const baseUrl = document.getElementById('baseUrl')?.value || '';
435
+ const pathDisplay = document.querySelector('.path-display')?.textContent || '';
436
+ const url = baseUrl + pathDisplay;
437
+
438
+ navigator.clipboard.writeText(url).then(() => {
439
+ // Show copy success in the URL preview
440
+ const copyBtn = document.querySelector('.copy-btn');
441
+ if (copyBtn) {
442
+ const originalText = copyBtn.innerHTML;
443
+ copyBtn.innerHTML = '<span class="icon">✓</span>';
444
+ setTimeout(() => {
445
+ copyBtn.innerHTML = originalText;
446
+ }, 2000);
447
+ }
448
+ }).catch(() => {
449
+ console.error('Failed to copy URL');
450
+ });
451
+ }
452
+ };
453
+
454
+ // Initialize when DOM is loaded
455
+ document.addEventListener('DOMContentLoaded', function() {
456
+ FormManager.init();
457
+ });
458
+
459
+ // Global functions for backward compatibility
460
+ window.resetForm = () => FormManager.resetForm();
461
+ window.filterParameters = (query) => FormManager.filterParameters(query);
462
+ window.copyToClipboard = () => FormManager.copyToClipboard();
463
+
464
+ // Export for global access
465
+ window.FormManager = FormManager;
@@ -0,0 +1,50 @@
1
+ // Main try-out functionality - combines all components
2
+ document.addEventListener('DOMContentLoaded', function() {
3
+ // Initialize all components
4
+ if (window.TabManager) {
5
+ TabManager.init();
6
+ }
7
+
8
+ if (window.FormManager) {
9
+ FormManager.init();
10
+ }
11
+
12
+ if (window.TryOutSuggestions) {
13
+ TryOutSuggestions.init();
14
+ }
15
+
16
+ // Initialize modal functionality
17
+ if (window.ModalManager) {
18
+ // Modal is already initialized through its own file
19
+ console.log('Try-out modal functionality loaded');
20
+ }
21
+
22
+ // Initialize request executor
23
+ if (window.RequestExecutor) {
24
+ console.log('Try-out request executor loaded');
25
+ }
26
+
27
+ console.log('Try-out functionality fully initialized');
28
+ });
29
+
30
+ // Legacy compatibility - maintain old interface
31
+ window.TryOutSidebar = {
32
+ openTryOut: () => window.ModalManager?.openTryOut(),
33
+ closeTryOut: () => window.ModalManager?.closeTryOut(),
34
+ closeResponseModal: () => window.ModalManager?.closeResponseModal(),
35
+ showResponseModal: (status, responseText, responseTime) => window.ModalManager?.showResponseModal(status, responseText, responseTime),
36
+ addQueryParam: () => window.FormManager?.addQueryParam(),
37
+ addHeader: () => window.FormManager?.addHeader(),
38
+ removeKvItem: (button) => window.FormManager?.removeKvItem(button),
39
+ validateRequiredParams: () => window.FormManager?.validateRequiredParams()
40
+ };
41
+
42
+ // Additional global functions for HTML onclick handlers
43
+ window.TryOutForm = {
44
+ resetForm: () => window.FormManager?.resetForm(),
45
+ sendRequest: () => window.RequestExecutor?.executeRequest()
46
+ };
47
+
48
+ // Global proxy functions for template onclick handlers
49
+ window.resetForm = () => window.TryOutForm?.resetForm?.();
50
+ window.executeRequest = () => window.TryOutForm?.sendRequest?.();