djgentelella 0.3.18__py3-none-any.whl → 0.3.20__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.
Files changed (47) hide show
  1. djgentelella/__init__.py +1 -1
  2. djgentelella/blog/forms.py +3 -3
  3. djgentelella/fields/files.py +125 -0
  4. djgentelella/forms/decorators.py +3 -3
  5. djgentelella/forms/forms.py +153 -33
  6. djgentelella/forms/models.py +2 -2
  7. djgentelella/serializers/selects.py +32 -0
  8. djgentelella/settings.py +1 -1
  9. djgentelella/static/djgentelella.flags.vendors.min.css +1 -1
  10. djgentelella/static/djgentelella.readonly.vendors.min.js +1 -1
  11. djgentelella/static/djgentelella.vendors.header.min.js +1 -1
  12. djgentelella/static/djgentelella.vendors.min.js +3 -2
  13. djgentelella/static/gentelella/css/custom.css +42 -2
  14. djgentelella/static/gentelella/js/base/dateranges_gridslider.js +1 -2
  15. djgentelella/static/gentelella/js/base/fileupload.widget.js +175 -72
  16. djgentelella/static/gentelella/js/base.js +178 -75
  17. djgentelella/static/gentelella/js/datatables.js +20 -3
  18. djgentelella/static/gentelella/js/obj_api_management.js +150 -51
  19. djgentelella/static/gentelella/js/widgets.js +2 -1
  20. djgentelella/static/vendors/flags/1x1/cp.svg +2 -2
  21. djgentelella/static/vendors/flags/1x1/dg.svg +2 -2
  22. djgentelella/static/vendors/flags/1x1/es-ga.svg +2 -2
  23. djgentelella/static/vendors/flags/4x3/ac.svg +2 -2
  24. djgentelella/static/vendors/flags/4x3/ea.svg +2 -2
  25. djgentelella/static/vendors/flags/4x3/es-ct.svg +2 -2
  26. djgentelella/static/vendors/friconix/friconix.js +1 -1
  27. djgentelella/static/vendors/interact/interact.min.js +3 -2
  28. djgentelella/static/vendors/storymapjs/storymap.js +1 -1
  29. djgentelella/templates/forms/as_grid.html +39 -0
  30. djgentelella/templates/forms/as_horizontal.html +36 -0
  31. djgentelella/templates/forms/as_inline.html +38 -0
  32. djgentelella/templates/forms/as_plain.html +33 -0
  33. djgentelella/templates/gentelella/index.html +14 -14
  34. djgentelella/templates/gentelella/widgets/chunkedupload.html +9 -14
  35. djgentelella/templates/gentelella/widgets/file.html +4 -9
  36. djgentelella/tests/__init__.py +2 -1
  37. djgentelella/tests/fields/__init__.py +0 -0
  38. djgentelella/tests/fields/files.py +39 -0
  39. djgentelella/views/select2autocomplete.py +8 -2
  40. djgentelella/widgets/core.py +33 -0
  41. djgentelella/widgets/files.py +37 -8
  42. {djgentelella-0.3.18.dist-info → djgentelella-0.3.20.dist-info}/METADATA +30 -15
  43. {djgentelella-0.3.18.dist-info → djgentelella-0.3.20.dist-info}/RECORD +47 -39
  44. {djgentelella-0.3.18.dist-info → djgentelella-0.3.20.dist-info}/WHEEL +1 -1
  45. {djgentelella-0.3.18.dist-info → djgentelella-0.3.20.dist-info}/AUTHORS +0 -0
  46. {djgentelella-0.3.18.dist-info → djgentelella-0.3.20.dist-info}/LICENSE.txt +0 -0
  47. {djgentelella-0.3.18.dist-info → djgentelella-0.3.20.dist-info}/top_level.txt +0 -0
