@saltcorn/mobile-app 0.7.3-beta.3 → 0.7.3
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.
- package/package.json +4 -1
- package/www/index.html +27 -14
- package/www/js/bundles/@saltcorn/any-bootstrap-theme.bundle.js +28 -0
- package/www/js/bundles/@saltcorn/ckeditor4.bundle.js +28 -0
- package/www/js/bundles/@saltcorn/html.bundle.js +28 -0
- package/www/js/bundles/@saltcorn/select2.bundle.js +28 -0
- package/www/js/bundles/@saltcorn/shared-files.bundle.js +28 -0
- package/www/js/bundles/@saltcorn/xncolorpicker.bundle.js +28 -0
- package/www/js/bundles/base_plugin.bundle.js +171 -0
- package/www/js/bundles/colorpick.bundle.js +28 -0
- package/www/js/bundles/colors.bundle.js +28 -0
- package/www/js/bundles/common_chunks.bundle.js +6358 -0
- package/www/js/bundles/data.bundle.js +1269 -0
- package/www/js/bundles/daterangepicker.bundle.js +28 -0
- package/www/js/bundles/flatpickr-date.bundle.js +28 -0
- package/www/js/bundles/fullcalendar.bundle.js +28 -0
- package/www/js/bundles/json.bundle.js +28 -0
- package/www/js/bundles/markup.bundle.js +331 -0
- package/www/js/bundles/sbadmin2.bundle.js +39 -0
- package/www/js/bundles/svelte-gantt.bundle.js +39 -0
- package/www/js/bundles/system-info.bundle.js +28 -0
- package/www/js/bundles/tabulator.bundle.js +28 -0
- package/www/js/{utils/login_form.js → routes/auth.js} +16 -1
- package/www/js/routes/init.js +9 -0
- package/www/js/routes/view.js +31 -2
- package/www/js/utils/global_utils.js +9 -0
- package/www/js/utils/iframe_view_utils.js +3 -3
- package/www/npm_packages/axios.min.js +3 -0
- package/www/npm_packages/jwt-decode.js +123 -0
- package/www/npm_packages/universal-router.min.js +3 -0
- package/www/plugins/public/@saltcorn/any-bootstrap-theme/sidebar-3.css +41 -0
- package/www/plugins/public/@saltcorn/ckeditor4/adapters/jquery.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/ckeditor.js +1286 -0
- package/www/plugins/public/@saltcorn/ckeditor4/config.js +38 -0
- package/www/plugins/public/@saltcorn/ckeditor4/contents.css +208 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/af.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ar.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/az.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/bg.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/bn.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/bs.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ca.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/cs.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/cy.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/da.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/de-ch.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/de.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/el.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/en-au.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/en-ca.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/en-gb.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/en.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/eo.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/es-mx.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/es.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/et.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/eu.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/fa.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/fi.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/fo.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/fr-ca.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/fr.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/gl.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/gu.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/he.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/hi.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/hr.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/hu.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/id.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/is.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/it.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ja.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ka.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/km.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ko.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ku.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/lt.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/lv.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/mk.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/mn.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ms.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/nb.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/nl.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/no.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/oc.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/pl.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/pt-br.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/pt.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ro.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ru.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/si.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/sk.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/sl.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/sq.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/sr-latn.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/sr.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/sv.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/th.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/tr.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/tt.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/ug.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/uk.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/vi.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/zh-cn.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/lang/zh.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/a11yhelp.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/_translationstatus.txt +25 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/af.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ar.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/az.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/bg.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ca.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/cs.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/cy.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/da.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/de-ch.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/de.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/el.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/en-au.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/en-gb.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/en.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/eo.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/es-mx.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/es.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/et.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/eu.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/fa.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/fi.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/fo.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/fr-ca.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/fr.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/gl.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/gu.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/he.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/hi.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/hr.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/hu.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/id.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/it.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ja.js +9 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/km.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ko.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ku.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/lt.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/lv.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/mk.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/mn.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/nb.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/nl.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/no.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/oc.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/pl.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/pt-br.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/pt.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ro.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ru.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/si.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/sk.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/sl.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/sq.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/sr-latn.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/sr.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/sv.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/th.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/tr.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/tt.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/ug.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/uk.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/vi.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/zh-cn.js +9 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/a11yhelp/dialogs/lang/zh.js +9 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/about/dialogs/about.js +8 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/about/dialogs/hidpi/logo_ckeditor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/about/dialogs/logo_ckeditor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/clipboard/dialogs/paste.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/icons/bgcolor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/icons/hidpi/bgcolor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/icons/hidpi/textcolor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/icons/textcolor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/af.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ar.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/az.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/bg.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/bn.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/bs.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ca.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/cs.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/cy.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/da.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/de-ch.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/de.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/el.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/en-au.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/en-ca.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/en-gb.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/en.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/eo.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/es-mx.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/es.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/et.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/eu.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/fa.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/fi.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/fo.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/fr-ca.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/fr.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/gl.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/gu.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/he.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/hi.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/hr.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/hu.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/id.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/is.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/it.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ja.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ka.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/km.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ko.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ku.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/lt.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/lv.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/mk.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/mn.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ms.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/nb.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/nl.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/no.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/oc.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/pl.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/pt-br.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/pt.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ro.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ru.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/si.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/sk.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/sl.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/sq.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/sr-latn.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/sr.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/sv.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/th.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/tr.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/tt.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/ug.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/uk.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/vi.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/zh-cn.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/lang/zh.js +75 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/colorbutton/plugin.js +1009 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/dialog/dialogDefinition.js +4 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/dialog/styles/dialog.css +18 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/dialogadvtab/plugin.js +196 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/af.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ar.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/az.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/bg.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/bn.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/bs.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ca.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/cs.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/cy.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/da.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/de-ch.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/de.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/el.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/en-au.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/en-ca.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/en-gb.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/en.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/eo.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/es-mx.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/es.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/et.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/eu.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/fa.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/fi.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/fo.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/fr-ca.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/fr.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/gl.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/gu.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/he.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/hi.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/hr.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/hu.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/id.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/is.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/it.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ja.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ka.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/km.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ko.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ku.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/lt.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/lv.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/mk.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/mn.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ms.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/nb.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/nl.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/no.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/oc.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/pl.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/pt-br.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/pt.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ro.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ru.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/si.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/sk.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/sl.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/sq.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/sr-latn.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/sr.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/sv.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/th.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/tr.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/tt.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/ug.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/uk.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/vi.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/zh-cn.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/lang/zh.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/font/plugin.js +512 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/icons.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/icons_hidpi.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/image/dialogs/image.js +44 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/image/images/noimage.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/hidpi/justifyblock.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/hidpi/justifycenter.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/hidpi/justifyleft.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/hidpi/justifyright.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/justifyblock.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/justifycenter.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/justifyleft.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/icons/justifyright.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/justify/plugin.js +265 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/link/dialogs/anchor.js +8 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/link/dialogs/link.js +30 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/link/images/anchor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/link/images/hidpi/anchor.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/magicline/images/hidpi/icon-rtl.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/magicline/images/hidpi/icon.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/magicline/images/icon-rtl.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/magicline/images/icon.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/panelbutton/plugin.js +161 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/pastefromgdocs/filter/default.js +8 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/pastefromlibreoffice/filter/default.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/pastefromword/filter/default.js +42 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/pastetools/filter/common.js +24 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/pastetools/filter/image.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/CHANGELOG.md +4 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/LICENSE.md +28 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/README.md +81 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/dialogs/dialog.css +23 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/dialogs/options.js +32 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/dialogs/toolbar.css +71 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/scayt/skins/moono-lisa/scayt.css +25 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/_translationstatus.txt +20 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/af.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ar.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/az.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/bg.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ca.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/cs.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/cy.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/da.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/de-ch.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/de.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/el.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/en-au.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/en-ca.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/en-gb.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/en.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/eo.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/es-mx.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/es.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/et.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/eu.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/fa.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/fi.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/fr-ca.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/fr.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/gl.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/he.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/hr.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/hu.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/id.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/it.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ja.js +9 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/km.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ko.js +10 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ku.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/lt.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/lv.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/nb.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/nl.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/no.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/oc.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/pl.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/pt-br.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/pt.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ro.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ru.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/si.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/sk.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/sl.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/sq.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/sr-latn.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/sr.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/sv.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/th.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/tr.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/tt.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/ug.js +13 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/uk.js +12 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/vi.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/zh-cn.js +9 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/lang/zh.js +9 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/specialchar/dialogs/specialchar.js +14 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/table/dialogs/table.js +22 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/tableselection/styles/tableselection.css +36 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/tabletools/dialogs/tableCell.js +18 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/widget/images/handle.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/LICENSE.md +28 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/README.md +84 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/dialogs/ciframe.html +66 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/dialogs/tmpFrameset.html +52 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/dialogs/wsc.css +82 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/dialogs/wsc.js +90 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/dialogs/wsc_ie.js +11 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/icons/hidpi/spellchecker.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/icons/spellchecker.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/af.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ar.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/bg.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/bn.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/bs.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ca.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/cs.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/cy.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/da.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/de.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/el.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/en-au.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/en-ca.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/en-gb.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/en.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/eo.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/es.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/et.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/eu.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/fa.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/fi.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/fo.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/fr-ca.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/fr.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/gl.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/gu.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/he.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/hi.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/hr.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/hu.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/is.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/it.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ja.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ka.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/km.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ko.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ku.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/lt.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/lv.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/mk.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/mn.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ms.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/nb.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/nl.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/no.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/pl.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/pt-br.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/pt.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ro.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ru.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/sk.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/sl.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/sr-latn.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/sr.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/sv.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/th.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/tr.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/ug.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/uk.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/vi.js +2 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/zh-cn.js +1 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/lang/zh.js +1 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/plugin.js +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/plugins/wsc/skins/moono-lisa/wsc.css +43 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/dialog.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/dialog_ie.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/dialog_ie8.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/dialog_iequirks.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/editor.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/editor_gecko.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/editor_ie.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/editor_ie8.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/editor_iequirks.css +5 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/icons.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/icons_hidpi.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/arrow.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/close.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/hidpi/close.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/hidpi/lock-open.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/hidpi/lock.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/hidpi/refresh.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/lock-open.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/lock.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/refresh.png +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/images/spinner.gif +0 -0
- package/www/plugins/public/@saltcorn/ckeditor4/skins/moono-lisa/readme.md +46 -0
- package/www/plugins/public/@saltcorn/ckeditor4/styles.js +137 -0
- package/www/plugins/public/@saltcorn/ckeditor4/vendor/promise.js +13 -0
- package/www/plugins/public/@saltcorn/shared-files/shared-files-client.js +1 -1
- package/www/static_assets/17d4adcb31668468/codemirror.css +350 -0
- package/www/static_assets/17d4adcb31668468/codemirror.js +9813 -0
- package/www/static_assets/17d4adcb31668468/jquery-3.6.0.min.js +2 -0
- package/www/static_assets/17d4adcb31668468/saltcorn-common.js +634 -0
- package/www/static_assets/17d4adcb31668468/saltcorn.css +305 -0
- package/www/static_assets/17d4adcb31668468/saltcorn.js +447 -0
- package/www/static_assets/17d4adcb31668468/socket.io.min.js +7 -0
- package/www/static_assets/1f89b5e9fd7b0c74/codemirror.css +350 -0
- package/www/static_assets/1f89b5e9fd7b0c74/codemirror.js +9813 -0
- package/www/static_assets/1f89b5e9fd7b0c74/jquery-3.6.0.min.js +2 -0
- package/www/static_assets/1f89b5e9fd7b0c74/saltcorn-common.js +634 -0
- package/www/static_assets/1f89b5e9fd7b0c74/saltcorn.css +305 -0
- package/www/static_assets/1f89b5e9fd7b0c74/saltcorn.js +447 -0
- package/www/static_assets/1f89b5e9fd7b0c74/socket.io.min.js +7 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
|
|
3
|
+
* This devtool is neither made for production nor for readable output files.
|
|
4
|
+
* It uses "eval()" calls to create a separate source file in the browser devtools.
|
|
5
|
+
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
|
6
|
+
* or disable the default devtool with "devtool: false".
|
|
7
|
+
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
|
8
|
+
*/
|
|
9
|
+
(function webpackUniversalModuleDefinition(root, factory) {
|
|
10
|
+
if(typeof exports === 'object' && typeof module === 'object')
|
|
11
|
+
module.exports = factory();
|
|
12
|
+
else if(typeof define === 'function' && define.amd)
|
|
13
|
+
define([], factory);
|
|
14
|
+
else if(typeof exports === 'object')
|
|
15
|
+
exports["saltcorn"] = factory();
|
|
16
|
+
else
|
|
17
|
+
root["saltcorn"] = root["saltcorn"] || {}, root["saltcorn"]["base_plugin"] = factory();
|
|
18
|
+
})(self, function() {
|
|
19
|
+
return (self["webpackChunksaltcorn_name_"] = self["webpackChunksaltcorn_name_"] || []).push([["base_plugin"],{
|
|
20
|
+
|
|
21
|
+
/***/ "../saltcorn-base-plugin/index.js":
|
|
22
|
+
/*!****************************************!*\
|
|
23
|
+
!*** ../saltcorn-base-plugin/index.js ***!
|
|
24
|
+
\****************************************/
|
|
25
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
26
|
+
|
|
27
|
+
eval("/**\n * @category saltcorn-base-plugin\n * @module saltcorn-base-plugin/index\n */\n\n/** \n * @type {base-plugin/index}\n */\nconst plugin = __webpack_require__(/*! @saltcorn/data/base-plugin */ \"../saltcorn-data/dist/base-plugin/index.js\");\nmodule.exports = plugin;\n\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-base-plugin/index.js?");
|
|
28
|
+
|
|
29
|
+
/***/ }),
|
|
30
|
+
|
|
31
|
+
/***/ "../saltcorn-data/dist/base-plugin/actions.js":
|
|
32
|
+
/*!****************************************************!*\
|
|
33
|
+
!*** ../saltcorn-data/dist/base-plugin/actions.js ***!
|
|
34
|
+
\****************************************************/
|
|
35
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
36
|
+
|
|
37
|
+
"use strict";
|
|
38
|
+
eval("\n/**\n * Action description\n * @category saltcorn-data\n * @module base-plugin/actions\n * @subcategory base-plugin\n */\nconst fetch = __webpack_require__(/*! node-fetch */ \"../../node_modules/node-fetch/browser.js\");\nconst vm = __webpack_require__(/*! vm */ \"../../node_modules/vm-browserify/index.js\");\nconst Table = __webpack_require__(/*! ../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst View = __webpack_require__(/*! ../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst { getState } = __webpack_require__(/*! ../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst User = __webpack_require__(/*! ../models/user */ \"../saltcorn-data/dist/models/user.js\");\nconst Trigger = __webpack_require__(/*! ../models/trigger */ \"../saltcorn-data/dist/models/trigger.js\");\nconst { getMailTransport, viewToEmailHtml } = __webpack_require__(/*! ../models/email */ \"../saltcorn-data/dist/mobile-mocks/models/email.js\");\nconst { get_async_expression_function, recalculate_for_stored, } = __webpack_require__(/*! ../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\nconst { div, code } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { sleep } = __webpack_require__(/*! ../utils */ \"../saltcorn-data/dist/utils.js\");\nconst db = __webpack_require__(/*! ../db */ \"../saltcorn-data/dist/db/index.js\");\nconst { isNode } = __webpack_require__(/*! ../utils */ \"../saltcorn-data/dist/utils.js\");\n//action use cases: field modify, like/rate (insert join), notify, send row to webhook\n// todo add translation\n/**\n * @param opts\n * @param opts.row\n * @param opts.table\n * @param opts.channel\n * @param opts.configuration\n * @param opts.user\n * @param opts.rest\n * @returns\n */\nconst run_code = async ({ row, table, channel, configuration: { code, run_where }, user, ...rest }) => {\n if (run_where === \"Client page\")\n return { eval_js: code };\n if (!isNode() && run_where === \"Server\")\n return { error: \"Running server code is not yet implemented.\" };\n const Actions = {};\n Object.entries(getState().actions).forEach(([k, v]) => {\n Actions[k] = (args = {}) => {\n v.run({ row, table, user, configuration: args, ...rest, ...args });\n };\n });\n const trigger_actions = await Trigger.find({\n when_trigger: { or: [\"API call\", \"Never\"] },\n });\n for (const trigger of trigger_actions) {\n const state_action = getState().actions[trigger.action];\n Actions[trigger.name] = (args = {}) => {\n state_action.run({\n row,\n table,\n configuration: trigger.configuration,\n user,\n ...rest,\n ...args,\n });\n };\n }\n const emitEvent = (eventType, channel, payload) => Trigger.emitEvent(eventType, channel, user, payload);\n const fetchJSON = async (...args) => await (await fetch(...args)).json();\n const f = vm.runInNewContext(`async () => {${code}}`, {\n Table,\n table,\n row,\n user,\n console,\n Actions,\n emitEvent,\n sleep,\n fetchJSON,\n fetch,\n channel: table ? table.name : channel,\n ...(row || {}),\n ...getState().function_context,\n ...rest,\n });\n return await f();\n};\nmodule.exports = {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n blocks: {\n disableInBuilder: true,\n disableInList: true,\n configFields: [\n {\n name: \"workspace\",\n input_type: \"hidden\",\n },\n {\n name: \"code\",\n input_type: \"hidden\",\n },\n ],\n /**\n * @type {base-plugin/actions~run_code}\n * @see base-plugin/actions~run_code\n */\n run: run_code,\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n emit_event: {\n /**\n * @returns {object[]}\n */\n configFields: () => [\n {\n name: \"eventType\",\n label: \"Event type\",\n required: true,\n input_type: \"select\",\n options: Trigger.when_options,\n },\n {\n name: \"channel\",\n label: \"Channel\",\n type: \"String\",\n fieldview: \"textarea\",\n },\n {\n name: \"payload\",\n label: \"Payload JSON\",\n sublabel: \"Leave blank to use row from table\",\n type: \"String\",\n fieldview: \"textarea\",\n },\n ],\n /**\n * @param {object} opts\n * @param {object} opts.row\n * @param {object} opts.configuration\n * @param {object} opts.user\n * @returns {Promise<void>}\n */\n run: async ({ row, configuration: { eventType, channel, payload }, user, }) => {\n return await Trigger.emitEvent(eventType, channel, user, payload ? JSON.parse(payload) : row);\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n webhook: {\n configFields: [\n {\n name: \"url\",\n label: \"URL\",\n type: \"String\",\n sublabel: \"Trigger will call specified URL\",\n },\n {\n name: \"body\",\n label: \"JSON body\",\n sublabel: \"Leave blank to use row from table\",\n type: \"String\",\n fieldview: \"textarea\", // I think that textarea is better\n },\n ],\n /**\n * @param {object} opts\n * @param {string} opts.url\n * @param {object} opts.body\n * @returns {Promise<object>}\n */\n run: async ({ row, configuration: { url, body } }) => {\n return await fetch(url, {\n method: \"post\",\n body: body || JSON.stringify(row),\n headers: { \"Content-Type\": \"application/json\" },\n });\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n find_or_create_dm_room: {\n /**\n * @returns {Promise<object[]>}\n */\n configFields: async () => {\n const views = await View.find_all_views_where(({ viewrow }) => viewrow.viewtemplate === \"Room\");\n const view_opts = views.map((v) => v.name);\n return [\n {\n name: \"viewname\",\n label: \"Room view\",\n sublabel: \"Select a view with the Room viewtemplate\",\n input_type: \"select\",\n options: view_opts,\n },\n ];\n },\n /**\n * @param {object} opts\n * @param {object} opts.row\n * @param {*} opts.table\n * @param {object} opts.configuration\n * @param {object} opts.user\n * @returns {Promise<object>}\n */\n run: async ({ row, table, configuration: { viewname }, user }) => {\n const view = await View.findOne({ name: viewname });\n const { participant_field } = view.configuration;\n const [part_table_name, part_key_to_room, part_user_field] = participant_field.split(\".\");\n const roomtable = Table.findOne({ id: view.table_id });\n const parttable = Table.findOne({ name: part_table_name });\n //find a room that has both participants\n // select id from rooms r where uid1 in (select id from participants where...) and\n const { rows } = await db.query(`with my_rooms as (select \"${part_key_to_room}\" from \"${db.getTenantSchema()}\".\"${db.sqlsanitize(part_table_name)}\" where \"${part_user_field}\" = $1) \n select * from \"${db.getTenantSchema()}\".\"${db.sqlsanitize(roomtable.name)}\" r where r.id in (select \"${part_key_to_room}\" from my_rooms) \n and $2 in (select \"${part_user_field}\" from \"${db.getTenantSchema()}\".\"${db.sqlsanitize(part_table_name)}\" where \"${part_key_to_room}\" = r.id)`, [user.id, row.id]);\n if (rows.length > 0) {\n return { goto: `/view/${viewname}?id=${rows[0].id}` };\n }\n else {\n //create room\n const room_id = await roomtable.insertRow({});\n await parttable.insertRow({\n [part_user_field]: user.id,\n [part_key_to_room]: room_id,\n });\n await parttable.insertRow({\n [part_user_field]: row.id,\n [part_key_to_room]: room_id,\n });\n return { goto: `/view/${viewname}?id=${room_id}` };\n }\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n send_email: {\n /**\n * @param {object} opts\n * @param {object} opts.table\n * @returns {Promise<object[]>}\n */\n configFields: async ({ table }) => {\n if (!table)\n return [];\n const views = await View.find_table_views_where(table, ({ viewtemplate }) => viewtemplate.runMany || viewtemplate.renderRows);\n const view_opts = views.map((v) => v.name);\n const fields = await table.getFields();\n const field_opts = fields\n .filter((f) => (f.type && f.type.name === \"String\") || f.reftable_name === \"users\")\n .map((f) => f.name);\n return [\n {\n name: \"viewname\",\n label: \"View to send\",\n sublabel: \"Select a view that can render a single record - for instance, of the Show template.\",\n input_type: \"select\",\n options: view_opts,\n },\n {\n name: \"to_email\",\n label: \"Recipient email address\",\n sublabel: \"Select email addresses for send email. Choose option to get more information\",\n input_type: \"select\",\n required: true,\n options: [\"Fixed\", \"User\", \"Field\"],\n },\n {\n name: \"to_email_field\",\n label: \"Field with email address\",\n sublabel: \"Field with email address a String, or Key to user who will receive email\",\n input_type: \"select\",\n options: field_opts,\n showIf: { to_email: \"Field\" },\n },\n {\n name: \"to_email_fixed\",\n label: \"Fixed address\",\n sublabel: \"Email address to send emails\",\n type: \"String\",\n showIf: { to_email: \"Fixed\" },\n },\n {\n name: \"subject\",\n label: \"Subject\",\n sublabel: \"Subject of email\",\n type: \"String\",\n required: true,\n },\n ];\n },\n requireRow: true,\n /**\n * @param {object} opts\n * @param {object} opts.row\n * @param {object} opts.table\n * @param {object} opts.configuration\n * @param {object} opts.user\n * @returns {Promise<object>}\n */\n run: async ({ row, table, configuration: { viewname, subject, to_email, to_email_field, to_email_fixed, }, user, }) => {\n let to_addr;\n switch (to_email) {\n case \"Fixed\":\n to_addr = to_email_fixed;\n break;\n case \"User\":\n to_addr = user.email;\n break;\n case \"Field\":\n const fields = await table.getFields();\n const field = fields.find((f) => f.name === to_email_field);\n if (field && field.type.name === \"String\")\n to_addr = row[to_email_field];\n else if (field && field.reftable_name === \"users\") {\n const refuser = await User.findOne({ id: row[to_email_field] });\n to_addr = refuser.email;\n }\n break;\n }\n const view = await View.findOne({ name: viewname });\n const html = await viewToEmailHtml(view, { id: row.id });\n console.log(\"Sending email from %s to %s with subject %s to_email\", getState().getConfig(\"email_from\"), to_addr, subject, to_addr);\n const email = {\n from: getState().getConfig(\"email_from\"),\n to: to_addr,\n subject,\n html,\n };\n //console.log(email);\n await getMailTransport().sendMail(email);\n return { notify: `E-mail sent to ${to_addr}` };\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n insert_joined_row: {\n /**\n * @param {object} opts\n * @param {object} opts.table\n * @returns {Promise<object[]>}\n */\n configFields: async ({ table }) => {\n if (!table)\n return [];\n const { child_field_list } = await table.get_child_relations();\n return [\n {\n name: \"joined_table\",\n label: \"Relation\",\n sublabel: \"Relation\",\n input_type: \"select\",\n options: child_field_list,\n },\n ];\n },\n requireRow: true,\n /**\n * @param {object} opts\n * @param {object} opts.row\n * @param {object} opts.table\n * @param {object} opts.configuration\n * @param {object} opts.user\n * @returns {Promise<object>}\n */\n run: async ({ row, table, configuration: { joined_table }, user }) => {\n const [join_table_name, join_field] = joined_table.split(\".\");\n const joinTable = await Table.findOne({ name: join_table_name });\n const fields = await joinTable.getFields();\n const newRow = { [join_field]: row.id };\n for (const field of fields) {\n if (field.type === \"Key\" &&\n field.reftable_name === \"users\" &&\n user &&\n user.id)\n newRow[field.name] = user.id;\n }\n return await joinTable.insertRow(newRow);\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n duplicate_row: {\n /**\n * @returns {Promise<object[]>}\n */\n configFields: () => [],\n requireRow: true,\n /**\n * @param {object} opts\n * @param {object} opts.row\n * @param {object} opts.table\n * @param {*} opts.user\n * @returns {Promise<object>}\n */\n run: async ({ row, table, user }) => {\n const newRow = { ...row };\n await table.getFields();\n delete newRow[table.pk_name];\n await table.insertRow(newRow);\n return { reload_page: true };\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n recalculate_stored_fields: {\n /**\n * @param {object} opts\n * @param {object} opts.table\n * @returns {Promise<object[]>}\n */\n configFields: async ({ table }) => {\n const tables = await Table.find();\n return [\n {\n name: \"table\",\n label: \"Table\",\n sublabel: \"Table on which to recalculate stored calculated fields\",\n input_type: \"select\",\n options: tables.map((t) => t.name),\n },\n ];\n },\n /**\n * @param {object} opts\n * @param {object} opts.configuration\n * @returns {Promise<void>}\n */\n run: async ({ configuration: { table } }) => {\n const table_for_recalc = await Table.findOne({ name: table });\n //intentionally omit await\n recalculate_for_stored(table_for_recalc);\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n insert_any_row: {\n /**\n * @param {object} opts\n * @param {*} opts.table\n * @returns {Promise<object[]>}\n */\n configFields: async ({ table }) => {\n const tables = await Table.find();\n return [\n {\n name: \"table\",\n label: \"Table\",\n sublabel: \"Table to insert rows in\",\n input_type: \"select\",\n options: tables.map((t) => t.name),\n },\n {\n name: \"row_expr\",\n label: \"Row expression\",\n sublabel: \"Expression for JavaScript object\",\n type: \"String\",\n fieldview: \"textarea\",\n },\n ];\n },\n /**\n * @param {object} opts\n * @param {object} opts.row\n * @param {object} opts.configuration\n * @param {object} opts.user\n * @param {...*} opts.rest\n * @returns {Promise<object|boolean>}\n */\n run: async ({ row, configuration: { row_expr, table }, user, ...rest }) => {\n const f = get_async_expression_function(row_expr, [], {\n row: row || {},\n user,\n console,\n });\n const calcrow = await f({});\n const table_for_insert = await Table.findOne({ name: table });\n const res = await table_for_insert.tryInsertRow(calcrow, user && user.id);\n if (res.error)\n return res;\n else\n return true;\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory actions\n */\n run_js_code: {\n /**\n * @param {object} opts\n * @param {object} opts.table\n * @returns {Promise<object[]>}\n */\n configFields: async ({ table }) => {\n const fields = table ? (await table.getFields()).map((f) => f.name) : [];\n const vars = [\n ...(table ? [\"row\"] : []),\n \"user\",\n \"console\",\n \"Actions\",\n \"Table\",\n ...(table ? [\"table\"] : []),\n ...fields,\n ]\n .map((f) => code(f))\n .join(\", \");\n return [\n {\n name: \"code\",\n label: \"Code\",\n input_type: \"code\",\n attributes: { mode: \"application/javascript\" },\n validator(s) {\n try {\n let AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;\n AsyncFunction(s);\n return true;\n }\n catch (e) {\n return e.message;\n }\n },\n },\n {\n input_type: \"section_header\",\n label: \" \",\n sublabel: div(\"Variables in scope: \", vars),\n showIf: { run_where: \"Server\" },\n },\n {\n name: \"run_where\",\n label: \"Run where\",\n input_type: \"select\",\n options: [\"Server\", \"Client page\"],\n },\n ];\n },\n /**\n * @type {base-plugin/actions~run_code}\n * @see base-plugin/actions~run_code\n **/\n run: run_code,\n },\n duplicate_row_prefill_edit: {\n configFields: async ({ table }) => {\n const fields = table ? await table.getFields() : [];\n const views = await View.find_table_views_where(table, ({ viewrow }) => viewrow.viewtemplate === \"Edit\");\n const fldOpts = fields.map((f) => ({\n label: f.name,\n name: f.name,\n default: f.name !== \"id\",\n type: \"Bool\",\n }));\n return [\n {\n name: \"viewname\",\n label: \"View to create\",\n input_type: \"select\",\n options: views.map((v) => v.name),\n },\n ...fldOpts,\n ];\n },\n requireRow: true,\n run: async ({ row, table, configuration: { viewname, ...flds }, user }) => {\n const qs = Object.entries(flds)\n .map(([k, v]) => v && typeof row[k] !== \"undefined\"\n ? `${encodeURIComponent(k)}=${encodeURIComponent(row[k])}`\n : false)\n .filter((s) => s)\n .join(\"&\");\n return { goto: `/view/${viewname}?${qs}` };\n },\n },\n};\n//# sourceMappingURL=actions.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/actions.js?");
|
|
39
|
+
|
|
40
|
+
/***/ }),
|
|
41
|
+
|
|
42
|
+
/***/ "../saltcorn-data/dist/base-plugin/fieldviews.js":
|
|
43
|
+
/*!*******************************************************!*\
|
|
44
|
+
!*** ../saltcorn-data/dist/base-plugin/fieldviews.js ***!
|
|
45
|
+
\*******************************************************/
|
|
46
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
47
|
+
|
|
48
|
+
"use strict";
|
|
49
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/fieldviews\n * @subcategory base-plugin\n */\nconst View = __webpack_require__(/*! ../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Table = __webpack_require__(/*! ../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst { option, a, h5, span, text_attr, script, input, } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst tags = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { select_options, radio_group } = __webpack_require__(/*! @saltcorn/markup/helpers */ \"../saltcorn-markup/dist/helpers.js\");\nconst { isNode } = __webpack_require__(/*! ../utils */ \"../saltcorn-data/dist/utils.js\");\n/**\n * select namespace\n * @namespace\n * @category saltcorn-data\n */\nconst select = {\n /** @type {string} */\n type: \"Key\",\n /** @type {boolean} */\n isEdit: true,\n blockDisplay: true,\n /**\n * @type {object[]}\n */\n configFields: () => [\n {\n name: \"neutral_label\",\n label: \"Neutral label\",\n type: \"String\",\n },\n {\n name: \"where\",\n label: \"Where\",\n type: \"String\",\n },\n {\n name: \"label_formula\",\n label: \"Label formula\",\n type: \"String\",\n class: \"validate-expression\",\n sublabel: \"Uses summary field if blank\",\n },\n {\n name: \"force_required\",\n label: \"Force required\",\n sublabel: \"User must select a value, even if the table field is not required\",\n type: \"Bool\",\n },\n ],\n /**\n * @param {*} nm\n * @param {*} v\n * @param {*} attrs\n * @param {*} cls\n * @param {*} reqd\n * @param {*} field\n * @returns {object}\n */\n run: (nm, v, attrs, cls, reqd, field) => {\n if (attrs.disabled)\n return (input({\n class: `${cls} ${field.class || \"\"}`,\n \"data-fieldname\": field.form_name,\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n readonly: true,\n placeholder: v || field.label,\n }) + span({ class: \"ml-m1\" }, \"v\"));\n return tags.select({\n class: `form-control form-select ${cls} ${field.class || \"\"}`,\n \"data-fieldname\": field.form_name,\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n }, select_options(v, field, (attrs || {}).force_required, (attrs || {}).neutral_label));\n },\n};\nconst two_level_select = {\n /** @type {string} */\n type: \"Key\",\n /** @type {boolean} */\n isEdit: true,\n blockDisplay: true,\n /**\n * @type {object[]}\n */\n configFields: async ({ table, name }) => {\n if (!table)\n return [];\n const fields = await table.getFields();\n const relOpts = [\"\"];\n const field = fields.find((f) => f.name === name);\n if (!field)\n return [];\n if (field.is_fkey && field.reftable_name) {\n const relTable = Table.findOne(field.reftable_name);\n if (!relTable)\n return [];\n const relFields = await relTable.getFields();\n relFields.forEach((relField) => {\n if (relField.is_fkey) {\n relOpts.push(relField.name);\n }\n });\n }\n return [\n {\n name: \"relation\",\n label: \"Top level field\",\n input_type: \"select\",\n options: relOpts,\n },\n {\n name: \"neutral_label\",\n label: \"Neutral label\",\n type: \"String\",\n },\n {\n name: \"force_required\",\n label: \"Force required\",\n sublabel: \"User must select a value, even if the table field is not required\",\n type: \"Bool\",\n },\n ];\n },\n run: (nm, v, attrs, cls, reqd, field) => {\n const options2 = {};\n Object.entries(field.options || {}).forEach(([label, { id, options }]) => {\n options2[id] = options;\n if (attrs.isFilter)\n options2[id].unshift({ label: \"\", value: \"\" });\n });\n const calcOptions = [`_${field.name}_toplevel`, options2];\n return (tags.select({\n class: `form-control form-select w-50 ${cls} ${field.class || \"\"} d-inline`,\n \"data-fieldname\": `_${field.name}_toplevel`,\n onChange: attrs.isFilter ? \"apply_showif()\" : undefined,\n }, select_options_first_level(v, field, attrs || {}, attrs || {})) +\n tags.select({\n class: `form-control form-select w-50 ${cls} ${field.class || \"\"} d-inline`,\n \"data-fieldname\": field.form_name,\n \"data-selected\": v,\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n onChange: attrs.onChange,\n \"data-calc-options\": encodeURIComponent(JSON.stringify(calcOptions)),\n }, option({ value: \"\" }, \"\")));\n },\n};\nconst select_options_first_level = (v, hdr, { force_required, neutral_label, isFilter }) => {\n const os = Object.entries(hdr.options || {}).map(([label, { id, options }]) => option({ value: id, selected: (options || []).map((o) => o.value).includes(v) }, label));\n if (isFilter)\n os.unshift(option({ value: \"\" }, \"\"));\n return os;\n};\n/**\n * radio_select namespace\n * @namespace\n * @category saltcorn-data\n */\nconst radio_select = {\n /** @type {string} */\n type: \"Key\",\n /** @type {boolean} */\n isEdit: true,\n /**\n * @param {*} nm\n * @param {*} v\n * @param {*} attrs\n * @param {*} cls\n * @param {*} reqd\n * @param {*} field\n * @returns {object}\n */\n run: (nm, v, attrs, cls, reqd, field) => radio_group({\n class: `${cls} ${field.class || \"\"}`,\n name: text_attr(nm),\n options: field.options,\n value: v,\n }),\n};\n/**\n * select namespace\n * @namespace\n * @category saltcorn-data\n */\nconst search_or_create = {\n /** @type {string} */\n type: \"Key\",\n /** @type {boolean} */\n isEdit: true,\n blockDisplay: true,\n /**\n * @param {object} field\n * @returns {Promise<object[]>}\n */\n configFields: async (field) => {\n const reftable = await Table.findOne({ name: field.reftable_name });\n if (!reftable)\n return [];\n const views = await View.find({ table_id: reftable.id });\n return [\n {\n name: \"viewname\",\n label: \"View to create\",\n input_type: \"select\",\n form_name: field.form_name,\n options: views.map((v) => v.name),\n },\n {\n name: \"label\",\n label: \"Label to create\",\n type: \"String\",\n },\n ];\n },\n /**\n * @param {*} nm\n * @param {*} v\n * @param {*} attrs\n * @param {*} cls\n * @param {*} reqd\n * @param {*} field\n * @returns {object}\n */\n run: (nm, v, attrs, cls, reqd, field) => {\n return (tags.select({\n class: `form-control form-select ${cls} ${field.class || \"\"}`,\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n }, select_options(v, field)) +\n a({\n href: `javascript:${isNode() ? \"ajax_modal\" : \"mobile_modal\"}('/view/${attrs.viewname}',{submitReload: false,onClose: soc_process_${nm}})`,\n }, attrs.label || \"Or create new\") +\n script(`\n function soc_process_${nm}(){\n $.ajax('/api/${field.reftable_name}', {\n success: function (res, textStatus, request) {\n var opts = res.success.map(x=>'<option value=\"'+x.id+'\">'+x.${attrs.summary_field}+'</option>').join(\"\")\n ${reqd ? \"\" : `opts = '<option></option>'+opts`}\n $('#input${text_attr(nm)}').html(opts).prop('selectedIndex', res.success.length${reqd ? \"-1\" : \"\"}); \n }\n })\n }`));\n },\n};\nconst search_join_field = {\n /** @type {string} */\n type: \"Key\",\n /** @type {boolean} */\n blockDisplay: true,\n isEdit: false,\n isFilter: true,\n configFields: async (field) => {\n const reftable = await Table.findOne({ name: field.reftable_name });\n if (!reftable)\n return [];\n const fields = await reftable.getFields();\n return [\n {\n name: \"joinfield\",\n label: \"Join field\",\n type: \"String\",\n required: true,\n attributes: {\n options: fields.map((v) => ({\n label: v.name,\n value: `${reftable.name}->${v.name}`,\n })),\n },\n },\n ];\n },\n run: (nm, v, attrs = {}, cls, required, field, state = {}) => {\n return input({\n type: \"text\",\n class: [\"form-control\", \"blur-on-enter-keypress\", cls],\n disabled: attrs.disabled,\n onBlur: `set_state_field('${nm}.${encodeURIComponent(attrs.joinfield)}', this.value)`,\n value: text_attr(state[`${nm}.${attrs.joinfield}`] || \"\"),\n });\n },\n};\nmodule.exports = {\n select,\n search_or_create,\n radio_select,\n two_level_select,\n search_join_field,\n};\n//# sourceMappingURL=fieldviews.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/fieldviews.js?");
|
|
50
|
+
|
|
51
|
+
/***/ }),
|
|
52
|
+
|
|
53
|
+
/***/ "../saltcorn-data/dist/base-plugin/fileviews.js":
|
|
54
|
+
/*!******************************************************!*\
|
|
55
|
+
!*** ../saltcorn-data/dist/base-plugin/fileviews.js ***!
|
|
56
|
+
\******************************************************/
|
|
57
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
58
|
+
|
|
59
|
+
"use strict";
|
|
60
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/fileview\n * @subcategory base-plugin\n */\nconst { a, img, script, domReady } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { link } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { isNode } = __webpack_require__(/*! ../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { div } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nmodule.exports = {\n /**\n * @namespace\n * @category saltcorn-data\n */\n \"Download link\": {\n /**\n * @param {string} file_id\n * @param {string} file_name\n * @returns {link}\n */\n run: (file_id, file_name) => link(isNode()\n ? `/files/download/${file_id}`\n : `javascript:notifyAlert('File donwloads are not supported.')`, file_name || \"Download\"),\n },\n /**\n * @namespace\n * @category saltcorn-data\n */\n Link: {\n /**\n * @param {string} file_id\n * @param {string} file_name\n * @returns {link}\n */\n run: (file_id, file_name) => link(isNode()\n ? `/files/serve/${file_id}`\n : `javascript:openFile(${file_id})`, file_name || \"Open\"),\n },\n /**\n * @namespace\n * @category saltcorn-data\n */\n \"Link (new tab)\": {\n /**\n * @param {string} file_id\n * @param {string} file_name\n * @returns {a}\n */\n run: (file_id, file_name) => a(isNode()\n ? { href: `/files/serve/${file_id}`, target: \"_blank\" }\n : { href: `javascript:openFile(${file_id})` }, file_name || \"Open\"),\n },\n /**\n * @namespace\n * @category saltcorn-data\n */\n \"Show Image\": {\n /**\n * @param {string} file_id\n * @param {string} file_name\n * @returns {img}\n */\n run: (file_id, file_name) => {\n if (isNode())\n return img({ src: `/files/download/${file_id}`, style: \"width: 100%\" });\n else {\n const elementId = `_sc_file_id_${file_id}_`;\n return div(img({ style: \"width: 100%\", id: elementId }), script(domReady(`buildEncodedImage(${file_id}, '${elementId}')`)));\n }\n },\n },\n};\n//# sourceMappingURL=fileviews.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/fileviews.js?");
|
|
61
|
+
|
|
62
|
+
/***/ }),
|
|
63
|
+
|
|
64
|
+
/***/ "../saltcorn-data/dist/base-plugin/index.js":
|
|
65
|
+
/*!**************************************************!*\
|
|
66
|
+
!*** ../saltcorn-data/dist/base-plugin/index.js ***!
|
|
67
|
+
\**************************************************/
|
|
68
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
69
|
+
|
|
70
|
+
"use strict";
|
|
71
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/index\n * @subcategory base-plugin\n */\n/**\n * All files in the base-plugin module.\n * @namespace base-plugin_overview\n * @property {module:base-plugin/actions} actions\n * @property {module:base-plugin/fieldviews} fieldviews\n * @property {module:base-plugin/fileview} fileview\n * @property {module:base-plugin/types} types\n *\n * @property {module:base-plugin/viewtemplates/edit} edit\n * @property {module:base-plugin/viewtemplates/feed} feed\n * @property {module:base-plugin/viewtemplates/filter} filter\n * @property {module:base-plugin/viewtemplates/list} list\n * @property {module:base-plugin/viewtemplates/listshowlist} listshowlist\n * @property {module:base-plugin/viewtemplates/room} room\n * @property {module:base-plugin/viewtemplates/show} show\n * @property {module:base-plugin/viewtemplates/viewable_fields} viewable_fields\n *\n *\n * @category saltcorn-data\n * @subcategory base-plugin\n */\nconst listshowlist = __webpack_require__(/*! ./viewtemplates/listshowlist */ \"../saltcorn-data/dist/base-plugin/viewtemplates/listshowlist.js\");\nconst list = __webpack_require__(/*! ./viewtemplates/list */ \"../saltcorn-data/dist/base-plugin/viewtemplates/list.js\");\nconst show = __webpack_require__(/*! ./viewtemplates/show */ \"../saltcorn-data/dist/base-plugin/viewtemplates/show.js\");\nconst feed = __webpack_require__(/*! ./viewtemplates/feed */ \"../saltcorn-data/dist/base-plugin/viewtemplates/feed.js\");\nconst room = __webpack_require__(/*! ./viewtemplates/room */ \"../saltcorn-data/dist/base-plugin/viewtemplates/room.js\");\nconst edit = __webpack_require__(/*! ./viewtemplates/edit */ \"../saltcorn-data/dist/base-plugin/viewtemplates/edit.js\");\nconst filter = __webpack_require__(/*! ./viewtemplates/filter */ \"../saltcorn-data/dist/base-plugin/viewtemplates/filter.js\");\nconst fileviews = __webpack_require__(/*! ./fileviews */ \"../saltcorn-data/dist/base-plugin/fileviews.js\");\nconst fieldviews = __webpack_require__(/*! ./fieldviews */ \"../saltcorn-data/dist/base-plugin/fieldviews.js\");\nconst actions = __webpack_require__(/*! ./actions */ \"../saltcorn-data/dist/base-plugin/actions.js\");\nconst { string, int, bool, date, float, color } = __webpack_require__(/*! ./types */ \"../saltcorn-data/dist/base-plugin/types.js\");\nconst types = [string, int, bool, date, float, color];\nconst viewtemplates = [list, edit, show, listshowlist, feed, filter, room];\nmodule.exports = {\n /** @type {number} */\n sc_plugin_api_version: 1,\n /** @type {object[]} */\n types,\n /** @type {object[]} */\n viewtemplates,\n /** @type {base-plugin/fileviews} */\n fileviews,\n /** @type {base-plugin/actions} */\n actions,\n /** @type {base-plugin/fieldviews} */\n fieldviews,\n /** @type {object} */\n serve_dependencies: {\n blockly: /*require.resolve*/(/*! blockly/package.json */ \"../../node_modules/blockly/package.json\"),\n },\n};\n//# sourceMappingURL=index.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/index.js?");
|
|
72
|
+
|
|
73
|
+
/***/ }),
|
|
74
|
+
|
|
75
|
+
/***/ "../saltcorn-data/dist/base-plugin/types.js":
|
|
76
|
+
/*!**************************************************!*\
|
|
77
|
+
!*** ../saltcorn-data/dist/base-plugin/types.js ***!
|
|
78
|
+
\**************************************************/
|
|
79
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
80
|
+
|
|
81
|
+
"use strict";
|
|
82
|
+
eval("\n/**\n * Embedded Types definition.\n *\n * More types can be added by plugin store mechanism https://store.saltcorn.com/\n * @category saltcorn-data\n * @module base-plugin/types\n * @subcategory base-plugin\n */\nconst moment = __webpack_require__(/*! moment */ \"../../node_modules/moment/moment.js\");\nconst { input, select, option, text, div, h3, a, i, button, textarea, span, img, text_attr, script, domReady, section, } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { contract, is } = __webpack_require__(/*! contractis */ \"../../node_modules/contractis/index.js\");\nconst { radio_group, checkbox_group } = __webpack_require__(/*! @saltcorn/markup/helpers */ \"../saltcorn-markup/dist/helpers.js\");\nconst { getState } = __webpack_require__(/*! ../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst { localeDate, localeDateTime } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { freeVariables } = __webpack_require__(/*! ../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\nconst Table = __webpack_require__(/*! ../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst isdef = (x) => (typeof x === \"undefined\" || x === null ? false : true);\nconst eqStr = (x, y) => `${x}` === `${y}`;\nconst number_slider = (type) => ({\n configFields: (field) => [\n ...(!isdef(field.attributes.min)\n ? [{ name: \"min\", type, required: false }]\n : []),\n ...(!isdef(field.attributes.max)\n ? [{ name: \"max\", type, required: false }]\n : []),\n ],\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs = {}, cls, required, field) => input({\n type: \"range\",\n class: [\"form-control\", cls],\n name: text_attr(nm),\n \"data-fieldname\": text_attr(field.name),\n disabled: attrs.disabled,\n onChange: attrs.onChange,\n step: type === \"Integer\"\n ? 1\n : attrs.decimal_places\n ? Math.pow(10, -attrs.decimal_places)\n : \"0.01\",\n id: `input${text_attr(nm)}`,\n ...(isdef(attrs.max) && { max: attrs.max }),\n ...(isdef(attrs.min) && { min: attrs.min }),\n ...(isdef(v) && { value: text_attr(v) }),\n }),\n});\nconst range_interval = (type) => ({\n configFields: (field) => [\n ...(!isdef(field.attributes.min)\n ? [{ name: \"min\", type, required: false }]\n : []),\n ...(!isdef(field.attributes.max)\n ? [{ name: \"max\", type, required: false }]\n : []),\n ],\n isEdit: false,\n isFilter: true,\n blockDisplay: true,\n /* https://stackoverflow.com/a/31083391 */\n run: (nm, v, attrs = {}, cls, required, field, state = {}) => {\n return section({ class: [\"range-slider\", cls] }, span({ class: \"rangeValues\" }), input({\n ...(isdef(state[`_gte_${nm}`])\n ? {\n value: text_attr(state[`_gte_${nm}`]),\n }\n : isdef(attrs.min)\n ? { value: text_attr(attrs.min) }\n : {}),\n ...(isdef(attrs.max) && { max: attrs.max }),\n ...(isdef(attrs.min) && { min: attrs.min }),\n type: \"range\",\n disabled: attrs.disabled,\n onChange: `set_state_field('_gte_${nm}', this.value)`,\n }), input({\n ...(isdef(state[`_lte_${nm}`])\n ? {\n value: text_attr(state[`_lte_${nm}`]),\n }\n : isdef(attrs.max)\n ? { value: text_attr(attrs.max) }\n : {}),\n ...(isdef(attrs.max) && { max: attrs.max }),\n ...(isdef(attrs.min) && { min: attrs.min }),\n type: \"range\",\n disabled: attrs.disabled,\n onChange: `set_state_field('_lte_${nm}', this.value)`,\n }));\n },\n});\nconst progress_bar = (type) => ({\n configFields: (field) => [\n ...(!isdef(field.attributes.min)\n ? [{ name: \"min\", type, required: true }]\n : []),\n ...(!isdef(field.attributes.max)\n ? [{ name: \"max\", type, required: true }]\n : []),\n { name: \"bar_color\", type: \"Color\", label: \"Bar color\" },\n { name: \"bg_color\", type: \"Color\", label: \"Background color\" },\n { name: \"px_height\", type: \"Integer\", label: \"Height in px\" },\n ],\n isEdit: false,\n run: (v, req, attrs = {}) => div({\n style: {\n width: \"100%\",\n height: `${attrs.px_height || 8}px`,\n backgroundColor: attrs.bg_color || \"#777777\",\n },\n }, div({\n style: {\n width: `${(100 * (v - attrs.min)) / (attrs.max - attrs.min)}%`,\n height: `${attrs.px_height || 8}px`,\n backgroundColor: attrs.bar_color || \"#0000ff\",\n },\n })),\n});\nconst number_limit = (direction) => ({\n isEdit: false,\n isFilter: true,\n blockDisplay: true,\n configFields: [\n { name: \"stepper_btns\", label: \"Stepper buttons\", type: \"Bool\" },\n ],\n run: (nm, v, attrs = {}, cls, requiZred, field, state = {}) => {\n const onChange = `set_state_field('_${direction}_${nm}', this.value)`;\n return attrs?.stepper_btns\n ? number_stepper(undefined, isdef(state[`_${direction}_${nm}`])\n ? text_attr(state[`_${direction}_${nm}`])\n : undefined, {\n ...attrs,\n onChange: `set_state_field('_${direction}_${nm}', $('#numlim_${nm}_${direction}').val())`,\n }, cls, undefined, `numlim_${nm}_${direction}`)\n : input({\n type: \"number\",\n class: [\"form-control\", cls],\n disabled: attrs.disabled,\n onChange,\n step: 1,\n ...(attrs.max && { max: attrs.max }),\n ...(attrs.min && { min: attrs.min }),\n ...(isdef(state[`_${direction}_${nm}`]) && {\n value: text_attr(state[`_${direction}_${nm}`]),\n }),\n });\n },\n});\nconst float_number_limit = (direction) => ({\n isEdit: false,\n isFilter: true,\n blockDisplay: true,\n run: (nm, v, attrs = {}, cls, required, field, state = {}) => input({\n type: \"number\",\n class: [\"form-control\", cls],\n disabled: attrs.disabled,\n onChange: `set_state_field('_${direction}_${nm}', this.value)`,\n step: attrs.decimal_places ? Math.pow(10, -attrs.decimal_places) : \"0.01\",\n ...(attrs.max && { max: attrs.max }),\n ...(attrs.min && { min: attrs.min }),\n ...(isdef(state[`_${direction}_${nm}`]) && {\n value: text_attr(state[`_${direction}_${nm}`]),\n }),\n }),\n});\nconst number_stepper = (name, v, attrs, cls, fieldname, id) => div({ class: \"input-group\" }, button({\n class: \"btn btn-outline-secondary\",\n type: \"button\",\n onClick: `$('#${id}').val(Math.max(${isdef(attrs.min) ? attrs.min : \"-Infinity\"},+$('#${id}').val()-1));${attrs.onChange || \"\"}`,\n}, i({ class: \"fas fa-minus\" })), input({\n type: \"number\",\n class: [\"form-control\", \"hideupdownbtns\", cls],\n disabled: attrs.disabled,\n \"data-fieldname\": fieldname,\n name,\n onChange: attrs.onChange,\n id,\n step: \"1\",\n ...(attrs.max && { max: attrs.max }),\n ...(attrs.min && { min: attrs.min }),\n ...(isdef(v) && { value: text_attr(v) }),\n}), button({\n class: \"btn btn-outline-secondary\",\n type: \"button\",\n onClick: `$('#${id}').val(Math.min(${isdef(attrs.max) ? attrs.max : \"Infinity\"},+$('#${id}').val()+1));${attrs.onChange || \"\"}`,\n}, i({ class: \"fas fa-plus\" })));\n/**\n * @param {string} v\n * @param {string} optsStr\n * @returns {string[]}\n */\nconst getStrOptions = (v, optsStr) => typeof optsStr === \"string\"\n ? optsStr\n .split(\",\")\n .map((o) => o.trim())\n .map((o) => option({ value: text_attr(o), ...(eqStr(v, o) && { selected: true }) }, text_attr(o)))\n : optsStr.map((o, ix) => o && typeof o.name !== \"undefined\" && typeof o.label !== \"undefined\"\n ? option({\n value: o.name,\n ...((eqStr(v, o.name) ||\n (ix === 0 && typeof v === \"undefined\" && o.disabled)) && {\n selected: true,\n }),\n ...(o.disabled && { disabled: true }),\n }, o.label)\n : option({ value: o, ...(eqStr(v, o) && { selected: true }) }, o));\nconst join_fields_in_formula = (fml) => {\n if (!fml)\n return [];\n return [...freeVariables(fml)];\n};\n/**\n * string type\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\nconst string = {\n /** @type {string} */\n name: \"String\",\n /** @type {string} */\n sql_name: \"text\",\n /**\n * @param {object} param\n * @returns {object}\n */\n attributes: ({ table }) => {\n const strFields = table &&\n table.fields.filter((f) => (f.type || {}).name === \"String\" &&\n !(f.attributes && f.attributes.localizes_field));\n const locales = Object.keys(getState().getConfig(\"localizer_languages\", {}));\n return [\n {\n name: \"regexp\",\n type: \"String\",\n required: false,\n sublabel: \"Match regular expression\",\n validator(s) {\n if (!is_valid_regexp(s))\n return \"Not a valid Regular Expression\";\n },\n },\n {\n name: \"re_invalid_error\",\n type: \"String\",\n required: false,\n sublabel: \"Error message when regular expression does not match\",\n },\n {\n name: \"max_length\",\n type: \"Integer\",\n required: false,\n sublabel: \"The maximum number of characters in the string\",\n },\n {\n name: \"min_length\",\n type: \"Integer\",\n required: false,\n sublabel: \"The minimum number of characters in the string\",\n },\n {\n name: \"options\",\n type: \"String\",\n required: false,\n sublabel: 'Use this to restrict your field to a list of options (separated by commas). For instance, if the permissible values are \"Red\", \"Green\" and \"Blue\", enter \"Red, Green, Blue\" here. Leave blank if the string can hold any value.',\n },\n ...(table\n ? [\n {\n name: \"localizes_field\",\n label: \"Translation of\",\n sublabel: \"This is a translation of a different field in a different language\",\n type: \"String\",\n attributes: {\n options: strFields.map((f) => f.name),\n },\n },\n {\n name: \"locale\",\n label: \"Locale\",\n sublabel: \"Language locale of translation\",\n input_type: \"select\",\n options: locales,\n showIf: { localizes_field: strFields.map((f) => f.name) },\n },\n ]\n : []),\n ];\n },\n /**\n * @param {object} opts\n * @param {string|undefined} opts.options\n * @returns {boolean}\n */\n contract: ({ options }) => typeof options === \"string\"\n ? is.one_of(options.split(\",\"))\n : typeof options === \"undefined\"\n ? is.str\n : is.one_of(options.map((o) => (typeof o === \"string\" ? o : o.name))),\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n fieldviews: {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n as_text: { isEdit: false, run: (s) => text_attr(s || \"\") },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n as_link: {\n isEdit: false,\n run: (s) => a({ href: text(s || \"\") }, text_attr(s || \"\")),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n img_from_url: {\n isEdit: false,\n run: (s, req, attrs) => img({ src: text(s || \"\"), style: \"width:100%\" }),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n as_header: { isEdit: false, run: (s) => h3(text_attr(s || \"\")) },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n edit: {\n isEdit: true,\n blockDisplay: true,\n configFields: (field) => [\n ...(field.attributes.options &&\n field.attributes.options.length > 0 &&\n !field.required\n ? [\n {\n name: \"neutral_label\",\n label: \"Neutral label\",\n type: \"String\",\n },\n {\n name: \"force_required\",\n label: \"Required\",\n sublabel: \"User must select a value, even if the table field is not required\",\n type: \"Bool\",\n },\n ]\n : []),\n {\n name: \"placeholder\",\n label: \"Placeholder\",\n type: \"String\",\n },\n {\n name: \"input_type\",\n label: \"Input type\",\n input_type: \"select\",\n options: [\"text\", \"email\", \"url\", \"tel\", \"password\"],\n },\n ],\n run: (nm, v, attrs, cls, required, field) => attrs.options && (attrs.options.length > 0 || !required)\n ? select({\n class: [\"form-control\", \"form-select\", cls],\n name: text_attr(nm),\n \"data-fieldname\": text_attr(field.name),\n id: `input${text_attr(nm)}`,\n disabled: attrs.disabled,\n onChange: attrs.onChange,\n }, required || attrs.force_required\n ? getStrOptions(v, attrs.options)\n : [\n option({ value: \"\" }, attrs.neutral_label || \"\"),\n ...getStrOptions(v, attrs.options),\n ])\n : attrs.options\n ? i(\"None available\")\n : attrs.calcOptions\n ? select({\n class: [\"form-control\", \"form-select\", cls],\n name: text_attr(nm),\n disabled: attrs.disabled,\n \"data-fieldname\": text_attr(field.name),\n id: `input${text_attr(nm)}`,\n onChange: attrs.onChange,\n \"data-selected\": v,\n \"data-calc-options\": encodeURIComponent(JSON.stringify(attrs.calcOptions)),\n }, option({ value: \"\" }, \"\"))\n : input({\n type: attrs.input_type || \"text\",\n disabled: attrs.disabled,\n class: [\"form-control\", cls],\n placeholder: attrs.placeholder,\n onChange: attrs.onChange,\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && { value: text_attr(v) }),\n }),\n },\n fill_formula_btn: {\n isEdit: true,\n blockDisplay: true,\n configFields: [\n {\n name: \"formula\",\n label: \"Formula\",\n type: \"String\",\n },\n {\n name: \"label\",\n label: \"Button label\",\n type: \"String\",\n },\n {\n name: \"make_unique\",\n label: \"Make unique after fill\",\n type: \"Bool\",\n },\n {\n name: \"include_space\",\n label: \"Include space\",\n type: \"Bool\",\n showIf: { make_unique: true },\n },\n {\n name: \"start_from\",\n label: \"Start from\",\n type: \"Integer\",\n default: 0,\n showIf: { make_unique: true },\n },\n {\n name: \"always_append\",\n label: \"Always append\",\n type: \"Bool\",\n showIf: { make_unique: true },\n },\n {\n name: \"char_type\",\n label: \"Append character type\",\n input_type: \"select\",\n options: [\"Digits\", \"Lowercase Letters\", \"Uppercase Letters\"],\n showIf: { make_unique: true },\n },\n ],\n run: (nm, v, attrs, cls, required, field) => div({ class: \"input-group\" }, input({\n type: attrs.input_type || \"text\",\n disabled: attrs.disabled,\n class: [\"form-control\", cls],\n placeholder: attrs.placeholder,\n onChange: attrs.onChange,\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && { value: text_attr(v) }),\n }), button({\n class: \"btn btn-secondary\",\n type: \"button\",\n \"data-formula\": encodeURIComponent(attrs?.formula),\n \"data-formula-free-vars\": encodeURIComponent(JSON.stringify(join_fields_in_formula(attrs?.formula))),\n \"data-formula-table\": encodeURIComponent(JSON.stringify(Table.findOne(field.table_id))),\n onClick: \"fill_formula_btn_click(this\" +\n (attrs.make_unique\n ? `,()=>make_unique_field('input${text_attr(nm)}', ${field.table_id}, '${field.name}', $('#input${text_attr(nm)}'), ${!!attrs.include_space}, ${attrs.start_from || 0}, ${!!attrs.always_append}, '${attrs.char_type}')`\n : \"\") +\n \")\",\n }, attrs?.label || \"Fill\")),\n },\n make_unique: {\n isEdit: true,\n blockDisplay: true,\n configFields: [\n {\n name: \"placeholder\",\n label: \"Placeholder\",\n type: \"String\",\n },\n {\n name: \"input_type\",\n label: \"Input type\",\n input_type: \"select\",\n options: [\"text\", \"email\", \"url\", \"tel\", \"password\"],\n },\n {\n name: \"include_space\",\n label: \"Include space\",\n type: \"Bool\",\n },\n {\n name: \"start_from\",\n label: \"Start from\",\n type: \"Integer\",\n default: 0,\n },\n {\n name: \"always_append\",\n label: \"Always append\",\n type: \"Bool\",\n },\n {\n name: \"char_type\",\n label: \"Append character type\",\n input_type: \"select\",\n options: [\"Digits\", \"Lowercase Letters\", \"Uppercase Letters\"],\n },\n ],\n run: (nm, v, attrs, cls, required, field) => input({\n type: attrs.input_type || \"text\",\n disabled: attrs.disabled,\n class: [\"form-control\", cls],\n placeholder: attrs.placeholder,\n onChange: attrs.onChange,\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && { value: text_attr(v) }),\n }) +\n script(domReady(`make_unique_field('input${text_attr(nm)}', ${field.table_id}, '${field.name}', $('#input${text_attr(nm)}'), ${attrs.include_space}, ${attrs.start_from}, ${attrs.always_append}, ${JSON.stringify(attrs.char_type)})`)),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n textarea: {\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs, cls, required, field) => textarea({\n class: [\"form-control\", cls],\n name: text_attr(nm),\n \"data-fieldname\": text_attr(field.name),\n disabled: attrs.disabled,\n onChange: attrs.onChange,\n id: `input${text_attr(nm)}`,\n rows: 5,\n }, text(v) || \"\"),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n radio_group: {\n isEdit: true,\n configFields: [\n {\n type: \"Bool\",\n name: \"inline\",\n label: \"Inline\",\n },\n ],\n run: (nm, v, attrs, cls, required, field) => attrs.options\n ? radio_group({\n class: cls,\n name: text_attr(nm),\n disabled: attrs.disabled,\n inline: attrs.inline,\n onChange: attrs.onChange,\n options: Array.isArray(attrs.options)\n ? attrs.options\n : attrs.options.split(\",\").map((o) => o.trim()),\n value: v,\n })\n : i(\"None available\"),\n },\n checkbox_group: {\n isEdit: false,\n isFilter: true,\n configFields: [\n {\n type: \"Bool\",\n name: \"inline\",\n label: \"Inline\",\n },\n ],\n run: (nm, v, attrs, cls, required, field) => attrs && attrs.options\n ? checkbox_group({\n class: cls,\n name: text_attr(nm),\n disabled: attrs.disabled,\n inline: attrs.inline,\n options: Array.isArray(attrs.options)\n ? attrs.options\n : attrs.options.split(\",\").map((o) => o.trim()),\n value: v,\n })\n : i(\"None available\"),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n password: {\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs, cls, required, field) => input({\n type: \"password\",\n disabled: attrs.disabled,\n class: [\"form-control\", cls],\n \"data-fieldname\": text_attr(field.name),\n onChange: attrs.onChange,\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && { value: text_attr(v) }),\n }),\n },\n },\n /**\n * @param {*} v\n * @returns {string|undefined}\n */\n read: (v) => {\n switch (typeof v) {\n case \"string\":\n //PG dislikes null bytes\n return v.replace(/\\0/g, \"\");\n default:\n return undefined;\n }\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / string\n */\n presets: {\n /**\n * @param {object} opts\n * @param {object} opts.req\n * @returns {object}\n */\n IP: ({ req }) => req.ip,\n /**\n * @param {object} opts\n * @param {object} opts.req\n * @returns {object}\n */\n SessionID: ({ req }) => req.sessionID || req.cookies[\"express:sess\"],\n },\n /**\n * @param {object} param\n * @returns {object|true}\n */\n validate: ({ min_length, max_length, regexp, re_invalid_error }) => (x) => {\n if (!x || typeof x !== \"string\")\n return true; //{ error: \"Not a string\" };\n if (isdef(min_length) && x.length < min_length)\n return { error: `Must be at least ${min_length} characters` };\n if (isdef(max_length) && x.length > max_length)\n return { error: `Must be at most ${max_length} characters` };\n if (isdef(regexp) && !new RegExp(regexp).test(x))\n return {\n error: re_invalid_error || `Does not match regular expression`,\n };\n return true;\n },\n /**\n * @param {object} param\n * @returns {object}\n */\n validate_attributes: ({ min_length, max_length, regexp }) => (!isdef(min_length) || !isdef(max_length) || max_length >= min_length) &&\n (!isdef(regexp) || is_valid_regexp(regexp)),\n};\n/**\n * @param {string} s\n * @returns {boolean}\n */\nconst is_valid_regexp = (s) => {\n try {\n new RegExp(s);\n return true;\n }\n catch {\n return false;\n }\n};\n/**\n * Integer type\n * @namespace\n * @category saltcorn-data\n * @subcategory types / int\n */\nconst int = {\n /** @type {string} */\n name: \"Integer\",\n /** @type {string} */\n sql_name: \"int\",\n /**\n * @param {object} opts\n * @param {number} opts.min\n * @param {number} opts.max\n * @returns {boolean}\n */\n contract: ({ min, max }) => is.integer({ lte: max, gte: min }),\n primaryKey: { sql_type: \"serial\" },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / int\n */\n fieldviews: {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / int\n */\n show: { isEdit: false, run: (s) => text(s) },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / int\n */\n edit: {\n isEdit: true,\n blockDisplay: true,\n configFields: [\n { name: \"stepper_btns\", label: \"Stepper buttons\", type: \"Bool\" },\n ],\n run: (nm, v, attrs, cls, required, field) => {\n const id = `input${text_attr(nm)}`;\n const name = text_attr(nm);\n return attrs?.stepper_btns\n ? number_stepper(name, v, attrs, cls, text_attr(field.name), id)\n : input({\n type: \"number\",\n class: [\"form-control\", cls],\n disabled: attrs.disabled,\n \"data-fieldname\": text_attr(field.name),\n name,\n onChange: attrs.onChange,\n id,\n step: \"1\",\n ...(attrs.max && { max: attrs.max }),\n ...(attrs.min && { min: attrs.min }),\n ...(isdef(v) && { value: text_attr(v) }),\n });\n },\n },\n number_slider: number_slider(\"Integer\"),\n range_interval: range_interval(\"Integer\"),\n progress_bar: progress_bar(\"Integer\"),\n above_input: number_limit(\"gte\"),\n below_input: number_limit(\"lte\"),\n },\n /** @type {object[]} */\n attributes: [\n { name: \"min\", type: \"Integer\", required: false },\n { name: \"max\", type: \"Integer\", required: false },\n ],\n /**\n * @param {object} param\n * @returns {boolean}\n */\n validate_attributes: ({ min, max }) => !isdef(min) || !isdef(max) || max > min,\n /**\n * @param {object} v\n * @returns {object}\n */\n read: (v) => {\n switch (typeof v) {\n case \"number\":\n return Math.round(v);\n case \"string\":\n if (v === \"\")\n return undefined;\n const parsed = +v;\n return isNaN(parsed) ? undefined : parsed;\n default:\n return undefined;\n }\n },\n /**\n * @param {object} param\n * @returns {boolean}\n */\n validate: ({ min, max }) => (x) => {\n if (isdef(min) && x < min)\n return { error: `Must be ${min} or higher` };\n if (isdef(max) && x > max)\n return { error: `Must be ${max} or less` };\n return true;\n },\n};\n/**\n * Color Type\n * @namespace color\n * @category saltcorn-data\n * @subcategory types / color\n */\nconst color = {\n /** @type {string} */\n name: \"Color\",\n /** @type {string} */\n sql_name: \"text\",\n /**\n * @returns {function}\n */\n contract: () => is.str,\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / color\n */\n fieldviews: {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / color\n */\n show: {\n isEdit: false,\n run: (s) => s\n ? div({\n class: \"color-type-show\",\n style: `background: ${s};`,\n })\n : \"\",\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / color\n */\n edit: {\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs, cls, required, field) => input({\n type: \"color\",\n class: [\"form-control\", cls],\n disabled: attrs.disabled,\n onChange: attrs.onChange,\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && { value: text_attr(v) }),\n }),\n },\n },\n /** @type {object[]} */\n attributes: [],\n /**\n * @param {object} v\n * @returns {object}\n */\n read: (v) => {\n switch (typeof v) {\n case \"string\":\n return v;\n default:\n return undefined;\n }\n },\n /**\n * @returns {boolean}\n */\n validate: () => (x) => {\n return true;\n },\n};\n/**\n * Float type\n * @namespace\n * @category saltcorn-data\n * @subcategory types / float\n */\nconst float = {\n /** @type {string} */\n name: \"Float\",\n /** @type {string} */\n sql_name: \"double precision\",\n /**\n * @param {object} opts\n * @param {number} opts.min\n * @param {number} opts.max\n * @returns {function}\n */\n contract: ({ min, max }) => is.number({ lte: max, gte: min }),\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / float\n */\n fieldviews: {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / float\n */\n show: { isEdit: false, run: (s) => text(s) },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / float\n */\n edit: {\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs, cls, required, field) => input({\n type: \"number\",\n class: [\"form-control\", cls],\n name: text_attr(nm),\n \"data-fieldname\": text_attr(field.name),\n disabled: attrs.disabled,\n onChange: attrs.onChange,\n step: attrs.decimal_places\n ? Math.pow(10, -attrs.decimal_places)\n : \"0.01\",\n id: `input${text_attr(nm)}`,\n ...(attrs.max && { max: attrs.max }),\n ...(attrs.min && { min: attrs.min }),\n ...(isdef(v) && { value: text_attr(v) }),\n }),\n },\n number_slider: number_slider(\"Float\"),\n range_interval: range_interval(\"Float\"),\n progress_bar: progress_bar(\"Float\"),\n above_input: float_number_limit(\"gte\"),\n below_input: float_number_limit(\"lte\"),\n },\n /** @type {object[]} */\n attributes: [\n { name: \"min\", type: \"Float\", required: false },\n { name: \"max\", type: \"Float\", required: false },\n { name: \"units\", type: \"String\", required: false },\n { name: \"decimal_places\", type: \"Integer\", required: false },\n ],\n /**\n * @param {object} v\n * @returns {number|string|undefined}\n */\n read: (v) => {\n switch (typeof v) {\n case \"number\":\n return v;\n case \"string\":\n const parsed = parseFloat(v);\n return isNaN(parsed) ? undefined : parsed;\n default:\n return undefined;\n }\n },\n /**\n * @param {object} param\n * @returns {object|boolean}\n */\n validate: ({ min, max }) => (x) => {\n if (isdef(min) && x < min)\n return { error: `Must be ${min} or higher` };\n if (isdef(max) && x > max)\n return { error: `Must be ${max} or less` };\n return true;\n },\n};\n/**\n * @param {object} req\n * @returns {string|undefined}\n */\nconst locale = (req) => {\n //console.log(req && req.getLocale ? req.getLocale() : undefined);\n return req && req.getLocale ? req.getLocale() : undefined;\n};\n/**\n * @param {*} x\n * @returns {*}\n */\nconst logit = (x) => {\n console.log(x);\n return x;\n};\n/**\n * Date type\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\nconst date = {\n /** @type {string} */\n name: \"Date\",\n /** @type {string} */\n sql_name: \"timestamptz\",\n /**\n * @returns {function}\n */\n contract: () => is.date,\n /** @type {object[]} */\n attributes: [],\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n fieldviews: {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n show: {\n isEdit: false,\n run: (d, req) => typeof d === \"string\"\n ? localeDateTime(new Date(d))\n : d && d.toISOString\n ? localeDateTime(d)\n : \"\",\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n showDay: {\n isEdit: false,\n run: (d, req) => typeof d === \"string\"\n ? localeDate(new Date(d))\n : d && d.toISOString\n ? localeDate(d)\n : \"\",\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n format: {\n isEdit: false,\n configFields: [\n {\n name: \"format\",\n label: \"Format\",\n type: \"String\",\n sublabel: \"moment.js format specifier\",\n },\n ],\n run: (d, req, options) => {\n if (!d)\n return \"\";\n if (!options || !options.format)\n return text(moment(d).format());\n return text(moment(d).format(options.format));\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n relative: {\n isEdit: false,\n run: (d, req) => {\n if (!d)\n return \"\";\n const loc = locale(req);\n if (loc)\n return text(moment(d).locale(loc).fromNow());\n else\n return text(moment(d).fromNow());\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n yearsAgo: {\n isEdit: false,\n run: (d, req) => {\n if (!d)\n return \"\";\n return text(moment.duration(new Date() - d).years());\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n edit: {\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs, cls, required, field) => input({\n type: \"text\",\n class: [\"form-control\", cls],\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n onChange: attrs.onChange,\n disabled: attrs.disabled,\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && {\n value: text_attr(typeof v === \"string\"\n ? new Date(v).toLocaleString(attrs.locale)\n : v.toLocaleString(attrs.locale)),\n }),\n }),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n editDay: {\n isEdit: true,\n blockDisplay: true,\n run: (nm, v, attrs, cls, required, field) => input({\n type: \"text\",\n class: [\"form-control\", cls],\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n onChange: attrs.onChange,\n disabled: attrs.disabled,\n id: `input${text_attr(nm)}`,\n ...(isdef(v) && {\n value: text_attr(typeof v === \"string\"\n ? new Date(v).toLocaleDateString(attrs.locale)\n : v.toLocaleDateString(attrs.locale)),\n }),\n }),\n },\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / date\n */\n presets: {\n Now: () => new Date(),\n },\n /**\n * @param {object} v\n * @param {object} attrs\n * @returns {object}\n */\n read: (v, attrs) => {\n if (v instanceof Date && !isNaN(v))\n return v;\n if (typeof v === \"string\") {\n if (attrs && attrs.locale) {\n const d = moment(v, \"L LT\", attrs.locale).toDate();\n if (d instanceof Date && !isNaN(d))\n return d;\n }\n const d = new Date(v);\n if (d instanceof Date && !isNaN(d))\n return d;\n else\n return null;\n }\n },\n /**\n * @param {object} param\n * @returns {boolean}\n */\n validate: ({}) => (v) => v instanceof Date && !isNaN(v),\n};\n/**\n * Boolean Type\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\nconst bool = {\n /** @type {string} */\n name: \"Bool\",\n /** @type {string} */\n sql_name: \"boolean\",\n /**\n * @returns {function}\n */\n contract: () => is.bool,\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\n fieldviews: {\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\n show: {\n isEdit: false,\n run: (v) => typeof v === \"undefined\" || v === null\n ? \"\"\n : !!v\n ? i({\n class: \"fas fa-lg fa-check-circle text-success\",\n })\n : i({\n class: \"fas fa-lg fa-times-circle text-danger\",\n }),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\n checkboxes: {\n isEdit: false,\n run: (v) => v === true\n ? input({ disabled: true, type: \"checkbox\", checked: true })\n : v === false\n ? input({ type: \"checkbox\", disabled: true })\n : \"\",\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\n TrueFalse: {\n isEdit: false,\n run: (v) => (v === true ? \"True\" : v === false ? \"False\" : \"\"),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\n edit: {\n isEdit: true,\n run: (nm, v, attrs, cls, required, field) => input({\n class: [\"me-2 mt-1\", cls],\n \"data-fieldname\": text_attr(field.name),\n type: \"checkbox\",\n onChange: attrs.onChange,\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n ...(v && { checked: true }),\n ...(attrs.disabled && { onclick: \"return false;\" }),\n }),\n },\n /**\n * @namespace\n * @category saltcorn-data\n * @subcategory types / bool\n */\n tristate: {\n isEdit: true,\n run: (nm, v, attrs, cls, required, field) => attrs.disabled\n ? !(!isdef(v) || v === null)\n ? \"\"\n : v\n ? \"T\"\n : \"F\"\n : input({\n type: \"hidden\",\n \"data-fieldname\": text_attr(field.name),\n name: text_attr(nm),\n id: `input${text_attr(nm)}`,\n value: !isdef(v) || v === null ? \"?\" : v ? \"on\" : \"off\",\n }) +\n button({\n onClick: `tristateClick('${text_attr(nm)}')`,\n type: \"button\",\n id: `trib${text_attr(nm)}`,\n }, !isdef(v) || v === null ? \"?\" : v ? \"T\" : \"F\"),\n },\n },\n /** @type {object[]} */\n attributes: [],\n /**\n * @param {*} rec\n * @param {string} name\n * @returns {boolean|null}\n */\n readFromFormRecord: (rec, name) => {\n if (!rec[name])\n return false;\n if ([\"undefined\", \"false\", \"off\"].includes(rec[name]))\n return false;\n if (rec[name] === \"?\")\n return null;\n return rec[name] ? true : false;\n },\n /**\n * @param {object} v\n * @returns {boolean|null}\n */\n read: (v) => {\n switch (typeof v) {\n case \"string\":\n if ([\"TRUE\", \"T\", \"ON\"].includes(v.toUpperCase()))\n return true;\n if (v === \"?\")\n return null;\n else\n return false;\n default:\n if (v === null)\n return null;\n return v ? true : false;\n }\n },\n /**\n * @param {object} v\n * @returns {object}\n */\n readFromDB: (v) => !!v,\n /**\n * @param {object} v\n * @returns {object}\n */\n listAs: (v) => JSON.stringify(v),\n /**\n * @returns {boolean}\n */\n validate: () => (x) => true,\n};\nmodule.exports = { string, int, bool, date, float, color };\n//# sourceMappingURL=types.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/types.js?");
|
|
83
|
+
|
|
84
|
+
/***/ }),
|
|
85
|
+
|
|
86
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/edit.js":
|
|
87
|
+
/*!***************************************************************!*\
|
|
88
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/edit.js ***!
|
|
89
|
+
\***************************************************************/
|
|
90
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
91
|
+
|
|
92
|
+
"use strict";
|
|
93
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/edit\n * @subcategory base-plugin\n */\nconst Field = __webpack_require__(/*! ../../models/field */ \"../saltcorn-data/dist/models/field.js\");\nconst File = __webpack_require__(/*! ../../models/file */ \"../saltcorn-data/dist/models/file.js\");\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst User = __webpack_require__(/*! ../../models/user */ \"../saltcorn-data/dist/models/user.js\");\nconst Crash = __webpack_require__(/*! ../../models/crash */ \"../saltcorn-data/dist/models/crash.js\");\nconst Form = __webpack_require__(/*! ../../models/form */ \"../saltcorn-data/dist/models/form.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst Trigger = __webpack_require__(/*! ../../models/trigger */ \"../saltcorn-data/dist/models/trigger.js\");\nconst { getState } = __webpack_require__(/*! ../../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst { text, text_attr } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { renderForm } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst FieldRepeat = __webpack_require__(/*! ../../models/fieldrepeat */ \"../saltcorn-data/dist/models/fieldrepeat.js\");\nconst { get_expression_function, expressionChecker, } = __webpack_require__(/*! ../../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\nconst { InvalidConfiguration, isNode, mergeIntoWhere } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst Library = __webpack_require__(/*! ../../models/library */ \"../saltcorn-data/dist/models/library.js\");\nconst { check_view_columns } = __webpack_require__(/*! ../../plugin-testing */ \"../saltcorn-data/dist/mobile-mocks/saltcorn/plugin-testing.js\");\nconst { initial_config_all_fields, calcfldViewOptions, calcfldViewConfig, get_parent_views, get_link_view_opts, picked_fields_to_query, stateFieldsToWhere, stateFieldsToQuery, strictParseInt, run_action_column, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { splitUniques, getForm, fill_presets, parse_view_select, get_view_link_query, objToQueryString, action_url, action_link, } = __webpack_require__(/*! ./viewable_fields */ \"../saltcorn-data/dist/base-plugin/viewtemplates/viewable_fields.js\");\nconst { traverse, getStringsForI18n, translateLayout, traverseSync, } = __webpack_require__(/*! ../../models/layout */ \"../saltcorn-data/dist/models/layout.js\");\nconst { asyncMap, isWeb } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst db = __webpack_require__(/*! ../../db */ \"../saltcorn-data/dist/db/index.js\");\nconst builtInActions = [\n \"Save\",\n \"SaveAndContinue\",\n \"Reset\",\n \"GoBack\",\n \"Delete\",\n \"Cancel\",\n];\n/**\n * @param {object} req\n * @returns {Workflow}\n */\nconst configuration_workflow = (req) => new Workflow({\n steps: [\n {\n name: req.__(\"Layout\"),\n builder: async (context) => {\n const table = await Table.findOne({ id: context.table_id });\n const fields = (await table.getFields()).filter((f) => !f.primary_key);\n for (const field of fields) {\n if (field.type === \"Key\") {\n field.reftable = await Table.findOne({\n name: field.reftable_name,\n });\n if (field.reftable)\n await field.reftable.getFields();\n }\n }\n const { field_view_options, handlesTextStyle, blockDisplay } = calcfldViewOptions(fields, \"edit\");\n const fieldViewConfigForms = await calcfldViewConfig(fields, true);\n const roles = await User.get_roles();\n const images = await File.find({ mime_super: \"image\" });\n const actions = [...builtInActions];\n const triggers = await Trigger.find({\n when_trigger: { or: [\"API call\", \"Never\"] },\n });\n triggers.forEach((tr) => {\n actions.push(tr.name);\n });\n const actionConfigForms = {\n Delete: [\n {\n name: \"after_delete_url\",\n label: req.__(\"URL after delete\"),\n type: \"String\",\n },\n ],\n GoBack: [\n {\n name: \"save_first\",\n label: req.__(\"Save before going back\"),\n type: \"Bool\",\n },\n {\n name: \"reload_after\",\n label: req.__(\"Reload after going back\"),\n type: \"Bool\",\n },\n {\n name: \"steps\",\n label: req.__(\"Steps to go back\"),\n type: \"Integer\",\n default: 1,\n },\n ],\n };\n const views = await get_link_view_opts(table, context.viewname);\n if (table.name === \"users\") {\n actions.push(\"Login\");\n actions.push(\"Sign up\");\n Object.entries(getState().auth_methods).forEach(([k, v]) => {\n actions.push(`Login with ${k}`);\n });\n fields.push({\n name: \"password\",\n label: req.__(\"Password\"),\n type: \"String\",\n });\n fields.push({\n name: \"passwordRepeat\",\n label: req.__(\"Password Repeat\"),\n type: \"String\",\n });\n fields.push({\n name: \"remember\",\n label: req.__(\"Remember me\"),\n type: \"Bool\",\n });\n field_view_options.password = [\"password\"];\n field_view_options.passwordRepeat = [\"password\"];\n field_view_options.remember = [\"edit\"];\n }\n const library = (await Library.find({})).filter((l) => l.suitableFor(\"edit\"));\n const myviewrow = await View.findOne({ name: context.viewname });\n const { parent_field_list } = await table.get_parent_relations(true, true);\n return {\n tableName: table.name,\n fields,\n field_view_options,\n parent_field_list,\n handlesTextStyle,\n blockDisplay,\n roles,\n actions,\n fieldViewConfigForms,\n actionConfigForms,\n images,\n min_role: (myviewrow || {}).min_role,\n library,\n views,\n mode: \"edit\",\n };\n },\n },\n {\n name: req.__(\"Fixed fields\"),\n contextField: \"fixed\",\n onlyWhen: async (context) => {\n const table = await Table.findOne({ id: context.table_id });\n const fields = await table.getFields();\n const in_form_fields = context.columns.map((f) => f.field_name);\n return fields.some((f) => !in_form_fields.includes(f.name) &&\n !f.calculated &&\n !f.primary_key);\n },\n form: async (context) => {\n const table = await Table.findOne({ id: context.table_id });\n const fields = await table.getFields();\n const in_form_fields = context.columns.map((f) => f.field_name);\n const omitted_fields = fields.filter((f) => !in_form_fields.includes(f.name) &&\n !f.calculated &&\n !f.primary_key);\n var formFields = [];\n omitted_fields.forEach((f) => {\n f.required = false;\n formFields.push(f);\n if (f.presets) {\n formFields.push(new Field({\n name: \"preset_\" + f.name,\n label: req.__(\"Preset %s\", f.label),\n type: \"String\",\n attributes: { options: Object.keys(f.presets) },\n }));\n }\n });\n const form = new Form({\n blurb: req.__(\"These fields were missing, you can give values here. The values you enter here can be overwritten by information coming from other views, for instance if the form is triggered from a list.\"),\n fields: formFields,\n });\n await form.fill_fkey_options();\n return form;\n },\n },\n {\n name: req.__(\"Edit options\"),\n onlyWhen: async (context) => {\n const done_views = await View.find_all_views_where(({ state_fields, viewrow }) => viewrow.name !== context.viewname &&\n (viewrow.table_id === context.table_id ||\n state_fields.every((sf) => !sf.required)));\n return done_views.length > 0;\n },\n form: async (context) => {\n const own_views = await View.find_all_views_where(({ state_fields, viewrow }) => viewrow.name !== context.viewname &&\n (viewrow.table_id === context.table_id ||\n state_fields.every((sf) => !sf.required)));\n const table = await Table.findOne({ id: context.table_id });\n const parent_views = await get_parent_views(table, context.viewname);\n const done_view_opts = own_views.map((v) => v.select_option);\n parent_views.forEach(({ relation, related_table, views }) => views.forEach((v) => {\n done_view_opts.push(`${v.name}.${relation.name}`);\n }));\n return new Form({\n fields: [\n {\n name: \"auto_save\",\n label: req.__(\"Auto save\"),\n sublabel: req.__(\"Save any changes immediately\"),\n type: \"Bool\",\n },\n {\n name: \"destination_type\",\n label: \"Destination type\",\n type: \"String\",\n required: true,\n sublabel: req.__(\"This is the view to which the user will be sent when the form is submitted. The view you specify here can be ignored depending on the context of the form, for instance if it appears in a pop-up the redirect will not take place.\"),\n //fieldview: \"radio_group\",\n attributes: {\n options: [\"View\", \"Formula\", \"Back to referer\"],\n },\n },\n {\n name: \"view_when_done\",\n label: req.__(\"Destination view\"),\n type: \"String\",\n required: true,\n attributes: {\n options: done_view_opts,\n },\n showIf: { destination_type: \"View\" },\n },\n new FieldRepeat({\n name: \"formula_destinations\",\n showIf: { destination_type: \"Formula\" },\n fields: [\n {\n type: \"String\",\n name: \"expression\",\n label: \"Formula\",\n class: \"validate-expression\",\n sublabel: \"if this formula evaluates to true, use the following view\",\n },\n {\n name: \"view\",\n label: req.__(\"View\"),\n type: \"String\",\n required: true,\n attributes: {\n options: done_view_opts,\n },\n },\n ],\n }),\n ],\n });\n },\n },\n ],\n});\n/**\n * @param {*} table_id\n * @param {*} viewname\n * @param {object} opts\n * @param {*} opts.columns\n * @returns {Promise<object[]>}\n */\nconst get_state_fields = async (table_id, viewname, { columns }) => [\n {\n name: \"id\",\n type: \"Integer\",\n primary_key: true,\n },\n];\n/**\n * @param {Form} form\n * @param {string} locale\n */\nconst setDateLocales = (form, locale) => {\n form.fields.forEach((f) => {\n if (f.type && f.type.name === \"Date\") {\n f.attributes.locale = locale;\n }\n });\n};\n/** @type {function} */\nconst initial_config = initial_config_all_fields(true);\n/**\n * @param {number} table_id\n * @param {string} viewname\n * @param {object} optsOne\n * @param {*} optsOne.columns\n * @param {*} optsOne.layout\n * @param {string} state\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {object} optsTwo.res\n * @returns {Promise<Form>}\n */\nconst run = async (table_id, viewname, {}, state, { res, req }, { editQuery }) => {\n return await editQuery(state);\n};\n/**\n * @param {number} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {*} opts.columns\n * @param {*} opts.layout\n * @param {State} state\n * @param {object} extra\n * @returns {Promise<Form[]>}\n */\nconst runMany = async (table_id, viewname, { columns, layout, auto_save }, state, extra, { editManyQuery, getRowQuery, optionsQuery }) => {\n let { table, fields, rows } = await editManyQuery(state, {\n limit: extra.limit,\n offset: extra.offset,\n orderBy: extra.orderBy,\n orderDesc: extra.orderDesc,\n where: extra.where,\n });\n if (!isNode()) {\n table = Table.findOne({ id: table.id });\n fields = await table.getFields();\n }\n return await asyncMap(rows, async (row) => {\n const html = await render({\n table,\n fields,\n viewname,\n columns,\n layout,\n row,\n req: extra.req,\n res: extra.res,\n state,\n auto_save,\n getRowQuery,\n optionsQuery,\n });\n return { html, row };\n });\n};\n/**\n * @param {object} opts\n * @param {Form} opts.form\n * @param {Table} opts.table\n * @param {object} opts.req\n * @param {object} opts.row\n * @param {object} opts.res\n * @throws {InvalidConfiguration}\n * @returns {Promise<void>}\n */\nconst transformForm = async ({ form, table, req, row, res, getRowQuery, viewname, }) => {\n await traverse(form.layout, {\n action(segment) {\n if (segment.action_name === \"Delete\") {\n if (form.values && form.values.id) {\n segment.action_url = `/delete/${table.name}/${form.values.id}`;\n }\n else {\n segment.type = \"blank\";\n segment.contents = \"\";\n }\n }\n else if (![\"Sign up\", ...builtInActions].includes(segment.action_name) &&\n !segment.action_name.startsWith(\"Login\")) {\n const url = action_url(viewname, table, segment.action_name, row, segment.rndid, \"rndid\");\n segment.action_link = action_link(url, req, segment);\n }\n },\n join_field(segment) {\n const qs = objToQueryString(segment.configuration);\n segment.sourceURL = `/field/show-calculated/${table.name}/${segment.join_field}/${segment.fieldview}?${qs}`;\n },\n async view(segment) {\n //console.log(segment);\n const view_select = parse_view_select(segment.view);\n //console.log({ view_select });\n const view = await View.findOne({ name: view_select.viewname });\n if (!view)\n throw new InvalidConfiguration(`Cannot find embedded view: ${view_select.viewname}`);\n if (view.viewtemplate === \"Edit\" && view_select.type === \"ChildList\") {\n const childTable = Table.findOne({ id: view.table_id });\n const childForm = await getForm(childTable, view.name, view.configuration.columns, view.configuration.layout, row?.id, req);\n traverseSync(childForm.layout, {\n field(segment) {\n segment.field_name = `${view_select.field_name}.${segment.field_name}`;\n },\n });\n const fr = new FieldRepeat({\n name: view_select.field_name,\n label: view_select.field_name,\n fields: childForm.fields,\n layout: childForm.layout,\n metadata: {\n table_id: childTable.id,\n relation: view_select.field_name,\n },\n });\n if (row?.id) {\n const childRows = getRowQuery\n ? await getRowQuery(view.table_id, view_select, row.id)\n : await childTable.getRows({\n [view_select.field_name]: row.id,\n });\n fr.metadata.rows = childRows;\n if (!fr.fields.map((f) => f.name).includes(childTable.pk_name))\n fr.fields.push({\n name: childTable.pk_name,\n input_type: \"hidden\",\n });\n }\n form.fields.push(fr);\n segment.type = \"field_repeat\";\n segment.field_repeat = fr;\n return;\n }\n if (!row) {\n segment.type = \"blank\";\n segment.contents = \"\";\n return;\n }\n if (!view)\n throw new InvalidConfiguration(`Edit view incorrectly configured: cannot find embedded view ${view_select.viewname}`);\n let state;\n switch (view_select.type) {\n case \"Own\":\n state = { id: row.id };\n break;\n case \"Independent\":\n state = {};\n break;\n case \"ChildList\":\n case \"OneToOneShow\":\n state = { [view_select.field_name]: row.id };\n break;\n case \"ParentShow\":\n state = { id: row[view_select.field_name] };\n break;\n }\n segment.contents = await view.run(state, { req, res });\n },\n });\n translateLayout(form.layout, req.getLocale());\n if (req.xhr)\n form.xhrSubmit = true;\n setDateLocales(form, req.getLocale());\n};\n/**\n * @param {object} opts\n * @param {Table} opts.table\n * @param {Fields[]} opts.fields\n * @param {string} opts.viewname\n * @param {object[]} opts.columns\n * @param {Layout} opts.layout\n * @param {object} opts.row\n * @param {object} opts.req\n * @param {object} opts.state\n * @param {object} opts.res\n * @returns {Promise<Form>}\n */\nconst render = async ({ table, fields, viewname, columns, layout, row, req, state, res, auto_save, destination_type, isRemote, getRowQuery, optionsQuery, }) => {\n const form = await getForm(table, viewname, columns, layout, state.id, req, isRemote);\n if (auto_save)\n form.onChange = `saveAndContinue(this, ${!isWeb(req) ? `'${form.action}'` : undefined})`;\n if (row) {\n form.values = row;\n const file_fields = form.fields.filter((f) => f.type === \"File\");\n for (const field of file_fields) {\n if (row[field.name]) {\n const file = await File.findOne({ id: row[field.name] });\n form.values[field.name] = file.filename;\n }\n }\n form.hidden(table.pk_name);\n }\n if (destination_type === \"Back to referer\") {\n form.hidden(\"_referer\");\n form.values._referer = req.headers?.referer;\n }\n Object.entries(state).forEach(([k, v]) => {\n const field = form.fields.find((f) => f.name === k);\n if (field && ((field.type && field.type.read) || field.is_fkey)) {\n form.values[k] = field.type.read ? field.type.read(v) : v;\n }\n else {\n const tbl_field = fields.find((f) => f.name === k);\n if (tbl_field && !field) {\n form.fields.push(new Field({ name: k, input_type: \"hidden\" }));\n form.values[k] = tbl_field.type.read ? tbl_field.type.read(v) : v;\n }\n }\n });\n await form.fill_fkey_options(false, optionsQuery);\n await transformForm({ form, table, req, row, res, getRowQuery, viewname });\n return renderForm(form, !isRemote && req.csrfToken ? req.csrfToken() : false);\n};\n/**\n * @param {number} table_id\n * @param {string} viewname\n * @param {object} optsOne\n * @param {object[]} optsOne.columns\n * @param {Layout} optsOne.layout\n * @param {object} optsOne.fixed\n * @param {boolean} optsOne.view_when_done\n * @param {object[]} optsOne.formula_destinations\n * @param {object} state\n * @param {*} body\n * @param {object} optsTwo\n * @param {object} optsTwo.res\n * @param {object} optsTwo.req\n * @param {string} optsTwo.redirect\n * @returns {Promise<void>}\n */\nconst runPost = async (table_id, viewname, { columns, layout, fixed, view_when_done, formula_destinations, auto_save, destination_type, }, state, body, { res, req, redirect }, { tryInsertQuery, tryUpdateQuery, getRowQuery }, remote) => {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n const form = await getForm(table, viewname, columns, layout, body.id, req);\n if (auto_save)\n form.onChange = `saveAndContinue(this, ${!isWeb(req) ? `'${form.action}'` : undefined})`;\n Object.entries(body).forEach(([k, v]) => {\n const form_field = form.fields.find((f) => f.name === k);\n const tbl_field = fields.find((f) => f.name === k);\n if (tbl_field && !form_field) {\n form.fields.push(new Field({ name: k, input_type: \"hidden\" }));\n }\n });\n setDateLocales(form, req.getLocale());\n await transformForm({\n form,\n table,\n req,\n row: body[table.pk_name]\n ? { [table.pk_name]: body[table.pk_name] }\n : undefined,\n getRowQuery,\n viewname,\n });\n const cancel = body._cancel;\n form.validate(body);\n if (form.hasErrors && !cancel) {\n if (req.xhr)\n res.status(422);\n await form.fill_fkey_options();\n res.sendWrap(viewname, renderForm(form, req.csrfToken ? req.csrfToken() : false));\n }\n else {\n let row;\n const pk = fields.find((f) => f.primary_key);\n let id = pk.type.read(body[pk.name]);\n if (typeof id === \"undefined\") {\n const use_fixed = await fill_presets(table, req, fixed);\n row = { ...use_fixed, ...form.values };\n }\n else if (cancel) {\n //get row\n row = await table.getRow({ id });\n }\n else {\n row = { ...form.values };\n }\n for (const field of form.fields.filter((f) => f.isRepeat)) {\n delete row[field.name];\n }\n const file_fields = form.fields.filter((f) => f.type === \"File\");\n for (const field of file_fields) {\n if (req.files && req.files[field.name]) {\n if (!isNode() && !remote) {\n req.flash(\"error\", \"The mobile-app supports no local files, please use a remote table.\");\n res.sendWrap(viewname, renderForm(form, req.csrfToken ? req.csrfToken() : false));\n return;\n }\n const file = isNode()\n ? await File.from_req_files(req.files[field.name], req.user ? req.user.id : null, (field.attributes && +field.attributes.min_role_read) || 1)\n : await File.upload(req.files[field.name]);\n row[field.name] = file.id;\n }\n else {\n delete row[field.name];\n }\n }\n const originalID = id;\n if (!cancel) {\n if (typeof id === \"undefined\") {\n const ins_res = await tryInsertQuery(row);\n if (ins_res.success) {\n id = ins_res.success;\n row[pk.name] = id;\n }\n else {\n req.flash(\"error\", text_attr(ins_res.error));\n res.sendWrap(viewname, renderForm(form, req.csrfToken ? req.csrfToken() : false));\n return;\n }\n }\n else {\n const upd_res = await tryUpdateQuery(row, id);\n if (upd_res.error) {\n req.flash(\"error\", text_attr(upd_res.error));\n res.sendWrap(viewname, renderForm(form, req.csrfToken()));\n return;\n }\n }\n for (const field of form.fields.filter((f) => f.isRepeat)) {\n const childTable = Table.findOne({ id: field.metadata?.table_id });\n for (const childRow of form.values[field.name]) {\n childRow[field.metadata?.relation] = id;\n if (childRow[childTable.pk_name]) {\n const upd_res = await childTable.tryUpdateRow(childRow, childRow[childTable.pk_name]);\n if (upd_res.error) {\n req.flash(\"error\", text_attr(upd_res.error));\n res.sendWrap(viewname, renderForm(form, req.csrfToken()));\n return;\n }\n }\n else {\n const ins_res = await childTable.tryInsertRow(childRow, req.user ? +req.user.id : undefined);\n if (ins_res.error) {\n req.flash(\"error\", text_attr(ins_res.error));\n res.sendWrap(viewname, renderForm(form, req.csrfToken()));\n return;\n }\n }\n }\n }\n }\n if (req.xhr && !originalID && !req.smr) {\n res.json({ id, view_when_done });\n return;\n }\n if (redirect) {\n res.redirect(redirect);\n return;\n }\n let use_view_when_done = view_when_done;\n if (destination_type === \"Back to referer\" && body._referer) {\n res.redirect(body._referer);\n return;\n }\n else if (destination_type !== \"View\")\n for (const { view, expression } of formula_destinations || []) {\n if (expression) {\n const f = get_expression_function(expression, fields);\n if (f(row)) {\n use_view_when_done = view;\n continue;\n }\n }\n }\n if (!use_view_when_done) {\n res.redirect(`/`);\n return;\n }\n const [viewname_when_done, relation] = use_view_when_done.split(\".\");\n const nxview = await View.findOne({ name: viewname_when_done });\n if (!nxview) {\n req.flash(\"warning\", `View \"${use_view_when_done}\" not found - change \"View when done\" in \"${viewname}\" view`);\n res.redirect(`/`);\n }\n else {\n const state_fields = await nxview.get_state_fields();\n let target = `/view/${text(viewname_when_done)}`;\n let query = \"\";\n if ((nxview.table_id === table_id || relation) &&\n state_fields.some((sf) => sf.name === pk.name)) {\n const get_query = get_view_link_query(fields);\n query = relation\n ? `?${pk.name}=${text(row[relation])}`\n : get_query(row);\n }\n const redirectPath = `${target}${query}`;\n if (!isWeb(req)) {\n res.json({ redirect: `get${redirectPath}` });\n }\n else {\n res.redirect(redirectPath);\n }\n }\n }\n};\nconst doAuthPost = async ({ body, table_id, req }) => {\n const table = await Table.findOne({ id: table_id });\n const user_id = req.user ? req.user.id : null;\n if (table.ownership_field_id && user_id) {\n const field_name = await table.owner_fieldname();\n if (typeof body[field_name] === \"undefined\") {\n const fields = await table.getFields();\n const { uniques } = splitUniques(fields, body);\n if (Object.keys(uniques).length > 0) {\n body = await table.getRow(uniques);\n return table.is_owner(req.user, body);\n }\n }\n else\n return field_name && `${body[field_name]}` === `${user_id}`;\n }\n if (table.ownership_formula && user_id) {\n return await table.is_owner(req.user, body);\n }\n if (table.name === \"users\" && `${body.id}` === `${user_id}`)\n return true;\n return false;\n};\n/**\n * @param {object} opts\n * @param {object} opts.body\n * @param {string} opts.table_id\n * @param {object} opts.req\n * @returns {Promise<boolean>}\n */\nconst authorise_post = async ({ body, table_id, req }, { authorizePostQuery }) => {\n return await authorizePostQuery(body, table_id);\n};\n/**\n * @param {number} table_id\n * @param {*} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {*} opts.layout\n * @param {*} body\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {*} optsTwo.res\n * @returns {Promise<object>}\n */\nconst run_action = async (table_id, viewname, { columns, layout }, body, { req, res }, { actionQuery }) => {\n const result = await actionQuery();\n if (result.json.error) {\n Crash.create({ message: result.json.error, stack: \"\" }, req);\n }\n return result;\n};\nmodule.exports = {\n /** @type {string} */\n name: \"Edit\",\n /** @type {string} */\n description: \"Form for creating a new row or editing existing rows\",\n configuration_workflow,\n run,\n runMany,\n runPost,\n get_state_fields,\n initial_config,\n /** @type {boolean} */\n display_state_form: false,\n authorise_post,\n /**\n * @param {object} opts\n * @param {object} opts.query\n * @param {...*} opts.rest\n * @returns {Promise<boolean>}\n */\n authorise_get: async ({ query, table_id, req }, { authorizeGetQuery }) => {\n return await authorizeGetQuery(query, table_id);\n },\n /**\n * @param {object} opts\n * @param {Layout} opts.layout\n * @returns {string[]}\n */\n getStringsForI18n({ layout }) {\n return getStringsForI18n(layout);\n },\n queries: ({ table_id, name, configuration: { columns, default_state, layout, auto_save, destination_type, }, req, res, }) => ({\n async editQuery(state) {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n const { uniques } = splitUniques(fields, state);\n let row = null;\n if (Object.keys(uniques).length > 0) {\n row = await table.getRow(uniques);\n }\n const isRemote = !isWeb(req);\n return await render({\n table,\n fields,\n viewname: name,\n columns,\n layout,\n row,\n req,\n res,\n state,\n auto_save,\n destination_type,\n isRemote,\n });\n },\n async editManyQuery(state, { limit, offset, orderBy, orderDesc, where }) {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n const { joinFields, aggregations } = picked_fields_to_query(columns, fields);\n const qstate = await stateFieldsToWhere({ fields, state });\n const q = await stateFieldsToQuery({ state, fields });\n if (where)\n mergeIntoWhere(qstate, where);\n const rows = await table.getJoinedRows({\n where: qstate,\n joinFields,\n aggregations,\n ...(limit && { limit: limit }),\n ...(offset && { offset: offset }),\n ...(orderBy && { orderBy: orderBy }),\n ...(orderDesc && { orderDesc: orderDesc }),\n ...q,\n });\n return {\n table,\n fields,\n rows,\n };\n },\n async tryInsertQuery(row) {\n const table = await Table.findOne({ id: table_id });\n const ins_res = await table.tryInsertRow(row, req.user ? +req.user.id : undefined);\n return ins_res;\n },\n async tryUpdateQuery(row, id) {\n const table = await Table.findOne({ id: table_id });\n const upd_res = await table.tryUpdateRow(row, id, req.user ? +req.user.id : undefined);\n return upd_res;\n },\n async authorizePostQuery(body, table_id /*overwrites*/) {\n return await doAuthPost({ body, table_id, req });\n },\n async authorizeGetQuery(query, table_id) {\n let body = query || {};\n if (Object.keys(body).length == 1) {\n const table = await Table.findOne({ id: table_id });\n if (table.ownership_field_id || table.ownership_formula) {\n const fields = await table.getFields();\n const { uniques } = splitUniques(fields, body);\n if (Object.keys(uniques).length > 0) {\n body = await table.getRow(uniques);\n return table.is_owner(req.user, body);\n }\n }\n }\n return doAuthPost({ body, table_id, req });\n },\n async getRowQuery(table_id, view_select, row_id) {\n const childTable = Table.findOne({ id: table_id });\n return await childTable.getRows({\n [view_select.field_name]: row_id,\n });\n },\n async actionQuery() {\n const body = req.body;\n const col = columns.find((c) => c.type === \"Action\" && c.rndid === body.rndid && body.rndid);\n const table = await Table.findOne({ id: table_id });\n const row = body.id ? await table.getRow({ id: body.id }) : undefined;\n try {\n const result = await run_action_column({\n col,\n req,\n table,\n row,\n referrer: req.get(\"Referrer\"),\n });\n return { json: { success: \"ok\", ...(result || {}) } };\n }\n catch (e) {\n return { json: { error: e.message || e } };\n }\n },\n async optionsQuery(reftable_name, type, attributes, where) {\n const rows = await db.select(reftable_name, type === \"File\" ? attributes.select_file_where : where);\n return rows;\n },\n }),\n routes: { run_action },\n configCheck: async (view) => {\n const { name, configuration: { view_when_done, destination_type, formula_destinations }, } = view;\n const errs = [];\n if (destination_type !== \"Back to referer\") {\n const vwd = await View.findOne({\n name: (view_when_done || \"\").split(\".\")[0],\n });\n if (!vwd)\n errs.push(`In View ${name}, view when done ${view_when_done} not found`);\n for (const { expression } of formula_destinations || []) {\n if (expression)\n expressionChecker(expression, `In View ${name}, destination formula ${expression} error: `, errs);\n }\n }\n errs.push(...(await check_view_columns(view, view.configuration.columns)));\n return errs;\n },\n};\n//# sourceMappingURL=edit.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/edit.js?");
|
|
94
|
+
|
|
95
|
+
/***/ }),
|
|
96
|
+
|
|
97
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/feed.js":
|
|
98
|
+
/*!***************************************************************!*\
|
|
99
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/feed.js ***!
|
|
100
|
+
\***************************************************************/
|
|
101
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
102
|
+
|
|
103
|
+
"use strict";
|
|
104
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/feed\n * @subcategory base-plugin\n */\nconst Field = __webpack_require__(/*! ../../models/field */ \"../saltcorn-data/dist/models/field.js\");\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst Form = __webpack_require__(/*! ../../models/form */ \"../saltcorn-data/dist/models/form.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst { text, div, h4, hr, button } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { pagination } = __webpack_require__(/*! @saltcorn/markup/helpers */ \"../saltcorn-markup/dist/helpers.js\");\nconst { renderForm, tabs, link } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { mkTable } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst {} = __webpack_require__(/*! ./viewable_fields */ \"../saltcorn-data/dist/base-plugin/viewtemplates/viewable_fields.js\");\nconst pluralize = __webpack_require__(/*! pluralize */ \"../../node_modules/pluralize/pluralize.js\");\nconst { link_view, stateToQueryString, stateFieldsToWhere, stateFieldsToQuery, readState, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { InvalidConfiguration, isNode, isWeb } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { getState } = __webpack_require__(/*! ../../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst { jsexprToWhere } = __webpack_require__(/*! ../../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\n/**\n * @param {object} req\n * @returns {Workflow}\n */\nconst configuration_workflow = (req) => new Workflow({\n steps: [\n {\n name: req.__(\"Views\"),\n form: async (context) => {\n const table = await Table.findOne(context.table_id);\n const show_views = await View.find_table_views_where(context.table_id, ({ state_fields, viewtemplate, viewrow }) => viewtemplate.runMany &&\n viewrow.name !== context.viewname &&\n state_fields.some((sf) => sf.name === \"id\"));\n const create_views = await View.find_table_views_where(context.table_id, ({ state_fields, viewrow }) => viewrow.name !== context.viewname &&\n state_fields.every((sf) => !sf.required));\n const show_view_opts = show_views.map((v) => v.select_option);\n const create_view_opts = create_views.map((v) => v.select_option);\n return new Form({\n fields: [\n {\n name: \"show_view\",\n label: req.__(\"Single item view\"),\n type: \"String\",\n sublabel: req.__(\"The underlying individual view of each table row\"),\n required: true,\n attributes: {\n options: show_view_opts,\n },\n },\n {\n name: \"view_to_create\",\n label: req.__(\"Use view to create\"),\n sublabel: req.__(\"If user has write permission. Leave blank to have no link to create a new item\"),\n type: \"String\",\n attributes: {\n options: create_view_opts,\n },\n },\n {\n name: \"create_view_display\",\n label: req.__(\"Display create view as\"),\n type: \"String\",\n required: true,\n attributes: {\n options: \"Link,Embedded,Popup\",\n },\n },\n {\n name: \"create_view_label\",\n label: req.__(\"Label for create\"),\n sublabel: req.__(\"Label in link or button to create. Leave blank for a default label\"),\n type: \"String\",\n showIf: { create_view_display: [\"Link\", \"Popup\"] },\n },\n {\n name: \"create_view_location\",\n label: req.__(\"Location\"),\n sublabel: req.__(\"Location of link to create new row\"),\n //required: true,\n attributes: {\n options: [\n \"Bottom left\",\n \"Bottom right\",\n \"Top left\",\n \"Top right\",\n ],\n },\n type: \"String\",\n showIf: { create_view_display: [\"Link\", \"Popup\"] },\n },\n ...(table.ownership_field_id\n ? [\n {\n name: \"always_create_view\",\n label: req.__(\"Always show create view\"),\n sublabel: req.__(\"If off, only show create view if the query state is about the current user\"),\n type: \"Bool\",\n },\n ]\n : []),\n ],\n });\n },\n },\n {\n name: req.__(\"Order and layout\"),\n form: async (context) => {\n const table = await Table.findOne({ id: context.table_id });\n const fields = await table.getFields();\n return new Form({\n fields: [\n {\n name: \"order_field\",\n label: req.__(\"Order by\"),\n type: \"String\",\n required: true,\n attributes: {\n options: fields.map((f) => f.name),\n },\n },\n {\n name: \"descending\",\n label: req.__(\"Descending\"),\n type: \"Bool\",\n required: true,\n },\n {\n name: \"include_fml\",\n label: req.__(\"Row inclusion formula\"),\n class: \"validate-expression\",\n sublabel: req.__(\"Only include rows where this formula is true\"),\n type: \"String\",\n },\n {\n name: \"cols_sm\",\n label: req.__(\"Columns small screen\"),\n type: \"Integer\",\n attributes: {\n min: 1,\n max: 4,\n },\n required: true,\n default: 1,\n },\n {\n name: \"cols_md\",\n label: req.__(\"Columns medium screen\"),\n type: \"Integer\",\n attributes: {\n min: 1,\n max: 4,\n },\n required: true,\n default: 1,\n },\n {\n name: \"cols_lg\",\n label: req.__(\"Columns large screen\"),\n type: \"Integer\",\n attributes: {\n min: 1,\n max: 4,\n },\n required: true,\n default: 1,\n },\n {\n name: \"cols_xl\",\n label: req.__(\"Columns extra-large screen\"),\n type: \"Integer\",\n attributes: {\n min: 1,\n max: 4,\n },\n required: true,\n default: 1,\n },\n {\n name: \"rows_per_page\",\n label: req.__(\"Items per page\"),\n type: \"Integer\",\n attributes: {\n min: 1,\n },\n required: true,\n default: 20,\n },\n {\n name: \"in_card\",\n label: req.__(\"Each in card?\"),\n type: \"Bool\",\n required: true,\n },\n {\n name: \"masonry_columns\",\n label: req.__(\"Masonry columns\"),\n type: \"Bool\",\n showIf: { in_card: true },\n required: true,\n },\n {\n name: \"hide_pagination\",\n label: req.__(\"Hide pagination\"),\n type: \"Bool\",\n required: true,\n },\n ],\n });\n },\n },\n ],\n});\n/**\n * @param {number} table_id\n * @param {*} viewname\n * @param {object} opts\n * @param {*} opts.show_view\n * @returns {Promise<Field>}\n */\nconst get_state_fields = async (table_id, viewname, { show_view }) => {\n const table_fields = await Field.find({ table_id });\n return table_fields\n .filter((f) => !f.primary_key)\n .map((f) => {\n const sf = new Field(f);\n sf.required = false;\n return sf;\n });\n};\n/**\n * @param {number} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {string} opts.show_view\n * @param {name} opts.order_field\n * @param {boolean} opts.descending\n * @param {string} [opts.view_to_create]\n * @param {string} opts.create_view_display\n * @param {boolean} opts.in_card\n * @param {string} opts.masonry_columns\n * @param {number} [opts.rows_per_page = 20]\n * @param {boolean} opts.hide_pagination\n * @param {string} [opts.create_view_label]\n * @param {string} [opts.create_view_location]\n * @param {boolean} opts.always_create_view\n * @param {*} opts.cols\n * @param {object} state\n * @param {*} extraArgs\n * @returns {Promise<div>}\n */\nconst run = async (table_id, viewname, { show_view, order_field, descending, view_to_create, create_view_display, in_card, masonry_columns, rows_per_page = 20, hide_pagination, create_view_label, create_view_location, always_create_view, include_fml, ...cols }, state, extraArgs, { countRowsQuery }) => {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n readState(state, fields);\n const appState = getState();\n const locale = extraArgs.req.getLocale();\n const __ = isNode()\n ? (s) => appState.i18n.__({ phrase: s, locale }) || s\n : (s) => s;\n const sview = await View.findOne({ name: show_view });\n if (!sview)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${show_view}`);\n const q = await stateFieldsToQuery({ state, fields });\n let qextra = {};\n if (!q.orderBy) {\n qextra.orderBy = order_field;\n if (descending)\n qextra.orderDesc = true;\n }\n qextra.limit = q.limit || rows_per_page;\n const current_page = parseInt(state._page) || 1;\n if (include_fml) {\n qextra.where = jsexprToWhere(include_fml, state);\n }\n const sresp = await sview.runMany(state, {\n ...extraArgs,\n ...qextra,\n });\n let paginate = \"\";\n if (!hide_pagination && (sresp.length === qextra.limit || current_page > 1)) {\n const nrows = await countRowsQuery(state);\n if (nrows > qextra.limit || current_page > 1) {\n paginate = pagination({\n current_page,\n pages: Math.ceil(nrows / qextra.limit),\n get_page_link: (n) => `javascript:gopage(${n}, ${qextra.limit}, { _paged_view:'${viewname}' })`,\n });\n }\n }\n const [vpos, hpos] = (create_view_location || \"Bottom left\").split(\" \");\n const istop = vpos === \"Top\";\n const isright = hpos === \"right\";\n const role = extraArgs && extraArgs.req && extraArgs.req.user\n ? extraArgs.req.user.role_id\n : 10;\n var create_link = \"\";\n const user_id = extraArgs && extraArgs.req.user ? extraArgs.req.user.id : null;\n const about_user = fields.some((f) => f.reftable_name === \"users\" && state[f.name] && state[f.name] === user_id);\n if (view_to_create &&\n (role <= table.min_role_write ||\n (table.ownership_field_id && (about_user || always_create_view)))) {\n if (create_view_display === \"Embedded\") {\n const create_view = await View.findOne({ name: view_to_create });\n if (!create_view)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find embedded view to create ${view_to_create}`);\n create_link = await create_view.run(state, extraArgs);\n }\n else {\n const target = `/view/${encodeURIComponent(view_to_create)}${stateToQueryString(state)}`;\n const hrefVal = isWeb(extraArgs.req)\n ? target\n : `javascript:execLink('${target}');`;\n create_link = link_view(hrefVal, __(create_view_label) || `Add ${pluralize(table.name, 1)}`, create_view_display === \"Popup\", create_view_display === \"Popup\" && \"btn btn-secondary\", create_view_display === \"Popup\" && \"btn-sm\");\n }\n }\n const create_link_div = isright\n ? div({ class: \"float-end\" }, create_link)\n : create_link;\n const setCols = (sz) => `col-${sz}-${Math.round(12 / cols[`cols_${sz}`])}`;\n const showRowInner = (r) => in_card\n ? div({ class: `card shadow ${masonry_columns ? \"mt-2\" : \"mt-4\"}` }, div({ class: \"card-body\" }, r.html))\n : r.html;\n const showRow = (r) => div({\n class: [setCols(\"sm\"), setCols(\"md\"), setCols(\"lg\"), setCols(\"xl\")],\n }, showRowInner(r));\n const correct_order = ([main, pagin, create]) => istop ? [create, main, pagin] : [main, pagin, create];\n const inner = in_card && masonry_columns\n ? div(correct_order([\n div({ class: \"card-columns\" }, sresp.map(showRowInner)),\n paginate,\n create_link_div,\n ]))\n : div(correct_order([\n div({ class: \"row\" }, sresp.map(showRow)),\n paginate,\n create_link_div,\n ]));\n return inner;\n};\nmodule.exports = {\n /** @type {string} */\n name: \"Feed\",\n /** @type {string} */\n description: \"Show multiple rows by displaying a chosen view for each row, stacked or in columns\",\n configuration_workflow,\n run,\n get_state_fields,\n /** @type {boolean} */\n display_state_form: false,\n /**\n * @param {object} opts\n * @param {*} opts.create_view_label\n * @returns {string[]|Object[]}\n */\n getStringsForI18n({ create_view_label }) {\n if (create_view_label)\n return [create_view_label];\n else\n return [];\n },\n queries: ({ table_id, viewname, configuration: { columns, default_state }, req, }) => ({\n async countRowsQuery(state) {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n const where = await stateFieldsToWhere({ fields, state });\n return await table.countRows(where);\n },\n }),\n};\n//# sourceMappingURL=feed.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/feed.js?");
|
|
105
|
+
|
|
106
|
+
/***/ }),
|
|
107
|
+
|
|
108
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/filter.js":
|
|
109
|
+
/*!*****************************************************************!*\
|
|
110
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/filter.js ***!
|
|
111
|
+
\*****************************************************************/
|
|
112
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
113
|
+
|
|
114
|
+
"use strict";
|
|
115
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/filter\n * @subcategory base-plugin\n */\nconst User = __webpack_require__(/*! ../../models/user */ \"../saltcorn-data/dist/models/user.js\");\nconst Page = __webpack_require__(/*! ../../models/page */ \"../saltcorn-data/dist/models/page.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst Field = __webpack_require__(/*! ../../models/field */ \"../saltcorn-data/dist/models/field.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst { div, text, span, i, option, select, button, text_attr, script, } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst renderLayout = __webpack_require__(/*! @saltcorn/markup/layout */ \"../saltcorn-markup/dist/layout.js\");\nconst { readState, calcfldViewOptions, calcfldViewConfig, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { search_bar } = __webpack_require__(/*! @saltcorn/markup/helpers */ \"../saltcorn-markup/dist/helpers.js\");\nconst { eachView, translateLayout, getStringsForI18n, traverse, } = __webpack_require__(/*! ../../models/layout */ \"../saltcorn-data/dist/models/layout.js\");\nconst { InvalidConfiguration } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { jsexprToWhere } = __webpack_require__(/*! ../../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\nconst Library = __webpack_require__(/*! ../../models/library */ \"../saltcorn-data/dist/models/library.js\");\nconst { getState } = __webpack_require__(/*! ../../db/state */ \"../saltcorn-data/dist/db/state.js\");\n/**\n * @returns {Workflow}\n */\nconst configuration_workflow = () => new Workflow({\n steps: [\n {\n name: \"Layout\",\n builder: async (context) => {\n const table = await Table.findOne(context.table_id || context.exttable_name);\n const fields = await table.getFields();\n const { child_field_list, child_relations } = await table.get_child_relations();\n const roles = await User.get_roles();\n for (const cr of child_relations) {\n const cfields = await cr.table.getFields();\n cfields.forEach((cf) => {\n if (cf.name !== cr.key_field.name)\n fields.push(new Field({\n ...cf,\n label: `${cr.table.name}.${cr.key_field.name}→${cf.name}`,\n name: `${cr.table.name}.${cr.key_field.name}.${cf.name}`,\n }));\n });\n }\n const actions = [\"Clear\"];\n const own_link_views = await View.find_table_views_where(context.table_id || context.exttable_name, ({ viewrow }) => viewrow.name !== context.viewname);\n const views = own_link_views.map((v) => ({\n label: v.name,\n name: v.name,\n viewtemplate: v.viewtemplate,\n }));\n for (const field of fields) {\n const presets = field.presets;\n field.preset_options = presets ? Object.keys(presets) : [];\n }\n const library = (await Library.find({})).filter((l) => l.suitableFor(\"filter\"));\n const fieldViewConfigForms = await calcfldViewConfig(fields, false);\n const { field_view_options, handlesTextStyle } = calcfldViewOptions(fields, \"filter\");\n const pages = await Page.find();\n return {\n fields,\n tableName: table.name,\n roles,\n actions,\n views,\n pages,\n library,\n field_view_options,\n fieldViewConfigForms,\n mode: \"filter\",\n };\n },\n },\n ],\n});\n/** @returns {object[]} */\nconst get_state_fields = () => [];\n/**\n *\n * @returns {Promise<object>}\n */\nconst initial_config = async () => ({ layout: {}, columns: [] });\n/**\n * @param {number} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {object} opts.layout\n * @param {object} state\n * @param {object} extra\n * @returns {Promise<Layout>}\n */\nconst run = async (table_id, viewname, { columns, layout }, state, extra, { distinctValuesQuery }) => {\n //console.log(columns);\n //console.log(layout);\n if (!columns || !layout)\n return \"View not yet built\";\n const table = await Table.findOne(table_id);\n const fields = await table.getFields();\n readState(state, fields);\n const { distinct_values, role } = await distinctValuesQuery();\n const badges = [];\n Object.entries(state).forEach(([k, v]) => {\n if (typeof v === \"undefined\")\n return;\n if (k[0] !== \"_\") {\n let showv = v;\n if (distinct_values[k]) {\n const realv = distinct_values[k].find((dv) => dv.value === v);\n if (realv)\n showv = realv.label;\n }\n badges.push({\n text: `${text_attr(k)}:${text_attr(showv)}`,\n onclick: `unset_state_field('${text_attr(k)}')`,\n });\n }\n });\n await traverse(layout, {\n field: async (segment) => {\n const { field_name, fieldview, configuration } = segment;\n let field = fields.find((fld) => fld.name === field_name);\n if (!field)\n return;\n field.fieldview = fieldview;\n Object.assign(field.attributes, configuration);\n await field.fill_fkey_options();\n segment.field = field;\n },\n view: async (segment) => {\n const view = await View.findOne({ name: segment.view });\n if (!view)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${segment.view}`);\n else\n segment.contents = await view.run(state, extra);\n },\n link: (segment) => {\n if (segment.transfer_state) {\n segment.url +=\n `?` +\n Object.entries(state || {})\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join(\"&\");\n }\n },\n });\n translateLayout(layout, extra.req.getLocale());\n const blockDispatch = {\n field(segment) {\n const { field_name, fieldview, configuration, field } = segment;\n if (!field)\n return \"\";\n //console.log({ fieldview, field });\n if (fieldview && field.type && field.type === \"Key\") {\n const fv = getState().keyFieldviews[fieldview];\n if (fv && (fv.isEdit || fv.isFilter)) {\n segment.options = distinct_values[field_name];\n return fv.run(field_name, state[field_name], {\n onChange: `set_state_field('${field_name}', this.value)`,\n ...field.attributes,\n isFilter: true,\n ...configuration,\n }, \"\", false, field, state);\n }\n }\n if (fieldview &&\n field.type &&\n field.type.fieldviews &&\n field.type.fieldviews[fieldview]) {\n const fv = field.type.fieldviews[fieldview];\n if (fv.isEdit || fv.isFilter)\n return fv.run(field_name, state[field_name], {\n onChange: `set_state_field('${field_name}', this.value)`,\n isFilter: true,\n ...field.attributes,\n ...configuration,\n }, \"\", false, field, state);\n }\n return \"\";\n },\n search_bar({ has_dropdown, contents, show_badges }, go) {\n const rendered_contents = go(contents);\n return search_bar(\"_fts\", state[\"_fts\"], {\n stateField: \"_fts\",\n has_dropdown,\n contents: rendered_contents,\n badges: show_badges ? badges : null,\n });\n },\n dropdown_filter({ field_name, neutral_label, full_width }) {\n return select({\n name: `ddfilter${field_name}`,\n class: \"form-control form-select d-inline\",\n style: full_width ? undefined : \"width: unset;\",\n onchange: `this.value=='' ? unset_state_field('${field_name}'): set_state_field('${field_name}', this.value)`,\n }, (distinct_values[field_name] || []).map(({ label, value, jsvalue }) => option({\n value,\n selected: state[field_name] === or_if_undef(jsvalue, value),\n class: !value && !label ? \"text-muted\" : undefined,\n }, !value && !label ? neutral_label : label)));\n },\n action({ block, action_label, action_style, action_size, action_icon, action_name, }) {\n const label = action_label || action_name;\n if (action_style === \"btn-link\")\n return a({ href: \"javascript:clear_state()\" }, action_icon ? i({ class: action_icon }) + \" \" : false, label);\n else\n return button({\n onClick: \"clear_state()\",\n class: `btn ${action_style || \"btn-primary\"} ${action_size || \"\"}`,\n }, action_icon ? i({ class: action_icon }) + \" \" : false, label);\n },\n toggle_filter({ field_name, value, preset_value, label, size, style }) {\n const field = fields.find((f) => f.name === field_name);\n const isBool = field && field.type.name === \"Bool\";\n const use_value = preset_value && field.presets\n ? field.presets[preset_value]({\n user: extra.req.user,\n req: extra.req,\n })\n : value;\n const active = isBool\n ? {\n on: state[field_name],\n off: state[field_name] === false,\n \"?\": state[field_name] === null,\n }[use_value]\n : eq_string(state[field_name], use_value);\n return button({\n class: [\n \"btn\",\n active\n ? `btn-${style || \"primary\"}`\n : `btn-outline-${style || \"primary\"}`,\n size && size,\n ],\n onClick: active || use_value === undefined\n ? `unset_state_field('${field_name}')`\n : `set_state_field('${field_name}', '${use_value || \"\"}')`,\n }, label || value || preset_value);\n },\n };\n return div({ class: \"form-namespace\" }, renderLayout({ blockDispatch, layout, role, req: extra.req }));\n};\n/**\n * @param {object|undefined} x\n * @param {object|undefined} y\n * @returns {object}\n */\nconst or_if_undef = (x, y) => (typeof x === \"undefined\" ? y : x);\n/**\n * @param {string} x\n * @param {string} y\n * @returns {boolean}\n */\nconst eq_string = (x, y) => `${x}` === `${y}`;\nmodule.exports = {\n /** @type {string} */\n name: \"Filter\",\n /** @type {string} */\n description: \"Elements that limit the rows shown in other views on the same page. Filter views do not show any rows on their own.\",\n get_state_fields,\n configuration_workflow,\n run,\n initial_config,\n /** @type {boolean} */\n display_state_form: false,\n /**\n * @param {object} opts\n * @param {*} opts.layout\n * @returns {string[]}\n */\n getStringsForI18n({ layout }) {\n return getStringsForI18n(layout);\n },\n queries: ({ table_id, viewname, configuration: { columns, default_state }, req, }) => ({\n async distinctValuesQuery() {\n const table = await Table.findOne(table_id);\n const fields = await table.getFields();\n let distinct_values = {};\n const role = req.user ? req.user.role_id : 10;\n for (const col of columns) {\n if (col.type === \"DropDownFilter\") {\n const field = fields.find((f) => f.name === col.field_name);\n if (table.external) {\n distinct_values[col.field_name] = (await table.distinctValues(col.field_name)).map((x) => ({ label: x, value: x }));\n }\n else if (field)\n distinct_values[col.field_name] = await field.distinct_values(req, jsexprToWhere(col.where));\n else if (col.field_name.includes(\".\")) {\n const kpath = col.field_name.split(\".\");\n if (kpath.length === 3) {\n const [jtNm, jFieldNm, lblField] = kpath;\n const jtable = await Table.findOne({ name: jtNm });\n if (!jtable)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find join table ${jtNm}`);\n const jfields = await jtable.getFields();\n const jfield = jfields.find((f) => f.name === lblField);\n if (jfield)\n distinct_values[col.field_name] = await jfield.distinct_values(req, jsexprToWhere(col.where));\n }\n }\n const dvs = distinct_values[col.field_name];\n if (dvs && dvs[0]) {\n if (dvs[0].value !== \"\") {\n dvs.unshift({ label: \"\", value: \"\" });\n }\n }\n }\n }\n return { distinct_values, role };\n },\n }),\n};\n//# sourceMappingURL=filter.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/filter.js?");
|
|
116
|
+
|
|
117
|
+
/***/ }),
|
|
118
|
+
|
|
119
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/list.js":
|
|
120
|
+
/*!***************************************************************!*\
|
|
121
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/list.js ***!
|
|
122
|
+
\***************************************************************/
|
|
123
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
124
|
+
|
|
125
|
+
"use strict";
|
|
126
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/list\n * @subcategory base-plugin\n */\nconst Field = __webpack_require__(/*! ../../models/field */ \"../saltcorn-data/dist/models/field.js\");\nconst FieldRepeat = __webpack_require__(/*! ../../models/fieldrepeat */ \"../saltcorn-data/dist/models/fieldrepeat.js\");\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst Form = __webpack_require__(/*! ../../models/form */ \"../saltcorn-data/dist/models/form.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst Crash = __webpack_require__(/*! ../../models/crash */ \"../saltcorn-data/dist/models/crash.js\");\nconst { mkTable, h, post_btn, link } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { text, script, button, div } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst pluralize = __webpack_require__(/*! pluralize */ \"../../node_modules/pluralize/pluralize.js\");\nconst { removeEmptyStrings, removeDefaultColor, applyAsync, mergeIntoWhere, } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { field_picker_fields, picked_fields_to_query, stateFieldsToWhere, initial_config_all_fields, stateToQueryString, stateFieldsToQuery, link_view, getActionConfigFields, readState, run_action_column, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { get_viewable_fields } = __webpack_require__(/*! ./viewable_fields */ \"../saltcorn-data/dist/base-plugin/viewtemplates/viewable_fields.js\");\nconst { getState } = __webpack_require__(/*! ../../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst { get_async_expression_function, jsexprToWhere, } = __webpack_require__(/*! ../../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\nconst db = __webpack_require__(/*! ../../db */ \"../saltcorn-data/dist/db/index.js\");\nconst { get_existing_views } = __webpack_require__(/*! ../../models/discovery */ \"../saltcorn-data/dist/models/discovery.js\");\nconst { InvalidConfiguration, isWeb } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { check_view_columns } = __webpack_require__(/*! ../../plugin-testing */ \"../saltcorn-data/dist/mobile-mocks/saltcorn/plugin-testing.js\");\n/**\n * @param {object} context\n * @returns {Promise<void>}\n */\nconst create_db_view = async (context) => {\n const table = await Table.findOne({ id: context.table_id });\n const fields = await table.getFields();\n const { joinFields, aggregations } = picked_fields_to_query(context.columns, fields);\n const { sql } = await table.getJoinedQuery({\n where: {},\n joinFields,\n aggregations,\n });\n const schema = db.getTenantSchemaPrefix();\n // is there already a table with this name ? if yes add _sqlview\n const extable = await Table.findOne({ name: context.viewname });\n const sql_view_name = `${schema}\"${db.sqlsanitize(context.viewname)}${extable ? \"_sqlview\" : \"\"}\"`;\n await db.query(`drop view if exists ${sql_view_name};`);\n await db.query(`create or replace view ${sql_view_name} as ${sql};`);\n};\n/**\n * @param {*} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {*} opts.default_state\n * @returns {Promise<void>}\n */\nconst on_delete = async (table_id, viewname, { default_state }) => {\n if (!db.isSQLite) {\n const sqlviews = (await get_existing_views()).map((v) => v.table_name);\n const vnm = db.sqlsanitize(viewname);\n const schema = db.getTenantSchemaPrefix();\n if (sqlviews.includes(vnm))\n await db.query(`drop view if exists ${schema}\"${vnm}\";`);\n if (sqlviews.includes(vnm + \"_sqlview\"))\n await db.query(`drop view if exists ${schema}\"${vnm + \"_sqlview\"}\";`);\n }\n};\n/**\n * @param {object} req\n * @returns {Workflow}\n */\nconst configuration_workflow = (req) => new Workflow({\n onDone: async (ctx) => {\n if (ctx.default_state._create_db_view) {\n await create_db_view(ctx);\n }\n return ctx;\n },\n steps: [\n {\n name: req.__(\"Columns\"),\n form: async (context) => {\n const table = await Table.findOne(context.table_id\n ? { id: context.table_id }\n : { name: context.exttable_name });\n //console.log(context);\n const field_picker_repeat = await field_picker_fields({\n table,\n viewname: context.viewname,\n req,\n });\n const create_views = await View.find_table_views_where(context.table_id || context.exttable_name, ({ state_fields, viewrow }) => viewrow.name !== context.viewname &&\n state_fields.every((sf) => !sf.required));\n const create_view_opts = create_views.map((v) => v.select_option);\n return new Form({\n blurb: req.__(\"Specify the fields in the table to show\"),\n fields: [\n new FieldRepeat({\n name: \"columns\",\n fancyMenuEditor: true,\n fields: field_picker_repeat,\n }),\n ...(create_view_opts.length > 0\n ? [\n {\n name: \"view_to_create\",\n label: req.__(\"Use view to create\"),\n sublabel: req.__(\"If user has write permission. Leave blank to have no link to create a new item\"),\n type: \"String\",\n attributes: {\n options: create_view_opts,\n },\n },\n {\n name: \"create_view_display\",\n label: req.__(\"Display create view as\"),\n type: \"String\",\n required: true,\n attributes: {\n options: \"Link,Embedded,Popup\",\n },\n },\n {\n name: \"create_view_label\",\n label: req.__(\"Label for create\"),\n sublabel: req.__(\"Label in link or button to create. Leave blank for a default label\"),\n type: \"String\",\n showIf: { create_view_display: [\"Link\", \"Popup\"] },\n },\n {\n name: \"create_view_location\",\n label: req.__(\"Location\"),\n sublabel: req.__(\"Location of link to create new row\"),\n //required: true,\n attributes: {\n options: [\n \"Bottom left\",\n \"Bottom right\",\n \"Top left\",\n \"Top right\",\n ],\n },\n type: \"String\",\n showIf: { create_view_display: [\"Link\", \"Popup\"] },\n },\n ]\n : []),\n ],\n });\n },\n },\n {\n name: req.__(\"Default state\"),\n contextField: \"default_state\",\n form: async (context) => {\n const table = await Table.findOne(context.table_id || context.exttable_name);\n const table_fields = (await table.getFields()).filter((f) => !f.calculated || f.stored);\n const formfields = table_fields.map((f) => {\n return {\n name: f.name,\n label: f.label,\n type: f.type,\n reftable_name: f.reftable_name,\n attributes: f.attributes,\n fieldview: f.type && f.type.name === \"Bool\" ? \"tristate\" : undefined,\n required: false,\n };\n });\n const form = new Form({\n fields: formfields,\n blurb: req.__(\"Default search form values when first loaded\"),\n });\n await form.fill_fkey_options(true);\n form.fields.forEach((ff) => {\n if (ff.reftable_name === \"users\" && ff.options) {\n // key to user\n //console.log(ff);\n ff.options.push({\n label: \"LoggedIn\",\n value: \"Preset:LoggedIn\",\n });\n }\n });\n return form;\n },\n },\n {\n name: req.__(\"Options\"),\n contextField: \"default_state\",\n form: async (context) => {\n const table = await Table.findOne(context.table_id || context.exttable_name);\n const table_fields = (await table.getFields()).filter((f) => !f.calculated || f.stored);\n const formfields = [];\n formfields.push({\n name: \"_order_field\",\n label: req.__(\"Default order by\"),\n type: \"String\",\n attributes: {\n options: table_fields.map((f) => f.name),\n },\n });\n formfields.push({\n name: \"_descending\",\n label: req.__(\"Default descending?\"),\n type: \"Bool\",\n required: true,\n });\n formfields.push({\n name: \"include_fml\",\n label: req.__(\"Row inclusion formula\"),\n class: \"validate-expression\",\n sublabel: req.__(\"Only include rows where this formula is true\"),\n type: \"String\",\n });\n formfields.push({\n name: \"transpose\",\n label: req.__(\"Transpose\"),\n sublabel: req.__(\"Display one column per line\"),\n type: \"Bool\",\n });\n formfields.push({\n name: \"transpose_width\",\n label: req.__(\"Vertical column width\"),\n type: \"Integer\",\n showIf: { transpose: true },\n });\n formfields.push({\n name: \"transpose_width_units\",\n label: req.__(\"Vertical width units\"),\n type: \"String\",\n fieldview: \"radio_group\",\n attributes: {\n inline: true,\n options: [\"px\", \"%\", \"vw\", \"em\", \"rem\"],\n },\n showIf: { transpose: true },\n });\n formfields.push({\n name: \"_omit_state_form\",\n label: req.__(\"Omit search form\"),\n sublabel: req.__(\"Do not display the search filter form\"),\n type: \"Bool\",\n default: true,\n });\n formfields.push({\n name: \"_omit_header\",\n label: req.__(\"Omit header\"),\n sublabel: req.__(\"Do not display the header\"),\n type: \"Bool\",\n });\n formfields.push({\n name: \"hide_null_columns\",\n label: req.__(\"Hide null columns\"),\n sublabel: req.__(\"Do not display a column if it contains entirely missing values\"),\n type: \"Bool\",\n });\n if (!db.isSQLite && !table.external)\n formfields.push({\n name: \"_create_db_view\",\n label: req.__(\"Create database view\"),\n sublabel: req.__(\"Create an SQL view in the database with the fields in this list\"),\n type: \"Bool\",\n });\n formfields.push({\n name: \"_rows_per_page\",\n label: req.__(\"Rows per page\"),\n type: \"Integer\",\n default: 20,\n attributes: { min: 0 },\n });\n const form = new Form({\n fields: formfields,\n blurb: req.__(\"List options\"),\n });\n await form.fill_fkey_options(true);\n return form;\n },\n },\n ],\n});\n/**\n * @param {string} table_id\n * @param {*} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @returns {function}\n */\nconst get_state_fields = async (table_id, viewname, { columns }) => {\n const table_fields = await Field.find({ table_id });\n var state_fields = [];\n state_fields.push({ name: \"_fts\", label: \"Anywhere\", input_type: \"text\" });\n (columns || []).forEach((column) => {\n if (column.type === \"Field\" && column.state_field) {\n const tbl_fld = table_fields.find((f) => f.name == column.field_name);\n if (tbl_fld) {\n const f = new Field(tbl_fld);\n f.required = false;\n if (column.header_label)\n f.label = column.header_label;\n state_fields.push(f);\n }\n }\n });\n state_fields.push({ name: \"_sortby\", input_type: \"hidden\" });\n state_fields.push({ name: \"_page\", input_type: \"hidden\" });\n return state_fields;\n};\n/**\n * @param {object} opts\n * @param {object} opts.layout\n * @param {object[]} opts.fields\n * @returns {Promise<void>}\n */\nconst set_join_fieldviews = async ({ table, columns, fields }) => {\n for (const segment of columns) {\n const { join_field, join_fieldview } = segment;\n if (!join_fieldview)\n continue;\n const field = await table.getField(join_field);\n if (field && field.type === \"File\")\n segment.field_type = \"File\";\n else if (field?.type.name && field?.type?.fieldviews[join_fieldview])\n segment.field_type = field.type.name;\n }\n};\n/** @type {function} */\nconst initial_config = initial_config_all_fields(false);\n/**\n * @param {string|number} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {string} [opts.view_to_create]\n * @param {string} opts.create_view_display\n * @param {string} [opts.create_view_label]\n * @param {object} [opts.default_state]\n * @param {string} [opts.create_view_location]\n * @param {object} [stateWithId]\n * @param {object} extraOpts\n * @returns {Promise<*>}\n */\nconst run = async (table_id, viewname, { columns, view_to_create, create_view_display, create_view_label, default_state, create_view_location, }, stateWithId, extraOpts, { listQuery }) => {\n const table = await Table.findOne(typeof table_id === \"string\" ? { name: table_id } : { id: table_id });\n const fields = await table.getFields();\n const appState = getState();\n const locale = extraOpts.req.getLocale();\n const __ = (s) => isWeb(extraOpts.req) ? appState.i18n.__({ phrase: s, locale }) || s : s;\n //move fieldview cfg into configuration subfield in each column\n for (const col of columns) {\n if (col.type === \"Field\") {\n const field = fields.find((f) => f.name === col.field_name);\n if (!field)\n continue;\n const fieldviews = field.type === \"Key\"\n ? appState.keyFieldviews\n : field.type.fieldviews || {};\n if (!fieldviews)\n continue;\n const fv = fieldviews[col.fieldview];\n if (fv && fv.configFields) {\n const cfgForm = await applyAsync(fv.configFields, field);\n col.configuration = {};\n for (const formField of cfgForm || []) {\n col.configuration[formField.name] = col[formField.name];\n }\n }\n }\n }\n const role = extraOpts && extraOpts.req && extraOpts.req.user\n ? extraOpts.req.user.role_id\n : 10;\n await set_join_fieldviews({ table, columns, fields });\n const tfields = get_viewable_fields(viewname, table, fields, columns, false, extraOpts.req, __);\n readState(stateWithId, fields, extraOpts.req);\n const { id, ...state } = stateWithId || {};\n const { rows, rowCount } = await listQuery(state);\n const rows_per_page = (default_state && default_state._rows_per_page) || 20;\n const current_page = parseInt(state._page) || 1;\n var page_opts = extraOpts && extraOpts.onRowSelect\n ? { onRowSelect: extraOpts.onRowSelect, selectedId: id }\n : { selectedId: id };\n if ((rows && rows.length === rows_per_page) || current_page > 1) {\n const nrows = rowCount;\n if (nrows > rows_per_page || current_page > 1) {\n page_opts.pagination = {\n current_page,\n pages: Math.ceil(nrows / rows_per_page),\n get_page_link: (n) => `javascript:gopage(${n}, ${rows_per_page}, { _paged_view:'${viewname}' })`,\n };\n }\n }\n if (default_state && default_state._omit_header) {\n page_opts.noHeader = true;\n }\n page_opts.transpose = (default_state || {}).transpose;\n page_opts.transpose_width = (default_state || {}).transpose_width;\n page_opts.transpose_width_units = (default_state || {}).transpose_width_units;\n const [vpos, hpos] = (create_view_location || \"Bottom left\").split(\" \");\n const istop = vpos === \"Top\";\n const isright = hpos === \"right\";\n var create_link = \"\";\n const user_id = extraOpts && extraOpts.req.user ? extraOpts.req.user.id : null;\n const about_user = fields.some((f) => f.reftable_name === \"users\" && state[f.name] && state[f.name] === user_id);\n if (view_to_create &&\n (role <= table.min_role_write || (table.ownership_field_id && about_user))) {\n if (create_view_display === \"Embedded\") {\n const create_view = await View.findOne({ name: view_to_create });\n if (!create_view)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find embedded view to create ${view_to_create}`);\n create_link = await create_view.run(state, extraOpts);\n }\n else {\n const target = `/view/${encodeURIComponent(view_to_create)}${stateToQueryString(state)}`;\n const hrefVal = isWeb(extraOpts.req) || create_view_display === \"Popup\"\n ? target\n : `javascript:execLink('${target}');`;\n create_link = link_view(hrefVal, __(create_view_label) || `Add ${pluralize(table.name, 1)}`, create_view_display === \"Popup\", create_view_display === \"Popup\" && \"btn btn-secondary\", create_view_display === \"Popup\" && \"btn-sm\");\n }\n }\n const create_link_div = isright\n ? div({ class: \"float-end\" }, create_link)\n : create_link;\n const tableHtml = mkTable(default_state?.hide_null_columns\n ? remove_null_cols(tfields, rows)\n : tfields, rows, page_opts);\n return istop ? create_link_div + tableHtml : tableHtml + create_link_div;\n};\nconst remove_null_cols = (tfields, rows) => tfields.filter((tfield) => {\n const key = tfield.row_key || tfield.key;\n if (!(typeof key === \"string\" || Array.isArray(key)))\n return true; //unable to tell if should be removed\n const is_not_null_simple = (row) => row[key] !== null && typeof row[key] !== \"undefined\";\n const is_not_null_array = (row) => row[key[0]] !== null &&\n typeof row[key[0]] !== \"undefined\" &&\n typeof row[key[0]][key[1]] !== \"undefined\";\n if (Array.isArray(key))\n return rows.some(is_not_null_array);\n else\n return rows.some(is_not_null_simple);\n});\n/**\n * @param {number} table_id\n * @param {*} viewname\n * @param {object} optsOne\n * @param {object[]} optsOne.columns\n * @param {*} optsOne.layout\n * @param {object} body\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {*} optsTwo.res\n * @returns {Promise<object>}\n */\nconst run_action = async (table_id, viewname, { columns, layout }, body, { req, res }, { getRowQuery }) => {\n const col = columns.find((c) => c.type === \"Action\" &&\n c.action_name === body.action_name &&\n body.action_name);\n const table = await Table.findOne({ id: table_id });\n const row = await getRowQuery(body.id);\n const state_action = getState().actions[col.action_name];\n col.configuration = col.configuration || {};\n if (state_action) {\n const cfgFields = await getActionConfigFields(state_action, table);\n cfgFields.forEach(({ name }) => {\n col.configuration[name] = col[name];\n });\n }\n try {\n const result = await run_action_column({\n col,\n req,\n table,\n row,\n referrer: req.get(\"Referrer\"),\n });\n return { json: { success: \"ok\", ...(result || {}) } };\n }\n catch (e) {\n Crash.create(e, req);\n return { json: { error: e.message || e } };\n }\n};\nmodule.exports = {\n /** @type {string} */\n name: \"List\",\n /** @type {string} */\n description: \"Display multiple rows from a table in a grid with columns you specify\",\n configuration_workflow,\n run,\n /** @type {string} */\n view_quantity: \"Many\",\n get_state_fields,\n initial_config,\n on_delete,\n routes: { run_action },\n /**\n * @param {object} opts\n * @returns {boolean}\n */\n display_state_form: (opts) => !(opts && opts.default_state && opts.default_state._omit_state_form),\n /**\n * @param {object} opts\n * @returns {boolean}\n */\n default_state_form: ({ default_state }) => {\n if (!default_state)\n return default_state;\n const { _omit_state_form, _create_db_view, ...ds } = default_state;\n return ds && removeDefaultColor(removeEmptyStrings(ds));\n },\n /**\n * @param {object} opts\n * @param {*} opts.columns\n * @param {*} opts.create_view_label\n * @returns {string[]}\n */\n getStringsForI18n({ columns, create_view_label }) {\n const strings = [];\n const maybeAdd = (s) => {\n if (s)\n strings.push(s);\n };\n for (const column of columns) {\n maybeAdd(column.header_label);\n maybeAdd(column.link_text);\n maybeAdd(column.view_label);\n maybeAdd(column.action_label);\n }\n maybeAdd(create_view_label);\n return strings;\n },\n queries: ({ table_id, viewname, configuration: { columns, default_state }, req, }) => ({\n async listQuery(state) {\n const table = await Table.findOne(typeof table_id === \"string\" ? { name: table_id } : { id: table_id });\n const fields = await table.getFields();\n const { joinFields, aggregations } = picked_fields_to_query(columns, fields);\n const where = await stateFieldsToWhere({ fields, state });\n const q = await stateFieldsToQuery({ state, fields, prefix: \"a.\" });\n const rows_per_page = (default_state && default_state._rows_per_page) || 20;\n if (!q.limit)\n q.limit = rows_per_page;\n if (!q.orderBy)\n q.orderBy =\n (default_state && default_state._order_field) || table.pk_name;\n if (!q.orderDesc)\n q.orderDesc = default_state && default_state._descending;\n const role = req && req.user ? req.user.role_id : 10;\n if (table.ownership_field_id && role > table.min_role_read && req) {\n const owner_field = fields.find((f) => f.id === table.ownership_field_id);\n mergeIntoWhere(where, {\n [owner_field.name]: req.user ? req.user.id : -1,\n });\n }\n //console.log({ i: default_state.include_fml });\n if (default_state?.include_fml) {\n let where1 = jsexprToWhere(default_state.include_fml, state);\n mergeIntoWhere(where, where1);\n }\n let rows = await table.getJoinedRows({\n where,\n joinFields,\n aggregations,\n ...q,\n });\n //TODO this will mean that limit is not respected. change filter to jsexprToWhere\n if (table.ownership_formula && role > table.min_role_read && req) {\n rows = rows.filter((row) => table.is_owner(extraOpts.req.user, row));\n }\n const rowCount = await table.countRows();\n return { rows, rowCount };\n },\n async getRowQuery(id) {\n const table = await Table.findOne({ id: table_id });\n return await table.getRow({ id });\n },\n }),\n configCheck: async (view) => {\n return await check_view_columns(view, view.configuration.columns);\n },\n};\n//# sourceMappingURL=list.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/list.js?");
|
|
127
|
+
|
|
128
|
+
/***/ }),
|
|
129
|
+
|
|
130
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/listshowlist.js":
|
|
131
|
+
/*!***********************************************************************!*\
|
|
132
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/listshowlist.js ***!
|
|
133
|
+
\***********************************************************************/
|
|
134
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
135
|
+
|
|
136
|
+
"use strict";
|
|
137
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/listshowlist\n * @subcategory base-plugin\n */\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst Form = __webpack_require__(/*! ../../models/form */ \"../saltcorn-data/dist/models/form.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst { text, div, h4, h6 } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { renderForm, tabs } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { get_child_views, get_parent_views, readState, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { splitUniques } = __webpack_require__(/*! ./viewable_fields */ \"../saltcorn-data/dist/base-plugin/viewtemplates/viewable_fields.js\");\nconst { InvalidConfiguration } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\n/**\n * @param {object} req\n * @returns {Workflow}\n */\nconst configuration_workflow = (req) => new Workflow({\n steps: [\n {\n name: req.__(\"Views\"),\n form: async (context) => {\n const list_views = await View.find_table_views_where(context.table_id, ({ state_fields, viewrow, viewtemplate }) => viewtemplate.view_quantity === \"Many\" &&\n viewrow.name !== context.viewname &&\n state_fields.every((sf) => !sf.required));\n const list_view_opts = list_views.map((v) => v.name);\n const show_views = await View.find_table_views_where(context.table_id, ({ state_fields, viewrow }) => viewrow.name !== context.viewname &&\n state_fields.some((sf) => sf.name === \"id\"));\n const show_view_opts = show_views.map((v) => v.name);\n return new Form({\n fields: [\n {\n name: \"list_view\",\n label: req.__(\"List View\"),\n type: \"String\",\n sublabel: req.__(\"A list view shown on the left, to select rows\"),\n required: false,\n attributes: {\n options: list_view_opts,\n },\n },\n {\n name: \"show_view\",\n label: req.__(\"Show View\"),\n type: \"String\",\n sublabel: req.__(\"The view to show the selected row\"),\n required: false,\n attributes: {\n options: show_view_opts,\n },\n },\n {\n name: \"list_width\",\n label: req.__(\"List width\"),\n sublabel: req.__(\"Number of columns (1-12) allocated to the list view\"),\n type: \"Integer\",\n default: 6,\n attributes: {\n min: 1,\n max: 12,\n },\n },\n {\n name: \"_omit_state_form\",\n label: req.__(\"Omit search form\"),\n sublabel: req.__(\"Do not display the search filter form\"),\n type: \"Bool\",\n default: true,\n },\n ],\n });\n },\n },\n {\n name: req.__(\"Subtables\"),\n contextField: \"subtables\",\n form: async (context) => {\n const tbl = await Table.findOne({ id: context.table_id });\n var fields = [];\n const child_views = await get_child_views(tbl, context.viewname);\n for (const { relation, related_table, views } of child_views) {\n for (const view of views) {\n fields.push({\n name: `ChildList:${view.name}.${related_table.name}.${relation.name}`,\n label: `${view.name} of ${relation.label} on ${related_table.name}`,\n type: \"Bool\",\n });\n }\n }\n const parent_views = await get_parent_views(tbl, context.viewname);\n for (const { relation, related_table, views } of parent_views) {\n for (const view of views) {\n fields.push({\n name: `ParentShow:${view.name}.${related_table.name}.${relation.name}`,\n label: `${view.name} of ${relation.name} on ${related_table.name}`,\n type: \"Bool\",\n });\n }\n }\n return new Form({\n fields,\n blurb: req.__(\"Which related tables would you like to show in sub-lists below the selected item?\"),\n });\n },\n },\n ],\n});\n/**\n * @param {*} table_id\n * @param {*} viewname\n * @param {object} opts\n * @param {string} opts.list_view\n * @param {*} opts.show_view\n * @returns {Promise<object[]>}\n */\nconst get_state_fields = async (table_id, viewname, { list_view, show_view }) => {\n const id = {\n name: \"id\",\n type: \"Integer\",\n required: false,\n };\n if (list_view) {\n const lview = await View.findOne({ name: list_view });\n if (lview) {\n const lview_sfs = await lview.get_state_fields();\n return [id, ...lview_sfs];\n }\n else\n return [id];\n }\n else\n return [id];\n};\n/**\n * @param {string} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {string} opts.list_view\n * @param {string} opts.show_view\n * @param {object} opts.subtables\n * @param {*} state\n * @param {*} extraArgs\n * @returns {Promise<div>}\n */\nconst run = async (table_id, viewname, { list_view, show_view, list_width, subtables }, state, extraArgs, { getRowQuery }) => {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n readState(state, fields);\n var lresp;\n if (list_view) {\n const lview = await View.findOne({ name: list_view });\n if (!lview)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${list_view}`);\n const state1 = lview.combine_state_and_default_state(state);\n lresp = await lview.run(state1, {\n ...extraArgs,\n onRowSelect: (v) => `select_id('${v.id}')`,\n });\n }\n var sresp = \"\";\n if (show_view) {\n const sview = await View.findOne({ name: show_view });\n if (!sview)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${show_view}`);\n sresp = await sview.run(state, extraArgs);\n }\n var reltbls = {};\n var myrow;\n const { uniques } = splitUniques(fields, state, true);\n if (Object.keys(uniques).length > 0) {\n var id;\n if (state.id)\n id = state.id;\n else {\n myrow = getRowQuery(uniques);\n if (!myrow)\n return `Not found`;\n id = myrow.id;\n }\n for (const relspec of Object.keys(subtables || {})) {\n if (subtables[relspec]) {\n const [reltype, rel] = relspec.split(\":\");\n switch (reltype) {\n case \"ChildList\":\n case \"OneToOneShow\":\n const [vname, reltblnm, relfld] = rel.split(\".\");\n const tab_name = reltblnm;\n let subviewPaging = {};\n if (state._paged_view && state._paged_view === vname) {\n subviewPaging._page = state._page;\n subviewPaging._pagesize = state._pagesize;\n }\n const subview = await View.findOne({ name: vname });\n if (!subview)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${vname}`);\n else {\n const subresp = await subview.run({ [relfld]: id, ...subviewPaging }, extraArgs);\n reltbls[tab_name] = subresp;\n }\n break;\n case \"ParentShow\":\n const [pvname, preltblnm, prelfld] = rel.split(\".\");\n if (!myrow)\n myrow = await getRowQuery({ id });\n if (!myrow)\n continue;\n const ptab_name = prelfld;\n const psubview = await View.findOne({ name: pvname });\n if (!psubview)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${pvname}`);\n else {\n const psubresp = await psubview.run({ id: myrow[prelfld] }, extraArgs);\n reltbls[ptab_name] = psubresp;\n }\n break;\n default:\n break;\n }\n }\n }\n }\n const relTblResp = Object.keys(reltbls).length === 1\n ? [h6(Object.keys(reltbls)[0]), reltbls[Object.keys(reltbls)[0]]]\n : tabs(reltbls);\n if (lresp) {\n if (list_width === 12)\n return lresp;\n return div({ class: \"row\" }, div({ class: `col-sm-${list_width || 6}` }, lresp), div({ class: `col-sm-${12 - (list_width || 6)}` }, sresp, relTblResp));\n }\n else {\n return div(sresp, relTblResp);\n }\n};\nmodule.exports = {\n /** @type {string} */\n name: \"ListShowList\",\n /** @type {string} */\n description: \"Combine an optional list view on the left with displays on the right of a single selected row, with views of related rows from different tables underneath\",\n configuration_workflow,\n run,\n get_state_fields,\n /**\n \n * @param {object} opts\n * @param {string} opts.list_view\n * @param {boolean} opts._omit_state_form\n * @returns {boolean}\n */\n display_state_form: ({ list_view, _omit_state_form }) => !!list_view && !_omit_state_form,\n queries: ({ table_id, viewname, configuration: { columns, default_state }, req, }) => ({\n async getRowQuery(uniques) {\n const table = await Table.findOne({ id: table_id });\n return await table.getRow(uniques);\n },\n }),\n};\n//# sourceMappingURL=listshowlist.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/listshowlist.js?");
|
|
138
|
+
|
|
139
|
+
/***/ }),
|
|
140
|
+
|
|
141
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/room.js":
|
|
142
|
+
/*!***************************************************************!*\
|
|
143
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/room.js ***!
|
|
144
|
+
\***************************************************************/
|
|
145
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
146
|
+
|
|
147
|
+
"use strict";
|
|
148
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/room\n * @subcategory base-plugin\n */\nconst Field = __webpack_require__(/*! ../../models/field */ \"../saltcorn-data/dist/models/field.js\");\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst Form = __webpack_require__(/*! ../../models/form */ \"../saltcorn-data/dist/models/form.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst { text, div, h4, hr, button, form, input, i, script, domReady, } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst { pagination } = __webpack_require__(/*! @saltcorn/markup/helpers */ \"../saltcorn-markup/dist/helpers.js\");\nconst { renderForm, tabs, link } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { mkTable } = __webpack_require__(/*! @saltcorn/markup */ \"../saltcorn-markup/dist/index.js\");\nconst { link_view, stateToQueryString, stateFieldsToWhere, stateFieldsToQuery, readState, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { InvalidConfiguration, isNode } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { getState } = __webpack_require__(/*! ../../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst db = __webpack_require__(/*! ../../db */ \"../saltcorn-data/dist/db/index.js\");\nconst { getForm, fill_presets } = __webpack_require__(/*! ./viewable_fields */ \"../saltcorn-data/dist/base-plugin/viewtemplates/viewable_fields.js\");\n/**\n *\n * @param {object} req\n * @returns {Workflow}\n */\nconst configuration_workflow = (req) => new Workflow({\n steps: [\n {\n name: req.__(\"Views\"),\n form: async (context) => {\n /*\n we need:\n - message string\n - message show view?\n - message sender field\n - participant field: key to user in table with fkey to this\n */\n const roomtable = await Table.findOne(context.table_id);\n const { child_relations } = await roomtable.get_child_relations();\n //const msg_table_options = child_relations.map(cr=>cr.table.name)\n const participant_field_options = [];\n const msg_relation_options = [];\n const msgsender_field_options = {};\n const msgview_options = {};\n const msgform_options = {};\n const participant_max_read_options = [];\n const msg_own_options = [];\n for (const { table, key_field } of child_relations) {\n const fields = await table.getFields();\n for (const f of fields) {\n if (f.reftable_name === \"users\") {\n participant_field_options.push(`${table.name}.${key_field.name}.${f.name}`);\n msg_relation_options.push(`${table.name}.${key_field.name}`);\n msgsender_field_options[`${table.name}.${key_field.name}`] = [\n ...(msgsender_field_options[`${table.name}.${key_field.name}`] || []),\n f.name,\n ];\n const views = await View.find_possible_links_to_table(table);\n msgview_options[`${table.name}.${key_field.name}`] = views.map((v) => v.name);\n msgform_options[`${table.name}.${key_field.name}`] = views.map((v) => v.name);\n }\n else if (f.reftable_name) {\n participant_max_read_options.push(`${table.name}.${key_field.name}.${f.name}`);\n }\n }\n }\n return new Form({\n fields: [\n {\n name: \"msg_relation\",\n label: req.__(\"Message relation\"),\n type: \"String\",\n sublabel: req.__(\"The relationship to the table of individual messages\"),\n required: true,\n attributes: {\n options: msg_relation_options,\n },\n },\n {\n name: \"msgsender_field\",\n label: req.__(\"Message sender field\"),\n type: \"String\",\n sublabel: req.__(\"The field for the sender user id on the table for messages\"),\n required: true,\n attributes: {\n calcOptions: [\"msg_relation\", msgsender_field_options],\n },\n },\n {\n name: \"msgview\",\n label: req.__(\"Message show view\"),\n type: \"String\",\n sublabel: req.__(\"The view to show an individual message\"),\n required: true,\n attributes: {\n calcOptions: [\"msg_relation\", msgview_options],\n },\n },\n {\n name: \"msgform\",\n label: req.__(\"New message form view\"),\n type: \"String\",\n sublabel: req.__(\"The view to enter a new message\"),\n required: true,\n attributes: {\n calcOptions: [\"msg_relation\", msgform_options],\n },\n },\n {\n name: \"participant_field\",\n label: req.__(\"Participant field\"),\n type: \"String\",\n sublabel: req.__(\"The field for the participant user id\"),\n required: true,\n attributes: {\n options: participant_field_options,\n },\n },\n {\n name: \"participant_maxread_field\",\n label: req.__(\"Participant max read id field\"),\n type: \"String\",\n sublabel: req.__(\"The field for the participant's last read message, of type Key to message table\"),\n attributes: {\n options: participant_max_read_options,\n },\n },\n ],\n });\n },\n },\n ],\n});\n/**\n * @returns {object[]}\n */\nconst get_state_fields = () => [\n {\n name: \"id\",\n type: \"Integer\",\n required: true,\n primary_key: true,\n },\n];\nconst limit = 10;\n/**\n * @param {string} table_id\n * @param {string} viewname\n * @param {object} optsOne\n * @param {string} optsOne.participant_field,\n * @param {string} optsOne.msg_relation\n * @param {*} optsOne.msgsender_field\n * @param {string} optsOne.msgview\n * @param {string} optsOne.msgform\n * @param {string} optsOne.participant_maxread_field\n * @param {object} state\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {object} optsTwo.res\n * @returns {Promise<div>}\n * @throws {InvalidConfiguration}\n */\nconst run = async (table_id, viewname, { participant_field, msg_relation, msgsender_field, msgview, msgform, participant_maxread_field, }, state, { req, res }, { getRowQuery, updateQuery, optionsQuery }) => {\n const table = await Table.findOne({ id: table_id });\n const fields = await table.getFields();\n readState(state, fields);\n if (!state.id)\n return \"Need room id\";\n const appState = getState();\n const locale = req.getLocale();\n const __ = (s) => appState.i18n.__({ phrase: s, locale }) || s;\n if (!participant_field ||\n !msgview ||\n !msgform ||\n !msgsender_field ||\n !msg_relation)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: must supply Message views, Message sender and Participant fields`);\n const [msgtable_name, msgkey_to_room] = msg_relation.split(\".\");\n const [part_table_name, part_key_to_room, part_user_field] = participant_field.split(\".\");\n // check we participate\n const partRow = await getRowQuery(state.id, part_table_name, part_user_field, part_key_to_room);\n if (!partRow)\n return \"You are not a participant in this room\";\n const v = await View.findOne({ name: msgview });\n const vresps = await v.runMany({ [msgkey_to_room]: state.id }, { req, res, orderBy: \"id\", orderDesc: true, limit });\n vresps.reverse();\n const n_retrieved = vresps.length;\n const msglist = vresps.map((r) => r.html).join(\"\");\n const formview = await View.findOne({ name: msgform });\n if (!formview)\n throw new InvalidConfiguration(\"Message form view does not exist\");\n const { columns, layout } = formview.configuration;\n const msgtable = Table.findOne({ name: msgtable_name });\n const min_read_id = Math.min.apply(Math, vresps.map((r) => r.row.id));\n if (participant_maxread_field) {\n const [part_table_name1, part_key_to_room1, part_maxread_field] = participant_maxread_field.split(\".\");\n const max_read_id = Math.max.apply(Math, vresps.map((r) => r.row.id));\n if (vresps.length > 0)\n await updateQuery(partRow, part_table_name, max_read_id, part_maxread_field);\n }\n const form = await getForm(msgtable, viewname, columns, layout, null, req);\n form.class = `room-${state.id}`;\n form.hidden(\"room_id\");\n form.values = { room_id: state.id };\n await form.fill_fkey_options(false, optionsQuery);\n return div(n_retrieved === limit &&\n button({\n class: \"btn btn-outline-secondary mb-1 fetch_older\",\n onclick: `room_older('${viewname}',${state.id},this)`,\n \"data-lt-msg-id\": min_read_id,\n }, req.__(\"Show older messages\")), div({ class: `msglist-${state.id}`, \"data-user-id\": req.user.id }, msglist), renderForm(form, req.csrfToken()), script({\n src: `/static_assets/${db.connectObj.version_tag}/socket.io.min.js`,\n }) + script(domReady(`init_room(\"${viewname}\", ${state.id})`)));\n};\n/**\n * @param {*} table_id\n * @param {*} viewname\n * @param {object} optsOne\n * @param {string} optsOne.participant_field\n * @param {string} optsOne.participant_maxread_field\n * @param {body} body\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {object} optsTwo.res\n * @returns {Promise<void>}\n */\nconst ack_read = async (table_id, viewname, { participant_field, participant_maxread_field }, body, { req, res }, { ackReadQuery }) => {\n if (!participant_maxread_field)\n return {\n json: {\n success: \"ok\",\n },\n };\n return await ackReadQuery(participant_field, participant_maxread_field, body);\n};\n/**\n * @param {*} table_id\n * @param {*} viewname\n * @param {object} optsOne.\n * @param {string} optsOne.participant_field\n * @param {string} optsOne.msg_relation\n * @param {*} optsOne.msgsender_field\n * @param {string} optsOne.msgview\n * @param {*} optsOne.msgform\n * @param {*} optsOne.participant_maxread_field\n * @param {object} body\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {object} optsTwo.res\n * @returns {Promise<object>}\n */\nconst fetch_older_msg = async (table_id, viewname, { participant_field, msg_relation, msgsender_field, msgview, msgform, participant_maxread_field, }, body, { req, res }, { fetchOlderMsgQuery }) => {\n const partRow = await fetchOlderMsgQuery(participant_field, body);\n if (!partRow)\n return {\n json: {\n error: \"Not participating\",\n },\n };\n const [msgtable_name, msgkey_to_room] = msg_relation.split(\".\");\n const v = await View.findOne({ name: msgview });\n const vresps = await v.runMany({ [msgkey_to_room]: +body.room_id }, {\n req,\n res,\n orderBy: \"id\",\n orderDesc: true,\n limit,\n where: { id: { lt: +body.lt_msg_id } },\n });\n vresps.reverse();\n const n_retrieved = vresps.length;\n const min_read_id = Math.min.apply(Math, vresps.map((r) => r.row.id));\n const msglist = vresps.map((r) => r.html).join(\"\");\n return {\n json: {\n success: \"ok\",\n prepend: msglist,\n remove_fetch_older: n_retrieved < limit,\n new_fetch_older_lt: min_read_id,\n },\n };\n};\n/**\n * @param {*} table_id\n * @param {string} viewname\n * @param {object} optsOne\n * @param {string} optsOne.participant_field\n * @param {string} optsOne.msg_relation\n * @param {*} optsOne.msgsender_field\n * @param {string} optsOne.msgview\n * @param {string} optsOne.msgform\n * @param {string} optsOne.participant_maxread_field\n * @param {*} body\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {object} optsTwo.res\n * @returns {Promise<object>}\n */\nconst submit_msg_ajax = async (table_id, viewname, { participant_field, msg_relation, msgsender_field, msgview, msgform, participant_maxread_field, }, body, { req, res }, { submitAjaxQuery }) => {\n const queryResult = await submitAjaxQuery(msg_relation, participant_field, body, msgform, msgsender_field, participant_maxread_field);\n if (!queryResult.json.error) {\n const msgid = queryResult.json.msgid;\n const v = await View.findOne({ name: msgview });\n const myhtml = await v.run({ id: msgid.success }, { req, res });\n const newreq = { ...req, user: { ...req.user, id: 0 } };\n const theirhtml = await v.run({ id: msgid.success }, { req: newreq, res });\n getState().emitRoom(viewname, +body.room_id, {\n append: theirhtml,\n not_for_user_id: req.user.id,\n pls_ack_msg_id: msgid.success,\n });\n return {\n json: {\n success: \"ok\",\n append: myhtml,\n },\n };\n }\n else {\n return queryResult;\n }\n};\n/**\n * @param {*} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {*} opts.participant_field\n * @param {string} opts.msg_relation,\n * @param {string} opts.msgsender_field,\n * @param {string} opts.msgview,\n * @param {*} opts.msgform,\n * @param {*} opts.participant_maxread_field,\n * @returns {object[]}\n */\nconst virtual_triggers = (table_id, viewname, { participant_field, msg_relation, msgsender_field, msgview, msgform, participant_maxread_field, }) => {\n if (!msg_relation)\n return [];\n const [msgtable_name, msgkey_to_room] = msg_relation.split(\".\");\n const msgtable = Table.findOne({ name: msgtable_name });\n if (!msgsender_field)\n return [];\n return [\n {\n when_trigger: \"Insert\",\n table_id: msgtable.id,\n run: async (row) => {\n if (row[msgsender_field])\n return; // TODO how else to avoid double emit\n const v = await View.findOne({ name: msgview });\n const html = await v.run({ id: row.id }, {\n req: { getLocale: () => \"en\", user: { id: 0 }, __: (s) => s },\n res: {},\n });\n getState().emitRoom(viewname, row[msgkey_to_room], {\n append: html,\n pls_ack_msg_id: row.id,\n });\n },\n },\n ];\n};\nmodule.exports = {\n /** @type {string} */\n name: \"Room\",\n /** @type {string} */\n description: \"Real-time space for chat\",\n configuration_workflow,\n run,\n get_state_fields,\n /** @type {boolean} */\n display_state_form: false,\n routes: { submit_msg_ajax, ack_read, fetch_older_msg },\n /** @type {boolean} */\n noAutoTest: true,\n /**\n * @param {object} opts\n * @param {object} opts.participant_field\n * @param {string} room_id\n * @param {object} user\n * @returns {Promise<object>}\n */\n authorize_join: async ({ participant_field }, room_id, user) => {\n // TODO ch authorize_join query\n if (!user)\n return false;\n const [part_table_name, part_key_to_room, part_user_field] = participant_field.split(\".\");\n // TODO check we participate\n const parttable = Table.findOne({ name: part_table_name });\n const partRow = await parttable.getRow({\n [part_user_field]: user.id,\n [part_key_to_room]: room_id,\n });\n return !!partRow;\n },\n virtual_triggers,\n /** @returns {object[]} */\n getStringsForI18n() {\n return [];\n },\n queries: ({ table_id, viewname, configuration: { columns, default_state }, req, }) => ({\n async getRowQuery(state_id, part_table_name, part_user_field, part_key_to_room) {\n const parttable = Table.findOne({ name: part_table_name });\n return await parttable.getRow({\n [part_user_field]: req.user ? req.user.id : 0,\n [part_key_to_room]: +state_id,\n });\n },\n async updateQuery(partRow, part_table_name, max_read_id, part_maxread_field) {\n const parttable = Table.findOne({ name: part_table_name });\n await parttable.updateRow({ [part_maxread_field]: max_read_id }, partRow.id);\n },\n async submitAjaxQuery(msg_relation, participant_field, body, msgform, msgsender_field, participant_maxread_field) {\n const [msgtable_name, msgkey_to_room] = msg_relation.split(\".\");\n const [part_table_name, part_key_to_room, part_user_field] = participant_field.split(\".\");\n const parttable = Table.findOne({ name: part_table_name });\n // check we participate\n const partRow = await parttable.getRow({\n [part_user_field]: req.user ? req.user.id : 0,\n [part_key_to_room]: +body.room_id,\n });\n if (!partRow)\n return {\n json: {\n error: \"Not participating\",\n },\n };\n const formview = await View.findOne({ name: msgform });\n if (!formview)\n throw new InvalidConfiguration(\"Message form view does not exist\");\n const { columns, layout, fixed } = formview.configuration;\n const msgtable = Table.findOne({ name: msgtable_name });\n const form = await getForm(msgtable, viewname, columns, layout, null, req);\n form.validate(req.body);\n if (!form.hasErrors) {\n const use_fixed = await fill_presets(msgtable, req, fixed);\n const row = {\n ...form.values,\n ...use_fixed,\n [msgkey_to_room]: body.room_id,\n [msgsender_field]: req.user.id,\n };\n const msgid = await msgtable.tryInsertRow(row, req.user.id);\n if (participant_maxread_field) {\n const [part_table_name1, part_key_to_room1, part_maxread_field] = participant_maxread_field.split(\".\");\n await parttable.updateRow({ [part_maxread_field]: msgid.success }, partRow.id);\n }\n return {\n json: { msgid },\n };\n }\n else {\n return {\n json: {\n error: form.errors,\n },\n };\n }\n },\n async ackReadQuery(participant_field, participant_maxread_field, body) {\n const [part_table_name, part_key_to_room, part_user_field] = participant_field.split(\".\");\n const [part_table_name1, part_key_to_room1, part_maxread_field] = participant_maxread_field.split(\".\");\n const parttable = Table.findOne({ name: part_table_name });\n // check we participate\n const partRow = await parttable.getRow({\n [part_user_field]: req.user ? req.user.id : 0,\n [part_key_to_room]: +body.room_id,\n });\n if (!partRow)\n return {\n json: {\n error: \"Not participating\",\n },\n };\n await parttable.updateRow({ [part_maxread_field]: body.id }, partRow.id);\n return {\n json: {\n success: \"ok\",\n },\n };\n },\n async fetchOlderMsgQuery(participant_field, body) {\n const [part_table_name, part_key_to_room, part_user_field] = participant_field.split(\".\");\n const parttable = Table.findOne({ name: part_table_name });\n // check we participate\n return await parttable.getRow({\n [part_user_field]: req.user ? req.user.id : 0,\n [part_key_to_room]: +body.room_id,\n });\n },\n async optionsQuery(reftable_name, type, attributes, where) {\n const rows = await db.select(reftable_name, type === \"File\" ? attributes.select_file_where : where);\n return rows;\n },\n }),\n};\n/*todo:\n\nfind_or_create_dm_room -dms only\n\n*/\n//# sourceMappingURL=room.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/room.js?");
|
|
149
|
+
|
|
150
|
+
/***/ }),
|
|
151
|
+
|
|
152
|
+
/***/ "../saltcorn-data/dist/base-plugin/viewtemplates/show.js":
|
|
153
|
+
/*!***************************************************************!*\
|
|
154
|
+
!*** ../saltcorn-data/dist/base-plugin/viewtemplates/show.js ***!
|
|
155
|
+
\***************************************************************/
|
|
156
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
157
|
+
|
|
158
|
+
"use strict";
|
|
159
|
+
eval("\n/**\n * @category saltcorn-data\n * @module base-plugin/viewtemplates/show\n * @subcategory base-plugin\n */\nconst Form = __webpack_require__(/*! ../../models/form */ \"../saltcorn-data/dist/models/form.js\");\nconst User = __webpack_require__(/*! ../../models/user */ \"../saltcorn-data/dist/models/user.js\");\nconst Field = __webpack_require__(/*! ../../models/field */ \"../saltcorn-data/dist/models/field.js\");\nconst View = __webpack_require__(/*! ../../models/view */ \"../saltcorn-data/dist/models/view.js\");\nconst File = __webpack_require__(/*! ../../models/file */ \"../saltcorn-data/dist/models/file.js\");\nconst Table = __webpack_require__(/*! ../../models/table */ \"../saltcorn-data/dist/models/table.js\");\nconst Page = __webpack_require__(/*! ../../models/page */ \"../saltcorn-data/dist/models/page.js\");\nconst Crash = __webpack_require__(/*! ../../models/crash */ \"../saltcorn-data/dist/models/crash.js\");\nconst Workflow = __webpack_require__(/*! ../../models/workflow */ \"../saltcorn-data/dist/models/workflow.js\");\nconst Trigger = __webpack_require__(/*! ../../models/trigger */ \"../saltcorn-data/dist/models/trigger.js\");\nconst { getState } = __webpack_require__(/*! ../../db/state */ \"../saltcorn-data/dist/db/state.js\");\nconst { eachView, traverse, getStringsForI18n, translateLayout, } = __webpack_require__(/*! ../../models/layout */ \"../saltcorn-data/dist/models/layout.js\");\nconst { check_view_columns } = __webpack_require__(/*! ../../plugin-testing */ \"../saltcorn-data/dist/mobile-mocks/saltcorn/plugin-testing.js\");\nconst { div, text, span, a, text_attr, i, button, } = __webpack_require__(/*! @saltcorn/markup/tags */ \"../saltcorn-markup/dist/tags.js\");\nconst renderLayout = __webpack_require__(/*! @saltcorn/markup/layout */ \"../saltcorn-markup/dist/layout.js\");\nconst { stateFieldsToWhere, stateFieldsToQuery, get_link_view_opts, picked_fields_to_query, initial_config_all_fields, calcfldViewOptions, calcfldViewConfig, getActionConfigFields, run_action_column, readState, } = __webpack_require__(/*! ../../plugin-helper */ \"../saltcorn-data/dist/plugin-helper.js\");\nconst { action_url, view_linker, parse_view_select, action_link, splitUniques, } = __webpack_require__(/*! ./viewable_fields */ \"../saltcorn-data/dist/base-plugin/viewtemplates/viewable_fields.js\");\nconst db = __webpack_require__(/*! ../../db */ \"../saltcorn-data/dist/db/index.js\");\nconst { asyncMap, structuredClone, InvalidConfiguration, mergeIntoWhere, isWeb, } = __webpack_require__(/*! ../../utils */ \"../saltcorn-data/dist/utils.js\");\nconst { traverseSync } = __webpack_require__(/*! ../../models/layout */ \"../saltcorn-data/dist/models/layout.js\");\nconst { get_expression_function, eval_expression, } = __webpack_require__(/*! ../../models/expression */ \"../saltcorn-data/dist/models/expression.js\");\nconst { get_base_url } = __webpack_require__(/*! ../../models/config */ \"../saltcorn-data/dist/models/config.js\");\nconst Library = __webpack_require__(/*! ../../models/library */ \"../saltcorn-data/dist/models/library.js\");\n/**\n * @param {object} req\n * @returns {Workflow}\n */\nconst configuration_workflow = (req) => new Workflow({\n steps: [\n {\n name: req.__(\"Layout\"),\n builder: async (context) => {\n const table = await Table.findOne(context.table_id || context.exttable_name);\n const fields = await table.getFields();\n const boolfields = fields.filter((f) => f.type && f.type.name === \"Bool\");\n const stateActions = Object.entries(getState().actions).filter(([k, v]) => !v.disableInBuilder);\n const actions = [\n \"Delete\",\n \"GoBack\",\n ...boolfields.map((f) => `Toggle ${f.name}`),\n ...stateActions.map(([k, v]) => k),\n ];\n const triggers = await Trigger.find({\n when_trigger: { or: [\"API call\", \"Never\"] },\n });\n triggers.forEach((tr) => {\n actions.push(tr.name);\n });\n for (const field of fields) {\n if (field.type === \"Key\") {\n field.reftable = await Table.findOne({\n name: field.reftable_name,\n });\n if (field.reftable)\n await field.reftable.getFields();\n }\n }\n const actionConfigForms = {};\n for (const [name, action] of stateActions) {\n if (action.configFields) {\n actionConfigForms[name] = await getActionConfigFields(action, table);\n }\n }\n const fieldViewConfigForms = await calcfldViewConfig(fields, false);\n const { field_view_options, handlesTextStyle } = calcfldViewOptions(fields, \"show\");\n if (table.name === \"users\") {\n fields.push(new Field({\n name: \"verification_url\",\n label: \"Verification URL\",\n type: \"String\",\n }));\n field_view_options.verification_url = [\"as_text\", \"as_link\"];\n }\n const link_view_opts = await get_link_view_opts(table, context.viewname);\n const roles = await User.get_roles();\n const { parent_field_list } = await table.get_parent_relations(true, true);\n const { child_field_list, child_relations } = await table.get_child_relations();\n var agg_field_opts = {};\n child_relations.forEach(({ table, key_field }) => {\n agg_field_opts[`${table.name}.${key_field.name}`] = table.fields\n .filter((f) => !f.calculated || f.stored)\n .map((f) => f.name);\n });\n const views = link_view_opts;\n const pages = await Page.find();\n const images = await File.find({ mime_super: \"image\" });\n const library = (await Library.find({})).filter((l) => l.suitableFor(\"show\"));\n const myviewrow = await View.findOne({ name: context.viewname });\n return {\n tableName: table.name,\n fields,\n images,\n actions,\n actionConfigForms,\n fieldViewConfigForms,\n field_view_options,\n link_view_opts,\n parent_field_list,\n child_field_list,\n agg_field_opts,\n min_role: (myviewrow || {}).min_role,\n roles,\n views,\n library,\n pages,\n handlesTextStyle,\n mode: \"show\",\n ownership: !!table.ownership_field_id || table.name === \"users\",\n };\n },\n },\n {\n name: req.__(\"Set page title\"),\n form: () => new Form({\n blurb: req.__(\"Skip this section if you do not want to set the page title\"),\n fields: [\n {\n name: \"page_title\",\n label: req.__(\"Page title\"),\n class: \"validate-expression validate-expression-conditional\",\n type: \"String\",\n },\n {\n name: \"page_title_formula\",\n label: req.__(\"Page title is a formula?\"),\n type: \"Bool\",\n required: false,\n },\n ],\n }),\n },\n ],\n});\n/**\n * @returns {object[]}\n */\nconst get_state_fields = () => [\n {\n name: \"id\",\n type: \"Integer\",\n required: true,\n primary_key: true,\n },\n];\n/** @type {function} */\nconst initial_config = initial_config_all_fields(false);\n/**\n * @param {string} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {object} opts.layout\n * @param {string} [opts.page_title]\n * @param {boolean} opts.page_title_formula\n * @param {object} state\n * @param {object} extra\n * @returns {Promise<string>}\n */\nconst run = async (table_id, viewname, { columns, layout, page_title, page_title_formula }, state, extra, { showQuery }) => {\n //console.log(columns);\n //console.log(layout);\n if (!columns || !layout)\n return \"View not yet built\";\n const tbl = await Table.findOne(table_id);\n const fields = await tbl.getFields();\n if (tbl.name === \"users\") {\n fields.push(new Field({\n name: \"verification_token\",\n label: \"Verification Token\",\n type: \"String\",\n }));\n }\n const { rows, message } = await showQuery(state, fields);\n if (message)\n return extra.req.__(message);\n if (rows.length > 1)\n rows.sort((a, b) => {\n let diff = 0;\n Object.keys(state).forEach((key) => {\n if (a[key] && b[key]) {\n if (typeof a[key] === \"string\" && typeof b[key] === \"string\") {\n diff += a[key].length - b[key].length;\n }\n }\n });\n return diff;\n });\n if (rows.length == 0)\n return extra.req.__(\"No row selected\");\n if (tbl.name === \"users\") {\n const base = get_base_url(extra.req);\n fields.push(new Field({\n name: \"verification_url\",\n label: \"Verification URL\",\n type: \"String\",\n }));\n for (const row of rows) {\n row.verification_url = `${base}auth/verify?token=${row.verification_token}&email=${encodeURIComponent(row.email)}`;\n }\n }\n await set_join_fieldviews({ table: tbl, layout, fields });\n const rendered = (await renderRows(tbl, viewname, { columns, layout }, extra, [rows[0]]))[0];\n let page_title_preamble = \"\";\n if (page_title) {\n let the_title = page_title;\n if (page_title_formula) {\n const f = get_expression_function(page_title, fields);\n the_title = f(rows[0]);\n }\n page_title_preamble = `<!--SCPT:${text_attr(the_title)}-->`;\n }\n return page_title_preamble + rendered;\n};\n/**\n * @param {object} opts\n * @param {object} opts.layout\n * @param {object[]} opts.fields\n * @returns {Promise<void>}\n */\nconst set_join_fieldviews = async ({ table, layout, fields }) => {\n await traverse(layout, {\n join_field: async (segment) => {\n const { join_field, fieldview } = segment;\n if (!fieldview)\n return;\n const field = await table.getField(join_field);\n if (field && field.type === \"File\")\n segment.field_type = \"File\";\n else if (field?.type.name && field?.type?.fieldviews[fieldview])\n segment.field_type = field.type.name;\n },\n });\n};\n/**\n * @param {object} table\n * @param {string} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {object} opts.layout\n * @param {object} extra\n * @param {object[]} rows\n * @returns {Promise<string>}\n */\nconst renderRows = async (table, viewname, { columns, layout }, extra, rows) => {\n //console.log(columns);\n //console.log(layout);\n if (!columns || !layout)\n return req.__(\"View not yet built\");\n const fields = await table.getFields();\n const role = extra.req.user ? extra.req.user.role_id : 10;\n var views = {};\n const getView = async (nm) => {\n if (views[nm])\n return views[nm];\n const view_select = parse_view_select(nm);\n const view = await View.findOne({ name: view_select.viewname });\n if (!view)\n return false;\n if (view.table_id === table.id)\n view.table = table;\n else\n view.table = await Table.findOne({ id: view.table_id });\n view.view_select = view_select;\n views[nm] = view;\n return view;\n };\n await set_join_fieldviews({ table, layout, fields });\n const owner_field = await table.owner_fieldname();\n return await asyncMap(rows, async (row) => {\n await eachView(layout, async (segment) => {\n const view = await getView(segment.view);\n if (!view)\n throw new InvalidConfiguration(`View ${viewname} incorrectly configured: cannot find view ${segment.view}`);\n view.check_viewtemplate();\n if (view.viewtemplateObj.renderRows && view.view_select.type === \"Own\") {\n segment.contents = (await view.viewtemplateObj.renderRows(view.table, view.name, view.configuration, extra, [row]))[0];\n }\n else {\n let state;\n const pk_name = table.pk_name;\n switch (view.view_select.type) {\n case \"Own\":\n state = { [pk_name]: row[pk_name] };\n break;\n case \"Independent\":\n state = {};\n break;\n case \"ChildList\":\n case \"OneToOneShow\":\n state = {\n [view.view_select.through\n ? `${view.view_select.throughTable}.${view.view_select.through}.${view.view_select.table_name}.${view.view_select.field_name}`\n : view.view_select.field_name]: row[pk_name],\n };\n break;\n case \"ParentShow\":\n //todo set by pk name of parent tablr\n state = { id: row[view.view_select.field_name] };\n break;\n }\n const extra_state = segment.extra_state_fml\n ? eval_expression(segment.extra_state_fml, row, extra.req.user)\n : {};\n const state1 = { ...state, ...extra_state };\n segment.contents = await view.run(state1, extra);\n }\n });\n const user_id = extra.req.user ? extra.req.user.id : null;\n const is_owner = table.ownership_formula && user_id\n ? await table.is_owner(extra.req.user, row)\n : owner_field && user_id && row[owner_field] === user_id;\n return render(row, fields, layout, viewname, table, role, extra.req, is_owner);\n });\n};\n/**\n * @param {number} table_id\n * @param {string} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {object} opts.layout\n * @param {object} state\n * @param {object} extra\n * @returns {Promise<object[]>}\n */\nconst runMany = async (table_id, viewname, { columns, layout }, state, extra, { runManyQuery }) => {\n const tbl = await Table.findOne({ id: table_id });\n const rows = await runManyQuery(state, {\n where: extra.where,\n limit: extra.limit,\n offset: extra.offset,\n orderBy: extra.orderBy,\n orderDesc: extra.orderDesc,\n });\n const rendered = await renderRows(tbl, viewname, { columns, layout }, extra, rows);\n return rendered.map((html, ix) => ({ html, row: rows[ix] }));\n};\n/**\n * @param {object} row\n * @param {Field[]} fields\n * @param {Layout} layout0\n * @param {string} viewname\n * @param {Table} table\n * @param {Role} role\n * @param {object} req\n * @param {object} is_owner\n * @throws {Error}\n * @returns {Layout}\n */\nconst render = (row, fields, layout0, viewname, table, role, req, is_owner) => {\n const evalMaybeExpr = (segment, key, fmlkey) => {\n if (segment.isFormula && segment.isFormula[fmlkey || key]) {\n try {\n segment[key] = eval_expression(segment[key], row, req.user);\n }\n catch (error) {\n error.message = `Error in formula ${segment[key]} for property ${key} in segment of type ${segment.type}:\\n${error.message}`;\n throw error;\n }\n }\n };\n const layout = structuredClone(layout0);\n traverseSync(layout, {\n link(segment) {\n evalMaybeExpr(segment, \"url\");\n evalMaybeExpr(segment, \"text\");\n },\n view_link(segment) {\n evalMaybeExpr(segment, \"view_label\", \"label\");\n },\n blank(segment) {\n evalMaybeExpr(segment, \"contents\", \"text\");\n },\n action(segment) {\n evalMaybeExpr(segment, \"action_label\");\n },\n card(segment) {\n evalMaybeExpr(segment, \"url\");\n evalMaybeExpr(segment, \"title\");\n },\n image(segment) {\n evalMaybeExpr(segment, \"url\");\n evalMaybeExpr(segment, \"alt\");\n if (segment.srctype === \"Field\") {\n const field = fields.find((f) => f.name === segment.field);\n if (!field)\n return;\n if (field.type.name === \"String\")\n segment.url = row[segment.field];\n if (field.reftable_name === \"_sc_files\")\n segment.url = `/files/serve/${row[segment.field]}`;\n }\n },\n container(segment) {\n evalMaybeExpr(segment, \"bgColor\");\n evalMaybeExpr(segment, \"customClass\");\n evalMaybeExpr(segment, \"url\");\n if (segment.showIfFormula) {\n const f = get_expression_function(segment.showIfFormula, fields);\n if (!f(row))\n segment.hide = true;\n }\n },\n });\n const locale = req.getLocale();\n translateLayout(layout, locale);\n const blockDispatch = {\n field({ field_name, fieldview, configuration }) {\n let field = fields.find((fld) => fld.name === field_name);\n if (!field)\n return \"\";\n let val = row[field_name];\n if (field &&\n field.attributes &&\n field.attributes.localized_by &&\n field.attributes.localized_by[locale]) {\n const localized_fld = field.attributes.localized_by[locale];\n val = row[localized_fld];\n }\n const cfg = { ...field.attributes, ...configuration };\n if (fieldview && field.type === \"File\") {\n return val\n ? getState().fileviews[fieldview].run(val, row[`${field_name}__filename`], cfg)\n : \"\";\n }\n else if (fieldview &&\n field.type &&\n field.type.fieldviews &&\n field.type.fieldviews[fieldview])\n return field.type.fieldviews[fieldview].run(val, req, cfg);\n else\n return text(val);\n },\n join_field(jf) {\n const { join_field, field_type, fieldview, configuration } = jf;\n const keypath = join_field.split(\".\");\n let value;\n if (join_field.includes(\"->\")) {\n const [relation, target] = join_field.split(\"->\");\n const [ontable, ref] = relation.split(\".\");\n value = row[`${ref}_${ontable}_${target}`];\n }\n else {\n value = row[join_field.split(\".\").join(\"_\")];\n }\n if (field_type === \"File\") {\n return value ? getState().fileviews[fieldview].run(value, \"\") : \"\";\n }\n if (field_type && fieldview) {\n const type = getState().types[field_type];\n if (type && getState().types[field_type]) {\n return type.fieldviews[fieldview].run(value, req, configuration);\n }\n else\n return text(value);\n }\n else\n return text(value);\n },\n aggregation({ agg_relation, stat }) {\n const [table, fld] = agg_relation.split(\".\");\n const targetNm = (stat + \"_\" + table + \"_\" + fld).toLowerCase();\n const val = row[targetNm];\n if (stat.toLowerCase() === \"array_agg\" && Array.isArray(val))\n return val.map((v) => text(v.toString())).join(\", \");\n else\n return text(val);\n },\n action(segment) {\n const url = action_url(viewname, table, segment.action_name, row, segment.rndid, \"rndid\");\n return action_link(url, req, segment);\n },\n view_link(view) {\n const { key } = view_linker(view, fields, (s) => s, isWeb(req));\n return key(row);\n },\n tabs(segment, go) {\n if (segment.tabsStyle !== \"Value switch\")\n return false;\n const value = row[segment.field];\n const ix = segment.titles.findIndex((t) => typeof t.value === \"undefined\"\n ? `${t}` === `${value}`\n : value === t.value);\n if (ix === -1)\n return \"\";\n return go(segment.contents[ix]);\n },\n };\n return renderLayout({\n blockDispatch,\n layout,\n role,\n is_owner,\n req,\n });\n};\n/**\n * @param {number} table_id\n * @param {*} viewname\n * @param {object} opts\n * @param {object[]} opts.columns\n * @param {*} opts.layout\n * @param {*} body\n * @param {object} optsTwo\n * @param {object} optsTwo.req\n * @param {*} optsTwo.res\n * @returns {Promise<object>}\n */\nconst run_action = async (table_id, viewname, { columns, layout }, body, { req, res }, { actionQuery }) => {\n const result = await actionQuery();\n if (result.json.error) {\n Crash.create({ message: result.json.error, stack: \"\" }, req);\n }\n return result;\n};\nmodule.exports = {\n /** @type {string} */\n name: \"Show\",\n /** @type {string} */\n description: \"Show a single row, with flexible layout\",\n get_state_fields,\n configuration_workflow,\n run,\n runMany,\n renderRows,\n initial_config,\n /** @type {boolean} */\n display_state_form: false,\n routes: { run_action },\n /**\n * @param {object} opts\n * @param {object} opts.layout\n * @returns {string[]}\n */\n getStringsForI18n({ layout }) {\n return getStringsForI18n(layout);\n },\n authorise_get: async ({ query, table_id }, { authorizeGetQuery }) => {\n return await authorizeGetQuery(query, table_id);\n },\n queries: ({ table_id, viewname, configuration: { columns, layout }, req, }) => ({\n async showQuery(state, fields) {\n const { joinFields, aggregations } = picked_fields_to_query(columns, fields, layout);\n readState(state, fields);\n const qstate = await stateFieldsToWhere({\n fields,\n state,\n approximate: true,\n });\n if (Object.keys(qstate).length === 0)\n return {\n rows: null,\n message: \"No row selected\",\n };\n const tbl = await Table.findOne(table_id);\n const rows = await tbl.getJoinedRows({\n where: qstate,\n joinFields,\n aggregations,\n limit: 5,\n });\n return {\n rows,\n message: null,\n };\n },\n async runManyQuery(state, { where, limit, offset, orderBy, orderDesc }) {\n const tbl = await Table.findOne({ id: table_id });\n const fields = await tbl.getFields();\n const { joinFields, aggregations } = picked_fields_to_query(columns, fields, layout);\n const qstate = await stateFieldsToWhere({ fields, state });\n const q = await stateFieldsToQuery({ state, fields });\n if (where)\n mergeIntoWhere(qstate, where);\n const role = req && req.user ? req.user.role_id : 10;\n if (tbl.ownership_field_id && role > tbl.min_role_read && req) {\n const owner_field = fields.find((f) => f.id === tbl.ownership_field_id);\n if (qstate[owner_field.name])\n qstate[owner_field.name] = [\n qstate[owner_field.name],\n req.user ? req.user.id : -1,\n ];\n else\n qstate[owner_field.name] = req.user ? req.user.id : -1;\n }\n let rows = await tbl.getJoinedRows({\n where: qstate,\n joinFields,\n aggregations,\n ...(limit && { limit: limit }),\n ...(offset && { offset: offset }),\n ...(orderBy && { orderBy: orderBy }),\n ...(orderDesc && { orderDesc: orderDesc }),\n ...q,\n });\n if (tbl.ownership_formula && role > tbl.min_role_read && req) {\n rows = rows.filter((row) => tbl.is_owner(req.user, row));\n }\n return rows;\n },\n async actionQuery() {\n const body = req.body;\n const col = columns.find((c) => c.type === \"Action\" && c.rndid === body.rndid && body.rndid);\n const table = await Table.findOne({ id: table_id });\n const row = await table.getRow({ id: body.id });\n try {\n const result = await run_action_column({\n col,\n req,\n table,\n row,\n referrer: req.get(\"Referrer\"),\n });\n return { json: { success: \"ok\", ...(result || {}) } };\n }\n catch (e) {\n return { json: { error: e.message || e } };\n }\n },\n async authorizeGetQuery(query, table_id) {\n let body = query || {};\n const user_id = req.user ? req.user.id : null;\n if (user_id && Object.keys(body).length == 1) {\n const table = await Table.findOne({ id: table_id });\n if (table.ownership_field_id || table.ownership_formula) {\n const fields = await table.getFields();\n const { uniques } = splitUniques(fields, body);\n if (Object.keys(uniques).length > 0) {\n const row = await table.getRow(uniques);\n return table.is_owner(req.user, row);\n }\n }\n }\n return false;\n },\n }),\n configCheck: async (view) => {\n return await check_view_columns(view, view.configuration.columns);\n },\n};\n//# sourceMappingURL=show.js.map\n\n//# sourceURL=webpack://saltcorn.%5Bname%5D/../saltcorn-data/dist/base-plugin/viewtemplates/show.js?");
|
|
160
|
+
|
|
161
|
+
/***/ })
|
|
162
|
+
|
|
163
|
+
},
|
|
164
|
+
/******/ __webpack_require__ => { // webpackRuntimeModules
|
|
165
|
+
/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
|
|
166
|
+
/******/ __webpack_require__.O(0, ["common_chunks","data"], () => (__webpack_exec__("../saltcorn-base-plugin/index.js")));
|
|
167
|
+
/******/ var __webpack_exports__ = __webpack_require__.O();
|
|
168
|
+
/******/ return __webpack_exports__;
|
|
169
|
+
/******/ }
|
|
170
|
+
]);
|
|
171
|
+
});
|