dynamicforms 0.76.14__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 (287) hide show
  1. dynamicforms/__init__.py +8 -0
  2. dynamicforms/action.py +521 -0
  3. dynamicforms/apps.py +5 -0
  4. dynamicforms/fields.py +1570 -0
  5. dynamicforms/filters.py +44 -0
  6. dynamicforms/locale/en/LC_MESSAGES/django.po +67 -0
  7. dynamicforms/locale/en/LC_MESSAGES/djangojs.po +31 -0
  8. dynamicforms/locale/sl/LC_MESSAGES/django.po +71 -0
  9. dynamicforms/locale/sl/LC_MESSAGES/djangojs.po +36 -0
  10. dynamicforms/management/__init__.py +0 -0
  11. dynamicforms/management/commands/__init__.py +0 -0
  12. dynamicforms/management/commands/clean_dfpreuploaded_files.py +26 -0
  13. dynamicforms/migrations/__init__.py +0 -0
  14. dynamicforms/mixins/__init__.py +27 -0
  15. dynamicforms/mixins/action.py +14 -0
  16. dynamicforms/mixins/choice/__init__.py +94 -0
  17. dynamicforms/mixins/choice/allow_tags.py +79 -0
  18. dynamicforms/mixins/choice/null_choice.py +26 -0
  19. dynamicforms/mixins/choice/single_choice.py +21 -0
  20. dynamicforms/mixins/color_field.py +4 -0
  21. dynamicforms/mixins/conditional_visibility.py +193 -0
  22. dynamicforms/mixins/enable_copy.py +4 -0
  23. dynamicforms/mixins/field_render.py +209 -0
  24. dynamicforms/mixins/file_field.py +5 -0
  25. dynamicforms/mixins/help_text.py +46 -0
  26. dynamicforms/mixins/implicit_hidden.py +7 -0
  27. dynamicforms/mixins/implicit_natural_date.py +88 -0
  28. dynamicforms/mixins/null_value.py +15 -0
  29. dynamicforms/mixins/password_field.py +23 -0
  30. dynamicforms/mixins/related_field_ajax.py +142 -0
  31. dynamicforms/mixins/rtf_field.py +58 -0
  32. dynamicforms/models.py +5 -0
  33. dynamicforms/models_utils.py +33 -0
  34. dynamicforms/pagination.py +175 -0
  35. dynamicforms/preupload_files.py +42 -0
  36. dynamicforms/progress.py +71 -0
  37. dynamicforms/renderers.py +1 -0
  38. dynamicforms/routers.py +36 -0
  39. dynamicforms/serializers.py +486 -0
  40. dynamicforms/struct.py +40 -0
  41. dynamicforms/template_render/__init__.py +10 -0
  42. dynamicforms/template_render/layout.py +178 -0
  43. dynamicforms/template_render/mixins/__init__.py +0 -0
  44. dynamicforms/template_render/mixins/base.py +39 -0
  45. dynamicforms/template_render/mixins/field.py +74 -0
  46. dynamicforms/template_render/mixins/listserializer.py +100 -0
  47. dynamicforms/template_render/mixins/render_mode_enum.py +8 -0
  48. dynamicforms/template_render/mixins/serializer.py +301 -0
  49. dynamicforms/template_render/mixins/serializer_filter.py +19 -0
  50. dynamicforms/template_render/mixins/serializer_render_actions.py +21 -0
  51. dynamicforms/template_render/mixins/serializer_render_fields.py +57 -0
  52. dynamicforms/template_render/mixins/util.py +9 -0
  53. dynamicforms/template_render/renderer.py +38 -0
  54. dynamicforms/template_render/responsive_table_layout.py +64 -0
  55. dynamicforms/urls.py +9 -0
  56. dynamicforms/utils.py +32 -0
  57. dynamicforms/views.py +1 -0
  58. dynamicforms/viewsets.py +421 -0
  59. dynamicforms-0.76.14.dist-info/METADATA +129 -0
  60. dynamicforms-0.76.14.dist-info/RECORD +287 -0
  61. dynamicforms-0.76.14.dist-info/WHEEL +4 -0
  62. dynamicforms-0.76.14.dist-info/licenses/LICENSE +21 -0
  63. dynamicforms_legacy/__init__.py +8 -0
  64. dynamicforms_legacy/action.py +561 -0
  65. dynamicforms_legacy/apps.py +5 -0
  66. dynamicforms_legacy/context_processors.py +27 -0
  67. dynamicforms_legacy/dynamicforms_migration_mixin.py +42 -0
  68. dynamicforms_legacy/fields.py +1108 -0
  69. dynamicforms_legacy/filters.py +44 -0
  70. dynamicforms_legacy/migrations/__init__.py +0 -0
  71. dynamicforms_legacy/mixins/__init__.py +16 -0
  72. dynamicforms_legacy/mixins/action.py +14 -0
  73. dynamicforms_legacy/mixins/allow_tags.py +85 -0
  74. dynamicforms_legacy/mixins/enable_copy.py +4 -0
  75. dynamicforms_legacy/mixins/file_field.py +5 -0
  76. dynamicforms_legacy/mixins/help_text.py +38 -0
  77. dynamicforms_legacy/mixins/implicit_hidden.py +7 -0
  78. dynamicforms_legacy/mixins/implicit_natural_date.py +86 -0
  79. dynamicforms_legacy/mixins/null_choice.py +26 -0
  80. dynamicforms_legacy/mixins/null_value.py +15 -0
  81. dynamicforms_legacy/mixins/password_field.py +19 -0
  82. dynamicforms_legacy/mixins/related_field_ajax.py +58 -0
  83. dynamicforms_legacy/mixins/render.py +203 -0
  84. dynamicforms_legacy/mixins/rtf_field.py +52 -0
  85. dynamicforms_legacy/mixins/single_choice.py +21 -0
  86. dynamicforms_legacy/models.py +5 -0
  87. dynamicforms_legacy/pagination.py +168 -0
  88. dynamicforms_legacy/progress.py +71 -0
  89. dynamicforms_legacy/renderers.py +183 -0
  90. dynamicforms_legacy/serializers.py +335 -0
  91. dynamicforms_legacy/settings.py +196 -0
  92. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.css +587 -0
  93. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -0
  94. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css +6 -0
  95. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -0
  96. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.css +6834 -0
  97. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -0
  98. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.min.css +6 -0
  99. dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -0
  100. dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.eot +0 -0
  101. dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.svg +288 -0
  102. dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  103. dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.woff +0 -0
  104. dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  105. dynamicforms_legacy/static/bootstrap-3.4.1-dist/js/bootstrap.js +2580 -0
  106. dynamicforms_legacy/static/bootstrap-3.4.1-dist/js/bootstrap.min.js +6 -0
  107. dynamicforms_legacy/static/bootstrap-3.4.1-dist/js/npm.js +13 -0
  108. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.css +3719 -0
  109. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.css.map +1 -0
  110. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.min.css +7 -0
  111. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.min.css.map +1 -0
  112. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.css +331 -0
  113. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.css.map +1 -0
  114. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.min.css +8 -0
  115. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.min.css.map +1 -0
  116. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.css +10038 -0
  117. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.css.map +1 -0
  118. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.min.css +7 -0
  119. dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.min.css.map +1 -0
  120. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.js +7013 -0
  121. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.js.map +1 -0
  122. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.min.js +7 -0
  123. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.min.js.map +1 -0
  124. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.js +4435 -0
  125. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.js.map +1 -0
  126. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.min.js +7 -0
  127. dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.min.js.map +1 -0
  128. dynamicforms_legacy/static/ckeditor-df/ckEditorCustomBuildReadMe.txt +255 -0
  129. dynamicforms_legacy/static/ckeditor-df/ckeditor.js +6 -0
  130. dynamicforms_legacy/static/dynamicforms/dynamicforms.js +1883 -0
  131. dynamicforms_legacy/static/dynamicforms/icons/copy.svg +7 -0
  132. dynamicforms_legacy/static/dynamicforms/icons/eye-off-outline.svg +10 -0
  133. dynamicforms_legacy/static/dynamicforms/icons/eye-outline.svg +7 -0
  134. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  135. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  136. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  137. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  138. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  139. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  140. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  141. dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  142. dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_222222_256x240.png +0 -0
  143. dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_228ef1_256x240.png +0 -0
  144. dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_ef8c08_256x240.png +0 -0
  145. dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_ffd27a_256x240.png +0 -0
  146. dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_ffffff_256x240.png +0 -0
  147. dynamicforms_legacy/static/jquery_ui/css/jquery-ui.min.css +7 -0
  148. dynamicforms_legacy/static/jquery_ui/css/jquery-ui.structure.min.css +5 -0
  149. dynamicforms_legacy/static/jquery_ui/css/jquery-ui.theme.min.css +5 -0
  150. dynamicforms_legacy/static/jquery_ui/js/jquery-3.3.1.min.js +2 -0
  151. dynamicforms_legacy/static/jquery_ui/js/jquery-ui.min.js +13 -0
  152. dynamicforms_legacy/static/select2/css/select2-bootstrap3.min.css +7 -0
  153. dynamicforms_legacy/static/select2/css/select2-bootstrap4.min.css +578 -0
  154. dynamicforms_legacy/static/select2/select2-4.0.5/css/select2.min.css +1 -0
  155. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/af.js +3 -0
  156. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ar.js +3 -0
  157. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/az.js +3 -0
  158. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/bg.js +3 -0
  159. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/bs.js +3 -0
  160. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ca.js +3 -0
  161. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/cs.js +3 -0
  162. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/da.js +3 -0
  163. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/de.js +3 -0
  164. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/dsb.js +3 -0
  165. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/el.js +3 -0
  166. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/en.js +3 -0
  167. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/es.js +3 -0
  168. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/et.js +3 -0
  169. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/eu.js +3 -0
  170. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/fa.js +3 -0
  171. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/fi.js +3 -0
  172. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/fr.js +3 -0
  173. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/gl.js +3 -0
  174. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/he.js +3 -0
  175. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hi.js +3 -0
  176. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hr.js +3 -0
  177. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hsb.js +3 -0
  178. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hu.js +3 -0
  179. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hy.js +3 -0
  180. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/id.js +3 -0
  181. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/is.js +3 -0
  182. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/it.js +3 -0
  183. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ja.js +3 -0
  184. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/km.js +3 -0
  185. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ko.js +3 -0
  186. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/lt.js +3 -0
  187. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/lv.js +3 -0
  188. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/mk.js +3 -0
  189. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ms.js +3 -0
  190. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/nb.js +3 -0
  191. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/nl.js +3 -0
  192. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/pl.js +3 -0
  193. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ps.js +3 -0
  194. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/pt-BR.js +3 -0
  195. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/pt.js +3 -0
  196. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ro.js +3 -0
  197. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ru.js +3 -0
  198. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sk.js +3 -0
  199. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sl.js +3 -0
  200. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sr-Cyrl.js +3 -0
  201. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sr.js +3 -0
  202. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sv.js +3 -0
  203. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/th.js +3 -0
  204. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/tr.js +3 -0
  205. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/uk.js +3 -0
  206. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/vi.js +3 -0
  207. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/zh-CN.js +3 -0
  208. dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/zh-TW.js +3 -0
  209. dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.full.js +6457 -0
  210. dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.full.min.js +1 -0
  211. dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.js +5746 -0
  212. dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.min.js +1 -0
  213. dynamicforms_legacy/struct.py +40 -0
  214. dynamicforms_legacy/templates/dynamicforms/base.html +12 -0
  215. dynamicforms_legacy/templates/dynamicforms/base_form.html +44 -0
  216. dynamicforms_legacy/templates/dynamicforms/base_includes.html +51 -0
  217. dynamicforms_legacy/templates/dynamicforms/base_includes_select2.html +6 -0
  218. dynamicforms_legacy/templates/dynamicforms/base_list.html +47 -0
  219. dynamicforms_legacy/templates/dynamicforms/base_table_body.html +46 -0
  220. dynamicforms_legacy/templates/dynamicforms/base_table_filter.html +44 -0
  221. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_form.html +10 -0
  222. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_includes.html +46 -0
  223. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_includes_v3.html +90 -0
  224. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_includes_v4.html +77 -0
  225. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_list.html +9 -0
  226. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_table_body.html +4 -0
  227. dynamicforms_legacy/templates/dynamicforms/bootstrap/base_table_filter.html +5 -0
  228. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/base_field.html +41 -0
  229. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/base_field_v3.html +11 -0
  230. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/base_field_v4.html +11 -0
  231. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/checkbox.html +7 -0
  232. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/checkbox_multiple.html +7 -0
  233. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/fieldset.html +21 -0
  234. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/form.html +4 -0
  235. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/input.html +31 -0
  236. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/list_fieldset.html +18 -0
  237. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/radio.html +8 -0
  238. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/rtf_field.html +4 -0
  239. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/select.html +46 -0
  240. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/select_multiple.html +17 -0
  241. dynamicforms_legacy/templates/dynamicforms/bootstrap/field/textarea.html +4 -0
  242. dynamicforms_legacy/templates/dynamicforms/bootstrap/modal_dialog.html +13 -0
  243. dynamicforms_legacy/templates/dynamicforms/bootstrap/modal_dialog_rest.html +23 -0
  244. dynamicforms_legacy/templates/dynamicforms/bootstrap/page.html +11 -0
  245. dynamicforms_legacy/templates/dynamicforms/field/base_field.html +55 -0
  246. dynamicforms_legacy/templates/dynamicforms/field/checkbox.html +28 -0
  247. dynamicforms_legacy/templates/dynamicforms/field/checkbox_multiple.html +16 -0
  248. dynamicforms_legacy/templates/dynamicforms/field/dict_field.html +4 -0
  249. dynamicforms_legacy/templates/dynamicforms/field/fieldset.html +4 -0
  250. dynamicforms_legacy/templates/dynamicforms/field/form.html +18 -0
  251. dynamicforms_legacy/templates/dynamicforms/field/input.html +31 -0
  252. dynamicforms_legacy/templates/dynamicforms/field/list_field.html +4 -0
  253. dynamicforms_legacy/templates/dynamicforms/field/list_fieldset.html +4 -0
  254. dynamicforms_legacy/templates/dynamicforms/field/radio.html +24 -0
  255. dynamicforms_legacy/templates/dynamicforms/field/rtf_field.html +14 -0
  256. dynamicforms_legacy/templates/dynamicforms/field/select.html +97 -0
  257. dynamicforms_legacy/templates/dynamicforms/field/select_multiple.html +67 -0
  258. dynamicforms_legacy/templates/dynamicforms/field/textarea.html +13 -0
  259. dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_form.html +13 -0
  260. dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_includes.html +225 -0
  261. dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_list.html +9 -0
  262. dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_table_body.html +4 -0
  263. dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_table_filter.html +5 -0
  264. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/base_field.html +16 -0
  265. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/checkbox.html +7 -0
  266. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/checkbox_multiple.html +9 -0
  267. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/fieldset.html +11 -0
  268. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/form.html +4 -0
  269. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/input.html +17 -0
  270. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/list_fieldset.html +6 -0
  271. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/radio.html +8 -0
  272. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/rtf_field.html +4 -0
  273. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/select.html +37 -0
  274. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/select_multiple.html +18 -0
  275. dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/textarea.html +4 -0
  276. dynamicforms_legacy/templates/dynamicforms/jquery_ui/modal_dialog.html +2 -0
  277. dynamicforms_legacy/templates/dynamicforms/jquery_ui/modal_dialog_rest.html +27 -0
  278. dynamicforms_legacy/templates/dynamicforms/jquery_ui/page.html +20 -0
  279. dynamicforms_legacy/templates/dynamicforms/modal_dialog.html +4 -0
  280. dynamicforms_legacy/templates/dynamicforms/modal_dialog_rest.html +18 -0
  281. dynamicforms_legacy/templates/dynamicforms/page.html +25 -0
  282. dynamicforms_legacy/templates/dynamicforms/rtf_field_style.html +41 -0
  283. dynamicforms_legacy/templatetags/__init__.py +0 -0
  284. dynamicforms_legacy/templatetags/dynamicforms.py +475 -0
  285. dynamicforms_legacy/urls.py +8 -0
  286. dynamicforms_legacy/views.py +1 -0
  287. dynamicforms_legacy/viewsets.py +366 -0
