djgentelella 0.3.24__py3-none-any.whl → 0.3.26__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 (33) hide show
  1. djgentelella/__init__.py +1 -1
  2. djgentelella/locale/es/LC_MESSAGES/django.mo +0 -0
  3. djgentelella/locale/es/LC_MESSAGES/django.po +14 -2
  4. djgentelella/management/commands/createbasejs.py +3 -1
  5. djgentelella/management/commands/loaddevstatic.py +9 -0
  6. djgentelella/objectmanagement.py +2 -2
  7. djgentelella/serializers/paginators.py +15 -0
  8. djgentelella/static/djgentelella.vendors.min.css +19 -0
  9. djgentelella/static/djgentelella.vendors.min.js +6 -0
  10. djgentelella/static/gentelella/js/base/api_list.js +135 -0
  11. djgentelella/static/gentelella/js/base/form.common.js +255 -0
  12. djgentelella/static/gentelella/js/base/formset.js +102 -83
  13. djgentelella/static/gentelella/js/base.js +494 -81
  14. djgentelella/static/gentelella/js/obj_api_management.js +5 -147
  15. djgentelella/static/gentelella/js/widgets.js +3 -0
  16. djgentelella/static/vendors/htmlx/htmx.min.js +1 -0
  17. djgentelella/static/vendors/pdfjs/interact.min.js +4 -0
  18. djgentelella/static/vendors/pdfjs/pdf.min.mjs +21 -0
  19. djgentelella/static/vendors/pdfjs/pdf.worker.min.mjs +21 -0
  20. djgentelella/static/vendors/pdfjs/pdf_viewer.min.css +19 -0
  21. djgentelella/templates/gentelella/base.html +1 -1
  22. djgentelella/templates/gentelella/blocks/listcard_template.html +60 -0
  23. djgentelella/templates/gentelella/blocks/squirrelly_pagination.html +34 -0
  24. djgentelella/templates/gentelella/plain.html +1 -1
  25. djgentelella/templates/gentelella/statics/javascript.html +4 -0
  26. djgentelella/templates/gentelella/statics/stylesheets.html +1 -2
  27. djgentelella/views/listAreaViewset.py +74 -0
  28. {djgentelella-0.3.24.dist-info → djgentelella-0.3.26.dist-info}/METADATA +9 -2
  29. {djgentelella-0.3.24.dist-info → djgentelella-0.3.26.dist-info}/RECORD +33 -22
  30. {djgentelella-0.3.24.dist-info → djgentelella-0.3.26.dist-info}/AUTHORS +0 -0
  31. {djgentelella-0.3.24.dist-info → djgentelella-0.3.26.dist-info}/LICENSE.txt +0 -0
  32. {djgentelella-0.3.24.dist-info → djgentelella-0.3.26.dist-info}/WHEEL +0 -0
  33. {djgentelella-0.3.24.dist-info → djgentelella-0.3.26.dist-info}/top_level.txt +0 -0
@@ -699,24 +699,283 @@ $.fn.select2related = function(action, relatedobjs=[]) {
699
699
 
700
700
  })(jQuery)
701
701
 
