From 82c44b73da7557402b0bb6795477ce659a341a0c Mon Sep 17 00:00:00 2001 From: Kilian Saffran Date: Mon, 19 Apr 2021 16:04:21 +0200 Subject: [PATCH] v20210419 --- .hourtrax/hourtrax.sql | 122 +- .hourtrax/potsync.conf | 12 +- .vscode/sftp.json | 22 +- bin/CGI/api/db.cgi | 126 + bin/CGI/api/fingerprint.cgi | 92 + bin/CGI/api/lib/dksconfig.pm | 42 + bin/CGI/api/lib/dksdb.pm | 417 + bin/CGI/api/lib/sendemail.pm | 130 + bin/CGI/api/lib/session.pm | 232 + bin/CGI/api/service.cgi | 208 + bin/CGI/api/system.cgi | 167 + bin/CGI/api/tools/fingerdelete.py | 45 + bin/CGI/api/tools/fingerenroll.py | 79 + bin/CGI/api/tools/fingerledoff.py | 27 + bin/CGI/api/tools/fingerledon.py | 27 + bin/CGI/api/tools/fingersearch.py | 69 + bin/CGI/api/tools/pyfingerprint2/__init__.py | 11 + bin/CGI/api/tools/pyfingerprint2/__init__.pyc | Bin 0 -> 305 bytes .../api/tools/pyfingerprint2/pyfingerprint.py | 1358 + .../tools/pyfingerprint2/pyfingerprint.pyc | Bin 0 -> 31322 bytes bin/CGI/index.cgi | 199 + bin/CGI/tmpl/app/hourtrax/index.tt | 59 + .../tmpl/app/hourtrax/module/members/index.js | 97 + .../tmpl/app/hourtrax/module/members/index.tt | 61 + .../app/hourtrax/module/settings/index.js | 0 .../app/hourtrax/module/settings/index.tt | 34 + .../app/hourtrax/module/timetrack/index.js | 90 + .../app/hourtrax/module/timetrack/index.tt | 9 + bin/CGI/tmpl/app/timeclock/index.js | 295 + bin/CGI/tmpl/app/timeclock/index.tt | 117 + bin/CGI/tmpl/block/snackbar.tt | 1 + bin/CGI/tmpl/macro/fields.tt | 123 + bin/CGI/tmpl/skeleton/app.tt | 3 + bin/CGI/tmpl/skeleton/file.tt | 3 + bin/CGI/tmpl/skeleton/index.tt | 36 + bin/CGI/tmpl/skeleton/module.tt | 61 + bin/htdocs/css/admin.css | 240 + bin/htdocs/css/clock.css | 236 + bin/htdocs/css/clock2.css | 5 + bin/htdocs/css/w3pro.css | 378 + bin/htdocs/img/dks_1000.png | Bin 0 -> 68554 bytes bin/htdocs/img/hourtrax.png | Bin 0 -> 23443 bytes bin/htdocs/img/hourtrax.svg | 90 + bin/htdocs/img/icons/Adobe_Acrobat.svg | 1 + bin/htdocs/img/icons/Adobe_PDF_Export.svg | 1 + bin/htdocs/img/icons/Agreement_01.svg | 1 + bin/htdocs/img/icons/Bill.svg | 1 + bin/htdocs/img/icons/Document_Save.svg | 1 + bin/htdocs/img/icons/Save.svg | 1 + bin/htdocs/img/icons/address.svg | 3 + bin/htdocs/img/icons/address_white.svg | 3 + bin/htdocs/img/icons/apps.svg | 3 + bin/htdocs/img/icons/apps_white.svg | 3 + bin/htdocs/img/icons/archive.svg | 3 + bin/htdocs/img/icons/archive_white.svg | 3 + bin/htdocs/img/icons/calendar.svg | 3 + bin/htdocs/img/icons/calendar_white.svg | 3 + bin/htdocs/img/icons/clocktime.svg | 18 + bin/htdocs/img/icons/clocktime_white.svg | 14 + bin/htdocs/img/icons/club.svg | 3 + bin/htdocs/img/icons/club_white.svg | 3 + bin/htdocs/img/icons/clubs.svg | 3 + bin/htdocs/img/icons/clubs_white.svg | 3 + bin/htdocs/img/icons/code.svg | 1 + bin/htdocs/img/icons/cube.svg | 3 + bin/htdocs/img/icons/cube_white.svg | 3 + bin/htdocs/img/icons/cubelight.svg | 3 + bin/htdocs/img/icons/cubelight_white.svg | 3 + bin/htdocs/img/icons/dashboard.svg | 3 + bin/htdocs/img/icons/dashboard_white.svg | 3 + bin/htdocs/img/icons/download.svg | 3 + bin/htdocs/img/icons/download_white.svg | 3 + bin/htdocs/img/icons/duplicate.svg | 3 + bin/htdocs/img/icons/duplicate_white.svg | 3 + bin/htdocs/img/icons/edit.svg | 3 + bin/htdocs/img/icons/edit_white.svg | 3 + bin/htdocs/img/icons/file.svg | 3 + bin/htdocs/img/icons/file/dir.png | Bin 0 -> 6937 bytes bin/htdocs/img/icons/file/doc.png | Bin 0 -> 6455 bytes bin/htdocs/img/icons/file/docx.png | Bin 0 -> 6455 bytes bin/htdocs/img/icons/file/file.png | Bin 0 -> 4540 bytes bin/htdocs/img/icons/file/jpg.png | Bin 0 -> 6297 bytes bin/htdocs/img/icons/file/pdf.png | Bin 0 -> 8783 bytes bin/htdocs/img/icons/file/png.png | Bin 0 -> 6297 bytes bin/htdocs/img/icons/file/txt.png | Bin 0 -> 6049 bytes bin/htdocs/img/icons/file/xls.png | Bin 0 -> 6065 bytes bin/htdocs/img/icons/file/xlsx.png | Bin 0 -> 6065 bytes bin/htdocs/img/icons/file_white.svg | 3 + bin/htdocs/img/icons/folder.svg | 3 + bin/htdocs/img/icons/folder_white.svg | 3 + bin/htdocs/img/icons/globe.svg | 3 + bin/htdocs/img/icons/globe_white.svg | 3 + bin/htdocs/img/icons/inbox.svg | 3 + bin/htdocs/img/icons/inbox_white.svg | 3 + bin/htdocs/img/icons/library.svg | 3 + bin/htdocs/img/icons/library_white.svg | 3 + bin/htdocs/img/icons/license.svg | 3 + bin/htdocs/img/icons/license_white.svg | 3 + bin/htdocs/img/icons/list.svg | 3 + bin/htdocs/img/icons/list_white.svg | 3 + bin/htdocs/img/icons/logout.svg | 3 + bin/htdocs/img/icons/logout_white.svg | 3 + bin/htdocs/img/icons/menu.svg | 3 + bin/htdocs/img/icons/menu_white.svg | 3 + bin/htdocs/img/icons/newspaper.svg | 3 + bin/htdocs/img/icons/newspaper_white.svg | 3 + bin/htdocs/img/icons/numberlist.svg | 3 + bin/htdocs/img/icons/numberlist_white.svg | 3 + bin/htdocs/img/icons/package.svg | 3 + bin/htdocs/img/icons/package_white.svg | 3 + bin/htdocs/img/icons/pictures.svg | 1 + bin/htdocs/img/icons/pictures_white.svg | 5 + bin/htdocs/img/icons/plus.svg | 3 + bin/htdocs/img/icons/plus_white.svg | 3 + bin/htdocs/img/icons/remove.svg | 3 + bin/htdocs/img/icons/remove_white.svg | 3 + bin/htdocs/img/icons/squares.svg | 3 + bin/htdocs/img/icons/squares_white.svg | 3 + bin/htdocs/img/icons/target.svg | 3 + bin/htdocs/img/icons/target_white.svg | 3 + bin/htdocs/img/icons/user.svg | 3 + bin/htdocs/img/icons/user_white.svg | 3 + bin/htdocs/js/admin.js | 78 + bin/htdocs/js/admin_ht.js | 249 + bin/htdocs/js/fieldsave.js | 48 + bin/htdocs/js/formsave.js | 193 + bin/htdocs/js/moduleglobal.js | 24 + bin/htdocs/js/request.js | 149 + bin/htdocs/js/sysconfig.js | 149 + bin/htdocs/vendor/choices/base.css | 191 + bin/htdocs/vendor/choices/base.min.css | 1 + bin/htdocs/vendor/choices/choices.css | 368 + bin/htdocs/vendor/choices/choices.js | 6787 +++++ bin/htdocs/vendor/choices/choices.min.css | 1 + bin/htdocs/vendor/choices/choices.min.js | 58 + bin/htdocs/vendor/choices/scripts/choices.js | 6787 +++++ .../vendor/choices/scripts/choices.min.js | 58 + bin/htdocs/vendor/flatpickr/flatpickr.css | 784 + bin/htdocs/vendor/flatpickr/flatpickr.js | 2596 ++ bin/htdocs/vendor/flatpickr/flatpickr.min.css | 13 + bin/htdocs/vendor/flatpickr/flatpickr.min.js | 2 + bin/htdocs/vendor/flatpickr/ie.css | 13 + bin/htdocs/vendor/flatpickr/index.d.ts | 4 + bin/htdocs/vendor/flatpickr/l10n/de.d.ts | 66 + bin/htdocs/vendor/flatpickr/l10n/de.js | 70 + bin/htdocs/vendor/flatpickr/l10n/default.d.ts | 3 + bin/htdocs/vendor/flatpickr/l10n/default.js | 83 + bin/htdocs/vendor/flatpickr/l10n/fr.d.ts | 66 + bin/htdocs/vendor/flatpickr/l10n/fr.js | 75 + bin/htdocs/vendor/flatpickr/l10n/lu.d.ts | 67 + bin/htdocs/vendor/flatpickr/l10n/lu.js | 71 + .../plugins/confirmDate/confirmDate.css | 24 + .../plugins/confirmDate/confirmDate.d.ts | 9 + .../plugins/confirmDate/confirmDate.js | 84 + .../plugins/labelPlugin/labelPlugin.d.ts | 3 + .../plugins/labelPlugin/labelPlugin.js | 31 + .../flatpickr/plugins/minMaxTimePlugin.d.ts | 17 + .../flatpickr/plugins/minMaxTimePlugin.js | 326 + .../flatpickr/plugins/monthSelect/index.d.ts | 13 + .../flatpickr/plugins/monthSelect/index.js | 174 + .../flatpickr/plugins/monthSelect/style.css | 69 + .../plugins/monthSelect/tests.spec.d.ts | 1 + .../vendor/flatpickr/plugins/rangePlugin.d.ts | 12 + .../vendor/flatpickr/plugins/rangePlugin.js | 146 + .../flatpickr/plugins/scrollPlugin.d.ts | 3 + .../vendor/flatpickr/plugins/scrollPlugin.js | 58 + .../plugins/weekSelect/weekSelect.d.ts | 7 + .../plugins/weekSelect/weekSelect.js | 86 + bin/htdocs/vendor/flatpickr/themes/airbnb.css | 872 + .../vendor/flatpickr/themes/confetti.css | 795 + bin/htdocs/vendor/flatpickr/themes/dark.css | 784 + bin/htdocs/vendor/flatpickr/themes/light.css | 798 + .../vendor/flatpickr/themes/material_blue.css | 795 + .../flatpickr/themes/material_green.css | 795 + .../flatpickr/themes/material_orange.css | 795 + .../vendor/flatpickr/themes/material_red.css | 795 + .../vendor/flatpickr/types/globals.d.ts | 20 + .../vendor/flatpickr/types/instance.d.ts | 118 + bin/htdocs/vendor/flatpickr/types/locale.d.ts | 45 + .../vendor/flatpickr/types/options.d.ts | 144 + bin/htdocs/vendor/flatpickr/typings.d.ts | 38 + bin/htdocs/vendor/flatpickr/utils/dates.d.ts | 17 + bin/htdocs/vendor/flatpickr/utils/dom.d.ts | 6 + .../vendor/flatpickr/utils/formatting.d.ts | 13 + bin/htdocs/vendor/flatpickr/utils/index.d.ts | 8 + .../vendor/flatpickr/utils/polyfills.d.ts | 0 .../vendor/moment/moment-with-locales.min.js | 1 + bin/htdocs/vendor/moment/moment.min.js | 1 + .../css/bootstrap/tabulator_bootstrap.css | 842 + .../css/bootstrap/tabulator_bootstrap.min.css | 3 + .../bootstrap/tabulator_bootstrap.min.css.map | 1 + .../css/bootstrap/tabulator_bootstrap4.css | 1045 + .../bootstrap/tabulator_bootstrap4.min.css | 3 + .../tabulator_bootstrap4.min.css.map | 1 + .../tabulator/css/bulma/tabulator_bulma.css | 847 + .../css/bulma/tabulator_bulma.min.css | 3 + .../css/bulma/tabulator_bulma.min.css.map | 1 + .../css/semantic-ui/tabulator_semantic-ui.css | 1322 + .../semantic-ui/tabulator_semantic-ui.min.css | 3 + .../tabulator_semantic-ui.min.css.map | 1 + bin/htdocs/vendor/tabulator/css/tabulator.css | 807 + .../vendor/tabulator/css/tabulator.min.css | 3 + .../tabulator/css/tabulator.min.css.map | 1 + .../tabulator/css/tabulator_midnight.css | 810 + .../tabulator/css/tabulator_midnight.min.css | 3 + .../css/tabulator_midnight.min.css.map | 1 + .../vendor/tabulator/css/tabulator_modern.css | 832 + .../tabulator/css/tabulator_modern.min.css | 3 + .../css/tabulator_modern.min.css.map | 1 + .../vendor/tabulator/css/tabulator_simple.css | 804 + .../tabulator/css/tabulator_simple.min.css | 3 + .../css/tabulator_simple.min.css.map | 1 + .../vendor/tabulator/css/tabulator_site.css | 804 + .../tabulator/css/tabulator_site.min.css | 3 + .../tabulator/css/tabulator_site.min.css.map | 1 + .../vendor/tabulator/js/jquery_wrapper.js | 46 + .../vendor/tabulator/js/jquery_wrapper.min.js | 2 + .../vendor/tabulator/js/modules/accessor.js | 91 + .../tabulator/js/modules/accessor.min.js | 2 + .../vendor/tabulator/js/modules/ajax.js | 465 + .../vendor/tabulator/js/modules/ajax.min.js | 2 + .../js/modules/calculation_colums.js | 468 + .../js/modules/calculation_colums.min.js | 2 + .../vendor/tabulator/js/modules/clipboard.js | 1014 + .../tabulator/js/modules/clipboard.min.js | 2 + .../vendor/tabulator/js/modules/data_tree.js | 335 + .../tabulator/js/modules/data_tree.min.js | 2 + .../vendor/tabulator/js/modules/download.js | 900 + .../tabulator/js/modules/download.min.js | 2 + .../vendor/tabulator/js/modules/edit.js | 1712 ++ .../vendor/tabulator/js/modules/edit.min.js | 2 + .../vendor/tabulator/js/modules/filter.js | 752 + .../vendor/tabulator/js/modules/filter.min.js | 2 + .../vendor/tabulator/js/modules/format.js | 626 + .../vendor/tabulator/js/modules/format.min.js | 2 + .../tabulator/js/modules/frozen_columns.js | 243 + .../js/modules/frozen_columns.min.js | 2 + .../tabulator/js/modules/frozen_rows.js | 98 + .../tabulator/js/modules/frozen_rows.min.js | 2 + .../vendor/tabulator/js/modules/group_rows.js | 1048 + .../tabulator/js/modules/group_rows.min.js | 2 + .../vendor/tabulator/js/modules/history.js | 133 + .../tabulator/js/modules/history.min.js | 2 + .../tabulator/js/modules/html_table_export.js | 377 + .../js/modules/html_table_export.min.js | 2 + .../tabulator/js/modules/html_table_import.js | 203 + .../js/modules/html_table_import.min.js | 2 + .../tabulator/js/modules/keybindings.js | 378 + .../tabulator/js/modules/keybindings.min.js | 2 + .../tabulator/js/modules/moveable_columns.js | 289 + .../js/modules/moveable_columns.min.js | 2 + .../tabulator/js/modules/moveable_rows.js | 580 + .../tabulator/js/modules/moveable_rows.min.js | 2 + .../vendor/tabulator/js/modules/mutator.js | 113 + .../tabulator/js/modules/mutator.min.js | 2 + .../vendor/tabulator/js/modules/page.js | 636 + .../vendor/tabulator/js/modules/page.min.js | 2 + .../tabulator/js/modules/persistence.js | 222 + .../tabulator/js/modules/persistence.min.js | 2 + .../vendor/tabulator/js/modules/print.js | 96 + .../vendor/tabulator/js/modules/print.min.js | 2 + .../tabulator/js/modules/reactive_data.js | 235 + .../tabulator/js/modules/reactive_data.min.js | 2 + .../tabulator/js/modules/resize_columns.js | 161 + .../js/modules/resize_columns.min.js | 2 + .../tabulator/js/modules/resize_rows.js | 98 + .../tabulator/js/modules/resize_rows.min.js | 2 + .../tabulator/js/modules/resize_table.js | 38 + .../tabulator/js/modules/resize_table.min.js | 2 + .../tabulator/js/modules/responsive_layout.js | 255 + .../js/modules/responsive_layout.min.js | 2 + .../vendor/tabulator/js/modules/select_row.js | 359 + .../tabulator/js/modules/select_row.min.js | 2 + .../vendor/tabulator/js/modules/sort.js | 560 + .../vendor/tabulator/js/modules/sort.min.js | 2 + .../vendor/tabulator/js/modules/validate.js | 212 + .../tabulator/js/modules/validate.min.js | 2 + bin/htdocs/vendor/tabulator/js/tabulator.js | 22796 ++++++++++++++++ .../vendor/tabulator/js/tabulator.min.js | 11 + .../vendor/tabulator/js/tabulator_core.js | 7812 ++++++ .../vendor/tabulator/js/tabulator_core.min.js | 5 + bin/syncup.pl | 252 +- bin/websrv.pl | 112 + desktopapp/img/touch.svg | 8 +- dev/main.py | 714 +- install/.hourtrax/ht.sql | 156 +- .../bin/electron/resources/app/css/clock.css | 470 +- .../resources/app/img/fingerprint/finger1.svg | 160 +- .../resources/app/img/fingerprint/finger2.svg | 164 +- .../resources/app/img/fingerprint/finger3.svg | 160 +- .../resources/app/img/fingerprint/finger4.svg | 156 +- .../resources/app/img/fingerprint/finger5.svg | 158 +- .../app/img/fingerprint/fingerprint-check.svg | 172 +- .../img/fingerprint/fingerprint-crosshair.svg | 182 +- .../img/fingerprint/fingerprint-remove.svg | 172 +- .../fingerprint/fingerprint-remove_white.svg | 172 +- .../fingerprint-scanning-index.svg | 218 +- .../img/fingerprint/fingerprint-scanning.svg | 180 +- .../img/fingerprint/fingerprint-search.svg | 406 +- .../img/fingerprint/fingerprint-simple.svg | 174 +- .../bin/electron/resources/app/img/pot.svg | 520 +- .../bin/electron/resources/app/img/touch.svg | 8 +- .../bin/electron/resources/app/js/admin.js | 132 +- install/bin/electron/resources/app/js/app.js | 78 +- install/bin/electron/resources/app/main.js | 186 +- .../electron/resources/app/package-lock.json | 1876 +- .../bin/electron/resources/app/package.json | 20 +- .../bin/electron/resources/app/css/clock.css | 470 +- .../resources/app/img/fingerprint/finger1.svg | 160 +- .../resources/app/img/fingerprint/finger2.svg | 164 +- .../resources/app/img/fingerprint/finger3.svg | 160 +- .../resources/app/img/fingerprint/finger4.svg | 156 +- .../resources/app/img/fingerprint/finger5.svg | 158 +- .../app/img/fingerprint/fingerprint-check.svg | 172 +- .../img/fingerprint/fingerprint-crosshair.svg | 182 +- .../img/fingerprint/fingerprint-remove.svg | 172 +- .../fingerprint/fingerprint-remove_white.svg | 172 +- .../fingerprint-scanning-index.svg | 218 +- .../img/fingerprint/fingerprint-scanning.svg | 180 +- .../img/fingerprint/fingerprint-search.svg | 406 +- .../img/fingerprint/fingerprint-simple.svg | 174 +- latest/bin/electron/resources/app/img/pot.svg | 520 +- .../bin/electron/resources/app/img/touch.svg | 8 +- latest/bin/electron/resources/app/js/app.js | 132 +- latest/bin/electron/resources/app/main.js | 186 +- .../electron/resources/app/package-lock.json | 1876 +- .../bin/electron/resources/app/package.json | 20 +- 327 files changed, 90401 insertions(+), 6368 deletions(-) create mode 100644 bin/CGI/api/db.cgi create mode 100644 bin/CGI/api/fingerprint.cgi create mode 100644 bin/CGI/api/lib/dksconfig.pm create mode 100644 bin/CGI/api/lib/dksdb.pm create mode 100644 bin/CGI/api/lib/sendemail.pm create mode 100644 bin/CGI/api/lib/session.pm create mode 100644 bin/CGI/api/service.cgi create mode 100644 bin/CGI/api/system.cgi create mode 100644 bin/CGI/api/tools/fingerdelete.py create mode 100644 bin/CGI/api/tools/fingerenroll.py create mode 100644 bin/CGI/api/tools/fingerledoff.py create mode 100644 bin/CGI/api/tools/fingerledon.py create mode 100644 bin/CGI/api/tools/fingersearch.py create mode 100644 bin/CGI/api/tools/pyfingerprint2/__init__.py create mode 100644 bin/CGI/api/tools/pyfingerprint2/__init__.pyc create mode 100644 bin/CGI/api/tools/pyfingerprint2/pyfingerprint.py create mode 100644 bin/CGI/api/tools/pyfingerprint2/pyfingerprint.pyc create mode 100644 bin/CGI/index.cgi create mode 100644 bin/CGI/tmpl/app/hourtrax/index.tt create mode 100644 bin/CGI/tmpl/app/hourtrax/module/members/index.js create mode 100644 bin/CGI/tmpl/app/hourtrax/module/members/index.tt create mode 100644 bin/CGI/tmpl/app/hourtrax/module/settings/index.js create mode 100644 bin/CGI/tmpl/app/hourtrax/module/settings/index.tt create mode 100644 bin/CGI/tmpl/app/hourtrax/module/timetrack/index.js create mode 100644 bin/CGI/tmpl/app/hourtrax/module/timetrack/index.tt create mode 100644 bin/CGI/tmpl/app/timeclock/index.js create mode 100644 bin/CGI/tmpl/app/timeclock/index.tt create mode 100644 bin/CGI/tmpl/block/snackbar.tt create mode 100644 bin/CGI/tmpl/macro/fields.tt create mode 100644 bin/CGI/tmpl/skeleton/app.tt create mode 100644 bin/CGI/tmpl/skeleton/file.tt create mode 100644 bin/CGI/tmpl/skeleton/index.tt create mode 100644 bin/CGI/tmpl/skeleton/module.tt create mode 100644 bin/htdocs/css/admin.css create mode 100644 bin/htdocs/css/clock.css create mode 100644 bin/htdocs/css/clock2.css create mode 100644 bin/htdocs/css/w3pro.css create mode 100644 bin/htdocs/img/dks_1000.png create mode 100644 bin/htdocs/img/hourtrax.png create mode 100644 bin/htdocs/img/hourtrax.svg create mode 100644 bin/htdocs/img/icons/Adobe_Acrobat.svg create mode 100644 bin/htdocs/img/icons/Adobe_PDF_Export.svg create mode 100644 bin/htdocs/img/icons/Agreement_01.svg create mode 100644 bin/htdocs/img/icons/Bill.svg create mode 100644 bin/htdocs/img/icons/Document_Save.svg create mode 100644 bin/htdocs/img/icons/Save.svg create mode 100644 bin/htdocs/img/icons/address.svg create mode 100644 bin/htdocs/img/icons/address_white.svg create mode 100644 bin/htdocs/img/icons/apps.svg create mode 100644 bin/htdocs/img/icons/apps_white.svg create mode 100644 bin/htdocs/img/icons/archive.svg create mode 100644 bin/htdocs/img/icons/archive_white.svg create mode 100644 bin/htdocs/img/icons/calendar.svg create mode 100644 bin/htdocs/img/icons/calendar_white.svg create mode 100644 bin/htdocs/img/icons/clocktime.svg create mode 100644 bin/htdocs/img/icons/clocktime_white.svg create mode 100644 bin/htdocs/img/icons/club.svg create mode 100644 bin/htdocs/img/icons/club_white.svg create mode 100644 bin/htdocs/img/icons/clubs.svg create mode 100644 bin/htdocs/img/icons/clubs_white.svg create mode 100644 bin/htdocs/img/icons/code.svg create mode 100644 bin/htdocs/img/icons/cube.svg create mode 100644 bin/htdocs/img/icons/cube_white.svg create mode 100644 bin/htdocs/img/icons/cubelight.svg create mode 100644 bin/htdocs/img/icons/cubelight_white.svg create mode 100644 bin/htdocs/img/icons/dashboard.svg create mode 100644 bin/htdocs/img/icons/dashboard_white.svg create mode 100644 bin/htdocs/img/icons/download.svg create mode 100644 bin/htdocs/img/icons/download_white.svg create mode 100644 bin/htdocs/img/icons/duplicate.svg create mode 100644 bin/htdocs/img/icons/duplicate_white.svg create mode 100644 bin/htdocs/img/icons/edit.svg create mode 100644 bin/htdocs/img/icons/edit_white.svg create mode 100644 bin/htdocs/img/icons/file.svg create mode 100644 bin/htdocs/img/icons/file/dir.png create mode 100644 bin/htdocs/img/icons/file/doc.png create mode 100644 bin/htdocs/img/icons/file/docx.png create mode 100644 bin/htdocs/img/icons/file/file.png create mode 100644 bin/htdocs/img/icons/file/jpg.png create mode 100644 bin/htdocs/img/icons/file/pdf.png create mode 100644 bin/htdocs/img/icons/file/png.png create mode 100644 bin/htdocs/img/icons/file/txt.png create mode 100644 bin/htdocs/img/icons/file/xls.png create mode 100644 bin/htdocs/img/icons/file/xlsx.png create mode 100644 bin/htdocs/img/icons/file_white.svg create mode 100644 bin/htdocs/img/icons/folder.svg create mode 100644 bin/htdocs/img/icons/folder_white.svg create mode 100644 bin/htdocs/img/icons/globe.svg create mode 100644 bin/htdocs/img/icons/globe_white.svg create mode 100644 bin/htdocs/img/icons/inbox.svg create mode 100644 bin/htdocs/img/icons/inbox_white.svg create mode 100644 bin/htdocs/img/icons/library.svg create mode 100644 bin/htdocs/img/icons/library_white.svg create mode 100644 bin/htdocs/img/icons/license.svg create mode 100644 bin/htdocs/img/icons/license_white.svg create mode 100644 bin/htdocs/img/icons/list.svg create mode 100644 bin/htdocs/img/icons/list_white.svg create mode 100644 bin/htdocs/img/icons/logout.svg create mode 100644 bin/htdocs/img/icons/logout_white.svg create mode 100644 bin/htdocs/img/icons/menu.svg create mode 100644 bin/htdocs/img/icons/menu_white.svg create mode 100644 bin/htdocs/img/icons/newspaper.svg create mode 100644 bin/htdocs/img/icons/newspaper_white.svg create mode 100644 bin/htdocs/img/icons/numberlist.svg create mode 100644 bin/htdocs/img/icons/numberlist_white.svg create mode 100644 bin/htdocs/img/icons/package.svg create mode 100644 bin/htdocs/img/icons/package_white.svg create mode 100644 bin/htdocs/img/icons/pictures.svg create mode 100644 bin/htdocs/img/icons/pictures_white.svg create mode 100644 bin/htdocs/img/icons/plus.svg create mode 100644 bin/htdocs/img/icons/plus_white.svg create mode 100644 bin/htdocs/img/icons/remove.svg create mode 100644 bin/htdocs/img/icons/remove_white.svg create mode 100644 bin/htdocs/img/icons/squares.svg create mode 100644 bin/htdocs/img/icons/squares_white.svg create mode 100644 bin/htdocs/img/icons/target.svg create mode 100644 bin/htdocs/img/icons/target_white.svg create mode 100644 bin/htdocs/img/icons/user.svg create mode 100644 bin/htdocs/img/icons/user_white.svg create mode 100644 bin/htdocs/js/admin.js create mode 100644 bin/htdocs/js/admin_ht.js create mode 100644 bin/htdocs/js/fieldsave.js create mode 100644 bin/htdocs/js/formsave.js create mode 100644 bin/htdocs/js/moduleglobal.js create mode 100644 bin/htdocs/js/request.js create mode 100644 bin/htdocs/js/sysconfig.js create mode 100644 bin/htdocs/vendor/choices/base.css create mode 100644 bin/htdocs/vendor/choices/base.min.css create mode 100644 bin/htdocs/vendor/choices/choices.css create mode 100644 bin/htdocs/vendor/choices/choices.js create mode 100644 bin/htdocs/vendor/choices/choices.min.css create mode 100644 bin/htdocs/vendor/choices/choices.min.js create mode 100644 bin/htdocs/vendor/choices/scripts/choices.js create mode 100644 bin/htdocs/vendor/choices/scripts/choices.min.js create mode 100644 bin/htdocs/vendor/flatpickr/flatpickr.css create mode 100644 bin/htdocs/vendor/flatpickr/flatpickr.js create mode 100644 bin/htdocs/vendor/flatpickr/flatpickr.min.css create mode 100644 bin/htdocs/vendor/flatpickr/flatpickr.min.js create mode 100644 bin/htdocs/vendor/flatpickr/ie.css create mode 100644 bin/htdocs/vendor/flatpickr/index.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/l10n/de.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/l10n/de.js create mode 100644 bin/htdocs/vendor/flatpickr/l10n/default.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/l10n/default.js create mode 100644 bin/htdocs/vendor/flatpickr/l10n/fr.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/l10n/fr.js create mode 100644 bin/htdocs/vendor/flatpickr/l10n/lu.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/l10n/lu.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/confirmDate/confirmDate.css create mode 100644 bin/htdocs/vendor/flatpickr/plugins/confirmDate/confirmDate.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/confirmDate/confirmDate.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/labelPlugin/labelPlugin.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/labelPlugin/labelPlugin.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/minMaxTimePlugin.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/minMaxTimePlugin.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/monthSelect/index.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/monthSelect/index.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/monthSelect/style.css create mode 100644 bin/htdocs/vendor/flatpickr/plugins/monthSelect/tests.spec.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/rangePlugin.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/rangePlugin.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/scrollPlugin.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/scrollPlugin.js create mode 100644 bin/htdocs/vendor/flatpickr/plugins/weekSelect/weekSelect.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/plugins/weekSelect/weekSelect.js create mode 100644 bin/htdocs/vendor/flatpickr/themes/airbnb.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/confetti.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/dark.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/light.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/material_blue.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/material_green.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/material_orange.css create mode 100644 bin/htdocs/vendor/flatpickr/themes/material_red.css create mode 100644 bin/htdocs/vendor/flatpickr/types/globals.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/types/instance.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/types/locale.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/types/options.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/typings.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/utils/dates.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/utils/dom.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/utils/formatting.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/utils/index.d.ts create mode 100644 bin/htdocs/vendor/flatpickr/utils/polyfills.d.ts create mode 100644 bin/htdocs/vendor/moment/moment-with-locales.min.js create mode 100644 bin/htdocs/vendor/moment/moment.min.js create mode 100644 bin/htdocs/vendor/tabulator/css/bootstrap/tabulator_bootstrap.css create mode 100644 bin/htdocs/vendor/tabulator/css/bootstrap/tabulator_bootstrap.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/bootstrap/tabulator_bootstrap.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/bootstrap/tabulator_bootstrap4.css create mode 100644 bin/htdocs/vendor/tabulator/css/bootstrap/tabulator_bootstrap4.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/bootstrap/tabulator_bootstrap4.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/bulma/tabulator_bulma.css create mode 100644 bin/htdocs/vendor/tabulator/css/bulma/tabulator_bulma.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/bulma/tabulator_bulma.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/semantic-ui/tabulator_semantic-ui.css create mode 100644 bin/htdocs/vendor/tabulator/css/semantic-ui/tabulator_semantic-ui.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/semantic-ui/tabulator_semantic-ui.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_midnight.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_midnight.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_midnight.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_modern.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_modern.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_modern.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_simple.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_simple.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_simple.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_site.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_site.min.css create mode 100644 bin/htdocs/vendor/tabulator/css/tabulator_site.min.css.map create mode 100644 bin/htdocs/vendor/tabulator/js/jquery_wrapper.js create mode 100644 bin/htdocs/vendor/tabulator/js/jquery_wrapper.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/accessor.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/accessor.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/ajax.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/ajax.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/calculation_colums.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/calculation_colums.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/clipboard.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/clipboard.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/data_tree.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/data_tree.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/download.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/download.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/edit.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/edit.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/filter.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/filter.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/format.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/format.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/frozen_columns.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/frozen_columns.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/frozen_rows.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/frozen_rows.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/group_rows.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/group_rows.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/history.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/history.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/html_table_export.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/html_table_export.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/html_table_import.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/html_table_import.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/keybindings.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/keybindings.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/moveable_columns.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/moveable_columns.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/moveable_rows.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/moveable_rows.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/mutator.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/mutator.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/page.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/page.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/persistence.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/persistence.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/print.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/print.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/reactive_data.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/reactive_data.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/resize_columns.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/resize_columns.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/resize_rows.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/resize_rows.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/resize_table.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/resize_table.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/responsive_layout.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/responsive_layout.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/select_row.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/select_row.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/sort.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/sort.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/validate.js create mode 100644 bin/htdocs/vendor/tabulator/js/modules/validate.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/tabulator.js create mode 100644 bin/htdocs/vendor/tabulator/js/tabulator.min.js create mode 100644 bin/htdocs/vendor/tabulator/js/tabulator_core.js create mode 100644 bin/htdocs/vendor/tabulator/js/tabulator_core.min.js create mode 100644 bin/websrv.pl diff --git a/.hourtrax/hourtrax.sql b/.hourtrax/hourtrax.sql index 6a6c2af..4009253 100644 --- a/.hourtrax/hourtrax.sql +++ b/.hourtrax/hourtrax.sql @@ -1,61 +1,61 @@ -CREATE TABLE staff ( - id TEXT NOT NULL, - staffnumber TEXT, - prename TEXT, - surname TEXT, - pin TEXT, - rfid TEXT, - isblocked BOOLEAN, - isdisabled BOOLEAN, - isdeleted BOOLEAN, - modified DATETIME DEFAULT (datetime('now','localtime')), - created DATETIME DEFAULT (datetime('now','localtime')), - PRIMARY KEY (id) -); -CREATE TABLE timetracks ( - id text not null, - id_staff TEXT, - daydate date, - stamp_in DATETIME, - stamp_out DATETIME, - tracktype TEXT, - modified DATETIME DEFAULT (datetime('now','localtime')), - created DATETIME DEFAULT (datetime('now','localtime')), - primary key (id) -); -CREATE TABLE fingerprints ( - id_staff TEXT, - fingerhash TEXT, - fingertype integer, - modified DATETIME DEFAULT (datetime('now','localtime')), - created DATETIME DEFAULT (datetime('now','localtime')), - primary key (id_staff,fingerhash) -); -CREATE TABLE staffworktimes ( - id TEXT not null, - id_staff TEXT, - daydate date, - starttime1 TEXT, - endtime1 TEXT, - starttime2 TEXT, - endtime2 TEXT, - modified DATETIME DEFAULT (datetime('now','localtime')), - created DATETIME DEFAULT (datetime('now','localtime')), - primary key (id) -); -CREATE TRIGGER trg_staff_upd UPDATE ON staff - BEGIN - UPDATE staff SET modified=datetime('now','localtime') WHERE id = NEW.id; - END; -CREATE TRIGGER trg_timetracks_upd UPDATE ON staff - BEGIN - UPDATE timetracks SET modified=datetime('now','localtime') WHERE id = NEW.id; - END; -CREATE TRIGGER trg_staffworktimes_upd UPDATE ON staff - BEGIN - UPDATE staffworktimes SET modified=datetime('now','localtime') WHERE id = NEW.id; - END; - CREATE TRIGGER trg_fingerprints_upd UPDATE ON staff - BEGIN - UPDATE staffworktimes SET modified=datetime('now','localtime') WHERE id_staff = NEW.id_staff and fingertype= NEW.fingertype; - END; +CREATE TABLE staff ( + id TEXT NOT NULL, + staffnumber TEXT, + prename TEXT, + surname TEXT, + pin TEXT, + rfid TEXT, + isblocked BOOLEAN, + isdisabled BOOLEAN, + isdeleted BOOLEAN, + modified DATETIME DEFAULT (datetime('now','localtime')), + created DATETIME DEFAULT (datetime('now','localtime')), + PRIMARY KEY (id) +); +CREATE TABLE timetracks ( + id text not null, + id_staff TEXT, + daydate date, + stamp_in DATETIME, + stamp_out DATETIME, + tracktype TEXT, + modified DATETIME DEFAULT (datetime('now','localtime')), + created DATETIME DEFAULT (datetime('now','localtime')), + primary key (id) +); +CREATE TABLE fingerprints ( + id_staff TEXT, + fingerhash TEXT, + fingertype integer, + modified DATETIME DEFAULT (datetime('now','localtime')), + created DATETIME DEFAULT (datetime('now','localtime')), + primary key (id_staff,fingerhash) +); +CREATE TABLE staffworktimes ( + id TEXT not null, + id_staff TEXT, + daydate date, + starttime1 TEXT, + endtime1 TEXT, + starttime2 TEXT, + endtime2 TEXT, + modified DATETIME DEFAULT (datetime('now','localtime')), + created DATETIME DEFAULT (datetime('now','localtime')), + primary key (id) +); +CREATE TRIGGER trg_staff_upd UPDATE ON staff + BEGIN + UPDATE staff SET modified=datetime('now','localtime') WHERE id = NEW.id; + END; +CREATE TRIGGER trg_timetracks_upd UPDATE ON staff + BEGIN + UPDATE timetracks SET modified=datetime('now','localtime') WHERE id = NEW.id; + END; +CREATE TRIGGER trg_staffworktimes_upd UPDATE ON staff + BEGIN + UPDATE staffworktimes SET modified=datetime('now','localtime') WHERE id = NEW.id; + END; + CREATE TRIGGER trg_fingerprints_upd UPDATE ON staff + BEGIN + UPDATE staffworktimes SET modified=datetime('now','localtime') WHERE id_staff = NEW.id_staff and fingertype= NEW.fingertype; + END; diff --git a/.hourtrax/potsync.conf b/.hourtrax/potsync.conf index 7267af7..276fce0 100644 --- a/.hourtrax/potsync.conf +++ b/.hourtrax/potsync.conf @@ -1,6 +1,6 @@ -USERAGENT=POT Hourtrax -POTAPIKEY=6b9c80d2-9153-11eb-8558-efa3f9982293 -POTAPIURL=http://app.pot.lan/potapp/api.php -POTSCHEMA=alicehartmann -POTLASTSYNCFROMSERVER= -POTLASTSYNCTOSERVER= +USERAGENT=POT Hourtrax +POTAPIKEY=6b9c80d2-9153-11eb-8558-efa3f9982293 +POTAPIURL=http://app.pot.lan/potapp/api.php +POTSCHEMA=alicehartmann +POTLASTSYNCFROMSERVER= +POTLASTSYNCTOSERVER= diff --git a/.vscode/sftp.json b/.vscode/sftp.json index 8d5f6a8..198bff8 100644 --- a/.vscode/sftp.json +++ b/.vscode/sftp.json @@ -1,11 +1,11 @@ - -{ - "name": "htx-test", - "scheme": "sftp", - "context": "bin/", - "host": "dhart-pot02", - "username": "pot", - "password": "sai4seip", - "port":3587, - "remotePath": "/home/pot/bin/" -} + +{ + "name": "htx-test", + "scheme": "sftp", + "context": "bin/", + "host": "dhart-hourtrax01", + "username": "pot", + "password": "sai4seip", + "port":3587, + "remotePath": "/home/pot/bin/" +} diff --git a/bin/CGI/api/db.cgi b/bin/CGI/api/db.cgi new file mode 100644 index 0000000..6a6e177 --- /dev/null +++ b/bin/CGI/api/db.cgi @@ -0,0 +1,126 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl +use strict; +use FindBin qw($Bin); +# use lib ('CGI/api/lib/perl5'); +# use lib ('CGI/api/lib'); +use lib ($Bin.'/CGI/api/lib/perl5'); +use lib ($Bin.'/CGI/api/lib'); +use CGI; +use CGI::Cookie; +# use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use JSON::PP; +#use UUID::Tiny ':std'; +use dksconfig qw/$sitecfg/; +use dksdb; + +# use session; +#use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +my $html->{result} = (); +# $p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +# my $se = session->new(); +# my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8"); +my $dbredirect = {}; +if ($sitecfg->{dbtype} eq "SQLite"){ + if (exists($p->{db})){ + $dbredirect->{dsn} = "DBI:SQLite:dbname=".$sitecfg->{datapath}.'/'.$p->{db}.'.sqlite'; + } +} +$html->{conn} = $dbredirect; +# if ($sess == undef){ +# $html->{error} = "No Authorisation"; +# print JSON::PP::encode_json($html); +# exit(0); +# } +# $html->{p} = $p; +# $html->{sess} =$sess; +#my $datapath = $ENV{"DOCUMENT_ROOT"}.dirname(dirname($scriptpath)).'/data/'; +if (($cgi->request_method() eq "GET") || ($cgi->request_method() eq "POST")){ + + # my @params = $cgi->param(); + # foreach my $pp (@params){ + # $p->{$pp} = $cgi->param($pp); + # } + my $db = dksdb->new($dbredirect); + if (exists($p->{get})){ + my $sql = "select * from vw_".$p->{get}; + if (exists($p->{fields}) ){ + $sql = "select ".$p->{fields}." from vw_".$p->{get}; + } + if (exists($p->{filter})){ + $sql .= " WHERE ".$p->{filter}.";"; + } + $html->{result}->{sqldata} = $db->query($sql); + } + elsif (exists($p->{set})){ + my $type = "ins"; + foreach my $x (keys(%{$p})){ + if ($x =~ /^ident_/ ){ + if ($p->{$x} ne ""){ + $type = "upd"; + } else { + my $uuid = create_uuid(UUID_TIME); + my $uuid_str=uuid_to_string($uuid); + $p->{$x} = $uuid_str; + } + + } + } + + my $x = $p; + delete $x->{sid}; + delete $x->{set}; + my @sql = (); + + if ($type eq "ins"){ + + @sql = $db->create_ddl_insert($x); + }else { + @sql = $db->create_ddl_update($x); + } + if (scalar(@sql) > 0 ){ + my $rid = $db->query($sql[0]); + if (keys(%{$rid}) > 0 ){ + $html->{result} = $rid->{0}; + } + } + } + elsif (exists($p->{del})){ + my $x = $p; + delete $x->{sid}; + delete $x->{del}; + my @sql = $db->create_ddl_delete($x); + if (scalar(@sql) > 0 ){ + my $rid = $db->exec($sql[0]); + if (keys(%{$rid}) > 0 ){ + $html->{result} = $rid->{0}; + } + } + } + elsif (exists($p->{sql})){ + if (exists($p->{key})){ + $html->{result} = $db->querybykey($p->{key},$p->{sql}); + } + if ((lc($p->{sql}) =~ /^insert/) || (lc($p->{sql}) =~ /^update/) || (lc($p->{sql}) =~ /^delete/)){ + $html->{result} = $db->exec($p->{sql}); + } + else { + $html->{result} = $db->query($p->{sql}); + } + } + elsif (exists($p->{ddl})){ + $html->{result} = $db->exec($p->{sql}); + } +} +print JSON::PP::encode_json($html); +# for my $e ( keys %ENV ) { +# print "$e: $ENV{$e}
"; +# } \ No newline at end of file diff --git a/bin/CGI/api/fingerprint.cgi b/bin/CGI/api/fingerprint.cgi new file mode 100644 index 0000000..0ade403 --- /dev/null +++ b/bin/CGI/api/fingerprint.cgi @@ -0,0 +1,92 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl +use strict; +use FindBin qw($Bin); +# use lib ('CGI/api/lib/perl5'); +# use lib ('CGI/api/lib'); +use lib ($Bin.'/CGI/api/lib/perl5'); +use lib ($Bin.'/CGI/api/lib'); +use CGI; +use CGI::Cookie; +# use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use JSON::PP; + +use dksconfig qw/$sitecfg/; +use dksdb; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +my $html->{result} = (); +# $p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +# my $se = session->new(); +# my $sess = $se->getsession($p->{sid}); +if (exists($p->{fn}) ){ + if (exists($p->{id_user})){ + if ($p->{fn} eq "new"){ + my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledon.py'; + my $res = `$cmd`; + chomp($res); + if ($res eq ''){ + $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerenroll.py'; + my $res = `$cmd`; + } + + + + } elsif ($p->{fn} eq "check"){ + my $cmd ='sudo /usr/bin/python '.dirname($0).'/tools/fingersearch.py'; + my $res = `$cmd`; + chomp($res); + if ($res =~ /POS:.*HASH:/){ + my ($pos,$hash) = $res =~ m/.*POS:(\d+);HASH:(.+)\s*$/; + $html->{result}->{pos} = $pos; + $html->{result}->{hash} = $hash; + if (length($pos) > 0 && length($hash) > 0){ + my $sql = "select id,fingerpos,fingerhash from staff where id=".$p->{id_user}." and fingerpos=".$pos." and fingerhash='".$hash."';"; + my $db = dksdb->new(); + $html->{result}->{sql} = $sql; + my @rdb = $db->query($sql); + if (scalar(@rdb) > 0 ){ + $html->{result}->{status} ="OK"; + $html->{result}->{db} = \@rdb; + $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledoff.py'; + $res = `$cmd`; + } + } + + } else { + $html->{result}->{status} = $res; + } + } + } + elsif($p->{fn} eq "unload"){ + my $cmd = 'ps ax | grep "tools/finger" | awk \'{ print \$ }\''; + my $res = `$cmd`; + } + elsif($p->{fn} eq "ledon"){ + my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledon.py'; + my $res = `$cmd`; + chomp($res); + if ($res eq ""){ + $html->{result}->{status} = "ok"; + } else { + $html->{result}->{status} = "error"; + } + } + elsif($p->{fn} eq "ledoff"){ + my $cmd ='/usr/bin/python2 '.dirname($0).'/tools/fingerledoff.py'; + my $res = `$cmd`; + chomp($res); + if ($res eq ""){ + $html->{result}->{status} = "ok"; + } else { + $html->{result}->{status} = "error"; + } + } +} +print $cgi->header(-type=>"application/json", -charset => "utf-8"); +print JSON::PP::encode_json($html); \ No newline at end of file diff --git a/bin/CGI/api/lib/dksconfig.pm b/bin/CGI/api/lib/dksconfig.pm new file mode 100644 index 0000000..e35669d --- /dev/null +++ b/bin/CGI/api/lib/dksconfig.pm @@ -0,0 +1,42 @@ +package dksconfig; + +use strict; +# use lib ('./lib/perl5'); +# use lib ('./lib'); +# use lib ('./'); +use File::Basename; +use Exporter 'import'; +our @EXPORT_OK = qw($sitecfg); +my $cfgpath=$ENV{HOME}.'/.hourtrax'; +if ($^O eq "MSWin32"){ + $cfgpath = $ENV{APPDATA}.'/hourtrax'; +} elsif ($^O eq "darwin"){ + $cfgpath = $ENV{HOME}.'/Library/Application Support/hourtrax'; +} +$cfgpath =~ s/\\/\//g; +our $sitecfg ={ + #cookiename => undef, + datapath => $cfgpath, + dbtype => 'SQLite', #'PgPP' or ScLite + dsn => 'DBI:SQLite:dbname='.$cfgpath.'/hourtrax.sqlite', + dbuser => '', + dbpassword => '', + basepath => '/', + staticpath => 'htdocs/', + #dsn => 'DBI:PgPP:dbname=fldlu_db;host=DKS-LAPTOP.fritz.box', + #dsn => 'DBI:PgPP:dbname=fldlu_db;host=sql629.your-server.de', + #dbuser => 'fldlu_user', + #dbpassword => 'Tm6G1bjQSudiEBAY', + page => 'index.tt', + pagename => 'index', + # basepath => substr((exists($ENV{"SCRIPT_FILENAME"})?dirname($ENV{"SCRIPT_FILENAME"}):dirname($0)),length($ENV{"DOCUMENT_ROOT"})), + # datapath => substr((exists($ENV{"SCRIPT_FILENAME"})?dirname($ENV{"SCRIPT_FILENAME"}):dirname($0)),length($ENV{"DOCUMENT_ROOT"})).'/data/', + # docroot => $ENV{"DOCUMENT_ROOT"}, + # registration_enabled => '1', + # default_group => 'users', + # sitename => 'FLD Member Area', + # season => '2019-2020', + # season_id => 2 +}; + +1; \ No newline at end of file diff --git a/bin/CGI/api/lib/dksdb.pm b/bin/CGI/api/lib/dksdb.pm new file mode 100644 index 0000000..fda73ef --- /dev/null +++ b/bin/CGI/api/lib/dksdb.pm @@ -0,0 +1,417 @@ +package dksdb; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +#BEGIN { $ENV{DBI_PUREPERL} = 2 } +use DBI; +use File::Basename; + +use Digest::SHA::PurePerl qw(sha256_hex); +use DBD::PgPP; +use DBD::SQLite; +use URI::Encode qw(uri_encode uri_decode); +use Encode; +use dksconfig qw($sitecfg); +use Text::Unidecode; + + +sub new { + my $class = shift; + my $param = shift; + my $self = bless {}, $class; + foreach my $p (keys %{$param}){ + $self->{$p} = $param->{$p}; + } + + return $self; +} + +sub securetext(){ + my $self = shift; + my $text = shift; + $text =~ s/'/''/g; + return $text; +} + +sub query(){ + my $self = shift; + my $stat = shift; + # my $vw_info = shift; + my @retdata = (); + my $dbh = DBI->connect(((exists($self->{dsn}))?$self->{dsn}:$sitecfg->{dsn}),$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return \@retdata;#$retdata[0] = "dbquery Connection Error!".$!; + $stat = encode("utf8", $stat); + # open FILE,">>tmp/sql.log"; + # print FILE "$stat\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return \@retdata;#$retdata[0] = "dbquery".$dbh->errstr. "- SQL: ".$stat;; + + + $sth->execute() or return \@retdata; #"dbquery: ".$sth->errstr; + + while(my $data = $sth->fetchrow_hashref()){ + my $row = (); + foreach my $k (keys %{$data}){ + $row->{$k} = decode("utf-8",$data->{$k}); + } + push @retdata,$row; + } + + $sth->finish(); + $dbh->disconnect(); + + return \@retdata; +} + +sub querybykey(){ + my $self = shift; + my $key = shift; + my $stat = shift; + #my $retempty = shift; + my @retdata =(); + my $dbh = DBI->connect(((exists($self->{dsn}))?$self->{dsn}:$sitecfg->{dsn}),$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return \@retdata;#$retdata[0] = "dbquery Connection Error!".$!; + # $stat = encode("utf8", $stat); + + # open FILE,">>sql.log"; + # print FILE "$stat\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return \@retdata;#$retdata[0] = "dbquery: ".$stat; + $sth->execute() or return \@retdata;#$retata[0] = "dbquery: ".$stat; + while(my $data = $sth->fetchrow_hashref()) + { + if (exists $data->{$key}){ + my $row = (); + foreach my $k (keys %{$data}){ + $row->{$k} = decode("utf-8",$data->{$k}); + } + push @retdata,$row; + } + } + # if (keys(%{$retdata}) == 0){ + # $retdata =(); + # } + $sth->finish(); + $dbh->disconnect(); + return \@retdata; +} + +# sub dbquerysorted(){ +# my $self = shift; +# my $stat = shift; +# # my $vw_info = shift; +# my $retdata; +# my $dbh = DBI->connect(((exists($self->{dsn}))?$self->{dsn}:$sitecfg->{dsn}),$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!; +# # $stat = encode("utf8", $stat); +# # open FILE,">>tmp/sql.log"; +# # print FILE "\n==\n$stat\n==\n"; +# # close FILE; +# my $sth = $dbh->prepare($stat) or return $retdata->{error} = "dbquerysorted ".$dbh->errstr. "- SQL: ".$stat;; + + +# $sth->execute() or return $retdata->{error} = "dbquerysorted: ".$sth->errstr; +# my $count = 0; + +# while(my $data = $sth->fetchrow_hashref()) +# { +# #$retdata->{$count} = $data; +# my $row = (); +# foreach my $k (keys %{$data}){ +# $row->{$k} = decode("utf-8",$data->{$k}); +# } +# push @retdata,$row; +# } + +# # my $qstruct = (); +# # my $num_fields = $sth->{NUM_OF_FIELDS}; + +# # for ( my $i=0; $i< $num_fields; $i++ ) { +# # $qstruct->{$i}->{name} = $sth->{NAME}->[$i]; +# # #$qstruct->{$i}->{type} = $sth->{COMMENT}->[$i]; +# # #$qstruct->{$i}->{precision} = $sth->{PRECISION}->[$i]; +# # } + +# $sth->finish(); +# $dbh->disconnect(); + +# return $retdata; +# } + +sub exec(){ + my $self = shift; + my $stat = shift; + my $retdata; + my $dbh = DBI->connect(((exists($self->{dsn}))?$self->{dsn}:$sitecfg->{dsn}),$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return $retdata->{error} = "exec Connection Error!".$!; + # $stat = decode("UTF-8", $stat); + # open FILE,">>tmp/sql.log"; + # print FILE "\n==\n$stat\n==\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return $retdata->{error} = "exec ".$dbh->errstr. "- SQL: ".$stat; + $retdata->{success} = $dbh->do($stat) or return $retdata->{error} = "dbexec ".$dbh->errstr. "- SQL: ".$stat; + $dbh->disconnect(); + return $retdata; +} + +# sub dbqueryarray(){ +# my $self = shift; +# my $stat = shift; +# my @retdata = (); +# my $dbh = DBI->connect(((exists($self->{dsn}))?$self->{dsn}:$sitecfg->{dsn}),$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return ({"error" => "dbqueryarray Connection Error!".$!}); +# #$stat = encode("utf8", $stat); +# #open FILE,">>/tmp/sql.log"; +# #print "$stat\n"; +# # close FILE; +# my $sth = $dbh->prepare($stat); + +# $sth->execute() or print "dbqueryarray: ".$sth->errstr; +# my $count = 0; + +# while(my $data = $sth->fetchrow_hashref()) +# { +# my $row = (); +# foreach my $k (keys %{$data}){ +# $row->{$k} = decode("utf-8",$data->{$k}); +# } +# push @retdata,$row; +# } + +# $sth->finish(); +# $dbh->disconnect(); +# #%retdata = sort {$a <=> $b} keys %retdata; +# return \@retdata; +# } + + +sub create_ddl_insert(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + + foreach my $f (keys(%{$data})){ + if (($f =~ /\_/) && ($f !~ /^ident_/)){ + my $t = substr($f,0,index($f,"_")); + my $c = substr($f,length($t)+1); + #my ($t,$c) = $f =~ m/(.+)\_(.+)/; + $fields->{$t}->{$c} = $data->{$f}; + } elsif ($f =~ /^ident_/){ + my $f2 = $f; + $f2 =~ s/^ident_//; + + my $t = substr($f2,0,index($f2,"_")); + my $c = substr($f2,length($t)+1); + $fields->{$t}->{$c} = $data->{$f}; + } + + } + + foreach my $tb (keys(%{$fields})){ + my @sqlcol = (); + my @sqlval = (); + foreach my $c (keys(%{$fields->{$tb}})){ + my $v = $fields->{$tb}->{$c}; + $v =~ s/'/''/g; + push (@sqlcol,$c); + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlval,$v); + } + push(@ddl,"INSERT INTO ".$tb." (".join(",",@sqlcol).") VALUES (".join(",",@sqlval).") returning id;"); + } + return @ddl; +} + +sub create_ddl_insert_json(){ + my $self = shift; + my $schema = shift; + my $table = shift; + my $columns = shift; + my $data = shift; + my @ddl = (); + my @sqlcol = (); + my @sqlval = (); + foreach my $c (keys(%{$data})){ + #if (exists($columns->{$c})){ + push (@sqlcol,'"'.$c.'"'); + my $v = $data->{$c}; + + if ($v eq ''){ + $v = 'null'; + }elsif ($v =~ /^data:.+;base64,/){ + $v =~ s/'/''/g; + $v = "'".$v."'"; + } + else { + $v= uri_decode($v); + $v =~ s/'/''/g; + if ($columns->{$c}->{data_type} eq "ARRAY"){ + if (ref($data->{$c}) eq "ARRAY"){ + $v = "{\"".join("\",\"",@{$data->{$c}})."\"}"; + } + else { + $v = 'null'; + } + $v =~ s/""/null/g; + }elsif ($columns->{$c}->{data_type} =~ /^timestamp/ ){ + + }elsif($columns->{$c}->{data_type} eq "date"){ + + }elsif($columns->{$c}->{data_type} eq "time"){ + + } + $v = "'".$v."'"; + } + push (@sqlval,$v); + #} + } + return "INSERT INTO ".$schema.".\"".$table."\" (".join(",",@sqlcol).") VALUES (".join(",",@sqlval).");"; +} + +sub create_ddl_update(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + foreach my $f (keys(%{$data})){ + if ($f =~ /^ident_/){ + my $fx = substr($f,6); + my $t = substr($fx,0,index($fx,"_")); + my $c = substr($fx,length($t)+1); + #my ($t,$c) = $f =~ m/^ident_(.+)\_([a-z0-9|\_]+)/; + $fields->{$t}->{cond}->{$c} = $data->{$f}; + } elsif ( ($f !~ /^ident/) && ($f =~ /.+\_.+/) ){ + my $t = substr($f,0,index($f,"_")); + my $c = substr($f,length($t)+1); + #my ($t,$c) = $f =~ m/^(.+)\_([a-z0-9|\_]+)/; + $fields->{$t}->{fields}->{$c} = $data->{$f}; + } + } + foreach my $tb (keys(%{$fields})){ + my @sqlupd = (); + my @sqlcond = (); + foreach my $c (keys(%{$fields->{$tb}->{fields}})){ + + my $v = $fields->{$tb}->{fields}->{$c}; + $v =~ s/'/''/g; + + if ($c =~ /-/){ + my @jp = split('-',$c); + if ($v eq ''){ + $v = 'null'; + } else { + $v = '"'.$v.'"'; + } + $c = 'jsonb_set(to_jsonb('.$jp[0].'),\'{"'.$jp[1].'"}\',\''.$v.'\')::json'; + push (@sqlupd,$jp[0]."=".$c); + }else { + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlupd,$c."=".$v); + } + + } + foreach my $c (keys(%{$fields->{$tb}->{cond}})){ + my $v = $fields->{$tb}->{cond}->{$c}; + $v =~ s/'/''/g; + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlcond,$c."=".$v); + } + push(@ddl,"UPDATE ".$tb." SET ".join(",",@sqlupd)." WHERE ".join(" AND ",@sqlcond).";"); + } + + return @ddl; +} + +sub create_cnt_statement(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + foreach my $f (keys(%{$data})){ + if ($f =~ /^ident_/){ + my $fx = substr($f,6); + my $t = substr($fx,0,index($fx,"_")); + my $c = substr($fx,length($t)+1); + #my ($t,$c) = $f =~ m/^ident_(.+)\_([a-z0-9|\_]+)/; + $fields->{$t}->{cond}->{$c} = $data->{$f}; + } + } + foreach my $tb (keys(%{$fields})){ + my @sqlcond = (); + foreach my $c (keys(%{$fields->{$tb}->{cond}})){ + my $v = $fields->{$tb}->{cond}->{$c}; + $v =~ s/'/''/g; + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlcond,$c."=".$v); + } + push(@ddl,"SELECT count(*) as cnt from ".$tb." WHERE ".join(" AND ",@sqlcond).";"); + } + # open FILE,">>tmp/sql.log"; + # print FILE "\n==\n".join("\n",@ddl)."\n==\n"; + # close FILE; + return @ddl; +} + +sub create_ddl_delete(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + my @refcols = (); + my $refdata = (); + foreach my $f (keys(%{$data})){ + if ($f =~ /^ident_/){ + my ($t,$c) = $f =~ m/ident_(.+)\_(.+)/; + + $fields->{$t}->{cond}->{$c} = $data->{$f}; + push(@refcols,"'".$c.'_'.$t."'"); + $refdata->{$c.'_'.$t} = $data->{$f}; + } + } + +# my $ref = $self->dbquerysorted("select TABLE_NAME,COLUMN_NAME from information_schema.KEY_COLUMN_USAGE where COLUMN_NAME in (".join(",",@refcols).") and CONSTRAINT_SCHEMA='".$self->{dbname}."';"); +# foreach my $r (keys(%{$ref})){ +# my $refv = $refdata->{$ref->{$r}->{COLUMN_NAME}}; +# if ($refv eq ''){ +# $refv = ' is null'; +# } else { +# $refv =~ s/'/''/g; +# $refv = "='".$refv."'"; +# } +# push(@ddl,"DELETE from ".$ref->{$r}->{TABLE_NAME}." where ".$ref->{$r}->{COLUMN_NAME}.$refv.";"); +# } + foreach my $tb (keys(%{$fields})){ + my @sqlcond = (); + foreach my $c (keys(%{$fields->{$tb}->{cond}})){ + my $v = $fields->{$tb}->{cond}->{$c}; + $v =~ s/'/''/g; + push (@sqlcond,$c."='".$v."'"); + } + push(@ddl,"DELETE FROM ".$tb." WHERE ".join(" AND ",@sqlcond).";"); + } + return @ddl; +} + +sub textunidecode(){ + my $self = shift; + my $text = shift; + $text = lc(unidecode(decode("utf-8",$text))); + $text =~ s/^[a-z0-9]//g; + return $text; +} + +1; diff --git a/bin/CGI/api/lib/sendemail.pm b/bin/CGI/api/lib/sendemail.pm new file mode 100644 index 0000000..58ed8fb --- /dev/null +++ b/bin/CGI/api/lib/sendemail.pm @@ -0,0 +1,130 @@ +package sendemail; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +use Data::Dumper; +use File::Basename qw/dirname basename/; +use dksdb; + +sub new { + my $class = shift; + my $self = bless {}, $class; + $self->{server} = "mail.your-server.de"; + $self->{port} = "587"; + $self->{user} = 'kilian.saffran@fld.lu'; + $self->{password} = "Y6cWvXR6D2"; + $self->{from} = 'webmaster@fld.lu'; + return $self; +} + +sub sendemail(){ + my $self = shift; + my $template = shift; + my $iduser = shift; + my $sendto = shift; + my $data = shift; + my $attach = shift; + my $body = ""; + my $subject = ""; + my $maildata = (); + my $db = dksdb->new(); + my $send = -1; + my $tmpl = $db->query("select *,ml.mailtemplate from mailtemplates mt join maillayouts ml on (mt.id_maillayout=ml.id) where templatename='".$template."';"); + if (keys(%{$tmpl}) > 0){ + $tmpl = $tmpl->{0}; + } + # open (LOG,">>tmp/sendmail.log"); + # print LOG $ENV{SCRIPT_FILENAME}; + # print LOG "SEND EMAIL:".Dumper($data)."\n"; + # close(LOG); + my $datasql = $tmpl->{'emaildatasql'}; + $data->{id} = $iduser; + foreach my $key (keys(%{$data})){ + my $srch = '%%'.lc($key).'%%'; + my $repl = $data->{$key}; + $datasql =~ s/$srch/$repl/g; + } + # open (LOG,">>tmp/sendmail.log"); + # print LOG "TEMPLATE DATA:".$datasql."\n"; + # close(LOG); + $maildata = $db->query($datasql); + + $body = $tmpl->{'emailtext'}; + $subject = $tmpl->{'mailsubject'}; + foreach my $key (keys(%{$maildata->{0}})){ + $data->{$key} = $maildata->{0}->{$key}; + } + foreach my $key (keys(%{$data})){ + my $srch = '%%'.lc($key).'%%'; + my $repl = $data->{$key}; + $body =~ s/$srch/$repl/g; + $subject =~ s/$srch/$repl/g; + } + my $bodytmpl = $tmpl->{mailtemplate}; + $bodytmpl =~ s/%%BODYCONTENT%%/$body/; + my $siteurl = $ENV{'REQUEST_SCHEME'}.'://'.$ENV{"HTTP_HOST"}; + $bodytmpl =~ s/%%siteurl%%/$siteurl/g; + $bodytmpl =~ s/%%SITEURL%%/$siteurl/g; + $bodytmpl =~ s/\r//g; + #$bodytmpl =~ s/"/\\\"/g; + #PROD REPLACE all not replaced DATA + #$bodytmpl =~ s/%%\w+%%//g; + #$sendto = 'ksaffran@dks.lu'; + # open (LOG,">>tmp/sendmail.log"); + # print LOG "SUBJECT:".$subject."\n"; + # print LOG "BODY TEXT:".$bodytmpl."\n"; + # close(LOG); + if (($bodytmpl ne "") && ($subject ne "") && ($sendto =~ /.+\@.+\..+/)){ + + + my $binsemail = dirname($ENV{'SCRIPT_FILENAME'}).'/sendEmail'; + my $f = dirname($ENV{SCRIPT_FILENAME}).'/tmp/mailbody_'.$sendto.'.txt'; + $f =~ s/\@/_/g; + if (! -e $binsemail){ + $binsemail = dirname($ENV{'SCRIPT_FILENAME'}).'/api/sendEmail'; + $f = dirname($ENV{SCRIPT_FILENAME}).'/api/tmp/mailbody_'.$sendto.'.txt'; + $f =~ s/\@/_/g; + if (! -e $binsemail){ + return 256; + } + } + + my $cmd= 'perl "'.$binsemail.'" -f '.$tmpl->{mailfrom}.' '; + $cmd .= ' -s "'.$self->{server}.':'.$self->{port}.'" -xu "'.$self->{user}.'" -xp "'.$self->{password}.'" -q '; + $cmd .= '-o tls=auto '; + $cmd .= '-o message-content-type=html '; + $cmd .= '-o message-charset=ISO-8859-1 '; + $cmd .= '-o message-file='.$f.' '; + $cmd .= '-t "'.$sendto.'" '; + $cmd .= '-u "'.$subject.'" '; + # open (LOG,">>sendmail.log"); + # print LOG $cmd."\n"; + # # print LOG "BODY TEXT:".$bodytmpl."\n"; + # close(LOG); + open(EML,">".$f); + print EML $bodytmpl; + close(EML); + # $cmd .= '-m "'.$bodytmpl.'" '; + if ($attach != undef){ + $cmd .= " -a"; + + foreach my $a (@{$attach}){ + $cmd .= " ".$a." "; + } + } + # open (LOG,">>tmp/sendmail.log"); + # print LOG "SEND EMAIL CMD:".$cmd."\n"; + # close(LOG); + # $cmd =~ s/'/''/g; + $send = system($cmd); + # open (LOG,">>tmp/sendmail.log"); + # print LOG "CMD RETURN NUM:".$send."\n"; + # close(LOG); + unlink($f); + } + return $send; +} + +1; \ No newline at end of file diff --git a/bin/CGI/api/lib/session.pm b/bin/CGI/api/lib/session.pm new file mode 100644 index 0000000..44ab6a1 --- /dev/null +++ b/bin/CGI/api/lib/session.pm @@ -0,0 +1,232 @@ +package session; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +use File::Basename; +use Digest::SHA qw(sha256_hex); + +use dksdb; +use sendemail; +# use Data::Dumper; + +sub new { + my $class = shift; + my $self = bless {}, $class; + $self->{db} = dksdb->new(); + return $self; +} + +sub checklogin(){ + my $self = shift; + my $login = shift; + my $password = shift; + # open FILE,">>tmp/sql.log"; + # print FILE "pwd: $password\n"; + # close(FILE); + my $pwd = sha256_hex($password); + my $ret->{messagetype} ='w3-red'; + # my $newsid = undef; + $login = lc($login); + $login =~ s/^\s+//; + $login =~ s/\s+$//; + + $ret->{message} = "Passwuert oder Login onbekannt!"; + $ret->{messagetype} = "w3-red"; + $ret->{sid} = undef; + my $user = $self->{db}->dbquerysorted("select id from users where lower(username)=lower('".$self->{db}->securetext($login)."') and userpassword = '".$pwd."' and \"blocked\" is null;"); + # open FILE,">>tmp/sql.log"; + # print FILE "select id from users where username= '".$self->{db}->securetext($login)."' and userpassword = '".$pwd."' and \"blocked\" is null;\n"; + # close FILE; + if (keys(%{$user}) > 0){ + $ret->{sid} = $self->randomstring(40); + $self->{db}->dbexec("DELETE FROM sessions where id_user=".$user->{0}->{id}." and remote_addr='".$ENV{REMOTE_ADDR}."' and user_agent='".$ENV{HTTP_USER_AGENT}."';"); + my $r = $self->{db}->dbexec("INSERT INTO sessions (id_user,idsession,remote_addr,user_agent) VALUES (".$user->{0}->{id}.", '".$ret->{sid}."', '".$ENV{REMOTE_ADDR}."', '".$ENV{HTTP_USER_AGENT}."');"); + } + return $ret; +} + +sub savepassword(){ + my $self = shift; + my $iduser = shift; + my $newpwd = shift; + my $pwd = sha256_hex($newpwd); + $self->{db}->dbexec("UPDATE users SET userpassword = '".$pwd."' WHERE id=".$iduser.";"); + return 1; +} + +sub passwordforgotten(){ + my $self = shift; + my $email = shift; + my $ret->{messagetype} ='w3-red'; + $ret->{message} = "Onbekannt E-mail!"; + my $sql = "select id,userpassword from users where username='".$self->{db}->securetext($email)."';"; + my $ex = $self->{db}->dbquerysorted($sql); + if (keys(%{$ex}) > 0){ + my $newpwd = $self->randomstring(12); + my $pwd = sha256_hex($newpwd); + $self->{db}->dbexec("UPDATE users SET userpassword = '".$pwd."' WHERE id=".$ex->{0}->{id}.";"); + my $data->{newpassword} = $newpwd; + my $eml = sendemail->new(); + my $mret = $eml->sendemail('user_forgotpasswd',$ex->{0}->{id},$email,$data,undef); + if ($mret != 0){ + $ret->{messagetype} ='w3-red'; + $ret->{message} = "Den Moment ass et leider nët méglech d'Passwuert autmatesch zreckzesetzen,
wend dech w.e.g. via E-Mail un webmaster\@fld.lu!"; + return $ret; + } + $ret->{message} = "Mir hun dir eng E-Mail, matt engem neien Passwuert gescheckt!"; + $ret->{messagetype} = "w3-green"; + } + return $ret; +} + +sub registeruser(){ + my $self = shift; + my $data = shift; + my $ret->{messagetype} ='w3-red'; + $ret->{message} = "Een Fehler ass passéiert, probéier et spéier nach eemol!"; + $ret->{page} = "message.tt"; + if (!exists($data->{license}) || !exists($data->{regcode}) || !exists($data->{email}) || !exists($data->{terms})){ + $ret->{message} = "W.e.g. All Felder ausfëllen!"; + $ret->{page} = "register.tt"; + return $ret; + } + foreach my $d (%{$data}){ + $data->{$d} = $self->{db}->securetext($data->{$d}); + } + + my $user = $self->{db}->dbquerysorted("select id from users where username='".$data->{email}."';"); + if (keys(%{$user}) > 0){ + $ret->{page} = "register.tt"; + $ret->{message} = "Een Benotzer matt der selwechter E-Mail existéiert schon!"; + return $ret; + } + my $license = $self->{db}->dbquerysorted("select us.id as id_user,lic.license,mb.id as id_member,us.username,us.vcode,us.regcode from members mb join licenses lic on (lic.id_member=mb.id) join users us on (mb.id_user=us.id) where us.regcode='".$data->{regcode}."' and lic.license='".$data->{license}."' limit 1"); + if (keys(%{$license}) == 0){ + $ret->{message} = "Falsch Lizenz-Nummer oder falschen Régistréierungs-Code!"; + return $ret; + } + my $regcode = $license->{0}->{regcode}; + my $newcode = $self->randomstring(6); + #my $usergroup = $self->{db}->dbquerysorted("select id from usergroups where usergroup ='avocat';"); + my $newuserid = $self->{db}->dbquerysorted("UPDATE users set username='".$data->{email}."',vcode='".$newcode."' where id=".$license->{0}->{id_user}." ;"); + my $maildata->{vcode} = $newcode; + my $eml = sendemail->new(); + my $mret = $eml->sendemail('user_verification',$license->{0}->{id_user},$data->{email},$maildata,undef); + if ($mret == 0){ + $ret->{message} = "Merci,
Mir hun dir elo eng E-Mail gescheckt, mattengem Code fir deng E-Mail ze verifizéieren!
Gëff desen Code w.e.g. an daat Feld hei drënner an!
Bei Problemer wend dech w.e.g. via E-Mail un webmaster\@fld.lu"; + $ret->{messagetype} = "w3-green"; + $ret->{page} = "validationcode.tt"; + } else { + $self->{db}->dbexec("UPDATE users set username='".$data->{email}."',vcode=null where id=".$license->{0}->{id_user}." ;"); + $ret->{message} = "Aus iergend engem Grond konnten mir dir keng E-Mail un '".$data->{email}."' schecken! Falls dess E-Mail-Address net existéiert, versich et nach eng Kéier matt enger E-Mail-Address, déi existéiert!
Bei Problemer wend dech w.e.g. via E-Mail un webmaster\@fld.lu"; + $ret->{messagetype} = "w3-red"; + $ret->{page} = "register.tt"; + } + #$self->{db}->dbexec("insert into appaccess (id_user) values (".$newuserid->{0}->{id}.");"); + # $ret->{messagetype} = "w3-green"; + + return $ret; +} + +sub validateaccount(){ + my $self = shift; + my $data = shift; + foreach my $d (%{$data}){ + $data->{$d} = $self->{db}->securetext($data->{$d}); + } + + my $ret->{messagetype} ='w3-red'; + my $vcodedata = $self->{db}->dbquerysorted("select id,vcode,username from users where vcode='".$data->{vcode}."';"); + if (keys(%{$vcodedata}) == 0){ + $ret->{message} = "Benotzer onbekannt oder Code falsch!"; + $ret->{page} = "validationcode.tt"; + } + my $newpwd = $self->randomstring(12); + my $pwd = sha256_hex($newpwd); + my $maildata->{password} = $newpwd; + my $eml = sendemail->new(); + my $newuserid = $self->{db}->dbquerysorted("UPDATE users set userpassword='".$pwd."',vcode=null,regcode=null where id=".$vcodedata->{0}->{id}." returning id,username;"); + my $mret = $eml->sendemail('user_registration',$vcodedata->{0}->{id},$vcodedata->{0}->{username},$maildata,undef); + if ($mret == 0){ + $ret->{message} = "Merci,
Mir hun dir elo eng E-Mail gescheckt, matt all deenen néidegen Donnéeen fir dech anzeloggen!
Bei Problemer wend dech w.e.g. via E-Mail un webmaster\@fld.lu"; + $ret->{messagetype} = "w3-green"; + $ret->{page} = "message.tt"; + } else { + $ret->{message} = "Aus iergend engem Grond konnten mir dir keng E-Mail un '".$newuserid->{0}->{username}."' schecken! Falls dess E-Mail-Address net existéiert, versich et nach eng Kéier matt enger E-Mail-Address, déi existéiert!
Bei Problemer wend dech w.e.g. via E-Mail un webmaster\@fld.lu"; + $ret->{page} = "message.tt"; + } + return $ret; +} + +sub getsession($){ + my $self = shift; + my $sid = shift; + my $sql ="select se.idsession,us.id,us.username,string_agg(distinct(aug.usergroup),',') as usergroups from sessions se +join users us on (us.id=se.id_user) +left join useringroups uig on (us.id=uig.id_user) +left join usergroups aug on (aug.id=uig.id_group) +where se.idsession= '".$self->{db}->securetext($sid)."' +and se.remote_addr= '".$ENV{REMOTE_ADDR}."' +and se.user_agent='".$ENV{HTTP_USER_AGENT}."' and us.blocked is null group by se.id,us.id;"; + my $res= $self->{db}->dbquerysorted($sql); + my $ret = undef; + if (keys(%{$res}) > 0){ + return $res->{0}; + } + return $ret; +} + +sub deletesession(){ + my $self = shift; + my $sid = shift; + $self->{db}->dbexec("DELETE FROM sessions where idsession='".$self->{db}->securetext($sid)."';"); +} + +sub randomstring(){ + my $self = shift; + my $num = shift; + my @alphanumeric = ('a'..'z', 'A'..'Z', 0..9); + my $randstring = join '', map $alphanumeric[rand @alphanumeric], 0..$num; + return $randstring; +} + + +# sub deleteprofile(){ +# my $self = shift; +# my $data = shift; +# my $ret->{message} = "mot de passe ou profile inconnue!"; +# $ret->{messagetype} = "danger"; +# if ($data->{id_user} eq ''){ +# $ret->{sid} = undef; +# return $ret; +# } +# my $pwd = sha256_hex($data->{password}); +# my $user = $self->{db}->dbquerysorted("select id from users where id= '".$data->{id_user}."' and userpassword = '".$pwd."';"); +# if (keys(%{$user}) > 0){ +# $self->admindeleteuser($data->{id_user}); +# my $ret->{'message'} = "Votre profile a été supprimé!"; +# $ret->{'messagetype'} = "info"; +# $ret->{sid} = undef; +# } +# return $ret; + +# } + +# sub admindeleteuser(){ +# my $self = shift; +# my $id_user = shift; +# my @dl = ("DELETE FROM public.useringroups WHERE id_uset=".$id_user.";", +# "DELETE FROM public.userclients WHERE id_user=".$id_user.";", +# "DELETE FROM public.appaccess WHERE id_user=".$id_user.";", +# "DELETE FROM public.modulepreferences WHERE id_user=".$id_user.";",, +# "DELETE FROM public.sessions WHERE id_user=".$id_user.";", +# "delete from users where id=".$id_user.";"); +# foreach my $s (@dl){ +# $self->{db}->dbexec($s); +# } +# return 1; +# } + +1; \ No newline at end of file diff --git a/bin/CGI/api/service.cgi b/bin/CGI/api/service.cgi new file mode 100644 index 0000000..1e019e6 --- /dev/null +++ b/bin/CGI/api/service.cgi @@ -0,0 +1,208 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl +use strict; +use FindBin qw($Bin $RealBin); +# use lib ('CGI/api/lib/perl5'); +# use lib ('CGI/api/lib'); +use lib ($Bin.'/CGI/api/lib/perl5'); +use lib ($Bin.'/CGI/api/lib'); +use CGI; +use CGI::Cookie; +# use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use JSON::PP; +use dksconfig qw/$sitecfg/; +use dksdb; +use Digest::SHA::PurePerl qw(sha256_hex); + +# use session; +#use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +my $html->{result} = (); +# $p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +# my $se = session->new(); +# my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8"); + +if (exists($p->{fn})){ + if ($p->{fn} eq "info"){ + $html->{result} = &appinfo($p); + } + if ($$p->{fn} eq "preferences"){ + $html->{result} = &preferences($p); + } + if ($p->{fn} eq "setaccess"){ + $html->{result} = &setWebLogin($p); + } + if ($p->{fn} eq "getaccess"){ + $html->{result} = &getWebLogin($p); + } + if (($p->{fn} eq "stop") || ($p->{fn} eq "unload")){ + exit(0); + } +} +print JSON::PP::encode_json($html); + +sub preferences(){ + + my $req =shift; + my $name = &getAppName(); + my $pref= (); + my $appcfgpath = &getappconfigpath(); + if (exists($req->{page})){ + $appcfgpath =~ s/\\/\//g; + if (-e $appcfgpath.'/'.$req->{page}.'.json'){ + open(PREF,$appcfgpath.'/'.$req->{page}.'.json'); + my $strpref = ""; + while (my $l = ){ + $strpref .= $l; + } + close(PREF); + $pref=JSON::PP::decode_json($strpref); + } + my @kk = keys(%{$p}); + my $setcron = ''; + #print "keys.".Dumper(@kk)."\n"; + if (scalar(@kk) > 0){ + foreach my $px (@kk){ + my $newpref = JSON::PP::decode_json($req->{$px}); + if ($p eq 'sync'){ + $setcron = $p; + } + #if (exists($pref->{result}->{$p})){ + $pref->{$p} = $newpref; + #} + } + open(PREF,">".$appcfgpath.'/'.$req->{page}.'.json'); + print PREF JSON::PP::encode_json($pref); + close(PREF); + + } + if ($setcron ne ''){ + if ($setcron eq 'sync'){ + &setcron(dirname($0).'/syncdb.pl',$pref->{sync}->{time}); + } + } + } + +} + +sub appinfo(){ + my $req = shift; + my $ret = (); + + my $name = basename($0); + $name =~ s/srv\.pl$//; + $name =~ s/srv\.exe$//; + $ret->{OS} = $^O; + $ret->{app} = $name; + $ret->{appcfgpath} = &getappconfigpath(); + if ($^O eq "MSWin32"){ + $ret->{home} = $ENV{USERPROFILE}; + $ret->{user} = $ENV{USERNAME}; + $$ret->{hostname} = $ENV{COMPUTERNAME}; + $ret->{arch} = $ENV{PROCESSOR_ARCHITEW6432}; + $ret->{appcfgpath} =~ s/\\/\//g; + $ret->{home} =~ s/\\/\//g; + } else { + $ret->{home} = $ENV{HOME}; + $ret->{user} = $ENV{USER}; + $ret->{hostname} = `hostname -s`; + chomp($ret->{hostname}); + $ret->{arch} = `uname -m`; + chomp($ret->{arch}); + } + if (! -e $ret->{appcfgpath}){ + make_path($ret->{appcfgpath}); + } + if (-e $ret->{appcfgpath}.'/'.$name.'.json'){ + open(LCFG,$ret->{appcfgpath}.'/'.$name.'.json'); + my $strprofile = ""; + while (my $l = ){ + $strprofile .= $l; + } + close(LCFG); + if ($strprofile ne ""){ + $ret->{appconfig} = JSON::PP::decode_json($strprofile); + } + } + if (!exists($ret->{appconfig})){ + $ret->{appconfig} = undef; + } + return $ret; +} + +sub getWebLogin(){ + + my $req = shift; + my $ret = (); + + my $apppath = &getappconfigpath(); + my $loginname= ""; + #print "read:". $apppath.'/'.&getAppName().'.passwd'."\n"; + if (-e $apppath.'/'.&getAppName().'.passwd'){ + open(AUTH,$apppath.'/'.&getAppName().'.passwd'); + while (my $l = ){ + chomp($l); + if ($l eq ""){ next;} + ($loginname) = $l =~ m/^(\w+)\=.*/; + } + close(AUTH); + } + $ret->{login} = $loginname; + return $ret; +} + +sub setWebLogin(){ + my $req = shift; + my $ret = -1; + my $apppath = &getappconfigpath(); + if (exists($req->{login}) && exists($req->{passwd})){ + open(AUTH,">".$apppath.'/'.&getAppName().'.passwd'); + print AUTH $req->{login}.'='.$req->{passwd}; + close(AUTH); + $ret = 0; + } + return $ret; +} + +sub getappconfigpath(){ + my $datadir = dirname($RealBin).'/data'; + return $datadir; +} + +sub getAppName(){ + my $name = basename($0); + $name =~ s/srv\.pl$//; + $name =~ s/srv\.exe$//; + return lc($name); +} + +sub setcron(){ + my $script =shift; + my $time = shift; + print "setcron\n"; + my $strcron = `crontab -l`; + my @lines = split("\n",$strcron); + my $crontabline = ""; + if ((defined($time) && $time =~ /\d\d:\d\d/)){ + $crontabline = int(substr($time,3,2)).' '.int(substr($time,0,2)).' * * * '.$script; + } + my $newcrontab = ""; + foreach my $l (@lines){ + chomp($l); + if ($l !~ $script){ + $newcrontab .= $l."\n"; + } + } + if ($crontabline ne ""){ + $newcrontab .= $crontabline."\n"; + } + print "\n----\n".$newcrontab."\n----\n"; + system('sudo echo "'.$newcrontab.'" > /var/spool/cron/crontabs/'.$ENV{USER}); +} diff --git a/bin/CGI/api/system.cgi b/bin/CGI/api/system.cgi new file mode 100644 index 0000000..5d0d463 --- /dev/null +++ b/bin/CGI/api/system.cgi @@ -0,0 +1,167 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl +use strict; +use FindBin qw($Bin); +# use lib ('CGI/api/lib/perl5'); +# use lib ('CGI/api/lib'); +use lib ($Bin.'/CGI/api/lib/perl5'); +use lib ($Bin.'/CGI/api/lib'); +use CGI; +use CGI::Cookie; +# use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use JSON::PP; +use dksconfig qw/$sitecfg/; +use dksdb; + +# use session; +#use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +my $html->{result} = undef; +# $p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +# my $se = session->new(); +# my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8"); +if (exists($p->{fn})) { + if ($p->{fn} eq "getconfig"){ + $html->{result} = &getconfig($p); + } elsif ($p->{fn} eq "setconfig") { + $html->{result} = &setconfig($p); + } elsif ($p->{fn} eq "shutdown"){ + print "Shutdown launched!\n"; + system('sudo shutdown -h now'); + $html->{result} = "shutdown launched"; + } elsif ($p->{fn} eq "restart"){ + print "Restart launched!\n"; + system('sudo shutdown -r now'); + $html->{result} = "restart launched"; + } +} +print JSON::PP::encode_json($html); + +sub getconfig(){ + + my $req = shift; + my $ret = (); + my @sections = ('lan','wlan','hostname','activenet'); + if (exists($req->{section})){ + @sections = split(',',$req->{section}); + } + foreach my $s (@sections){ + if ($s eq 'wlan') { + $ret->{$s} = &getwifinetworks(); + } elsif ($s eq 'hostname') { + $ret->{$s} = &gethostname(); + } elsif ($s eq 'activenet'){ + $ret->{$s} = &getactivenet(); + } + } + return $ret; +} + +sub setconfig(){ + my $req = shift; + my $ret = (); + my @sections = ('wlan','hostname'); + if (exists($req->{section})){ + @sections = split(',',$req->{section}); + } + foreach my $k (@sections){ + my $values = JSON::PP::decode_json($req->{$k}); + #print Dumper($values); + if ($k eq 'wlan'){ + $ret->{$k} = &setwifinetwork($values); + } + if ($k eq 'hostname'){ + $ret->{$k} = &sethostname($values); + } + } + return $ret; +} + +#weblogin + +sub getactivenet(){ + my $netconfig = `ip -4 a show`; +my @rows = split("\n",$netconfig); +my $net = (); +my $cnet = ""; +foreach my $r (@rows){ + chomp($r); + if ($r =~ /^\d:/){ + my ($tmp) = $r =~ m/^\d:\s(.+):/; + $cnet = $tmp; + } elsif ($r =~ /^\s+inet\s/){ + my ($ip) = $r =~ m/^\s+inet\s([\d|\.]+)/; + $net->{$cnet} = $ip; + } +} + return $net; +} + +#hostname +sub gethostname(){ + my $hostname = `hostname -s`; + chomp($hostname); + return $hostname; +} + +sub sethostname(){ + my $data = shift; + my $ret = -1; + if (exists($data->{hostname}) && $data->{hostname} ne ""){ + system("sudo hostnamectl set-hostname ".$data->{hostname}); + my $ret = system('sudo sed -i "s/^127.0.1.1.*/127.0.1.1\t'.$data->{hostname}.'/" /etc/hosts'); + } + return $ret; +} + +#wlan +sub getwifinetworks(){ + my $cmd = "sudo wpa_cli -i wlan0 status | grep -e \"^ssid=\" | awk -F \"=\" '\{ print \$2 \}'"; + my $current = `$cmd`; + chomp($current); + my $wifi->{ssid} = undef; + if ($current ne ""){ + $wifi->{ssid} = $current; + } + my $strlist = `sudo iw wlan0 scan | grep SSID | sed \'s/.*SSID: //g\'`; + my @list = split("\n",$strlist); + $wifi->{networks} = \@list; + return $wifi; + +} + +sub setwifinetwork(){ + my $data = shift; + my $strwpa = 'ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev'."\n"; + $strwpa .= 'update_config=1'."\n"; + $strwpa .= 'country=GB'."\n"; + + if (exists($data->{hiddenssid})){ + $strwpa .= "\t".'scan_ssid=1'."\n"; + } + if (exists($data->{passphrase})){ + my $cmd = 'wpa_passphrase "'.$data->{ssid}.'" "'.$data->{passphrase}.'"'; + my $enc = `$cmd`; + #chomp($enc); + $strwpa .= $enc; + } else { + $strwpa .= 'network={'."\n"; + $strwpa .= "\t".'ssid="'.$data->{ssid}."\"\n"; + $strwpa .= "\t".'key_mgmt=NONE'."\n"; + $strwpa .= '}'."\n"; + } + + print $strwpa."\n---\n"; + my $st = system('echo "'.$strwpa.'" > /tmp/wpa_supplicant.conf'); + $st = system('sudo cp /tmp/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf'); + my $cmd = "sudo wpa_cli -i wlan0 reconfigure"; + my $ret = system($cmd); + return 1; +} diff --git a/bin/CGI/api/tools/fingerdelete.py b/bin/CGI/api/tools/fingerdelete.py new file mode 100644 index 0000000..cfcdf29 --- /dev/null +++ b/bin/CGI/api/tools/fingerdelete.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" +import sys +from pyfingerprint2.pyfingerprint import PyFingerprint +if len(sys.argv) == 1: + print ('Error: No position!'); + exit(1) + +## Deletes a finger from sensor +## + + +## Tries to initialize the sensor +try: + f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000) + + if ( f.verifyPassword() == False ): + raise ValueError('The given fingerprint sensor password is wrong!') + +except Exception as e: + print('The fingerprint sensor could not be initialized!') + print('Exception message: ' + str(e)) + exit(1) + +## Gets some sensor information +#print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity())) + +## Tries to delete the template of the finger +try: + positionNumber = int(sys.argv[1]) + + if ( f.deleteTemplate(positionNumber) == True ): + print('Template ' + str(positionNumber) +' deleted!') + +except Exception as e: + print('Operation failed!') + print('Exception message: ' + str(e)) + exit(1) diff --git a/bin/CGI/api/tools/fingerenroll.py b/bin/CGI/api/tools/fingerenroll.py new file mode 100644 index 0000000..8319dc8 --- /dev/null +++ b/bin/CGI/api/tools/fingerenroll.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" + +import time +from pyfingerprint2.pyfingerprint import PyFingerprint + + +## Enrolls new finger +## + +## Tries to initialize the sensor +try: + f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000) + + if ( f.verifyPassword() == False ): + raise ValueError('The given fingerprint sensor password is wrong!') + +except Exception as e: + print('The fingerprint sensor could not be initialized!') + print('Exception message: ' + str(e)) + exit(1) + +## Gets some sensor information +print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity())) + +## Tries to enroll new finger +try: + print('Waiting for finger...') + + ## Wait that finger is read + while ( f.readImage() == False ): + pass + + ## Converts read image to characteristics and stores it in charbuffer 1 + f.convertImage(0x01) + + ## Checks if finger is already enrolled + result = f.searchTemplate() + positionNumber = result[0] + + if ( positionNumber >= 0 ): + print('Template already exists at position #' + str(positionNumber)) + exit(0) + + print('Remove finger...') + time.sleep(2) + + print('Waiting for same finger again...') + + ## Wait that finger is read again + while ( f.readImage() == False ): + pass + + ## Converts read image to characteristics and stores it in charbuffer 2 + f.convertImage(0x02) + + ## Compares the charbuffers + if ( f.compareCharacteristics() == 0 ): + raise Exception('Fingers do not match') + + ## Creates a template + f.createTemplate() + + ## Saves template at new position number + positionNumber = f.storeTemplate() + print('Finger enrolled successfully!') + print('New template position #' + str(positionNumber)) + +except Exception as e: + print('Operation failed!') + print('Exception message: ' + str(e)) + exit(1) diff --git a/bin/CGI/api/tools/fingerledoff.py b/bin/CGI/api/tools/fingerledoff.py new file mode 100644 index 0000000..1eec425 --- /dev/null +++ b/bin/CGI/api/tools/fingerledoff.py @@ -0,0 +1,27 @@ +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" + +import time +from pyfingerprint2.pyfingerprint import PyFingerprint + + +## Enrolls new finger +## + +## Tries to initialize the sensor +try: + f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000) + + if ( f.verifyPassword() == False ): + raise ValueError('The given fingerprint sensor password is wrong!') + +except Exception as e: + print('The fingerprint sensor could not be initialized!') + print('Exception message: ' + str(e)) + exit(1) + +f.setLEDoff() diff --git a/bin/CGI/api/tools/fingerledon.py b/bin/CGI/api/tools/fingerledon.py new file mode 100644 index 0000000..8a08f7f --- /dev/null +++ b/bin/CGI/api/tools/fingerledon.py @@ -0,0 +1,27 @@ +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" + +import time +from pyfingerprint2.pyfingerprint import PyFingerprint + + +## Enrolls new finger +## + +## Tries to initialize the sensor +try: + f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000) + + if ( f.verifyPassword() == False ): + raise ValueError('The given fingerprint sensor password is wrong!') + +except Exception as e: + print('The fingerprint sensor could not be initialized!') + print('Exception message: ' + str(e)) + exit(1) + +f.setLEDon() diff --git a/bin/CGI/api/tools/fingersearch.py b/bin/CGI/api/tools/fingersearch.py new file mode 100644 index 0000000..be98fce --- /dev/null +++ b/bin/CGI/api/tools/fingersearch.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" + +import hashlib +from pyfingerprint2.pyfingerprint import PyFingerprint + + +## Search for a finger +## + +## Tries to initialize the sensor +try: + f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000) + + if ( f.verifyPassword() == False ): + raise ValueError('The given fingerprint sensor password is wrong!') + +except Exception as e: + print('The fingerprint sensor could not be initialized!') + print('Exception message: ' + str(e)) + exit(1) + +## Gets some sensor information +print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity())) + +## Tries to search the finger and calculate hash +try: + print('Waiting for finger...') + + ## Wait that finger is read + while ( f.readImage() == False ): + pass + + ## Converts read image to characteristics and stores it in charbuffer 1 + f.convertImage(0x01) + + ## Searchs template + result = f.searchTemplate() + + positionNumber = result[0] + accuracyScore = result[1] + + if ( positionNumber == -1 ): + print('No match found!') + exit(0) + else: + print('Found template at position #' + str(positionNumber)) + print('The accuracy score is: ' + str(accuracyScore)) + ## Loads the found template to charbuffer 1 + f.loadTemplate(positionNumber, 0x01) + + ## Downloads the characteristics of template loaded in charbuffer 1 + characterics = str(f.downloadCharacteristics(0x01)).encode('utf-8') + + ## Hashes characteristics of template + #print('SHA-2 hash of template: ' + hashlib.sha256(characterics).hexdigest()) + print('POS:' + str(positionNumber) + ';HASH:' + hashlib.sha256(characterics).hexdigest()) + +except Exception as e: + print('Operation failed!') + print('Exception message: ' + str(e)) + exit(1) diff --git a/bin/CGI/api/tools/pyfingerprint2/__init__.py b/bin/CGI/api/tools/pyfingerprint2/__init__.py new file mode 100644 index 0000000..4882220 --- /dev/null +++ b/bin/CGI/api/tools/pyfingerprint2/__init__.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" + +__version__ = '1.5' diff --git a/bin/CGI/api/tools/pyfingerprint2/__init__.pyc b/bin/CGI/api/tools/pyfingerprint2/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04b4849b1dda873d9d9597b684e86ed85be98c6c GIT binary patch literal 305 zcmYLEO-lnY5Y28uZA9=VRP6W>hlro`K3NH_QZxguSl`2TG6Tlrw*@Uf?W&?8NJc(Vxq(5c#^elCB5<_S~ h#_r?vi?LM7d521svBL|RG2I5UYwc`E9Qq^9@;`Y{Q6K;S literal 0 HcmV?d00001 diff --git a/bin/CGI/api/tools/pyfingerprint2/pyfingerprint.py b/bin/CGI/api/tools/pyfingerprint2/pyfingerprint.py new file mode 100644 index 0000000..f5e8d19 --- /dev/null +++ b/bin/CGI/api/tools/pyfingerprint2/pyfingerprint.py @@ -0,0 +1,1358 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +PyFingerprint +Copyright (C) 2015 Bastian Raschke +All rights reserved. + +""" + +import os +import serial +from PIL import Image +import struct + + +## Baotou start byte +FINGERPRINT_STARTCODE = 0xEF01 + +## Packet identification +## + +FINGERPRINT_COMMANDPACKET = 0x01 + +FINGERPRINT_ACKPACKET = 0x07 +FINGERPRINT_DATAPACKET = 0x02 +FINGERPRINT_ENDDATAPACKET = 0x08 + +## Instruction codes +## + +FINGERPRINT_VERIFYPASSWORD = 0x13 +FINGERPRINT_SETPASSWORD = 0x12 +FINGERPRINT_SETADDRESS = 0x15 +FINGERPRINT_SETSYSTEMPARAMETER = 0x0E +FINGERPRINT_GETSYSTEMPARAMETERS = 0x0F +FINGERPRINT_TEMPLATEINDEX = 0x1F +FINGERPRINT_TEMPLATECOUNT = 0x1D + +FINGERPRINT_READIMAGE = 0x01 + +## Note: The documentation mean upload to host computer. +FINGERPRINT_DOWNLOADIMAGE = 0x0A + +FINGERPRINT_CONVERTIMAGE = 0x02 + +FINGERPRINT_CREATETEMPLATE = 0x05 +FINGERPRINT_STORETEMPLATE = 0x06 +FINGERPRINT_SEARCHTEMPLATE = 0x04 +FINGERPRINT_LOADTEMPLATE = 0x07 +FINGERPRINT_DELETETEMPLATE = 0x0C + +FINGERPRINT_CLEARDATABASE = 0x0D +FINGERPRINT_GENERATERANDOMNUMBER = 0x14 +FINGERPRINT_COMPARECHARACTERISTICS = 0x03 + +## Note: The documentation mean download from host computer. +FINGERPRINT_UPLOADCHARACTERISTICS = 0x09 + +## Note: The documentation mean upload to host computer. +FINGERPRINT_DOWNLOADCHARACTERISTICS = 0x08 +## LED +FINGERPRINT_LEDON = 0x50 +FINGERPRINT_LEDOFF = 0x51 +## Packet reply confirmations +## + +FINGERPRINT_OK = 0x00 +FINGERPRINT_ERROR_COMMUNICATION = 0x01 + +FINGERPRINT_ERROR_WRONGPASSWORD = 0x13 + +FINGERPRINT_ERROR_INVALIDREGISTER = 0x1A + +FINGERPRINT_ERROR_NOFINGER = 0x02 +FINGERPRINT_ERROR_READIMAGE = 0x03 + +FINGERPRINT_ERROR_MESSYIMAGE = 0x06 +FINGERPRINT_ERROR_FEWFEATUREPOINTS = 0x07 +FINGERPRINT_ERROR_INVALIDIMAGE = 0x15 + +FINGERPRINT_ERROR_CHARACTERISTICSMISMATCH = 0x0A + +FINGERPRINT_ERROR_INVALIDPOSITION = 0x0B +FINGERPRINT_ERROR_FLASH = 0x18 + +FINGERPRINT_ERROR_NOTEMPLATEFOUND = 0x09 + +FINGERPRINT_ERROR_LOADTEMPLATE = 0x0C + +FINGERPRINT_ERROR_DELETETEMPLATE = 0x10 + +FINGERPRINT_ERROR_CLEARDATABASE = 0x11 + +FINGERPRINT_ERROR_NOTMATCHING = 0x08 + +FINGERPRINT_ERROR_DOWNLOADIMAGE = 0x0F +FINGERPRINT_ERROR_DOWNLOADCHARACTERISTICS = 0x0D + +## Unknown error codes +## + +FINGERPRINT_ADDRCODE = 0x20 +FINGERPRINT_PASSVERIFY = 0x21 + +FINGERPRINT_PACKETRESPONSEFAIL = 0x0E + +FINGERPRINT_ERROR_TIMEOUT = 0xFF +FINGERPRINT_ERROR_BADPACKET = 0xFE + + +class PyFingerprint(object): + """ + A python written library for the ZhianTec ZFM-20 fingerprint sensor. + + @attribute integer(4 bytes) __address + Address to connect to sensor. + + @attribute integer(4 bytes) __password + Password to connect to sensor. + + @attribute Serial __serial + UART serial connection via PySerial. + """ + __address = None + __password = None + __serial = None + + def __init__(self, port = '/dev/ttyUSB0', baudRate = 57600, address = 0xFFFFFFFF, password = 0x00000000): + """ + Constructor + + @param string port + @param integer baudRate + @param integer(4 bytes) address + @param integer(4 bytes) password + """ + + if ( os.path.exists(port) == False ): + raise ValueError('The fingerprint sensor port "' + port + '" was not found!') + + if ( baudRate < 9600 or baudRate > 115200 or baudRate % 9600 != 0 ): + raise ValueError('The given baudrate is invalid!') + + if ( address < 0x00000000 or address > 0xFFFFFFFF ): + raise ValueError('The given address is invalid!') + + if ( password < 0x00000000 or password > 0xFFFFFFFF ): + raise ValueError('The given password is invalid!') + + self.__address = address + self.__password = password + + ## Initialize PySerial connection + self.__serial = serial.Serial(port = port, baudrate = baudRate, bytesize = serial.EIGHTBITS, timeout = 2) + + if ( self.__serial.isOpen() == True ): + self.__serial.close() + + self.__serial.open() + + def __del__(self): + """ + Destructor + + """ + + ## Close connection if still established + if ( self.__serial is not None and self.__serial.isOpen() == True ): + self.__serial.close() + + def __rightShift(self, n, x): + """ + Shift a byte. + + @param integer n + @param integer x + @return integer + """ + + return (n >> x & 0xFF) + + def __leftShift(self, n, x): + """ + Shift a byte. + + @param integer n + @param integer x + @return integer + """ + + return (n << x) + + def __bitAtPosition(self, n, p): + """ + Get the bit of n at position p. + + @param integer n + @param integer p + @return integer + """ + + ## A bitshift 2 ^ p + twoP = 1 << p + + ## Binary AND composition (on both positions must be a 1) + ## This can only happen at position p + result = n & twoP + return int(result > 0) + + def __byteToString(self, byte): + """ + Converts a byte to string. + + @param byte byte + @return string + """ + + return struct.pack('@B', byte) + + def __stringToByte(self, string): + """ + Convert one "string" byte (like '0xFF') to real integer byte (0xFF). + + @param string string + @return byte + """ + + return struct.unpack('@B', string)[0] + + def __writePacket(self, packetType, packetPayload): + """ + Send a packet to fingerprint sensor. + + @param integer(1 byte) packetType + @param tuple packetPayload + + @return void + """ + + ## Write header (one byte at once) + self.__serial.write(self.__byteToString(self.__rightShift(FINGERPRINT_STARTCODE, 8))) + self.__serial.write(self.__byteToString(self.__rightShift(FINGERPRINT_STARTCODE, 0))) + + self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 24))) + self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 16))) + self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 8))) + self.__serial.write(self.__byteToString(self.__rightShift(self.__address, 0))) + + self.__serial.write(self.__byteToString(packetType)) + + ## The packet length = package payload (n bytes) + checksum (2 bytes) + packetLength = len(packetPayload) + 2 + + self.__serial.write(self.__byteToString(self.__rightShift(packetLength, 8))) + self.__serial.write(self.__byteToString(self.__rightShift(packetLength, 0))) + + ## The packet checksum = packet type (1 byte) + packet length (2 bytes) + payload (n bytes) + packetChecksum = packetType + self.__rightShift(packetLength, 8) + self.__rightShift(packetLength, 0) + + ## Write payload + for i in range(0, len(packetPayload)): + self.__serial.write(self.__byteToString(packetPayload[i])) + packetChecksum += packetPayload[i] + + ## Write checksum (2 bytes) + self.__serial.write(self.__byteToString(self.__rightShift(packetChecksum, 8))) + self.__serial.write(self.__byteToString(self.__rightShift(packetChecksum, 0))) + + def __readPacket(self): + """ + Receive a packet from fingerprint sensor. + + Return a tuple that contain the following information: + 0: integer(1 byte) The packet type. + 1: integer(n bytes) The packet payload. + + @return tuple + """ + + receivedPacketData = [] + i = 0 + + while ( True ): + + ## Read one byte + receivedFragment = self.__serial.read() + + if ( len(receivedFragment) != 0 ): + receivedFragment = self.__stringToByte(receivedFragment) + ## print 'Received packet fragment = ' + hex(receivedFragment) + + ## Insert byte if packet seems valid + receivedPacketData.insert(i, receivedFragment) + i += 1 + + ## Packet could be complete (the minimal packet size is 12 bytes) + if ( i >= 12 ): + + ## Check the packet header + if ( receivedPacketData[0] != self.__rightShift(FINGERPRINT_STARTCODE, 8) or receivedPacketData[1] != self.__rightShift(FINGERPRINT_STARTCODE, 0) ): + raise Exception('The received packet do not begin with a valid header!') + + ## Calculate packet payload length (combine the 2 length bytes) + packetPayloadLength = self.__leftShift(receivedPacketData[7], 8) + packetPayloadLength = packetPayloadLength | self.__leftShift(receivedPacketData[8], 0) + + ## Check if the packet is still fully received + ## Condition: index counter < packet payload length + packet frame + if ( i < packetPayloadLength + 9 ): + continue + + ## At this point the packet should be fully received + + packetType = receivedPacketData[6] + + ## Calculate checksum: + ## checksum = packet type (1 byte) + packet length (2 bytes) + packet payload (n bytes) + packetChecksum = packetType + receivedPacketData[7] + receivedPacketData[8] + + packetPayload = [] + + ## Collect package payload (ignore the last 2 checksum bytes) + for j in range(9, 9 + packetPayloadLength - 2): + packetPayload.append(receivedPacketData[j]) + packetChecksum += receivedPacketData[j] + + ## Calculate full checksum of the 2 separate checksum bytes + receivedChecksum = self.__leftShift(receivedPacketData[i - 2], 8) + receivedChecksum = receivedChecksum | self.__leftShift(receivedPacketData[i - 1], 0) + + if ( receivedChecksum != packetChecksum ): + raise Exception('The received packet is corrupted (the checksum is wrong)!') + + return (packetType, packetPayload) + + def verifyPassword(self): + """ + Verify password of the fingerprint sensor. + + @return boolean + """ + + packetPayload = ( + FINGERPRINT_VERIFYPASSWORD, + self.__rightShift(self.__password, 24), + self.__rightShift(self.__password, 16), + self.__rightShift(self.__password, 8), + self.__rightShift(self.__password, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Sensor password is correct + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ADDRCODE ): + raise Exception('The address is wrong') + + ## DEBUG: Sensor password is wrong + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_WRONGPASSWORD ): + return False + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def setPassword(self, newPassword): + """ + Set the password of the sensor. + + @param integer(4 bytes) newPassword + @return boolean + """ + + ## Validate the password (maximum 4 bytes) + if ( newPassword < 0x00000000 or newPassword > 0xFFFFFFFF ): + raise ValueError('The given password is invalid!') + + packetPayload = ( + FINGERPRINT_SETPASSWORD, + self.__rightShift(newPassword, 24), + self.__rightShift(newPassword, 16), + self.__rightShift(newPassword, 8), + self.__rightShift(newPassword, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Password set was successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + self.__password = newPassword + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def setAddress(self, newAddress): + """ + Set the module address of the sensor. + + @param integer(4 bytes) newAddress + @return boolean + """ + + ## Validate the address (maximum 4 bytes) + if ( newAddress < 0x00000000 or newAddress > 0xFFFFFFFF ): + raise ValueError('The given address is invalid!') + + packetPayload = ( + FINGERPRINT_SETADDRESS, + self.__rightShift(newAddress, 24), + self.__rightShift(newAddress, 16), + self.__rightShift(newAddress, 8), + self.__rightShift(newAddress, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Address set was successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + self.__address = newAddress + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def setSystemParameter(self, parameterNumber, parameterValue): + """ + Set a system parameter of the sensor. + + @param integer(1 byte) parameterNumber + @param integer(1 byte) parameterValue + @return boolean + """ + + ## Validate the baudrate parameter + if ( parameterNumber == 4 ): + + if ( parameterValue < 1 or parameterValue > 12 ): + raise ValueError('The given baudrate parameter is invalid!') + + ## Validate the security level parameter + elif ( parameterNumber == 5 ): + + if ( parameterValue < 1 or parameterValue > 5 ): + raise ValueError('The given security level parameter is invalid!') + + ## Validate the package length parameter + elif ( parameterNumber == 6 ): + + if ( parameterValue < 0 or parameterValue > 3 ): + raise ValueError('The given package length parameter is invalid!') + + ## The parameter number is not valid + else: + raise ValueError('The given parameter number is invalid!') + + packetPayload = ( + FINGERPRINT_SETSYSTEMPARAMETER, + parameterNumber, + parameterValue, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Parameter set was successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDREGISTER ): + raise Exception('Invalid register number') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + + def getSystemParameters(self): + """ + Get all available system information of the sensor. + + Return a tuple that contain the following information: + 0: integer(2 bytes) The status register. + 1: integer(2 bytes) The system id. + 2: integer(2 bytes) The storage capacity. + 3: integer(2 bytes) The security level. + 4: integer(4 bytes) The sensor address. + 5: integer(2 bytes) The packet length. + 6: integer(2 bytes) The baudrate. + + @return tuple + """ + + packetPayload = ( + FINGERPRINT_GETSYSTEMPARAMETERS, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Read successfully + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + + statusRegister = self.__leftShift(receivedPacketPayload[1], 8) | self.__leftShift(receivedPacketPayload[2], 0) + systemID = self.__leftShift(receivedPacketPayload[3], 8) | self.__leftShift(receivedPacketPayload[4], 0) + storageCapacity = self.__leftShift(receivedPacketPayload[5], 8) | self.__leftShift(receivedPacketPayload[6], 0) + securityLevel = self.__leftShift(receivedPacketPayload[7], 8) | self.__leftShift(receivedPacketPayload[8], 0) + deviceAddress = ((receivedPacketPayload[9] << 8 | receivedPacketPayload[10]) << 8 | receivedPacketPayload[11]) << 8 | receivedPacketPayload[12] ## TODO + packetLength = self.__leftShift(receivedPacketPayload[13], 8) | self.__leftShift(receivedPacketPayload[14], 0) + baudRate = self.__leftShift(receivedPacketPayload[15], 8) | self.__leftShift(receivedPacketPayload[16], 0) + + return (statusRegister, systemID, storageCapacity, securityLevel, deviceAddress, packetLength, baudRate) + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def getTemplateIndex(self, page): + """ + Get a list of the template positions with usage indicator. + + @param integer(1 byte) page + @return list + """ + + if ( page < 0 or page > 3 ): + raise ValueError('The given index page is invalid!') + + packetPayload = ( + FINGERPRINT_TEMPLATEINDEX, + page, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Read index table successfully + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + + templateIndex = [] + + ## Contain the table page bytes (skip the first status byte) + pageElements = receivedPacketPayload[1:] + + for pageElement in pageElements: + ## Test every bit (bit = template position is used indicator) of a table page element + for p in range(0, 7 + 1): + positionIsUsed = (self.__bitAtPosition(pageElement, p) == 1) + templateIndex.append(positionIsUsed) + + return templateIndex + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def getTemplateCount(self): + """ + Get the number of stored templates. + + @return integer(2 bytes) + """ + + packetPayload = ( + FINGERPRINT_TEMPLATECOUNT, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Read successfully + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + templateCount = self.__leftShift(receivedPacketPayload[1], 8) + templateCount = templateCount | self.__leftShift(receivedPacketPayload[2], 0) + return templateCount + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def readImage(self): + """ + Read the image of a finger and stores it in ImageBuffer. + + @return boolean + """ + + packetPayload = ( + FINGERPRINT_READIMAGE, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Image read successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + ## DEBUG: No finger found + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOFINGER ): + return False + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_READIMAGE ): + raise Exception('Could not read image') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + ## TODO: + ## Implementation of uploadImage() + def setLEDoff(self): + packetPayload = ( + FINGERPRINT_LEDOFF, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + + ## Get first reply packet + receivedPacket = self.__readPacket() + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + def setLEDon(self): + packetPayload = ( + FINGERPRINT_LEDON, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + + ## Get first reply packet + receivedPacket = self.__readPacket() + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + def downloadImage(self, imageDestination): + """ + Download the image of a finger to host computer. + + @param string imageDestination + @return void + """ + + destinationDirectory = os.path.dirname(imageDestination) + + if ( os.access(destinationDirectory, os.W_OK) == False ): + raise ValueError('The given destination directory "' + destinationDirectory + '" is not writable!') + + packetPayload = ( + FINGERPRINT_DOWNLOADIMAGE, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + + ## Get first reply packet + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: The sensor will sent follow-up packets + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + pass + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DOWNLOADIMAGE ): + raise Exception('Could not download image') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + ## Initialize image library + resultImage = Image.new('L', (256, 288), 'white') + pixels = resultImage.load() + + ## Y coordinate of current pixel + line = 0 + + ## Get follow-up data packets until the last data packet is received + while ( receivedPacketType != FINGERPRINT_ENDDATAPACKET ): + + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_DATAPACKET and receivedPacketType != FINGERPRINT_ENDDATAPACKET ): + raise Exception('The received packet is no data packet!') + + ## X coordinate of current pixel + x = 0 + + for i in range(0, len(receivedPacketPayload)): + + ## Thanks to Danylo Esterman for the "multiple with 17" improvement: + + ## Draw left 4 Bits one byte of package + pixels[x, line] = (receivedPacketPayload[i] >> 4) * 17 + x = x + 1 + + ## Draw right 4 Bits one byte of package + pixels[x, line] = (receivedPacketPayload[i] & 0b00001111) * 17 + x = x + 1 + + line = line + 1 + + resultImage.save(imageDestination) + + def convertImage(self, charBufferNumber = 0x01): + """ + Convert the image in ImageBuffer to finger characteristics and store in CharBuffer1 or CharBuffer2. + + @param integer(1 byte) charBufferNumber + @return boolean + """ + + if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ): + raise ValueError('The given charbuffer number is invalid!') + + packetPayload = ( + FINGERPRINT_CONVERTIMAGE, + charBufferNumber, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Image converted + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_MESSYIMAGE ): + raise Exception('The image is too messy') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_FEWFEATUREPOINTS ): + raise Exception('The image contains too few feature points') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDIMAGE ): + raise Exception('The image is invalid') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def createTemplate(self): + """ + Combine the characteristics which are stored in CharBuffer1 and CharBuffer2 to a template. + The created template will be stored again in CharBuffer1 and CharBuffer2 as the same. + + @return boolean + """ + + packetPayload = ( + FINGERPRINT_CREATETEMPLATE, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Template created successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + ## DEBUG: The characteristics not matching + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_CHARACTERISTICSMISMATCH ): + return False + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def storeTemplate(self, positionNumber = -1, charBufferNumber = 0x01): + """ + Save a template from the specified CharBuffer to the given position number. + + @param integer(2 bytes) positionNumber + @param integer(1 byte) charBufferNumber + @return integer + """ + + ## Find a free index + if ( positionNumber == -1 ): + for page in range(0, 4): + ## Free index found? + if ( positionNumber >= 0 ): + break + + templateIndex = self.getTemplateIndex(page) + + for i in range(0, len(templateIndex)): + ## Index not used? + if ( templateIndex[i] == False ): + positionNumber = (len(templateIndex) * page) + i + break + + if ( positionNumber < 0x0000 or positionNumber >= self.getStorageCapacity() ): + raise ValueError('The given position number is invalid!') + + if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ): + raise ValueError('The given charbuffer number is invalid!') + + packetPayload = ( + FINGERPRINT_STORETEMPLATE, + charBufferNumber, + self.__rightShift(positionNumber, 8), + self.__rightShift(positionNumber, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Template stored successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return positionNumber + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ): + raise Exception('Could not store template in that position') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_FLASH ): + raise Exception('Error writing to flash') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def searchTemplate(self): + """ + Search the finger characteristics in CharBuffer in database. + + Return a tuple that contain the following information: + 0: integer(2 bytes) The position number of found template. + 1: integer(2 bytes) The accuracy score of found template. + + @return tuple + """ + + ## CharBuffer1 and CharBuffer2 are the same in this case + charBufferNumber = 0x01 + + ## Begin search at index 0 + positionStart = 0x0000 + templatesCount = self.getStorageCapacity() + + packetPayload = ( + FINGERPRINT_SEARCHTEMPLATE, + charBufferNumber, + self.__rightShift(positionStart, 8), + self.__rightShift(positionStart, 0), + self.__rightShift(templatesCount, 8), + self.__rightShift(templatesCount, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Found template + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + + positionNumber = self.__leftShift(receivedPacketPayload[1], 8) + positionNumber = positionNumber | self.__leftShift(receivedPacketPayload[2], 0) + + accuracyScore = self.__leftShift(receivedPacketPayload[3], 8) + accuracyScore = accuracyScore | self.__leftShift(receivedPacketPayload[4], 0) + + return (positionNumber, accuracyScore) + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + ## DEBUG: Did not found a matching template + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOTEMPLATEFOUND ): + return (-1, -1) + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def loadTemplate(self, positionNumber, charBufferNumber = 0x01): + """ + Load an existing template specified by position number to specified CharBuffer. + + @param integer(2 bytes) positionNumber + @param integer(1 byte) charBufferNumber + @return boolean + """ + + if ( positionNumber < 0x0000 or positionNumber >= self.getStorageCapacity() ): + raise ValueError('The given position number is invalid!') + + if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ): + raise ValueError('The given charbuffer number is invalid!') + + packetPayload = ( + FINGERPRINT_LOADTEMPLATE, + charBufferNumber, + self.__rightShift(positionNumber, 8), + self.__rightShift(positionNumber, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Template loaded successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_LOADTEMPLATE ): + raise Exception('The template could not be read') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ): + raise Exception('Could not load template from that position') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def deleteTemplate(self, positionNumber, count = 1): + """ + Delete templates from fingerprint database. Per default one. + + @param integer(2 bytes) positionNumber + @param integer(2 bytes) count + @return boolean + """ + + capacity = self.getStorageCapacity() + + if ( positionNumber < 0x0000 or positionNumber >= capacity ): + raise ValueError('The given position number is invalid!') + + if ( count < 0x0000 or count > capacity - positionNumber ): + raise ValueError('The given count is invalid!') + + packetPayload = ( + FINGERPRINT_DELETETEMPLATE, + self.__rightShift(positionNumber, 8), + self.__rightShift(positionNumber, 0), + self.__rightShift(count, 8), + self.__rightShift(count, 0), + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Template deleted successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_INVALIDPOSITION ): + raise Exception('Invalid position') + + ## DEBUG: Could not delete template + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DELETETEMPLATE ): + return False + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def clearDatabase(self): + """ + Clear the complete template database. + + @return boolean + """ + + packetPayload = ( + FINGERPRINT_CLEARDATABASE, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Database cleared successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + return True + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + ## DEBUG: Could not clear database + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_CLEARDATABASE ): + return False + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def compareCharacteristics(self): + """ + Compare the finger characteristics of CharBuffer1 with CharBuffer2 and return the accuracy score. + + @return integer(2 bytes) + """ + + packetPayload = ( + FINGERPRINT_COMPARECHARACTERISTICS, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: Comparison successful + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + accuracyScore = self.__leftShift(receivedPacketPayload[1], 8) + accuracyScore = accuracyScore | self.__leftShift(receivedPacketPayload[2], 0) + return accuracyScore + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + ## DEBUG: The characteristics do not matching + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_NOTMATCHING ): + return 0 + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + def uploadCharacteristics(self, charBufferNumber = 0x01, characteristicsData = [0]): + """ + Upload finger characteristics to CharBuffer1 or CharBuffer2. + + @author: David Gilson + + @param integer(1 byte) charBufferNumber + @param integer(list) characteristicsData + + @return boolean + Return true if everything is right. + """ + + if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ): + raise ValueError('The given charbuffer number is invalid!') + + if ( characteristicsData == [0] ): + raise ValueError('The characteristics data is required!') + + maxPacketSize = self.getMaxPacketSize() + + ## Upload command + + packetPayload = ( + FINGERPRINT_UPLOADCHARACTERISTICS, + charBufferNumber + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + + ## Get first reply packet + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: The sensor will sent follow-up packets + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + pass + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_PACKETRESPONSEFAIL ): + raise Exception('Could not upload characteristics') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + ## Upload data packets + packetNbr = len(characteristicsData) / maxPacketSize + + if ( packetNbr <= 1 ): + self.__writePacket(FINGERPRINT_ENDDATAPACKET, characteristicsData) + else: + i = 1 + while ( i < packetNbr ): + lfrom = (i-1) * maxPacketSize + lto = lfrom + maxPacketSize + self.__writePacket(FINGERPRINT_DATAPACKET, characteristicsData[lfrom:lto]) + i += 1 + + lfrom = (i-1) * maxPacketSize + lto = lfrom + maxPacketSize + self.__writePacket(FINGERPRINT_ENDDATAPACKET, characteristicsData[lfrom:lto]) + + ## Verify uploaded characteristics + characterics = self.downloadCharacteristics(charBufferNumber) + return (characterics == characteristicsData) + + def getMaxPacketSize(self): + """ + Get the maximum allowed size of packet by sensor. + + @author: David Gilson + + @return int + Return the max size. Default 32 bytes. + """ + + packetMaxSizeType = self.getSystemParameters()[5] + + if (packetMaxSizeType == 1): + return 64 + elif (packetMaxSizeType == 2): + return 128 + elif (packetMaxSizeType == 3): + return 256 + else: + return 32 + + def getStorageCapacity(self): + """ + Get the sensor storage capacity. + + @return int + The storage capacity. + """ + + return self.getSystemParameters()[2] + + def generateRandomNumber(self): + """ + Generate a random 32-bit decimal number. + + @author: Philipp Meisberger + + @return int + The generated random number + """ + packetPayload = ( + FINGERPRINT_GENERATERANDOMNUMBER, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + pass + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + number = 0 + number = number | self.__leftShift(receivedPacketPayload[1], 24) + number = number | self.__leftShift(receivedPacketPayload[2], 16) + number = number | self.__leftShift(receivedPacketPayload[3], 8) + number = number | self.__leftShift(receivedPacketPayload[4], 0) + return number + + def downloadCharacteristics(self, charBufferNumber = 0x01): + """ + Download the finger characteristics of CharBuffer1 or CharBuffer2. + + @param integer(1 byte) charBufferNumber + + @return list + Return a list that contains 512 integer(1 byte) elements of the characteristic. + """ + + if ( charBufferNumber != 0x01 and charBufferNumber != 0x02 ): + raise ValueError('The given charbuffer number is invalid!') + + packetPayload = ( + FINGERPRINT_DOWNLOADCHARACTERISTICS, + charBufferNumber, + ) + + self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload) + + ## Get first reply packet + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_ACKPACKET ): + raise Exception('The received packet is no ack packet!') + + ## DEBUG: The sensor will sent follow-up packets + if ( receivedPacketPayload[0] == FINGERPRINT_OK ): + pass + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_COMMUNICATION ): + raise Exception('Communication error') + + elif ( receivedPacketPayload[0] == FINGERPRINT_ERROR_DOWNLOADCHARACTERISTICS ): + raise Exception('Could not download characteristics') + + else: + raise Exception('Unknown error '+ hex(receivedPacketPayload[0])) + + completePayload = [] + + ## Get follow-up data packets until the last data packet is received + while ( receivedPacketType != FINGERPRINT_ENDDATAPACKET ): + + receivedPacket = self.__readPacket() + + receivedPacketType = receivedPacket[0] + receivedPacketPayload = receivedPacket[1] + + if ( receivedPacketType != FINGERPRINT_DATAPACKET and receivedPacketType != FINGERPRINT_ENDDATAPACKET ): + raise Exception('The received packet is no data packet!') + + for i in range(0, len(receivedPacketPayload)): + completePayload.append(receivedPacketPayload[i]) + + return completePayload diff --git a/bin/CGI/api/tools/pyfingerprint2/pyfingerprint.pyc b/bin/CGI/api/tools/pyfingerprint2/pyfingerprint.pyc new file mode 100644 index 0000000000000000000000000000000000000000..081a9062f99d901a8bfc05a54efc87b11b381d65 GIT binary patch literal 31322 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 V`tXgptf{q=YrU)A*rHzL{|}mqadiLy literal 0 HcmV?d00001 diff --git a/bin/CGI/index.cgi b/bin/CGI/index.cgi new file mode 100644 index 0000000..542d7bf --- /dev/null +++ b/bin/CGI/index.cgi @@ -0,0 +1,199 @@ +#!C:\Strawberry\perl\bin\perl.exe + +use strict; +use FindBin qw($Bin); +# use lib ('CGI/api/lib/perl5'); +# use lib ('CGI/api/lib'); +use lib ($Bin.'/CGI/api/lib/perl5'); +use lib ($Bin.'/CGI/api/lib'); +# use lib ('./api/lib/perl5'); +# use lib ('./api/lib'); +use File::Basename qw/dirname basename/; +use Template; +# use Template::Constants qw( :debug ); +use CGI; +#use CGI::Carp qw(fatalsToBrowser); +use CGI::Cookie; +use Data::Dumper; +use JSON::PP; + +use dksconfig qw/$sitecfg/; +# use session; + +my $skl = "skeleton/index.tt"; +my $cgi = new CGI(); +my $p=(); +my $cookie; +my $vars = $sitecfg; + +#$vars->{filepath} = substr($cgi->url({-absolute=>1}),length($vars->{basepath})+1); +$vars->{filepath} = substr($ENV{PATH_INFO},1); +$vars->{baseurl} = $cgi->url({-base=>1}).$vars->{basepath}; + +if ($vars->{basepath} eq "/"){ + $vars->{siteurl} = $cgi->url({-base=>1}); +}else { + $vars->{siteurl} = $cgi->url({-base=>1}).dirname($vars->{basepath}); + $vars->{docroot} = $vars->{docroot}.dirname($vars->{basepath}); + #$vars->{sitepath} = dirname($vars->{basepath}); +} + + +if ($vars->{filepath} ne ""){ + $vars->{suffix} = substr($vars->{filepath},rindex($vars->{filepath},'.')); + $vars->{page} = $vars->{filepath}; + $vars->{page} =~ s/html$/tt/; +} +$vars->{abspath} = ""; + +# my $sess = (); +# my $se = session->new(); +# $p->{sid} = $cgi->cookie($vars->{cookiename}); +if ($cgi->request_method() eq "GET"){ + my @params = $cgi->param(); + foreach my $pp (@params){ + $p->{$pp} = $cgi->param($pp); + } + +} + +# if ($cgi->request_method() eq "POST"){ + +# my @params = $cgi->param(); +# foreach my $pp (@params){ +# $p->{$pp} = $cgi->param($pp); +# } +# # $vars->{hasposts} = $p; +# # if (exists($p->{'btnlogin'})){ +# # my $ret = $se->checklogin($p->{login},$p->{password}); +# # if ($ret->{sid} ne ""){ +# # $p->{sid} = $ret->{sid}; +# # $cookie = CGI::Cookie->new(-name=>$vars->{cookiename},-value=>$p->{sid},-httponly => 1); +# # }else { +# # $vars->{message} = $ret->{message}; +# # $vars->{messagetype} = $ret->{messagetype}; +# # $vars->{page} = "message.tt"; +# # } +# # } +# # if (exists($p->{'btnregister'})){ + +# # my $ret = $se->registeruser($p); + +# # $vars->{message} = $ret->{message}; +# # $vars->{messagetype} = $ret->{messagetype}; +# # $vars->{page} = $ret->{page}; +# # } +# # if (exists($p->{'btnforgotpassword'})){ +# # my $ret = $se->passwordforgotten($p->{email}); +# # $vars->{message} = $ret->{message}; +# # $vars->{messagetype} = $ret->{messagetype}; +# # $vars->{page} = "message.tt"; +# # } +# # if (exists($p->{'btnvalidateemail'})){ +# # my $ret = $se->validateaccount($p); +# # $vars->{message} = $ret->{message}; +# # $vars->{messagetype} = $ret->{messagetype}; +# # $vars->{page} = "message.tt"; +# # } +# # if (exists($p->{'btnresendcode'})){ +# # my $ret = $se->resendcode($p->{email}); +# # $vars->{message} = $ret->{message}; +# # $vars->{messagetype} = $ret->{messagetype}; +# # $vars->{page} = "message.tt"; +# # } + +# # if (exists($p->{logout})){ +# # $se->deletesession($p->{sid}); +# # $p->{sid} = ""; +# # $cookie = CGI::Cookie->new(-name=>$vars->{cookiename},-value=>"",-httponly => 1); +# # } +# # if (exists($p->{btndeleteprofile})){ +# # my $ret = $se->deleteprofile($p->{deleteprofile}); +# # $vars->{message} = $ret->{message}; +# # $vars->{messagetype} = $ret->{messagetype}; +# # $vars->{page} = "message.tt"; +# # if (exists($ret->{sid})){ +# # $p->{sid} = ""; +# # } +# # $cookie = CGI::Cookie->new(-name=>$vars->{cookiename},-value=>"",-httponly => 1); +# # } +# } + +# # if ($p->{sid} ne ""){ +# # $sess = $se->getsession($p->{sid}); +# # } + + +# #$vars->{beforex} = $vars->{page}; +# if (!exists($sess->{id}) || (!exists($p->{sid})) || $p->{sid} eq ""){ +# $skl = "skeleton/index.tt"; +# } +# # if ($vars->{page} eq "deleteprofile.tt") { +# # $skl = "skeleton/login.tt"; +# # } +# # my ($appname) = $ENV{REQUEST_URI} =~ /.*\/module\/(\w+)\/.*/; +# if ($p->{sid} ne ""){ +# $vars->{session} = $sess; +# } +# #SESSION - End +# # #BEGIN - Browser Blocking +# # if (($ENV{HTTP_USER_AGENT} !~ /Chrome/) || ($ENV{HTTP_USER_AGENT} =~ /Edge/) || ($ENV{HTTP_USER_AGENT} =~ /Firefox/)){ +# # $skl = "skeleton/browser.tt"; +# # } +# # #END - Browser Blocking +my $ctype = 'text/html'; +if ($vars->{suffix} eq ".js"){ + $ctype= "text/javascript"; +} elsif ($vars->{suffix} eq ".css"){ + $ctype = "text/css"; +} +#print $cgi->header(-type=>$ctype, -charset=>"utf-8",-cookie => $cookie); +print $cgi->header(-type=>$ctype, -charset=>"utf-8"); + +# print dirname($ENV{"SCRIPT_FILENAME"}); + +my $template = Template->new({INCLUDE_PATH => [$Bin.'/CGI/tmpl']}); +#} + +my @lv = split(/\//,$vars->{filepath}); +my $absnum = scalar(@lv)-1; + +for (my $i=0;$i<$absnum;$i++){ + $vars->{abspath} .= "../"; +} +if ($vars->{page} =~ /^app/){ + my @spl = split("/",$vars->{page}); + $vars->{app} = $spl[1]; +} +# $vars->{page} = $vars->{page}; +if ($vars->{page} =~ /module/){ + $vars->{module} = basename(dirname($vars->{page})); +} +$vars->{pagename} = basename($vars->{page}); +$vars->{pagename} =~ s/\.tt$//; +# my ($appname) = $ENV{REQUEST_URI} =~ /.*\/apps\/(\w+)\/.*/; +#$vars->{requri} = $ENV{REQUEST_URI}; + +#BEGIN - iFrame - Modules +#$skl ne "skeleton/login.tt" && +if ($vars->{page} =~ /module/){ + $skl = "skeleton/module.tt"; + if ($vars->{page} !~ /\.tt$/) { + $skl = "skeleton/file.tt"; + } + $vars->{params}= $p; +}elsif ($vars->{page} =~ /^app/){ + $skl = "skeleton/app.tt"; + if ($vars->{page} !~ /\.tt$/) { + $skl = "skeleton/file.tt"; + } + $vars->{params}= $p; +} + +#END - iFrame - Modules + +$template->process($skl,$vars) || die "Template process failed: ", $template->error(), "\n"; +#print '/*
'.Dumper($vars)."
*/";
+
+
+
diff --git a/bin/CGI/tmpl/app/hourtrax/index.tt b/bin/CGI/tmpl/app/hourtrax/index.tt
new file mode 100644
index 0000000..5cba12e
--- /dev/null
+++ b/bin/CGI/tmpl/app/hourtrax/index.tt
@@ -0,0 +1,59 @@
+[% USE date %]
+[% vstamp=date.format(date.now, '%d%m%Y%H%M%S') %]
+
+
+
+
+
+
+  
+  
+
+Invoice Journal
+
+
+
+
+
+
+
+ +
+
+ +
+ + +
+ +
+ + +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/bin/CGI/tmpl/app/hourtrax/module/members/index.js b/bin/CGI/tmpl/app/hourtrax/module/members/index.js new file mode 100644 index 0000000..d474d6a --- /dev/null +++ b/bin/CGI/tmpl/app/hourtrax/module/members/index.js @@ -0,0 +1,97 @@ +var tbl=null; + + +function initpage(){ + //console.log(mpref.cfg); + //console.log("APP:" + parent.app); + flatpickr(".timefield",{altInput: true, + altFormat: "H:i", + allowInput: true, + enableTime: true, + noCalendar: true, + dateFormat: "H:i", + time_24hr: true, + "locale": "fr", + }); + flatpickr(".datefield",{altInput: true, + altFormat: "d.m.Y", + dateFormat: "Y-m-d", + allowInput: true, + "locale": "fr", + }); + tbl = new Tabulator("#tbl_staff", { + headerFilterPlaceholder:"filtre...", + height: "95vh", + layout:"fitColumns", + selectable:1, + locale:"fr", + columns: [ + {title:"Nom", field:"surname",headerFilter:"input"}, + {title:"Prénom", field:"prename",headerFilter:"input"}, + {title:"Blocké", field:"blocked",formatter:"tickCross", + formatterParams:{allowEmpty:true,allowTruthy:true,tickElement:'X'}}, + {title:"Invisible", field:"disabled",formatter:"tickCross", + formatterParams:{allowEmpty:true,allowTruthy:true,tickElement:'X'}}, + ] + }); + gettbldata(); + return false; +} + +function gettbldata(){ + sql = "SELECT id, prename, surname, blocked, disabled FROM staff;"; + req.reqdata("POST","db.cgi",{ "sql":sql},loadtbldata); + return false; +} + +function loadtbldata(data){ + console.log(data); + if (data){ + tbl.setData(data); + } + return false; +} + +function edit(){ + var udata = tbl.getSelectedData(); + if (udata[0]){ + console.log(udata); + req.reqdata("POST","db.cgi",{"get":"staff","filter":"id=" + udata[0].id},loadstaffdata); + } + return false; +} + +function loadstaffdata(data){ + if (data){ + fillformbydataclass('staff',data[0],false); + document.getElementById('dlgstaff').style.display='block'; + } +} + +function add(){ + cleanform('staff'); + document.getElementById('dlgstaff').style.display='block'; +} + +function remove(){ + var udata = tbl.getSelectedData(); + if (udata[0]){ + fillformbydataclass('staffremove',udata[0],false); + document.getElementById('dlgstaffremove').style.display='block'; + } +} + +function staffremove(ident){ + req.reqdata("POST","db.cgi",{"del":"1","ident_staff_id":document.getElementById("ident_" + ident + "_id")},afterstaffremove); + +} + +function afterstaffremove(){ + gettbldata(); + formsaved(); + document.getElementById('dlgstaffremove').style.display='none'; +} + +function afterstaffsaved(){ + document.getElementById('dlgstaff').style.display='none'; +} \ No newline at end of file diff --git a/bin/CGI/tmpl/app/hourtrax/module/members/index.tt b/bin/CGI/tmpl/app/hourtrax/module/members/index.tt new file mode 100644 index 0000000..fabb851 --- /dev/null +++ b/bin/CGI/tmpl/app/hourtrax/module/members/index.tt @@ -0,0 +1,61 @@ +[% PROCESS macro/fields.tt %] +
+
+ + + + +
+
+
+
+
+
+ × +

Employé(e)

+
+
+ +
+ [% fieldhidden("id","staff","ident",'') %] + [% fieldeditbox("surname","staff","Nom",'w3-half','','') %] + [% fieldeditbox("prename","staff","Prénom",'w3-half','','') %] + [% fieldpasswordbox("pin","staff","Code Pin",'w3-third','','') %] + [% fieldcheckbox("disabled","staff","invisible",'w3-third','','') %] + [% fieldcheckbox("blocked","staff","bloqué",'w3-third','','') %] +
+ [% fieldtimebox("dailyhours","staff","heures par jour",'w3-third','','') %] + [% fieldtimebox("pausehours","staff","pause à deduire",'w3-third','','') %] +
+
+
+
+ + + [% formdlgsavebutton('users','sauvegarder','afterstaffsaved') %] +
+
+
+
+
+
+ × +

Supprimer Employé(e)?

+
+
+ +
+ [% fieldhidden("id","staffremove","ident",'') %] + [% fieldeditbox("surname","staffremove","Nom",'w3-half','readonly','') %] + [% fieldeditbox("prename","staffremove","Prénom",'w3-half','readonly','') %] +
+
+
+ + + +
+
+
\ No newline at end of file diff --git a/bin/CGI/tmpl/app/hourtrax/module/settings/index.js b/bin/CGI/tmpl/app/hourtrax/module/settings/index.js new file mode 100644 index 0000000..e69de29 diff --git a/bin/CGI/tmpl/app/hourtrax/module/settings/index.tt b/bin/CGI/tmpl/app/hourtrax/module/settings/index.tt new file mode 100644 index 0000000..a8c7a27 --- /dev/null +++ b/bin/CGI/tmpl/app/hourtrax/module/settings/index.tt @@ -0,0 +1,34 @@ +[% PROCESS macro/fields.tt %] +
+
+

Accès Admin

+
+
+ [% fieldeditbox("name","login",'Login','','') %] + [% fieldpasswordbox("password1","login",'Mot de passe','','') %] + [% fieldpasswordbox("password2","login",'Répérer mot de passe','','') %] +
+
+
+ +
+
+
+

Réseau

+
+
+ [% fieldeditbox("hostname","system",'Hostname','','readonly','') %] + [% fieldselectbox("wlanssid","system",'Wifi SSID','','','') %] + [% fieldpasswordbox ("wlanpassword","system",'Wifi Mot de passe','','','') %] +
+
+
+ +
+ +
+ +
+ + + \ No newline at end of file diff --git a/bin/CGI/tmpl/app/hourtrax/module/timetrack/index.js b/bin/CGI/tmpl/app/hourtrax/module/timetrack/index.js new file mode 100644 index 0000000..10301b9 --- /dev/null +++ b/bin/CGI/tmpl/app/hourtrax/module/timetrack/index.js @@ -0,0 +1,90 @@ +var tbl=null; + +var tbltypes = [{"value":"trackbyday","label":"pointage par jour"}, +{"value":"trackbystaff","label":"pointage par employé(e) et mois"},{"value":"trackincomplete","label":"pointages incomplètes"}]; + +curtbl = "trackbyday"; +function initpage(){ + console.log(mpref.cfg); + console.log("APP:" + parent.app); + flatpickr(".timefield",{altInput: true, + altFormat: "H:M", + dateFormat: "H:M", + allowInput: true, + "locale": "fr", + }); + flatpickr(".datefield",{altInput: true, + altFormat: "d.m.Y H:M", + dateFormat: "Y-m-d H:M", + allowInput: true, + "locale": "fr", + }); + tbl = new Tabulator("#tbl_clocks", { + headerFilterPlaceholder:"filtre...", + height: "95vh", + layout:"fitColumns", + selectable:1, + locale:"fr", + // responsiveLayout:"collapse", + groupBy:["staffname"], + groupStartOpen:[true, false], + groupHeader:[ + function(value, count, data){ //generate header contents for gender groups + return value; + }, + function(value, count, data){ //generate header contents for color groups + return value; + }, + ], + columns: [ + {title:"Mois", field:"dspdaydate",formatter:"datetime", formatterParams:{ + inputFormat:"DD.MM.YYYY", + outputFormat:"MMM YYYY", + invalidPlaceholder:""},headerFilter:"input"}, + {title:"Date", field:"dspdaydate",align: "right",formatter:"datetime", formatterParams:{ + inputFormat:"DD.MM.YYYY", + outputFormat:"DD.MM.YYYY", + invalidPlaceholder:""},headerFilter:"input"}, + {title:"Nom", field:"staffname",headerFilter:"input"}, + {title:"Entrée",align: "right",field:"entry"}, + {title:"Sortie",align: "right",field:"leave"}, + {title:"Incomplète",field:"incomplete",formatter:"tickCross", + formatterParams:{allowEmpty:true,allowTruthy:true,tickElement:'X'}}, + {title:"Total", field:"hoursworked",align: "right",formatter:"money",sorter:"number", + formatterParams:{decimal:",",thousand:".",symbol:"",symbolAfter:"h",precision:2}, + bottomCalc:"sum", bottomCalcParams:{precision:2},bottomCalcFormatterParams:{decimal:",",thousand:".",symbol:"",symbolAfter:"h",precision:2}} + ] + }); + gettbldata(); + +} + +function gettbldata(){ + sql = "select hrx.id,hrx.id_staff, coalesce(upper(hrx.surname),'') || ' ' || coalesce(hrx.prename,'') as staffname,date(hrx.stamp_in) as daydate,strftime(\"%d.%m.%Y\",date(hrx.stamp_in)) as dspdaydate,strftime(\"%H:%M\",hrx.stamp_in) as entry,strftime(\"%H:%M\",hrx.stamp_out) as leave,printf(\"%.2f\",CAST ((julianday(hrx.stamp_out) - julianday(hrx.stamp_in)) * 24 as REAL)) as hoursworked,hrx.incomplete from (SELECT hr.id, hr.id_staff, st.prename,st.surname, hr.stamp_in, case when hr.stamp_out is null then date(hr.stamp_in,'+1 day') || ' 00:00:00' else hr.stamp_out end as stamp_out,case when hr.stamp_out is null then true else null end as incomplete FROM hours hr join staff st on (hr.id_staff=st.id)) hrx order by hrx.stamp_in,hrx.id_staff;"; + req.reqdata("POST","db.cgi",{ "sql":sql},loadtbldata); + +} + +function loadtbldata(data){ + console.log(data); + if (data){ + tbl.setData(data); + } +} + +function edit(){ + var udata = tbl.getSelectedData(); + if (udata[0]){ + console.log(udata); + + } + +} + +function add(){ + +} + +function remove(){ + +} \ No newline at end of file diff --git a/bin/CGI/tmpl/app/hourtrax/module/timetrack/index.tt b/bin/CGI/tmpl/app/hourtrax/module/timetrack/index.tt new file mode 100644 index 0000000..138a8d4 --- /dev/null +++ b/bin/CGI/tmpl/app/hourtrax/module/timetrack/index.tt @@ -0,0 +1,9 @@ +
+
+ + + + +
+
+
\ No newline at end of file diff --git a/bin/CGI/tmpl/app/timeclock/index.js b/bin/CGI/tmpl/app/timeclock/index.js new file mode 100644 index 0000000..1f9310f --- /dev/null +++ b/bin/CGI/tmpl/app/timeclock/index.js @@ -0,0 +1,295 @@ +var currentuser= null; +var currentpanel = null; +var currentpinfield = null; +var lasttrack = null; +var interval = null; +var intervaltime = 60; + +function initpage(){ + loadusers(); +} + +function loadpanel(pnlid){ + var pnls = document.querySelectorAll(".clockpanel"); + + for (var i in pnls){ + //var pnl = pnls[i]; + if (pnls[i].id){ + //console.log(pnls[i].id); + pnls[i].style.display = 'none'; + } + // + } + currentpanel = pnlid; + console.log("Panel: " + currentpanel + " Users" + JSON.stringify(currentuser)); + //console.log(currentuser); + if ((pnlid == 'users') || (pnlid == null)){ + loadusers(); + } + else if (pnlid == 'userpin'){ + loaduserpin(); + } + else if (pnlid == 'newuserpin'){ + loadnewuserpin(); + } + else if (pnlid == 'timetracker'){ + console.log("before timetracker"); + loadpnltimetracker(); + } + else if (pnlid == 'status'){ + loadstatus(); + } + return false; +} + +function displaypanel(){ + intervaltime = 60; + if ((currentpanel ) && (currentpanel != 'users')) { + startCheckIdle(); + } else { + stopCheckIdle(); + } + console.log("Current Panel:" + currentpanel); + if (currentpanel){ + document.getElementById("pnl_" + currentpanel).style.display = 'block'; + } + + return false; +} + +function loadusers(){ + req.reqdata("POST","db.cgi",{"sql":"select id,prename,surname from staff where disabled is null and blocked is null;"},displayusers); + document.getElementById("sidebtn_pnlusers").style.display = 'none'; + document.getElementById("sidebtn_pnlchangepin").style.display = 'none'; + document.getElementById("sidebtn_pnluserpin").style.display = 'none'; + currentuser=null; + displaypanel(); + return false; +} + +function displayusers(data){ + document.getElementById('userlist').innerHTML=""; + //console.log(data); + + if (data){ + // if (data.length > 20){ + // document.getElementById('btnscrollup').style.display = 'inline'; + // document.getElementById('btnscrolldown').style.display = 'inline'; + // } else { + // document.getElementById('btnscrollup').style.display = 'none'; + // document.getElementById('btnscrolldown').style.display = 'none'; + // } + var ulist = ""; + for (var i in data){ + ulist += ''; + } + document.getElementById('userlist').innerHTML=ulist; + } +} + +function loaduserpin(){ + document.getElementById("pincode").value=''; + currentpinfield="pincode"; + document.getElementById("usergreeting1").innerHTML = 'Bonjour, '+ currentuser.prename + ' ' + currentuser.surname + ''; + document.getElementById("sidebtn_pnlusers").style.display = 'block'; + document.getElementById("sidebtn_pnlchangepin").style.display = 'none'; + document.getElementById("sidebtn_pnluserpin").style.display = 'none'; + displaypanel(); + return false; +} + +function loadnewuserpin(){ + document.getElementById("newpincode1").value=''; + document.getElementById("newpincode2").value=''; + document.getElementById("usergreeting2").innerHTML = 'Bonjour, '+ currentuser.prename + ' ' + currentuser.surname + ''; + currentpinfield="newpincode1"; + document.getElementById("sidebtn_pnlusers").style.display = 'block'; + document.getElementById("sidebtn_pnlchangepin").style.display = 'none'; + document.getElementById("sidebtn_pnluserpin").style.display = 'none'; + displaypanel(); + return false; +} + +function loadpnltimetracker(){ + console.log("load time tracker"); + document.getElementById("trackusername").innerHTML="" + currentuser.prename + " " + currentuser.surname + ""; + document.getElementById("sidebtn_pnlusers").style.display = 'block'; + document.getElementById("sidebtn_pnlchangepin").style.display = 'block'; + document.getElementById("sidebtn_pnluserpin").style.display = 'none'; + displaypanel(); + return false; +} + +function loadloader(){ + document.getElementById("sidebtn_pnlusers").style.display = 'block'; + document.getElementById("sidebtn_pnlchangepin").style.display = 'none'; + document.getElementById("sidebtn_pnluserpin").style.display = 'none'; + displaypanel(); + return false; +} + +function loadstatus(){ + document.getElementById("sidebtn_pnlusers").style.display = 'block'; + document.getElementById("sidebtn_pnlchangepin").style.display = 'none'; + document.getElementById("sidebtn_pnluserpin").style.display = 'none'; + displaypanel(); + return false; +} + +function setuser(id){ + var sqlq = "select id,prename,surname,pin,blocked,disabled from staff where id="+id+";"; + req.reqdata("POST","db.cgi",{"sql":sqlq},loaduser); + return false; +} + +function loaduser(data){ + if (data){ + currentuser = data[0]; + console.log(currentuser); + console.log("after cuser"); + if ((currentuser.pin == "" || currentuser.pin == null)){ + loadpanel('newuserpin'); + } else { + loadpanel('userpin'); + } + }else { + currentuser = null; + } + return false; +} + +function checkuserpin(){ + var sqlq = "select pin,blocked,disabled from staff where id="+currentuser.id+";"; + req.reqdata("POST","db.cgi",{"sql":sqlq},loadtimetracker); + return false; +} + + + +function loadtimetracker(data){ + var userpin= document.getElementById("pincode").value; + if (data){ + console.log(userpin + "<=>" + data[0].pin); + if (userpin==data[0].pin){ + req.reqdata("POST","db.cgi",{"sql":"select id,strftime(\"%d.%m.%Y\",date(stamp_in)) as daydate,strftime(\"%H:%M\",stamp_in) as stamp_in,strftime(\"%H:%M\",stamp_out) as stamp_out,date(stamp_in) as cmpdaydate from hours where id_staff="+ currentuser.id+" order by date(stamp_in) desc,stamp_in desc,stamp_out desc LIMIT 1;"},loadtrackdata); + loadpanel("timetracker"); + } else { + document.getElementById("pincode").value = ""; + intervaltime=60; + document.getElementById("usergreeting1").innerHTML = 'Code PIN pas correcte!'; + } + } + return false; +} + +function loadtrackdata(data){ + console.log(data); + var cdate = new Date().toISOString().substring(0,10); + document.getElementById("btntrackin").disabled = true; + document.getElementById("btntrackout").disabled = true; + //console.log(cdate + "<=>" + data[0].cmpdaydate); + if (data && data[0] && data.length > 0){ + lasttrack=data[0]; + if (data[0].cmpdaydate && (data[0].cmpdaydate == cdate)){ + console.log("IN:" + data[0].stamp_in); + console.log("out:" + data[0].stamp_out); + if ((data[0].stamp_in != null) && (data[0].stamp_out != null)){ + document.getElementById("btntrackin").disabled = false; + } else { + document.getElementById("btntrackout").disabled = false; + } + } else { + document.getElementById("btntrackin").disabled = false; + } + // + document.getElementById("lasttrack").innerHTML = "Dernier Pointage:
" + ((data[0].daydate)?data[0].daydate:"") + " "+ ((data[0].stamp_in)?" Entrée:" + data[0].stamp_in:"N/A") + " Sortie: " +((data[0].stamp_out)?data[0].stamp_out:"N/A") + ""; + } else { + lasttrack = null; + document.getElementById("btntrackin").disabled = false; + document.getElementById("lasttrack").innerHTML = ""; + } + + return false; +} + +function setnewuserpin(){ + var pin1 = document.getElementById("newpincode1").value; + var pin2 = document.getElementById("newpincode2").value; + console.log(pin1 + "<=>" + pin2); + if (pin1.length >= 4 && pin2.length == 0){ + currentpinfield = "newpincode2"; + return false; + } + if (pin1.length < 4 || pin2.length < 4){ + clearUserPin(); + document.getElementById("usergreeting2").innerHTML = 'Entrez un code pin de min 4 nombres!'; + return false; + } else if (pin1 != pin2){ + clearUserPin(); + document.getElementById("usergreeting2").innerHTML = 'Les codes ne sont pas identiques!'; + return false; + } + req.reqdata("POST","db.cgi",{"sql":"update staff set pin='" + pin1 + "' where id=" + currentuser.id + ";"},afterpincodeupdate); + return false; +} + +function afterpincodeupdate(data){ + setuser(currentuser.id); + return false; +} + +function setPinValue(key){ + intervaltime = 60; + var cobj = document.getElementById(currentpinfield); + var cpin = cobj.value; + cobj.value = cpin + key; + return false; +} + +function clearUserPin(){ + intervaltime = 60; + document.getElementById("pincode").value = ""; + document.getElementById("newpincode1").value = ""; + document.getElementById("newpincode2").value = ""; + return false; +} + +function setTrack(direction){ + var sql = ""; + //intervaltime = 60; + if (direction == 'in'){ + sql = "INSERT INTO hours (id_staff, stamp_in) VALUES ("+currentuser.id+",CURRENT_TIMESTAMP);"; + } else if (direction == 'out'){ + sql = "UPDATE hours SET stamp_out=CURRENT_TIMESTAMP where id_staff='"+ currentuser.id+"' and id='"+lasttrack.id+"';"; + } + //console.log(sql); + req.reqdata("POST","db.cgi",{"sql":sql},showstatus); +} + +function showstatus(data){ + //console.log(data); + if (data && data.success) { document.getElementById("statusmsg").innerHTML = "Merci, le pointage a été enregistré!"} + loadpanel("status"); + setTimeout("loadpanel('users');",3000); +} + +function checkIdle(){ + //console.log("check idle"); + if (intervaltime < 0){ + //console.log("change view"); + location.href = location.href; + } else { + + intervaltime = intervaltime - 1; + //console.log(intervaltime); + } +} +function startCheckIdle(){ + interval = window.setInterval("checkIdle()",1000); + +} +function stopCheckIdle(){ + window.clearInterval(interval); +} + + diff --git a/bin/CGI/tmpl/app/timeclock/index.tt b/bin/CGI/tmpl/app/timeclock/index.tt new file mode 100644 index 0000000..7f4203f --- /dev/null +++ b/bin/CGI/tmpl/app/timeclock/index.tt @@ -0,0 +1,117 @@ +[% USE date %] +[% vstamp=date.format(date.now, '%d%m%Y%H%M%S') %] + + + + + + + + + + +Time Clock + + +
+ + + + +
+
+
+
+
+
+
+ +
+
+
Bonjour Prename,
+
+
+
+ + + + + + + + + + + + +
+
+
+ + + +
+
+ + + + + + + + + \ No newline at end of file diff --git a/bin/CGI/tmpl/block/snackbar.tt b/bin/CGI/tmpl/block/snackbar.tt new file mode 100644 index 0000000..464a162 --- /dev/null +++ b/bin/CGI/tmpl/block/snackbar.tt @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/bin/CGI/tmpl/macro/fields.tt b/bin/CGI/tmpl/macro/fields.tt new file mode 100644 index 0000000..63c16fe --- /dev/null +++ b/bin/CGI/tmpl/macro/fields.tt @@ -0,0 +1,123 @@ +[% MACRO fieldhidden(column,table,ident,value) BLOCK -%] + +[% END -%] +[% MACRO fieldeditbox(column,table,title,size,state,value,plhold) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldfile(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldpasswordbox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldtagbox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldcheckbox(column,table,title,size,state,value) BLOCK -%] +
+
+ 0 %][% state %][% END %]> + +
+[% END -%] + +[% MACRO fieldemailbox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> +
+[% END -%] + +[% MACRO fieldselectbox(column,table,title,size,state,value) BLOCK -%] + [% IF state.length > 0 %] + [% fieldeditbox(column,table,title,size,state,value) %] + [% ELSE %] +
+ + + +
+ [% END %] +[% END -%] +[% MACRO fieldmultiselectbox(column,table,title,size,state,value) BLOCK -%] + [% IF state.length > 0 %] + [% fieldeditbox(column,table,title,size,state,value) %] + [% ELSE %] +
+ + + +
+ [% END %] +[% END -%] +[% MACRO fielddatebox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]]/> + +
+[% END -%] +[% MACRO fieldtimebox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]]/> + +
+[% END -%] +[% MACRO fieldtextarea(column,table,title,size,state,height,value) BLOCK -%] +
+ + +
+[% END -%] +[% MACRO fieldrichtextarea(column,table,title,size,state,height,value) BLOCK -%] +
+ + +
+[% END -%] + +[% MACRO formsavebutton(formname,btnname) BLOCK -%] +
+ +
+[% END -%] +[% MACRO formsavetextfilebutton(formname,btnname) BLOCK -%] +
+ +
+[% END -%] +[% MACRO formdlgsavebutton(formname,btnname,clbk) BLOCK -%] + +[% END -%] +[% MACRO formsavefilebutton(formname,btnname,container) BLOCK -%] +[% IF container.length > 0 %] +
+ [% END %] + +[% IF container.length > 0 %] +
+[% END %] +[% END -%] \ No newline at end of file diff --git a/bin/CGI/tmpl/skeleton/app.tt b/bin/CGI/tmpl/skeleton/app.tt new file mode 100644 index 0000000..e5e9f5f --- /dev/null +++ b/bin/CGI/tmpl/skeleton/app.tt @@ -0,0 +1,3 @@ +[% #USE DBI %] +[% #USE dksdb = DBI(dsn, dbuser, dbpassword) %] +[% INCLUDE $page %] \ No newline at end of file diff --git a/bin/CGI/tmpl/skeleton/file.tt b/bin/CGI/tmpl/skeleton/file.tt new file mode 100644 index 0000000..e5e9f5f --- /dev/null +++ b/bin/CGI/tmpl/skeleton/file.tt @@ -0,0 +1,3 @@ +[% #USE DBI %] +[% #USE dksdb = DBI(dsn, dbuser, dbpassword) %] +[% INCLUDE $page %] \ No newline at end of file diff --git a/bin/CGI/tmpl/skeleton/index.tt b/bin/CGI/tmpl/skeleton/index.tt new file mode 100644 index 0000000..b4df386 --- /dev/null +++ b/bin/CGI/tmpl/skeleton/index.tt @@ -0,0 +1,36 @@ +[% USE date %] +[% #USE env = EnvHash %] +[% vstamp=date.format(date.now, '%d%m%Y%H%M%S') %] + + + + + + + + + +Hourtrax + + +
+
+ +
Hourtrax
+ + +
+
+
+
+ +
+
+
+
+ + + + + + diff --git a/bin/CGI/tmpl/skeleton/module.tt b/bin/CGI/tmpl/skeleton/module.tt new file mode 100644 index 0000000..f5bd93d --- /dev/null +++ b/bin/CGI/tmpl/skeleton/module.tt @@ -0,0 +1,61 @@ +[% USE Dumper %] + +[% #USE dksdb = DBI(dsn, dbuser, dbpassword) %] +[% #USE date %] +[% vstamp=date.format(date.now, '%d%m%Y') %] + + + + + + + + + [% adminname %] - [% module %] - [% pagename %] + + + + + + + + + + + [% #INCLUDE "module/$module/css.tt" %] + + + + +
+ [% #IF session.id %] + [% INCLUDE $page %] +
+ + + + + + + + + + + [% #INCLUDE "module/$module/javascript.tt" %] + + + [% #ELSE %] + + [% #END %] + [% INCLUDE block/snackbar.tt %] + + + \ No newline at end of file diff --git a/bin/htdocs/css/admin.css b/bin/htdocs/css/admin.css new file mode 100644 index 0000000..78685c1 --- /dev/null +++ b/bin/htdocs/css/admin.css @@ -0,0 +1,240 @@ + * { + font-family: sans-sherif, Arial, Helvetica !important; + } + body,html { + margin: 0px; + } +header { + overflow: hidden; + position: fixed; /* Set the navbar to fixed position */ + top: 0; /* Position the navbar at the top of the page */ + width: 100%; /* Full width */ + height: 60px; + padding-left: 5px; + background: linear-gradient(to right, purple, gray); +} + +header > h1 { + color: yellow; + margin-top: 10px; + float: left; + text-shadow: 0px -1px 0px rgba(0,0,0,.5); +} +div.headerlinks { + margin-left: 10px; + margin-top: 5px; + float: left; +} +button { + /* display: inline-block; + */ + text-decoration: none; + color: #fff; + font-weight: bold; + background-color: #538fbe; + /* padding: 20px 70px; + font-size: 24px; */ + border: 1px solid #2d6898; + background-image: linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -o-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -moz-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -webkit-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -ms-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, rgb(73,132,180)), + color-stop(1, rgb(97,155,203)) + ); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + text-shadow: 0px -1px 0px rgba(0,0,0,.5); + /* -webkit-box-shadow: 0px 6px 0px #2b638f, 0px 3px 15px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); + -moz-box-shadow: 0px 6px 0px #2b638f, 0px 3px 15px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); + box-shadow: 0px 6px 0px #2b638f, 0px 3px 15px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); */ + /* -webkit-transition: all .1s ease-in-out; + -moz-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; + -webkit-transform: rotateX(20deg); */ +} + + +button { + margin-left: 3px; + height: 30px; +} + +div.headerlinks button { + height: 50px; +} + + +section.main { + width: 1024px; + margin: auto; + margin-top: 70px; + +} +table { + margin-top: 10px; + width: 100%; + border: 1px solid silver; + border-collapse: collapse; +} +table thead { + background-color: gray; +} + +table thead th { + padding: 5px 10px; + border: 1px solid silver; +} + +table tbody tr:nth-child(even){ + background-color: rgba(128,0,128,0.3); + +} + +table tbody tr:hover { + background-color: #79bcff; +} + +table tbody td { + border: 1px solid silver; + padding: 5px 10px; +} +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + + + +input, select { + border: 1px solid silver; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + padding: 5px 10px; +} + +input:disabled { + border: 0; + color: #000000; + background: transparent !important; +} + +.page { + display: none; +} + +input[type=number] { + text-align: right; +} + + + +tbody > tr.selected { + background-color: #0080ff; +} + +.panel { + border: 1px solid silver; + width: 100%; + display: block; + border: 1px solid silver; + padding: 5px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + margin: 4px; +} + +.panel-head { + margin: 0px; + padding: 3px; + height: 20px; + +} + +h4 { + margin: 0px; + padding: 2px; +} + +.tabset > input[type="radio"] { + position: absolute; + left: -200vw; +} + +.tabset .tab-panel { + display: none; +} + +.tabset > input:first-child:checked ~ .tab-panels > .tab-panel:first-child, +.tabset > input:nth-child(3):checked ~ .tab-panels > .tab-panel:nth-child(2), +.tabset > input:nth-child(5):checked ~ .tab-panels > .tab-panel:nth-child(3), +.tabset > input:nth-child(7):checked ~ .tab-panels > .tab-panel:nth-child(4), +.tabset > input:nth-child(9):checked ~ .tab-panels > .tab-panel:nth-child(5), +.tabset > input:nth-child(11):checked ~ .tab-panels > .tab-panel:nth-child(6) { + display: block; +} + +.tabset > label { + position: relative; + display: inline-block; + padding: 15px 15px 15px; + border: 1px solid transparent; + border-bottom: 0; + cursor: pointer; + font-weight: 600; +} + +/* .tabset > label::after { + position: absolute; + left: 15px; + bottom: 10px; + width: 22px; + height: 4px; + background: #8d8d8d; +} */ + +.tabset > label:hover, +.tabset > input:focus + label { + color: #06c; +} + +.tabset > label:hover::after, +.tabset > input:focus + label::after, +.tabset > input:checked + label::after { + background: #06c; +} + +.tabset > input:checked + label { + border-color: #ccc; + border-bottom: 1px solid #fff; + margin-bottom: -1px; +} + +.tab-panel { + padding: 30px 0; + border-top: 1px solid #ccc; +} + +label.formlabel { + width: 120px; +} + +div.row { + margin-top: 3px; + margin-bottom: 3px; +} + +section.sysconfig { + display: none; +} + diff --git a/bin/htdocs/css/clock.css b/bin/htdocs/css/clock.css new file mode 100644 index 0000000..79ba471 --- /dev/null +++ b/bin/htdocs/css/clock.css @@ -0,0 +1,236 @@ + + body,html { + overflow: hidden; + margin: 0px; + + } + div { + margin: auto; + } + header { + height: 60px; + padding-left: 5px; + background: linear-gradient(to right, purple, gray); + } + h1 { + padding-top: 5px; + margin-top: 0px; + color: yellow; + } + button { + display: inline-block; + text-decoration: none; + color: #fff; + font-weight: bold; + background-color: #538fbe; + /* padding: 20px 70px; + font-size: 24px; */ + border: 1px solid #2d6898; + background-image: linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -o-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -moz-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -webkit-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + background-image: -ms-linear-gradient(bottom, rgb(73,132,180) 0%, rgb(97,155,203) 100%); + + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, rgb(73,132,180)), + color-stop(1, rgb(97,155,203)) + ); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + text-shadow: 0px -1px 0px rgba(0,0,0,.5); + -webkit-box-shadow: 0px 6px 0px #2b638f, 0px 3px 15px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); + -moz-box-shadow: 0px 6px 0px #2b638f, 0px 3px 15px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); + box-shadow: 0px 6px 0px #2b638f, 0px 3px 15px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); + -webkit-transition: all .1s ease-in-out; + -moz-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; + -webkit-transform: rotateX(20deg); +} + +button:hover { + background-image: linear-gradient(bottom, rgb(79,142,191) 0%, rgb(102,166,214) 100%); + background-image: -o-linear-gradient(bottom, rgb(79,142,191) 0%, rgb(102,166,214) 100%); + background-image: -moz-linear-gradient(bottom, rgb(79,142,191) 0%, rgb(102,166,214) 100%); + background-image: -webkit-linear-gradient(bottom, rgb(79,142,191) 0%, rgb(102,166,214) 100%); + background-image: -ms-linear-gradient(bottom, rgb(79,142,191) 0%, rgb(102,166,214) 100%); + + /* background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, rgb(79,142,191)), + color-stop(1, rgb(102,166,214)) + ); */ +} + +button:active { +-webkit-box-shadow: 0px 2px 0px #2b638f, 0px 1px 6px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); +-moz-box-shadow: 0px 2px 0px #2b638f, 0px 1px 6px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); +box-shadow: 0px 2px 0px #2b638f, 0px 1px 6px rgba(0,0,0,.4), inset 0px 1px 0px rgba(255,255,255,.3), inset 0px 0px 3px rgba(255,255,255,.5); + background-image: linear-gradient(bottom, rgb(88,154,204) 0%, rgb(90,150,199) 100%); + background-image: -o-linear-gradient(bottom, rgb(88,154,204) 0%, rgb(90,150,199) 100%); + background-image: -moz-linear-gradient(bottom, rgb(88,154,204) 0%, rgb(90,150,199) 100%); + background-image: -webkit-linear-gradient(bottom, rgb(88,154,204) 0%, rgb(90,150,199) 100%); + background-image: -ms-linear-gradient(bottom, rgb(88,154,204) 0%, rgb(90,150,199) 100%); + + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, rgb(88,154,204)), + color-stop(1, rgb(90,150,199)) + ); + -webkit-transform: translate(0, 4px) rotateX(20deg); + -moz-transform: translate(0, 4px); + transform: translate(0, 4px); +} + +button:disabled { + background-image: none; + background-color: #f4f4f4; + color: #000; + font-weight: bold; + box-shadow: none; + -webkit-transform: none; +} + /* button { + background-color: lightgrey; + border: 1px solid silver; + outline: none; + } */ + button.user { + height: 90px; + width: 90px; + margin: 10px; + white-space: nowrap; + overflow: hidden; + } + button.btnkeypad { + height: 70px; + width: 70px; + margin: 5px; + font-weight: bold; + font-size: 20px; + white-space: nowrap; + overflow: hidden; + } + button.btntrack { + background-color: + height: 150px; + width: 150px; + margin: 15px; + font-weight: bold; + font-size: 30px; + white-space: nowrap; + overflow: hidden; + } + #scrloader { + display: none; + margin: auto; + border: 1px solid silver; + max-width: 800px; + width: 800px; + height: 430px; + max-height: 430px; + overflow: hidden; + } + #scruserlist { + display: none; + border: 1px solid silver; + max-width: 800px; + width: 800px; + height: 430px; + max-height: 430px; + overflow: hidden; + } + #scruserpin { + display: none; + margin: auto; + border: 1px solid silver; + max-width: 800px; + width: 800px; + height: 430px; + max-height: 430px; + overflow: hidden; + } + #scrnewuserpin { + display: none; + margin: auto; + border: 1px solid silver; + max-width: 800px; + width: 800px; + height: 430px; + max-height: 430px; + overflow: hidden; + } + #scrtimetracker{ + display: none; + margin: auto; + border: 1px solid silver; + max-width: 800px; + width: 800px; + height: 430px; + max-height: 430px; + overflow: hidden; + } + #scrstatus{ + display: none; + margin: auto; + border: 1px solid silver; + max-width: 800px; + width: 800px; + height: 430px; + max-height: 430px; + overflow: hidden; + } + #keypad { + border: 1px solid silver; + width: 270px; + margin: auto; + } + #timetracker{ + border: 1px solid silver; + width: 400px; + margin: auto; + margin-top: 20px; + text-align: center; + } + div.pincode { + text-align: center; + } + #pincode,#newpincode1,#newpincode2 { + min-height: 30px; + border: 1px solid silver; + width: 270px; + margin: auto; + text-align: center; + font-weight: bold; + font-size: 10px; + } + #newpincode1,#newpincode2{ + width: 135px; + } + .usergreeting { + text-align: center; + } + #pinmessage, #pinmessage2 { + height: 30px; + display: block; + color: red; + font-weight: bold; + text-align: center; + } + #lasttrackin,#lasttrackout { + font-size: 12px; + color: #000; + font-weight: bold; + } + + +/* screenheight: 480;*/ +/* screenwidth: 80px;*/ \ No newline at end of file diff --git a/bin/htdocs/css/clock2.css b/bin/htdocs/css/clock2.css new file mode 100644 index 0000000..9886d0c --- /dev/null +++ b/bin/htdocs/css/clock2.css @@ -0,0 +1,5 @@ +.btnkeypad { + height: 75px; + font-weight: bold; + font-size: 30px; +} \ No newline at end of file diff --git a/bin/htdocs/css/w3pro.css b/bin/htdocs/css/w3pro.css new file mode 100644 index 0000000..3013489 --- /dev/null +++ b/bin/htdocs/css/w3pro.css @@ -0,0 +1,378 @@ +/* W3PRO.CSS 4.13 June 2019 by Jan Egil and Borge Refsnes */ +html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit} +/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */ +html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} +article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item} +audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline} +audio:not([controls]){display:none;height:0}[hidden],template{display:none} +a{background-color:transparent}a:active,a:hover{outline-width:0} +abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} +b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000} +small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} +sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none} +code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible} +button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold} +button,input{overflow:visible}button,select{text-transform:none} +button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button} +button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0} +button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText} +fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em} +legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto} +[type=checkbox],[type=radio]{padding:0} +[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto} +[type=search]{-webkit-appearance:textfield;outline-offset:-2px} +[type=search]::-webkit-search-decoration{-webkit-appearance:none} +::-webkit-file-upload-button{-webkit-appearance:button;font:inherit} +/* End extract */ +html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden} +h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}.w3-serif{font-family:serif} +h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin: 0}.w3-wide{letter-spacing:4px} +hr{border:0;border-top:1px solid #eee;margin:20px 0} +.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit} +.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc} +.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1} +.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1} +.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center} +.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top} +.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px} +.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap} +.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)} +.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none} +.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none} +.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%} +.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none} +.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block} +.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s} +.w3-input{padding:8px;display:block;border:1px solid #ccc;width:100%;background-color: #e8f0fe; } +.w3-select{padding:9px 0; display:block;width:100%;border:1px solid #ccc;background-color: #e8f0fe;} +.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer} +.w3-dropdown-hover:hover .w3-dropdown-content{display:block; } +.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000} +.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000} +.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1} +.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px} +.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto} +.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%} +.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%} +.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px} +.w3-main,#main{transition:margin-left .4s} +.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)} +.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px} +.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto} +.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0} +.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left} +.w3-bar .w3-button{white-space:normal} +.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0} +.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%} +.w3-responsive{display:block;overflow-x:auto} +.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before, +.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both} +.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%} +.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%} +.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%} +.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%} +@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%} +.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%} +.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}} +@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%} +.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%} +.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}} +.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px} +.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px} +.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell} +.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom} +.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important} +@media (max-width:1205px){.w3-auto{max-width:95%}} +@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px} +.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative} +.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center} +.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}} +@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}} +@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}} +@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}} +@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}} +.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0} +.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2} +.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0} +.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0} +.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)} +.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)} +.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)} +.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)} +.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)} +.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none} +.w3-display-position{position:absolute} +.w3-circle{border-radius:50%} +.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px} +.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px} +.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px} +.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px} +.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word} +.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%} +.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16)} +.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)} +.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}} +.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}} +.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}} +.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}} +.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}} +.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}} +.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}} +.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}} +.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important} +.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1} +.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75} +.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)} +.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)} +.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)} +.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important} +.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important} +.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important} +.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important} +.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important} +.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important} +.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important} +.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important} +.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important} +.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important} +.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important} +.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important} +.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important} +.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important} +.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important} +.w3-left{float:left!important}.w3-right{float:right!important} +.w3-button:hover{color:#000!important;background-color:#ccc!important} +.w3-transparent,.w3-hover-none:hover{background-color:transparent!important} +.w3-hover-none:hover{box-shadow:none!important} +/* DEFAULT COLORS */ +.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important} +.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important} +.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important} +.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important} +.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important} +.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important} +.w3-blue-grey,.w3-hover-blue-grey:hover{color:#fff!important;background-color:#607d8b!important} +.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important} +.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important} +.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important} +.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important} +.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important} +.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important} +.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important} +.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important} +.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important} +.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important} +.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important} +.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important} +.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important} +.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important} +.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important} +.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important} +.w3-grey,.w3-hover-grey:hover{color:#000!important;background-color:#9e9e9e!important} +.w3-light-grey,.w3-hover-light-grey:hover{color:#000!important;background-color:#f1f1f1!important} +.w3-dark-grey,.w3-hover-dark-grey:hover{color:#fff!important;background-color:#616161!important} +.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffe7e7!important}.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#e7ffe7!important} +.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffd7!important}.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#e7ffff!important} +.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important} +.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important} +.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important} +.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important} +.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important} +.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important} +.w3-text-blue-grey,.w3-hover-text-blue-grey:hover{color:#607d8b!important} +.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important} +.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important} +.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important} +.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important} +.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important} +.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important} +.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important} +.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important} +.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important} +.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important} +.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important} +.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important} +.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important} +.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important} +.w3-text-white,.w3-hover-text-white:hover{color:#fff!important} +.w3-text-black,.w3-hover-text-black:hover{color:#000!important} +.w3-text-grey,.w3-hover-text-grey:hover{color:#757575!important} +.w3-text-light-grey,.w3-hover-text-light-grey:hover{color:#f1f1f1!important} +.w3-text-dark-grey,.w3-hover-text-dark-grey:hover{color:#3a3a3a!important} +.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important} +.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important} +.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important} +.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important} +.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important} +.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important} +.w3-border-blue-grey,.w3-hover-blue-grey:hover{border-color:#607d8b!important} +.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important} +.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important} +.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important} +.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important} +.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important} +.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important} +.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important} +.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important} +.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important} +.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important} +.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important} +.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important} +.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important} +.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important} +.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important} +.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important} +.w3-border-grey,.w3-hover-border-grey:hover{border-color:#9e9e9e!important} +.w3-border-light-grey,.w3-hover-border-light-grey:hover{border-color:#f1f1f1!important} +.w3-border-dark-grey,.w3-hover-border-dark-grey:hover{border-color:#616161!important} +.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important} +.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffd7!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important} +/* DEFAULT THEME */ +.w3-theme-l5 {color:#000 !important; background-color:#f6f8fc !important} +.w3-theme-l4 {color:#000 !important; background-color:#e1e9f6 !important} +.w3-theme-l3 {color:#000 !important; background-color:#c3d3ed !important} +.w3-theme-l2 {color:#000 !important; background-color:#a5bee4 !important} +.w3-theme-l1 {color:#fff !important; background-color:#88a8db !important} +.w3-theme-d1 {color:#fff !important; background-color:#5180cb !important} +.w3-theme-d2 {color:#fff !important; background-color:#3a6fc3 !important} +.w3-theme-d3 {color:#fff !important; background-color:#3361aa !important} +.w3-theme-d4 {color:#fff !important; background-color:#2c5392 !important} +.w3-theme-d5 {color:#fff !important; background-color:#24457a !important} + +.w3-theme-light {color:#000 !important; background-color:#f6f8fc !important} +.w3-theme-dark {color:#fff !important; background-color:#24457a !important} +.w3-theme-action {color:#fff !important; background-color:#24457a !important} + +.w3-theme {color:#fff !important; background-color:#6a92d3 !important} +.w3-text-theme {color:#6a92d3 !important} +.w3-border-theme {border-color:#6a92d3 !important} + +.w3-hover-theme:hover {color:#fff !important; background-color:#6a92d3 !important} +.w3-hover-text-theme:hover {color:#6a92d3 !important} +.w3-hover-border-theme:hover {border-color:#6a92d3 !important} + +.w3-label { color: rgb(153, 150, 150);} +#main {margin-left: 210px;} +@media (max-width:768px){ + #sidebar { display: none;} + #main { margin-left: 0px;} +} + +.w3-select { + display: block; + font-size: 16px; + font-family: sans-serif; + font-weight: normal; + color: #444; + line-height: 1.3; + padding: .6em 1.4em .5em .8em; + width: 100%; + max-width: 100%; + box-sizing: border-box; + margin: 0; + border-bottom: 1px solid #aaa; + box-shadow: 0 1px 0 1px rgba(0,0,0,.04); + /* border-radius: .5em; */ + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background-color: #e8f0fe; + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23000%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'), + linear-gradient(to bottom, #e8f0fe 0%,#e8f0fe 100%); + background-repeat: no-repeat, repeat; + background-position: right .7em top 50%, 0 0; + background-size: .65em auto, 100%; +} +.w3-select::-ms-expand { + display: none; +} +.w3-select:hover { + border-color: #888; +} +.w3-select:focus { + border-color: #aaa; + box-shadow: 0 0 1px 1px #6a92d3; + box-shadow: 0 0 0 1px -moz-mac-focusring; + color: #222; + outline: none; +} + + +.w3-select option { + font-weight:normal; +} + +.w3-table { + table-layout: fixed; +} + +.w3-text-line-through { text-decoration: line-through; } + +#snackbar { + visibility: hidden; + min-width: 250px; + margin-left: -125px; + background-color: #333; + color: #fff; + text-align: center; + border-radius: 2px; + padding: 16px; + position: fixed; + z-index: 1; + left: 50%; + bottom: 30px; + font-size: 17px; +} + +#snackbar.show { + visibility: visible; + -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; + animation: fadein 0.5s, fadeout 0.5s 2.5s; +} + +@-webkit-keyframes fadein { + from {bottom: 0; opacity: 0;} + to {bottom: 30px; opacity: 1;} +} + +@keyframes fadein { + from {bottom: 0; opacity: 0;} + to {bottom: 30px; opacity: 1;} +} + +@-webkit-keyframes fadeout { + from {bottom: 30px; opacity: 1;} + to {bottom: 0; opacity: 0;} +} + +@keyframes fadeout { + from {bottom: 30px; opacity: 1;} + to {bottom: 0; opacity: 0;} +} + +.tabulator-header-filter > input { + background-color: #e8f0fe; + border: 1px solid #ccc; + font-weight: normal; +} + +.w3-readonly { + pointer-events:none; + padding:8px;display:block;border:0px;width:100%;background-color: #fff; +} + +.right-side-bg { + background: url("../img/bg1.jpg"); + background-size: cover; + min-height: 100vh; +} + +/* .mceContentBody { + background: #e8f0fe; + color:#000; +} */ + +/* .tabulator-row-even { + background-color: #757575; +} */ \ No newline at end of file diff --git a/bin/htdocs/img/dks_1000.png b/bin/htdocs/img/dks_1000.png new file mode 100644 index 0000000000000000000000000000000000000000..87b44eb9a1899d458cb0acb063fc98541ee8ea14 GIT binary patch literal 68554 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⪚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 AX8-^I literal 0 HcmV?d00001 diff --git a/bin/htdocs/img/hourtrax.svg b/bin/htdocs/img/hourtrax.svg new file mode 100644 index 0000000..05f00e2 --- /dev/null +++ b/bin/htdocs/img/hourtrax.svg @@ -0,0 +1,90 @@ + + + + + + + image/svg+xml + + + + + + + Hourtrax + + + + + + + + + + + + + + + diff --git a/bin/htdocs/img/icons/Adobe_Acrobat.svg b/bin/htdocs/img/icons/Adobe_Acrobat.svg new file mode 100644 index 0000000..43a58e1 --- /dev/null +++ b/bin/htdocs/img/icons/Adobe_Acrobat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/Adobe_PDF_Export.svg b/bin/htdocs/img/icons/Adobe_PDF_Export.svg new file mode 100644 index 0000000..49169f9 --- /dev/null +++ b/bin/htdocs/img/icons/Adobe_PDF_Export.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/Agreement_01.svg b/bin/htdocs/img/icons/Agreement_01.svg new file mode 100644 index 0000000..27a8a06 --- /dev/null +++ b/bin/htdocs/img/icons/Agreement_01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/Bill.svg b/bin/htdocs/img/icons/Bill.svg new file mode 100644 index 0000000..b891cd2 --- /dev/null +++ b/bin/htdocs/img/icons/Bill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/Document_Save.svg b/bin/htdocs/img/icons/Document_Save.svg new file mode 100644 index 0000000..7262b20 --- /dev/null +++ b/bin/htdocs/img/icons/Document_Save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/Save.svg b/bin/htdocs/img/icons/Save.svg new file mode 100644 index 0000000..ce6bfa3 --- /dev/null +++ b/bin/htdocs/img/icons/Save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/address.svg b/bin/htdocs/img/icons/address.svg new file mode 100644 index 0000000..4d51035 --- /dev/null +++ b/bin/htdocs/img/icons/address.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/address_white.svg b/bin/htdocs/img/icons/address_white.svg new file mode 100644 index 0000000..a5de7d7 --- /dev/null +++ b/bin/htdocs/img/icons/address_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/apps.svg b/bin/htdocs/img/icons/apps.svg new file mode 100644 index 0000000..eef3c30 --- /dev/null +++ b/bin/htdocs/img/icons/apps.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/apps_white.svg b/bin/htdocs/img/icons/apps_white.svg new file mode 100644 index 0000000..f37f596 --- /dev/null +++ b/bin/htdocs/img/icons/apps_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/archive.svg b/bin/htdocs/img/icons/archive.svg new file mode 100644 index 0000000..0e614f8 --- /dev/null +++ b/bin/htdocs/img/icons/archive.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/archive_white.svg b/bin/htdocs/img/icons/archive_white.svg new file mode 100644 index 0000000..1dcbdf5 --- /dev/null +++ b/bin/htdocs/img/icons/archive_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/calendar.svg b/bin/htdocs/img/icons/calendar.svg new file mode 100644 index 0000000..6b51e03 --- /dev/null +++ b/bin/htdocs/img/icons/calendar.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/calendar_white.svg b/bin/htdocs/img/icons/calendar_white.svg new file mode 100644 index 0000000..c738ec5 --- /dev/null +++ b/bin/htdocs/img/icons/calendar_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/clocktime.svg b/bin/htdocs/img/icons/clocktime.svg new file mode 100644 index 0000000..7a94f5b --- /dev/null +++ b/bin/htdocs/img/icons/clocktime.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/bin/htdocs/img/icons/clocktime_white.svg b/bin/htdocs/img/icons/clocktime_white.svg new file mode 100644 index 0000000..be92d7a --- /dev/null +++ b/bin/htdocs/img/icons/clocktime_white.svg @@ -0,0 +1,14 @@ + + + + diff --git a/bin/htdocs/img/icons/club.svg b/bin/htdocs/img/icons/club.svg new file mode 100644 index 0000000..8a941e3 --- /dev/null +++ b/bin/htdocs/img/icons/club.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/club_white.svg b/bin/htdocs/img/icons/club_white.svg new file mode 100644 index 0000000..5325dc0 --- /dev/null +++ b/bin/htdocs/img/icons/club_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/clubs.svg b/bin/htdocs/img/icons/clubs.svg new file mode 100644 index 0000000..0a7d497 --- /dev/null +++ b/bin/htdocs/img/icons/clubs.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/clubs_white.svg b/bin/htdocs/img/icons/clubs_white.svg new file mode 100644 index 0000000..7184d28 --- /dev/null +++ b/bin/htdocs/img/icons/clubs_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/code.svg b/bin/htdocs/img/icons/code.svg new file mode 100644 index 0000000..c3b4f28 --- /dev/null +++ b/bin/htdocs/img/icons/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/cube.svg b/bin/htdocs/img/icons/cube.svg new file mode 100644 index 0000000..31b3129 --- /dev/null +++ b/bin/htdocs/img/icons/cube.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/cube_white.svg b/bin/htdocs/img/icons/cube_white.svg new file mode 100644 index 0000000..9a78edf --- /dev/null +++ b/bin/htdocs/img/icons/cube_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/cubelight.svg b/bin/htdocs/img/icons/cubelight.svg new file mode 100644 index 0000000..ff786d4 --- /dev/null +++ b/bin/htdocs/img/icons/cubelight.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/cubelight_white.svg b/bin/htdocs/img/icons/cubelight_white.svg new file mode 100644 index 0000000..c7965b6 --- /dev/null +++ b/bin/htdocs/img/icons/cubelight_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/dashboard.svg b/bin/htdocs/img/icons/dashboard.svg new file mode 100644 index 0000000..c5f36cc --- /dev/null +++ b/bin/htdocs/img/icons/dashboard.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/dashboard_white.svg b/bin/htdocs/img/icons/dashboard_white.svg new file mode 100644 index 0000000..c6a7dda --- /dev/null +++ b/bin/htdocs/img/icons/dashboard_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/download.svg b/bin/htdocs/img/icons/download.svg new file mode 100644 index 0000000..eb20956 --- /dev/null +++ b/bin/htdocs/img/icons/download.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/download_white.svg b/bin/htdocs/img/icons/download_white.svg new file mode 100644 index 0000000..100cebf --- /dev/null +++ b/bin/htdocs/img/icons/download_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/duplicate.svg b/bin/htdocs/img/icons/duplicate.svg new file mode 100644 index 0000000..cebaad8 --- /dev/null +++ b/bin/htdocs/img/icons/duplicate.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/duplicate_white.svg b/bin/htdocs/img/icons/duplicate_white.svg new file mode 100644 index 0000000..a643c74 --- /dev/null +++ b/bin/htdocs/img/icons/duplicate_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/edit.svg b/bin/htdocs/img/icons/edit.svg new file mode 100644 index 0000000..c0bb9ac --- /dev/null +++ b/bin/htdocs/img/icons/edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/edit_white.svg b/bin/htdocs/img/icons/edit_white.svg new file mode 100644 index 0000000..bbbe89f --- /dev/null +++ b/bin/htdocs/img/icons/edit_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/file.svg b/bin/htdocs/img/icons/file.svg new file mode 100644 index 0000000..6df51bd --- /dev/null +++ b/bin/htdocs/img/icons/file.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/file/dir.png b/bin/htdocs/img/icons/file/dir.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e3c0f7a86c11aa1fcf421ea51a3af8b34d1afa GIT binary patch literal 6937 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 literal 0 HcmV?d00001 diff --git a/bin/htdocs/img/icons/file/doc.png b/bin/htdocs/img/icons/file/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..8e43190813bc7f09fad8d4cc8d5998249b1ffa7e GIT binary patch literal 6455 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 b>>2zY@w+S`gh`U%00000NkvXXu0mjfe506! literal 0 HcmV?d00001 diff --git a/bin/htdocs/img/icons/file/xls.png b/bin/htdocs/img/icons/file/xls.png new file mode 100644 index 0000000000000000000000000000000000000000..ceabc7d00786e914f82fd171b155f6a12460fe10 GIT binary patch literal 6065 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 UUWti#UWNdQvZ}DJ(&nN61KZCx`Tzg` literal 0 HcmV?d00001 diff --git a/bin/htdocs/img/icons/file/xlsx.png b/bin/htdocs/img/icons/file/xlsx.png new file mode 100644 index 0000000000000000000000000000000000000000..ceabc7d00786e914f82fd171b155f6a12460fe10 GIT binary patch literal 6065 zcmb7H^-~*MuuYI4#exTS0>zBy^M^y zqKpiktGkPhy`wb%pb(Rn;iauLPZ~9j5JIS@5X7cUIM`{TDBvO#lDXJ2Y zFl|?uMshhOA9OXiL?*e8AvOZ2QMZosX-!>F_xo&G|!n9q3Si7+f9R|M6BID;TFppLlJ%KRO}K)*J(fa{@qh1gyH&*GrS$$f0DR_|L^VW)achZtvNVZ{m9ZPX%eM1`NCa_00I~vzvKi2-#0zalKsTX0@N0O#&)oJW68>2BCbq zsUBw>M*de>*7zdleBrMl!yaSn)+d`wtQ!d;gq`up<`A-N%$rueP8O>$xMHN_fXikb z#9vhq08Lrq+VaqP=g4W50_6+k-0%UcD*QA%nc~(T87CUX?;jg6AS9*b2xPWiv){XObQBL+G0F!;7diz7vs5v(v_Isx%UVs}-o4=`M z-#Ulw%j%^iV`X500~`0w@m&F4kc^rCxMt__@m~w?^Hkv!IIoPUkh6_%IjnDJY~A%1 zXR9FUh8E+|lZF)hkEt`7J53fgT>h5sZAPQf5K%OGmUN`#O+oeze(z)Hd}~I`!VP#L zLm#D#o#FFGAlFhemwLsK(FQP;}9uRP@9Y9tRbx)FV2bHKBt*IN_0>EEIMUjF=qq&*$u7(mP0bz7x#KDb)S%|FF%;=1bal1AUtA-fJ8G2PA4-&^*usA ziEv{{3N}oFY#~haPV|SYc?`=82)fjta_{in zUmLt#k#=S&p#Q_#rBTSP&yEH?A=Z644TZBCYj~GO>j`LIXd8dYtko~_hPf%6RuY>2 zREVkR(=aU4E`e+BMou;G>CDTCXp6}B)Vs%>q5qX9=ID=Jms!(@h2BGLp;p@ARch8+ zt<#>(Wd_GJw&c3}-{B(br1N)1Z+N(sN*NZ6>0C?`>Ob}#tuEbct- z#B?}y)O0%cSY`xgURKr4Y<>3md^)2vy)Yv;y;8|P9WafYZm#sI{DYLV&$JJB*nEF5 zDO`OD$8$;?raH<^5sBJfnhk$7D!?e9XLp38n#i4gyse|Dam9|yeQscI!v!)ESc(uPBZLgHB*j)M+$J_h-CZg7f{%Re1 z{Lvd1ns1)*`Zd1d67h#Es39onN$`mhXb4;i-U_ai9PCaH36Lr+M3l4StF{_{3d2>V9&z#FFPdFLF8^alMEK-yU8oQVZE^Ab-XmLE^IwH!) zaKUg%IsV1Ht;W>KlFllw^g(4M|8>@SzGm{7b~mZ^i~NeairKPG)fXy@1y^k1EC_Mb zPsy2X+6v%utb4vj{&T*l`jPtB`qJUtPlv{W%-DpltYzlozPI-a%#Tk8_rboK@?~#i zXr-RB2#H=Rty3?7cDy#O@+ppy^ z6z?2x84YO+Z?ty^f;Mn*aQnA%*_fy$>rQ4D*Ifqg8^w{t%JvHhwm5!Xj9!4w3AflE zl~<|IDtj}NDc2~!RQltx<=lCbKB|{)7O;@gVEt{R$Z=eEM0ag=e{rdq8mh-N&P}^W z^Bv)VVI}`F@srr6gAR2IJ&oqLZ_3}54I#$!Cf4eWje7x}N|y==dMbW3HizX4zuSG< zYY$H6kh&E*dWP4|wdTj8zFl`?ppwYgfXo1qdm2GGp{tS1 zfYHR!QO;~m>l)YUQqMEv|af^`6K25mQW5pt@C% zE0ONGx4XNEv_dHR9_Pl0d(?1uxSTjn%%5-jkLT@PAH4Bdx%^l6VvH=&^qt8;+oo%! zM|WW12F5+DD2N&)7DW}+#w})Y1j!fjUyr>{N9rMJ^V>;X52uFyC9myk{B~JUXrV{^ zY`@*ny{p-7_HZ6wGVmY^Xx_}9Ld4!@UsDDOJk*)&(TPj!iHn|?_k@XAE!DBUv3|M; z?AW2dwdfBYgPk)j$`7&xuyVgKz4891IGdVP(f{V&3M9#zDv z6$GMQho9fO0VDUHH6+MVSsn&>`p*gx6{*h%maBq+2LSMb=syPnvUACwK@7N}iY&$k z79Ji24$7E{z%vAa%j&~rT%4S&o#6l(cWVo{^*cH*d$=8)yrPP_UI-o;0D!Zk2$RzG zUO3FN_a>I57<`%$muG=Qs?vcm3A@q$CTWp{d!8B^tQio1)eSNjQId0p(vt{K=n2Tw z(TM2_3*9+}iclEX89wdEB{Al@w-j24*tpx4SGQlGvVd|EQ(IGbFN5+QwFfVzYpYk9 zoqv#rwHqSt^6cja6U(uRF}Wmdc_h)8K%1kPB00Bzg~S#8+3(TNG+>-@=xC)|DU6a| zM?rh8!7;@N1k$94NA`jEJaq&RC75H_+h?5^GgRHfAzwABu0*ceco;>A4W{w#cdZHI zu6?D#Tcy)o7r(M;h}Ek{ASTrZu_KpdP?}~r6ubSyA%)G`0=X)2$**QcC1fBR7#z-D z48owlup&PY%G%7)4^dl^HCOXD4y!RoJRbE@c5Jzi)cA4z zD7P7$?_^~ogyAOu400$T8jxE}RkAnIT2N!Y^TDcxFRlluOU4_STrya!p>6fdPj2;= zSa$hXY7f+0`frAXP)BEerdmYx`D*o@RMt6j$RYDd>Po=i-AiBkSIo~%GUbp9xeGi$D6|a9 z##U5SpIEIywdx7C=p{6ikdA zRIqf%W110EHZW___TxYw4>h;*v4RH4^jBtjCmZb5UMEnj^zgyPw(VG&Yp^MsHo6v3 zN-{4iu8@oIH6jX|j^hj7yQtnFpzqJWwR&9=q+P8eE?u`ua-xp9`!%DS^CH`I^bV{z zELw;@li|$L7w&ASQl;sT@S-78oDj5uBPIq+p1lMKAG7(etjk{ub5l+sZH@9DQnnXA zAWd3){<_bWZGcJhCjZ8-%u-_@c{xUQAW%QzQFCke^DNxO;Y`2qcqw%0KSQcffYhtOsmk>Ez55vekzHgqxk`!P9kjp z=6=K~nN8u?*@;tjB&V&yZcDRzaiM3u7?9Zax0S?5Cz8VKeR#%s@ZqxrRC0 z!Sg~Bo$)>~$0zfj4oh?#dtCq=#kclRo;79C{YjdG`Q1lAo}E2v9u zyJ{7XY;;pL%-vXeucYD)IJv8+2J7~&`OL&*wJ@SrxO3S>=Dave4==236y;MSf1&|*D)85N6uJ!(Ak4M(1=;{CMz~0~i4Ce=s;Bu^GyA9N+glV@k zR%{Opwu!lA9on7eu_kC3u2-Nc`K{-+xQfA#SI*fe zT744JY@~#LKr-VR&}V+l=W2{jS%>jmTBBIlTsUdfl-h#0KW|$SZn4~`2jm0D$9-k= z9Mmj*O|re@Kmx-#Tp~LyK*XF?|G^B7+8;1?9W>3p#b4%mkzyCDMkYnxI|&nLOTRz? zyWGFwgz>+1<_K)&+jIXtw9m-fh(>L5;79wZMkL#f<+TI>W+%eRB|VO(Y9BBva6j%J zbvf_XGI{<=5|D%@9_gY`%QIFbZ;Ha%tg{!=ZdCY$x{$xEMOh)^UT@})rPk8v`8 z`jEZ$(DsiS{bJClNsa5ruY9dn8;=g#N}FVJ!klJ{-HY#wdP1?p$Tsw=xm0_@(8QZ0 zKE(t%XD7&k6WpGbM{@^W!ilZUR!9P?15Vd!ipZAQhf0GNhBMd*2`>1AB3B0_X|3PS zprQq*3e}n~%tmA`JLDoy~EOjNGLO*KOn-g3r zIEm1?=1gctv7EO%K^w$q`*!#gp*hBQudJg);9R*8`!ae9tfF41sahclJeX<`_x1E%zrF=# zE(T%0OCG<{dBF+-I3^l@2@2FL>#RBqn40u>5XgK$*s*cH5X8^TwulGit`Vt~Bs%!MpCXoE}5p&^ksi>Z#r*P}8Fw;Er#JDz$^9d>Qo*bPK!~ z{a3;zXlN27sPo|zA4<9-AFCS%C57-uf>qpZ8c}|IKbZ7jMe{0nZ-MH>{Kl$(6+W77 zXM`V=7(j-{*wxZ)-$HCDrTIIE?xUE1&O|t0B+0TCm|28YvDNMYQfI{4V;TD+I$>9z zf8zE6Il?Nx+Fge#oa+baTp1lB?@dETF4IV{LD_z!*qY3d-u4I2s;%bxYGj*kNB`BL%c4m4Xbq7ya5xza zQnT9nAShB4O^SZPD6X$hMQ9oz%z!|NMG|_Jfh_GpEAF;T3-^ao; zHsU2XVVDvY5w;~$!CO)jTI6KI!St`m-Wo8Q`$VV}C>l45YnfYqOpYY&p(iCK+q(S< z`!`zf7Z_-ziV5u&mXBZvR$wHtI6APN{4WZzs_0-H|TcZfK$A;oJOfscS zl=!RJ2!e_r(T^FpdB1-^D``>|FZ=iZ1Z|$FvYHX+cAcM9;xYlQ@Sn&VaTXfa5r`c6 z9R_3HBHdw7QS^Hka+N)P(pG76+GHIk0DF9q^)eJ5YhMeINAK-6Ik#{-l|(F50nKQT zorqz&os)i#xCe=mt0=TgZh+q)!ek9t<+eX%u4!D5#R8N3i2t&4^lXweZ$h9Ld@U_r z9l-9pvJ86JHA&<7sWSef>QO{piUX%79=LaA{DNPdG&KR0+V62q@xvga~;qs zEQyyy2K>L7`ii9R*A20~BNJ}6u$AjrQP0ic zP_B~#`uq34)2{_c@jp$J!($@cLRfJf`zu2`N+tl2@FoiUEESb3i8wQWfervzD2pgp z*gYi#Y%;wTocr4sqs2-x^j7ZMm`ky2q!x;KMaq$1mXnwuijv$mq z3Cz)@tMoVU!%?sOZS~lJLl9WrVU}J{ur1PkZ`c64sw){9AKqX#M1M~JiFrb$o|@KG UUWti#UWNdQvZ}DJ(&nN61KZCx`Tzg` literal 0 HcmV?d00001 diff --git a/bin/htdocs/img/icons/file_white.svg b/bin/htdocs/img/icons/file_white.svg new file mode 100644 index 0000000..3e04bda --- /dev/null +++ b/bin/htdocs/img/icons/file_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/folder.svg b/bin/htdocs/img/icons/folder.svg new file mode 100644 index 0000000..f1f6e4a --- /dev/null +++ b/bin/htdocs/img/icons/folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/folder_white.svg b/bin/htdocs/img/icons/folder_white.svg new file mode 100644 index 0000000..25baa23 --- /dev/null +++ b/bin/htdocs/img/icons/folder_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/globe.svg b/bin/htdocs/img/icons/globe.svg new file mode 100644 index 0000000..9af64dc --- /dev/null +++ b/bin/htdocs/img/icons/globe.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/globe_white.svg b/bin/htdocs/img/icons/globe_white.svg new file mode 100644 index 0000000..f0c2dea --- /dev/null +++ b/bin/htdocs/img/icons/globe_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/inbox.svg b/bin/htdocs/img/icons/inbox.svg new file mode 100644 index 0000000..034e942 --- /dev/null +++ b/bin/htdocs/img/icons/inbox.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/inbox_white.svg b/bin/htdocs/img/icons/inbox_white.svg new file mode 100644 index 0000000..1d98ae9 --- /dev/null +++ b/bin/htdocs/img/icons/inbox_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/library.svg b/bin/htdocs/img/icons/library.svg new file mode 100644 index 0000000..0a917f3 --- /dev/null +++ b/bin/htdocs/img/icons/library.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/library_white.svg b/bin/htdocs/img/icons/library_white.svg new file mode 100644 index 0000000..3928fdd --- /dev/null +++ b/bin/htdocs/img/icons/library_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/license.svg b/bin/htdocs/img/icons/license.svg new file mode 100644 index 0000000..54f0fec --- /dev/null +++ b/bin/htdocs/img/icons/license.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/license_white.svg b/bin/htdocs/img/icons/license_white.svg new file mode 100644 index 0000000..2563f36 --- /dev/null +++ b/bin/htdocs/img/icons/license_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/list.svg b/bin/htdocs/img/icons/list.svg new file mode 100644 index 0000000..ea3f0e2 --- /dev/null +++ b/bin/htdocs/img/icons/list.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/list_white.svg b/bin/htdocs/img/icons/list_white.svg new file mode 100644 index 0000000..b57b752 --- /dev/null +++ b/bin/htdocs/img/icons/list_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/logout.svg b/bin/htdocs/img/icons/logout.svg new file mode 100644 index 0000000..da64de0 --- /dev/null +++ b/bin/htdocs/img/icons/logout.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/logout_white.svg b/bin/htdocs/img/icons/logout_white.svg new file mode 100644 index 0000000..3feb1b7 --- /dev/null +++ b/bin/htdocs/img/icons/logout_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/menu.svg b/bin/htdocs/img/icons/menu.svg new file mode 100644 index 0000000..1a247ab --- /dev/null +++ b/bin/htdocs/img/icons/menu.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/menu_white.svg b/bin/htdocs/img/icons/menu_white.svg new file mode 100644 index 0000000..222cc94 --- /dev/null +++ b/bin/htdocs/img/icons/menu_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/newspaper.svg b/bin/htdocs/img/icons/newspaper.svg new file mode 100644 index 0000000..420b45a --- /dev/null +++ b/bin/htdocs/img/icons/newspaper.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/newspaper_white.svg b/bin/htdocs/img/icons/newspaper_white.svg new file mode 100644 index 0000000..472b389 --- /dev/null +++ b/bin/htdocs/img/icons/newspaper_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/numberlist.svg b/bin/htdocs/img/icons/numberlist.svg new file mode 100644 index 0000000..33ac90c --- /dev/null +++ b/bin/htdocs/img/icons/numberlist.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/numberlist_white.svg b/bin/htdocs/img/icons/numberlist_white.svg new file mode 100644 index 0000000..e98d4aa --- /dev/null +++ b/bin/htdocs/img/icons/numberlist_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/package.svg b/bin/htdocs/img/icons/package.svg new file mode 100644 index 0000000..0b6a94d --- /dev/null +++ b/bin/htdocs/img/icons/package.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/package_white.svg b/bin/htdocs/img/icons/package_white.svg new file mode 100644 index 0000000..9a40a7b --- /dev/null +++ b/bin/htdocs/img/icons/package_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/pictures.svg b/bin/htdocs/img/icons/pictures.svg new file mode 100644 index 0000000..97bb690 --- /dev/null +++ b/bin/htdocs/img/icons/pictures.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bin/htdocs/img/icons/pictures_white.svg b/bin/htdocs/img/icons/pictures_white.svg new file mode 100644 index 0000000..9142d7f --- /dev/null +++ b/bin/htdocs/img/icons/pictures_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/bin/htdocs/img/icons/plus.svg b/bin/htdocs/img/icons/plus.svg new file mode 100644 index 0000000..08e85b5 --- /dev/null +++ b/bin/htdocs/img/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/plus_white.svg b/bin/htdocs/img/icons/plus_white.svg new file mode 100644 index 0000000..22714fe --- /dev/null +++ b/bin/htdocs/img/icons/plus_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/remove.svg b/bin/htdocs/img/icons/remove.svg new file mode 100644 index 0000000..e459477 --- /dev/null +++ b/bin/htdocs/img/icons/remove.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/remove_white.svg b/bin/htdocs/img/icons/remove_white.svg new file mode 100644 index 0000000..77e856e --- /dev/null +++ b/bin/htdocs/img/icons/remove_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/squares.svg b/bin/htdocs/img/icons/squares.svg new file mode 100644 index 0000000..8e084a0 --- /dev/null +++ b/bin/htdocs/img/icons/squares.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/squares_white.svg b/bin/htdocs/img/icons/squares_white.svg new file mode 100644 index 0000000..489f802 --- /dev/null +++ b/bin/htdocs/img/icons/squares_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/target.svg b/bin/htdocs/img/icons/target.svg new file mode 100644 index 0000000..72b5eb0 --- /dev/null +++ b/bin/htdocs/img/icons/target.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/target_white.svg b/bin/htdocs/img/icons/target_white.svg new file mode 100644 index 0000000..b02c6c4 --- /dev/null +++ b/bin/htdocs/img/icons/target_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/user.svg b/bin/htdocs/img/icons/user.svg new file mode 100644 index 0000000..37b4e3d --- /dev/null +++ b/bin/htdocs/img/icons/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/img/icons/user_white.svg b/bin/htdocs/img/icons/user_white.svg new file mode 100644 index 0000000..78d94ca --- /dev/null +++ b/bin/htdocs/img/icons/user_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/htdocs/js/admin.js b/bin/htdocs/js/admin.js new file mode 100644 index 0000000..e43b9d9 --- /dev/null +++ b/bin/htdocs/js/admin.js @@ -0,0 +1,78 @@ +var admin = { + current_dataset: {}, + loadapp: function(appident){ + console.log(appident); + console.log(location.origin + '/app/' + appident + '/index.html'); + location.href=location.origin + '/app/' + appident + '/index.html'; + }, + loadpage: function(modulepage,modulename){ + console.log(admin.current_dataset); + console.log("Load module:" + modulepage); + if (modulename){ + document.getElementById("modulename").innerHTML = modulename; + } + var pm = []; + for (var i in admin.current_dataset){ + pm.push(i + "=" + encodeURIComponent(admin.current_dataset[i])); + } + if (pm.length > 0){ + modulepage = modulepage + "?" + pm.join("&"); + } + console.log(modulepage); + document.getElementById("moduleframe").setAttribute('src',modulepage); + }, + sidebarclick: function(modulepage,modulename){ + admin.ladpage(modulepage,modulename); + }, + logout: function(){ + req.reqdata("POST",location.href,{"logout":"1"},admin.reloadpage); + + }, + reloadpage(page){ + location.href=location.href; + + }, + getdatasets: function(){ + req.reqdata("POST","db.cgi",{"db":app,"type":"array","sql":"select * from datastores;"},admin.loaddatasets); + }, + loaddatasets: function(data){ + console.log(data); + var gdt = document.getElementById('globaldatasets'); + gdt.innerHTML = ''; + if (data && data.sqldata){ + var opts = ';' + for (var i in data.sqldata){ + opts += ''; + } + gdt.innerHTML = opts; + } + if (admin.current_dataset.db){ + + }else { + admin.current_dataset["db"]=gdt.value; + } + console.log(admin.current_dataset); + } +} + +function reload_page(){ + location.href=location.href; +} + +function closeSidebar(){ + document.getElementById("sidebar").style.display = "none"; + document.getElementById("main").style.margin = "0 0 0 0"; + document.getElementById("modulename").style.setProperty("margin-left","0px"); +} + +function openSidebar(){ + document.getElementById("sidebar").style.display = "block"; + document.getElementById("main").style.setProperty("margin-left","210px"); + document.getElementById("modulename").style.setProperty("margin-left","150px"); +} + +document.addEventListener("DOMContentLoaded", function() { + if (app && app != ""){ + //initpage() + } +}); \ No newline at end of file diff --git a/bin/htdocs/js/admin_ht.js b/bin/htdocs/js/admin_ht.js new file mode 100644 index 0000000..751b0e4 --- /dev/null +++ b/bin/htdocs/js/admin_ht.js @@ -0,0 +1,249 @@ +var admin = { + lastrow: null, + lastpage: null, + lasttracktable: null, + currentrowdata: null, + loadpage: function (pagename){ + //disable all first + admin.lastrow = null; + document.getElementById(admin.lastpage).style.display = 'none'; + if (pagename == 'page_track'){ + document.getElementById("select_table").style.display = 'inline'; + + document.getElementById("page_track").style.display = 'block'; + admin.change_tracktable(); + + } else if (pagename == 'page_staff'){ + document.getElementById("page_staff").style.display = 'block'; + admin.loadtable_staff(); + }else if (pagename == 'page_exportdata'){ + document.getElementById("page_exportdata").style.display = 'block'; + } else if (pagename == 'page_sysconfig'){ + sysconfig.showsection(sysconfig.lastsection); + document.getElementById("page_sysconfig").style.display = 'block'; + + } + admin.lastpage=pagename; + }, + change_tracktable: function(){ + document.getElementById("cmb_trackdate").style.display = 'none'; + document.getElementById("cmb_trackmonth").style.display = 'none'; + document.getElementById("select_staff").style.display = 'none'; + if (admin.lasttracktable != null){ + document.getElementById(admin.lasttracktable).style.display = 'none'; + } + var tablesel = document.getElementById("select_table").value; + //console.log(tablesel); + document.getElementById('table_' + tablesel).style.display = 'block'; + admin.lasttracktable = 'table_' + tablesel; + if (tablesel == "trackbyday"){ + document.getElementById('cmb_trackdate').style.display = 'inline'; + admin.loadtable_trackbyday(); + }else if (tablesel == "trackbystaff"){ + document.getElementById("cmb_trackmonth").style.display = 'inline'; + document.getElementById("select_staff").style.display = 'inline'; + admin.loadtable_trackbystaff(); + } else { + admin.loadtable_trackincomplete(); + } + }, + loadtable_staff: function(){ + admin.lastrow = null; + document.getElementById("table_staff_tbody").innerHTML=""; + var xq = {"type":"querysorted","sql":"select st.id,st.prename,st.surname,st.pin,st.disabled,st.blocked, co.startdate, co.weekhours from staff st left join contract co on (st.id=co.idstaff) order by st.surname,st.prename,st.id;"}; + var tbldata = req.reqdata('POST','sqlite/query',xq,null); + var ntbldata = ''; + for (var i in tbldata.sqldata){ + var row = ''; + //row += ''; + row += ''; + row += ''; + row += ''; + row += 'h'; + row += ''; + row += ''; + row += ''; + row += ''; + row += ''; + ntbldata += row; + } + document.getElementById("table_staff_tbody").innerHTML=ntbldata; + }, + loadtable_trackbyday: function(){ + admin.lastrow = null; + document.getElementById("table_trackbyday_tbody").innerHTML=""; + var trackdate = document.getElementById("cmb_trackdate").value; + //console.log("trackdate" + trackdate); + var xq = {"type":"querysorted","sql":"select hr.id,co.idstaff,st.prename,st.surname,hr.stamp_in, hr.stamp_out from staff st left join contract co on (st.id=co.idstaff) left join (select id,idstaff,stamp_in,stamp_out from hours where date(stamp_in) = date('"+trackdate +"')) hr on (st.id=hr.idstaff) where st.disabled is null and co.startdate <= date('"+ trackdate +"') order by st.surname,st.prename,co.idstaff;"}; + var tbldata = req.reqdata('POST','sqlite/query',xq,null); + var ntbldata = ''; + for (var i in tbldata.sqldata){ + var row=''; + row += ''+tbldata.sqldata[i].surname+' '+tbldata.sqldata[i].prename+''; + row += ''; + row += ''; + row +=''; + ntbldata += row; + } + document.getElementById("table_trackbyday_tbody").innerHTML=ntbldata; + }, + loadtable_trackbystaff: function(){ + admin.lastrow = null; + document.getElementById("table_trackbystaff_tbody").innerHTML=""; + var trackdate = document.getElementById("cmb_trackmonth").value; + var staffid = document.getElementById("select_staff").value; + var bdate = new Date(trackdate + "-01"); + var edate = new Date(bdate.getFullYear(),bdate.getMonth()+1,1); + var sqldays = new Array(); + var cdate2 = new Date(); + for (var cdate2=bdate;cdate2<=edate;cdate2.setDate(cdate2.getDate() +1)){ + sqldays.push ("SELECT date('" + cdate2.toISOString().substring(0,10) +"') as daydate"); + } + var sqlret = sqldays.join(' UNION ALL '); + + var sql = "select md.daydate,hr.id,hr.stamp_in,hr.stamp_out,hr.idstaff from (" + sqlret +") md left join (select * from hours where idstaff='"+staffid+"' and date(stamp_in) between date('"+trackdate+"-01') and date('"+trackdate+"-01','+1 month','-1 day')) hr on (date(hr.stamp_in)= md.daydate);"; + var xq = {"type":"querysorted","sql":sql}; + var tbldata = req.reqdata('POST','sqlite/query',xq,null); + var ntbldata = ''; + +// var cdate = new Date(bdate); +// +// while (cdate <= enddate){ +// console.log("cdate:" + cdate.toISOString()); +// cdate.setDate(cdate.getDate() + 1); +// } + for (var i in tbldata.sqldata){ + + var row=''; + row += ''; + row += ''; + row += ''; + row +=''; + ntbldata += row; + } + document.getElementById("table_trackbystaff_tbody").innerHTML=ntbldata; + }, + loadtable_trackincomplete: function(){ + admin.lastrow = null; + document.getElementById("table_trackincomplete_tbody").innerHTML=""; + var xq = {"type":"querysorted","sql":"select hr.id,hr.idstaff,st.prename,st.surname,hr.stamp_in,hr.stamp_out from hours hr left join staff st on (hr.idstaff=st.id) where stamp_out is null order by hr.stamp_in,st.surname,st.prename,st.id; "}; + var tbldata = req.reqdata('POST','sqlite/query',xq,null); + var ntbldata = ''; + for (var i in tbldata.sqldata){ + + var row=''; + row += ''; + row += ''+tbldata.sqldata[i].surname+' '+tbldata.sqldata[i].prename+''; + row += ''; + row += ''; + row +=''; + ntbldata += row; + } + document.getElementById("table_trackincomplete_tbody").innerHTML=ntbldata; + }, + deleteRow: function(table,id){ + + var xq = {"type":"exec","sql":"delete from "+ table+" WHERE id='"+ id +"';"}; + var ret = req.reqdata('POST','sqlite/exec',xq,null); + if (ret){ + admin.loadpage(admin.lastpage); + } + }, + addRow: function(){ + + }, + export_data: function(){ + + }, + save_config: function(){ + + }, + changeData: function(field){ + var dbfield = field.id.split("_"); + + var where=[]; + for (var i in admin.currentrowdata){ + where.push( i + "='" +admin.currentrowdata[i] + "'"); + } + var sql = ""; + var value= "'" + field.value + "'"; + if (field.type == "date"){ + value= "date('"+ field.value+"')"; + } else if (field.type == "number"){ + value= field.value; + } else if (field.type == "checkbox"){ + if (field.checked == true){ + value= "'1'"; + } else { + value= "null"; + } + + } + if (field.value == ''){ + value = "null"; + } + if (where.length > 0 ){ + sql = "UPDATE " + dbfield[0] +" SET " + dbfield[1] + "=" + value + " WHERE "+ where.join(" AND ") +";"; + } else { + sql = "INSERT INTO " + dbfield[0] + " (" + dbfield[1] + ") VALUES (" + value + ");"; + } + console.log(sql); + var xu = {"type":"exec","sql":sql}; + var tbldata = req.reqdata('POST','sqlite/query',xu,req.asyncNoEvent); + //console.log(field.type); + //console.log(field.id + " " + field.tagName + " " + field.type); + + }, + + load_select_staff: function(selected){ + document.getElementById("select_staff").innerHTML=''; + var xq = {"type":"querysorted","sql":"select id,prename,surname from staff order by surname,prename,id"}; + var cmbdata = req.reqdata('POST','sqlite/query',xq,null); + var tcmbdata = ''; + for (var i in cmbdata.sqldata){ + tcmbdata += ''; + } + document.getElementById("select_staff").innerHTML=tcmbdata; + }, + setRowEditable: function(row){ + //console.log("set Editable!"); + if (row == admin.lastrow){ + return false; + } + if (admin.lastrow != null){ + var lins = admin.lastrow.getElementsByTagName('input'); + for (var z=0;z < lins.length; z++){ + //console.log("YUppi " + z); + document.getElementById(lins[z].id).setAttribute('disabled',true); + } + } + admin.currentrowdata = row.dataset; + var ins = row.getElementsByTagName('input'); + for (var z=0;z < ins.length; z++){ + //console.log("Yeah " + z); + if (document.getElementById(ins[z].id).getAttribute('readonly') == null){ + document.getElementById(ins[z].id).removeAttribute('disabled'); + } + + } + + ////console.log(row.dataset); + admin.lastrow = row; + return true; + } + } +window.onload = function() { + //console.log('window - onload'); + admin.lastpage = 'page_track'; + admin.loadpage('page_track'); + var cdate = new Date(); + //console.log(cdate.toISOString().substring(0,10)); + document.getElementById("cmb_trackdate").value = cdate.toISOString().substring(0,10); + document.getElementById("cmb_trackmonth").value = cdate.toISOString().substring(0,7); + admin.load_select_staff(null); + var nav = navigator.userAgent + + /*if (nav.indexOf("Chrome/65") == -1){ + location.href='/supported.html'; + }*/s +};s \ No newline at end of file diff --git a/bin/htdocs/js/fieldsave.js b/bin/htdocs/js/fieldsave.js new file mode 100644 index 0000000..bf317a0 --- /dev/null +++ b/bin/htdocs/js/fieldsave.js @@ -0,0 +1,48 @@ +var fsaveelements = document.querySelectorAll("input.fieldsave"); +for (var i = 0; i < fsaveelements.length; i++) { + fsaveelements[i].addEventListener('blur', function (event) { + savefield(event.currentTarget.id); + }, false); +} + +function savefield(obj){ + // console.log("save"); + var field = {"ident":obj.id}; + //var obj = document.getElementById(objid); + var fieldname = obj.getAttribute('name'); + var xsp = fieldname.split("_"); + // console.log(xsp); + // console.log(xsp[0] + "_id"); + var identfield = document.getElementById("id"); + field["ident_" + xsp[0] + "_id"] = identfield.value; + if (obj.tagName == 'TEXTAREA'){ + field[obj.getAttribute('name')] = obj.innerHTML; + } else if (obj.tagName == "SELECT"){ + field[obj.getAttribute('name')] = obj.value; + } else if ((obj.getAttribute('type') == "checkbox")){ + if ($("#" +objid).prop('checked')){ + field[obj.getAttribute('name')] = obj.value; + } else { + field[obj.getAttribute('name')] = ""; + } + + } else if (obj.getAttribute('type') == "file") { + if (obj.value != ""){ + alert("file save TODO!") + return false; + } + } else { + field[obj.getAttribute('name')] = obj.value; + } + + field["fn"] = "savefield"; + // console.log(field); + + req.reqdata("POST","index.cgi",field,fieldsaved); + return false; +} + +function fieldsaved(data){ + console.log("field saved"); + // console.log(data); +} \ No newline at end of file diff --git a/bin/htdocs/js/formsave.js b/bin/htdocs/js/formsave.js new file mode 100644 index 0000000..cd98192 --- /dev/null +++ b/bin/htdocs/js/formsave.js @@ -0,0 +1,193 @@ +function saveform(frmid,aftercallback){ + var flds=getformcontent(frmid,null); + flds["fn"] ="saveform"; + + //console.log(flds); + if (aftercallback){ + req.reqdata("POST","index.cgi",flds,aftercallback); + formsaved({}); + } + else { + req.reqdata("POST","index.cgi",flds,formsaved); + } + return false; +} + +function formsaved(data){ + var sb = document.getElementById("snackbar"); + sb.className="show w3-green"; + sb.innerHTML = 'Les données ont été sauvegarder!'; + setTimeout(function(){ sb.className = sb.className.replace("show w3-green", ""); }, 3000); + return false; +} + +function showsnackbar(xclass,xmessage){ + var sb = document.getElementById("snackbar"); + sb.className="show " + xclass; + sb.innerHTML = xmessage; + setTimeout(function(){ sb.className = sb.className.replace(sb.className, ""); }, 3000); + return false; +} + +function getformcontent(frmid,dataflds){ + var frm = document.getElementById("frm_" + frmid); + var flds = []; + if (dataflds){ + flds = dataflds; + } + + for (var i = 0; i < frm.elements.length; i++) { + var field = frm.elements[i]; + //console.log("field:" + field.id + " Name:" + field.getAttribute("name")); + if (field.tagName == "INPUT" || field.tagName == "SELECT" || field.tagName == "TEXTAREA"){ + if (field.classList.contains("tagedit")){ + var fvalue=field.value.trim(); + var ndata = null; + if (fvalue != ""){ + ndata = fvalue.split(","); + } + + flds[field.getAttribute("name")] = ndata; + }else if (field.tagName == "TEXTAREA" ){ + if (field.classList.contains("richeditarea")){ + flds[field.getAttribute("name")] = tinymce.get(field.id).getContent(); + } else { + flds[field.getAttribute("name")] = field.innerHTML; + } + + }else if (field.type == "checkbox" ){ + if (field.checked){ + flds[field.getAttribute("name")] = "1"; + } else { + flds[field.getAttribute("name")] = ""; + } + + } + else { + if (field.tagName == "SELECT" && field.multiple == true){ + var opts = field.selectedOptions; + var vals = []; + for (var o in opts){ + if (opts[o].value){ + vals.push(opts[o].value); + } + } + if (vals.length > 0) { + flds[field.getAttribute("name")] = vals; + } else { + flds[field.getAttribute("name")] = ""; + } + + } else { + flds[field.getAttribute("name")] = field.value; + } + + } + + } + } + return flds; +} + +function cleanform(frmname){ + //console.log("Clean Form: " + frmname); + var frm = document.getElementById("frm_" + frmname); + + for (var f in frm){ + //console.log(frm[f].id); + if (frm[f] && frm[f].id){ + if (frm[f].tagName == 'INPUT'){ + //console.log("is INPUT" + frm[f].id + " type:" + frm[f].type + " class:" + frm[f].classList); + if (frm[f].type == "checkbox"){ + frm[f].checked = false; + } else if (frm[f].classList.contains("datefield")){ + if (frm[f]._flatpickr){ frm[f]._flatpickr.clear(); } + } else if (frm[f].classList.contains("choices__input")){ + if (choice[frmname][frm[f].id]){ + choice[frmname][frm[f].id].removeActiveItems(); + } + } else { + frm[f].value = ""; + } + } + if (frm[f].tagName == 'SELECT'){ + //console.log("is INPUT" + frm[f].id + " multiple:" + frm[f].multiple + " class:" + frm[f].classList); + if (frm[f].multiple == true){ + if (frm[f].classList.contains("choices__input")){ + choice[frmname][frm[f].id].removeActiveItems(); + } + } else { + frm[f].value = ""; + } + + } + if (frm[f].tagName == 'TEXTAREA'){ + //console.log("is INPUT" + frm[f].id + " class:" + frm[f].classList); + if (frm[f].classList.contains("richeditarea")){ + tinymce.get(frm[f].id).setContent(""); + } else { + frm[f].innerHTML = ""; + } + } + } + } + return false; +} + +function fillformbydataclass(dataclass,data,readonly = false){ + //console.log(data); + var frm = document.querySelectorAll('.data_'+ dataclass); + if (data){ + for (var f in frm){ + console.log(frm[f].id + "=>" + data[frm[f].id]); + if (data[frm[f].id]){ + console.log(frm[f].id + " => " + data[frm[f].id]); + if (readonly){ frm[f].readonly = true;} + if (frm[f].tagName == 'INPUT'){ + if (frm[f].type == "checkbox"){ + if (data[frm[f].id] == "1"){ + frm[f].checked = true; + } else { + frm[f].checked = false; + } + } else if (frm[f].classList.contains("datefield")){ + frm[f]._flatpickr.setDate(data[frm[f].id]); + } else if (frm[f].classList.contains("choices__input")){ + if ((data[frm[f].id] != null) && (data[frm[f].id] != '[""]')){ + choice[dataclass][frm[f].id].setValue(JSON.parse(data[frm[f].id])); + } + } else { + frm[f].value=data[frm[f].id]; + } + } + if (frm[f].tagName == 'SELECT'){ + if (frm[f].classList.contains("choices__input")){ + if (frm[f].multiple == true){ + //console.log(data[frm[f].id]); + choice[dataclass][frm[f].id].setChoiceByValue(JSON.parse(data[frm[f].id])); + }else { + choice[dataclass][frm[f].id].setChoiceByValue(data[frm[f].id]); + } + } else { + frm[f].value=data[frm[f].id]; + } + + } + } + + } + } +} + +function fillselectlist(obj,data,vidcol,vvalcol){ + var sellist = []; + obj.clearStore(); + sellist.push({value:"",label:""}); + if (data){ + for (var i in data){ + sellist.push({value:data[i][vidcol],label:data[i][vvalcol]}); + } + } + obj.setChoices(sellist, 'value', 'label', true); + return false; +} \ No newline at end of file diff --git a/bin/htdocs/js/moduleglobal.js b/bin/htdocs/js/moduleglobal.js new file mode 100644 index 0000000..1855b24 --- /dev/null +++ b/bin/htdocs/js/moduleglobal.js @@ -0,0 +1,24 @@ +document.addEventListener("DOMContentLoaded", function() { + console.log( "Iframe "+ location.pathname.substring(location.pathname.lastIndexOf("/")) +" ready!" ); + mpref.loadconfig(); + initpage(); +}); + +var mpref ={ + cfg: null, + getSearchParams: function (k){ + //alert(location.href); + var p={}; + console.log("params =>" + location.search); + location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){p[k]=v}); + return k?p[k]:p; + }, + loadconfig: function(){ + this.cfg = this.getSearchParams(); + //var page = location.pathname.substring(location.pathname.lastIndexOf("/")); + //page = page.replace(/\.html/,''); + //apppref.getpreference(page); + //appdb.dbfile = this.cfg.dbfile; + //appdb.url = decodeURIComponent(this.cfg.serviceurl) + 'sqlite/' + decodeURIComponent(this.cfg.dbfile); + } +} diff --git a/bin/htdocs/js/request.js b/bin/htdocs/js/request.js new file mode 100644 index 0000000..a303a86 --- /dev/null +++ b/bin/htdocs/js/request.js @@ -0,0 +1,149 @@ +var api = location.origin+'/api/'; +// if (location.pathname.indexOf('modules') > 0){ +// api = location.origin + location.pathname.substring(0, location.pathname.indexOf('module')) + 'api/'; +// } +console.log(api); +var req = { + multipartform: function(url,frmdata,callback=null){ + var ret = null; + var rdata = null; + var async = false; + if (callback){ + async=true; + } + + var request = new XMLHttpRequest(); + + console.log(frmdata); + var sendurl = api + url; + console.log("Multipart sending URL: " + "POST" + " => " +sendurl); + request.open("POST", sendurl, true); + request.onload = function(){ + if (request.status >= 200 && request.status <= 400){ + //console.log("Status returned: " + request.status + "resp:" + request.getResponseHeader("Content-Type")); + if (request.getResponseHeader("Content-Type").indexOf('application/json') == 0){ + var xparse = JSON.parse(request.responseText); + ret = xparse.result; + //console.log(ret); + } + else { + ret = request.responseText; + } + if (async){ + callback(ret); + } + } else { + alert("ServerERROR:" + request.status + "\n" + request.responseText); + } + }; + request.onerror = function(){ + alert("Connection ERROR!\n" + url); + }; + + request.setRequestHeader('Content-Type','multipart/form-data'); + request.send(frmdata); + return ret; + }, + reqdata: function(method,url,data,callback=null){ + + var ret = null; + var rdata = null; + var async = false; + if (callback){ + async=true; + } + + var request = new XMLHttpRequest(); + if (typeof data == 'object'){ + var xdata = []; + for (var i in data){ + var value = ''; + if (typeof(data[i]) == 'object'){ + value = encodeURIComponent(JSON.stringify(data[i])); + } else { + value = encodeURIComponent(data[i]); + } + xdata.push(i + "=" + value); + } + rdata = xdata.join("&"); + }else { + rdata = data; + } + //console.log(rdata); + //console.log("Data to send: " + decodeURIComponent(rdata)); + var sendurl = api + url; + if (method.toUpperCase() == 'GET'){ + sendurl = sendurl + '?' + rdata; + } + console.log("sending URL: " + method + " => " +sendurl + '?' + rdata); + request.open(method.toUpperCase(), sendurl, true); + request.onload = function(){ + if (request.status >= 200 && request.status <= 400){ + // console.log("Status returned: " + request.status + "resp:" + request.getResponseHeader("Content-Type")); + if (request.getResponseHeader("Content-Type").indexOf('application/json') == 0){ + //console.log(xparse); + var xparse = JSON.parse(request.responseText); + ret = xparse.result; + //console.log(ret); + } + // else if (request.getResponseHeader("Content-Type").indexOf('application/vnd.ms-excel') == 0){ + // var filename = ""; + // var disposition = request.getResponseHeader('Content-Disposition'); + // if (disposition && disposition.indexOf('attachment') !== -1) { + // var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; + // var matches = filenameRegex.exec(disposition); + // if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, ''); + // } + // var type = request.getResponseHeader('Content-Type'); + // var blob = new Blob([this.response], { type: type }); + // var URL = window.URL; + // var downloadUrl = URL.createObjectURL(blob); + // if (filename) { + // var a = document.createElement("a"); + // if (typeof a.download === 'undefined') { + // window.location = downloadUrl; + // } else { + // a.href = downloadUrl; + // a.download = filename; + // document.body.appendChild(a); + // a.click(); + // } + // } else { + // window.location = downloadUrl; + // } + //setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); + // } + else { + ret = request.responseText; + console.log("TEXT returned:" + ret); + } + ////console.log("data returned: " + request.responseText); + if (async){ + callback(ret); + } + + } else { + //console.log("ServerERROR: " + request.status + "\n" + request.responseText); + alert("ServerERROR:" + request.status + "\n" + request.responseText); + } + }; + request.onerror = function(){ + //console.log("ERROR: connection ERROR\n" + url); + alert("Connection ERROR!\n" + url); + }; + if (method.toUpperCase() == 'POST'){ + request.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8'); + request.send(rdata); + } else { + //request.withCredentials = true; + request.send(); + } + return ret; + }, + asyncNoEvent: function(data){ + console.log("query done"); + console.log(data); + console.log("done"); + } + +} \ No newline at end of file diff --git a/bin/htdocs/js/sysconfig.js b/bin/htdocs/js/sysconfig.js new file mode 100644 index 0000000..4dd7b82 --- /dev/null +++ b/bin/htdocs/js/sysconfig.js @@ -0,0 +1,149 @@ +var sysconfig={ + lastsection: null, + showsection: function(){ + var sectionsel = document.getElementById("select_sysconfig").value; + if (sysconfig.lastsection != null){ + document.getElementById(sysconfig.lastsection).style.display = 'none'; + document.getElementById(sectionsel).style.display = 'block'; + sysconfig.lastsection = sectionsel; + } else { + document.getElementById("sysexport").style.display = 'block'; + sysconfig.lastsection = "sysexport"; + } + console.log(sysconfig.lastsection); + if (sysconfig.lastsection == 'sysaccess'){ + req.reqdata("GET",'app/getaccess','',sysconfig.getSystemUser); + } else if (sysconfig.lastsection == 'syssync'){ + req.reqdata("GET",'app/preferences/hourtrax','',sysconfig.getSyncData); + } else if (sysconfig.lastsection == 'sysexport'){ + var xa = {"type":"querysorted","sql":"select distinct strftime('%Y-%m',stamp_in) as exportmonth from hours order by stamp_in DESC;"}; + req.reqdata("POST",'sqlite/query',xa,sysconfig.setExportConfig); + } else if (sysconfig.lastsection == 'syssystem' ){ + req.reqdata("GET",'system/getconfig','',sysconfig.getSystemConfig); + } + + }, + setExportConfig: function(data){ + console.log("setExportConfig"); + console.log(data); + document.getElementById('cmb_exportmonth').innerHTML = ""; + var expm=[]; + if (data.sqldata){ + for (var m in data.sqldata){ + expm.push(''); + } + } + document.getElementById('cmb_exportmonth').innerHTML = expm.join(''); + }, + getSyncData: function(data){ + console.log("getSyncData"); + console.log(data); + var section = document.getElementById("syssync"); + var elements = section.querySelectorAll('input'); + if ((data) && (data.sync)){ + elements.forEach( function (index, value) { + var ident = index.id.substring(14); + if (data.sync[ident] != null){ + index.value=data.sync[ident]; + } + }); + } + elements = section.querySelectorAll('textarea'); + elements.forEach( function (index, value) { + var ident = index.id.substring(14); + if (data.sync[ident] != null){ + index.innerHTML=data.sync[ident]; + } + }); + }, + setSyncData: function(){ + var section = document.getElementById("syssync"); + var elements = section.querySelectorAll('input'); + var syncdata={ "sync":{}}; + elements.forEach( function (index, value) { + var ident = index.id.substring(14); + syncdata.sync[ident] = ((index.value)?index.value:null); + }); + elements = section.querySelectorAll('textarea'); + elements.forEach( function (index, value) { + var ident = index.id.substring(14); + syncdata.sync[ident] = ((index.value)?index.value:null); + }); + console.log(syncdata); + req.reqdata("POST",'app/preferences/hourtrax',syncdata,req.asyncNoEvent); + }, + getSystemUser: function(data){ + console.log(data); + document.getElementById("sysconfig_user").value = data.login; + }, + setSystemUser: function(){ + var pwd1 = document.getElementById("sysconfig_pwd1").value; + var pwd2 = document.getElementById("sysconfig_pwd2").value; + var user = document.getElementById("sysconfig_user").value; + if (user == ""){ + alert("Nom du utilisateur requis!"); + return; + } + if (pwd1 != pwd2){ + alert("les mot de passe ne sont pas identiques"); + return; + } + if (pwd1.length < 8){ + alert("le mot de passe doit avoir au moin 8 charactères!"); + return; + } + var xa = {"login":user,"passwd":pwd1}; + req.reqdata('POST','app/setaccess',xa,req.asyncNoEvent); + }, + setNetworkConfig: function(){ + var hostname = document.getElementById("sysconfig_hostname").value; + var wlanssid = document.getElementById("sysconfig_wlanssid").value; + var wlanpwd = document.getElementById("sysconfig_wlanpwd").value; + + var xa = {"hostname":{"hostname":hostname},"wlan":{"ssid":wlanssid,"passphrase":wlanpwd}}; + req.reqdata('POST','system/setconfig',xa,sysconfig.showsection); + }, + getSystemConfig: function(data){ + console.log(data); + var ssids = data.wlan.networks; + + var currentssid = ''; + if (data.wlan.ssid){ + currentssid = data.wlan.ssid; + } + //gethostname + document.getElementById("sysconfig_hostname").value = data.hostname; + document.getElementById("sysconfig_wlanssid").innerHTML =""; + var strssids =""; + for (var i in ssids){ + strssids += ''; + } + document.getElementById("sysconfig_wlanssid").innerHTML = strssids; + document.getElementById("sysconfig_wlanssid").value = currentssid; + document.getElementById("sysconfig_wlanpwd").value = ""; + document.getElementById("sysconfig_netstatus").innerHTML =""; + var netstatus = ""; + for (var e in data.activenet){ + if (e != "lo"){ + netstatus += ''+ e +':' + data.activenet[e]+ '
'; + } + } + document.getElementById("sysconfig_netstatus").innerHTML = netstatus; + }, + + exportdata: function(){ + var monthdate = document.getElementById('cmb_exportmonth').value; + + + var xa = {"type":"CSV","sql":"select st.surname || ' ' ||st.prename as name, hr.stamp_in as entry, hr.stamp_out as exit from hours hr left join staff st on (st.id=hr.idstaff) where hr.stamp_in between date('" + monthdate+"-01') and date('" + monthdate+"-01','+1 month','-1 day') and hr.stamp_out between date('" + monthdate+"-01') and date('" + monthdate+"-01','+1 month','-1 day');","filename":"export_" +monthdate+".csv"} + + req.reqdata("POST",'sqlite/export',xa,null); + + }, + shutdown: function(){ + req.reqdata("GET",'system/shutdown','',req.asyncNoEvent); + }, + restart:function(){ + req.reqdata("GET",'system/restart','',req.asyncNoEvent); + } +} \ No newline at end of file diff --git a/bin/htdocs/vendor/choices/base.css b/bin/htdocs/vendor/choices/base.css new file mode 100644 index 0000000..2d090bd --- /dev/null +++ b/bin/htdocs/vendor/choices/base.css @@ -0,0 +1,191 @@ +/*============================================= += Generic styling = +=============================================*/ +* { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +*, +*:before, +*:after { + box-sizing: border-box; +} + +html, +body { + position: relative; + margin: 0; + width: 100%; + height: 100%; +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 16px; + line-height: 1.4; + color: #FFFFFF; + background-color: #333; + overflow-x: hidden; +} + +label { + display: block; + margin-bottom: 8px; + font-size: 14px; + font-weight: 500; + cursor: pointer; +} + +p { + margin-top: 0; +} + +hr { + display: block; + margin: 30px 0; + border: 0; + border-bottom: 1px solid #eaeaea; + height: 1px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin-top: 0; + margin-bottom: 12px; + font-weight: 400; + line-height: 1.2; +} + +a, +a:visited, +a:focus { + color: #FFFFFF; + text-decoration: none; + font-weight: 600; +} + +.form-control { + display: block; + width: 100%; + background-color: #f9f9f9; + padding: 12px; + border: 1px solid #ddd; + border-radius: 2.5px; + font-size: 14px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + margin-bottom: 24px; +} + +h1, +.h1 { + font-size: 32px; +} + +h2, +.h2 { + font-size: 24px; +} + +h3, +.h3 { + font-size: 20px; +} + +h4, +.h4 { + font-size: 18px; +} + +h5, +.h5 { + font-size: 16px; +} + +h6, +.h6 { + font-size: 14px; +} + +p { + margin-bottom: 8px; +} + +label + p { + margin-top: -4px; +} + +.container { + display: block; + margin: auto; + max-width: 40em; + padding: 48px; +} + +@media (max-width: 620px) { + .container { + padding: 0; + } +} + +.section { + background-color: #FFFFFF; + padding: 24px; + color: #333; +} + +.section a, +.section a:visited, +.section a:focus { + color: #00bcd4; +} + +.logo { + display: block; + margin-bottom: 12px; +} + +.logo__img { + width: 100%; + height: auto; + display: inline-block; + max-width: 100%; + vertical-align: top; + padding: 6px 0; +} + +.visible-ie { + display: none; +} + +.push-bottom { + margin-bottom: 24px; +} + +.zero-bottom { + margin-bottom: 0; +} + +.zero-top { + margin-top: 0; +} + +.text-center { + text-align: center; +} + +.is-hidden { + display: none; +} + +[data-test-hook] { + margin-bottom: 24px; +} + +/*===== End of Section comment block ======*/ diff --git a/bin/htdocs/vendor/choices/base.min.css b/bin/htdocs/vendor/choices/base.min.css new file mode 100644 index 0000000..7992056 --- /dev/null +++ b/bin/htdocs/vendor/choices/base.min.css @@ -0,0 +1 @@ +*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{position:relative;margin:0;width:100%;height:100%}body{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:16px;line-height:1.4;color:#fff;background-color:#333;overflow-x:hidden}hr,label{display:block}label,p{margin-bottom:8px}label{font-size:14px;font-weight:500;cursor:pointer}p{margin-top:0}hr{margin:30px 0;border:0;border-bottom:1px solid #eaeaea;height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:12px;font-weight:400;line-height:1.2}a,a:focus,a:visited{color:#fff;text-decoration:none;font-weight:600}.form-control{display:block;width:100%;background-color:#f9f9f9;padding:12px;border:1px solid #ddd;border-radius:2.5px;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;margin-bottom:24px}.h1,h1{font-size:32px}.h2,h2{font-size:24px}.h3,h3{font-size:20px}.h4,h4{font-size:18px}.h5,h5{font-size:16px}.h6,h6{font-size:14px}label+p{margin-top:-4px}.container{display:block;margin:auto;max-width:40em;padding:48px}@media (max-width:620px){.container{padding:0}}.section{background-color:#fff;padding:24px;color:#333}.section a,.section a:focus,.section a:visited{color:#00bcd4}.logo{display:block;margin-bottom:12px}.logo__img{width:100%;height:auto;display:inline-block;max-width:100%;vertical-align:top;padding:6px 0}.visible-ie{display:none}.push-bottom{margin-bottom:24px}.zero-bottom{margin-bottom:0}.zero-top{margin-top:0}.text-center{text-align:center}.is-hidden{display:none}[data-test-hook]{margin-bottom:24px} \ No newline at end of file diff --git a/bin/htdocs/vendor/choices/choices.css b/bin/htdocs/vendor/choices/choices.css new file mode 100644 index 0000000..e3bc037 --- /dev/null +++ b/bin/htdocs/vendor/choices/choices.css @@ -0,0 +1,368 @@ +/*=============================== += Choices = +===============================*/ +.choices { + position: relative; + margin-bottom: 24px; + font-size: 16px; +} + +.choices:focus { + outline: none; +} + +.choices:last-child { + margin-bottom: 0; +} + +.choices.is-disabled .choices__inner, +.choices.is-disabled .choices__input { + background-color: #EAEAEA; + cursor: not-allowed; + user-select: none; +} + +.choices.is-disabled .choices__item { + cursor: not-allowed; +} + +.choices[data-type*="select-one"] { + cursor: pointer; +} + +.choices[data-type*="select-one"] .choices__inner { + padding-bottom: 7.5px; + +} + +.choices[data-type*="select-one"] .choices__input { + display: block; + width: 100%; + padding: 10px; + border-bottom: 1px solid #DDDDDD; + background-color: #FFFFFF; + margin: 0; +} + +.choices[data-type*="select-one"] .choices__button { + background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==); + padding: 0; + background-size: 8px; + position: absolute; + top: 50%; + right: 0; + margin-top: -10px; + margin-right: 25px; + height: 20px; + width: 20px; + /* border-radius: 10em; */ + opacity: .5; +} + +.choices[data-type*="select-one"] .choices__button:hover, .choices[data-type*="select-one"] .choices__button:focus { + opacity: 1; +} + +.choices[data-type*="select-one"] .choices__button:focus { + box-shadow: 0px 0px 0px 2px #00BCD4; +} + +.choices[data-type*="select-one"]:after { + content: ""; + height: 0; + width: 0; + border-style: solid; + border-color: #333333 transparent transparent transparent; + border-width: 5px; + position: absolute; + right: 11.5px; + top: 50%; + margin-top: -2.5px; + pointer-events: none; +} + +.choices[data-type*="select-one"].is-open:after { + border-color: transparent transparent #333333 transparent; + margin-top: -7.5px; +} + +.choices[data-type*="select-one"][dir="rtl"]:after { + left: 11.5px; + right: auto; +} + +.choices[data-type*="select-one"][dir="rtl"] .choices__button { + right: auto; + left: 0; + margin-left: 25px; + margin-right: 0; +} + +.choices[data-type*="select-multiple"] .choices__inner, +.choices[data-type*="text"] .choices__inner { + cursor: text; +} + +.choices[data-type*="select-multiple"] .choices__button, +.choices[data-type*="text"] .choices__button { + position: relative; + display: inline-block; + margin-top: 0; + margin-right: -4px; + margin-bottom: 0; + margin-left: 8px; + padding-left: 16px; + border-left: 1px solid #008fa1; + background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==); + background-size: 8px; + width: 8px; + line-height: 1; + opacity: .75; + border-radius: 0; +} + +.choices[data-type*="select-multiple"] .choices__button:hover, .choices[data-type*="select-multiple"] .choices__button:focus, +.choices[data-type*="text"] .choices__button:hover, +.choices[data-type*="text"] .choices__button:focus { + opacity: 1; +} + +.choices__inner { + display: inline-block; + vertical-align: top; + width: 100%; + background-color: #e8f0fe; + padding: 7.5px 7.5px 3.75px; + border: 1px solid #ccc; + /* border-radius: 2.5px; */ + /* font-size: 14px; */ + min-height: 44px; + overflow: hidden; + /* font-weight: bold; */ +} + +.is-focused .choices__inner, +.is-open .choices__inner { + border-color: #b7b7b7; +} + +.is-open .choices__inner { + /* border-radius: 2.5px 2.5px 0 0; */ +} + +.is-flipped.is-open .choices__inner { + /* border-radius: 0 0 2.5px 2.5px; */ +} + +.choices__list { + margin: 0; + padding-left: 0; + list-style: none; +} + +.choices__list--single { + display: inline-block; + padding: 4px 16px 4px 4px; + width: 100%; +} + +[dir="rtl"] .choices__list--single { + padding-right: 4px; + padding-left: 16px; +} + +.choices__list--single .choices__item { + width: 100%; +} + +.choices__list--multiple { + display: inline; +} + +.choices__list--multiple .choices__item { + display: inline-block; + vertical-align: middle; + /* border-radius: 20px; */ + padding: 4px 6px; + font-size: 16px; + height: 40px; + /* font-size: 12px; */ + /* font-weight: 500; */ + margin-right: 3.75px; + /* margin-bottom: 3.75px; */ + background-color: #607d8b; + border: 1px solid #607d8b; + color: #FFFFFF; + /* font-weightfont-weight: bold; */ + word-break: break-all; +} + +.choices__list--multiple .choices__item[data-deletable] { + padding-right: 5px; +} + +[dir="rtl"] .choices__list--multiple .choices__item { + margin-right: 0; + margin-left: 3.75px; +} + +.choices__list--multiple .choices__item.is-highlighted { + background-color: #00a5bb; + border: 1px solid #008fa1; +} + +.is-disabled .choices__list--multiple .choices__item { + background-color: #aaaaaa; + border: 1px solid #919191; +} + +.choices__list--dropdown { + display: none; + z-index: 1; + position: absolute; + width: 100%; + background-color: #FFFFFF; + border: 1px solid #DDDDDD; + top: 100%; + margin-top: -1px; + /* border-bottom-left-radius: 2.5px; */ + /* border-bottom-right-radius: 2.5px; */ + overflow: hidden; + word-break: break-all; +} + +.choices__list--dropdown.is-active { + display: block; +} + +.is-open .choices__list--dropdown { + border-color: #b7b7b7; +} + +.is-flipped .choices__list--dropdown { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: -1px; + /* border-radius: .25rem .25rem 0 0; */ +} + +.choices__list--dropdown .choices__list { + position: relative; + max-height: 300px; + overflow: auto; + -webkit-overflow-scrolling: touch; + will-change: scroll-position; +} + +.choices__list--dropdown .choices__item { + position: relative; + padding: 10px; + font-size: 14px; +} + +[dir="rtl"] .choices__list--dropdown .choices__item { + text-align: right; +} + +@media (min-width: 640px) { + .choices__list--dropdown .choices__item--selectable { + padding-right: 100px; + } + .choices__list--dropdown .choices__item--selectable:after { + content: attr(data-select-text); + font-size: 12px; + opacity: 0; + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + } + [dir="rtl"] .choices__list--dropdown .choices__item--selectable { + text-align: right; + padding-left: 100px; + padding-right: 10px; + } + [dir="rtl"] .choices__list--dropdown .choices__item--selectable:after { + right: auto; + left: 10px; + } +} + +.choices__list--dropdown .choices__item--selectable.is-highlighted { + background-color: #f2f2f2; +} + +.choices__list--dropdown .choices__item--selectable.is-highlighted:after { + opacity: .5; +} + +.choices__item { + cursor: default; +} + +.choices__item--selectable { + cursor: pointer; +} + +.choices__item--disabled { + cursor: not-allowed; + user-select: none; + opacity: .5; +} + +.choices__heading { + /* font-weight: 600; */ + font-size: 12px; + padding: 10px; + border-bottom: 1px solid #f7f7f7; + color: gray; +} + +.choices__button { + text-indent: -9999px; + -webkit-appearance: none; + appearance: none; + border: 0; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + cursor: pointer; +} + +.choices__button:focus { + outline: none; +} + +.choices__input { + display: inline-block; + vertical-align: baseline; + background-color: #f9f9f9; + font-size: 14px; + margin-bottom: 5px; + border: 0; + border-radius: 0; + max-width: 100%; + padding: 4px 0 4px 2px; +} + +.choices__input:focus { + outline: 0; +} + +[dir="rtl"] .choices__input { + padding-right: 2px; + padding-left: 0; +} + +.choices__placeholder { + opacity: .5; +} + +.choices__input.is-hidden, +.choices[data-type*="select-one"] .choices__input.is-hidden, +.choices[data-type*="select-multiple"] .choices__input.is-hidden { + display: none; +} + +/*===== End of Choices ======*/ diff --git a/bin/htdocs/vendor/choices/choices.js b/bin/htdocs/vendor/choices/choices.js new file mode 100644 index 0000000..93e8b4e --- /dev/null +++ b/bin/htdocs/vendor/choices/choices.js @@ -0,0 +1,6787 @@ +(function webpackUniversalModuleDefinition(root, factory) { + //CommonJS2 + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + //AMD + else if(typeof define === 'function' && define.amd) + define([], factory); + //CommonJS + else if(typeof exports === 'object') + exports["Choices"] = factory(); + //Window + else + root["Choices"] = factory(); +})(window, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "/public/assets/scripts/"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 9); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.diff = exports.cloneObject = exports.existsInArray = exports.isIE11 = exports.fetchFromObject = exports.getWindowHeight = exports.dispatchEvent = exports.sortByScore = exports.sortByAlpha = exports.calcWidthOfInput = exports.strToEl = exports.sanitise = exports.isScrolledIntoView = exports.getAdjacentEl = exports.findAncestorByAttrName = exports.wrap = exports.isElement = exports.isType = exports.getType = exports.generateId = exports.generateChars = exports.getRandomNumber = void 0; + +var _this = void 0; + +var getRandomNumber = function getRandomNumber(min, max) { + return Math.floor(Math.random() * (max - min) + min); +}; + +exports.getRandomNumber = getRandomNumber; + +var generateChars = function generateChars(length) { + var chars = ''; + + for (var i = 0; i < length; i++) { + var randomChar = getRandomNumber(0, 36); + chars += randomChar.toString(36); + } + + return chars; +}; + +exports.generateChars = generateChars; + +var generateId = function generateId(element, prefix) { + var id = element.id || element.name && "".concat(element.name, "-").concat(generateChars(2)) || generateChars(4); + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = "".concat(prefix, "-").concat(id); + return id; +}; + +exports.generateId = generateId; + +var getType = function getType(obj) { + return Object.prototype.toString.call(obj).slice(8, -1); +}; + +exports.getType = getType; + +var isType = function isType(type, obj) { + return obj !== undefined && obj !== null && getType(obj) === type; +}; + +exports.isType = isType; + +var isElement = function isElement(element) { + return element instanceof Element; +}; + +exports.isElement = isElement; + +var wrap = function wrap(element) { + var wrapper = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.createElement('div'); + + if (element.nextSibling) { + element.parentNode.insertBefore(wrapper, element.nextSibling); + } else { + element.parentNode.appendChild(wrapper); + } + + return wrapper.appendChild(element); +}; + +exports.wrap = wrap; + +var findAncestorByAttrName = function findAncestorByAttrName(el, attr) { + var target = el; + + while (target) { + if (target.hasAttribute(attr)) { + return target; + } + + target = target.parentElement; + } + + return null; +}; + +exports.findAncestorByAttrName = findAncestorByAttrName; + +var getAdjacentEl = function getAdjacentEl(startEl, className) { + var direction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + + if (!startEl || !className) { + return; + } + + var parent = startEl.parentNode.parentNode; + var children = Array.from(parent.querySelectorAll(className)); + var startPos = children.indexOf(startEl); + var operatorDirection = direction > 0 ? 1 : -1; + return children[startPos + operatorDirection]; +}; + +exports.getAdjacentEl = getAdjacentEl; + +var isScrolledIntoView = function isScrolledIntoView(el, parent) { + var direction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + + if (!el) { + return; + } + + var isVisible; + + if (direction > 0) { + // In view from bottom + isVisible = parent.scrollTop + parent.offsetHeight >= el.offsetTop + el.offsetHeight; + } else { + // In view from top + isVisible = el.offsetTop >= parent.scrollTop; + } + + return isVisible; +}; + +exports.isScrolledIntoView = isScrolledIntoView; + +var sanitise = function sanitise(value) { + if (!isType('String', value)) { + return value; + } + + return value.replace(/&/g, '&').replace(/>/g, '&rt;').replace(/".concat(sanitise(value), "
")); + testEl.style.position = 'absolute'; + testEl.style.padding = '0'; + testEl.style.top = '-9999px'; + testEl.style.left = '-9999px'; + testEl.style.width = 'auto'; + testEl.style.whiteSpace = 'pre'; + + if (document.body.contains(input) && window.getComputedStyle) { + var inputStyle = window.getComputedStyle(input); + + if (inputStyle) { + testEl.style.fontSize = inputStyle.fontSize; + testEl.style.fontFamily = inputStyle.fontFamily; + testEl.style.fontWeight = inputStyle.fontWeight; + testEl.style.fontStyle = inputStyle.fontStyle; + testEl.style.letterSpacing = inputStyle.letterSpacing; + testEl.style.textTransform = inputStyle.textTransform; + testEl.style.padding = inputStyle.padding; + } + } + + document.body.appendChild(testEl); + requestAnimationFrame(function () { + if (value && testEl.offsetWidth !== input.offsetWidth) { + width = testEl.offsetWidth + 4; + } + + document.body.removeChild(testEl); + callback.call(_this, "".concat(width, "px")); + }); + } else { + callback.call(_this, "".concat(width, "px")); + } +}; + +exports.calcWidthOfInput = calcWidthOfInput; + +var sortByAlpha = function sortByAlpha(a, b) { + var labelA = "".concat(a.label || a.value).toLowerCase(); + var labelB = "".concat(b.label || b.value).toLowerCase(); + + if (labelA < labelB) { + return -1; + } + + if (labelA > labelB) { + return 1; + } + + return 0; +}; + +exports.sortByAlpha = sortByAlpha; + +var sortByScore = function sortByScore(a, b) { + return a.score - b.score; +}; + +exports.sortByScore = sortByScore; + +var dispatchEvent = function dispatchEvent(element, type) { + var customArgs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + var event = new CustomEvent(type, { + detail: customArgs, + bubbles: true, + cancelable: true + }); + return element.dispatchEvent(event); +}; + +exports.dispatchEvent = dispatchEvent; + +var getWindowHeight = function getWindowHeight() { + var body = document.body; + var html = document.documentElement; + return Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight); +}; + +exports.getWindowHeight = getWindowHeight; + +var fetchFromObject = function fetchFromObject(object, path) { + var index = path.indexOf('.'); + + if (index > -1) { + return fetchFromObject(object[path.substring(0, index)], path.substr(index + 1)); + } + + return object[path]; +}; + +exports.fetchFromObject = fetchFromObject; + +var isIE11 = function isIE11() { + return !!(navigator.userAgent.match(/Trident/) && navigator.userAgent.match(/rv[ :]11/)); +}; + +exports.isIE11 = isIE11; + +var existsInArray = function existsInArray(array, value) { + var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'value'; + return array.some(function (item) { + if (isType('String', value)) { + return item[key] === value.trim(); + } + + return item[key] === value; + }); +}; + +exports.existsInArray = existsInArray; + +var cloneObject = function cloneObject(obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +exports.cloneObject = cloneObject; + +var diff = function diff(a, b) { + var aKeys = Object.keys(a).sort(); + var bKeys = Object.keys(b).sort(); + return aKeys.filter(function (i) { + return bKeys.indexOf(i) < 0; + }); +}; + +exports.diff = diff; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SCROLLING_SPEED = exports.KEY_CODES = exports.ACTION_TYPES = exports.EVENTS = exports.DEFAULT_CONFIG = exports.DEFAULT_CLASSNAMES = void 0; + +var _utils = __webpack_require__(0); + +var DEFAULT_CLASSNAMES = { + containerOuter: 'choices', + containerInner: 'choices__inner', + input: 'choices__input', + inputCloned: 'choices__input--cloned', + list: 'choices__list', + listItems: 'choices__list--multiple', + listSingle: 'choices__list--single', + listDropdown: 'choices__list--dropdown', + item: 'choices__item', + itemSelectable: 'choices__item--selectable', + itemDisabled: 'choices__item--disabled', + itemChoice: 'choices__item--choice', + placeholder: 'choices__placeholder', + group: 'choices__group', + groupHeading: 'choices__heading', + button: 'choices__button', + activeState: 'is-active', + focusState: 'is-focused', + openState: 'is-open', + disabledState: 'is-disabled', + highlightedState: 'is-highlighted', + hiddenState: 'is-hidden', + flippedState: 'is-flipped', + loadingState: 'is-loading', + noResults: 'has-no-results', + noChoices: 'has-no-choices' +}; +exports.DEFAULT_CLASSNAMES = DEFAULT_CLASSNAMES; +var DEFAULT_CONFIG = { + items: [], + choices: [], + silent: false, + renderChoiceLimit: -1, + maxItemCount: -1, + addItems: true, + addItemFilterFn: null, + removeItems: true, + removeItemButton: false, + editItems: false, + duplicateItemsAllowed: true, + delimiter: ',', + paste: true, + searchEnabled: true, + searchChoices: true, + searchFloor: 1, + searchResultLimit: 4, + searchFields: ['label', 'value'], + position: 'auto', + resetScrollPosition: true, + shouldSort: true, + shouldSortItems: false, + sortFn: _utils.sortByAlpha, + placeholder: true, + placeholderValue: null, + searchPlaceholderValue: null, + prependValue: null, + appendValue: null, + renderSelectedChoices: 'auto', + loadingText: 'Loading...', + noResultsText: 'No results found', + noChoicesText: 'No choices to choose from', + itemSelectText: 'Press to select', + uniqueItemText: 'Only unique values can be added', + customAddItemText: 'Only values matching specific conditions can be added', + addItemText: function addItemText(value) { + return "Press Enter to add \"".concat((0, _utils.sanitise)(value), "\""); + }, + maxItemText: function maxItemText(maxItemCount) { + return "Only ".concat(maxItemCount, " values can be added"); + }, + itemComparer: function itemComparer(choice, item) { + return choice === item; + }, + fuseOptions: { + includeScore: true + }, + callbackOnInit: null, + callbackOnCreateTemplates: null, + classNames: DEFAULT_CLASSNAMES +}; +exports.DEFAULT_CONFIG = DEFAULT_CONFIG; +var EVENTS = { + showDropdown: 'showDropdown', + hideDropdown: 'hideDropdown', + change: 'change', + choice: 'choice', + search: 'search', + addItem: 'addItem', + removeItem: 'removeItem', + highlightItem: 'highlightItem', + highlightChoice: 'highlightChoice' +}; +exports.EVENTS = EVENTS; +var ACTION_TYPES = { + ADD_CHOICE: 'ADD_CHOICE', + FILTER_CHOICES: 'FILTER_CHOICES', + ACTIVATE_CHOICES: 'ACTIVATE_CHOICES', + CLEAR_CHOICES: 'CLEAR_CHOICES', + ADD_GROUP: 'ADD_GROUP', + ADD_ITEM: 'ADD_ITEM', + REMOVE_ITEM: 'REMOVE_ITEM', + HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM', + CLEAR_ALL: 'CLEAR_ALL' +}; +exports.ACTION_TYPES = ACTION_TYPES; +var KEY_CODES = { + BACK_KEY: 46, + DELETE_KEY: 8, + ENTER_KEY: 13, + A_KEY: 65, + ESC_KEY: 27, + UP_KEY: 38, + DOWN_KEY: 40, + PAGE_UP_KEY: 33, + PAGE_DOWN_KEY: 34 +}; +exports.KEY_CODES = KEY_CODES; +var SCROLLING_SPEED = 4; +exports.SCROLLING_SPEED = SCROLLING_SPEED; + +/***/ }), +/* 2 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global, module) {/* harmony import */ var _ponyfill_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* global window */ + + +var root; + +if (typeof self !== 'undefined') { + root = self; +} else if (typeof window !== 'undefined') { + root = window; +} else if (typeof global !== 'undefined') { + root = global; +} else if (true) { + root = module; +} else {} + +var result = Object(_ponyfill_js__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"])(root); +/* harmony default export */ __webpack_exports__["a"] = (result); + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(3), __webpack_require__(14)(module))) + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || new Function("return this")(); +} catch (e) { + // This works if the window reference is available + if (typeof window === "object") g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _utils = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var WrappedElement = +/*#__PURE__*/ +function () { + function WrappedElement(_ref) { + var element = _ref.element, + classNames = _ref.classNames; + + _classCallCheck(this, WrappedElement); + + Object.assign(this, { + element: element, + classNames: classNames + }); + + if (!(0, _utils.isElement)(element)) { + throw new TypeError('Invalid element passed'); + } + + this.isDisabled = false; + } + + _createClass(WrappedElement, [{ + key: "conceal", + value: function conceal() { + // Hide passed input + this.element.classList.add(this.classNames.input); + this.element.classList.add(this.classNames.hiddenState); // Remove element from tab index + + this.element.tabIndex = '-1'; // Backup original styles if any + + var origStyle = this.element.getAttribute('style'); + + if (origStyle) { + this.element.setAttribute('data-choice-orig-style', origStyle); + } + + this.element.setAttribute('aria-hidden', 'true'); + this.element.setAttribute('data-choice', 'active'); + } + }, { + key: "reveal", + value: function reveal() { + // Reinstate passed element + this.element.classList.remove(this.classNames.input); + this.element.classList.remove(this.classNames.hiddenState); + this.element.removeAttribute('tabindex'); // Recover original styles if any + + var origStyle = this.element.getAttribute('data-choice-orig-style'); + + if (origStyle) { + this.element.removeAttribute('data-choice-orig-style'); + this.element.setAttribute('style', origStyle); + } else { + this.element.removeAttribute('style'); + } + + this.element.removeAttribute('aria-hidden'); + this.element.removeAttribute('data-choice'); // Re-assign values - this is weird, I know + + this.element.value = this.element.value; + } + }, { + key: "enable", + value: function enable() { + this.element.removeAttribute('disabled'); + this.element.disabled = false; + this.isDisabled = false; + } + }, { + key: "disable", + value: function disable() { + this.element.setAttribute('disabled', ''); + this.element.disabled = true; + this.isDisabled = true; + } + }, { + key: "triggerEvent", + value: function triggerEvent(eventType, data) { + (0, _utils.dispatchEvent)(this.element, eventType, data); + } + }, { + key: "value", + get: function get() { + return this.element.value; + } + }]); + + return WrappedElement; +}(); + +exports.default = WrappedElement; + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.TEMPLATES = void 0; + +var _classnames = _interopRequireDefault(__webpack_require__(27)); + +var _utils = __webpack_require__(0); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var TEMPLATES = { + containerOuter: function containerOuter(globalClasses, direction, isSelectElement, isSelectOneElement, searchEnabled, passedElementType) { + var tabIndex = isSelectOneElement ? 'tabindex="0"' : ''; + var role = isSelectElement ? 'role="listbox"' : ''; + var ariaAutoComplete = ''; + + if (isSelectElement && searchEnabled) { + role = 'role="combobox"'; + ariaAutoComplete = 'aria-autocomplete="list"'; + } + + return (0, _utils.strToEl)("\n \n \n ")); + }, + containerInner: function containerInner(globalClasses) { + return (0, _utils.strToEl)("\n
\n ")); + }, + itemList: function itemList(globalClasses, isSelectOneElement) { + var _classNames; + + var localClasses = (0, _classnames.default)(globalClasses.list, (_classNames = {}, _defineProperty(_classNames, globalClasses.listSingle, isSelectOneElement), _defineProperty(_classNames, globalClasses.listItems, !isSelectOneElement), _classNames)); + return (0, _utils.strToEl)("\n
\n ")); + }, + placeholder: function placeholder(globalClasses, value) { + return (0, _utils.strToEl)("\n
\n ").concat(value, "\n
\n ")); + }, + item: function item(globalClasses, data, removeItemButton) { + var _classNames2; + + var ariaSelected = data.active ? 'aria-selected="true"' : ''; + var ariaDisabled = data.disabled ? 'aria-disabled="true"' : ''; + var localClasses = (0, _classnames.default)(globalClasses.item, (_classNames2 = {}, _defineProperty(_classNames2, globalClasses.highlightedState, data.highlighted), _defineProperty(_classNames2, globalClasses.itemSelectable, !data.highlighted), _defineProperty(_classNames2, globalClasses.placeholder, data.placeholder), _classNames2)); + + if (removeItemButton) { + var _classNames3; + + localClasses = (0, _classnames.default)(globalClasses.item, (_classNames3 = {}, _defineProperty(_classNames3, globalClasses.highlightedState, data.highlighted), _defineProperty(_classNames3, globalClasses.itemSelectable, !data.disabled), _defineProperty(_classNames3, globalClasses.placeholder, data.placeholder), _classNames3)); + return (0, _utils.strToEl)("\n \n ").concat(data.label, "\n Remove item\n \n \n ")); + } + + return (0, _utils.strToEl)("\n \n ").concat(data.label, "\n \n ")); + }, + choiceList: function choiceList(globalClasses, isSelectOneElement) { + var ariaMultiSelectable = !isSelectOneElement ? 'aria-multiselectable="true"' : ''; + return (0, _utils.strToEl)("\n \n \n ")); + }, + choiceGroup: function choiceGroup(globalClasses, data) { + var ariaDisabled = data.disabled ? 'aria-disabled="true"' : ''; + var localClasses = (0, _classnames.default)(globalClasses.group, _defineProperty({}, globalClasses.itemDisabled, data.disabled)); + return (0, _utils.strToEl)("\n \n
").concat(data.value, "
\n \n ")); + }, + choice: function choice(globalClasses, data, itemSelectText) { + var _classNames5; + + var role = data.groupId > 0 ? 'role="treeitem"' : 'role="option"'; + var localClasses = (0, _classnames.default)(globalClasses.item, globalClasses.itemChoice, (_classNames5 = {}, _defineProperty(_classNames5, globalClasses.itemDisabled, data.disabled), _defineProperty(_classNames5, globalClasses.itemSelectable, !data.disabled), _defineProperty(_classNames5, globalClasses.placeholder, data.placeholder), _classNames5)); + return (0, _utils.strToEl)("\n \n ").concat(data.label, "\n \n ")); + }, + input: function input(globalClasses) { + var localClasses = (0, _classnames.default)(globalClasses.input, globalClasses.inputCloned); + return (0, _utils.strToEl)("\n \n ")); + }, + dropdown: function dropdown(globalClasses) { + var localClasses = (0, _classnames.default)(globalClasses.list, globalClasses.listDropdown); + return (0, _utils.strToEl)("\n \n \n ")); + }, + notice: function notice(globalClasses, label) { + var _classNames6; + + var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; + var localClasses = (0, _classnames.default)(globalClasses.item, globalClasses.itemChoice, (_classNames6 = {}, _defineProperty(_classNames6, globalClasses.noResults, type === 'no-results'), _defineProperty(_classNames6, globalClasses.noChoices, type === 'no-choices'), _classNames6)); + return (0, _utils.strToEl)("\n
\n ").concat(label, "\n
\n ")); + }, + option: function option(data) { + return (0, _utils.strToEl)("\n \n ")); + } +}; +exports.TEMPLATES = TEMPLATES; +var _default = TEMPLATES; +exports.default = _default; + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); + +// EXTERNAL MODULE: ./node_modules/lodash-es/_freeGlobal.js +var _freeGlobal = __webpack_require__(8); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_root.js + + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = _freeGlobal["a" /* default */] || freeSelf || Function('return this')(); + +/* harmony default export */ var _root = (root); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_Symbol.js + + +/** Built-in value references. */ +var Symbol = _root.Symbol; + +/* harmony default export */ var _Symbol = (Symbol); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_getRawTag.js + + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var _getRawTag_hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Built-in value references. */ +var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = _getRawTag_hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +/* harmony default export */ var _getRawTag = (getRawTag); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_objectToString.js +/** Used for built-in method references. */ +var _objectToString_objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var _objectToString_nativeObjectToString = _objectToString_objectProto.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return _objectToString_nativeObjectToString.call(value); +} + +/* harmony default export */ var _objectToString = (objectToString); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_baseGetTag.js + + + + +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + +/** Built-in value references. */ +var _baseGetTag_symToStringTag = _Symbol ? _Symbol.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (_baseGetTag_symToStringTag && _baseGetTag_symToStringTag in Object(value)) + ? _getRawTag(value) + : _objectToString(value); +} + +/* harmony default export */ var _baseGetTag = (baseGetTag); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_overArg.js +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/* harmony default export */ var _overArg = (overArg); + +// CONCATENATED MODULE: ./node_modules/lodash-es/_getPrototype.js + + +/** Built-in value references. */ +var getPrototype = _overArg(Object.getPrototypeOf, Object); + +/* harmony default export */ var _getPrototype = (getPrototype); + +// CONCATENATED MODULE: ./node_modules/lodash-es/isObjectLike.js +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +/* harmony default export */ var lodash_es_isObjectLike = (isObjectLike); + +// CONCATENATED MODULE: ./node_modules/lodash-es/isPlainObject.js + + + + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + isPlainObject_objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var isPlainObject_hasOwnProperty = isPlainObject_objectProto.hasOwnProperty; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!lodash_es_isObjectLike(value) || _baseGetTag(value) != objectTag) { + return false; + } + var proto = _getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = isPlainObject_hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; +} + +/* harmony default export */ var lodash_es_isPlainObject = (isPlainObject); + +// EXTERNAL MODULE: ./node_modules/symbol-observable/es/index.js +var es = __webpack_require__(2); + +// CONCATENATED MODULE: ./node_modules/redux/es/createStore.js + + + +/** + * These are private action types reserved by Redux. + * For any unknown actions, you must return the current state. + * If the current state is undefined, you must return the initial state. + * Do not reference these action types directly in your code. + */ +var ActionTypes = { + INIT: '@@redux/INIT' + + /** + * Creates a Redux store that holds the state tree. + * The only way to change the data in the store is to call `dispatch()` on it. + * + * There should only be a single store in your app. To specify how different + * parts of the state tree respond to actions, you may combine several reducers + * into a single reducer function by using `combineReducers`. + * + * @param {Function} reducer A function that returns the next state tree, given + * the current state tree and the action to handle. + * + * @param {any} [preloadedState] The initial state. You may optionally specify it + * to hydrate the state from the server in universal apps, or to restore a + * previously serialized user session. + * If you use `combineReducers` to produce the root reducer function, this must be + * an object with the same shape as `combineReducers` keys. + * + * @param {Function} [enhancer] The store enhancer. You may optionally specify it + * to enhance the store with third-party capabilities such as middleware, + * time travel, persistence, etc. The only store enhancer that ships with Redux + * is `applyMiddleware()`. + * + * @returns {Store} A Redux store that lets you read the state, dispatch actions + * and subscribe to changes. + */ +};function createStore_createStore(reducer, preloadedState, enhancer) { + var _ref2; + + if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { + enhancer = preloadedState; + preloadedState = undefined; + } + + if (typeof enhancer !== 'undefined') { + if (typeof enhancer !== 'function') { + throw new Error('Expected the enhancer to be a function.'); + } + + return enhancer(createStore_createStore)(reducer, preloadedState); + } + + if (typeof reducer !== 'function') { + throw new Error('Expected the reducer to be a function.'); + } + + var currentReducer = reducer; + var currentState = preloadedState; + var currentListeners = []; + var nextListeners = currentListeners; + var isDispatching = false; + + function ensureCanMutateNextListeners() { + if (nextListeners === currentListeners) { + nextListeners = currentListeners.slice(); + } + } + + /** + * Reads the state tree managed by the store. + * + * @returns {any} The current state tree of your application. + */ + function getState() { + return currentState; + } + + /** + * Adds a change listener. It will be called any time an action is dispatched, + * and some part of the state tree may potentially have changed. You may then + * call `getState()` to read the current state tree inside the callback. + * + * You may call `dispatch()` from a change listener, with the following + * caveats: + * + * 1. The subscriptions are snapshotted just before every `dispatch()` call. + * If you subscribe or unsubscribe while the listeners are being invoked, this + * will not have any effect on the `dispatch()` that is currently in progress. + * However, the next `dispatch()` call, whether nested or not, will use a more + * recent snapshot of the subscription list. + * + * 2. The listener should not expect to see all state changes, as the state + * might have been updated multiple times during a nested `dispatch()` before + * the listener is called. It is, however, guaranteed that all subscribers + * registered before the `dispatch()` started will be called with the latest + * state by the time it exits. + * + * @param {Function} listener A callback to be invoked on every dispatch. + * @returns {Function} A function to remove this change listener. + */ + function subscribe(listener) { + if (typeof listener !== 'function') { + throw new Error('Expected listener to be a function.'); + } + + var isSubscribed = true; + + ensureCanMutateNextListeners(); + nextListeners.push(listener); + + return function unsubscribe() { + if (!isSubscribed) { + return; + } + + isSubscribed = false; + + ensureCanMutateNextListeners(); + var index = nextListeners.indexOf(listener); + nextListeners.splice(index, 1); + }; + } + + /** + * Dispatches an action. It is the only way to trigger a state change. + * + * The `reducer` function, used to create the store, will be called with the + * current state tree and the given `action`. Its return value will + * be considered the **next** state of the tree, and the change listeners + * will be notified. + * + * The base implementation only supports plain object actions. If you want to + * dispatch a Promise, an Observable, a thunk, or something else, you need to + * wrap your store creating function into the corresponding middleware. For + * example, see the documentation for the `redux-thunk` package. Even the + * middleware will eventually dispatch plain object actions using this method. + * + * @param {Object} action A plain object representing “what changed”. It is + * a good idea to keep actions serializable so you can record and replay user + * sessions, or use the time travelling `redux-devtools`. An action must have + * a `type` property which may not be `undefined`. It is a good idea to use + * string constants for action types. + * + * @returns {Object} For convenience, the same action object you dispatched. + * + * Note that, if you use a custom middleware, it may wrap `dispatch()` to + * return something else (for example, a Promise you can await). + */ + function dispatch(action) { + if (!lodash_es_isPlainObject(action)) { + throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.'); + } + + if (typeof action.type === 'undefined') { + throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?'); + } + + if (isDispatching) { + throw new Error('Reducers may not dispatch actions.'); + } + + try { + isDispatching = true; + currentState = currentReducer(currentState, action); + } finally { + isDispatching = false; + } + + var listeners = currentListeners = nextListeners; + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + + return action; + } + + /** + * Replaces the reducer currently used by the store to calculate the state. + * + * You might need this if your app implements code splitting and you want to + * load some of the reducers dynamically. You might also need this if you + * implement a hot reloading mechanism for Redux. + * + * @param {Function} nextReducer The reducer for the store to use instead. + * @returns {void} + */ + function replaceReducer(nextReducer) { + if (typeof nextReducer !== 'function') { + throw new Error('Expected the nextReducer to be a function.'); + } + + currentReducer = nextReducer; + dispatch({ type: ActionTypes.INIT }); + } + + /** + * Interoperability point for observable/reactive libraries. + * @returns {observable} A minimal observable of state changes. + * For more information, see the observable proposal: + * https://github.com/tc39/proposal-observable + */ + function observable() { + var _ref; + + var outerSubscribe = subscribe; + return _ref = { + /** + * The minimal observable subscription method. + * @param {Object} observer Any object that can be used as an observer. + * The observer object should have a `next` method. + * @returns {subscription} An object with an `unsubscribe` method that can + * be used to unsubscribe the observable from the store, and prevent further + * emission of values from the observable. + */ + subscribe: function subscribe(observer) { + if (typeof observer !== 'object') { + throw new TypeError('Expected the observer to be an object.'); + } + + function observeState() { + if (observer.next) { + observer.next(getState()); + } + } + + observeState(); + var unsubscribe = outerSubscribe(observeState); + return { unsubscribe: unsubscribe }; + } + }, _ref[es["a" /* default */]] = function () { + return this; + }, _ref; + } + + // When a store is created, an "INIT" action is dispatched so that every + // reducer returns their initial state. This effectively populates + // the initial state tree. + dispatch({ type: ActionTypes.INIT }); + + return _ref2 = { + dispatch: dispatch, + subscribe: subscribe, + getState: getState, + replaceReducer: replaceReducer + }, _ref2[es["a" /* default */]] = observable, _ref2; +} +// CONCATENATED MODULE: ./node_modules/redux/es/utils/warning.js +/** + * Prints a warning in the console if it exists. + * + * @param {String} message The warning message. + * @returns {void} + */ +function warning(message) { + /* eslint-disable no-console */ + if (typeof console !== 'undefined' && typeof console.error === 'function') { + console.error(message); + } + /* eslint-enable no-console */ + try { + // This error was thrown as a convenience so that if you enable + // "break on all exceptions" in your console, + // it would pause the execution at this line. + throw new Error(message); + /* eslint-disable no-empty */ + } catch (e) {} + /* eslint-enable no-empty */ +} +// CONCATENATED MODULE: ./node_modules/redux/es/combineReducers.js + + + + +function getUndefinedStateErrorMessage(key, action) { + var actionType = action && action.type; + var actionName = actionType && '"' + actionType.toString() + '"' || 'an action'; + + return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state. ' + 'If you want this reducer to hold no value, you can return null instead of undefined.'; +} + +function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) { + var reducerKeys = Object.keys(reducers); + var argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer'; + + if (reducerKeys.length === 0) { + return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.'; + } + + if (!lodash_es_isPlainObject(inputState)) { + return 'The ' + argumentName + ' has unexpected type of "' + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected argument to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"'); + } + + var unexpectedKeys = Object.keys(inputState).filter(function (key) { + return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key]; + }); + + unexpectedKeys.forEach(function (key) { + unexpectedKeyCache[key] = true; + }); + + if (unexpectedKeys.length > 0) { + return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('"' + reducerKeys.join('", "') + '". Unexpected keys will be ignored.'); + } +} + +function assertReducerShape(reducers) { + Object.keys(reducers).forEach(function (key) { + var reducer = reducers[key]; + var initialState = reducer(undefined, { type: ActionTypes.INIT }); + + if (typeof initialState === 'undefined') { + throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined. If you don\'t want to set a value for this reducer, ' + 'you can use null instead of undefined.'); + } + + var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.'); + if (typeof reducer(undefined, { type: type }) === 'undefined') { + throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined, but can be null.'); + } + }); +} + +/** + * Turns an object whose values are different reducer functions, into a single + * reducer function. It will call every child reducer, and gather their results + * into a single state object, whose keys correspond to the keys of the passed + * reducer functions. + * + * @param {Object} reducers An object whose values correspond to different + * reducer functions that need to be combined into one. One handy way to obtain + * it is to use ES6 `import * as reducers` syntax. The reducers may never return + * undefined for any action. Instead, they should return their initial state + * if the state passed to them was undefined, and the current state for any + * unrecognized action. + * + * @returns {Function} A reducer function that invokes every reducer inside the + * passed object, and builds a state object with the same shape. + */ +function combineReducers(reducers) { + var reducerKeys = Object.keys(reducers); + var finalReducers = {}; + for (var i = 0; i < reducerKeys.length; i++) { + var key = reducerKeys[i]; + + if (false) {} + + if (typeof reducers[key] === 'function') { + finalReducers[key] = reducers[key]; + } + } + var finalReducerKeys = Object.keys(finalReducers); + + var unexpectedKeyCache = void 0; + if (false) {} + + var shapeAssertionError = void 0; + try { + assertReducerShape(finalReducers); + } catch (e) { + shapeAssertionError = e; + } + + return function combination() { + var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var action = arguments[1]; + + if (shapeAssertionError) { + throw shapeAssertionError; + } + + if (false) { var warningMessage; } + + var hasChanged = false; + var nextState = {}; + for (var _i = 0; _i < finalReducerKeys.length; _i++) { + var _key = finalReducerKeys[_i]; + var reducer = finalReducers[_key]; + var previousStateForKey = state[_key]; + var nextStateForKey = reducer(previousStateForKey, action); + if (typeof nextStateForKey === 'undefined') { + var errorMessage = getUndefinedStateErrorMessage(_key, action); + throw new Error(errorMessage); + } + nextState[_key] = nextStateForKey; + hasChanged = hasChanged || nextStateForKey !== previousStateForKey; + } + return hasChanged ? nextState : state; + }; +} +// CONCATENATED MODULE: ./node_modules/redux/es/bindActionCreators.js +function bindActionCreator(actionCreator, dispatch) { + return function () { + return dispatch(actionCreator.apply(undefined, arguments)); + }; +} + +/** + * Turns an object whose values are action creators, into an object with the + * same keys, but with every function wrapped into a `dispatch` call so they + * may be invoked directly. This is just a convenience method, as you can call + * `store.dispatch(MyActionCreators.doSomething())` yourself just fine. + * + * For convenience, you can also pass a single function as the first argument, + * and get a function in return. + * + * @param {Function|Object} actionCreators An object whose values are action + * creator functions. One handy way to obtain it is to use ES6 `import * as` + * syntax. You may also pass a single function. + * + * @param {Function} dispatch The `dispatch` function available on your Redux + * store. + * + * @returns {Function|Object} The object mimicking the original object, but with + * every action creator wrapped into the `dispatch` call. If you passed a + * function as `actionCreators`, the return value will also be a single + * function. + */ +function bindActionCreators(actionCreators, dispatch) { + if (typeof actionCreators === 'function') { + return bindActionCreator(actionCreators, dispatch); + } + + if (typeof actionCreators !== 'object' || actionCreators === null) { + throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?'); + } + + var keys = Object.keys(actionCreators); + var boundActionCreators = {}; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var actionCreator = actionCreators[key]; + if (typeof actionCreator === 'function') { + boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); + } + } + return boundActionCreators; +} +// CONCATENATED MODULE: ./node_modules/redux/es/compose.js +/** + * Composes single-argument functions from right to left. The rightmost + * function can take multiple arguments as it provides the signature for + * the resulting composite function. + * + * @param {...Function} funcs The functions to compose. + * @returns {Function} A function obtained by composing the argument functions + * from right to left. For example, compose(f, g, h) is identical to doing + * (...args) => f(g(h(...args))). + */ + +function compose() { + for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { + funcs[_key] = arguments[_key]; + } + + if (funcs.length === 0) { + return function (arg) { + return arg; + }; + } + + if (funcs.length === 1) { + return funcs[0]; + } + + return funcs.reduce(function (a, b) { + return function () { + return a(b.apply(undefined, arguments)); + }; + }); +} +// CONCATENATED MODULE: ./node_modules/redux/es/applyMiddleware.js +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + + + +/** + * Creates a store enhancer that applies middleware to the dispatch method + * of the Redux store. This is handy for a variety of tasks, such as expressing + * asynchronous actions in a concise manner, or logging every action payload. + * + * See `redux-thunk` package as an example of the Redux middleware. + * + * Because middleware is potentially asynchronous, this should be the first + * store enhancer in the composition chain. + * + * Note that each middleware will be given the `dispatch` and `getState` functions + * as named arguments. + * + * @param {...Function} middlewares The middleware chain to be applied. + * @returns {Function} A store enhancer applying the middleware. + */ +function applyMiddleware() { + for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) { + middlewares[_key] = arguments[_key]; + } + + return function (createStore) { + return function (reducer, preloadedState, enhancer) { + var store = createStore(reducer, preloadedState, enhancer); + var _dispatch = store.dispatch; + var chain = []; + + var middlewareAPI = { + getState: store.getState, + dispatch: function dispatch(action) { + return _dispatch(action); + } + }; + chain = middlewares.map(function (middleware) { + return middleware(middlewareAPI); + }); + _dispatch = compose.apply(undefined, chain)(store.dispatch); + + return _extends({}, store, { + dispatch: _dispatch + }); + }; + }; +} +// CONCATENATED MODULE: ./node_modules/redux/es/index.js +/* concated harmony reexport createStore */__webpack_require__.d(__webpack_exports__, "createStore", function() { return createStore_createStore; }); +/* concated harmony reexport combineReducers */__webpack_require__.d(__webpack_exports__, "combineReducers", function() { return combineReducers; }); +/* concated harmony reexport bindActionCreators */__webpack_require__.d(__webpack_exports__, "bindActionCreators", function() { return bindActionCreators; }); +/* concated harmony reexport applyMiddleware */__webpack_require__.d(__webpack_exports__, "applyMiddleware", function() { return applyMiddleware; }); +/* concated harmony reexport compose */__webpack_require__.d(__webpack_exports__, "compose", function() { return compose; }); + + + + + + + +/* +* This is a dummy function to check if the function name has been altered by minification. +* If the function has been minified and NODE_ENV !== 'production', warn the user. +*/ +function isCrushed() {} + +if (false) {} + + + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return symbolObservablePonyfill; }); +function symbolObservablePonyfill(root) { + var result; + var Symbol = root.Symbol; + + if (typeof Symbol === 'function') { + if (Symbol.observable) { + result = Symbol.observable; + } else { + result = Symbol('observable'); + Symbol.observable = result; + } + } else { + result = '@@observable'; + } + + return result; +}; + + +/***/ }), +/* 8 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + +/* harmony default export */ __webpack_exports__["a"] = (freeGlobal); + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(3))) + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(10); + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _fuse = _interopRequireDefault(__webpack_require__(11)); + +var _deepmerge = _interopRequireDefault(__webpack_require__(12)); + +var _store = _interopRequireDefault(__webpack_require__(13)); + +var _components = __webpack_require__(20); + +var _constants = __webpack_require__(1); + +var _templates = __webpack_require__(5); + +var _choices = __webpack_require__(28); + +var _items = __webpack_require__(29); + +var _groups = __webpack_require__(30); + +var _misc = __webpack_require__(31); + +var _general = __webpack_require__(32); + +var _utils = __webpack_require__(0); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +/** + * Choices + * @author Josh Johnson + */ +var Choices = +/*#__PURE__*/ +function () { + function Choices() { + var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '[data-choice]'; + var userConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Choices); + + if ((0, _utils.isType)('String', element)) { + var elements = Array.from(document.querySelectorAll(element)); // If there are multiple elements, create a new instance + // for each element besides the first one (as that already has an instance) + + if (elements.length > 1) { + return this._generateInstances(elements, userConfig); + } + } + + this.config = _deepmerge.default.all([_constants.DEFAULT_CONFIG, Choices.userDefaults, userConfig], // When merging array configs, replace with a copy of the userConfig array, + // instead of concatenating with the default array + { + arrayMerge: function arrayMerge(destinationArray, sourceArray) { + return [].concat(sourceArray); + } + }); + var invalidConfigOptions = (0, _utils.diff)(this.config, _constants.DEFAULT_CONFIG); + + if (invalidConfigOptions.length) { + console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', ')); + } + + if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) { + this.config.renderSelectedChoices = 'auto'; + } // Retrieve triggering element (i.e. element with 'data-choice' trigger) + + + var passedElement = (0, _utils.isType)('String', element) ? document.querySelector(element) : element; + + if (!passedElement) { + return console.error('Could not find passed element or passed element was of an invalid type'); + } + + this._isTextElement = passedElement.type === 'text'; + this._isSelectOneElement = passedElement.type === 'select-one'; + this._isSelectMultipleElement = passedElement.type === 'select-multiple'; + this._isSelectElement = this._isSelectOneElement || this._isSelectMultipleElement; + + if (this._isTextElement) { + this.passedElement = new _components.WrappedInput({ + element: passedElement, + classNames: this.config.classNames, + delimiter: this.config.delimiter + }); + } else if (this._isSelectElement) { + this.passedElement = new _components.WrappedSelect({ + element: passedElement, + classNames: this.config.classNames + }); + } + + if (!this.passedElement) { + return console.error('Passed element was of an invalid type'); + } + + if (this.config.shouldSortItems === true && this._isSelectOneElement && !this.config.silent) { + console.warn("shouldSortElements: Type of passed element is 'select-one', falling back to false."); + } + + this.initialised = false; + this._store = new _store.default(this.render); + this._initialState = {}; + this._currentState = {}; + this._prevState = {}; + this._currentValue = ''; + this._canSearch = this.config.searchEnabled; + this._isScrollingOnIe = false; + this._highlightPosition = 0; + this._wasTap = true; + this._placeholderValue = this._generatePlaceholderValue(); + this._baseId = (0, _utils.generateId)(this.passedElement.element, 'choices-'); + this._direction = this.passedElement.element.getAttribute('dir') || 'ltr'; + this._idNames = { + itemChoice: 'item-choice' + }; // Assign preset choices from passed object + + this._presetChoices = this.config.choices; // Assign preset items from passed object first + + this._presetItems = this.config.items; // Then add any values passed from attribute + + if (this.passedElement.value) { + this._presetItems = this._presetItems.concat(this.passedElement.value.split(this.config.delimiter)); + } + + this._render = this._render.bind(this); + this._onFocus = this._onFocus.bind(this); + this._onBlur = this._onBlur.bind(this); + this._onKeyUp = this._onKeyUp.bind(this); + this._onKeyDown = this._onKeyDown.bind(this); + this._onClick = this._onClick.bind(this); + this._onTouchMove = this._onTouchMove.bind(this); + this._onTouchEnd = this._onTouchEnd.bind(this); + this._onMouseDown = this._onMouseDown.bind(this); + this._onMouseOver = this._onMouseOver.bind(this); + this._onFormReset = this._onFormReset.bind(this); + this._onAKey = this._onAKey.bind(this); + this._onEnterKey = this._onEnterKey.bind(this); + this._onEscapeKey = this._onEscapeKey.bind(this); + this._onDirectionKey = this._onDirectionKey.bind(this); + this._onDeleteKey = this._onDeleteKey.bind(this); // If element has already been initialised with Choices, fail silently + + if (this.passedElement.element.getAttribute('data-choice') === 'active') { + console.warn('Trying to initialise Choices on element already initialised'); + } // Let's go + + + this.init(); + } + /* ======================================== + = Public functions = + ======================================== */ + + + _createClass(Choices, [{ + key: "init", + value: function init() { + if (this.initialised) { + return; + } + + this._createTemplates(); + + this._createElements(); + + this._createStructure(); // Set initial state (We need to clone the state because some reducers + // modify the inner objects properties in the state) 🤢 + + + this._initialState = (0, _utils.cloneObject)(this._store.state); + + this._store.subscribe(this._render); + + this._render(); + + this._addEventListeners(); + + var shouldDisable = !this.config.addItems || this.passedElement.element.hasAttribute('disabled'); + + if (shouldDisable) { + this.disable(); + } + + this.initialised = true; + var callbackOnInit = this.config.callbackOnInit; // Run callback if it is a function + + if (callbackOnInit && (0, _utils.isType)('Function', callbackOnInit)) { + callbackOnInit.call(this); + } + } + }, { + key: "destroy", + value: function destroy() { + if (!this.initialised) { + return; + } + + this._removeEventListeners(); + + this.passedElement.reveal(); + this.containerOuter.unwrap(this.passedElement.element); + + if (this._isSelectElement) { + this.passedElement.options = this._presetChoices; + } + + this.clearStore(); + this.config.templates = null; + this.initialised = false; + } + }, { + key: "enable", + value: function enable() { + if (this.passedElement.isDisabled) { + this.passedElement.enable(); + } + + if (this.containerOuter.isDisabled) { + this._addEventListeners(); + + this.input.enable(); + this.containerOuter.enable(); + } + + return this; + } + }, { + key: "disable", + value: function disable() { + if (!this.passedElement.isDisabled) { + this.passedElement.disable(); + } + + if (!this.containerOuter.isDisabled) { + this._removeEventListeners(); + + this.input.disable(); + this.containerOuter.disable(); + } + + return this; + } + }, { + key: "highlightItem", + value: function highlightItem(item) { + var runEvent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + if (!item) { + return this; + } + + var id = item.id, + _item$groupId = item.groupId, + groupId = _item$groupId === void 0 ? -1 : _item$groupId, + _item$value = item.value, + value = _item$value === void 0 ? '' : _item$value, + _item$label = item.label, + label = _item$label === void 0 ? '' : _item$label; + var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; + + this._store.dispatch((0, _items.highlightItem)(id, true)); + + if (runEvent) { + this.passedElement.triggerEvent(_constants.EVENTS.highlightItem, { + id: id, + value: value, + label: label, + groupValue: group && group.value ? group.value : null + }); + } + + return this; + } + }, { + key: "unhighlightItem", + value: function unhighlightItem(item) { + if (!item) { + return this; + } + + var id = item.id, + _item$groupId2 = item.groupId, + groupId = _item$groupId2 === void 0 ? -1 : _item$groupId2, + _item$value2 = item.value, + value = _item$value2 === void 0 ? '' : _item$value2, + _item$label2 = item.label, + label = _item$label2 === void 0 ? '' : _item$label2; + var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; + + this._store.dispatch((0, _items.highlightItem)(id, false)); + + this.passedElement.triggerEvent(_constants.EVENTS.highlightItem, { + id: id, + value: value, + label: label, + groupValue: group && group.value ? group.value : null + }); + return this; + } + }, { + key: "highlightAll", + value: function highlightAll() { + var _this = this; + + this._store.items.forEach(function (item) { + return _this.highlightItem(item); + }); + + return this; + } + }, { + key: "unhighlightAll", + value: function unhighlightAll() { + var _this2 = this; + + this._store.items.forEach(function (item) { + return _this2.unhighlightItem(item); + }); + + return this; + } + }, { + key: "removeActiveItemsByValue", + value: function removeActiveItemsByValue(value) { + var _this3 = this; + + this._store.activeItems.filter(function (item) { + return item.value === value; + }).forEach(function (item) { + return _this3._removeItem(item); + }); + + return this; + } + }, { + key: "removeActiveItems", + value: function removeActiveItems(excludedId) { + var _this4 = this; + + this._store.activeItems.filter(function (_ref) { + var id = _ref.id; + return id !== excludedId; + }).forEach(function (item) { + return _this4._removeItem(item); + }); + + return this; + } + }, { + key: "removeHighlightedItems", + value: function removeHighlightedItems() { + var _this5 = this; + + var runEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + this._store.highlightedActiveItems.forEach(function (item) { + _this5._removeItem(item); // If this action was performed by the user + // trigger the event + + + if (runEvent) { + _this5._triggerChange(item.value); + } + }); + + return this; + } + }, { + key: "showDropdown", + value: function showDropdown(preventInputFocus) { + var _this6 = this; + + if (this.dropdown.isActive) { + return this; + } + + requestAnimationFrame(function () { + _this6.dropdown.show(); + + _this6.containerOuter.open(_this6.dropdown.distanceFromTopWindow()); + + if (!preventInputFocus && _this6._canSearch) { + _this6.input.focus(); + } + + _this6.passedElement.triggerEvent(_constants.EVENTS.showDropdown, {}); + }); + return this; + } + }, { + key: "hideDropdown", + value: function hideDropdown(preventInputBlur) { + var _this7 = this; + + if (!this.dropdown.isActive) { + return this; + } + + requestAnimationFrame(function () { + _this7.dropdown.hide(); + + _this7.containerOuter.close(); + + if (!preventInputBlur && _this7._canSearch) { + _this7.input.removeActiveDescendant(); + + _this7.input.blur(); + } + + _this7.passedElement.triggerEvent(_constants.EVENTS.hideDropdown, {}); + }); + return this; + } + }, { + key: "getValue", + value: function getValue() { + var valueOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + var values = this._store.activeItems.reduce(function (selectedItems, item) { + var itemValue = valueOnly ? item.value : item; + selectedItems.push(itemValue); + return selectedItems; + }, []); + + return this._isSelectOneElement ? values[0] : values; + } + }, { + key: "setValue", + value: function setValue(args) { + var _this8 = this; + + if (!this.initialised) { + return this; + } + + [].concat(args).forEach(function (value) { + return _this8._setChoiceOrItem(value); + }); + return this; + } + }, { + key: "setChoiceByValue", + value: function setChoiceByValue(value) { + var _this9 = this; + + if (!this.initialised || this._isTextElement) { + return this; + } // If only one value has been passed, convert to array + + + var choiceValue = (0, _utils.isType)('Array', value) ? value : [value]; // Loop through each value and + + choiceValue.forEach(function (val) { + return _this9._findAndSelectChoiceByValue(val); + }); + return this; + } + }, { + key: "setChoices", + value: function setChoices() { + var _this10 = this; + + var choices = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var label = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; + var replaceChoices = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + if (!this._isSelectElement || !value) { + return this; + } // Clear choices if needed + + + if (replaceChoices) { + this.clearChoices(); + } + + this.containerOuter.removeLoadingState(); + + var addGroupsAndChoices = function addGroupsAndChoices(groupOrChoice) { + if (groupOrChoice.choices) { + _this10._addGroup({ + group: groupOrChoice, + id: groupOrChoice.id || null, + valueKey: value, + labelKey: label + }); + } else { + _this10._addChoice({ + value: groupOrChoice[value], + label: groupOrChoice[label], + isSelected: groupOrChoice.selected, + isDisabled: groupOrChoice.disabled, + customProperties: groupOrChoice.customProperties, + placeholder: groupOrChoice.placeholder + }); + } + }; + + this._setLoading(true); + + choices.forEach(addGroupsAndChoices); + + this._setLoading(false); + + return this; + } + }, { + key: "clearChoices", + value: function clearChoices() { + this._store.dispatch((0, _choices.clearChoices)()); + } + }, { + key: "clearStore", + value: function clearStore() { + this._store.dispatch((0, _misc.clearAll)()); + + return this; + } + }, { + key: "clearInput", + value: function clearInput() { + var shouldSetInputWidth = !this._isSelectOneElement; + this.input.clear(shouldSetInputWidth); + + if (!this._isTextElement && this._canSearch) { + this._isSearching = false; + + this._store.dispatch((0, _choices.activateChoices)(true)); + } + + return this; + } + }, { + key: "ajax", + value: function ajax(fn) { + var _this11 = this; + + if (!this.initialised || !this._isSelectElement || !fn) { + return this; + } + + requestAnimationFrame(function () { + return _this11._handleLoadingState(true); + }); + fn(this._ajaxCallback()); + return this; + } + /* ===== End of Public functions ====== */ + + /* ============================================= + = Private functions = + ============================================= */ + + }, { + key: "_render", + value: function _render() { + if (this._store.isLoading()) { + return; + } + + this._currentState = this._store.state; + var stateChanged = this._currentState.choices !== this._prevState.choices || this._currentState.groups !== this._prevState.groups || this._currentState.items !== this._prevState.items; + var shouldRenderChoices = this._isSelectElement; + var shouldRenderItems = this._currentState.items !== this._prevState.items; + + if (!stateChanged) { + return; + } + + if (shouldRenderChoices) { + this._renderChoices(); + } + + if (shouldRenderItems) { + this._renderItems(); + } + + this._prevState = this._currentState; + } + }, { + key: "_renderChoices", + value: function _renderChoices() { + var _this12 = this; + + var _this$_store = this._store, + activeGroups = _this$_store.activeGroups, + activeChoices = _this$_store.activeChoices; + var choiceListFragment = document.createDocumentFragment(); + this.choiceList.clear(); + + if (this.config.resetScrollPosition) { + requestAnimationFrame(function () { + return _this12.choiceList.scrollToTop(); + }); + } // If we have grouped options + + + if (activeGroups.length >= 1 && !this._isSearching) { + // If we have a placeholder choice along with groups + var activePlaceholders = activeChoices.filter(function (activeChoice) { + return activeChoice.placeholder === true && activeChoice.groupId === -1; + }); + + if (activePlaceholders.length >= 1) { + choiceListFragment = this._createChoicesFragment(activePlaceholders, choiceListFragment); + } + + choiceListFragment = this._createGroupsFragment(activeGroups, activeChoices, choiceListFragment); + } else if (activeChoices.length >= 1) { + choiceListFragment = this._createChoicesFragment(activeChoices, choiceListFragment); + } // If we have choices to show + + + if (choiceListFragment.childNodes && choiceListFragment.childNodes.length > 0) { + var activeItems = this._store.activeItems; + + var canAddItem = this._canAddItem(activeItems, this.input.value); // ...and we can select them + + + if (canAddItem.response) { + // ...append them and highlight the first choice + this.choiceList.append(choiceListFragment); + + this._highlightChoice(); + } else { + // ...otherwise show a notice + this.choiceList.append(this._getTemplate('notice', canAddItem.notice)); + } + } else { + // Otherwise show a notice + var dropdownItem; + var notice; + + if (this._isSearching) { + notice = (0, _utils.isType)('Function', this.config.noResultsText) ? this.config.noResultsText() : this.config.noResultsText; + dropdownItem = this._getTemplate('notice', notice, 'no-results'); + } else { + notice = (0, _utils.isType)('Function', this.config.noChoicesText) ? this.config.noChoicesText() : this.config.noChoicesText; + dropdownItem = this._getTemplate('notice', notice, 'no-choices'); + } + + this.choiceList.append(dropdownItem); + } + } + }, { + key: "_renderItems", + value: function _renderItems() { + var activeItems = this._store.activeItems || []; + this.itemList.clear(); // Create a fragment to store our list items + // (so we don't have to update the DOM for each item) + + var itemListFragment = this._createItemsFragment(activeItems); // If we have items to add, append them + + + if (itemListFragment.childNodes) { + this.itemList.append(itemListFragment); + } + } + }, { + key: "_createGroupsFragment", + value: function _createGroupsFragment(groups, choices, fragment) { + var _this13 = this; + + var groupFragment = fragment || document.createDocumentFragment(); + + var getGroupChoices = function getGroupChoices(group) { + return choices.filter(function (choice) { + if (_this13._isSelectOneElement) { + return choice.groupId === group.id; + } + + return choice.groupId === group.id && (_this13.config.renderSelectedChoices === 'always' || !choice.selected); + }); + }; // If sorting is enabled, filter groups + + + if (this.config.shouldSort) { + groups.sort(this.config.sortFn); + } + + groups.forEach(function (group) { + var groupChoices = getGroupChoices(group); + + if (groupChoices.length >= 1) { + var dropdownGroup = _this13._getTemplate('choiceGroup', group); + + groupFragment.appendChild(dropdownGroup); + + _this13._createChoicesFragment(groupChoices, groupFragment, true); + } + }); + return groupFragment; + } + }, { + key: "_createChoicesFragment", + value: function _createChoicesFragment(choices, fragment) { + var _this14 = this; + + var withinGroup = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + // Create a fragment to store our list items (so we don't have to update the DOM for each item) + var choicesFragment = fragment || document.createDocumentFragment(); + var _this$config = this.config, + renderSelectedChoices = _this$config.renderSelectedChoices, + searchResultLimit = _this$config.searchResultLimit, + renderChoiceLimit = _this$config.renderChoiceLimit; + var filter = this._isSearching ? _utils.sortByScore : this.config.sortFn; + + var appendChoice = function appendChoice(choice) { + var shouldRender = renderSelectedChoices === 'auto' ? _this14._isSelectOneElement || !choice.selected : true; + + if (shouldRender) { + var dropdownItem = _this14._getTemplate('choice', choice, _this14.config.itemSelectText); + + choicesFragment.appendChild(dropdownItem); + } + }; + + var rendererableChoices = choices; + + if (renderSelectedChoices === 'auto' && !this._isSelectOneElement) { + rendererableChoices = choices.filter(function (choice) { + return !choice.selected; + }); + } // Split array into placeholders and "normal" choices + + + var _rendererableChoices$ = rendererableChoices.reduce(function (acc, choice) { + if (choice.placeholder) { + acc.placeholderChoices.push(choice); + } else { + acc.normalChoices.push(choice); + } + + return acc; + }, { + placeholderChoices: [], + normalChoices: [] + }), + placeholderChoices = _rendererableChoices$.placeholderChoices, + normalChoices = _rendererableChoices$.normalChoices; // If sorting is enabled or the user is searching, filter choices + + + if (this.config.shouldSort || this._isSearching) { + normalChoices.sort(filter); + } + + var choiceLimit = rendererableChoices.length; // Prepend placeholeder + + var sortedChoices = [].concat(placeholderChoices, normalChoices); + + if (this._isSearching) { + choiceLimit = searchResultLimit; + } else if (renderChoiceLimit > 0 && !withinGroup) { + choiceLimit = renderChoiceLimit; + } // Add each choice to dropdown within range + + + for (var i = 0; i < choiceLimit; i += 1) { + if (sortedChoices[i]) { + appendChoice(sortedChoices[i]); + } + } + + return choicesFragment; + } + }, { + key: "_createItemsFragment", + value: function _createItemsFragment(items) { + var _this15 = this; + + var fragment = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + // Create fragment to add elements to + var _this$config2 = this.config, + shouldSortItems = _this$config2.shouldSortItems, + sortFn = _this$config2.sortFn, + removeItemButton = _this$config2.removeItemButton; + var itemListFragment = fragment || document.createDocumentFragment(); // If sorting is enabled, filter items + + if (shouldSortItems && !this._isSelectOneElement) { + items.sort(sortFn); + } + + if (this._isTextElement) { + // Update the value of the hidden input + this.passedElement.value = items; + } else { + // Update the options of the hidden input + this.passedElement.options = items; + } + + var addItemToFragment = function addItemToFragment(item) { + // Create new list element + var listItem = _this15._getTemplate('item', item, removeItemButton); // Append it to list + + + itemListFragment.appendChild(listItem); + }; // Add each list item to list + + + items.forEach(function (item) { + return addItemToFragment(item); + }); + return itemListFragment; + } + }, { + key: "_triggerChange", + value: function _triggerChange(value) { + if (value === undefined || value === null) { + return; + } + + this.passedElement.triggerEvent(_constants.EVENTS.change, { + value: value + }); + } + }, { + key: "_selectPlaceholderChoice", + value: function _selectPlaceholderChoice() { + var placeholderChoice = this._store.placeholderChoice; + + if (placeholderChoice) { + this._addItem({ + value: placeholderChoice.value, + label: placeholderChoice.label, + choiceId: placeholderChoice.id, + groupId: placeholderChoice.groupId, + placeholder: placeholderChoice.placeholder + }); + + this._triggerChange(placeholderChoice.value); + } + } + }, { + key: "_handleButtonAction", + value: function _handleButtonAction(activeItems, element) { + if (!activeItems || !element || !this.config.removeItems || !this.config.removeItemButton) { + return; + } + + var itemId = element.parentNode.getAttribute('data-id'); + var itemToRemove = activeItems.find(function (item) { + return item.id === parseInt(itemId, 10); + }); // Remove item associated with button + + this._removeItem(itemToRemove); + + this._triggerChange(itemToRemove.value); + + if (this._isSelectOneElement) { + this._selectPlaceholderChoice(); + } + } + }, { + key: "_handleItemAction", + value: function _handleItemAction(activeItems, element) { + var _this16 = this; + + var hasShiftKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (!activeItems || !element || !this.config.removeItems || this._isSelectOneElement) { + return; + } + + var passedId = element.getAttribute('data-id'); // We only want to select one item with a click + // so we deselect any items that aren't the target + // unless shift is being pressed + + activeItems.forEach(function (item) { + if (item.id === parseInt(passedId, 10) && !item.highlighted) { + _this16.highlightItem(item); + } else if (!hasShiftKey && item.highlighted) { + _this16.unhighlightItem(item); + } + }); // Focus input as without focus, a user cannot do anything with a + // highlighted item + + this.input.focus(); + } + }, { + key: "_handleChoiceAction", + value: function _handleChoiceAction(activeItems, element) { + if (!activeItems || !element) { + return; + } // If we are clicking on an option + + + var id = element.getAttribute('data-id'); + + var choice = this._store.getChoiceById(id); + + var passedKeyCode = activeItems[0] && activeItems[0].keyCode ? activeItems[0].keyCode : null; + var hasActiveDropdown = this.dropdown.isActive; // Update choice keyCode + + choice.keyCode = passedKeyCode; + this.passedElement.triggerEvent(_constants.EVENTS.choice, { + choice: choice + }); + + if (choice && !choice.selected && !choice.disabled) { + var canAddItem = this._canAddItem(activeItems, choice.value); + + if (canAddItem.response) { + this._addItem({ + value: choice.value, + label: choice.label, + choiceId: choice.id, + groupId: choice.groupId, + customProperties: choice.customProperties, + placeholder: choice.placeholder, + keyCode: choice.keyCode + }); + + this._triggerChange(choice.value); + } + } + + this.clearInput(); // We wont to close the dropdown if we are dealing with a single select box + + if (hasActiveDropdown && this._isSelectOneElement) { + this.hideDropdown(true); + this.containerOuter.focus(); + } + } + }, { + key: "_handleBackspace", + value: function _handleBackspace(activeItems) { + if (!this.config.removeItems || !activeItems) { + return; + } + + var lastItem = activeItems[activeItems.length - 1]; + var hasHighlightedItems = activeItems.some(function (item) { + return item.highlighted; + }); // If editing the last item is allowed and there are not other selected items, + // we can edit the item value. Otherwise if we can remove items, remove all selected items + + if (this.config.editItems && !hasHighlightedItems && lastItem) { + this.input.value = lastItem.value; + this.input.setWidth(); + + this._removeItem(lastItem); + + this._triggerChange(lastItem.value); + } else { + if (!hasHighlightedItems) { + // Highlight last item if none already highlighted + this.highlightItem(lastItem, false); + } + + this.removeHighlightedItems(true); + } + } + }, { + key: "_setLoading", + value: function _setLoading(isLoading) { + this._store.dispatch((0, _general.setIsLoading)(isLoading)); + } + }, { + key: "_handleLoadingState", + value: function _handleLoadingState() { + var setLoading = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + var placeholderItem = this.itemList.getChild(".".concat(this.config.classNames.placeholder)); + + if (setLoading) { + this.disable(); + this.containerOuter.addLoadingState(); + + if (this._isSelectOneElement) { + if (!placeholderItem) { + placeholderItem = this._getTemplate('placeholder', this.config.loadingText); + this.itemList.append(placeholderItem); + } else { + placeholderItem.innerHTML = this.config.loadingText; + } + } else { + this.input.placeholder = this.config.loadingText; + } + } else { + this.enable(); + this.containerOuter.removeLoadingState(); + + if (this._isSelectOneElement) { + placeholderItem.innerHTML = this._placeholderValue || ''; + } else { + this.input.placeholder = this._placeholderValue || ''; + } + } + } + }, { + key: "_handleSearch", + value: function _handleSearch(value) { + if (!value || !this.input.isFocussed) { + return; + } + + var choices = this._store.choices; + var _this$config3 = this.config, + searchFloor = _this$config3.searchFloor, + searchChoices = _this$config3.searchChoices; + var hasUnactiveChoices = choices.some(function (option) { + return !option.active; + }); // Check that we have a value to search and the input was an alphanumeric character + + if (value && value.length >= searchFloor) { + var resultCount = searchChoices ? this._searchChoices(value) : 0; // Trigger search event + + this.passedElement.triggerEvent(_constants.EVENTS.search, { + value: value, + resultCount: resultCount + }); + } else if (hasUnactiveChoices) { + // Otherwise reset choices to active + this._isSearching = false; + + this._store.dispatch((0, _choices.activateChoices)(true)); + } + } + }, { + key: "_canAddItem", + value: function _canAddItem(activeItems, value) { + var canAddItem = true; + var notice = (0, _utils.isType)('Function', this.config.addItemText) ? this.config.addItemText(value) : this.config.addItemText; + + if (!this._isSelectOneElement) { + var isDuplicateValue = (0, _utils.existsInArray)(activeItems, value); + + if (this.config.maxItemCount > 0 && this.config.maxItemCount <= activeItems.length) { + // If there is a max entry limit and we have reached that limit + // don't update + canAddItem = false; + notice = (0, _utils.isType)('Function', this.config.maxItemText) ? this.config.maxItemText(this.config.maxItemCount) : this.config.maxItemText; + } + + if (!this.config.duplicateItemsAllowed && isDuplicateValue && canAddItem) { + canAddItem = false; + notice = (0, _utils.isType)('Function', this.config.uniqueItemText) ? this.config.uniqueItemText(value) : this.config.uniqueItemText; + } + + if (this._isTextElement && this.config.addItems && canAddItem && (0, _utils.isType)('Function', this.config.addItemFilterFn) && !this.config.addItemFilterFn(value)) { + canAddItem = false; + notice = (0, _utils.isType)('Function', this.config.customAddItemText) ? this.config.customAddItemText(value) : this.config.customAddItemText; + } + } + + return { + response: canAddItem, + notice: notice + }; + } + }, { + key: "_ajaxCallback", + value: function _ajaxCallback() { + var _this17 = this; + + return function (results, value, label) { + if (!results || !value) { + return; + } + + var parsedResults = (0, _utils.isType)('Object', results) ? [results] : results; + + if (parsedResults && (0, _utils.isType)('Array', parsedResults) && parsedResults.length) { + // Remove loading states/text + _this17._handleLoadingState(false); + + _this17._setLoading(true); // Add each result as a choice + + + parsedResults.forEach(function (result) { + if (result.choices) { + _this17._addGroup({ + group: result, + id: result.id || null, + valueKey: value, + labelKey: label + }); + } else { + _this17._addChoice({ + value: (0, _utils.fetchFromObject)(result, value), + label: (0, _utils.fetchFromObject)(result, label), + isSelected: result.selected, + isDisabled: result.disabled, + customProperties: result.customProperties, + placeholder: result.placeholder + }); + } + }); + + _this17._setLoading(false); + + if (_this17._isSelectOneElement) { + _this17._selectPlaceholderChoice(); + } + } else { + // No results, remove loading state + _this17._handleLoadingState(false); + } + }; + } + }, { + key: "_searchChoices", + value: function _searchChoices(value) { + var newValue = (0, _utils.isType)('String', value) ? value.trim() : value; + var currentValue = (0, _utils.isType)('String', this._currentValue) ? this._currentValue.trim() : this._currentValue; + + if (newValue.length < 1 && newValue === "".concat(currentValue, " ")) { + return 0; + } // If new value matches the desired length and is not the same as the current value with a space + + + var haystack = this._store.searchableChoices; + var needle = newValue; + var keys = [].concat(this.config.searchFields); + var options = Object.assign(this.config.fuseOptions, { + keys: keys + }); + var fuse = new _fuse.default(haystack, options); + var results = fuse.search(needle); + this._currentValue = newValue; + this._highlightPosition = 0; + this._isSearching = true; + + this._store.dispatch((0, _choices.filterChoices)(results)); + + return results.length; + } + }, { + key: "_addEventListeners", + value: function _addEventListeners() { + document.addEventListener('keyup', this._onKeyUp); + document.addEventListener('keydown', this._onKeyDown); + document.addEventListener('click', this._onClick); + document.addEventListener('touchmove', this._onTouchMove); + document.addEventListener('touchend', this._onTouchEnd); + document.addEventListener('mousedown', this._onMouseDown); + document.addEventListener('mouseover', this._onMouseOver); + + if (this._isSelectOneElement) { + this.containerOuter.element.addEventListener('focus', this._onFocus); + this.containerOuter.element.addEventListener('blur', this._onBlur); + } + + this.input.element.addEventListener('focus', this._onFocus); + this.input.element.addEventListener('blur', this._onBlur); + + if (this.input.element.form) { + this.input.element.form.addEventListener('reset', this._onFormReset); + } + + this.input.addEventListeners(); + } + }, { + key: "_removeEventListeners", + value: function _removeEventListeners() { + document.removeEventListener('keyup', this._onKeyUp); + document.removeEventListener('keydown', this._onKeyDown); + document.removeEventListener('click', this._onClick); + document.removeEventListener('touchmove', this._onTouchMove); + document.removeEventListener('touchend', this._onTouchEnd); + document.removeEventListener('mousedown', this._onMouseDown); + document.removeEventListener('mouseover', this._onMouseOver); + + if (this._isSelectOneElement) { + this.containerOuter.element.removeEventListener('focus', this._onFocus); + this.containerOuter.element.removeEventListener('blur', this._onBlur); + } + + this.input.element.removeEventListener('focus', this._onFocus); + this.input.element.removeEventListener('blur', this._onBlur); + + if (this.input.element.form) { + this.input.element.form.removeEventListener('reset', this._onFormReset); + } + + this.input.removeEventListeners(); + } + }, { + key: "_onKeyDown", + value: function _onKeyDown(event) { + var _keyDownActions; + + var target = event.target, + keyCode = event.keyCode, + ctrlKey = event.ctrlKey, + metaKey = event.metaKey; + + if (target !== this.input.element && !this.containerOuter.element.contains(target)) { + return; + } + + var activeItems = this._store.activeItems; + var hasFocusedInput = this.input.isFocussed; + var hasActiveDropdown = this.dropdown.isActive; + var hasItems = this.itemList.hasChildren; + var keyString = String.fromCharCode(keyCode); + var BACK_KEY = _constants.KEY_CODES.BACK_KEY, + DELETE_KEY = _constants.KEY_CODES.DELETE_KEY, + ENTER_KEY = _constants.KEY_CODES.ENTER_KEY, + A_KEY = _constants.KEY_CODES.A_KEY, + ESC_KEY = _constants.KEY_CODES.ESC_KEY, + UP_KEY = _constants.KEY_CODES.UP_KEY, + DOWN_KEY = _constants.KEY_CODES.DOWN_KEY, + PAGE_UP_KEY = _constants.KEY_CODES.PAGE_UP_KEY, + PAGE_DOWN_KEY = _constants.KEY_CODES.PAGE_DOWN_KEY; + var hasCtrlDownKeyPressed = ctrlKey || metaKey; // If a user is typing and the dropdown is not active + + if (!this._isTextElement && /[a-zA-Z0-9-_ ]/.test(keyString)) { + this.showDropdown(); + } // Map keys to key actions + + + var keyDownActions = (_keyDownActions = {}, _defineProperty(_keyDownActions, A_KEY, this._onAKey), _defineProperty(_keyDownActions, ENTER_KEY, this._onEnterKey), _defineProperty(_keyDownActions, ESC_KEY, this._onEscapeKey), _defineProperty(_keyDownActions, UP_KEY, this._onDirectionKey), _defineProperty(_keyDownActions, PAGE_UP_KEY, this._onDirectionKey), _defineProperty(_keyDownActions, DOWN_KEY, this._onDirectionKey), _defineProperty(_keyDownActions, PAGE_DOWN_KEY, this._onDirectionKey), _defineProperty(_keyDownActions, DELETE_KEY, this._onDeleteKey), _defineProperty(_keyDownActions, BACK_KEY, this._onDeleteKey), _keyDownActions); // If keycode has a function, run it + + if (keyDownActions[keyCode]) { + keyDownActions[keyCode]({ + event: event, + target: target, + keyCode: keyCode, + metaKey: metaKey, + activeItems: activeItems, + hasFocusedInput: hasFocusedInput, + hasActiveDropdown: hasActiveDropdown, + hasItems: hasItems, + hasCtrlDownKeyPressed: hasCtrlDownKeyPressed + }); + } + } + }, { + key: "_onKeyUp", + value: function _onKeyUp(_ref2) { + var target = _ref2.target, + keyCode = _ref2.keyCode; + + if (target !== this.input.element) { + return; + } + + var value = this.input.value; + var activeItems = this._store.activeItems; + + var canAddItem = this._canAddItem(activeItems, value); + + var backKey = _constants.KEY_CODES.BACK_KEY, + deleteKey = _constants.KEY_CODES.DELETE_KEY; // We are typing into a text input and have a value, we want to show a dropdown + // notice. Otherwise hide the dropdown + + if (this._isTextElement) { + var canShowDropdownNotice = canAddItem.notice && value; + + if (canShowDropdownNotice) { + var dropdownItem = this._getTemplate('notice', canAddItem.notice); + + this.dropdown.element.innerHTML = dropdownItem.outerHTML; + this.showDropdown(true); + } else { + this.hideDropdown(true); + } + } else { + var userHasRemovedValue = (keyCode === backKey || keyCode === deleteKey) && !target.value; + var canReactivateChoices = !this._isTextElement && this._isSearching; + var canSearch = this._canSearch && canAddItem.response; + + if (userHasRemovedValue && canReactivateChoices) { + this._isSearching = false; + + this._store.dispatch((0, _choices.activateChoices)(true)); + } else if (canSearch) { + this._handleSearch(this.input.value); + } + } + + this._canSearch = this.config.searchEnabled; + } + }, { + key: "_onAKey", + value: function _onAKey(_ref3) { + var hasItems = _ref3.hasItems, + hasCtrlDownKeyPressed = _ref3.hasCtrlDownKeyPressed; + + // If CTRL + A or CMD + A have been pressed and there are items to select + if (hasCtrlDownKeyPressed && hasItems) { + this._canSearch = false; + var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement; + + if (shouldHightlightAll) { + this.highlightAll(); + } + } + } + }, { + key: "_onEnterKey", + value: function _onEnterKey(_ref4) { + var event = _ref4.event, + target = _ref4.target, + activeItems = _ref4.activeItems, + hasActiveDropdown = _ref4.hasActiveDropdown; + var enterKey = _constants.KEY_CODES.ENTER_KEY; + var targetWasButton = target.hasAttribute('data-button'); + + if (this._isTextElement && target.value) { + var value = this.input.value; + + var canAddItem = this._canAddItem(activeItems, value); + + if (canAddItem.response) { + this.hideDropdown(true); + + this._addItem({ + value: value + }); + + this._triggerChange(value); + + this.clearInput(); + } + } + + if (targetWasButton) { + this._handleButtonAction(activeItems, target); + + event.preventDefault(); + } + + if (hasActiveDropdown) { + var highlightedChoice = this.dropdown.getChild(".".concat(this.config.classNames.highlightedState)); + + if (highlightedChoice) { + // add enter keyCode value + if (activeItems[0]) { + activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign + } + + this._handleChoiceAction(activeItems, highlightedChoice); + } + + event.preventDefault(); + } else if (this._isSelectOneElement) { + this.showDropdown(); + event.preventDefault(); + } + } + }, { + key: "_onEscapeKey", + value: function _onEscapeKey(_ref5) { + var hasActiveDropdown = _ref5.hasActiveDropdown; + + if (hasActiveDropdown) { + this.hideDropdown(true); + this.containerOuter.focus(); + } + } + }, { + key: "_onDirectionKey", + value: function _onDirectionKey(_ref6) { + var event = _ref6.event, + hasActiveDropdown = _ref6.hasActiveDropdown, + keyCode = _ref6.keyCode, + metaKey = _ref6.metaKey; + var downKey = _constants.KEY_CODES.DOWN_KEY, + pageUpKey = _constants.KEY_CODES.PAGE_UP_KEY, + pageDownKey = _constants.KEY_CODES.PAGE_DOWN_KEY; // If up or down key is pressed, traverse through options + + if (hasActiveDropdown || this._isSelectOneElement) { + this.showDropdown(); + this._canSearch = false; + var directionInt = keyCode === downKey || keyCode === pageDownKey ? 1 : -1; + var skipKey = metaKey || keyCode === pageDownKey || keyCode === pageUpKey; + var selectableChoiceIdentifier = '[data-choice-selectable]'; + var nextEl; + + if (skipKey) { + if (directionInt > 0) { + nextEl = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier)).pop(); + } else { + nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier); + } + } else { + var currentEl = this.dropdown.element.querySelector(".".concat(this.config.classNames.highlightedState)); + + if (currentEl) { + nextEl = (0, _utils.getAdjacentEl)(currentEl, selectableChoiceIdentifier, directionInt); + } else { + nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier); + } + } + + if (nextEl) { + // We prevent default to stop the cursor moving + // when pressing the arrow + if (!(0, _utils.isScrolledIntoView)(nextEl, this.choiceList.element, directionInt)) { + this.choiceList.scrollToChoice(nextEl, directionInt); + } + + this._highlightChoice(nextEl); + } // Prevent default to maintain cursor position whilst + // traversing dropdown options + + + event.preventDefault(); + } + } + }, { + key: "_onDeleteKey", + value: function _onDeleteKey(_ref7) { + var event = _ref7.event, + target = _ref7.target, + hasFocusedInput = _ref7.hasFocusedInput, + activeItems = _ref7.activeItems; + + // If backspace or delete key is pressed and the input has no value + if (hasFocusedInput && !target.value && !this._isSelectOneElement) { + this._handleBackspace(activeItems); + + event.preventDefault(); + } + } + }, { + key: "_onTouchMove", + value: function _onTouchMove() { + if (this._wasTap) { + this._wasTap = false; + } + } + }, { + key: "_onTouchEnd", + value: function _onTouchEnd(event) { + var _ref8 = event || event.touches[0], + target = _ref8.target; + + var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target); + + if (touchWasWithinContainer) { + var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element; + + if (containerWasExactTarget) { + if (this._isTextElement) { + this.input.focus(); + } else if (this._isSelectMultipleElement) { + this.showDropdown(); + } + } // Prevents focus event firing + + + event.stopPropagation(); + } + + this._wasTap = true; + } + }, { + key: "_onMouseDown", + value: function _onMouseDown(event) { + var target = event.target, + shiftKey = event.shiftKey; // If we have our mouse down on the scrollbar and are on IE11... + + if (this.choiceList.element.contains(target) && (0, _utils.isIE11)()) { + this._isScrollingOnIe = true; + } + + if (!this.containerOuter.element.contains(target) || target === this.input.element) { + return; + } + + var activeItems = this._store.activeItems; + var hasShiftKey = shiftKey; + var buttonTarget = (0, _utils.findAncestorByAttrName)(target, 'data-button'); + var itemTarget = (0, _utils.findAncestorByAttrName)(target, 'data-item'); + var choiceTarget = (0, _utils.findAncestorByAttrName)(target, 'data-choice'); + + if (buttonTarget) { + this._handleButtonAction(activeItems, buttonTarget); + } else if (itemTarget) { + this._handleItemAction(activeItems, itemTarget, hasShiftKey); + } else if (choiceTarget) { + this._handleChoiceAction(activeItems, choiceTarget); + } + + event.preventDefault(); + } + }, { + key: "_onMouseOver", + value: function _onMouseOver(_ref9) { + var target = _ref9.target; + var targetWithinDropdown = target === this.dropdown || this.dropdown.element.contains(target); + var shouldHighlightChoice = targetWithinDropdown && target.hasAttribute('data-choice'); + + if (shouldHighlightChoice) { + this._highlightChoice(target); + } + } + }, { + key: "_onClick", + value: function _onClick(_ref10) { + var target = _ref10.target; + var clickWasWithinContainer = this.containerOuter.element.contains(target); + + if (clickWasWithinContainer) { + if (!this.dropdown.isActive && !this.containerOuter.isDisabled) { + if (this._isTextElement) { + if (document.activeElement !== this.input.element) { + this.input.focus(); + } + } else { + this.showDropdown(); + this.containerOuter.focus(); + } + } else if (this._isSelectOneElement && target !== this.input.element && !this.dropdown.element.contains(target)) { + this.hideDropdown(); + } + } else { + var hasHighlightedItems = this._store.highlightedActiveItems; + + if (hasHighlightedItems) { + this.unhighlightAll(); + } + + this.containerOuter.removeFocusState(); + this.hideDropdown(true); + } + } + }, { + key: "_onFocus", + value: function _onFocus(_ref11) { + var _this18 = this; + + var target = _ref11.target; + var focusWasWithinContainer = this.containerOuter.element.contains(target); + + if (!focusWasWithinContainer) { + return; + } + + var focusActions = { + text: function text() { + if (target === _this18.input.element) { + _this18.containerOuter.addFocusState(); + } + }, + 'select-one': function selectOne() { + _this18.containerOuter.addFocusState(); + + if (target === _this18.input.element) { + _this18.showDropdown(true); + } + }, + 'select-multiple': function selectMultiple() { + if (target === _this18.input.element) { + _this18.showDropdown(true); // If element is a select box, the focused element is the container and the dropdown + // isn't already open, focus and show dropdown + + + _this18.containerOuter.addFocusState(); + } + } + }; + focusActions[this.passedElement.element.type](); + } + }, { + key: "_onBlur", + value: function _onBlur(_ref12) { + var _this19 = this; + + var target = _ref12.target; + var blurWasWithinContainer = this.containerOuter.element.contains(target); + + if (blurWasWithinContainer && !this._isScrollingOnIe) { + var activeItems = this._store.activeItems; + var hasHighlightedItems = activeItems.some(function (item) { + return item.highlighted; + }); + var blurActions = { + text: function text() { + if (target === _this19.input.element) { + _this19.containerOuter.removeFocusState(); + + if (hasHighlightedItems) { + _this19.unhighlightAll(); + } + + _this19.hideDropdown(true); + } + }, + 'select-one': function selectOne() { + _this19.containerOuter.removeFocusState(); + + if (target === _this19.input.element || target === _this19.containerOuter.element && !_this19._canSearch) { + _this19.hideDropdown(true); + } + }, + 'select-multiple': function selectMultiple() { + if (target === _this19.input.element) { + _this19.containerOuter.removeFocusState(); + + _this19.hideDropdown(true); + + if (hasHighlightedItems) { + _this19.unhighlightAll(); + } + } + } + }; + blurActions[this.passedElement.element.type](); + } else { + // On IE11, clicking the scollbar blurs our input and thus + // closes the dropdown. To stop this, we refocus our input + // if we know we are on IE *and* are scrolling. + this._isScrollingOnIe = false; + this.input.element.focus(); + } + } + }, { + key: "_onFormReset", + value: function _onFormReset() { + this._store.dispatch((0, _misc.resetTo)(this._initialState)); + } + }, { + key: "_highlightChoice", + value: function _highlightChoice() { + var _this20 = this; + + var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var choices = Array.from(this.dropdown.element.querySelectorAll('[data-choice-selectable]')); + + if (!choices.length) { + return; + } + + var passedEl = el; + var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(".".concat(this.config.classNames.highlightedState))); // Remove any highlighted choices + + highlightedChoices.forEach(function (choice) { + choice.classList.remove(_this20.config.classNames.highlightedState); + choice.setAttribute('aria-selected', 'false'); + }); + + if (passedEl) { + this._highlightPosition = choices.indexOf(passedEl); + } else { + // Highlight choice based on last known highlight location + if (choices.length > this._highlightPosition) { + // If we have an option to highlight + passedEl = choices[this._highlightPosition]; + } else { + // Otherwise highlight the option before + passedEl = choices[choices.length - 1]; + } + + if (!passedEl) { + passedEl = choices[0]; + } + } + + passedEl.classList.add(this.config.classNames.highlightedState); + passedEl.setAttribute('aria-selected', 'true'); + this.passedElement.triggerEvent(_constants.EVENTS.highlightChoice, { + el: passedEl + }); + + if (this.dropdown.isActive) { + // IE11 ignores aria-label and blocks virtual keyboard + // if aria-activedescendant is set without a dropdown + this.input.setActiveDescendant(passedEl.id); + this.containerOuter.setActiveDescendant(passedEl.id); + } + } + }, { + key: "_addItem", + value: function _addItem(_ref13) { + var value = _ref13.value, + _ref13$label = _ref13.label, + label = _ref13$label === void 0 ? null : _ref13$label, + _ref13$choiceId = _ref13.choiceId, + choiceId = _ref13$choiceId === void 0 ? -1 : _ref13$choiceId, + _ref13$groupId = _ref13.groupId, + groupId = _ref13$groupId === void 0 ? -1 : _ref13$groupId, + _ref13$customProperti = _ref13.customProperties, + customProperties = _ref13$customProperti === void 0 ? null : _ref13$customProperti, + _ref13$placeholder = _ref13.placeholder, + placeholder = _ref13$placeholder === void 0 ? false : _ref13$placeholder, + _ref13$keyCode = _ref13.keyCode, + keyCode = _ref13$keyCode === void 0 ? null : _ref13$keyCode; + var passedValue = (0, _utils.isType)('String', value) ? value.trim() : value; + var passedKeyCode = keyCode; + var passedCustomProperties = customProperties; + var items = this._store.items; + var passedLabel = label || passedValue; + var passedOptionId = parseInt(choiceId, 10) || -1; + var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; + var id = items ? items.length + 1 : 1; // If a prepended value has been passed, prepend it + + if (this.config.prependValue) { + passedValue = this.config.prependValue + passedValue.toString(); + } // If an appended value has been passed, append it + + + if (this.config.appendValue) { + passedValue += this.config.appendValue.toString(); + } + + this._store.dispatch((0, _items.addItem)({ + value: passedValue, + label: passedLabel, + id: id, + choiceId: passedOptionId, + groupId: groupId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: passedKeyCode + })); + + if (this._isSelectOneElement) { + this.removeActiveItems(id); + } // Trigger change event + + + this.passedElement.triggerEvent(_constants.EVENTS.addItem, { + id: id, + value: passedValue, + label: passedLabel, + customProperties: passedCustomProperties, + groupValue: group && group.value ? group.value : undefined, + keyCode: passedKeyCode + }); + return this; + } + }, { + key: "_removeItem", + value: function _removeItem(item) { + if (!item || !(0, _utils.isType)('Object', item)) { + return this; + } + + var id = item.id, + value = item.value, + label = item.label, + choiceId = item.choiceId, + groupId = item.groupId; + var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; + + this._store.dispatch((0, _items.removeItem)(id, choiceId)); + + if (group && group.value) { + this.passedElement.triggerEvent(_constants.EVENTS.removeItem, { + id: id, + value: value, + label: label, + groupValue: group.value + }); + } else { + this.passedElement.triggerEvent(_constants.EVENTS.removeItem, { + id: id, + value: value, + label: label + }); + } + + return this; + } + }, { + key: "_addChoice", + value: function _addChoice(_ref14) { + var value = _ref14.value, + _ref14$label = _ref14.label, + label = _ref14$label === void 0 ? null : _ref14$label, + _ref14$isSelected = _ref14.isSelected, + isSelected = _ref14$isSelected === void 0 ? false : _ref14$isSelected, + _ref14$isDisabled = _ref14.isDisabled, + isDisabled = _ref14$isDisabled === void 0 ? false : _ref14$isDisabled, + _ref14$groupId = _ref14.groupId, + groupId = _ref14$groupId === void 0 ? -1 : _ref14$groupId, + _ref14$customProperti = _ref14.customProperties, + customProperties = _ref14$customProperti === void 0 ? null : _ref14$customProperti, + _ref14$placeholder = _ref14.placeholder, + placeholder = _ref14$placeholder === void 0 ? false : _ref14$placeholder, + _ref14$keyCode = _ref14.keyCode, + keyCode = _ref14$keyCode === void 0 ? null : _ref14$keyCode; + + if (typeof value === 'undefined' || value === null) { + return; + } // Generate unique id + + + var choices = this._store.choices; + var choiceLabel = label || value; + var choiceId = choices ? choices.length + 1 : 1; + var choiceElementId = "".concat(this._baseId, "-").concat(this._idNames.itemChoice, "-").concat(choiceId); + + this._store.dispatch((0, _choices.addChoice)({ + value: value, + label: choiceLabel, + id: choiceId, + groupId: groupId, + disabled: isDisabled, + elementId: choiceElementId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: keyCode + })); + + if (isSelected) { + this._addItem({ + value: value, + label: choiceLabel, + choiceId: choiceId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: keyCode + }); + } + } + }, { + key: "_addGroup", + value: function _addGroup(_ref15) { + var _this21 = this; + + var group = _ref15.group, + id = _ref15.id, + _ref15$valueKey = _ref15.valueKey, + valueKey = _ref15$valueKey === void 0 ? 'value' : _ref15$valueKey, + _ref15$labelKey = _ref15.labelKey, + labelKey = _ref15$labelKey === void 0 ? 'label' : _ref15$labelKey; + var groupChoices = (0, _utils.isType)('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION')); + var groupId = id || Math.floor(new Date().valueOf() * Math.random()); + var isDisabled = group.disabled ? group.disabled : false; + + if (groupChoices) { + this._store.dispatch((0, _groups.addGroup)(group.label, groupId, true, isDisabled)); + + var addGroupChoices = function addGroupChoices(choice) { + var isOptDisabled = choice.disabled || choice.parentNode && choice.parentNode.disabled; + + _this21._addChoice({ + value: choice[valueKey], + label: (0, _utils.isType)('Object', choice) ? choice[labelKey] : choice.innerHTML, + isSelected: choice.selected, + isDisabled: isOptDisabled, + groupId: groupId, + customProperties: choice.customProperties, + placeholder: choice.placeholder + }); + }; + + groupChoices.forEach(addGroupChoices); + } else { + this._store.dispatch((0, _groups.addGroup)(group.label, group.id, false, group.disabled)); + } + } + }, { + key: "_getTemplate", + value: function _getTemplate(template) { + var _templates$template; + + if (!template) { + return null; + } + + var _this$config4 = this.config, + templates = _this$config4.templates, + classNames = _this$config4.classNames; + + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + return (_templates$template = templates[template]).call.apply(_templates$template, [this, classNames].concat(args)); + } + }, { + key: "_createTemplates", + value: function _createTemplates() { + var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates; + var userTemplates = {}; + + if (callbackOnCreateTemplates && (0, _utils.isType)('Function', callbackOnCreateTemplates)) { + userTemplates = callbackOnCreateTemplates.call(this, _utils.strToEl); + } + + this.config.templates = (0, _deepmerge.default)(_templates.TEMPLATES, userTemplates); + } + }, { + key: "_createElements", + value: function _createElements() { + this.containerOuter = new _components.Container({ + element: this._getTemplate('containerOuter', this._direction, this._isSelectElement, this._isSelectOneElement, this.config.searchEnabled, this.passedElement.element.type), + classNames: this.config.classNames, + type: this.passedElement.element.type, + position: this.config.position + }); + this.containerInner = new _components.Container({ + element: this._getTemplate('containerInner'), + classNames: this.config.classNames, + type: this.passedElement.element.type, + position: this.config.position + }); + this.input = new _components.Input({ + element: this._getTemplate('input'), + classNames: this.config.classNames, + type: this.passedElement.element.type + }); + this.choiceList = new _components.List({ + element: this._getTemplate('choiceList', this._isSelectOneElement) + }); + this.itemList = new _components.List({ + element: this._getTemplate('itemList', this._isSelectOneElement) + }); + this.dropdown = new _components.Dropdown({ + element: this._getTemplate('dropdown'), + classNames: this.config.classNames, + type: this.passedElement.element.type + }); + } + }, { + key: "_createStructure", + value: function _createStructure() { + // Hide original element + this.passedElement.conceal(); // Wrap input in container preserving DOM ordering + + this.containerInner.wrap(this.passedElement.element); // Wrapper inner container with outer container + + this.containerOuter.wrap(this.containerInner.element); + + if (this._isSelectOneElement) { + this.input.placeholder = this.config.searchPlaceholderValue || ''; + } else if (this._placeholderValue) { + this.input.placeholder = this._placeholderValue; + this.input.setWidth(true); + } + + this.containerOuter.element.appendChild(this.containerInner.element); + this.containerOuter.element.appendChild(this.dropdown.element); + this.containerInner.element.appendChild(this.itemList.element); + + if (!this._isTextElement) { + this.dropdown.element.appendChild(this.choiceList.element); + } + + if (!this._isSelectOneElement) { + this.containerInner.element.appendChild(this.input.element); + } else if (this.config.searchEnabled) { + this.dropdown.element.insertBefore(this.input.element, this.dropdown.element.firstChild); + } + + if (this._isSelectElement) { + this._addPredefinedChoices(); + } else if (this._isTextElement) { + this._addPredefinedItems(); + } + } + }, { + key: "_addPredefinedChoices", + value: function _addPredefinedChoices() { + var _this22 = this; + + var passedGroups = this.passedElement.optionGroups; + this._highlightPosition = 0; + this._isSearching = false; + + this._setLoading(true); + + if (passedGroups && passedGroups.length) { + // If we have a placeholder option + var placeholderChoice = this.passedElement.placeholderOption; + + if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') { + this._addChoice({ + value: placeholderChoice.value, + label: placeholderChoice.innerHTML, + isSelected: placeholderChoice.selected, + isDisabled: placeholderChoice.disabled, + placeholder: true + }); + } + + passedGroups.forEach(function (group) { + return _this22._addGroup({ + group: group, + id: group.id || null + }); + }); + } else { + var passedOptions = this.passedElement.options; + var filter = this.config.sortFn; + var allChoices = this._presetChoices; // Create array of options from option elements + + passedOptions.forEach(function (o) { + allChoices.push({ + value: o.value, + label: o.innerHTML, + selected: o.selected, + disabled: o.disabled || o.parentNode.disabled, + placeholder: o.hasAttribute('placeholder'), + customProperties: o.getAttribute('data-custom-properties') + }); + }); // If sorting is enabled or the user is searching, filter choices + + if (this.config.shouldSort) allChoices.sort(filter); // Determine whether there is a selected choice + + var hasSelectedChoice = allChoices.some(function (choice) { + return choice.selected; + }); + + var handleChoice = function handleChoice(choice, index) { + var value = choice.value, + label = choice.label, + customProperties = choice.customProperties, + placeholder = choice.placeholder; + + if (_this22._isSelectElement) { + // If the choice is actually a group + if (choice.choices) { + _this22._addGroup({ + group: choice, + id: choice.id || null + }); + } else { + // If there is a selected choice already or the choice is not + // the first in the array, add each choice normally + // Otherwise pre-select the first choice in the array if it's a single select + var shouldPreselect = _this22._isSelectOneElement && !hasSelectedChoice && index === 0; + var isSelected = shouldPreselect ? true : choice.selected; + var isDisabled = shouldPreselect ? false : choice.disabled; + + _this22._addChoice({ + value: value, + label: label, + isSelected: isSelected, + isDisabled: isDisabled, + customProperties: customProperties, + placeholder: placeholder + }); + } + } else { + _this22._addChoice({ + value: value, + label: label, + isSelected: choice.selected, + isDisabled: choice.disabled, + customProperties: customProperties, + placeholder: placeholder + }); + } + }; // Add each choice + + + allChoices.forEach(function (choice, index) { + return handleChoice(choice, index); + }); + } + + this._setLoading(false); + } + }, { + key: "_addPredefinedItems", + value: function _addPredefinedItems() { + var _this23 = this; + + var handlePresetItem = function handlePresetItem(item) { + var itemType = (0, _utils.getType)(item); + + if (itemType === 'Object' && item.value) { + _this23._addItem({ + value: item.value, + label: item.label, + choiceId: item.id, + customProperties: item.customProperties, + placeholder: item.placeholder + }); + } else if (itemType === 'String') { + _this23._addItem({ + value: item + }); + } + }; + + this._presetItems.forEach(function (item) { + return handlePresetItem(item); + }); + } + }, { + key: "_setChoiceOrItem", + value: function _setChoiceOrItem(item) { + var _this24 = this; + + var itemType = (0, _utils.getType)(item).toLowerCase(); + var handleType = { + object: function object() { + if (!item.value) { + return; + } // If we are dealing with a select input, we need to create an option first + // that is then selected. For text inputs we can just add items normally. + + + if (!_this24._isTextElement) { + _this24._addChoice({ + value: item.value, + label: item.label, + isSelected: true, + isDisabled: false, + customProperties: item.customProperties, + placeholder: item.placeholder + }); + } else { + _this24._addItem({ + value: item.value, + label: item.label, + choiceId: item.id, + customProperties: item.customProperties, + placeholder: item.placeholder + }); + } + }, + string: function string() { + if (!_this24._isTextElement) { + _this24._addChoice({ + value: item, + label: item, + isSelected: true, + isDisabled: false + }); + } else { + _this24._addItem({ + value: item + }); + } + } + }; + handleType[itemType](); + } + }, { + key: "_findAndSelectChoiceByValue", + value: function _findAndSelectChoiceByValue(val) { + var _this25 = this; + + var choices = this._store.choices; // Check 'value' property exists and the choice isn't already selected + + var foundChoice = choices.find(function (choice) { + return _this25.config.itemComparer(choice.value, val); + }); + + if (foundChoice && !foundChoice.selected) { + this._addItem({ + value: foundChoice.value, + label: foundChoice.label, + choiceId: foundChoice.id, + groupId: foundChoice.groupId, + customProperties: foundChoice.customProperties, + placeholder: foundChoice.placeholder, + keyCode: foundChoice.keyCode + }); + } + } + }, { + key: "_generateInstances", + value: function _generateInstances(elements, config) { + return elements.reduce(function (instances, element) { + instances.push(new Choices(element, config)); + return instances; + }, [this]); + } + }, { + key: "_generatePlaceholderValue", + value: function _generatePlaceholderValue() { + if (this._isSelectOneElement) { + return false; + } + + return this.config.placeholder ? this.config.placeholderValue || this.passedElement.element.getAttribute('placeholder') : false; + } + /* ===== End of Private functions ====== */ + + }]); + + return Choices; +}(); + +Choices.userDefaults = {}; // We cannot export default here due to Webpack: https://github.com/webpack/webpack/issues/3929 + +module.exports = Choices; + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +/*! + * Fuse.js v3.4.2 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(true) + module.exports = factory(); + else {} +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./src/bitap/bitap_matched_indices.js": +/*!********************************************!*\ + !*** ./src/bitap/bitap_matched_indices.js ***! + \********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function () { + var matchmask = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var minMatchCharLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + var matchedIndices = []; + var start = -1; + var end = -1; + var i = 0; + + for (var len = matchmask.length; i < len; i += 1) { + var match = matchmask[i]; + + if (match && start === -1) { + start = i; + } else if (!match && start !== -1) { + end = i - 1; + + if (end - start + 1 >= minMatchCharLength) { + matchedIndices.push([start, end]); + } + + start = -1; + } + } // (i-1 - start) + 1 => i - start + + + if (matchmask[i - 1] && i - start >= minMatchCharLength) { + matchedIndices.push([start, i - 1]); + } + + return matchedIndices; +}; + +/***/ }), + +/***/ "./src/bitap/bitap_pattern_alphabet.js": +/*!*********************************************!*\ + !*** ./src/bitap/bitap_pattern_alphabet.js ***! + \*********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (pattern) { + var mask = {}; + var len = pattern.length; + + for (var i = 0; i < len; i += 1) { + mask[pattern.charAt(i)] = 0; + } + + for (var _i = 0; _i < len; _i += 1) { + mask[pattern.charAt(_i)] |= 1 << len - _i - 1; + } + + return mask; +}; + +/***/ }), + +/***/ "./src/bitap/bitap_regex_search.js": +/*!*****************************************!*\ + !*** ./src/bitap/bitap_regex_search.js ***! + \*****************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var SPECIAL_CHARS_REGEX = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; + +module.exports = function (text, pattern) { + var tokenSeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : / +/g; + var regex = new RegExp(pattern.replace(SPECIAL_CHARS_REGEX, '\\$&').replace(tokenSeparator, '|')); + var matches = text.match(regex); + var isMatch = !!matches; + var matchedIndices = []; + + if (isMatch) { + for (var i = 0, matchesLen = matches.length; i < matchesLen; i += 1) { + var match = matches[i]; + matchedIndices.push([text.indexOf(match), match.length - 1]); + } + } + + return { + // TODO: revisit this score + score: isMatch ? 0.5 : 1, + isMatch: isMatch, + matchedIndices: matchedIndices + }; +}; + +/***/ }), + +/***/ "./src/bitap/bitap_score.js": +/*!**********************************!*\ + !*** ./src/bitap/bitap_score.js ***! + \**********************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (pattern, _ref) { + var _ref$errors = _ref.errors, + errors = _ref$errors === void 0 ? 0 : _ref$errors, + _ref$currentLocation = _ref.currentLocation, + currentLocation = _ref$currentLocation === void 0 ? 0 : _ref$currentLocation, + _ref$expectedLocation = _ref.expectedLocation, + expectedLocation = _ref$expectedLocation === void 0 ? 0 : _ref$expectedLocation, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? 100 : _ref$distance; + var accuracy = errors / pattern.length; + var proximity = Math.abs(expectedLocation - currentLocation); + + if (!distance) { + // Dodge divide by zero error. + return proximity ? 1.0 : accuracy; + } + + return accuracy + proximity / distance; +}; + +/***/ }), + +/***/ "./src/bitap/bitap_search.js": +/*!***********************************!*\ + !*** ./src/bitap/bitap_search.js ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var bitapScore = __webpack_require__(/*! ./bitap_score */ "./src/bitap/bitap_score.js"); + +var matchedIndices = __webpack_require__(/*! ./bitap_matched_indices */ "./src/bitap/bitap_matched_indices.js"); + +module.exports = function (text, pattern, patternAlphabet, _ref) { + var _ref$location = _ref.location, + location = _ref$location === void 0 ? 0 : _ref$location, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? 100 : _ref$distance, + _ref$threshold = _ref.threshold, + threshold = _ref$threshold === void 0 ? 0.6 : _ref$threshold, + _ref$findAllMatches = _ref.findAllMatches, + findAllMatches = _ref$findAllMatches === void 0 ? false : _ref$findAllMatches, + _ref$minMatchCharLeng = _ref.minMatchCharLength, + minMatchCharLength = _ref$minMatchCharLeng === void 0 ? 1 : _ref$minMatchCharLeng; + var expectedLocation = location; // Set starting location at beginning text and initialize the alphabet. + + var textLen = text.length; // Highest score beyond which we give up. + + var currentThreshold = threshold; // Is there a nearby exact match? (speedup) + + var bestLocation = text.indexOf(pattern, expectedLocation); + var patternLen = pattern.length; // a mask of the matches + + var matchMask = []; + + for (var i = 0; i < textLen; i += 1) { + matchMask[i] = 0; + } + + if (bestLocation !== -1) { + var score = bitapScore(pattern, { + errors: 0, + currentLocation: bestLocation, + expectedLocation: expectedLocation, + distance: distance + }); + currentThreshold = Math.min(score, currentThreshold); // What about in the other direction? (speed up) + + bestLocation = text.lastIndexOf(pattern, expectedLocation + patternLen); + + if (bestLocation !== -1) { + var _score = bitapScore(pattern, { + errors: 0, + currentLocation: bestLocation, + expectedLocation: expectedLocation, + distance: distance + }); + + currentThreshold = Math.min(_score, currentThreshold); + } + } // Reset the best location + + + bestLocation = -1; + var lastBitArr = []; + var finalScore = 1; + var binMax = patternLen + textLen; + var mask = 1 << patternLen - 1; + + for (var _i = 0; _i < patternLen; _i += 1) { + // Scan for the best match; each iteration allows for one more error. + // Run a binary search to determine how far from the match location we can stray + // at this error level. + var binMin = 0; + var binMid = binMax; + + while (binMin < binMid) { + var _score3 = bitapScore(pattern, { + errors: _i, + currentLocation: expectedLocation + binMid, + expectedLocation: expectedLocation, + distance: distance + }); + + if (_score3 <= currentThreshold) { + binMin = binMid; + } else { + binMax = binMid; + } + + binMid = Math.floor((binMax - binMin) / 2 + binMin); + } // Use the result from this iteration as the maximum for the next. + + + binMax = binMid; + var start = Math.max(1, expectedLocation - binMid + 1); + var finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen; // Initialize the bit array + + var bitArr = Array(finish + 2); + bitArr[finish + 1] = (1 << _i) - 1; + + for (var j = finish; j >= start; j -= 1) { + var currentLocation = j - 1; + var charMatch = patternAlphabet[text.charAt(currentLocation)]; + + if (charMatch) { + matchMask[currentLocation] = 1; + } // First pass: exact match + + + bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch; // Subsequent passes: fuzzy match + + if (_i !== 0) { + bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1]; + } + + if (bitArr[j] & mask) { + finalScore = bitapScore(pattern, { + errors: _i, + currentLocation: currentLocation, + expectedLocation: expectedLocation, + distance: distance + }); // This match will almost certainly be better than any existing match. + // But check anyway. + + if (finalScore <= currentThreshold) { + // Indeed it is + currentThreshold = finalScore; + bestLocation = currentLocation; // Already passed `loc`, downhill from here on in. + + if (bestLocation <= expectedLocation) { + break; + } // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`. + + + start = Math.max(1, 2 * expectedLocation - bestLocation); + } + } + } // No hope for a (better) match at greater error levels. + + + var _score2 = bitapScore(pattern, { + errors: _i + 1, + currentLocation: expectedLocation, + expectedLocation: expectedLocation, + distance: distance + }); // console.log('score', score, finalScore) + + + if (_score2 > currentThreshold) { + break; + } + + lastBitArr = bitArr; + } // console.log('FINAL SCORE', finalScore) + // Count exact matches (those with a score of 0) to be "almost" exact + + + return { + isMatch: bestLocation >= 0, + score: finalScore === 0 ? 0.001 : finalScore, + matchedIndices: matchedIndices(matchMask, minMatchCharLength) + }; +}; + +/***/ }), + +/***/ "./src/bitap/index.js": +/*!****************************!*\ + !*** ./src/bitap/index.js ***! + \****************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var bitapRegexSearch = __webpack_require__(/*! ./bitap_regex_search */ "./src/bitap/bitap_regex_search.js"); + +var bitapSearch = __webpack_require__(/*! ./bitap_search */ "./src/bitap/bitap_search.js"); + +var patternAlphabet = __webpack_require__(/*! ./bitap_pattern_alphabet */ "./src/bitap/bitap_pattern_alphabet.js"); + +var Bitap = +/*#__PURE__*/ +function () { + function Bitap(pattern, _ref) { + var _ref$location = _ref.location, + location = _ref$location === void 0 ? 0 : _ref$location, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? 100 : _ref$distance, + _ref$threshold = _ref.threshold, + threshold = _ref$threshold === void 0 ? 0.6 : _ref$threshold, + _ref$maxPatternLength = _ref.maxPatternLength, + maxPatternLength = _ref$maxPatternLength === void 0 ? 32 : _ref$maxPatternLength, + _ref$isCaseSensitive = _ref.isCaseSensitive, + isCaseSensitive = _ref$isCaseSensitive === void 0 ? false : _ref$isCaseSensitive, + _ref$tokenSeparator = _ref.tokenSeparator, + tokenSeparator = _ref$tokenSeparator === void 0 ? / +/g : _ref$tokenSeparator, + _ref$findAllMatches = _ref.findAllMatches, + findAllMatches = _ref$findAllMatches === void 0 ? false : _ref$findAllMatches, + _ref$minMatchCharLeng = _ref.minMatchCharLength, + minMatchCharLength = _ref$minMatchCharLeng === void 0 ? 1 : _ref$minMatchCharLeng; + + _classCallCheck(this, Bitap); + + this.options = { + location: location, + distance: distance, + threshold: threshold, + maxPatternLength: maxPatternLength, + isCaseSensitive: isCaseSensitive, + tokenSeparator: tokenSeparator, + findAllMatches: findAllMatches, + minMatchCharLength: minMatchCharLength + }; + this.pattern = this.options.isCaseSensitive ? pattern : pattern.toLowerCase(); + + if (this.pattern.length <= maxPatternLength) { + this.patternAlphabet = patternAlphabet(this.pattern); + } + } + + _createClass(Bitap, [{ + key: "search", + value: function search(text) { + if (!this.options.isCaseSensitive) { + text = text.toLowerCase(); + } // Exact match + + + if (this.pattern === text) { + return { + isMatch: true, + score: 0, + matchedIndices: [[0, text.length - 1]] + }; + } // When pattern length is greater than the machine word length, just do a a regex comparison + + + var _this$options = this.options, + maxPatternLength = _this$options.maxPatternLength, + tokenSeparator = _this$options.tokenSeparator; + + if (this.pattern.length > maxPatternLength) { + return bitapRegexSearch(text, this.pattern, tokenSeparator); + } // Otherwise, use Bitap algorithm + + + var _this$options2 = this.options, + location = _this$options2.location, + distance = _this$options2.distance, + threshold = _this$options2.threshold, + findAllMatches = _this$options2.findAllMatches, + minMatchCharLength = _this$options2.minMatchCharLength; + return bitapSearch(text, this.pattern, this.patternAlphabet, { + location: location, + distance: distance, + threshold: threshold, + findAllMatches: findAllMatches, + minMatchCharLength: minMatchCharLength + }); + } + }]); + + return Bitap; +}(); // let x = new Bitap("od mn war", {}) +// let result = x.search("Old Man's War") +// console.log(result) + + +module.exports = Bitap; + +/***/ }), + +/***/ "./src/helpers/deep_value.js": +/*!***********************************!*\ + !*** ./src/helpers/deep_value.js ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var isArray = __webpack_require__(/*! ./is_array */ "./src/helpers/is_array.js"); + +var deepValue = function deepValue(obj, path, list) { + if (!path) { + // If there's no path left, we've gotten to the object we care about. + list.push(obj); + } else { + var dotIndex = path.indexOf('.'); + var firstSegment = path; + var remaining = null; + + if (dotIndex !== -1) { + firstSegment = path.slice(0, dotIndex); + remaining = path.slice(dotIndex + 1); + } + + var value = obj[firstSegment]; + + if (value !== null && value !== undefined) { + if (!remaining && (typeof value === 'string' || typeof value === 'number')) { + list.push(value.toString()); + } else if (isArray(value)) { + // Search each item in the array. + for (var i = 0, len = value.length; i < len; i += 1) { + deepValue(value[i], remaining, list); + } + } else if (remaining) { + // An object. Recurse further. + deepValue(value, remaining, list); + } + } + } + + return list; +}; + +module.exports = function (obj, path) { + return deepValue(obj, path, []); +}; + +/***/ }), + +/***/ "./src/helpers/is_array.js": +/*!*********************************!*\ + !*** ./src/helpers/is_array.js ***! + \*********************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (obj) { + return !Array.isArray ? Object.prototype.toString.call(obj) === '[object Array]' : Array.isArray(obj); +}; + +/***/ }), + +/***/ "./src/index.js": +/*!**********************!*\ + !*** ./src/index.js ***! + \**********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var Bitap = __webpack_require__(/*! ./bitap */ "./src/bitap/index.js"); + +var deepValue = __webpack_require__(/*! ./helpers/deep_value */ "./src/helpers/deep_value.js"); + +var isArray = __webpack_require__(/*! ./helpers/is_array */ "./src/helpers/is_array.js"); + +var Fuse = +/*#__PURE__*/ +function () { + function Fuse(list, _ref) { + var _ref$location = _ref.location, + location = _ref$location === void 0 ? 0 : _ref$location, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? 100 : _ref$distance, + _ref$threshold = _ref.threshold, + threshold = _ref$threshold === void 0 ? 0.6 : _ref$threshold, + _ref$maxPatternLength = _ref.maxPatternLength, + maxPatternLength = _ref$maxPatternLength === void 0 ? 32 : _ref$maxPatternLength, + _ref$caseSensitive = _ref.caseSensitive, + caseSensitive = _ref$caseSensitive === void 0 ? false : _ref$caseSensitive, + _ref$tokenSeparator = _ref.tokenSeparator, + tokenSeparator = _ref$tokenSeparator === void 0 ? / +/g : _ref$tokenSeparator, + _ref$findAllMatches = _ref.findAllMatches, + findAllMatches = _ref$findAllMatches === void 0 ? false : _ref$findAllMatches, + _ref$minMatchCharLeng = _ref.minMatchCharLength, + minMatchCharLength = _ref$minMatchCharLeng === void 0 ? 1 : _ref$minMatchCharLeng, + _ref$id = _ref.id, + id = _ref$id === void 0 ? null : _ref$id, + _ref$keys = _ref.keys, + keys = _ref$keys === void 0 ? [] : _ref$keys, + _ref$shouldSort = _ref.shouldSort, + shouldSort = _ref$shouldSort === void 0 ? true : _ref$shouldSort, + _ref$getFn = _ref.getFn, + getFn = _ref$getFn === void 0 ? deepValue : _ref$getFn, + _ref$sortFn = _ref.sortFn, + sortFn = _ref$sortFn === void 0 ? function (a, b) { + return a.score - b.score; + } : _ref$sortFn, + _ref$tokenize = _ref.tokenize, + tokenize = _ref$tokenize === void 0 ? false : _ref$tokenize, + _ref$matchAllTokens = _ref.matchAllTokens, + matchAllTokens = _ref$matchAllTokens === void 0 ? false : _ref$matchAllTokens, + _ref$includeMatches = _ref.includeMatches, + includeMatches = _ref$includeMatches === void 0 ? false : _ref$includeMatches, + _ref$includeScore = _ref.includeScore, + includeScore = _ref$includeScore === void 0 ? false : _ref$includeScore, + _ref$verbose = _ref.verbose, + verbose = _ref$verbose === void 0 ? false : _ref$verbose; + + _classCallCheck(this, Fuse); + + this.options = { + location: location, + distance: distance, + threshold: threshold, + maxPatternLength: maxPatternLength, + isCaseSensitive: caseSensitive, + tokenSeparator: tokenSeparator, + findAllMatches: findAllMatches, + minMatchCharLength: minMatchCharLength, + id: id, + keys: keys, + includeMatches: includeMatches, + includeScore: includeScore, + shouldSort: shouldSort, + getFn: getFn, + sortFn: sortFn, + verbose: verbose, + tokenize: tokenize, + matchAllTokens: matchAllTokens + }; + this.setCollection(list); + } + + _createClass(Fuse, [{ + key: "setCollection", + value: function setCollection(list) { + this.list = list; + return list; + } + }, { + key: "search", + value: function search(pattern) { + var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + limit: false + }; + + this._log("---------\nSearch pattern: \"".concat(pattern, "\"")); + + var _this$_prepareSearche = this._prepareSearchers(pattern), + tokenSearchers = _this$_prepareSearche.tokenSearchers, + fullSearcher = _this$_prepareSearche.fullSearcher; + + var _this$_search = this._search(tokenSearchers, fullSearcher), + weights = _this$_search.weights, + results = _this$_search.results; + + this._computeScore(weights, results); + + if (this.options.shouldSort) { + this._sort(results); + } + + if (opts.limit && typeof opts.limit === 'number') { + results = results.slice(0, opts.limit); + } + + return this._format(results); + } + }, { + key: "_prepareSearchers", + value: function _prepareSearchers() { + var pattern = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var tokenSearchers = []; + + if (this.options.tokenize) { + // Tokenize on the separator + var tokens = pattern.split(this.options.tokenSeparator); + + for (var i = 0, len = tokens.length; i < len; i += 1) { + tokenSearchers.push(new Bitap(tokens[i], this.options)); + } + } + + var fullSearcher = new Bitap(pattern, this.options); + return { + tokenSearchers: tokenSearchers, + fullSearcher: fullSearcher + }; + } + }, { + key: "_search", + value: function _search() { + var tokenSearchers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var fullSearcher = arguments.length > 1 ? arguments[1] : undefined; + var list = this.list; + var resultMap = {}; + var results = []; // Check the first item in the list, if it's a string, then we assume + // that every item in the list is also a string, and thus it's a flattened array. + + if (typeof list[0] === 'string') { + // Iterate over every item + for (var i = 0, len = list.length; i < len; i += 1) { + this._analyze({ + key: '', + value: list[i], + record: i, + index: i + }, { + resultMap: resultMap, + results: results, + tokenSearchers: tokenSearchers, + fullSearcher: fullSearcher + }); + } + + return { + weights: null, + results: results + }; + } // Otherwise, the first item is an Object (hopefully), and thus the searching + // is done on the values of the keys of each item. + + + var weights = {}; + + for (var _i = 0, _len = list.length; _i < _len; _i += 1) { + var item = list[_i]; // Iterate over every key + + for (var j = 0, keysLen = this.options.keys.length; j < keysLen; j += 1) { + var key = this.options.keys[j]; + + if (typeof key !== 'string') { + weights[key.name] = { + weight: 1 - key.weight || 1 + }; + + if (key.weight <= 0 || key.weight > 1) { + throw new Error('Key weight has to be > 0 and <= 1'); + } + + key = key.name; + } else { + weights[key] = { + weight: 1 + }; + } + + this._analyze({ + key: key, + value: this.options.getFn(item, key), + record: item, + index: _i + }, { + resultMap: resultMap, + results: results, + tokenSearchers: tokenSearchers, + fullSearcher: fullSearcher + }); + } + } + + return { + weights: weights, + results: results + }; + } + }, { + key: "_analyze", + value: function _analyze(_ref2, _ref3) { + var key = _ref2.key, + _ref2$arrayIndex = _ref2.arrayIndex, + arrayIndex = _ref2$arrayIndex === void 0 ? -1 : _ref2$arrayIndex, + value = _ref2.value, + record = _ref2.record, + index = _ref2.index; + var _ref3$tokenSearchers = _ref3.tokenSearchers, + tokenSearchers = _ref3$tokenSearchers === void 0 ? [] : _ref3$tokenSearchers, + _ref3$fullSearcher = _ref3.fullSearcher, + fullSearcher = _ref3$fullSearcher === void 0 ? [] : _ref3$fullSearcher, + _ref3$resultMap = _ref3.resultMap, + resultMap = _ref3$resultMap === void 0 ? {} : _ref3$resultMap, + _ref3$results = _ref3.results, + results = _ref3$results === void 0 ? [] : _ref3$results; + + // Check if the texvaluet can be searched + if (value === undefined || value === null) { + return; + } + + var exists = false; + var averageScore = -1; + var numTextMatches = 0; + + if (typeof value === 'string') { + this._log("\nKey: ".concat(key === '' ? '-' : key)); + + var mainSearchResult = fullSearcher.search(value); + + this._log("Full text: \"".concat(value, "\", score: ").concat(mainSearchResult.score)); + + if (this.options.tokenize) { + var words = value.split(this.options.tokenSeparator); + var scores = []; + + for (var i = 0; i < tokenSearchers.length; i += 1) { + var tokenSearcher = tokenSearchers[i]; + + this._log("\nPattern: \"".concat(tokenSearcher.pattern, "\"")); // let tokenScores = [] + + + var hasMatchInText = false; + + for (var j = 0; j < words.length; j += 1) { + var word = words[j]; + var tokenSearchResult = tokenSearcher.search(word); + var obj = {}; + + if (tokenSearchResult.isMatch) { + obj[word] = tokenSearchResult.score; + exists = true; + hasMatchInText = true; + scores.push(tokenSearchResult.score); + } else { + obj[word] = 1; + + if (!this.options.matchAllTokens) { + scores.push(1); + } + } + + this._log("Token: \"".concat(word, "\", score: ").concat(obj[word])); // tokenScores.push(obj) + + } + + if (hasMatchInText) { + numTextMatches += 1; + } + } + + averageScore = scores[0]; + var scoresLen = scores.length; + + for (var _i2 = 1; _i2 < scoresLen; _i2 += 1) { + averageScore += scores[_i2]; + } + + averageScore = averageScore / scoresLen; + + this._log('Token score average:', averageScore); + } + + var finalScore = mainSearchResult.score; + + if (averageScore > -1) { + finalScore = (finalScore + averageScore) / 2; + } + + this._log('Score average:', finalScore); + + var checkTextMatches = this.options.tokenize && this.options.matchAllTokens ? numTextMatches >= tokenSearchers.length : true; + + this._log("\nCheck Matches: ".concat(checkTextMatches)); // If a match is found, add the item to , including its score + + + if ((exists || mainSearchResult.isMatch) && checkTextMatches) { + // Check if the item already exists in our results + var existingResult = resultMap[index]; + + if (existingResult) { + // Use the lowest score + // existingResult.score, bitapResult.score + existingResult.output.push({ + key: key, + arrayIndex: arrayIndex, + value: value, + score: finalScore, + matchedIndices: mainSearchResult.matchedIndices + }); + } else { + // Add it to the raw result list + resultMap[index] = { + item: record, + output: [{ + key: key, + arrayIndex: arrayIndex, + value: value, + score: finalScore, + matchedIndices: mainSearchResult.matchedIndices + }] + }; + results.push(resultMap[index]); + } + } + } else if (isArray(value)) { + for (var _i3 = 0, len = value.length; _i3 < len; _i3 += 1) { + this._analyze({ + key: key, + arrayIndex: _i3, + value: value[_i3], + record: record, + index: index + }, { + resultMap: resultMap, + results: results, + tokenSearchers: tokenSearchers, + fullSearcher: fullSearcher + }); + } + } + } + }, { + key: "_computeScore", + value: function _computeScore(weights, results) { + this._log('\n\nComputing score:\n'); + + for (var i = 0, len = results.length; i < len; i += 1) { + var output = results[i].output; + var scoreLen = output.length; + var currScore = 1; + var bestScore = 1; + + for (var j = 0; j < scoreLen; j += 1) { + var weight = weights ? weights[output[j].key].weight : 1; + var score = weight === 1 ? output[j].score : output[j].score || 0.001; + var nScore = score * weight; + + if (weight !== 1) { + bestScore = Math.min(bestScore, nScore); + } else { + output[j].nScore = nScore; + currScore *= nScore; + } + } + + results[i].score = bestScore === 1 ? currScore : bestScore; + + this._log(results[i]); + } + } + }, { + key: "_sort", + value: function _sort(results) { + this._log('\n\nSorting....'); + + results.sort(this.options.sortFn); + } + }, { + key: "_format", + value: function _format(results) { + var finalOutput = []; + + if (this.options.verbose) { + var cache = []; + + this._log('\n\nOutput:\n\n', JSON.stringify(results, function (key, value) { + if (_typeof(value) === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Circular reference found, discard key + return; + } // Store value in our collection + + + cache.push(value); + } + + return value; + })); + + cache = null; + } + + var transformers = []; + + if (this.options.includeMatches) { + transformers.push(function (result, data) { + var output = result.output; + data.matches = []; + + for (var i = 0, len = output.length; i < len; i += 1) { + var item = output[i]; + + if (item.matchedIndices.length === 0) { + continue; + } + + var obj = { + indices: item.matchedIndices, + value: item.value + }; + + if (item.key) { + obj.key = item.key; + } + + if (item.hasOwnProperty('arrayIndex') && item.arrayIndex > -1) { + obj.arrayIndex = item.arrayIndex; + } + + data.matches.push(obj); + } + }); + } + + if (this.options.includeScore) { + transformers.push(function (result, data) { + data.score = result.score; + }); + } + + for (var i = 0, len = results.length; i < len; i += 1) { + var result = results[i]; + + if (this.options.id) { + result.item = this.options.getFn(result.item, this.options.id)[0]; + } + + if (!transformers.length) { + finalOutput.push(result.item); + continue; + } + + var data = { + item: result.item + }; + + for (var j = 0, _len2 = transformers.length; j < _len2; j += 1) { + transformers[j](result, data); + } + + finalOutput.push(data); + } + + return finalOutput; + } + }, { + key: "_log", + value: function _log() { + if (this.options.verbose) { + var _console; + + (_console = console).log.apply(_console, arguments); + } + } + }]); + + return Fuse; +}(); + +module.exports = Fuse; + +/***/ }) + +/******/ }); +}); + +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +var isMergeableObject = function isMergeableObject(value) { + return isNonNullObject(value) + && !isSpecial(value) +}; + +function isNonNullObject(value) { + return !!value && typeof value === 'object' +} + +function isSpecial(value) { + var stringValue = Object.prototype.toString.call(value); + + return stringValue === '[object RegExp]' + || stringValue === '[object Date]' + || isReactElement(value) +} + +// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25 +var canUseSymbol = typeof Symbol === 'function' && Symbol.for; +var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7; + +function isReactElement(value) { + return value.$$typeof === REACT_ELEMENT_TYPE +} + +function emptyTarget(val) { + return Array.isArray(val) ? [] : {} +} + +function cloneUnlessOtherwiseSpecified(value, options) { + return (options.clone !== false && options.isMergeableObject(value)) + ? deepmerge(emptyTarget(value), value, options) + : value +} + +function defaultArrayMerge(target, source, options) { + return target.concat(source).map(function(element) { + return cloneUnlessOtherwiseSpecified(element, options) + }) +} + +function mergeObject(target, source, options) { + var destination = {}; + if (options.isMergeableObject(target)) { + Object.keys(target).forEach(function(key) { + destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); + }); + } + Object.keys(source).forEach(function(key) { + if (!options.isMergeableObject(source[key]) || !target[key]) { + destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); + } else { + destination[key] = deepmerge(target[key], source[key], options); + } + }); + return destination +} + +function deepmerge(target, source, options) { + options = options || {}; + options.arrayMerge = options.arrayMerge || defaultArrayMerge; + options.isMergeableObject = options.isMergeableObject || isMergeableObject; + + var sourceIsArray = Array.isArray(source); + var targetIsArray = Array.isArray(target); + var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; + + if (!sourceAndTargetTypesMatch) { + return cloneUnlessOtherwiseSpecified(source, options) + } else if (sourceIsArray) { + return options.arrayMerge(target, source, options) + } else { + return mergeObject(target, source, options) + } +} + +deepmerge.all = function deepmergeAll(array, options) { + if (!Array.isArray(array)) { + throw new Error('first argument should be an array') + } + + return array.reduce(function(prev, next) { + return deepmerge(prev, next, options) + }, {}) +}; + +var deepmerge_1 = deepmerge; + +/* harmony default export */ __webpack_exports__["default"] = (deepmerge_1); + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _redux = __webpack_require__(6); + +var _index = _interopRequireDefault(__webpack_require__(15)); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var Store = +/*#__PURE__*/ +function () { + function Store() { + _classCallCheck(this, Store); + + this._store = (0, _redux.createStore)(_index.default, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); + } + /** + * Subscribe store to function call (wrapped Redux method) + * @param {Function} onChange Function to trigger when state changes + * @return + */ + + + _createClass(Store, [{ + key: "subscribe", + value: function subscribe(onChange) { + this._store.subscribe(onChange); + } + /** + * Dispatch event to store (wrapped Redux method) + * @param {Function} action Action function to trigger + * @return + */ + + }, { + key: "dispatch", + value: function dispatch(action) { + this._store.dispatch(action); + } + /** + * Get store object (wrapping Redux method) + * @return {Object} State + */ + + }, { + key: "isLoading", + + /** + * Get loading state from store + * @return {Boolean} Loading State + */ + value: function isLoading() { + return this.state.general.loading; + } + /** + * Get single choice by it's ID + * @return {Object} Found choice + */ + + }, { + key: "getChoiceById", + value: function getChoiceById(id) { + if (id) { + var choices = this.activeChoices; + var foundChoice = choices.find(function (choice) { + return choice.id === parseInt(id, 10); + }); + return foundChoice; + } + + return false; + } + /** + * Get group by group id + * @param {Number} id Group ID + * @return {Object} Group data + */ + + }, { + key: "getGroupById", + value: function getGroupById(id) { + return this.groups.find(function (group) { + return group.id === parseInt(id, 10); + }); + } + }, { + key: "state", + get: function get() { + return this._store.getState(); + } + /** + * Get items from store + * @return {Array} Item objects + */ + + }, { + key: "items", + get: function get() { + return this.state.items; + } + /** + * Get active items from store + * @return {Array} Item objects + */ + + }, { + key: "activeItems", + get: function get() { + return this.items.filter(function (item) { + return item.active === true; + }); + } + /** + * Get highlighted items from store + * @return {Array} Item objects + */ + + }, { + key: "highlightedActiveItems", + get: function get() { + return this.items.filter(function (item) { + return item.active && item.highlighted; + }); + } + /** + * Get choices from store + * @return {Array} Option objects + */ + + }, { + key: "choices", + get: function get() { + return this.state.choices; + } + /** + * Get active choices from store + * @return {Array} Option objects + */ + + }, { + key: "activeChoices", + get: function get() { + var choices = this.choices; + var values = choices.filter(function (choice) { + return choice.active === true; + }); + return values; + } + /** + * Get selectable choices from store + * @return {Array} Option objects + */ + + }, { + key: "selectableChoices", + get: function get() { + return this.choices.filter(function (choice) { + return choice.disabled !== true; + }); + } + /** + * Get choices that can be searched (excluding placeholders) + * @return {Array} Option objects + */ + + }, { + key: "searchableChoices", + get: function get() { + return this.selectableChoices.filter(function (choice) { + return choice.placeholder !== true; + }); + } + /** + * Get placeholder choice from store + * @return {Object} Found placeholder + */ + + }, { + key: "placeholderChoice", + get: function get() { + return [].concat(this.choices).reverse().find(function (choice) { + return choice.placeholder === true; + }); + } + /** + * Get groups from store + * @return {Array} Group objects + */ + + }, { + key: "groups", + get: function get() { + return this.state.groups; + } + /** + * Get active groups from store + * @return {Array} Group objects + */ + + }, { + key: "activeGroups", + get: function get() { + var groups = this.groups; + var choices = this.choices; + return groups.filter(function (group) { + var isActive = group.active === true && group.disabled === false; + var hasActiveOptions = choices.some(function (choice) { + return choice.active === true && choice.disabled === false; + }); + return isActive && hasActiveOptions; + }, []); + } + }]); + + return Store; +}(); + +exports.default = Store; + +/***/ }), +/* 14 */ +/***/ (function(module, exports) { + +module.exports = function(originalModule) { + if (!originalModule.webpackPolyfill) { + var module = Object.create(originalModule); + // module.parent = undefined by default + if (!module.children) module.children = []; + Object.defineProperty(module, "loaded", { + enumerable: true, + get: function() { + return module.l; + } + }); + Object.defineProperty(module, "id", { + enumerable: true, + get: function() { + return module.i; + } + }); + Object.defineProperty(module, "exports", { + enumerable: true + }); + module.webpackPolyfill = 1; + } + return module; +}; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _redux = __webpack_require__(6); + +var _items = _interopRequireDefault(__webpack_require__(16)); + +var _groups = _interopRequireDefault(__webpack_require__(17)); + +var _choices = _interopRequireDefault(__webpack_require__(18)); + +var _general = _interopRequireDefault(__webpack_require__(19)); + +var _utils = __webpack_require__(0); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var appReducer = (0, _redux.combineReducers)({ + items: _items.default, + groups: _groups.default, + choices: _choices.default, + general: _general.default +}); + +var rootReducer = function rootReducer(passedState, action) { + var state = passedState; // If we are clearing all items, groups and options we reassign + // state and then pass that state to our proper reducer. This isn't + // mutating our actual state + // See: http://stackoverflow.com/a/35641992 + + if (action.type === 'CLEAR_ALL') { + state = undefined; + } else if (action.type === 'RESET_TO') { + return (0, _utils.cloneObject)(action.state); + } + + return appReducer(state, action); +}; + +var _default = rootReducer; +exports.default = _default; + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = items; +exports.defaultState = void 0; +var defaultState = []; +exports.defaultState = defaultState; + +function items() { + var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultState; + var action = arguments.length > 1 ? arguments[1] : undefined; + + switch (action.type) { + case 'ADD_ITEM': + { + // Add object to items array + var newState = [].concat(state, [{ + id: action.id, + choiceId: action.choiceId, + groupId: action.groupId, + value: action.value, + label: action.label, + active: true, + highlighted: false, + customProperties: action.customProperties, + placeholder: action.placeholder || false, + keyCode: null + }]); + return newState.map(function (obj) { + var item = obj; + item.highlighted = false; + return item; + }); + } + + case 'REMOVE_ITEM': + { + // Set item to inactive + return state.map(function (obj) { + var item = obj; + + if (item.id === action.id) { + item.active = false; + } + + return item; + }); + } + + case 'HIGHLIGHT_ITEM': + { + return state.map(function (obj) { + var item = obj; + + if (item.id === action.id) { + item.highlighted = action.highlighted; + } + + return item; + }); + } + + default: + { + return state; + } + } +} + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = groups; +exports.defaultState = void 0; +var defaultState = []; +exports.defaultState = defaultState; + +function groups() { + var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultState; + var action = arguments.length > 1 ? arguments[1] : undefined; + + switch (action.type) { + case 'ADD_GROUP': + { + return [].concat(state, [{ + id: action.id, + value: action.value, + active: action.active, + disabled: action.disabled + }]); + } + + case 'CLEAR_CHOICES': + { + return []; + } + + default: + { + return state; + } + } +} + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = choices; +exports.defaultState = void 0; +var defaultState = []; +exports.defaultState = defaultState; + +function choices() { + var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultState; + var action = arguments.length > 1 ? arguments[1] : undefined; + + switch (action.type) { + case 'ADD_CHOICE': + { + /* + A disabled choice appears in the choice dropdown but cannot be selected + A selected choice has been added to the passed input's value (added as an item) + An active choice appears within the choice dropdown + */ + return [].concat(state, [{ + id: action.id, + elementId: action.elementId, + groupId: action.groupId, + value: action.value, + label: action.label || action.value, + disabled: action.disabled || false, + selected: false, + active: true, + score: 9999, + customProperties: action.customProperties, + placeholder: action.placeholder || false, + keyCode: null + }]); + } + + case 'ADD_ITEM': + { + // If all choices need to be activated + if (action.activateOptions) { + return state.map(function (obj) { + var choice = obj; + choice.active = action.active; + return choice; + }); + } // When an item is added and it has an associated choice, + // we want to disable it so it can't be chosen again + + + if (action.choiceId > -1) { + return state.map(function (obj) { + var choice = obj; + + if (choice.id === parseInt(action.choiceId, 10)) { + choice.selected = true; + } + + return choice; + }); + } + + return state; + } + + case 'REMOVE_ITEM': + { + // When an item is removed and it has an associated choice, + // we want to re-enable it so it can be chosen again + if (action.choiceId > -1) { + return state.map(function (obj) { + var choice = obj; + + if (choice.id === parseInt(action.choiceId, 10)) { + choice.selected = false; + } + + return choice; + }); + } + + return state; + } + + case 'FILTER_CHOICES': + { + return state.map(function (obj) { + var choice = obj; // Set active state based on whether choice is + // within filtered results + + choice.active = action.results.some(function (_ref) { + var item = _ref.item, + score = _ref.score; + + if (item.id === choice.id) { + choice.score = score; + return true; + } + + return false; + }); + return choice; + }); + } + + case 'ACTIVATE_CHOICES': + { + return state.map(function (obj) { + var choice = obj; + choice.active = action.active; + return choice; + }); + } + + case 'CLEAR_CHOICES': + { + return defaultState; + } + + default: + { + return state; + } + } +} + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.defaultState = void 0; +var defaultState = { + loading: false +}; +exports.defaultState = defaultState; + +var general = function general() { + var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultState; + var action = arguments.length > 1 ? arguments[1] : undefined; + + switch (action.type) { + case 'SET_IS_LOADING': + { + return { + loading: action.isLoading + }; + } + + default: + { + return state; + } + } +}; + +var _default = general; +exports.default = _default; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "Dropdown", { + enumerable: true, + get: function get() { + return _dropdown.default; + } +}); +Object.defineProperty(exports, "Container", { + enumerable: true, + get: function get() { + return _container.default; + } +}); +Object.defineProperty(exports, "Input", { + enumerable: true, + get: function get() { + return _input.default; + } +}); +Object.defineProperty(exports, "List", { + enumerable: true, + get: function get() { + return _list.default; + } +}); +Object.defineProperty(exports, "WrappedInput", { + enumerable: true, + get: function get() { + return _wrappedInput.default; + } +}); +Object.defineProperty(exports, "WrappedSelect", { + enumerable: true, + get: function get() { + return _wrappedSelect.default; + } +}); + +var _dropdown = _interopRequireDefault(__webpack_require__(21)); + +var _container = _interopRequireDefault(__webpack_require__(22)); + +var _input = _interopRequireDefault(__webpack_require__(23)); + +var _list = _interopRequireDefault(__webpack_require__(24)); + +var _wrappedInput = _interopRequireDefault(__webpack_require__(25)); + +var _wrappedSelect = _interopRequireDefault(__webpack_require__(26)); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var Dropdown = +/*#__PURE__*/ +function () { + function Dropdown(_ref) { + var element = _ref.element, + type = _ref.type, + classNames = _ref.classNames; + + _classCallCheck(this, Dropdown); + + Object.assign(this, { + element: element, + type: type, + classNames: classNames + }); + this.isActive = false; + } + /** + * Determine how far the top of our element is from + * the top of the window + * @return {Number} Vertical position + */ + + + _createClass(Dropdown, [{ + key: "distanceFromTopWindow", + value: function distanceFromTopWindow() { + this.dimensions = this.element.getBoundingClientRect(); + this.position = Math.ceil(this.dimensions.top + window.pageYOffset + this.element.offsetHeight); + return this.position; + } + /** + * Find element that matches passed selector + * @return {HTMLElement} + */ + + }, { + key: "getChild", + value: function getChild(selector) { + return this.element.querySelector(selector); + } + /** + * Show dropdown to user by adding active state class + * @return {Object} Class instance + * @public + */ + + }, { + key: "show", + value: function show() { + this.element.classList.add(this.classNames.activeState); + this.element.setAttribute('aria-expanded', 'true'); + this.isActive = true; + return this; + } + /** + * Hide dropdown from user + * @return {Object} Class instance + * @public + */ + + }, { + key: "hide", + value: function hide() { + this.element.classList.remove(this.classNames.activeState); + this.element.setAttribute('aria-expanded', 'false'); + this.isActive = false; + return this; + } + }]); + + return Dropdown; +}(); + +exports.default = Dropdown; + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _utils = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var Container = +/*#__PURE__*/ +function () { + function Container(_ref) { + var element = _ref.element, + type = _ref.type, + classNames = _ref.classNames, + position = _ref.position; + + _classCallCheck(this, Container); + + Object.assign(this, { + element: element, + classNames: classNames, + type: type, + position: position + }); + this.isOpen = false; + this.isFlipped = false; + this.isFocussed = false; + this.isDisabled = false; + this.isLoading = false; + this._onFocus = this._onFocus.bind(this); + this._onBlur = this._onBlur.bind(this); + } + /** + * Add event listeners + */ + + + _createClass(Container, [{ + key: "addEventListeners", + value: function addEventListeners() { + this.element.addEventListener('focus', this._onFocus); + this.element.addEventListener('blur', this._onBlur); + } + /** + * Remove event listeners + */ + + /** */ + + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + this.element.removeEventListener('focus', this._onFocus); + this.element.removeEventListener('blur', this._onBlur); + } + /** + * Determine whether container should be flipped + * based on passed dropdown position + * @param {Number} dropdownPos + * @returns + */ + + }, { + key: "shouldFlip", + value: function shouldFlip(dropdownPos) { + var windowHeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : (0, _utils.getWindowHeight)(); + + if (dropdownPos === undefined) { + return false; + } // If flip is enabled and the dropdown bottom position is + // greater than the window height flip the dropdown. + + + var shouldFlip = false; + + if (this.position === 'auto') { + shouldFlip = dropdownPos >= windowHeight; + } else if (this.position === 'top') { + shouldFlip = true; + } + + return shouldFlip; + } + /** + * Set active descendant attribute + * @param {Number} activeDescendant ID of active descendant + */ + + }, { + key: "setActiveDescendant", + value: function setActiveDescendant(activeDescendantID) { + this.element.setAttribute('aria-activedescendant', activeDescendantID); + } + /** + * Remove active descendant attribute + */ + + }, { + key: "removeActiveDescendant", + value: function removeActiveDescendant() { + this.element.removeAttribute('aria-activedescendant'); + } + }, { + key: "open", + value: function open(dropdownPos) { + this.element.classList.add(this.classNames.openState); + this.element.setAttribute('aria-expanded', 'true'); + this.isOpen = true; + + if (this.shouldFlip(dropdownPos)) { + this.element.classList.add(this.classNames.flippedState); + this.isFlipped = true; + } + } + }, { + key: "close", + value: function close() { + this.element.classList.remove(this.classNames.openState); + this.element.setAttribute('aria-expanded', 'false'); + this.removeActiveDescendant(); + this.isOpen = false; // A dropdown flips if it does not have space within the page + + if (this.isFlipped) { + this.element.classList.remove(this.classNames.flippedState); + this.isFlipped = false; + } + } + }, { + key: "focus", + value: function focus() { + if (!this.isFocussed) { + this.element.focus(); + } + } + }, { + key: "addFocusState", + value: function addFocusState() { + this.element.classList.add(this.classNames.focusState); + } + }, { + key: "removeFocusState", + value: function removeFocusState() { + this.element.classList.remove(this.classNames.focusState); + } + /** + * Remove disabled state + */ + + }, { + key: "enable", + value: function enable() { + this.element.classList.remove(this.classNames.disabledState); + this.element.removeAttribute('aria-disabled'); + + if (this.type === 'select-one') { + this.element.setAttribute('tabindex', '0'); + } + + this.isDisabled = false; + } + /** + * Set disabled state + */ + + }, { + key: "disable", + value: function disable() { + this.element.classList.add(this.classNames.disabledState); + this.element.setAttribute('aria-disabled', 'true'); + + if (this.type === 'select-one') { + this.element.setAttribute('tabindex', '-1'); + } + + this.isDisabled = true; + } + }, { + key: "wrap", + value: function wrap(element) { + (0, _utils.wrap)(element, this.element); + } + }, { + key: "unwrap", + value: function unwrap(element) { + // Move passed element outside this element + this.element.parentNode.insertBefore(element, this.element); // Remove this element + + this.element.parentNode.removeChild(this.element); + } + /** + * Add loading state to element + */ + + }, { + key: "addLoadingState", + value: function addLoadingState() { + this.element.classList.add(this.classNames.loadingState); + this.element.setAttribute('aria-busy', 'true'); + this.isLoading = true; + } + /** + * Remove loading state from element + */ + + }, { + key: "removeLoadingState", + value: function removeLoadingState() { + this.element.classList.remove(this.classNames.loadingState); + this.element.removeAttribute('aria-busy'); + this.isLoading = false; + } + /** + * Set focussed state + */ + + }, { + key: "_onFocus", + value: function _onFocus() { + this.isFocussed = true; + } + /** + * Remove blurred state + */ + + }, { + key: "_onBlur", + value: function _onBlur() { + this.isFocussed = false; + } + }]); + + return Container; +}(); + +exports.default = Container; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _utils = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var Input = +/*#__PURE__*/ +function () { + function Input(_ref) { + var element = _ref.element, + type = _ref.type, + classNames = _ref.classNames, + placeholderValue = _ref.placeholderValue; + + _classCallCheck(this, Input); + + Object.assign(this, { + element: element, + type: type, + classNames: classNames, + placeholderValue: placeholderValue + }); + this.element = element; + this.classNames = classNames; + this.isFocussed = this.element === document.activeElement; + this.isDisabled = false; + this._onPaste = this._onPaste.bind(this); + this._onInput = this._onInput.bind(this); + this._onFocus = this._onFocus.bind(this); + this._onBlur = this._onBlur.bind(this); + } + + _createClass(Input, [{ + key: "addEventListeners", + value: function addEventListeners() { + this.element.addEventListener('input', this._onInput); + this.element.addEventListener('paste', this._onPaste); + this.element.addEventListener('focus', this._onFocus); + this.element.addEventListener('blur', this._onBlur); + + if (this.element.form) { + this.element.form.addEventListener('reset', this._onFormReset); + } + } + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + this.element.removeEventListener('input', this._onInput); + this.element.removeEventListener('paste', this._onPaste); + this.element.removeEventListener('focus', this._onFocus); + this.element.removeEventListener('blur', this._onBlur); + + if (this.element.form) { + this.element.form.removeEventListener('reset', this._onFormReset); + } + } + }, { + key: "enable", + value: function enable() { + this.element.removeAttribute('disabled'); + this.isDisabled = false; + } + }, { + key: "disable", + value: function disable() { + this.element.setAttribute('disabled', ''); + this.isDisabled = true; + } + }, { + key: "focus", + value: function focus() { + if (!this.isFocussed) { + this.element.focus(); + } + } + }, { + key: "blur", + value: function blur() { + if (this.isFocussed) { + this.element.blur(); + } + } + /** + * Set value of input to blank + * @return {Object} Class instance + * @public + */ + + }, { + key: "clear", + value: function clear() { + var setWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + + if (this.element.value) { + this.element.value = ''; + } + + if (setWidth) { + this.setWidth(); + } + + return this; + } + /** + * Set the correct input width based on placeholder + * value or input value + * @return + */ + + }, { + key: "setWidth", + value: function setWidth(enforceWidth) { + var _this = this; + + var callback = function callback(width) { + _this.element.style.width = width; + }; + + if (this._placeholderValue) { + // If there is a placeholder, we only want to set the width of the input when it is a greater + // length than 75% of the placeholder. This stops the input jumping around. + var valueHasDesiredLength = this.element.value.length >= this._placeholderValue.length / 1.25; + + if (this.element.value && valueHasDesiredLength || enforceWidth) { + this.calcWidth(callback); + } + } else { + // If there is no placeholder, resize input to contents + this.calcWidth(callback); + } + } + }, { + key: "calcWidth", + value: function calcWidth(callback) { + return (0, _utils.calcWidthOfInput)(this.element, callback); + } + }, { + key: "setActiveDescendant", + value: function setActiveDescendant(activeDescendantID) { + this.element.setAttribute('aria-activedescendant', activeDescendantID); + } + }, { + key: "removeActiveDescendant", + value: function removeActiveDescendant() { + this.element.removeAttribute('aria-activedescendant'); + } + }, { + key: "_onInput", + value: function _onInput() { + if (this.type !== 'select-one') { + this.setWidth(); + } + } + }, { + key: "_onPaste", + value: function _onPaste(event) { + var target = event.target; + + if (target === this.element && this.preventPaste) { + event.preventDefault(); + } + } + }, { + key: "_onFocus", + value: function _onFocus() { + this.isFocussed = true; + } + }, { + key: "_onBlur", + value: function _onBlur() { + this.isFocussed = false; + } + }, { + key: "placeholder", + set: function set(placeholder) { + this.element.placeholder = placeholder; + } + }, { + key: "value", + set: function set(value) { + this.element.value = value; + }, + get: function get() { + return (0, _utils.sanitise)(this.element.value); + } + }]); + + return Input; +}(); + +exports.default = Input; + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _constants = __webpack_require__(1); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var List = +/*#__PURE__*/ +function () { + function List(_ref) { + var element = _ref.element; + + _classCallCheck(this, List); + + Object.assign(this, { + element: element + }); + this.scrollPos = this.element.scrollTop; + this.height = this.element.offsetHeight; + this.hasChildren = !!this.element.children; + } + + _createClass(List, [{ + key: "clear", + value: function clear() { + this.element.innerHTML = ''; + } + }, { + key: "append", + value: function append(node) { + this.element.appendChild(node); + } + }, { + key: "getChild", + value: function getChild(selector) { + return this.element.querySelector(selector); + } + }, { + key: "scrollToTop", + value: function scrollToTop() { + this.element.scrollTop = 0; + } + }, { + key: "scrollToChoice", + value: function scrollToChoice(choice, direction) { + var _this = this; + + if (!choice) { + return; + } + + var dropdownHeight = this.element.offsetHeight; + var choiceHeight = choice.offsetHeight; // Distance from bottom of element to top of parent + + var choicePos = choice.offsetTop + choiceHeight; // Scroll position of dropdown + + var containerScrollPos = this.element.scrollTop + dropdownHeight; // Difference between the choice and scroll position + + var endpoint = direction > 0 ? this.element.scrollTop + choicePos - containerScrollPos : choice.offsetTop; + requestAnimationFrame(function (time) { + _this._animateScroll(time, endpoint, direction); + }); + } + }, { + key: "_scrollDown", + value: function _scrollDown(scrollPos, strength, endpoint) { + var easing = (endpoint - scrollPos) / strength; + var distance = easing > 1 ? easing : 1; + this.element.scrollTop = scrollPos + distance; + } + }, { + key: "_scrollUp", + value: function _scrollUp(scrollPos, strength, endpoint) { + var easing = (scrollPos - endpoint) / strength; + var distance = easing > 1 ? easing : 1; + this.element.scrollTop = scrollPos - distance; + } + }, { + key: "_animateScroll", + value: function _animateScroll(time, endpoint, direction) { + var _this2 = this; + + var strength = _constants.SCROLLING_SPEED; + var choiceListScrollTop = this.element.scrollTop; + var continueAnimation = false; + + if (direction > 0) { + this._scrollDown(choiceListScrollTop, strength, endpoint); + + if (choiceListScrollTop < endpoint) { + continueAnimation = true; + } + } else { + this._scrollUp(choiceListScrollTop, strength, endpoint); + + if (choiceListScrollTop > endpoint) { + continueAnimation = true; + } + } + + if (continueAnimation) { + requestAnimationFrame(function () { + _this2._animateScroll(time, endpoint, direction); + }); + } + } + }]); + + return List; +}(); + +exports.default = List; + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _wrappedElement = _interopRequireDefault(__webpack_require__(4)); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } + +function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +var WrappedInput = +/*#__PURE__*/ +function (_WrappedElement) { + _inherits(WrappedInput, _WrappedElement); + + function WrappedInput(_ref) { + var _this; + + var element = _ref.element, + classNames = _ref.classNames, + delimiter = _ref.delimiter; + + _classCallCheck(this, WrappedInput); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(WrappedInput).call(this, { + element: element, + classNames: classNames + })); + _this.delimiter = delimiter; + return _this; + } + + _createClass(WrappedInput, [{ + key: "value", + set: function set(items) { + var itemValues = items.map(function (_ref2) { + var value = _ref2.value; + return value; + }); + var joinedValues = itemValues.join(this.delimiter); + this.element.setAttribute('value', joinedValues); + this.element.value = joinedValues; + } // @todo figure out why we need this? Perhaps a babel issue + , + get: function get() { + return _get(_getPrototypeOf(WrappedInput.prototype), "value", this); + } + }]); + + return WrappedInput; +}(_wrappedElement.default); + +exports.default = WrappedInput; + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _wrappedElement = _interopRequireDefault(__webpack_require__(4)); + +var _templates = _interopRequireDefault(__webpack_require__(5)); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +var WrappedSelect = +/*#__PURE__*/ +function (_WrappedElement) { + _inherits(WrappedSelect, _WrappedElement); + + function WrappedSelect(_ref) { + var element = _ref.element, + classNames = _ref.classNames; + + _classCallCheck(this, WrappedSelect); + + return _possibleConstructorReturn(this, _getPrototypeOf(WrappedSelect).call(this, { + element: element, + classNames: classNames + })); + } + + _createClass(WrappedSelect, [{ + key: "appendDocFragment", + value: function appendDocFragment(fragment) { + this.element.innerHTML = ''; + this.element.appendChild(fragment); + } + }, { + key: "placeholderOption", + get: function get() { + return this.element.querySelector('option[placeholder]'); + } + }, { + key: "optionGroups", + get: function get() { + return Array.from(this.element.getElementsByTagName('OPTGROUP')); + } + }, { + key: "options", + get: function get() { + return Array.from(this.element.options); + }, + set: function set(options) { + var fragment = document.createDocumentFragment(); + + var addOptionToFragment = function addOptionToFragment(data) { + // Create a standard select option + var template = _templates.default.option(data); // Append it to fragment + + + fragment.appendChild(template); + }; // Add each list item to list + + + options.forEach(function (optionData) { + return addOptionToFragment(optionData); + }); + this.appendDocFragment(fragment); + } + }]); + + return WrappedSelect; +}(_wrappedElement.default); + +exports.default = WrappedSelect; + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! + Copyright (c) 2017 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +/* global define */ + +(function () { + 'use strict'; + + var hasOwn = {}.hasOwnProperty; + + function classNames () { + var classes = []; + + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if (!arg) continue; + + var argType = typeof arg; + + if (argType === 'string' || argType === 'number') { + classes.push(arg); + } else if (Array.isArray(arg) && arg.length) { + var inner = classNames.apply(null, arg); + if (inner) { + classes.push(inner); + } + } else if (argType === 'object') { + for (var key in arg) { + if (hasOwn.call(arg, key) && arg[key]) { + classes.push(key); + } + } + } + } + + return classes.join(' '); + } + + if ( true && module.exports) { + classNames.default = classNames; + module.exports = classNames; + } else if (true) { + // register as 'classnames', consistent with npm package name + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () { + return classNames; + }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else {} +}()); + + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.clearChoices = exports.activateChoices = exports.filterChoices = exports.addChoice = void 0; + +var _constants = __webpack_require__(1); + +var addChoice = function addChoice(_ref) { + var value = _ref.value, + label = _ref.label, + id = _ref.id, + groupId = _ref.groupId, + disabled = _ref.disabled, + elementId = _ref.elementId, + customProperties = _ref.customProperties, + placeholder = _ref.placeholder, + keyCode = _ref.keyCode; + return { + type: _constants.ACTION_TYPES.ADD_CHOICE, + value: value, + label: label, + id: id, + groupId: groupId, + disabled: disabled, + elementId: elementId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: keyCode + }; +}; + +exports.addChoice = addChoice; + +var filterChoices = function filterChoices(results) { + return { + type: _constants.ACTION_TYPES.FILTER_CHOICES, + results: results + }; +}; + +exports.filterChoices = filterChoices; + +var activateChoices = function activateChoices() { + var active = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + return { + type: _constants.ACTION_TYPES.ACTIVATE_CHOICES, + active: active + }; +}; + +exports.activateChoices = activateChoices; + +var clearChoices = function clearChoices() { + return { + type: _constants.ACTION_TYPES.CLEAR_CHOICES + }; +}; + +exports.clearChoices = clearChoices; + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.highlightItem = exports.removeItem = exports.addItem = void 0; + +var _constants = __webpack_require__(1); + +var addItem = function addItem(_ref) { + var value = _ref.value, + label = _ref.label, + id = _ref.id, + choiceId = _ref.choiceId, + groupId = _ref.groupId, + customProperties = _ref.customProperties, + placeholder = _ref.placeholder, + keyCode = _ref.keyCode; + return { + type: _constants.ACTION_TYPES.ADD_ITEM, + value: value, + label: label, + id: id, + choiceId: choiceId, + groupId: groupId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: keyCode + }; +}; + +exports.addItem = addItem; + +var removeItem = function removeItem(id, choiceId) { + return { + type: _constants.ACTION_TYPES.REMOVE_ITEM, + id: id, + choiceId: choiceId + }; +}; + +exports.removeItem = removeItem; + +var highlightItem = function highlightItem(id, highlighted) { + return { + type: _constants.ACTION_TYPES.HIGHLIGHT_ITEM, + id: id, + highlighted: highlighted + }; +}; + +exports.highlightItem = highlightItem; + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.addGroup = void 0; + +var _constants = __webpack_require__(1); + +/* eslint-disable import/prefer-default-export */ +var addGroup = function addGroup(value, id, active, disabled) { + return { + type: _constants.ACTION_TYPES.ADD_GROUP, + value: value, + id: id, + active: active, + disabled: disabled + }; +}; + +exports.addGroup = addGroup; + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.resetTo = exports.clearAll = void 0; + +var clearAll = function clearAll() { + return { + type: 'CLEAR_ALL' + }; +}; + +exports.clearAll = clearAll; + +var resetTo = function resetTo(state) { + return { + type: 'RESET_TO', + state: state + }; +}; + +exports.resetTo = resetTo; + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.setIsLoading = void 0; + +/* eslint-disable import/prefer-default-export */ +var setIsLoading = function setIsLoading(isLoading) { + return { + type: 'SET_IS_LOADING', + isLoading: isLoading + }; +}; + +exports.setIsLoading = setIsLoading; + +/***/ }) +/******/ ]); +}); \ No newline at end of file diff --git a/bin/htdocs/vendor/choices/choices.min.css b/bin/htdocs/vendor/choices/choices.min.css new file mode 100644 index 0000000..d4268fb --- /dev/null +++ b/bin/htdocs/vendor/choices/choices.min.css @@ -0,0 +1 @@ +.choices{position:relative;margin-bottom:24px;font-size:16px}.choices:focus{outline:none}.choices:last-child{margin-bottom:0}.choices.is-disabled .choices__inner,.choices.is-disabled .choices__input{background-color:#eaeaea;cursor:not-allowed;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.choices.is-disabled .choices__item{cursor:not-allowed}.choices[data-type*=select-one]{cursor:pointer}.choices[data-type*=select-one] .choices__inner{padding-bottom:7.5px}.choices[data-type*=select-one] .choices__input{display:block;width:100%;padding:10px;border-bottom:1px solid #ddd;background-color:#fff;margin:0}.choices[data-type*=select-one] .choices__button{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);padding:0;background-size:8px;position:absolute;top:50%;right:0;margin-top:-10px;margin-right:25px;height:20px;width:20px;border-radius:10em;opacity:.5}.choices[data-type*=select-one] .choices__button:focus,.choices[data-type*=select-one] .choices__button:hover{opacity:1}.choices[data-type*=select-one] .choices__button:focus{box-shadow:0 0 0 2px #00bcd4}.choices[data-type*=select-one]:after{content:"";height:0;width:0;border-style:solid;border-color:#333 transparent transparent transparent;border-width:5px;position:absolute;right:11.5px;top:50%;margin-top:-2.5px;pointer-events:none}.choices[data-type*=select-one].is-open:after{border-color:transparent transparent #333 transparent;margin-top:-7.5px}.choices[data-type*=select-one][dir=rtl]:after{left:11.5px;right:auto}.choices[data-type*=select-one][dir=rtl] .choices__button{right:auto;left:0;margin-left:25px;margin-right:0}.choices[data-type*=select-multiple] .choices__inner,.choices[data-type*=text] .choices__inner{cursor:text}.choices[data-type*=select-multiple] .choices__button,.choices[data-type*=text] .choices__button{position:relative;display:inline-block;margin:0 -4px 0 8px;padding-left:16px;border-left:1px solid #008fa1;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);background-size:8px;width:8px;line-height:1;opacity:.75;border-radius:0}.choices[data-type*=select-multiple] .choices__button:focus,.choices[data-type*=select-multiple] .choices__button:hover,.choices[data-type*=text] .choices__button:focus,.choices[data-type*=text] .choices__button:hover{opacity:1}.choices__inner{display:inline-block;vertical-align:top;width:100%;background-color:#f9f9f9;padding:7.5px 7.5px 3.75px;border:1px solid #ddd;border-radius:2.5px;font-size:14px;min-height:44px;overflow:hidden}.is-focused .choices__inner,.is-open .choices__inner{border-color:#b7b7b7}.is-open .choices__inner{border-radius:2.5px 2.5px 0 0}.is-flipped.is-open .choices__inner{border-radius:0 0 2.5px 2.5px}.choices__list{margin:0;padding-left:0;list-style:none}.choices__list--single{display:inline-block;padding:4px 16px 4px 4px;width:100%}[dir=rtl] .choices__list--single{padding-right:4px;padding-left:16px}.choices__list--single .choices__item{width:100%}.choices__list--multiple{display:inline}.choices__list--multiple .choices__item{display:inline-block;vertical-align:middle;border-radius:20px;padding:4px 10px;font-size:12px;font-weight:500;margin-right:3.75px;margin-bottom:3.75px;background-color:#00bcd4;border:1px solid #00a5bb;color:#fff;word-break:break-all}.choices__list--multiple .choices__item[data-deletable]{padding-right:5px}[dir=rtl] .choices__list--multiple .choices__item{margin-right:0;margin-left:3.75px}.choices__list--multiple .choices__item.is-highlighted{background-color:#00a5bb;border:1px solid #008fa1}.is-disabled .choices__list--multiple .choices__item{background-color:#aaa;border:1px solid #919191}.choices__list--dropdown{display:none;z-index:1;position:absolute;width:100%;background-color:#fff;border:1px solid #ddd;top:100%;margin-top:-1px;border-bottom-left-radius:2.5px;border-bottom-right-radius:2.5px;overflow:hidden;word-break:break-all}.choices__list--dropdown.is-active{display:block}.is-open .choices__list--dropdown{border-color:#b7b7b7}.is-flipped .choices__list--dropdown{top:auto;bottom:100%;margin-top:0;margin-bottom:-1px;border-radius:.25rem .25rem 0 0}.choices__list--dropdown .choices__list{position:relative;max-height:300px;overflow:auto;-webkit-overflow-scrolling:touch;will-change:scroll-position}.choices__list--dropdown .choices__item{position:relative;padding:10px;font-size:14px}[dir=rtl] .choices__list--dropdown .choices__item{text-align:right}@media (min-width:640px){.choices__list--dropdown .choices__item--selectable{padding-right:100px}.choices__list--dropdown .choices__item--selectable:after{content:attr(data-select-text);font-size:12px;opacity:0;position:absolute;right:10px;top:50%;transform:translateY(-50%)}[dir=rtl] .choices__list--dropdown .choices__item--selectable{text-align:right;padding-left:100px;padding-right:10px}[dir=rtl] .choices__list--dropdown .choices__item--selectable:after{right:auto;left:10px}}.choices__list--dropdown .choices__item--selectable.is-highlighted{background-color:#f2f2f2}.choices__list--dropdown .choices__item--selectable.is-highlighted:after{opacity:.5}.choices__item{cursor:default}.choices__item--selectable{cursor:pointer}.choices__item--disabled{cursor:not-allowed;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;opacity:.5}.choices__heading{font-weight:600;font-size:12px;padding:10px;border-bottom:1px solid #f7f7f7;color:gray}.choices__button{text-indent:-9999px;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background-color:transparent;background-repeat:no-repeat;background-position:center;cursor:pointer}.choices__button:focus{outline:none}.choices__input{display:inline-block;vertical-align:baseline;background-color:#f9f9f9;font-size:14px;margin-bottom:5px;border:0;border-radius:0;max-width:100%;padding:4px 0 4px 2px}.choices__input:focus{outline:0}[dir=rtl] .choices__input{padding-right:2px;padding-left:0}.choices__placeholder{opacity:.5}.choices[data-type*=select-multiple] .choices__input.is-hidden,.choices[data-type*=select-one] .choices__input.is-hidden,.choices__input.is-hidden{display:none} \ No newline at end of file diff --git a/bin/htdocs/vendor/choices/choices.min.js b/bin/htdocs/vendor/choices/choices.min.js new file mode 100644 index 0000000..5d105dc --- /dev/null +++ b/bin/htdocs/vendor/choices/choices.min.js @@ -0,0 +1,58 @@ +/*! choices.js v7.0.0 | (c) 2019 Josh Johnson | https://github.com/jshjohnson/Choices#readme */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Choices=t():e.Choices=t()}(window,function(){return function(e){var t={};function i(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)i.d(n,o,function(t){return e[t]}.bind(null,o));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/public/assets/scripts/",i(i.s=9)}([function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.diff=t.cloneObject=t.existsInArray=t.isIE11=t.fetchFromObject=t.getWindowHeight=t.dispatchEvent=t.sortByScore=t.sortByAlpha=t.calcWidthOfInput=t.strToEl=t.sanitise=t.isScrolledIntoView=t.getAdjacentEl=t.findAncestorByAttrName=t.wrap=t.isElement=t.isType=t.getType=t.generateId=t.generateChars=t.getRandomNumber=void 0;var n=function(e,t){return Math.floor(Math.random()*(t-e)+e)};t.getRandomNumber=n;var o=function(e){for(var t="",i=0;i1&&void 0!==arguments[1]?arguments[1]:document.createElement("div");return e.nextSibling?e.parentNode.insertBefore(t,e.nextSibling):e.parentNode.appendChild(t),t.appendChild(e)};t.findAncestorByAttrName=function(e,t){for(var i=e;i;){if(i.hasAttribute(t))return i;i=i.parentElement}return null};t.getAdjacentEl=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;if(e&&t){var n=e.parentNode.parentNode,o=Array.from(n.querySelectorAll(t)),r=o.indexOf(e);return o[r+(i>0?1:-1)]}};t.isScrolledIntoView=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;if(e)return i>0?t.scrollTop+t.offsetHeight>=e.offsetTop+e.offsetHeight:e.offsetTop>=t.scrollTop};var a=function(e){return s("String",e)?e.replace(/&/g,"&").replace(/>/g,"&rt;").replace(/".concat(a(i),"
"));if(o.style.position="absolute",o.style.padding="0",o.style.top="-9999px",o.style.left="-9999px",o.style.width="auto",o.style.whiteSpace="pre",document.body.contains(e)&&window.getComputedStyle){var r=window.getComputedStyle(e);r&&(o.style.fontSize=r.fontSize,o.style.fontFamily=r.fontFamily,o.style.fontWeight=r.fontWeight,o.style.fontStyle=r.fontStyle,o.style.letterSpacing=r.letterSpacing,o.style.textTransform=r.textTransform,o.style.padding=r.padding)}document.body.appendChild(o),requestAnimationFrame(function(){i&&o.offsetWidth!==e.offsetWidth&&(n=o.offsetWidth+4),document.body.removeChild(o),t.call(void 0,"".concat(n,"px"))})}else t.call(void 0,"".concat(n,"px"))};t.sortByAlpha=function(e,t){var i="".concat(e.label||e.value).toLowerCase(),n="".concat(t.label||t.value).toLowerCase();return in?1:0};t.sortByScore=function(e,t){return e.score-t.score};t.dispatchEvent=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,n=new CustomEvent(t,{detail:i,bubbles:!0,cancelable:!0});return e.dispatchEvent(n)};t.getWindowHeight=function(){var e=document.body,t=document.documentElement;return Math.max(e.scrollHeight,e.offsetHeight,t.clientHeight,t.scrollHeight,t.offsetHeight)};t.fetchFromObject=function e(t,i){var n=i.indexOf(".");return n>-1?e(t[i.substring(0,n)],i.substr(n+1)):t[i]};t.isIE11=function(){return!(!navigator.userAgent.match(/Trident/)||!navigator.userAgent.match(/rv[ :]11/))};t.existsInArray=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"value";return e.some(function(e){return s("String",t)?e[i]===t.trim():e[i]===t})};t.cloneObject=function(e){return JSON.parse(JSON.stringify(e))};t.diff=function(e,t){var i=Object.keys(e).sort(),n=Object.keys(t).sort();return i.filter(function(e){return n.indexOf(e)<0})}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SCROLLING_SPEED=t.KEY_CODES=t.ACTION_TYPES=t.EVENTS=t.DEFAULT_CONFIG=t.DEFAULT_CLASSNAMES=void 0;var n=i(0),o={containerOuter:"choices",containerInner:"choices__inner",input:"choices__input",inputCloned:"choices__input--cloned",list:"choices__list",listItems:"choices__list--multiple",listSingle:"choices__list--single",listDropdown:"choices__list--dropdown",item:"choices__item",itemSelectable:"choices__item--selectable",itemDisabled:"choices__item--disabled",itemChoice:"choices__item--choice",placeholder:"choices__placeholder",group:"choices__group",groupHeading:"choices__heading",button:"choices__button",activeState:"is-active",focusState:"is-focused",openState:"is-open",disabledState:"is-disabled",highlightedState:"is-highlighted",hiddenState:"is-hidden",flippedState:"is-flipped",loadingState:"is-loading",noResults:"has-no-results",noChoices:"has-no-choices"};t.DEFAULT_CLASSNAMES=o;var r={items:[],choices:[],silent:!1,renderChoiceLimit:-1,maxItemCount:-1,addItems:!0,addItemFilterFn:null,removeItems:!0,removeItemButton:!1,editItems:!1,duplicateItemsAllowed:!0,delimiter:",",paste:!0,searchEnabled:!0,searchChoices:!0,searchFloor:1,searchResultLimit:4,searchFields:["label","value"],position:"auto",resetScrollPosition:!0,shouldSort:!0,shouldSortItems:!1,sortFn:n.sortByAlpha,placeholder:!0,placeholderValue:null,searchPlaceholderValue:null,prependValue:null,appendValue:null,renderSelectedChoices:"auto",loadingText:"Loading...",noResultsText:"No results found",noChoicesText:"No choices to choose from",itemSelectText:"Press to select",uniqueItemText:"Only unique values can be added",customAddItemText:"Only values matching specific conditions can be added",addItemText:function(e){return'Press Enter to add "'.concat((0,n.sanitise)(e),'"')},maxItemText:function(e){return"Only ".concat(e," values can be added")},itemComparer:function(e,t){return e===t},fuseOptions:{includeScore:!0},callbackOnInit:null,callbackOnCreateTemplates:null,classNames:o};t.DEFAULT_CONFIG=r;t.EVENTS={showDropdown:"showDropdown",hideDropdown:"hideDropdown",change:"change",choice:"choice",search:"search",addItem:"addItem",removeItem:"removeItem",highlightItem:"highlightItem",highlightChoice:"highlightChoice"};t.ACTION_TYPES={ADD_CHOICE:"ADD_CHOICE",FILTER_CHOICES:"FILTER_CHOICES",ACTIVATE_CHOICES:"ACTIVATE_CHOICES",CLEAR_CHOICES:"CLEAR_CHOICES",ADD_GROUP:"ADD_GROUP",ADD_ITEM:"ADD_ITEM",REMOVE_ITEM:"REMOVE_ITEM",HIGHLIGHT_ITEM:"HIGHLIGHT_ITEM",CLEAR_ALL:"CLEAR_ALL"};t.KEY_CODES={BACK_KEY:46,DELETE_KEY:8,ENTER_KEY:13,A_KEY:65,ESC_KEY:27,UP_KEY:38,DOWN_KEY:40,PAGE_UP_KEY:33,PAGE_DOWN_KEY:34};t.SCROLLING_SPEED=4},function(e,t,i){"use strict";(function(e,n){var o,r=i(7);o="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==e?e:n;var s=Object(r.a)(o);t.a=s}).call(this,i(3),i(14)(e))},function(e,t){var i;i=function(){return this}();try{i=i||new Function("return this")()}catch(e){"object"==typeof window&&(i=window)}e.exports=i},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=i(0);function o(e,t){for(var i=0;i