@@ -86,11 +86,21 @@ function addSearchInputsAndFooterDataTable(dataTable, tableId, columns) {
86
86
  $(this).html(select);
87
87
  }else if(columnType === 'select2'){
88
88
  var s2url = dataTable.settings()[0].aoColumns[i].url;
89
- var select = '<select class="form-control form-control-sm"><option value="">--</option>';
89
+ let multiple = '';
90
+ if ('multiple' in dataTable.settings()[0].aoColumns[i]){
91
+ if(dataTable.settings()[0].aoColumns[i].multiple) multiple='multiple=True';
92
+ }
93
+ var select = '<select class="tableselect form-control form-control-sm" '+multiple+'><option value="">--</option>';
90
94
  select += '</select>';
91
95
  $(this).html(select);
92
96
  let s2instance = $(this).find('select');
93
97
  let s2context={
98
+ allowClear: true,
99
+ placeholder: {
100
+ id: "none",
101
+ text:"------",
102
+ selected:'selected'
103
+ },
94
104
  ajax: { url: s2url, dataType: 'json'}
95
105
  }
96
106
  extract_select2_context(s2context, s2instance);
@@ -102,8 +112,14 @@ function addSearchInputsAndFooterDataTable(dataTable, tableId, columns) {
102
112
  }
103
113
 
104
114
  $('input, select', this).on('keyup change', function () {
105
- if (currentColumn.search() !== this.value) {
106
- currentColumn.search(this.value).draw();
115
+ let current_value=this.value;
116
+ if('multiple' in this && this.multiple){
117
+ let values=[];
118
+ $(this).find('option:selected').each(function(i,e){ values.push(e.value)});
119
+ current_value=values.toString();
120
+ }
121
+ if (currentColumn.search() !== current_value) {
122
+ currentColumn.search(current_value).draw();
107
123
  }
108
124
  });
109
125
  }
@@ -120,6 +136,7 @@ function addSearchInputsAndFooterDataTable(dataTable, tableId, columns) {
120
136
  function clearDataTableFilters(dataTable, tableId){
121
137
  dataTable.search('').columns().search('').draw();
122
138
  $(tableId).find('input, select').val('');
139
+ $(tableId).find('.tableselect').val(null).trigger('change');
123
140
  }
124
141
  function yesnoprint(data, type, row, meta){ return data ? "<i class=\"fa fa-check-circle\"></i> "+gettext("Yes") : "<i class=\"fa fa-times-circle\"></i>"+gettext("No"); };
125
142
  function emptyprint(data, type, row, meta){ return data ? data : "--"; };
@@ -1,39 +1,76 @@
1
- function convertFormToJSON(form, prefix="") {
2
- const re = new RegExp("^"+prefix);
3
- var selectmultipleitems = [];
4
- form.find("select").each(function(i,e){
5
- if($(e).prop('multiple')){
6
- selectmultipleitems.push(e.name.replace(re, ""));
7
- }
1
+ function convertFileToBase64(file) {
2
+ return new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+
5
+ reader.onload = () => {
6
+ const base64String = reader.result.split(',')[1];
7
+ resolve(base64String);
8
+ };
9
+
10
+ reader.onerror = (error) => {
11
+ reject(error);
12
+ };
13
+
14
+ reader.readAsDataURL(file);
8
15
  });
16
+ }
9
17
 
10
- return form
11
- .serializeArray()
12
- .reduce(function (json, { name, value }) {
13
- let clean_name = name.replace(re, "");
14
- if(json.hasOwnProperty(clean_name)){
15
- if(Array.isArray(json[clean_name])){
16
- json[clean_name].push(value);
17
- }else{
18
- let oldvalue = json[clean_name];
19
- json[clean_name]=[];
20
- json[clean_name].push(oldvalue);
21
- }
22
- }else{
23
- if(selectmultipleitems.indexOf(clean_name) !== -1){
24
- json[clean_name] = [value];
25
- }else{
26
- json[clean_name] = value;
27
- }
18
+ async function obtainFormAsJSON(form, prefix = '', extras={}) {
19
+ const fields = form.elements;
20
+ const formData = {};
21
+ // typeof variable === 'function'
22
+ for( let key in extras){
23
+ if(typeof extras[key] === 'function'){
24
+ formData[key]=extras[key](form, key, prefix);
25
+ }else{
26
+ formData[key]=extras[key];
27
+ }
28
+ }
29
+
30
+ for (let i = 0; i < fields.length; i++) {
31
+ const field = fields[i];
32
+
33
+ if (field.type !== 'submit' && field.type !== 'button') {
34
+ const fieldName = field.name.replace(prefix, '');
35
+ if(field.type === 'textarea'){
36
+ formData[fieldName] = $(field).val();
37
+ }else if(field.type === 'checkbox'){
38
+ formData[fieldName] = field.checked;
39
+ }else if (field.type === 'radio') {
40
+ if(field.checked){
41
+ formData[fieldName] = $(field).val();
42
+ }
43
+ }else if (field.type === 'file') {
44
+ const files = Array.from(field.files);
45
+ const filesBase64 = [];
46
+
47
+ for (let j = 0; j < files.length; j++) {
48
+ const file = files[j];
49
+ try {
50
+ const base64String = await convertFileToBase64(file);
51
+ filesBase64.push({ name: file.name, value: base64String });
52
+ } catch (error) {
53
+ console.error('Error converting file:', error);
54
+ }
55
+ }
56
+
57
+ formData[fieldName] = filesBase64;
58
+ } else if (field.multiple) {
59
+ const selectedOptions = Array.from(field.selectedOptions);
60
+ const selectedValues = selectedOptions.map((option) => option.value);
61
+ formData[fieldName] = selectedValues;
62
+ } else {
63
+ formData[fieldName] = field.value;
28
64
  }
29
- return json;
30
- }, {});
65
+ }
66
+ }
67
+
68
+ return JSON.stringify(formData);
31
69
  }
32
70
 
33
71
  function convertToStringJson(form, prefix="", extras={}){
34
- var formjson =convertFormToJSON(form, prefix=prefix);
35
- formjson=Object.assign({}, formjson, extras)
36
- return JSON.stringify(formjson);
72
+ result=obtainFormAsJSON(form[0], prefix=prefix, extras={});
73
+ return result;
37
74
  }
38
75
 
39
76
  function load_errors(error_list, obj){
@@ -85,11 +122,19 @@ function clear_action_form(form){
85
122
  $(this).trigger("click").prop("checked", false);
86
123
  }
87
124
  });
88
-
125
+ $(form).find('[data-widget="TaggingInput"],[data-widget="EmailTaggingInput"]').each(function(i, e) {
126
+ var tg=$(e).data().tagify;
127
+ tg.removeAllTags();
128
+ });
129
+ $(form).find('[data-widget="FileChunkedUpload"],[data-widget="FileInput"]').each(function(i, e) {
130
+ var tg=$(e).data().fileUploadWidget;
131
+ tg.resetEmpty();
132
+ });
89
133
  $(form).trigger('reset');
90
134
  $(form).find("select option:selected").prop("selected", false);
91
135
  $(form).find("select").val(null).trigger('change');
92
136
  $(form).find("ul.form_errors").remove();
137
+ $(form).find(".file-link").remove();
93
138
  }
94
139
 
95
140
  var gt_form_modals = {}
@@ -148,19 +193,21 @@ function GTBaseFormModal(modal_id, datatable_element, form_config) {
148
193
  var myModalEl = this.instance[0];
149
194
  myModalEl.addEventListener('hidden.bs.modal', this.hide_modalevent(this))
150
195
  this.instance.find(this.btn_class).on('click', this.add_btn_form(this));
151
-
196
+ $(this.form).on('submit', (e)=>{e.preventDefault();})
152
197
  },
153
198
  "add_btn_form": function(instance){
154
199
  return function(event){
155
- fetch(instance.url, {
200
+ convertToStringJson(instance.form, prefix=instance.prefix,
201
+ extras=instance.config.events.form_submit(instance)).then((result) => {
202
+ fetch(instance.url, {
156
203
  method: instance.type,
157
- body: convertToStringJson(instance.form, prefix=instance.prefix,
158
- extras=instance.config.events.form_submit(instance)),
204
+ body: result,
159
205
  headers: {'X-CSRFToken': getCookie('csrftoken'), 'Content-Type': 'application/json'}
160
206
  }
161
207
  ).then(response_manage_type_data(instance, instance.error, instance.error_text))
162
208
  .then(instance.fn_success(instance))
163
209
  .catch(error => instance.handle_error(instance, error));
210
+ });
164
211
  }
165
212
  },
166
213
  "success": function(instance, data){
@@ -223,7 +270,7 @@ function GTBaseFormModal(modal_id, datatable_element, form_config) {
223
270
  });
224
271
  // do select 2 items
225
272
  $.each(select2Items, function(i, e){
226
- var display_name_key = 'display_name';
273
+ var display_name_key = 'text';
227
274
  if(instance.relation_render.hasOwnProperty(e)){
228
275
  display_name_key=instance.relation_render[e];
229
276
  }
@@ -231,6 +278,7 @@ function GTBaseFormModal(modal_id, datatable_element, form_config) {
231
278
  if(datainstance[e]){
232
279
  if(Array.isArray(datainstance[e])){
233
280
  for(var x=0; x<datainstance[e].length; x++){
281
+ $('#id_'+instance.prefix+e+' option[value="'+datainstance[e][x]['id']+'"]').remove();
234
282
  var newOption = new Option(datainstance[e][x][display_name_key], datainstance[e][x]['id'], true, true);
235
283
  $('#id_'+instance.prefix+e).append(newOption);
236
284
  }
@@ -248,22 +296,67 @@ function GTBaseFormModal(modal_id, datatable_element, form_config) {
248
296
  },
249
297
  "updateInstanceForm": function (name, value){
250
298
  var item = this.form.find('input[name="'+name+'"], textarea[name="'+name+'"]');
251
-
299
+ var parent=this;
252
300
  item.each(function(i, inputfield){
253
301
  let done=false;
254
302
  inputfield=$(inputfield);
255
- if(inputfield.attr('type') === "checkbox" ){
256
- inputfield.prop( "checked", value);
303
+
304
+ if(inputfield.attr('class') === "chunkedvalue"){
305
+ if(value){
306
+ var chunked=parent.form.find('input[name="'+name+'_widget"]').data('fileUploadWidget');
307
+ chunked.addRemote(value);
308
+ }
309
+ done=true;
310
+ } else if(inputfield.attr('type') === 'file'){
311
+ if(value){
312
+ var newlink = document.createElement('a');
313
+ newlink.href = value.url;
314
+ newlink.textContent = value.name;
315
+ newlink.target = "_blank";
316
+ newlink.classList.add("link-primary");
317
+ newlink.classList.add("file-link");
318
+ newlink.classList.add("d-block");
319
+ inputfield.before(newlink)
320
+ }
321
+ done=true;
322
+ } else if(inputfield.attr('type') === "checkbox" ){
323
+ if (inputfield.data().widget === "YesNoInput"){
324
+ inputfield.prop( "checked", !value);
325
+ inputfield.trigger("click");
326
+ done=true;
327
+ }else{
328
+ inputfield.prop( "checked", value);
329
+ }
257
330
  done=true;
258
331
  } else if(inputfield.attr('type') === "radio"){
259
- var sel = inputfield.filter(function() { return this.value == value });
260
- sel.prop( "checked", true);
332
+ var is_icheck = inputfield.closest('.gtradio').length > 0;
333
+ var sel = inputfield.filter(function() { return this.value === value.toString() });
334
+ if(sel.length>0){
335
+ sel.prop( "checked", true);
336
+ if(is_icheck){
337
+ sel.iCheck('update');
338
+ sel.iCheck('check');
339
+ }
340
+
341
+ }else{
342
+ inputfield.prop( "checked", false);
343
+ if(is_icheck){
344
+ inputfield.iCheck('update');
345
+ inputfield.iCheck('uncheck');
346
+ }
347
+ }
261
348
  done=true;
262
349
  }
263
- if (inputfield.data().widget === "EditorTinymce"){
350
+ if (inputfield.data().widget === "EditorTinymce" || inputfield.data().widget === "TextareaWysiwyg"){
264
351
  tinymce.get(inputfield.attr('id')).setContent(value);
265
352
  done=true;
266
353
  }
354
+ if (inputfield.data().widget === "TaggingInput" || inputfield.data().widget === "EmailTaggingInput"){
355
+ var tagifyelement=inputfield.data().tagify;
356
+ tagifyelement.removeAllTags();
357
+ tagifyelement.loadOriginalValues(value);
358
+ done=true;
359
+ }
267
360
  if(!done) { inputfield.val(value); }
268
361
  });
269
362
  }
@@ -583,19 +676,25 @@ function ObjectCRUD(uniqueid, objconfig={}){
583
676
  className: this.config.actions.className,
584
677
  orderable: false,
585
678
  render: function(data, type, full, meta){
586
- var edittext = '<div class="d-flex mt-1">';
679
+ var edittext = '<div class="d-flex mt-1">';
680
+ let do_action=true;
587
681
  for(var x=0; x<instance.object_actions.length; x++){
588
682
  let action = instance.object_actions[x];
589
683
  let display_in_column = true;
590
- if('in_action_column' in action ){
591
- display_in_column=action.in_action_column;
684
+ do_action=true
685
+ if(action.name in data ){
686
+ do_action=data[action.name];
687
+ }
688
+ if(do_action){
689
+ if('in_action_column' in action ){
690
+ display_in_column=action.in_action_column;
691
+ }
692
+ if(display_in_column){
693
+ let params = "'"+instance.uniqueid+"', '"+action.name+"', "+meta.row;
694
+ edittext += '<i onclick="javascript:call_obj_crud_event('+params+');"';
695
+ edittext += ' class="'+instance.object_actions[x].i_class+'" ></i>';
696
+ }
592
697
  }
593
- if(display_in_column){
594
- let params = "'"+instance.uniqueid+"', '"+action.name+"', "+meta.row;
595
- edittext += '<i onclick="javascript:call_obj_crud_event('+params+');"';
596
- edittext += ' class="'+instance.object_actions[x].i_class+'" ></i>';
597
- }
598
-
599
698
  }
600
699
  edittext += '</div>';
601
700
  return edittext;
@@ -52,6 +52,7 @@ document.gtwidgets = {
52
52
  YesNoInput: function (instance) {
53
53
  instance.each(function (index, element) {
54
54
  switchery = new Switchery(element, { color: '#26B99A' });
55
+ instance.data('switchery', switchery);
55
56
  showHideRelatedFormFields($(element));
56
57
  });
57
58
  },
@@ -138,7 +139,7 @@ document.gtwidgets = {
138
139
  },
139
140
  EmailMaskInput: function (instance) {
140
141
  instance.inputmask({
141
- mask: "*{1,50}[.*{1,20}][.*{1,20}][.*{1,20}]@*{1,20}[.*{2,6}][.*{1,2}]",
142
+ regex: "[a-zA-Z0-9._%-]+@[a-zA-Z0-9-]+(\.[a-zA-Z]+)+",
142
143
  greedy: false,
143
144
  onBeforePaste: function (pastedValue, opts) {
144
145
  pastedValue = pastedValue.toLowerCase();
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head><title>404 Not Found</title></head>
3
- <body>
3
+ <body bgcolor="white">
4
4
  <center><h1>404 Not Found</h1></center>
5
- <hr><center>nginx</center>
5
+ <hr><center>nginx/1.10.3</center>
6
6
  </body>
7
7
  </html>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head><title>404 Not Found</title></head>
3
- <body>
3
+ <body bgcolor="white">
4
4
  <center><h1>404 Not Found</h1></center>
5
- <hr><center>nginx</center>
5
+ <hr><center>nginx/1.10.3</center>
6
6
  </body>
7
7
  </html>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head><title>404 Not Found</title></head>
3
- <body>
3
+ <body bgcolor="white">
4
4
  <center><h1>404 Not Found</h1></center>
5
- <hr><center>nginx</center>
5
+ <hr><center>nginx/1.10.3</center>
6
6
  </body>
7
7
  </html>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head><title>404 Not Found</title></head>
3
- <body>
3
+ <body bgcolor="white">
4
4
  <center><h1>404 Not Found</h1></center>
5
- <hr><center>nginx</center>
5
+ <hr><center>nginx/1.10.3</center>
6
6
  </body>
7
7
  </html>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head><title>404 Not Found</title></head>
3
- <body>
3
+ <body bgcolor="white">
4
4
  <center><h1>404 Not Found</h1></center>
5
- <hr><center>nginx</center>
5
+ <hr><center>nginx/1.10.3</center>
6
6
  </body>
7
7
  </html>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head><title>404 Not Found</title></head>
3
- <body>
3
+ <body bgcolor="white">
4
4
  <center><h1>404 Not Found</h1></center>
5
- <hr><center>nginx</center>
5
+ <hr><center>nginx/1.10.3</center>
6
6
  </body>
7
7
  </html>