702
- function gtforms(index,manager, formList, extra=true) {
702
+ function convertFileToBase64(file) {
703
+ return new Promise((resolve, reject) => {
704
+ const reader = new FileReader();
705
+
706
+ reader.onload = () => {
707
+ const base64String = reader.result.split(',')[1];
708
+ resolve(base64String);
709
+ };
710
+
711
+ reader.onerror = (error) => {
712
+ reject(error);
713
+ };
714
+
715
+ reader.readAsDataURL(file);
716
+ });
717
+ }
718
+
719
+ async function obtainFormAsJSON(form, prefix = '', extras = {}, format = true) {
720
+ const fields = form.elements;
721
+ const formData = {};
722
+ // typeof variable === 'function'
723
+ for (let key in extras) {
724
+ if (typeof extras[key] === 'function') {
725
+ formData[key] = extras[key](form, key, prefix);
726
+ } else {
727
+ formData[key] = extras[key];
728
+ }
729
+ }
730
+
731
+ for (let i = 0; i < fields.length; i++) {
732
+ const field = fields[i];
733
+
734
+ if (field.type !== 'submit' && field.type !== 'button') {
735
+ const fieldName = field.name.replace(prefix, '');
736
+ if (field.type === 'textarea') {
737
+ formData[fieldName] = $(field).val();
738
+ } else if (field.type === 'checkbox') {
739
+ formData[fieldName] = field.checked;
740
+ } else if (field.type === 'radio') {
741
+ if (field.checked) {
742
+ formData[fieldName] = $(field).val();
743
+ }
744
+ } else if (field.type === 'file') {
745
+ const files = Array.from(field.files);
746
+ const filesBase64 = [];
747
+
748
+ for (let j = 0; j < files.length; j++) {
749
+ const file = files[j];
750
+ try {
751
+ const base64String = await convertFileToBase64(file);
752
+ filesBase64.push({name: file.name, value: base64String});
753
+ } catch (error) {
754
+ console.error('Error converting file:', error);
755
+ }
756
+ }
757
+
758
+ formData[fieldName] = filesBase64;
759
+ } else if (field.multiple) {
760
+ const selectedOptions = Array.from(field.selectedOptions);
761
+ const selectedValues = selectedOptions.map((option) => option.value);
762
+ formData[fieldName] = selectedValues;
763
+ } else {
764
+ formData[fieldName] = field.value;
765
+ }
766
+ }
767
+ }
768
+
769
+ if (format) {
770
+ return JSON.stringify(formData);
771
+ }
772
+
773
+ return formData;
774
+ }
775
+
776
+ function convertToStringJson(form, prefix = "", extras = {}, format = true) {
777
+ return obtainFormAsJSON(form[0], prefix, extras, format);
778
+ }
779
+
780
+ function load_errors(error_list, obj, parentdiv) {
781
+ ul_obj = "<ul class='errorlist form_errors d-flex justify-content-center'>";
782
+ error_list.forEach((item) => {
783
+ ul_obj += "<li>" + item + "</li>";
784
+ });
785
+ ul_obj += "</ul>"
786
+ $(obj).parents(parentdiv).prepend(ul_obj);
787
+ return ul_obj;
788
+ }
789
+
790
+ function form_field_errors(target_form, form_errors, prefix, parentdiv) {
791
+ var item = "";
792
+ for (const [key, value] of Object.entries(form_errors)) {
793
+ item = " #id_" + prefix + key;
794
+ if (target_form.find(item).length > 0) {
795
+ load_errors(form_errors[key], item, parentdiv);
796
+ }
797
+ }
798
+ }
799
+
800
+ function response_manage_type_data(instance, err_json_fn, error_text_fn) {
801
+ return function (response) {
802
+ const contentType = response.headers.get("content-type");
803
+ if (response.ok) {
804
+ if (contentType && contentType.indexOf("application/json") !== -1) {
805
+ return response.json();
806
+ } else {
807
+ return response.text();
808
+ }
809
+ } else {
810
+ if (contentType && contentType.indexOf("application/json") !== -1) {
811
+ response.json().then(data => err_json_fn(instance, data));
812
+ } else {
813
+ response.text().then(data => error_text_fn(instance, data));
814
+ }
815
+ return Promise.resolve(false);
816
+ }
817
+
818
+ return Promise.reject(response); // then it will go to the catch if it is an error code
819
+ }
820
+ }
821
+
822
+ function clear_action_form(form) {
823
+ // clear switchery before the form reset so the check status doesn't get changed before the validation
824
+ $(form).find("input[data-switchery=true]").each(function () {
825
+ if ($(this).prop("checked")) { // only reset it if it is checked
826
+ $(this).trigger("click").prop("checked", false);
827
+ }
828
+ });
829
+ $(form).find('[data-widget="TaggingInput"],[data-widget="EmailTaggingInput"]').each(function (i, e) {
830
+ var tg = $(e).data().tagify;
831
+ tg.removeAllTags();
832
+ });
833
+ $(form).find('[data-widget="FileChunkedUpload"],[data-widget="FileInput"]').each(function (i, e) {
834
+ var tg = $(e).data().fileUploadWidget;
835
+ tg.resetEmpty();
836
+ });
837
+ $(form).trigger('reset');
838
+ $(form).find("select option:selected").prop("selected", false);
839
+ $(form).find("select").val(null).trigger('change');
840
+ $(form).find("ul.form_errors").remove();
841
+ $(form).find(".file-link").remove();
842
+ }
843
+
844
+ var gt_form_modals = {}
845
+ var gt_detail_modals = {}
846
+ var gt_crud_objs = {};
847
+
848
+ function updateInstanceValuesForm(form, name, value) {
849
+ var item = form.find(
850
+ 'input[name="' + name + '"], ' +
851
+ 'textarea[name="' + name + '"], ' +
852
+ 'select[name="' + name + '"]'
853
+ );
854
+ item.each(function (i, inputfield) {
855
+ let done = false;
856
+ inputfield = $(inputfield);
857
+
858
+ if (inputfield.attr('class') === "chunkedvalue") {
859
+ if (value) {
860
+ var chunked = form.find('input[name="' + name + '_widget"]').data('fileUploadWidget');
861
+ chunked.addRemote(value);
862
+ }
863
+ done = true;
864
+ } else if (inputfield.attr('type') === 'file') {
865
+ if (value) {
866
+ var newlink = document.createElement('a');
867
+ newlink.href = value.url;
868
+ newlink.textContent = value.name;
869
+ newlink.target = "_blank";
870
+ newlink.classList.add("link-primary");
871
+ newlink.classList.add("file-link");
872
+ newlink.classList.add("d-block");
873
+ inputfield.before(newlink)
874
+ }
875
+ done = true;
876
+ } else if (inputfield.attr('type') === "checkbox") {
877
+ if (inputfield.data().widget === "YesNoInput") {
878
+ inputfield.prop("checked", !value);
879
+ inputfield.trigger("click");
880
+ done = true;
881
+ } else {
882
+ inputfield.prop("checked", value);
883
+ }
884
+ done = true;
885
+ } else if (inputfield.attr('type') === "radio") {
886
+ var is_icheck = inputfield.closest('.gtradio').length > 0;
887
+ var sel = inputfield.filter(function () {
888
+ return this.value === value.toString()
889
+ });
890
+ if (sel.length > 0) {
891
+ sel.prop("checked", true);
892
+ if (is_icheck) {
893
+ sel.iCheck('update');
894
+ sel.iCheck('check');
895
+ }
896
+
897
+ } else {
898
+ inputfield.prop("checked", false);
899
+ if (is_icheck) {
900
+ inputfield.iCheck('update');
901
+ inputfield.iCheck('uncheck');
902
+ }
903
+ }
904
+ done = true;
905
+ }
906
+ if (inputfield.data().widget === "EditorTinymce" || inputfield.data().widget === "TextareaWysiwyg") {
907
+ tinymce.get(inputfield.attr('id')).setContent(value);
908
+ done = true;
909
+ }
910
+ if (inputfield.data().widget === "TaggingInput" || inputfield.data().widget === "EmailTaggingInput") {
911
+ var tagifyelement = inputfield.data().tagify;
912
+ tagifyelement.removeAllTags();
913
+ tagifyelement.loadOriginalValues(value);
914
+ done = true;
915
+ }
916
+
917
+ // New code for testing (*** start ***)
918
+ // data loading in select, autocompleteselect, autocompletemultiselect
919
+ else if (inputfield.is('select') && inputfield.data().widget === "Select") {
920
+ inputfield.val(value).trigger('change');
921
+ done = true;
922
+ } else if (inputfield.is('select') && inputfield.data().widget === "AutocompleteSelect") {
923
+ let data = value;
924
+ let select2Obj = inputfield.data('select2');
925
+ if (select2Obj) {
926
+ inputfield.select2('trigger', 'select', {
927
+ data: data
928
+ });
929
+ }
930
+ done = true;
931
+ } else if (inputfield.is('select') && inputfield.data().widget === "AutocompleteSelectMultiple") {
932
+
933
+ if (Array.isArray(value)) {
934
+ value.forEach(item => {
935
+ let newOption = new Option(item.text, item.id, true, true);
936
+ inputfield.append(newOption);
937
+ });
938
+ inputfield.trigger('change');
939
+ }
940
+ done = true;
941
+ }
942
+ // New code for testing (*** end ***)
943
+
944
+ if (!done) {
945
+ inputfield.val(value);
946
+ }
947
+ });
948
+ }
949
+
950
+ function updateInstanceForm(form, data) {
951
+ for (let key in data) {
952
+ if (data.hasOwnProperty(key)) {
953
+ updateInstanceValuesForm(form, key, data[key])
954
+ }
955
+ }
956
+ }
957
+
958
+
959
+ function gtforms(index, manager, formList, extra = true) {
703
960
  return {
704
961
  index: index,
705
962
  order: index,
963
+ deleted: false,
706
964
  manager: manager,
707
965
  formList: formList,
708
966
  extra: extra,
709
967
  instance: null,
710
- deleteForm: function(){
711
- if( !this.manager.validateDeleteForm()) {
712
- this.manager.notify('error', 'You can not delete this form, minimum form validation failed' )
713
- return;
714
- }
968
+ deleteForm: function () {
969
+ if (!this.manager.validateDeleteForm()) {
970
+ this.manager.notify('error', 'You can not delete this form, minimum form validation failed')
971
+ return;
972
+ }
973
+ this.deleted = true;
715
974
  this.instance.hide();
716
- this.instance.find('input[name="'+this.manager.prefix+'-'+this.index+'-DELETE"]').prop( "checked", true );
975
+ this.instance.find('input[name="' + this.manager.prefix + '-' + this.index + '-DELETE"]').prop("checked", true);
717
976
  this.manager.deleteForm(this.order);
718
977
  },
719
- render: function(){
978
+ render: function () {
720
979
  var html = this.manager.template.replace(/__prefix__/gi, this.index);
721
980
  this.instance = $(html);
722
981
  formList.append(this.instance);
@@ -724,37 +983,42 @@ function gtforms(index,manager, formList, extra=true) {
724
983
  this.registerBtns();
725
984
 
726
985
  },
727
- reorder: function(oper){
728
- var brother = this.manager.getForm(this.order+oper);
729
- this.manager.switchFrom(this.order, this.order+oper);
730
- if(brother != null){
731
- if(oper == 1 ){
986
+ reorder: function (oper) {
987
+ var brother = this.manager.getForm(this.order + oper);
988
+ this.manager.switchFrom(this.order, this.order + oper);
989
+ if (brother != null) {
990
+ if (oper == 1) {
732
991
  this.instance.before(brother.instance);
733
- }else{
992
+ } else {
734
993
  brother.instance.before(this.instance);
735
994
  }
736
995
  }
737
996
  },
738
- registerBtns: function(){
997
+ registerBtns: function () {
739
998
  this.instance.find('.deletebtn').on('click', this.callDelete(this));
740
999
  // down increment order and up decrement order when forms are inserted in bottom
741
1000
  this.instance.find('.btndown').on('click', this.callReorder(this, 1));
742
1001
  this.instance.find('.btnup').on('click', this.callReorder(this, -1));
743
1002
  },
744
- callDelete: function(instance){
745
- return () => { instance.deleteForm() };
1003
+ callDelete: function (instance) {
1004
+ return () => {
1005
+ instance.deleteForm()
1006
+ };
746
1007
  },
747
- initializeWidgets: function(instance){
1008
+ initializeWidgets: function (instance) {
748
1009
  gt_find_initialize(instance);
749
1010
  },
750
- callReorder: function(instance, oper){
751
- return () => { instance.reorder(oper) }
1011
+ callReorder: function (instance, oper) {
1012
+ return () => {
1013
+ instance.reorder(oper)
1014
+ }
752
1015
  },
753
- updateOrder: function(){
754
- this.instance.find('input[name="'+this.manager.prefix+'-'+this.index+'-ORDER"]').val(this.order);
1016
+ updateOrder: function () {
1017
+ this.instance.find('input[name="' + this.manager.prefix + '-' + this.index + '-ORDER"]').val(this.order);
755
1018
  }
756
1019
  }
757
1020
  }
1021
+
758
1022
  function gtformSetManager(instance) {
759
1023
  var obj = {
760
1024
  index: 0,
@@ -771,49 +1035,61 @@ function gtformSetManager(instance) {
771
1035
  formList: instance.find('.formlist'),
772
1036
  template: '',
773
1037
  prefix: 'form-',
774
- initialize: function(){
775
- this.template = this.formsetControl.find(".formsettemplate").contents()[0].data;
776
- this.prefix = this.formsetControl.data('prefix');
777
- this.validateMax = this.formsetControl.data('validate-max') == '1';
778
- this.validateMin = this.formsetControl.data('validate-min') == '1';
779
- this.loadManagementForm();
780
- this.instance.find('.formsetadd').on('click', this.addBtnForm(this));
781
- this.addFormDom();
1038
+ initialize: function () {
1039
+ this.template = this.formsetControl.find(".formsettemplate").contents()[0].data;
1040
+ this.prefix = this.formsetControl.data('prefix');
1041
+ this.validateMax = this.formsetControl.data('validate-max') == '1';
1042
+ this.validateMin = this.formsetControl.data('validate-min') == '1';
1043
+ this.loadManagementForm();
1044
+ this.instance.find('.formsetadd').on('click', this.addBtnForm(this));
1045
+ this.addFormDom();
782
1046
  },
783
- addBtnForm: function(instance){
784
- return () => { instance.addEmtpyForm() };
1047
+ addBtnForm: function (instance) {
1048
+ return (e) => {
1049
+ instance.addEmtpyForm(e)
1050
+ };
785
1051
  },
786
- addEmtpyForm: function(){
787
- if(this.validateAddForm()){
1052
+ addEmtpyForm: function (e) {
1053
+ if (this.validateAddForm()) {
1054
+ this.activeForms += 1;
788
1055
  var form = gtforms(this.index, this, this.formList);
789
1056
  form.render();
790
1057
  this.forms.push(form);
1058
+ this.addForm(this, form, true, e);
791
1059
  this.index += 1;
792
1060
  this.updateTotalForms(+1);
793
- }else{
1061
+ } else {
794
1062
  this.notify('error', 'You cannot add new form, limit is exceded')
795
1063
  }
796
1064
  },
797
- addForm: function(object){},
798
- addFormDom: function(){
799
- this.formList.children().each((i, element) =>{
800
- var form = gtforms(this.index, this, this.formList, extra=false);
801
- form.instance = $(element);
802
- form.registerBtns();
803
- this.forms.push(form);
804
- this.index += 1;
1065
+ addForm: function (parent, object, isempty, event) {
1066
+ },
1067
+ addFormDom: function () {
1068
+ this.formList.children().each((i, element) => {
1069
+ this.activeForms += 1;
1070
+ var form = gtforms(this.index, this, this.formList, extra = false);
1071
+ form.instance = $(element);
1072
+ form.registerBtns();
1073
+ this.forms.push(form);
1074
+ this.addForm(this, form, false, null);
1075
+ this.index += 1;
805
1076
  });
806
1077
  },
807
- deleteForm: function(index){
808
- if( !this.validateDeleteForm()) return;
809
- if(index>=0 && index < this.forms.length){
810
- if(this.forms[index].extra){
1078
+ delForm: function (parent, index, form) {
1079
+ },
1080
+ deleteForm: function (index) {
1081
+ if (!this.validateDeleteForm()) return;
1082
+ this.activeForms = Math.max(0, this.activeForms - 1);
1083
+
1084
+ if (index >= 0 && index < this.forms.length) {
1085
+ this.delForm(this, index, this.forms[index]);
1086
+ if (this.forms[index].extra) {
811
1087
  this.forms.splice(index, 1);
812
1088
  this.updateTotalForms(-1);
813
- if(index == this.forms.length){
1089
+ if (index == this.forms.length) {
814
1090
  this.index -= 1;
815
- }else{
816
- for(var x=0; x<this.forms.length; x++){
1091
+ } else {
1092
+ for (var x = 0; x < this.forms.length; x++) {
817
1093
  this.forms[x].order = x;
818
1094
  this.forms[x].updateOrder();
819
1095
  }
@@ -822,40 +1098,40 @@ function gtformSetManager(instance) {
822
1098
 
823
1099
  }
824
1100
  },
825
- validateAddForm: function(){
826
- if(!this.validateMax) return true;
1101
+ validateAddForm: function () {
1102
+ if (!this.validateMax) return true;
827
1103
  return this.MAX_NUM_FORMS == -1 || this.TOTAL_FORMS < this.MAX_NUM_FORMS;
828
1104
  },
829
- validateDeleteForm: function(){
830
- if(!this.validateMin) return true;
1105
+ validateDeleteForm: function () {
1106
+ if (!this.validateMin) return true;
831
1107
  return this.MIN_NUM_FORMS == -1 || this.TOTAL_FORMS > this.MIN_NUM_FORMS;
832
1108
  },
833
- loadManagementForm: function(){
834
- this.TOTAL_FORMS = parseInt(this.formsetControl.find('input[name="'+this.prefix+'-TOTAL_FORMS"]').val());
835
- this.INITIAL_FORMS = parseInt(this.formsetControl.find('input[name="'+this.prefix+'-INITIAL_FORMS"]').val());
836
- this.MIN_NUM_FORMS = parseInt(this.formsetControl.find('input[name="'+this.prefix+'-MIN_NUM_FORMS"]').val());
837
- this.MAX_NUM_FORMS = parseInt(this.formsetControl.find('input[name="'+this.prefix+'-MAX_NUM_FORMS"]').val());
1109
+ loadManagementForm: function () {
1110
+ this.TOTAL_FORMS = parseInt(this.formsetControl.find('input[name="' + this.prefix + '-TOTAL_FORMS"]').val());
1111
+ this.INITIAL_FORMS = parseInt(this.formsetControl.find('input[name="' + this.prefix + '-INITIAL_FORMS"]').val());
1112
+ this.MIN_NUM_FORMS = parseInt(this.formsetControl.find('input[name="' + this.prefix + '-MIN_NUM_FORMS"]').val());
1113
+ this.MAX_NUM_FORMS = parseInt(this.formsetControl.find('input[name="' + this.prefix + '-MAX_NUM_FORMS"]').val());
838
1114
  },
839
- updateManagementForm: function(){
840
- this.formsetControl.find('input[name="'+this.prefix+'-TOTAL_FORMS"]').val(this.TOTAL_FORMS);
841
- this.formsetControl.find('input[name="'+this.prefix+'-INITIAL_FORMS"]').val(this.INITIAL_FORMS);
842
- this.formsetControl.find('input[name="'+this.prefix+'-MIN_NUM_FORMS"]').val(this.MIN_NUM_FORMS);
843
- this.formsetControl.find('input[name="'+this.prefix+'-MAX_NUM_FORMS"]').val(this.MAX_NUM_FORMS);
1115
+ updateManagementForm: function () {
1116
+ this.formsetControl.find('input[name="' + this.prefix + '-TOTAL_FORMS"]').val(this.TOTAL_FORMS);
1117
+ this.formsetControl.find('input[name="' + this.prefix + '-INITIAL_FORMS"]').val(this.INITIAL_FORMS);
1118
+ this.formsetControl.find('input[name="' + this.prefix + '-MIN_NUM_FORMS"]').val(this.MIN_NUM_FORMS);
1119
+ this.formsetControl.find('input[name="' + this.prefix + '-MAX_NUM_FORMS"]').val(this.MAX_NUM_FORMS);
844
1120
  },
845
- updateTotalForms: function(oper){
846
- this.TOTAL_FORMS = this.TOTAL_FORMS+oper;
847
- this.formsetControl.find('input[name="'+this.prefix+'-TOTAL_FORMS"]').val(this.TOTAL_FORMS);
1121
+ updateTotalForms: function (oper) {
1122
+ this.TOTAL_FORMS = this.TOTAL_FORMS + oper;
1123
+ this.formsetControl.find('input[name="' + this.prefix + '-TOTAL_FORMS"]').val(this.TOTAL_FORMS);
848
1124
  },
849
- getForm: function(index){
850
- if(index>=0 && index < this.forms.length){
1125
+ getForm: function (index) {
1126
+ if (index >= 0 && index < this.forms.length) {
851
1127
  return this.forms[index];
852
1128
  }
853
1129
  return null;
854
1130
  },
855
- switchFrom: function(fref, fswap){
1131
+ switchFrom: function (fref, fswap) {
856
1132
  var freform = this.getForm(fref);
857
1133
  var fswapform = this.getForm(fswap);
858
- if(freform != null && fswapform != null){
1134
+ if (freform != null && fswapform != null) {
859
1135
  var tmporder = freform.order;
860
1136
  freform.order = fswapform.order;
861
1137
  fswapform.order = tmporder;
@@ -867,23 +1143,23 @@ function gtformSetManager(instance) {
867
1143
  }
868
1144
 
869
1145
  },
870
- redrawOrdering: function(){
871
- for(var x=0; x<this.forms.length; x++){
872
- this.formList.append(this.forms[x].instance);
1146
+ redrawOrdering: function () {
1147
+ for (var x = 0; x < this.forms.length; x++) {
1148
+ this.formList.append(this.forms[x].instance);
873
1149
  }
874
1150
  },
875
- notify: function(type, text){
1151
+ notify: function (type, text) {
876
1152
  console.log(text);
877
1153
  },
878
- clean: function(){
879
- while(this.forms.length>0){
1154
+ clean: function () {
1155
+ while (this.forms.length > 0) {
880
1156
  var f = this.forms.pop();
881
1157
  f.instance.remove();
882
1158
  }
883
- this.TOTAL_FORMS=0;
884
- this.INITIAL_FORMS=0;
885
- this.TOTAL_FORMS=0;
886
- this.index=0;
1159
+ this.TOTAL_FORMS = 0;
1160
+ this.INITIAL_FORMS = 0;
1161
+ this.TOTAL_FORMS = 0;
1162
+ this.index = 0;
887
1163
  this.updateManagementForm();
888
1164
  }
889
1165
  }
@@ -1970,3 +2246,140 @@ function getMediaRecord(element, mediatype){
1970
2246
  }
1971
2247
  }
1972
2248
 
2249
+
2250
+ class CardList {
2251
+ constructor(containerId, apiUrl, actions={}) {
2252
+ this.container = document.getElementById(containerId);
2253
+ this.apiUrl = apiUrl;
2254
+ this.page = 1;
2255
+ this.data=null;
2256
+ this.page_size = 10;
2257
+ this.totalPages = 1;
2258
+ this.recordsTotal = 0;
2259
+ this.template = '';
2260
+ this.filters = {};
2261
+ this.actions=actions;
2262
+ this.fetchData();
2263
+
2264
+ }
2265
+
2266
+ async fetchData() {
2267
+ try {
2268
+ const queryParams = new URLSearchParams({
2269
+ page: this.page,
2270
+ page_size: this.page_size,
2271
+ ...(this.filters || {}),
2272
+ }).toString();
2273
+
2274
+ const url = `${this.apiUrl}?${queryParams}`;
2275
+ const response = await fetch(url);
2276
+ if (!response.ok) throw new Error(`Error HTTP: ${response.status}`);
2277
+
2278
+ const data = await response.json();
2279
+ this.template = data.template || this.template;
2280
+ this.totalPages = data.totalPages || 1;
2281
+ this.recordsTotal = data.recordsTotal || 0;
2282
+ this.process_data(data);
2283
+ this.render(data);
2284
+ } catch (error) {
2285
+ console.error('Error fetching data:', error);
2286
+ }
2287
+ }
2288
+
2289
+ process_data(data){
2290
+ this.data={};
2291
+ data.data.forEach(item => {
2292
+ this.data[item.id]=item;
2293
+ })
2294
+ }
2295
+
2296
+ render(data) {
2297
+ if (!this.template) {
2298
+ console.error("No template found!");
2299
+ return;
2300
+ }
2301
+ this.container.innerHTML = Sqrl.render(this.template, data, Sqrl.getConfig({ tags: ["<%", "%>"] }));
2302
+ gt_find_initialize_from_dom(this.container);
2303
+ this.doPagination();
2304
+ this.dofiltering();
2305
+ this.doPageSizeOptions();
2306
+ this.doObjActions()
2307
+ }
2308
+
2309
+ async getFilters(){
2310
+ const form = this.container.querySelectorAll('.filter_form');
2311
+
2312
+ const result = await convertToStringJson(form);
2313
+ this.filters = JSON.parse(result);
2314
+ this.fetchData();
2315
+ }
2316
+ dofiltering(){
2317
+ /**
2318
+ const forminput = this.container.querySelectorAll('.filter_form input, .filter_form select');
2319
+ const parent=this;
2320
+ forminput.forEach(input => {
2321
+ input.onchange=function(event){
2322
+ parent.getFilters();
2323
+ }
2324
+ });
2325
+ **/
2326
+ }
2327
+ doPageSizeOptions(){
2328
+ const formselect = this.container.querySelectorAll('.page_size_select');
2329
+ const parent=this;
2330
+ parent.page_size=parseInt(formselect[0].value);
2331
+ formselect.forEach(input => {
2332
+ input.onchange=function(event){
2333
+ parent.page_size=event.target.value
2334
+ parent.getFilters();
2335
+ }
2336
+ });
2337
+
2338
+ }
2339
+ doPagination(){
2340
+ const alink = this.container.querySelectorAll('.pagination a');
2341
+ const parent=this;
2342
+ alink.forEach(link => {
2343
+ link.onclick = function(event) {
2344
+ parent.page=event.target.dataset.page;
2345
+ parent.fetchData();
2346
+ }
2347
+ });
2348
+ }
2349
+ doObjActions(){
2350
+ const actions = this.container.querySelectorAll('.obj_action');
2351
+ const parent=this;
2352
+ actions.forEach(action => {
2353
+ action.onclick = function(event) {
2354
+ event.preventDefault();
2355
+ var pk = action.dataset.instance;
2356
+ var name = action.dataset.action;
2357
+ if (typeof parent.actions[name] === 'function') {
2358
+ parent.actions[name](pk, parent.data[pk]);
2359
+ }
2360
+ }
2361
+ })
2362
+ const generalactions = this.container.querySelectorAll('.general_action');
2363
+ generalactions.forEach(action => {
2364
+ action.onclick = function(event) {
2365
+ event.preventDefault();
2366
+ var name = action.dataset.action;
2367
+ if (typeof parent.actions[name] === 'function') {
2368
+ parent.actions[name]();
2369
+ }else{
2370
+ if (typeof parent[name] === 'function') parent[name]();
2371
+ }
2372
+ }
2373
+ })
2374
+ }
2375
+ search(){
2376
+ this.getFilters();
2377
+ }
2378
+ clean(){
2379
+ const form = this.container.querySelectorAll('.filter_form');
2380
+ clear_action_form(form);
2381
+ this.container.querySelectorAll('.filter_form input').forEach(i=>{i.value="";});
2382
+ this.getFilters();
2383
+ }
2384
+ }
2385
+