@@ -0,0 +1,1883 @@
1
+ /**
2
+ * Two level dictionary
3
+ */
4
+ function TLD() {
5
+ this.storage = {};
6
+ }
7
+
8
+ TLD.prototype = {
9
+ get: function get(key1, key2) {
10
+ if (this.storage[key1] == undefined) {
11
+ return undefined;
12
+ }
13
+ if (key2 == undefined) {
14
+ return this.storage[key1];
15
+ }
16
+ return this.storage[key1][key2];
17
+ },
18
+
19
+ set: function set(key1, key2, value) {
20
+ if (this.storage[key1] == undefined)
21
+ this.storage[key1] = {};
22
+ if (key2 == undefined)
23
+ this.storage[key1] = value;
24
+ else
25
+ this.storage[key1][key2] = value;
26
+ },
27
+
28
+ del: function del(key1, key2) {
29
+ if (key2)
30
+ delete this.storage[key1][key2];
31
+ else
32
+ delete this.storage[key1];
33
+ },
34
+
35
+ getOrCreate: function getOrCreate(key1, key2, defVal) {
36
+ var res = this.get(key1, key2);
37
+ if (res == undefined) {
38
+ res = defVal;
39
+ this.set(key1, key2, res);
40
+ }
41
+ return res;
42
+ },
43
+ };
44
+
45
+ dynamicforms = {
46
+ // DYNAMICFORMS is an object containing all dynamicforms settings as specified by defaults and in settings.py
47
+ DYNAMICFORMS: {
48
+ 'template': 'dynamicforms/bootstrap/',
49
+ 'jquery_ui': false,
50
+ 'edit_in_dialog': true,
51
+ 'bootstrap_version': 'v4',
52
+ },
53
+
54
+ filter_sequence: 0,
55
+
56
+ /**
57
+ * Presents the error in data exchange with the server in a user understandable way
58
+ * @param xhr
59
+ * @param status
60
+ * @param error
61
+ */
62
+ showAjaxError: function showAjaxError(xhr, status, error) {
63
+ //TODO: make proper error display message. You will probably also need some text about what you were trying to do
64
+ console.log([xhr, status, error]);
65
+ },
66
+ /**
67
+ * Shows progress dialog if operation takes longer than 0.5 seconds. Also sets z-index of progress bar and overlay
68
+ * @param progressDlgID: ID of progress dialog element - for custom progress dialogs.
69
+ * @param progressSettings: Progress dialog settings - for custom progress dialogs.
70
+ */
71
+ showProgressDlg: function showProgressDialog(progressDlgID, progressSettings) {
72
+ var zIndexElement;
73
+ var progressDlg = $('#' + progressDlgID);
74
+ if (dynamicforms.DYNAMICFORMS.jquery_ui) {
75
+ if (progressSettings === undefined)
76
+ progressSettings = {value: 25};
77
+ $("#df-progress-bar-indeterminate").progressbar(progressSettings);
78
+ progressSettings['value'] = 0;
79
+ $("#df-progress-bar-determinate").progressbar(progressSettings);
80
+
81
+ if (dynamicforms.shouldShowProgressDlg) {
82
+ dynamicforms.shouldCloseProgressDlg = false;
83
+ dynamicforms.progressDlgShown = true;
84
+ dynamicforms.progressDlgStartShowing = true;
85
+ progressDlg.dialog({dialogClass: 'progress-bar', closeOnEscape: false, resizable: false,
86
+ open: function() {
87
+ dynamicforms.progressDlgShown = true;
88
+ if (dynamicforms.shouldCloseProgressDlg) {
89
+ dynamicforms.closeProgressDlg(progressDlgID);
90
+ }
91
+ }
92
+ });
93
+ }
94
+ zIndexElement = progressDlg.parents().first();
95
+ } else {
96
+ if (progressSettings === undefined)
97
+ progressSettings = {keyboard: false, backdrop: 'static'};
98
+ if (dynamicforms.shouldShowProgressDlg) {
99
+ dynamicforms.shouldCloseProgressDlg = false;
100
+ dynamicforms.progressDlgStartShowing = true;
101
+ progressDlg.modal(progressSettings);
102
+ progressDlg.on('shown.bs.modal', function () {
103
+ progressDlg.off('shown.bs.modal');
104
+ dynamicforms.progressDlgShown = true;
105
+ if(dynamicforms.shouldCloseProgressDlg){
106
+ dynamicforms.closeProgressDlg(progressDlgID);
107
+ }
108
+ })
109
+
110
+ }
111
+ zIndexElement = progressDlg;
112
+ }
113
+ var zIndexOrig = zIndexElement.css('z-index');
114
+ var zIndex = parseInt(zIndexOrig);
115
+ if (isNaN(zIndex))
116
+ zIndex = zIndexOrig;
117
+ else {
118
+ // Because all bootstrap modules have same z-index. If we want that clickable progress bar will be on top of all
119
+ // we must raise z-index. At the same time we must set overlay z-index, so nothing else will be clickable.
120
+ zIndex += 1;
121
+ zIndexElement.css('z-index', zIndex + 1);
122
+ }
123
+
124
+ $('#df-overlay').css('z-index', zIndex);
125
+ },
126
+
127
+ progressCheckInterval: null,
128
+ /**
129
+ * Sets continuous checking on server about operation progress. After first check shows progress dialog if necessary.
130
+ * @param progressDlgID: ID of progress dialog element - for custom progress dialogs.
131
+ * @param timestamp: used for generating operation progress key under which progress is stored on server.
132
+ * @param progressSettings: Progress dialog settings - for custom progress dialogs.
133
+ */
134
+ progressCheck: function progressCheck(progressDlgID, timestamp, progressSettings) {
135
+ if (!dynamicforms.progressDlgStartShowing && dynamicforms.progressCheckInterval != null) {
136
+ clearInterval(dynamicforms.progressCheckInterval);
137
+ dynamicforms.progressCheckInterval = null;
138
+ } else {
139
+ $.ajax({ url: '/dynamicforms/progress-legacy/', headers: { 'X-DF-TIMESTAMP': timestamp } })
140
+ .done(function (data) {
141
+ var pb_indet = $('#df-progress-bar-indeterminate');
142
+ var pb_det = $('#df-progress-bar-determinate');
143
+ var percent = data.value;
144
+ var show_indet = percent == null;
145
+ pb_indet.toggle(show_indet);
146
+ pb_det.toggle(!show_indet);
147
+
148
+ if (data.comment != null)
149
+ $('#df-progress-comment').html(data.comment);
150
+
151
+ if (dynamicforms.shouldShowProgressDlg && !dynamicforms.progressDlgStartShowing) {
152
+ dynamicforms.showProgressDlg(progressDlgID, progressSettings);
153
+ }
154
+ if (!show_indet) {
155
+ if (dynamicforms.DYNAMICFORMS.jquery_ui) {
156
+ pb_det.progressbar("value", parseInt(percent));
157
+ } else {
158
+ pb_det.css('width', percent + '%').attr('aria-valuenow', percent)
159
+ }
160
+ }
161
+ })
162
+ .fail(function () {
163
+ if (dynamicforms.shouldShowProgressDlg && !dynamicforms.progressDlgStartShowing) {
164
+ dynamicforms.showProgressDlg(progressDlgID, progressSettings);
165
+ }
166
+ });
167
+ }
168
+ },
169
+ /**
170
+ * Starts continuous checking on operations progress. After first check progress dialog is opened if necessary
171
+ * @param progressDlgID: ID of progress dialog element - for custom progress dialogs.
172
+ * @param timestamp: used for generating operation progress key under which progress is stored on server.
173
+ * @param progressSettings: Progress dialog settings - for custom progress dialogs.
174
+ */
175
+ startProgressChecker: function startProgressChecker(progressDlgID, timestamp, progressSettings) {
176
+ dynamicforms.progressCheck(progressDlgID, timestamp, progressSettings);
177
+ dynamicforms.progressCheckInterval = setInterval(dynamicforms.progressCheck, 500, progressDlgID, timestamp, progressSettings);
178
+ },
179
+ shouldShowProgressDlg: false,
180
+ shouldCloseProgressDlg: true,
181
+ progressDlgShown: false,
182
+ progressDlgOverlay: false,
183
+ /**
184
+ * Sets overlay so nothing can be clicked while operation last. If it last for more than 0.5 second it starts
185
+ * progress checker.
186
+ * @param progressDlgID: ID of progress dialog element - for custom progress dialogs.
187
+ * @param timestamp: used for generating operation progress key under which progress is stored on server.
188
+ * @param progressSettings: Progress dialog settings - for custom progress dialogs.
189
+ */
190
+ setProgressDlg: function setProgressDlg(progressDlgID, timestamp, progressSettings) {
191
+ dynamicforms.progressDlgOverlay = true;
192
+ $('#df-overlay').css('z-index', 10000).show();
193
+ dynamicforms.shouldShowProgressDlg = true;
194
+ window.setTimeout(function () {
195
+ if (dynamicforms.shouldShowProgressDlg && !dynamicforms.progressDlgShown) {
196
+ dynamicforms.startProgressChecker(progressDlgID, timestamp, progressSettings);
197
+ }
198
+ }, 500);
199
+ },
200
+ /**
201
+ * Closes progress dialog (if it is opened) and hides overlay that prevents clicks on other elements
202
+ * @param progressDlgID: ID of progress dialog element - for custom progress dialogs.
203
+ */
204
+ closeProgressDlg: function closeProgressDlg(progressDlgID) {
205
+ dynamicforms.shouldShowProgressDlg = false;
206
+ dynamicforms.shouldCloseProgressDlg = true;
207
+ if (dynamicforms.progressCheckInterval != null) {
208
+ clearInterval(dynamicforms.progressCheckInterval);
209
+ dynamicforms.progressCheckInterval = null;
210
+ }
211
+ $('.modal-backdrop').remove();
212
+ $('#df-overlay').hide();
213
+ if (dynamicforms.progressDlgShown) {
214
+ dynamicforms.progressDlgShown = false;
215
+ dynamicforms.progressDlgStartShowing = false;
216
+
217
+ var $dlg = $('#' + progressDlgID);
218
+ if ($dlg.length) {
219
+ if (dynamicforms.DYNAMICFORMS.jquery_ui) {
220
+ $dlg.dialog('close');
221
+ } else {
222
+ $dlg.remove();
223
+ }
224
+ }
225
+ }
226
+ dynamicforms.progressDlgOverlay = false;
227
+ },
228
+ /**
229
+ * Calls standard jQuery.ajax. Additionally it sets overlay that prevents clicks on other elements until operation
230
+ * completes If operation lasts for more than 0.5 seconds progress dialog is shown.
231
+ * @param options: Dict with options for ajax call ('ajax_setts'), and custom progress dialog ('progress_id',
232
+ * 'progress_sets')
233
+ * @returns ajax promise with everything set for progress dialog: X-DF-TIMESTAMP header for progress checking and
234
+ * callbacks for closing progress dialog after operation completes
235
+ */
236
+ ajaxWithProgress: function ajaxWithProgress(options) {
237
+ var progressDlgID = options['progress_id'] !== undefined ? options['progress_id'] : 'df-modal-dialog-container';
238
+ var timestamp = $.now()
239
+
240
+ var showProgress = undefined;
241
+ var progressSetts = options.progress_setts;
242
+
243
+ if (progressSetts != undefined)
244
+ showProgress = progressSetts.show;
245
+ if (showProgress == undefined)
246
+ showProgress = true;
247
+
248
+ if (showProgress && !dynamicforms.progressDlgOverlay) {
249
+ if (progressDlgID == 'df-modal-dialog-container') {
250
+ progressDlgID = 'df-modal-dialog-' + 'progress';
251
+ if ($('#' + progressDlgID).length) {
252
+ var $dlg = $('#' + progressDlgID);
253
+ } else {
254
+ var $dlg = $("#df-modal-dialog-container").clone();
255
+ $dlg.attr('id', progressDlgID);
256
+ if (dynamicforms.DYNAMICFORMS.jquery_ui) {
257
+ var dlg_template = '<div id="df-progress-comment"></div>' +
258
+ '<div id="df-progress-bar-indeterminate" class="indeterminate" style="display: none"></div>' +
259
+ '<div id="df-progress-bar-determinate" ></div>';
260
+ $dlg.attr('title', dynamicforms.DYNAMICFORMS.progress_dialog_title)
261
+ $dlg.html(dlg_template);
262
+ } else {
263
+ var dlg_template = '<div id="df-progress-comment"></div>' +
264
+ '<div id="df-progress-bar-div" class="progress" style="position: relative;">' +
265
+ '<div id="df-progress-bar-indeterminate" class="progress-bar progress-bar-striped indeterminate" ' +
266
+ 'style="display: none"></div> <div id="df-progress-bar-determinate" class="progress-bar progress-bar-striped" ' +
267
+ 'style="display: none" aria-valuemin="0" aria-valuemax="100"></div></div>';
268
+ $dlg.find('.modal-title').html(dynamicforms.DYNAMICFORMS.progress_dialog_title);
269
+ $dlg.find('.modal-body').html(dlg_template);
270
+ $dlg.find('.modal-footer').remove();
271
+ }
272
+ $(document.body).append($dlg);
273
+ }
274
+ }
275
+
276
+ dynamicforms.setProgressDlg(progressDlgID, timestamp, options['progress_setts']);
277
+ } else {
278
+ progressDlgID = 'df-modal-dialog-' + 'progress';
279
+ }
280
+
281
+ var closeProgressDialogFunc = function () {
282
+ if (showProgress)
283
+ dynamicforms.closeProgressDlg(progressDlgID);
284
+ };
285
+
286
+ var ajaxSettings = options['ajax_setts'] !== undefined ? options['ajax_setts'] : {};
287
+ var headers = ajaxSettings['headers'] !== undefined ? ajaxSettings['headers'] : {};
288
+ headers['X-DF-TIMESTAMP'] = timestamp;
289
+ ajaxSettings['headers'] = headers;
290
+
291
+ return $.ajax(ajaxSettings).done(closeProgressDialogFunc).fail(closeProgressDialogFunc);
292
+ },
293
+
294
+ /**
295
+ * Handles what happens when user says "Save data". Basically serialization, send to server, response to returned
296
+ * status and values
297
+ * @param $dlg: current dialog which will be updated with call results or closed on successful data store
298
+ * @param $form: the edited form containing the data
299
+ * @param refreshType: how to refresh the table
300
+ * @param doneFunc: if specified, this function will be called on successful data send
301
+ * @param dType: Custom dataType
302
+ */
303
+ submitForm: function submitForm($dlg, $form, refreshType, doneFunc, dType) {
304
+ var data = dynamicforms.getSerializedForm($form, 'final');
305
+ var method = data['data-dynamicforms-method'] || ([0, "", "0", undefined, null].indexOf(data.id) > -1 ? 'POST' : 'PUT');
306
+ var headers = {'X-DF-RENDER-TYPE': 'dialog'};
307
+
308
+ headers['X-CSRFToken'] = dynamicforms.csrf_token;
309
+
310
+ var recordURL = dynamicforms.getRecordURL($form.attr('id'));
311
+ var recordID = data.id ? data.id : false;
312
+
313
+ var listId = dynamicforms.form_helpers.get($form.attr('id'), 'listID');
314
+
315
+ var dataType = 'html';
316
+ function performRefresh(data, params){
317
+ if (!recordID) {
318
+ try {
319
+ recordID = $(data).find('form.dynamicforms-form').find('input[name=\'id\']').val().trim();
320
+ if (recordID == '')
321
+ recordID = false;
322
+ } catch (e) {}
323
+ }
324
+ dynamicforms.refreshList(recordURL, recordID, refreshType, listId, false, params);
325
+ }
326
+ var doneFuncExec;
327
+ if (doneFunc == undefined) {
328
+ doneFuncExec = function (data) {
329
+ dynamicforms.closeDialog($dlg);
330
+ performRefresh(data);
331
+ }
332
+ } else{
333
+ doneFuncExec = doneFunc;
334
+ dataType = dType ? dType : 'json'; // If custom datatype is not given, we hope that JSON was meant
335
+ }
336
+ if (dType != undefined)
337
+ dataType = dType;
338
+
339
+ function getDlg(){
340
+ return $dlg;
341
+ }
342
+
343
+ // We need this so ve can call refresh from custom function (arguments.callee.performRefresh())
344
+ doneFuncExec.performRefresh = performRefresh;
345
+ doneFuncExec.getDlg = getDlg;
346
+ dynamicforms.handleRTFFieldsValue(data, $form);
347
+
348
+ if (typeof window.FormData === "undefined") {
349
+ alert("Your browser does not support file upload.");
350
+ return;
351
+ }
352
+ var formDataObject = new FormData();
353
+ for (var key in data) {
354
+ if (data.hasOwnProperty(key)) {
355
+ var fileInput = $form.find('input[type="file"][name="' + key + '"]')
356
+ if (fileInput.length === 1) {
357
+ if (fileInput.get(0).files.length === 1 && !!fileInput.get(0).files[0]) {
358
+ formDataObject.append(key, fileInput.get(0).files[0]);
359
+ }
360
+ } else {
361
+ if ($.isArray(data[key])) {
362
+ for (var i = 0; i < data[key].length; i++) {
363
+ formDataObject.append(key, data[key][i]);
364
+ }
365
+ } else {
366
+ formDataObject.append(key, data[key]);
367
+ }
368
+ }
369
+ }
370
+ }
371
+
372
+ dynamicforms.ajaxWithProgress({
373
+ ajax_setts: {
374
+ type: method,
375
+ url: $form.attr("action"),
376
+ data: formDataObject,
377
+ dataType: dataType,
378
+ processData: false,
379
+ contentType: false,
380
+ headers: headers,
381
+ traditional: true,
382
+ },
383
+ })
384
+ .done(doneFuncExec)
385
+ .fail(function (xhr) {
386
+ // TODO: this doesn't handle errors correctly: if return status is 400 something, it *might* be OK
387
+ // but if it's 500 something, dialog will be replaced by non-dialog code and displaying it will fail
388
+ // also for any authorization errors, CSRF, etc, it will again fail
389
+ // Try finding a <div class="dynamicforms-dialog"/> in there to see if you actually got a dialog
390
+ if ($dlg != null)
391
+ dynamicforms.updateDialog($dlg, $(xhr.responseText), refreshType, listId, doneFunc, dType);
392
+ });
393
+ },
394
+
395
+ /**
396
+ * Sets record specific url
397
+ * @param formID: id of form
398
+ * @param url: url for record
399
+ */
400
+ setRecordURL: function setRecordURL(formID, url) {
401
+ dynamicforms.form_helpers.set(formID, 'recordURL', url);
402
+ },
403
+
404
+ /**
405
+ * Gets record specific url
406
+ * @param formID: id of form
407
+ */
408
+ getRecordURL: function getRecordURL(formID) {
409
+ return dynamicforms.form_helpers.get(formID, 'recordURL');
410
+ },
411
+
412
+ isFunction: function isFunction(passedFunction) {
413
+ return typeof (eval(passedFunction)) == "function";
414
+ },
415
+
416
+ /**
417
+ * Gets refreshed html after add or edit
418
+ * @param url: url for retrieving html
419
+ * @param recordID: id of the data
420
+ * @param refreshType: how to refresh the table
421
+ * @param formID: id of form
422
+ * @param deletion: if present delete action happened
423
+ * @param params: dict variable for additional parameters
424
+ */
425
+ refreshList: function refreshList(url, recordID, refreshType, formID, deletion, params) {
426
+ if (refreshType == undefined || refreshType == 'record') {
427
+
428
+ var data = dynamicforms.filterData(formID, true);
429
+ if (recordID)
430
+ data.id = recordID
431
+ if (params != undefined && params.additionalData != undefined) {
432
+ for (var key in params.additionalData) {
433
+ data[key] = params.additionalData[key];
434
+ }
435
+ }
436
+
437
+ dynamicforms.ajaxWithProgress({
438
+ ajax_setts: {type: 'GET', url: url, data: data, dataType: 'html',
439
+ headers: {'X-DF-CALLTYPE': 'refresh_record'}},
440
+ progress_setts: params != undefined ? params.progressSetts : undefined
441
+ })
442
+ .done(function (data) {
443
+ dynamicforms.refreshRow(data, formID, recordID);
444
+ // noinspection JSUnresolvedVariable
445
+ if(params && params.afterRefreshFunc)
446
+ params.afterRefreshFunc(data, formID, recordID);
447
+ })
448
+ .fail(function (xhr, status, error) {
449
+ // TODO: this doesn't handle errors correctly
450
+ });
451
+ } else if (refreshType == 'table') {
452
+ dynamicforms.refreshTable(formID, recordID);
453
+ if (deletion == true) {
454
+ dynamicforms.wasLastRowDeleted();
455
+ }
456
+ } else if (refreshType == 'page') {
457
+ window.location.reload(true);
458
+ } else if (typeof (refreshType) == 'function') {
459
+ refreshType();
460
+ } else if (refreshType.indexOf('redirect:') !== -1) {
461
+ window.location.href = refreshType.split(':').pop();
462
+ } else if (refreshType == 'no refresh') {
463
+ // pass
464
+ } else if (dynamicforms.isFunction(refreshType)) {
465
+ // Change passed string to function call
466
+ var functionString = refreshType + "();";
467
+ var customFunction = new Function(functionString);
468
+ customFunction();
469
+ }
470
+ },
471
+ /**
472
+ * Insert new row after the last row or insert first row
473
+ * @param $newRow
474
+ */
475
+ insertRow: function insertRow($newRow, formID, prevId) {
476
+ // Insert new row after the last row or insert first row
477
+ if ($newRow.length) {
478
+ var tbl_pagination = dynamicforms.df_tbl_pagination.get(formID, undefined);
479
+
480
+ var $lastRow;
481
+ var hasPrevId = (typeof prevId !== typeof undefined && prevId !== false && prevId != '');
482
+
483
+ if(hasPrevId){
484
+ if(prevId == 'None')
485
+ $lastRow = $('#list-' + formID + ' > tbody > tr[data-id]').first();
486
+ else{
487
+ $lastRow = $('#list-' + formID + ' > tbody > tr[data-id="' + prevId + '"]').first(); // First row of table
488
+ if ($lastRow.length == 0)
489
+ console.log('Row with prevId = "' + prevId + '" not found!');
490
+ }
491
+ }
492
+ else if(!dynamicforms.isLinkNext(tbl_pagination.link_next))
493
+ $lastRow = $('#list-' + formID + ' > tbody > tr[data-id]').last(); // Last row before adding new record
494
+ if ($lastRow != undefined && $lastRow.length) {
495
+ if(prevId == 'None')
496
+ $newRow.insertBefore($lastRow);
497
+ else
498
+ $newRow.insertAfter($lastRow);
499
+ } else {
500
+ $('#list-' + formID + ' > tbody > tr[data-title]').replaceWith($newRow);
501
+ }
502
+ }
503
+ },
504
+ /**
505
+ * Replaces edited row
506
+ * @param data
507
+ * @param recordID: id of edited data
508
+ * @param formID: id of form
509
+ */
510
+ refreshRow: function refreshRow(data, formID, recordID) {
511
+ var $rowToRefresh = null; // Row to refresh
512
+ var $htmlObject = (data instanceof jQuery) ? data : $(data);
513
+
514
+ if (recordID) {
515
+ var trSelector = "tr[data-id='" + recordID + "']";
516
+ $rowToRefresh = $('#list-' + formID + ' > tbody > ' + trSelector); // Row to refresh
517
+ var $editedRow = $htmlObject.find("table[id^='list-'] > tbody > " + trSelector); // Edited record from ajax returned html
518
+
519
+ if ($editedRow.length) {
520
+ var prevId = $editedRow.attr('data-df_prev_id');
521
+ var hasPrevId = (typeof prevId !== typeof undefined && prevId !== false && prevId != '');
522
+
523
+ if ($rowToRefresh != null && $rowToRefresh.length){
524
+ if(hasPrevId){
525
+ $rowToRefresh.remove();
526
+ dynamicforms.insertRow($editedRow, formID, prevId);
527
+ }
528
+ else
529
+ $rowToRefresh.replaceWith($editedRow);
530
+ }
531
+ else
532
+ dynamicforms.insertRow($editedRow, formID, prevId);
533
+ }
534
+ } else {
535
+ var $newRow = $htmlObject.find("table").find("tr[data-id]").last(); // Added record from ajax returned html
536
+ dynamicforms.insertRow($newRow, formID, $newRow.attr('data-df_prev_id'));
537
+ }
538
+ },
539
+
540
+ /**
541
+ * Replaces entire table
542
+ * @param formID: id of form object
543
+ * @param recordID: id of edited data
544
+ */
545
+ refreshTable: function refreshTable(formID, recordID) {
546
+
547
+ //If it is set to refresh table, we also want to see all the changes, that was made by other users.
548
+ //We can only get them by reread data.
549
+ dynamicforms.filterData(formID);
550
+ },
551
+
552
+ /**
553
+ * Shows a dialog, attaches appropriate event handlers to buttons and gets initial data values
554
+ * @param $dlg: dialog (parsed) html to show
555
+ * @param refreshType: how to refresh the table after the dialog is finished with editing
556
+ * @param listId: id of table element with records
557
+ * @param doneFunc: if specified, this function will be called on successful data send
558
+ * @param dataType: Custom dataType
559
+ */
560
+ showDialog: function showDialog($dlg, refreshType, listId, doneFunc, dataType) {
561
+ //TODO: adjust hashURL
562
+ $(document.body).append($dlg);
563
+ var $form = $dlg.find('.dynamicforms-form');
564
+ dynamicforms.form_helpers.set($form.attr('id'), 'listID', listId);
565
+
566
+ $($dlg).on('hidden.bs.modal', function () {
567
+ // dialog removes itself from DOM hierarchy
568
+ $('.modal-backdrop').remove();
569
+ $dlg.remove();
570
+
571
+ dynamicforms.removeFormDeclarations($form);
572
+ });
573
+
574
+ // Let's get initial field values from the form
575
+ dynamicforms.serializeForm($form, 'final');
576
+
577
+ var saveId = '#save-' + $form.attr('id');
578
+ $(saveId).on('click', function () {
579
+ dynamicforms.submitForm($dlg, $form, refreshType, doneFunc, dataType);
580
+ });
581
+ // And show the dialog
582
+ if (dynamicforms.DYNAMICFORMS.jquery_ui)
583
+ $dlg.dialog('open')
584
+ else {
585
+ $dlg.modal();
586
+ }
587
+ },
588
+
589
+ /**
590
+ * Updates the current dialog with errors.
591
+ * @param $dlg: dialog to update
592
+ * @param $newDlg: new dialog with errors in form
593
+ * @param refreshType: how to refresh the table after the dialog is finished with editing
594
+ * @param listId: id of table element with records
595
+ * @param doneFunc: if specified, this function will be called on successful data send
596
+ * @param dType: Custom dataType
597
+ */
598
+ updateDialog: function updateDialog($dlg, $newDlg, refreshType, listId, doneFunc, dType) {
599
+ if($dlg.hasClass('dynamicforms-dialog')){
600
+ $dlg.showNewAfterHide = $newDlg; // Old dialog will show the new one after being hidden
601
+ dynamicforms.closeDialog($dlg, refreshType, listId, doneFunc, dType);
602
+ } else {
603
+ /*
604
+ // Replace current form with new form containing errors
605
+ */
606
+ var newForm = $newDlg.find("form");
607
+ var currentForm = $dlg.find("form");
608
+ dynamicforms.clearSerializedForm(currentForm, 'final');
609
+ currentForm.replaceWith(newForm);
610
+ dynamicforms.serializeForm(newForm, 'final');
611
+ }
612
+ },
613
+
614
+ /**
615
+ * Closes the current dialog
616
+ * TODO: adjust hashURL
617
+ * @param $dlg: dialog to close
618
+ * @param refreshType: how to refresh the table after the dialog is finished with editing
619
+ * @param listId: id of table element with records
620
+ * @param doneFunc: if specified, this function will be called on successful data send
621
+ * @param dataType: Custom dataType
622
+ */
623
+ closeDialog: function closeDialog($dlg, refreshType, listId, doneFunc, dataType) {
624
+ if (!dynamicforms.DYNAMICFORMS.jquery_ui) {
625
+ $dlg.on('hidden.bs.modal', function () {
626
+ $dlg.remove();
627
+ if ($dlg.showNewAfterHide)
628
+ dynamicforms.showDialog($dlg.showNewAfterHide, refreshType, listId, doneFunc, dataType);
629
+ });
630
+
631
+ $dlg.modal('hide');
632
+ } else {
633
+ $dlg.remove();
634
+ if ($dlg.showNewAfterHide) {
635
+ dynamicforms.showDialog($dlg.showNewAfterHide, refreshType, listId, doneFunc, dataType);
636
+ }
637
+ }
638
+ },
639
+
640
+ /**
641
+ * Handles what should happen when user clicks to edit a record
642
+ * @param recordURL: url to call to get data / html for the record / dialog
643
+ * @param refreshType: how to refresh the table
644
+ * @param listId: id of table element with records
645
+ * @param params: additional parameters in dictionary format
646
+ */
647
+ editRow: function editRow(recordURL, refreshType, listId, params) {
648
+ if (dynamicforms.DYNAMICFORMS.edit_in_dialog) {
649
+ var ajaxSetts = {
650
+ url: recordURL,
651
+ headers: {'X-DF-RENDER-TYPE': 'dialog'}
652
+ }
653
+ if (params != undefined && params.data != undefined)
654
+ ajaxSetts['data'] = params.data;
655
+
656
+ dynamicforms.ajaxWithProgress({
657
+ ajax_setts: ajaxSetts
658
+ })
659
+ .done(function (dialogHTML) {
660
+ var submitDataType = undefined;
661
+ var submitDoneFunc = undefined;
662
+ try {
663
+ submitDataType = params.submitParams.dataType;
664
+ } catch (e) {}
665
+ try {
666
+ submitDoneFunc = params.submitParams.doneFunc;
667
+ } catch (e) {}
668
+ dynamicforms.showDialog($(dialogHTML), refreshType, listId, submitDoneFunc, submitDataType);
669
+ })
670
+ .fail(function (xhr, status, error) {
671
+ // TODO: this doesn't handle errors correctly
672
+ dynamicforms.showAjaxError(xhr, status, error);
673
+ });
674
+ } else
675
+ window.location = recordURL;
676
+ },
677
+
678
+ /**
679
+ * Removes table row after deletion
680
+ *
681
+ * @param recordID: data-id attribute of table row
682
+ */
683
+ removeRow: function removeRow(recordID) {
684
+ var $trToRemove = $("tr[data-id='" + recordID + "']");
685
+ $trToRemove.remove();
686
+ dynamicforms.wasLastRowDeleted();
687
+ },
688
+
689
+ /**
690
+ * Checks if last row was deleted and appends "No data" element if so
691
+ */
692
+ wasLastRowDeleted: function wasLastRowDeleted() {
693
+ var $leftTrsCount = $("tr[data-id]").length;
694
+ if ($leftTrsCount == 0) {
695
+ // Count how many lines should "No data" element span
696
+ var colCount = $("th").length;
697
+ var noDataElement = "<tr data-title='NoData'><td colspan=" + colCount + " style='text-align: center'>No data</td></tr>";
698
+ $("tbody").append(noDataElement);
699
+ }
700
+ },
701
+
702
+ /**
703
+ * Handles what should happen when user clicks to delete a record
704
+ * @param recordURL: url to call to get data / html for the record / dialog
705
+ * @param recordID: pk of row to be deleted
706
+ * @param refreshType: how to refresh the table
707
+ * @param listId: id of table element with records
708
+ */
709
+ deleteRow: function deleteRow(recordURL, recordID, refreshType, listId) {
710
+ //TODO: Ask user for confirmation
711
+ dynamicforms.ajaxWithProgress({
712
+ ajax_setts: {
713
+ url: recordURL,
714
+ method: 'DELETE',
715
+ headers: {'X-CSRFToken': dynamicforms.csrf_token}
716
+ }
717
+ })
718
+ .done(function (dialogHTML) {
719
+ console.log('Record successfully deleted.');
720
+ // TODO: make a proper notification
721
+ // Remove row after deletion
722
+ if (refreshType == undefined || refreshType == 'record') {
723
+ dynamicforms.removeRow(recordID);
724
+ } else if (refreshType == 'table') {
725
+ var recordURL = dynamicforms.getRecordURL(listId);
726
+ // var formId = $('table')[0].getAttribute('id').replace('list-', '');
727
+ dynamicforms.refreshList(recordURL, true, refreshType, listId, true);
728
+ } else if (refreshType == 'page') {
729
+ window.location.reload(true);
730
+ } else if (typeof (refreshType) == 'function') {
731
+ refreshType();
732
+ } else if (refreshType.indexOf('redirect') !== -1) {
733
+ window.location.href = refreshType.split(':').pop();
734
+ } else if (refreshType == 'no refresh') {
735
+ // pass
736
+ } else if (dynamicforms.isFunction(refreshType)) {
737
+ // Change passed string to function call
738
+ var functionString = refreshType + "();";
739
+ var customFunction = new Function(functionString);
740
+ customFunction();
741
+ }
742
+ })
743
+ .fail(function (xhr, status, error) {
744
+ // TODO: this doesn't handle errors correctly
745
+ dynamicforms.showAjaxError(xhr, status, error);
746
+ });
747
+ },
748
+
749
+
750
+ /**
751
+ * Handles what should happen when user clicks "Add new" button
752
+ * Right now newRow doesn't do anything distinct, so let's just call editRow
753
+ *
754
+ * @param recordURL: url to call to get data / html for the record / dialog
755
+ * @param refreshType: how to refresh the table
756
+ * @param listId: id of table element with records
757
+ * @returns {*|void}
758
+ */
759
+ newRow: function newRow(recordURL, refreshType, listId) {
760
+ return dynamicforms.editRow(recordURL, refreshType, listId);
761
+ },
762
+
763
+ /**************************************************************
764
+ * Form current values support functions
765
+ **************************************************************/
766
+
767
+ df_tbl_pagination: new TLD(),
768
+
769
+ form_helpers: new TLD(),
770
+
771
+ _checkFinalParam: function _checkFinalParam(final) {
772
+ if (final != 'final' && final != 'non-final') {
773
+ console.trace();
774
+ throw "Final is not in the allowed values! '" + final + "'";
775
+ }
776
+ },
777
+
778
+ serializeForm: function serializeForm($form, final) {
779
+ dynamicforms._checkFinalParam(final);
780
+ var formID = $form.attr('id');
781
+ var form_data = dynamicforms.form_helpers.getOrCreate(formID, final, {});
782
+ $.each(dynamicforms.form_helpers.get(formID, 'fields'), function (fieldID, field) {
783
+ form_data[field.name] = field.getValue(field.$field);
784
+ });
785
+ var fld = $form.find('input[name="data-dynamicforms-method"]');
786
+ if (fld.length == 1)
787
+ form_data['data-dynamicforms-method'] = fld.val();
788
+ fld = $form.find('input[name="csrfmiddlewaretoken"]');
789
+ if (fld.length == 1)
790
+ form_data['csrfmiddlewaretoken'] = fld.val();
791
+ },
792
+
793
+ clearSerializedForm: function clearSerializedForm($form, final) {
794
+ dynamicforms._checkFinalParam(final);
795
+ dynamicforms.form_helpers.del($form.attr('id'), final);
796
+ },
797
+
798
+ getSerializedForm: function getSerializedForm($form, final) {
799
+ dynamicforms._checkFinalParam(final);
800
+ return dynamicforms.form_helpers.get($form.attr('id'), final);
801
+ },
802
+
803
+ getSerializedFormFinal: function getSerializedFormFinal($form, final) {
804
+ var newFormData = dynamicforms.getSerializedForm($form, final);
805
+ if (final == 'final')
806
+ dynamicforms.clearSerializedForm($form, 'non-final');
807
+ else if (newFormData == undefined)
808
+ newFormData = dynamicforms.getSerializedForm($form, 'final');
809
+ return newFormData;
810
+ },
811
+
812
+ removeFormDeclarations: function removeFormDeclarations($form) {
813
+ var formID = $form.attr('id');
814
+ $.each(dynamicforms.form_helpers.getOrCreate(formID, 'fields', {}),
815
+ function (fieldID) {
816
+ dynamicforms.field_helpers.del(fieldID);
817
+ }
818
+ );
819
+ dynamicforms.form_helpers.del(formID);
820
+ },
821
+ /**************************************************************
822
+ * Actions support functions
823
+ **************************************************************/
824
+
825
+ // A helper obj containing all getters, setters, previous onchanging values, etc.
826
+ field_helpers: new TLD(),
827
+
828
+ /**
829
+ * fieldChange function is called whenever field's value changes. Some fields support even "changing" events where
830
+ * this function will be called for every change in the field's contents (e.g. typing a new letter into input).
831
+ * This function will then propagate the event to all actions letting them know of the change
832
+ * Note that "onchanging" has a separate "previous value" tracking. "onchanged" will report value before any editing
833
+ * no matter how many times "onchanging" has been processed
834
+ *
835
+ * TODO does getValue require a "default" parameter? In what situations would the default value be returned?
836
+ * TODO what does getValue return for inputs that are currently hidden or suppressed? Proposal: nothing, but we must
837
+ * always use PATCH, not PUT?
838
+ * //$inputs.on('change keyup paste', function () { self.selectMenuShow(false, $(this)); }); //navaden input
839
+ * onchanging
840
+ * //$inputs.on('focusout', function () { self.selectMenuShow(true, $(this)); }); // navaden input onchanged
841
+ *
842
+ * @param fieldID: id of the field
843
+ * @param final: 'final' when this is "onchanged" and 'non-final' when this is "onchanging"
844
+ */
845
+ fieldChange: function fieldChange(fieldID, final) {
846
+ dynamicforms._checkFinalParam(final);
847
+
848
+ var field = dynamicforms.field_helpers.get(fieldID),
849
+ $field = field.$field,
850
+ $form = field.$form,
851
+ newValue = field.getValue($field),
852
+ oldValue,
853
+ newFormData = dynamicforms.getSerializedFormFinal($form, final),
854
+ oldFormData = {};
855
+
856
+ // Copy the current form values to "old" object and adjust the current values with the change
857
+ $.extend(true, oldFormData, newFormData);
858
+ var field_name = $field.attr('name');
859
+ oldValue = newFormData[field_name];
860
+ newFormData[field_name] = newValue;
861
+
862
+ // Process the change if there was any
863
+ if (oldValue != newValue)
864
+ dynamicforms.processChangedFields(final, [fieldID], oldFormData, newFormData);
865
+ },
866
+
867
+ /**
868
+ * This function calls the handlers when a field has been changed. After processing the handlers it will check for
869
+ * additional changes. If detected, it will process the handlers for the new changes as well.
870
+ * @param final: 'final' when this is "onchanged" and 'non-final' when this is "onchanging"
871
+ * @param fields: list[field id]
872
+ * @param oldFormData: object
873
+ * @param newFormData: object
874
+ */
875
+ processChangedFields: function processChangedFields(final, fields, oldFormData, newFormData) {
876
+ var changedHelper = new TLD();
877
+
878
+ //Apply field actions
879
+ $.each(fields, function (idx, fieldID) {
880
+ var field = dynamicforms.field_helpers.get(fieldID),
881
+ $field = field.$field,
882
+ field_name = $field.attr('name'),
883
+ $form = field.$form,
884
+ formID = $form.attr('id');
885
+
886
+ if (changedHelper.get(formID, 'visibility') == undefined) {
887
+ // Remember current field visibility
888
+ changedHelper.set(formID, 'visibility', dynamicforms.getVisibleFields(formID));
889
+ changedHelper.set(formID, 'old', newFormData);
890
+ }
891
+ // console.log('Field "' + field_name + '" value has changed. Triggering actions');
892
+ var actions = dynamicforms.form_helpers.get(formID, 'actions_' + fieldID);
893
+ if (actions) {
894
+ $.each(actions, function (idx, action) {
895
+ // TODO while running actions, it's probably better not to process onchange
896
+ action($form.attr('id'), newFormData, oldFormData, [fieldID]);
897
+ });
898
+ }
899
+ });
900
+
901
+ $.each(changedHelper.storage, function (formID, ignored) {
902
+ var $form = $('#' + formID),
903
+ // Get new field values & visibility
904
+ oldFormData = changedHelper.get(formID, 'old'),
905
+ newFormData = dynamicforms.getSerializedFormFinal($form, final),
906
+ oldVisibility = changedHelper.get(formID, 'visibility'),
907
+ newVisibility = dynamicforms.getVisibleFields(formID),
908
+ changedFields = [];
909
+
910
+ // get diff for visibility & union it with diff for field values
911
+ $.each(dynamicforms.form_helpers.get(formID, 'fields'), function (fieldID, field) {
912
+ if (
913
+ ($.inArray(fieldID, oldVisibility) != -1) != ($.inArray(fieldID, newVisibility) != -1) ||
914
+ (newFormData[field.name] != oldFormData[field.name])
915
+ ) {
916
+ changedFields.push(fieldID);
917
+ }
918
+ });
919
+
920
+ // go through all fields and run their actions if either their value or their visibility is changed
921
+ processChangedFields(final, changedFields, oldFormData, newFormData);
922
+ });
923
+ },
924
+
925
+ /**
926
+ * Registers an onchange event with action to execute when given field's value changes
927
+ * @param formID: id of form object
928
+ * @param fieldID: id of the field
929
+ * @param func: function to be called for getting current field value
930
+ */
931
+ registerFieldAction: function registerFieldAction(formID, fieldID, func) {
932
+ var fieldActions = dynamicforms.form_helpers.get(formID, 'actions_' + fieldID) || [];
933
+ fieldActions.push(func);
934
+ dynamicforms.form_helpers.set(formID, 'actions_' + fieldID, fieldActions);
935
+ },
936
+
937
+ /**
938
+ * Registers the function which will get current field's value. See "standard" fieldGetValue below
939
+ * @param formID: id of form object
940
+ * @param fieldID: id of the field
941
+ * @param func: function to be called for getting current field value
942
+ */
943
+ registerFieldGetter: function registerFieldGetter(formID, fieldID, func) {
944
+ var field = dynamicforms.field_helpers.getOrCreate(fieldID, undefined, {});
945
+ field.getValue = func;
946
+ dynamicforms.updateFieldHelpers(formID, fieldID, field);
947
+ },
948
+
949
+ /**
950
+ * Registers the function which will set current field's value. See "standard" fieldSetValue below
951
+ * @param formID: id of form object
952
+ * @param fieldID: id of the field
953
+ * @param func: function to be called for setting current field value
954
+ */
955
+ registerFieldSetter: function registerFieldSetter(formID, fieldID, func) {
956
+ var field = dynamicforms.field_helpers.getOrCreate(fieldID, undefined, {});
957
+ field.setValue = func;
958
+ dynamicforms.updateFieldHelpers(formID, fieldID, field);
959
+ },
960
+
961
+ /**
962
+ * Sets some standard field helper values so that they don't have to be re-calculated every time
963
+ * @param formID: id of form object
964
+ * @param fieldID: id of the field
965
+ * @param field: field data to be populated
966
+ */
967
+ updateFieldHelpers: function updateFieldHelpers(formID, fieldID, field) {
968
+ if (field.$field == undefined) {
969
+ field.$field = $('#' + fieldID);
970
+ field.$form = $('#' + formID);
971
+ field.name = field.$field.attr('name');
972
+ }
973
+ var form_fields = dynamicforms.form_helpers.getOrCreate(formID, 'fields', {});
974
+ form_fields[fieldID] = field;
975
+ var field_ids = dynamicforms.form_helpers.getOrCreate(formID, 'field_ids', {});
976
+ field_ids[field.name] = fieldID;
977
+ },
978
+
979
+ /**
980
+ * Gets an object which maps field names to their IDs. This function is a helper for actions where field UUIDs
981
+ * are not known in advance. Its result is passed to functions such as fieldSetValue.
982
+ *
983
+ * @param formID: id of form object
984
+ * @return: object where obj.field_name == field control ID
985
+ */
986
+ getFieldIDs: function getFieldIDs(formID) {
987
+ return dynamicforms.form_helpers.getOrCreate(formID, 'field_ids', {});
988
+ },
989
+
990
+ /**
991
+ * "Standard" function for getting an input's current value. Any special cases will be handled in custom functions
992
+ *
993
+ * @param field: id or jQuery object of the field
994
+ * @returns field value
995
+ */
996
+ fieldGetValue: function fieldGetValue(field) {
997
+ var $field = field instanceof jQuery ? field : dynamicforms.field_helpers.get(field, '$field');
998
+ if ($field.attr('type') == 'checkbox')
999
+ return $field.is(':checked');
1000
+ return $field.val();
1001
+ },
1002
+
1003
+ /**
1004
+ * "Standard" function for setting an input's value. Any special cases will be handled in custom functions
1005
+ *
1006
+ * @param field: id or jQuery object of the field
1007
+ * @param value: new value to set
1008
+ * @param select2_ajax_option_text: label of selected option to be added to select2 options list. Only use when
1009
+ * select2 is ajax
1010
+ */
1011
+ fieldSetValue: function fieldSetValue(field, value, select2_ajax_option_text) {
1012
+ var $field = field instanceof jQuery ? field : dynamicforms.field_helpers.get(field, '$field');
1013
+ if ($field.attr('type') == 'checkbox')
1014
+ $field.prop('checked', value);
1015
+ if ($field.data('select2')) {
1016
+ if ($field.data('select2').options.options.ajax) {
1017
+ var opt = $('<option value="' + value + '"></option>').text(select2_ajax_option_text);
1018
+ $field.append(opt);
1019
+ } else {
1020
+ if ($field.data("allow-tags") && !$field.find("option[value='" + value + "']").length) {
1021
+ var newOption = new Option(value, value, true, true);
1022
+ $field.append(newOption).trigger('change');
1023
+ }
1024
+ }
1025
+ $field.val(value);
1026
+ dynamicforms.setSelect2Order($field, value);
1027
+ }
1028
+ $field.val(value);
1029
+ $field.trigger('change');
1030
+ },
1031
+ setSelect2Order: function setSelect2Order($field, value, forceSet){
1032
+ if(!forceSet)
1033
+ forceSet = false;
1034
+
1035
+ var vals
1036
+ if(forceSet || $field.data('preserved-order') != undefined){
1037
+ if(value.constructor === Array)
1038
+ vals = value;
1039
+ else
1040
+ vals = value.split(',');
1041
+
1042
+ vals = vals.length == 1 && vals[0] == "" ? [] : vals;
1043
+ $field.data('preserved-order', vals);
1044
+ dynamicforms.select2_renderSelections($field);
1045
+ }
1046
+ },
1047
+ select2_renderSelections: function select2_renderSelections($select2){
1048
+ var order = $select2.data('preserved-order') || [];
1049
+ var $container = $select2.next('.select2-container');
1050
+ var $tags = $container.find('li.select2-selection__choice');
1051
+ var $input = $tags.last().next();
1052
+
1053
+ // apply tag order
1054
+ var i;
1055
+ var val;
1056
+ var $el;
1057
+ for(i = 0; i<order.length; i++){
1058
+ val = order[i];
1059
+ $el = $tags.filter(function(i,tag){
1060
+ return $(tag).data('data').id === val;
1061
+ });
1062
+ $input.before( $el );
1063
+ }
1064
+ },
1065
+
1066
+ selectionHandler: function selectionHandler(e){
1067
+ var $select2 = $(this);
1068
+ var val = e.params.data.id;
1069
+ var order = $select2.data('preserved-order') || [];
1070
+ var found_index;
1071
+
1072
+ switch (e.type){
1073
+ case 'select2:select':
1074
+ found_index = order.indexOf(val);
1075
+ if (found_index < 0 )
1076
+ order[ order.length ] = val;
1077
+ break;
1078
+ case 'select2:unselect':
1079
+ found_index = order.indexOf(val);
1080
+ if (found_index >= 0 )
1081
+ order.splice(found_index,1);
1082
+ break;
1083
+ }
1084
+ $select2.data('preserved-order', order); // store it for later
1085
+ dynamicforms.select2_renderSelections($select2);
1086
+ },
1087
+
1088
+
1089
+ /**
1090
+ * "Standard" function for setting an input's visibility. Any special cases will be handled in custom functions
1091
+ *
1092
+ * @param field: id or jQuery object of the field
1093
+ * @param visible: boolean specifying whether field should be visible
1094
+ */
1095
+ fieldSetVisible: function fieldSetVisible(field, visible) {
1096
+ //TODO: we need to check parent container if everything inside it is hidden. If there is, the parent container needs to hide too
1097
+ var $field = field instanceof jQuery ? field : dynamicforms.field_helpers.get(field, '$field');
1098
+ var fieldID = $field.attr('id');
1099
+ var $hide = $field.parents('#container-' + fieldID);
1100
+ var $hideParent = $hide.parents('[data-hide-with-field]');
1101
+ if ($hideParent.length > 0)
1102
+ $hide = $hideParent;
1103
+
1104
+ // Toggle bootstrap hidden class
1105
+ var hidden_class = "d-none";
1106
+ if (this.DYNAMICFORMS.bootstrap_version == "v3")
1107
+ hidden_class = 'hidden';
1108
+
1109
+ if (visible) {
1110
+ $hide.toggleClass(hidden_class, false);
1111
+ } else {
1112
+ $hide.toggleClass(hidden_class, true);
1113
+ }
1114
+
1115
+ $hide.toggle(visible);
1116
+ },
1117
+
1118
+ /**
1119
+ * "Standard" function for checking whether an input's is visible. Any special cases will be handled in custom
1120
+ * functions
1121
+ *
1122
+ * @param field: id or jQuery object of the field
1123
+ * @return: boolean true for visible, false for hidden
1124
+ */
1125
+ fieldIsVisible: function fieldIsVisible(field) {
1126
+ var $field = field instanceof jQuery ? field : dynamicforms.field_helpers.get(field, '$field');
1127
+ var fieldID = $field.attr('id');
1128
+ return $field.parents('#container-' + fieldID).is(":visible");
1129
+ },
1130
+
1131
+ getVisibleFields: function getVisibleFields(formID) {
1132
+ var res = [];
1133
+ $.each(dynamicforms.form_helpers.get(formID, 'fields'), function (fieldID, field) {
1134
+ if (dynamicforms.fieldIsVisible(field.$field))
1135
+ res.push(fieldID);
1136
+ });
1137
+ return res;
1138
+ },
1139
+
1140
+ /**
1141
+ * Pagination init for table.
1142
+ * Remembers url for loading next page and sets trigger element for start of loading next page
1143
+ * When trigger element is visible on screen loading starts
1144
+ *
1145
+ * @param formID: id of table object
1146
+ * @param link_next: url with cursor definition for loading next page
1147
+ * @param link_prev: url with cursor definition for loading previous page
1148
+ */
1149
+ paginatorInitTable: function paginatorInitTable(formID, link_next, link_prev) {
1150
+ dynamicforms.df_tbl_pagination.set(formID, 'link_next', link_next);
1151
+ if (dynamicforms.isLinkNext(link_next)) {
1152
+ var table_rows = $("#list-" + formID).find("tbody:first").find("tr");
1153
+ dynamicforms.df_tbl_pagination.set(formID, 'trigger_element', table_rows[0]);
1154
+ }
1155
+ },
1156
+
1157
+ /**
1158
+ * Checks if loading of next page should start
1159
+ * If trigger element is visible on screen
1160
+ *
1161
+ * @param formID: id of table object
1162
+ */
1163
+ paginatorCheckGetNextPage: function paginatorCheckGetNextPage(formID) {
1164
+ var trigger_element = dynamicforms.df_tbl_pagination.get(formID, 'trigger_element');
1165
+
1166
+ if (trigger_element != null) {
1167
+ var rect = trigger_element.getBoundingClientRect();
1168
+
1169
+ if (rect.height != 0 && rect.width != 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight))
1170
+ dynamicforms.paginatorGetNextPage(formID, '');
1171
+
1172
+ //TODO: Check both methods of determining whether control item is showing (unit tests for one and the other?)
1173
+ // problem with unit tests is that automated ones only run in Firefox
1174
+
1175
+ // var top_of_element = trigger_element.offset().top;
1176
+ // var bottom_of_element = top_of_element + trigger_element.outerHeight();
1177
+ // var top_of_screen = $(window).scrollTop();
1178
+ // var bottom_of_screen = top_of_screen + window.innerHeight;
1179
+ //
1180
+ // if (bottom_of_screen > top_of_element) {
1181
+ // dynamicforms.paginatorGetNextPage(formID);
1182
+ // }
1183
+ }
1184
+ },
1185
+
1186
+ /**
1187
+ * Calls server to get next page. When filter is given all current records will be deleted and only new ones will be
1188
+ * shown
1189
+ *
1190
+ * @param formID: id of table object
1191
+ * @param filter: filter params
1192
+ */
1193
+ paginatorGetNextPage: function paginatorGetNextPage(formID, filter) {
1194
+ var tbl_pagination = dynamicforms.df_tbl_pagination.get(formID, undefined);
1195
+ var link_next = '';
1196
+ if (filter.length) {
1197
+ link_next = dynamicforms.form_helpers.get(formID, 'reverseRowURL');
1198
+ if (link_next == undefined)
1199
+ link_next = window.location.origin + window.location.pathname
1200
+
1201
+ // here we will determine if the query has any additional parameters other than cursor and add them to filter
1202
+ var link_params = '';
1203
+ if (tbl_pagination != undefined && tbl_pagination.link_next != null)
1204
+ link_params = tbl_pagination.link_next.split('?')[1];
1205
+
1206
+ if (link_params != undefined) {
1207
+ link_params = link_params.split('&');
1208
+ var addfilter = '',
1209
+ filterFields = dynamicforms.filterFields(formID);
1210
+ filterFields.push('cursor');
1211
+ filterFields.push('ordering');
1212
+ for (var i = 0; i < link_params.length; i++) {
1213
+ var skip_link = false;
1214
+ for (var j = 0; j < filterFields.length; j++) {
1215
+ var cmpVal = filterFields[j] + '='
1216
+ if (link_params[i].substr(0, cmpVal.length) == cmpVal)
1217
+ skip_link = true;
1218
+ }
1219
+ if (skip_link) continue;
1220
+ addfilter += '&' + link_params[i];
1221
+ }
1222
+ if (filter != 'nofilter') {
1223
+ filter += addfilter;
1224
+ } else {
1225
+ var _filter = addfilter.substr(1);
1226
+ filter = _filter ? _filter : filter;
1227
+ }
1228
+ }
1229
+ if (filter != 'nofilter')
1230
+ link_next += '?' + filter;
1231
+ } else
1232
+ link_next = tbl_pagination.link_next;
1233
+
1234
+ /*console.log(link_next);
1235
+ console.log(tbl_pagination.last_link_next);
1236
+ console.log(filter.length);*/
1237
+
1238
+ if (dynamicforms.isLinkNext(link_next) && (link_next != tbl_pagination.last_link_next || filter.length)) {
1239
+ tbl_pagination.last_link_next = link_next;
1240
+
1241
+ var table = $("#list-" + formID).find("tbody:first");
1242
+ if (filter.length) {
1243
+ dynamicforms.df_tbl_pagination.set(formID, 'trigger_element', null);
1244
+ table.find('tr').remove();
1245
+ }
1246
+ $("#loading-" + formID).show();
1247
+ var curr_sequence = dynamicforms.filter_sequence;
1248
+ $.ajax({
1249
+ type: 'GET',
1250
+ headers: {'X-CSRFToken': dynamicforms.csrf_token, 'X-DF-RENDER-TYPE': 'table rows'},
1251
+ url: link_next
1252
+ }).done(function (data) {
1253
+ if (curr_sequence != dynamicforms.filter_sequence) {
1254
+ console.log('Update table action was discarded as the filter has changed.');
1255
+ return false;
1256
+ }
1257
+
1258
+ data = $(data).filter("tr");
1259
+ tbl_pagination.link_next = data[0].getAttribute('data-next');
1260
+
1261
+ if (data[0].getAttribute("data-title") != "NoData") {
1262
+ // remove elements, that are already shown - in case of new data insertion and order different than id.
1263
+ for (var i = data.length - 1; i >= 0; i--) {
1264
+ var data_id = data[i].getAttribute('data-id');
1265
+ if (data_id == null || table.find("tr[data-id='" + data_id + "']").length > 0)
1266
+ data.splice(i, 1);
1267
+ }
1268
+ } else if (table.find("tr").length > 0)
1269
+ data = [];
1270
+
1271
+ //TODO: If NoData comes back - I reached the end of dataset... do I even attempt further reading?
1272
+ // for log-type datasets where new data is frequently inserted, it might be useful.
1273
+ $("#loading-" + formID).hide();
1274
+ if (data.length > 0) {
1275
+ table.append(data);
1276
+ tbl_pagination.trigger_element = data[0];
1277
+ if (table.find("tr").length > 1 && table.find("tr[data-title=NoData]").length > 0) {
1278
+ table.find("tr[data-title=NoData]").remove()
1279
+ }
1280
+ }
1281
+ dynamicforms.paginatorCheckGetNextPage(formID);
1282
+ }).fail(function (xhr, status, error) {
1283
+ $("#loading-" + formID).hide();
1284
+ if (xhr.status == 403) {
1285
+ var body = '<p>You are not authorized for this action.</p>';
1286
+ dynamicforms.showModalDialog('Authorisation', body, [{title: 'OK', style: 'primary'}]);
1287
+ } else if (xhr.status == 401 && dynamicforms.DYNAMICFORMS.login_url) {
1288
+ var body = '<p>You will be redirected to login screen.</p>';
1289
+ dynamicforms.showModalDialog('Authorisation', body, [{
1290
+ title: 'Login',
1291
+ style: 'primary',
1292
+ callback: 'dynamicforms.redirectToLogin',
1293
+ parameters: {path_next: link_next.replace(window.location.origin, '')},
1294
+ }]);
1295
+ } else if (xhr.status != 0) {
1296
+ //Fail with status 0 can occcur if request is not done yet and user refreshes browser.
1297
+ //https://stackoverflow.com/a/12621912/9625282
1298
+ //General server error dlg should not display in this case
1299
+
1300
+ var body = 'General server error.'
1301
+ if (xhr.responseText) {
1302
+ body = xhr.responseText;
1303
+ }
1304
+ dynamicforms.showModalDialog('Server error', body, [{title: 'OK', style: 'primary'}]);
1305
+ }
1306
+ });
1307
+ }
1308
+ },
1309
+
1310
+ /*
1311
+ * Callback function to redirect to login page
1312
+ */
1313
+ redirectToLogin: function redirectToLogin() {
1314
+ var location = dynamicforms.DYNAMICFORMS.login_url;
1315
+ if (this.path_next) {
1316
+ location += '?next=' + this.path_next
1317
+ }
1318
+ window.location = location;
1319
+ },
1320
+
1321
+ /**
1322
+ * Goes through all tables that uses pagination and calls paginatorCheckGetNextPage function for them
1323
+ */
1324
+ paginatorCheckGetNextPageAll: function paginatorCheckGetNextPageAll() {
1325
+ for (var formID in dynamicforms.df_tbl_pagination.storage)
1326
+ dynamicforms.paginatorCheckGetNextPage(formID);
1327
+ },
1328
+
1329
+ /**
1330
+ * Registers filtering data on enter press in filter fields
1331
+ *
1332
+ * @param formID: id of table object
1333
+ * @param reverseRowURL: url for getting filtered data
1334
+ */
1335
+ registerFilterRowKeypress: function registerFilterRowKeypress(formID, reverseRowURL) {
1336
+ dynamicforms.form_helpers.set(formID, 'reverseRowURL', reverseRowURL);
1337
+ $($("#list-" + formID).find("tr.dynamicforms-filterrow")[0]).keypress(function (e) {
1338
+ if (e.which == 13) {
1339
+ dynamicforms.filterData(formID);
1340
+ }
1341
+ })
1342
+ },
1343
+
1344
+ filterFields: function filterFields(formID) {
1345
+ var res = [];
1346
+ $("#list-" + formID).find(".dynamicforms-filterrow th").each(function () {
1347
+ res.push($(this).attr("data-name"));
1348
+ });
1349
+ return res;
1350
+ },
1351
+
1352
+ /**
1353
+ * Prepares filter string and calls server to get filtered data
1354
+ *
1355
+ * @param formID: id of table object
1356
+ * @param returnDict: set to true if only filter data should be returned
1357
+ */
1358
+ filterData: function filterData(formID, returnDict) {
1359
+ dynamicforms.filter_sequence++;
1360
+
1361
+ if (returnDict == undefined)
1362
+ returnDict = false;
1363
+ var filter = {},
1364
+ order = dynamicforms.df_tbl_pagination.get(formID, 'ordering');
1365
+
1366
+ $("#list-" + formID).find(".dynamicforms-filterrow th").each(function (index) {
1367
+
1368
+ var element = $(this).find("[name='" + $(this).attr("data-name") + "']");
1369
+
1370
+ if (element.attr('type') == 'checkbox') {
1371
+ if (element.is(':checked'))
1372
+ filter[element.attr("name")] = true;
1373
+ else if (!element.is('[readonly]'))
1374
+ filter[element.attr("name")] = false;
1375
+ } else if (element.val() != null && element.val().length) {
1376
+ if (element.is('select') && element.is("[multiple]")) {
1377
+ var delimiter = element.attr('value_delimiter');
1378
+ if (delimiter == undefined)
1379
+ delimiter = ',';
1380
+ filter[element.attr("name")] = element.val().join(delimiter);
1381
+ } else
1382
+ filter[element.attr("name")] = element.val();
1383
+ }
1384
+ });
1385
+ if (returnDict)
1386
+ return filter;
1387
+ filter = jQuery.param(filter);
1388
+ if (!filter.length) {
1389
+ if (order != null && order != '') filter = 'ordering=' + order;
1390
+ else filter = 'nofilter';
1391
+ }
1392
+ else if (order != null && order != '') filter += '&ordering=' + order;
1393
+
1394
+ dynamicforms.paginatorGetNextPage(formID, filter);
1395
+ },
1396
+
1397
+ /**
1398
+ * "Standard" function which is called after filter button in header is clicked.
1399
+ * It finds id of table object and calls filterData function with it.
1400
+ *
1401
+ * @param event: OnClick event from which we get id of table object
1402
+ */
1403
+ defaultFilter: function defaultFilter(event) {
1404
+ // And show the dialog
1405
+ var formId = (dynamicforms.DYNAMICFORMS.jquery_ui) ?
1406
+ $(event.currentTarget).parents('div.accordion').find('div.ui-accordion-content').find('table[id^="list-"]')[0].getAttribute('id').replace('list-', '') :
1407
+ $(event.currentTarget).parents('div.card').find('div.card-body').find('table[id^="list-"]')[0].getAttribute('id').replace('list-', '');
1408
+ dynamicforms.filterData(formId);
1409
+ },
1410
+
1411
+ isLinkNext: function isLinkNext(link_next) {
1412
+ return link_next != null && link_next != undefined && link_next != '' && link_next != "None";
1413
+ },
1414
+
1415
+ select2Opening: function select2Opening(evt, $select2, fnc, params) {
1416
+ if ($select2.data('unselecting')) {
1417
+ $select2.removeData('unselecting');
1418
+ evt.preventDefault();
1419
+ } else if (fnc != null){
1420
+ if(params != undefined)
1421
+ fnc(evt, $select2, params);
1422
+ else
1423
+ fnc(evt, $select2);
1424
+ }
1425
+
1426
+
1427
+ },
1428
+
1429
+ select2Unselecting: function select2Unselecting($select2) {
1430
+ $select2.data('unselecting', true);
1431
+ },
1432
+
1433
+ select2UpdateConfiguration: function select2UpdateConfiguration($select2, conf) {
1434
+ var sel2Conf = $select2.data('sel2Conf');
1435
+ Object.keys(conf).forEach(function(key) {
1436
+ sel2Conf[key] = conf[key];
1437
+ });
1438
+ $select2.select2("destroy").select2(sel2Conf);
1439
+ $select2.data('sel2Conf', sel2Conf);
1440
+ },
1441
+
1442
+ orderingColumnClicked: function orderingColumnClicked(event, $col, formID) {
1443
+ var ordering_index = dynamicforms.getOrderingAndIndex($col),
1444
+ index = ordering_index.index - 1,
1445
+ ordering = dynamicforms.getCurrentOrder(formID).segments;
1446
+
1447
+ if (!$col.hasClass('ordering')) return; // Only process columns that are sortable
1448
+
1449
+ this.stopEventPropagation(event);
1450
+
1451
+ function renumber() {
1452
+ for (var i = 0; i < ordering.length; i++)
1453
+ ordering[i].index = i + 1;
1454
+ }
1455
+
1456
+ if (event.altKey) {
1457
+ // Show dialog with sort order options
1458
+ }
1459
+ else if (event.ctrlKey && event.shiftKey) {
1460
+ // remove segment from ordering
1461
+ if (index >= 0) {
1462
+ ordering.splice(index, 1);
1463
+ renumber();
1464
+ dynamicforms.setCurrentOrder(formID, ordering);
1465
+ }
1466
+ }
1467
+ else if (event.ctrlKey) {
1468
+ // Move the segment to top
1469
+ if (index >= 0) ordering.splice(index, 1);
1470
+ if (ordering_index.direction === null) ordering_index.direction = true;
1471
+ ordering.splice(0, 0, ordering_index);
1472
+ renumber();
1473
+ dynamicforms.setCurrentOrder(formID, ordering);
1474
+ }
1475
+ else if (event.shiftKey) {
1476
+ // Change segment sort direction (and add it to sort segments list if not already there)
1477
+ // if shift is pressed add segment to existing ones. if not, set this column as the only segment of sort
1478
+ if (ordering_index.index < 1) {
1479
+ ordering_index.direction = ordering_index.direction !== false;
1480
+ ordering_index.index = ordering.length + 1;
1481
+ ordering.push(ordering_index);
1482
+ }
1483
+ else {
1484
+ ordering[index].direction = ordering[index].direction === false;
1485
+ }
1486
+ dynamicforms.setCurrentOrder(formID, ordering);
1487
+ }
1488
+ else {
1489
+ ordering_index.index = 1;
1490
+ if (ordering_index.direction === null) ordering_index.direction = true;
1491
+ else if (ordering_index.direction === true) ordering_index.direction = false;
1492
+ else {
1493
+ ordering_index.direction = null;
1494
+ ordering_index.index = 0;
1495
+ }
1496
+ dynamicforms.setCurrentOrder(formID, [ordering_index]);
1497
+ }
1498
+ },
1499
+
1500
+ getOrderingAndIndex: function getOrderingAndIndex($col) {
1501
+ var dir = null,
1502
+ index = 0,
1503
+ fieldName = null;
1504
+ if ($col.hasClass('ordering')) {
1505
+ fieldName = $col.attr('data-field-name');
1506
+ if ($col.hasClass('asc')) dir = true; // ascending
1507
+ else if ($col.hasClass('desc')) dir = false; // ascending
1508
+ for (var i = 1; i <= 20; i++) {
1509
+ if ($col.hasClass('seg-' + i)) {
1510
+ index = i;
1511
+ break;
1512
+ }
1513
+ }
1514
+ }
1515
+ return {direction: dir, index: index, fieldName: fieldName};
1516
+ },
1517
+
1518
+ renderOrderingIndicator: function renderOrderingIndicator($col, ordering_index) {
1519
+ var dir = '\u2195',
1520
+ index = '';
1521
+
1522
+ if ($col.hasClass('ordering')) {
1523
+ if (ordering_index.direction === true) dir = '\u2191'; // ascending
1524
+ else if (ordering_index.direction === false) dir = '\u2193'; // ascending
1525
+ if (ordering_index.index) index = String.fromCharCode(0x2460 + ordering_index.index - 1);
1526
+ $col.find('span.ordering').text(dir + index);
1527
+ }
1528
+ },
1529
+
1530
+ setCurrentOrder: function setCurrentOrder(formID, ordering) {
1531
+ var order = {};
1532
+ for (var i = 0; i < ordering.length; i++)
1533
+ order[ordering[i].fieldName] = ordering[i];
1534
+
1535
+ $('#list-' + formID + '>thead>tr>th').each(function() {
1536
+ var $col = $(this),
1537
+ fieldName = $col.attr('data-field-name');
1538
+ if ($col.hasClass('ordering')) {
1539
+ var ordr = order[fieldName];
1540
+
1541
+ // First remove all existing sorting classes
1542
+ $col.removeClass('asc');
1543
+ $col.removeClass('desc');
1544
+ $col.removeClass('unsorted');
1545
+ $col.removeClass(function(index, className) {
1546
+ return (className.match(/(^|\s)seg-\S+/g) || []).join(' ');
1547
+ });
1548
+
1549
+ // Then add the new classes
1550
+ if (ordr == null || ordr.index < 1) $col.addClass('unsorted');
1551
+ else {
1552
+ $col.addClass(ordr.direction === true ? 'asc' : 'desc');
1553
+ $col.addClass('seg-' + ordr.index);
1554
+ }
1555
+ }
1556
+ });
1557
+ dynamicforms.getInitialOrdering(formID, false);
1558
+ dynamicforms.filterData(formID);
1559
+ },
1560
+
1561
+ getCurrentOrder: function getCurrentOrder(formID) {
1562
+ var ordering = [],
1563
+ order = [];
1564
+ $('#list-' + formID + '>thead>tr>th').each(function() {
1565
+ var $col = $(this);
1566
+ if ($col.hasClass('ordering')) {
1567
+ var ordering_index = dynamicforms.getOrderingAndIndex($col);
1568
+ if (ordering_index.index > 0) ordering.push(ordering_index);
1569
+ }
1570
+ });
1571
+ function cmp(a, b) {
1572
+ if (a.index > b.index) return 1;
1573
+ else if (a.index < b.index) return -1;
1574
+ return 0;
1575
+ }
1576
+ ordering.sort(cmp);
1577
+ for (var i = 0; i < ordering.length; i++) {
1578
+ if (ordering[i].direction === true)
1579
+ order.push(ordering[i].fieldName);
1580
+ else
1581
+ order.push('-' + ordering[i].fieldName);
1582
+ }
1583
+ return {order: order.join(','), segments: ordering};
1584
+ },
1585
+
1586
+ getInitialOrdering: function getInitialOrdering(formID, assignOnClickListener) {
1587
+ $('#list-' + formID + '>thead>tr>th').each(function() {
1588
+ var $col = $(this);
1589
+ if ($col.hasClass('ordering')) {
1590
+ var ordering_index = dynamicforms.getOrderingAndIndex($col);
1591
+ dynamicforms.renderOrderingIndicator($col, ordering_index);
1592
+ if (assignOnClickListener !== false) {
1593
+ $col.on('click', function colclick(evt) {
1594
+ dynamicforms.orderingColumnClicked(evt, $col, formID);
1595
+ });
1596
+ }
1597
+ }
1598
+ });
1599
+ dynamicforms.df_tbl_pagination.set(formID, 'ordering', dynamicforms.getCurrentOrder(formID).order);
1600
+ },
1601
+
1602
+ select2CopyValue: function select2CopyValue(field) {
1603
+ var select_text = $("#" + field).select2('data')[0].text
1604
+ navigator.clipboard.writeText(select_text)
1605
+ },
1606
+
1607
+ togglePasswordField: function togglePasswordField(field) {
1608
+ version = dynamicforms.DYNAMICFORMS.bootstrap_version;
1609
+
1610
+ if (version == 'v4') {
1611
+ var field_class = 'password-field';
1612
+ var field_class_slash = 'password-field-slash';
1613
+ } else if (version == 'v3') {
1614
+ var field_class = 'glyphicon-eye-open';
1615
+ var field_class_slash = 'glyphicon-eye-close';
1616
+ } else {
1617
+ var field_class = 'ui-icon-circle-check';
1618
+ var field_class_slash = 'ui-icon-circle-close';
1619
+ }
1620
+
1621
+
1622
+ if ($("#" + field).attr('type') == 'password') {
1623
+ $("#" + field).attr('type', 'text');
1624
+ $("#pwf-" + field).toggleClass(field_class, false);
1625
+ $("#pwf-" + field).toggleClass(field_class_slash, true);
1626
+ } else {
1627
+ $("#" + field).attr('type', 'password');
1628
+ $("#pwf-" + field).toggleClass(field_class, true);
1629
+ $("#pwf-" + field).toggleClass(field_class_slash, false);
1630
+ }
1631
+ },
1632
+
1633
+ initRTFField: function initRTFField(fieldId) {
1634
+ var interval = null;
1635
+ var editor = null;
1636
+ var timestamp = Math.floor(Date.now() / 1000);
1637
+ var initFunction = function () {
1638
+ interval = window.setInterval(function () {
1639
+ if ($('#' + fieldId).length === 1) {
1640
+ var ckeditor_selector = 'ckeditor-' + fieldId
1641
+ ClassicEditor
1642
+ .create(document.querySelector("[id='" + fieldId + "']"), {
1643
+ toolbar: {
1644
+ removeItems: ['imageUpload', 'mediaEmbed'],
1645
+ items: ["heading", "|", "bold", "italic", "link", "fontColor", "bulletedList", "numberedList", "|", "indent",
1646
+ "outdent", "|", "imageUpload", "blockQuote", "insertTable", "mediaEmbed", "undo", "redo"],
1647
+ },
1648
+ fontColor: {
1649
+ colors: [
1650
+ {
1651
+ label: 'Alert - Primary',
1652
+ color: 'primary',
1653
+ },
1654
+ {
1655
+ color: 'secondary',
1656
+ label: 'Alert - Secondary'
1657
+ },
1658
+ {
1659
+ color: 'success',
1660
+ label: 'Alert - Success'
1661
+ },
1662
+ {
1663
+ color: 'danger',
1664
+ label: 'Alert - Danger'
1665
+ },
1666
+ {
1667
+ color: 'warning',
1668
+ label: 'Alert - Warning',
1669
+ },
1670
+ {
1671
+ color: 'info',
1672
+ label: 'Alert - Info',
1673
+ },
1674
+ ]
1675
+ },
1676
+ heading: {
1677
+ options: [
1678
+ {model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph'},
1679
+ {model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1'},
1680
+ {model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2'},
1681
+ {
1682
+ model: 'div-alert-primary',
1683
+ view: {
1684
+ name: 'div',
1685
+ classes: ['alert', 'alert-primary'],
1686
+ },
1687
+ title: 'Alert - Primary',
1688
+ class: 'ck-heading_alert-primary',
1689
+ converterPriority: 'high',
1690
+ },
1691
+ {
1692
+ model: 'div-alert-secondary',
1693
+ view: {
1694
+ name: 'div',
1695
+ classes: ['alert', 'alert-secondary'],
1696
+ },
1697
+ title: 'Alert - Secondary',
1698
+ class: 'ck-heading_alert-secondary',
1699
+ converterPriority: 'high',
1700
+ },
1701
+ {
1702
+ model: 'div-alert-success',
1703
+ view: {
1704
+ name: 'div',
1705
+ classes: ['alert', 'alert-success'],
1706
+ },
1707
+ title: 'Alert - Success',
1708
+ class: 'ck-heading_alert-success',
1709
+ converterPriority: 'high',
1710
+ },
1711
+ {
1712
+ model: 'div-alert-danger',
1713
+ view: {
1714
+ name: 'div',
1715
+ classes: ['alert', 'alert-danger'],
1716
+ },
1717
+ title: 'Alert - Danger',
1718
+ class: 'ck-heading_alert-danger',
1719
+ converterPriority: 'high',
1720
+ },
1721
+ {
1722
+ model: 'div-alert-warning',
1723
+ view: {
1724
+ name: 'div',
1725
+ classes: ['alert', 'alert-warning'],
1726
+ },
1727
+ title: 'Alert - Warning',
1728
+ class: 'ck-heading_alert-warning',
1729
+ converterPriority: 'high',
1730
+ },
1731
+ {
1732
+ model: 'div-alert-info',
1733
+ view: {
1734
+ name: 'div',
1735
+ classes: ['alert', 'alert-info'],
1736
+ },
1737
+ title: 'Alert - Info',
1738
+ class: 'ck-heading_alert-info',
1739
+ converterPriority: 'high',
1740
+ },
1741
+ ],
1742
+ },
1743
+ })
1744
+ .then(editor => {
1745
+ ckeditor_selector = editor;
1746
+ })
1747
+ .catch(error => {
1748
+ console.error(error);
1749
+ });
1750
+ window.clearInterval(interval);
1751
+ }
1752
+ if (Math.floor(Date.now() / 1000) - timestamp > 1) {
1753
+ window.clearInterval(interval)
1754
+ }
1755
+ }, 100);
1756
+ }
1757
+ initFunction();
1758
+ },
1759
+
1760
+ handleRTFFieldsValue: function handleRTFFieldsValue(_data, $_form) {
1761
+ for (var key in _data) {
1762
+ if (_data.hasOwnProperty(key)) {
1763
+ var textareaInput = $_form.find('textarea[name="' + key + '"]')
1764
+ if (textareaInput.length === 1 && textareaInput.hasClass('.ck-editor__editable')) {
1765
+ var domEditableElement = document.querySelector('.ck-editor__editable');
1766
+ if (domEditableElement !== 'undefined') {
1767
+ _data[key] = domEditableElement.ckeditorInstance.getData();
1768
+ }
1769
+ }
1770
+ }
1771
+ }
1772
+ },
1773
+
1774
+ slugify: function slugify(string) {
1775
+ string = string.toLowerCase();
1776
+ string = string.replace(/[^a-zA-Z0-9]+/g, '-');
1777
+ return string;
1778
+ },
1779
+
1780
+ modalDialogCustomCommand: function modalDialogCustomCommand(button) {
1781
+ return function () {
1782
+ if (button['callback']) {
1783
+ var customFunction = eval(button['callback']);
1784
+ if (typeof customFunction == 'function') {
1785
+ customFunction.apply(button['parameters']);
1786
+ }
1787
+ }
1788
+ if (dynamicforms.DYNAMICFORMS.jquery_ui) {
1789
+ $(this).dialog('close');
1790
+ }
1791
+ };
1792
+ },
1793
+
1794
+ showModalDialog: function showModalDialog(title, body, buttons, size) {
1795
+ var $dlg = $("#df-modal-dialog-container").clone();
1796
+ $dlg.attr('id', 'dialog-' + dynamicforms.slugify(title));
1797
+ $(document.body).append($dlg);
1798
+
1799
+ buttons = buttons || [
1800
+ {title: 'Cancel'},
1801
+ {title: 'OK', style: 'primary'},
1802
+ ];
1803
+
1804
+ $dlg.on('show.bs.modal', function (event) {
1805
+ var footer = '';
1806
+ buttons.forEach(function (button) {
1807
+ var btn_id = 'dlg-btn-' + dynamicforms.slugify(button['title']);
1808
+ var button_style = 'secondary';
1809
+ if (button['style']) {
1810
+ button_style = button['style'];
1811
+ }
1812
+
1813
+ footer = footer.concat('<button id=' + btn_id + ' type="button" class="btn btn-' + button_style + '" data-dismiss="modal">' + button['title'] + '</button>');
1814
+ });
1815
+
1816
+ $dlg.find('.modal-title').text(title);
1817
+ $dlg.find('.modal-body').html(body);
1818
+ $dlg.find('.modal-footer').html(footer);
1819
+ });
1820
+
1821
+ $dlg.on('shown.bs.modal', function (event) {
1822
+ buttons.forEach(function (button) {
1823
+ var fn = dynamicforms.modalDialogCustomCommand(button);
1824
+
1825
+ if (button) {
1826
+ var button_id = 'dlg-btn-' + dynamicforms.slugify(button['title']);
1827
+ $('#' + button_id).on('click', {callback: button['callback'], parameters: button['parameters']}, fn);
1828
+ }
1829
+ });
1830
+ });
1831
+
1832
+ $dlg.on('hidden.bs.modal', function (event) {
1833
+ $dlg.remove();
1834
+ });
1835
+
1836
+ // Show the dialog
1837
+ if (dynamicforms.DYNAMICFORMS.jquery_ui) {
1838
+ var btns = [];
1839
+ buttons.forEach(function (button) {
1840
+ var fn = dynamicforms.modalDialogCustomCommand(button);
1841
+ btns.push({text: button['title'], click: fn});
1842
+ });
1843
+
1844
+ $dlg.html(body);
1845
+ var dialog = $dlg.dialog({
1846
+ resizable: false,
1847
+ height: "auto",
1848
+ modal: true,
1849
+ buttons: btns,
1850
+ });
1851
+
1852
+ dialog.dialog("open");
1853
+ } else {
1854
+ if(size != undefined && size != '')
1855
+ $dlg.find('div.modal-dialog').addClass('modal-' + size);
1856
+ $dlg.modal();
1857
+ }
1858
+
1859
+ },
1860
+ stopEventPropagation: function stopEventPropagation(e){
1861
+ if (!e) {
1862
+ e = window.event;
1863
+ }
1864
+ e.cancelBubble = true;
1865
+ if (e.stopPropagation) {
1866
+ e.stopPropagation();
1867
+ }
1868
+ }
1869
+ };
1870
+
1871
+ $(document).ready(function () {
1872
+ // Let's get initial field values from the forms that are on-page already
1873
+ // TODO: Is this jQuery-specific? Will vue.js page also contain some kind of initializer or will everything just work?
1874
+ // TODO: also might be prudent to just move this to base_form.html. we already process dialogs separately...
1875
+ $('.dynamicforms-form').each(function (idx, form) {
1876
+ dynamicforms.serializeForm($(form), 'final');
1877
+ });
1878
+ window.setInterval(dynamicforms.paginatorCheckGetNextPageAll, 100);
1879
+
1880
+ var $overlay = $("<div id='df-overlay' style='position: fixed; display: none; width: 100%; height: 100%; top: 0; " +
1881
+ "left: 0; right: 0; bottom: 0; cursor: pointer; z-index: auto'></div>");
1882
+ $("body").append($overlay);
1883
+ })