igs-slm 0.1.0b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- igs_slm-0.1.0b0.dist-info/LICENSE +21 -0
- igs_slm-0.1.0b0.dist-info/METADATA +151 -0
- igs_slm-0.1.0b0.dist-info/RECORD +447 -0
- igs_slm-0.1.0b0.dist-info/WHEEL +4 -0
- igs_slm-0.1.0b0.dist-info/entry_points.txt +3 -0
- igs_tools/__init__.py +0 -0
- igs_tools/connection.py +88 -0
- igs_tools/defines/__init__.py +8 -0
- igs_tools/defines/constellation.py +21 -0
- igs_tools/defines/data_center.py +75 -0
- igs_tools/defines/rinex.py +49 -0
- igs_tools/directory.py +247 -0
- igs_tools/utils.py +66 -0
- slm/__init__.py +21 -0
- slm/admin.py +674 -0
- slm/api/edit/__init__.py +0 -0
- slm/api/edit/serializers.py +316 -0
- slm/api/edit/views.py +1632 -0
- slm/api/fields.py +89 -0
- slm/api/filter.py +504 -0
- slm/api/pagination.py +55 -0
- slm/api/permissions.py +65 -0
- slm/api/public/__init__.py +0 -0
- slm/api/public/serializers.py +249 -0
- slm/api/public/views.py +606 -0
- slm/api/serializers.py +132 -0
- slm/api/views.py +148 -0
- slm/apps.py +323 -0
- slm/authentication.py +198 -0
- slm/bin/__init__.py +0 -0
- slm/bin/startproject.py +262 -0
- slm/bin/templates/{{ project_dir }}/pyproject.toml +35 -0
- slm/bin/templates/{{ project_dir }}/sites/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/base.py +15 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/__init__.py +56 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/local.py +4 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/wsgi.py +16 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/manage.py +34 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/production/__init__.py +61 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/production/wsgi.py +16 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/urls.py +7 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/validation.py +11 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/admin.py +5 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/apps.py +14 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/commands/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/commands/import_archive.py +64 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/migrations/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/models.py +6 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/templates/slm/base.html +8 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/urls.py +10 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/views.py +5 -0
- slm/defines/AlertLevel.py +24 -0
- slm/defines/AntennaCalibration.py +25 -0
- slm/defines/AntennaFeatures.py +27 -0
- slm/defines/AntennaReferencePoint.py +22 -0
- slm/defines/Aspiration.py +13 -0
- slm/defines/CardinalDirection.py +19 -0
- slm/defines/CollocationStatus.py +12 -0
- slm/defines/EquipmentState.py +22 -0
- slm/defines/FlagSeverity.py +14 -0
- slm/defines/FractureSpacing.py +15 -0
- slm/defines/FrequencyStandardType.py +15 -0
- slm/defines/GeodesyMLVersion.py +48 -0
- slm/defines/ISOCountry.py +1194 -0
- slm/defines/Instrumentation.py +19 -0
- slm/defines/LogEntryType.py +30 -0
- slm/defines/SLMFileType.py +18 -0
- slm/defines/SiteFileUploadStatus.py +61 -0
- slm/defines/SiteLogFormat.py +49 -0
- slm/defines/SiteLogStatus.py +78 -0
- slm/defines/TectonicPlates.py +28 -0
- slm/defines/__init__.py +46 -0
- slm/forms.py +1126 -0
- slm/jinja2/slm/sitelog/ascii_9char.log +346 -0
- slm/jinja2/slm/sitelog/legacy.log +346 -0
- slm/jinja2/slm/sitelog/xsd/0.4/collocationInformation.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/condition.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/contact.xml +52 -0
- slm/jinja2/slm/sitelog/xsd/0.4/formInformation.xml +5 -0
- slm/jinja2/slm/sitelog/xsd/0.4/frequencyStandard.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/gnssAntenna.xml +16 -0
- slm/jinja2/slm/sitelog/xsd/0.4/gnssReceiver.xml +11 -0
- slm/jinja2/slm/sitelog/xsd/0.4/humiditySensor.xml +13 -0
- slm/jinja2/slm/sitelog/xsd/0.4/localEpisodicEffect.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/0.4/moreInformation.xml +22 -0
- slm/jinja2/slm/sitelog/xsd/0.4/multipathSource.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/0.4/otherInstrumentation.xml +5 -0
- slm/jinja2/slm/sitelog/xsd/0.4/pressureSensor.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/radioInterference.xml +11 -0
- slm/jinja2/slm/sitelog/xsd/0.4/sensor.xml +16 -0
- slm/jinja2/slm/sitelog/xsd/0.4/signalObstruction.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/0.4/siteIdentification.xml +22 -0
- slm/jinja2/slm/sitelog/xsd/0.4/siteLocation.xml +21 -0
- slm/jinja2/slm/sitelog/xsd/0.4/surveyedLocalTie.xml +20 -0
- slm/jinja2/slm/sitelog/xsd/0.4/temperatureSensor.xml +13 -0
- slm/jinja2/slm/sitelog/xsd/0.4/waterVaporSensor.xml +11 -0
- slm/jinja2/slm/sitelog/xsd/0.5/document.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/geodesyml_0.4.xml +99 -0
- slm/jinja2/slm/sitelog/xsd/geodesyml_0.5.xml +112 -0
- slm/management/__init__.py +0 -0
- slm/management/commands/__init__.py +53 -0
- slm/management/commands/build_index.py +96 -0
- slm/management/commands/generate_sinex.py +675 -0
- slm/management/commands/head_from_index.py +541 -0
- slm/management/commands/import_archive.py +908 -0
- slm/management/commands/import_equipment.py +351 -0
- slm/management/commands/set_site.py +56 -0
- slm/management/commands/sitelog.py +144 -0
- slm/management/commands/synchronize.py +60 -0
- slm/management/commands/update_data_availability.py +167 -0
- slm/management/commands/validate_db.py +186 -0
- slm/management/commands/validate_gml.py +73 -0
- slm/map/__init__.py +1 -0
- slm/map/admin.py +5 -0
- slm/map/api/__init__.py +0 -0
- slm/map/api/edit/__init__.py +0 -0
- slm/map/api/edit/serializers.py +28 -0
- slm/map/api/edit/views.py +46 -0
- slm/map/api/public/__init__.py +0 -0
- slm/map/api/public/serializers.py +29 -0
- slm/map/api/public/views.py +64 -0
- slm/map/apps.py +7 -0
- slm/map/defines.py +53 -0
- slm/map/migrations/0001_initial.py +115 -0
- slm/map/migrations/__init__.py +0 -0
- slm/map/models.py +63 -0
- slm/map/static/slm/css/map.css +86 -0
- slm/map/static/slm/js/map.js +159 -0
- slm/map/templates/slm/map.html +374 -0
- slm/map/templates/slm/station/base.html +11 -0
- slm/map/templates/slm/station/edit.html +10 -0
- slm/map/templates/slm/top_nav.html +17 -0
- slm/map/templatetags/__init__.py +0 -0
- slm/map/templatetags/slm_map.py +18 -0
- slm/map/urls.py +25 -0
- slm/map/views.py +36 -0
- slm/middleware.py +29 -0
- slm/migrations/0001_alter_siteantenna_marker_enu_alter_sitelocation_llh_and_more.py +47 -0
- slm/migrations/0001_initial.py +4826 -0
- slm/migrations/0002_alter_dataavailability_site.py +22 -0
- slm/migrations/0003_remove_logentry_slm_logentr_site_lo_7a2af7_idx_and_more.py +80 -0
- slm/migrations/0004_alter_logentry_timestamp_and_more.py +25 -0
- slm/migrations/0005_alter_logentry_options_alter_logentry_section_and_more.py +46 -0
- slm/migrations/0006_alter_logentry_options_alter_logentry_index_together.py +24 -0
- slm/migrations/0007_alter_dataavailability_rate.py +23 -0
- slm/migrations/0008_alter_archiveindex_options_and_more.py +64 -0
- slm/migrations/0009_alter_archiveindex_end.py +21 -0
- slm/migrations/0010_alter_dataavailability_rinex_version_and_more.py +844 -0
- slm/migrations/0011_alter_siteidentification_fracture_spacing.py +33 -0
- slm/migrations/0012_alter_logentry_type.py +36 -0
- slm/migrations/0013_unpublishedfilesalert.py +48 -0
- slm/migrations/0014_sitelogpublished.py +48 -0
- slm/migrations/0015_alter_siteantenna_options_and_more.py +181 -0
- slm/migrations/0016_alter_antenna_description_alter_radome_description_and_more.py +42 -0
- slm/migrations/0017_alter_logentry_unique_together_and_more.py +54 -0
- slm/migrations/0018_afix_deleted.py +34 -0
- slm/migrations/0018_alter_siteantenna_options_and_more.py +244 -0
- slm/migrations/0019_remove_siteantenna_marker_enu_siteantenna_marker_une_and_more.py +101 -0
- slm/migrations/0020_alter_manufacturer_options.py +16 -0
- slm/migrations/0021_alter_siteform_report_type.py +23 -0
- slm/migrations/0022_rename_antcal_antenna_radome_slm_antcal_antenna_20827a_idx_and_more.py +297 -0
- slm/migrations/0023_archivedsitelog_gml_version_and_more.py +55 -0
- slm/migrations/0024_alter_agency_name_alter_agency_shortname.py +24 -0
- slm/migrations/0025_alter_archivedsitelog_log_format_and_more.py +61 -0
- slm/migrations/0026_alter_archivedsitelog_log_format_and_more.py +61 -0
- slm/migrations/0027_importalert_file_contents_importalert_findings_and_more.py +41 -0
- slm/migrations/0028_antenna_replaced_manufacturer_url_radome_replaced_and_more.py +46 -0
- slm/migrations/0029_manufacturer_full_name.py +17 -0
- slm/migrations/0030_alter_antenna_state_alter_radome_state_and_more.py +43 -0
- slm/migrations/__init__.py +0 -0
- slm/migrations/load_satellitesystems.py +27 -0
- slm/models/__init__.py +118 -0
- slm/models/about.py +14 -0
- slm/models/alerts.py +1204 -0
- slm/models/data.py +58 -0
- slm/models/equipment.py +229 -0
- slm/models/help.py +14 -0
- slm/models/index.py +428 -0
- slm/models/sitelog.py +4279 -0
- slm/models/system.py +723 -0
- slm/models/user.py +304 -0
- slm/parsing/__init__.py +786 -0
- slm/parsing/legacy/__init__.py +4 -0
- slm/parsing/legacy/binding.py +817 -0
- slm/parsing/legacy/parser.py +377 -0
- slm/parsing/xsd/__init__.py +34 -0
- slm/parsing/xsd/binding.py +86 -0
- slm/parsing/xsd/geodesyml/0.4/commonTypes.xsd +133 -0
- slm/parsing/xsd/geodesyml/0.4/contact.xsd +29 -0
- slm/parsing/xsd/geodesyml/0.4/dataStreams.xsd +129 -0
- slm/parsing/xsd/geodesyml/0.4/document.xsd +64 -0
- slm/parsing/xsd/geodesyml/0.4/equipment.xsd +427 -0
- slm/parsing/xsd/geodesyml/0.4/fieldMeasurement.xsd +170 -0
- slm/parsing/xsd/geodesyml/0.4/geodesyML.xsd +71 -0
- slm/parsing/xsd/geodesyml/0.4/geodeticEquipment.xsd +343 -0
- slm/parsing/xsd/geodesyml/0.4/geodeticMonument.xsd +147 -0
- slm/parsing/xsd/geodesyml/0.4/lineage.xsd +614 -0
- slm/parsing/xsd/geodesyml/0.4/localInterferences.xsd +131 -0
- slm/parsing/xsd/geodesyml/0.4/measurement.xsd +473 -0
- slm/parsing/xsd/geodesyml/0.4/monumentInfo.xsd +251 -0
- slm/parsing/xsd/geodesyml/0.4/observationSystem.xsd +429 -0
- slm/parsing/xsd/geodesyml/0.4/project.xsd +38 -0
- slm/parsing/xsd/geodesyml/0.4/quality.xsd +176 -0
- slm/parsing/xsd/geodesyml/0.4/referenceFrame.xsd +194 -0
- slm/parsing/xsd/geodesyml/0.4/siteLog.xsd +71 -0
- slm/parsing/xsd/geodesyml/0.5/commonTypes.xsd +133 -0
- slm/parsing/xsd/geodesyml/0.5/contact.xsd +29 -0
- slm/parsing/xsd/geodesyml/0.5/dataStreams.xsd +129 -0
- slm/parsing/xsd/geodesyml/0.5/document.xsd +64 -0
- slm/parsing/xsd/geodesyml/0.5/equipment.xsd +427 -0
- slm/parsing/xsd/geodesyml/0.5/fieldMeasurement.xsd +170 -0
- slm/parsing/xsd/geodesyml/0.5/geodesyML.xsd +71 -0
- slm/parsing/xsd/geodesyml/0.5/geodeticEquipment.xsd +343 -0
- slm/parsing/xsd/geodesyml/0.5/geodeticMonument.xsd +147 -0
- slm/parsing/xsd/geodesyml/0.5/lineage.xsd +614 -0
- slm/parsing/xsd/geodesyml/0.5/localInterferences.xsd +131 -0
- slm/parsing/xsd/geodesyml/0.5/measurement.xsd +473 -0
- slm/parsing/xsd/geodesyml/0.5/monumentInfo.xsd +306 -0
- slm/parsing/xsd/geodesyml/0.5/observationSystem.xsd +429 -0
- slm/parsing/xsd/geodesyml/0.5/project.xsd +38 -0
- slm/parsing/xsd/geodesyml/0.5/quality.xsd +176 -0
- slm/parsing/xsd/geodesyml/0.5/referenceFrame.xsd +194 -0
- slm/parsing/xsd/geodesyml/0.5/siteLog.xsd +73 -0
- slm/parsing/xsd/parser.py +116 -0
- slm/parsing/xsd/resolver.py +28 -0
- slm/receivers/__init__.py +11 -0
- slm/receivers/alerts.py +87 -0
- slm/receivers/cleanup.py +41 -0
- slm/receivers/event_loggers.py +175 -0
- slm/receivers/index.py +67 -0
- slm/settings/__init__.py +55 -0
- slm/settings/auth.py +15 -0
- slm/settings/ckeditor.py +14 -0
- slm/settings/debug.py +47 -0
- slm/settings/internationalization.py +12 -0
- slm/settings/logging.py +113 -0
- slm/settings/platform/__init__.py +0 -0
- slm/settings/platform/darwin.py +10 -0
- slm/settings/rest.py +21 -0
- slm/settings/root.py +152 -0
- slm/settings/routines.py +43 -0
- slm/settings/secrets.py +37 -0
- slm/settings/security.py +5 -0
- slm/settings/slm.py +188 -0
- slm/settings/static_templates.py +53 -0
- slm/settings/templates.py +29 -0
- slm/settings/uploads.py +8 -0
- slm/settings/urls.py +126 -0
- slm/settings/validation.py +196 -0
- slm/signals.py +250 -0
- slm/singleton.py +49 -0
- slm/static/rest_framework/css/bootstrap-tweaks.css +204 -0
- slm/static/rest_framework/css/bootstrap.min.css +7 -0
- slm/static/rest_framework/css/bootstrap.min.css.map +1 -0
- slm/static/rest_framework/css/default.css +82 -0
- slm/static/rest_framework/css/prettify.css +30 -0
- slm/static/rest_framework/docs/css/base.css +344 -0
- slm/static/rest_framework/docs/css/highlight.css +125 -0
- slm/static/rest_framework/docs/css/jquery.json-view.min.css +11 -0
- slm/static/rest_framework/docs/img/favicon.ico +0 -0
- slm/static/rest_framework/docs/img/grid.png +0 -0
- slm/static/rest_framework/docs/js/api.js +321 -0
- slm/static/rest_framework/docs/js/highlight.pack.js +2 -0
- slm/static/rest_framework/docs/js/jquery.json-view.min.js +7 -0
- slm/static/rest_framework/img/grid.png +0 -0
- slm/static/rest_framework/js/ajax-form.js +127 -0
- slm/static/rest_framework/js/bootstrap.bundle.min.js +7 -0
- slm/static/rest_framework/js/bootstrap.bundle.min.js.map +1 -0
- slm/static/rest_framework/js/bootstrap.min.js.map +1 -0
- slm/static/rest_framework/js/coreapi-0.1.1.js +2043 -0
- slm/static/rest_framework/js/csrf.js +52 -0
- slm/static/rest_framework/js/default.js +47 -0
- slm/static/rest_framework/js/jquery-3.5.1.min.js +2 -0
- slm/static/rest_framework/js/prettify-min.js +28 -0
- slm/static/slm/css/admin.css +3 -0
- slm/static/slm/css/defines.css +82 -0
- slm/static/slm/css/forms.css +1 -0
- slm/static/slm/css/style.css +1004 -0
- slm/static/slm/img/email-branding.png +0 -0
- slm/static/slm/img/favicon.ico +0 -0
- slm/static/slm/img/login-bg.jpg +0 -0
- slm/static/slm/img/slm-logo.svg +4 -0
- slm/static/slm/js/autocomplete.js +341 -0
- slm/static/slm/js/enums.js +322 -0
- slm/static/slm/js/fileIcons.js +30 -0
- slm/static/slm/js/form.js +404 -0
- slm/static/slm/js/formWidget.js +23 -0
- slm/static/slm/js/persistable.js +33 -0
- slm/static/slm/js/slm.js +1028 -0
- slm/static/slm/js/time24.js +212 -0
- slm/static_templates/slm/css/defines.css +26 -0
- slm/static_templates/slm/js/enums.js +28 -0
- slm/static_templates/slm/js/fileIcons.js +16 -0
- slm/static_templates/slm/js/urls.js +5 -0
- slm/templates/account/base.html +20 -0
- slm/templates/account/email/base.html +43 -0
- slm/templates/account/email/base_message.txt +7 -0
- slm/templates/account/email/email_confirmation_message.html +16 -0
- slm/templates/account/email/email_confirmation_message.txt +7 -0
- slm/templates/account/email/email_confirmation_signup_message.html +1 -0
- slm/templates/account/email/email_confirmation_signup_message.txt +1 -0
- slm/templates/account/email/email_confirmation_signup_subject.txt +1 -0
- slm/templates/account/email/email_confirmation_subject.txt +4 -0
- slm/templates/account/email/password_reset_key_message.html +28 -0
- slm/templates/account/email/password_reset_key_message.txt +9 -0
- slm/templates/account/email/password_reset_key_subject.txt +4 -0
- slm/templates/account/email/unknown_account_message.html +25 -0
- slm/templates/account/email/unknown_account_message.txt +12 -0
- slm/templates/account/email/unknown_account_subject.txt +4 -0
- slm/templates/account/login.html +67 -0
- slm/templates/account/logout.html +38 -0
- slm/templates/account/password_change.html +48 -0
- slm/templates/account/password_reset.html +51 -0
- slm/templates/account/password_reset_done.html +20 -0
- slm/templates/account/password_reset_from_key.html +52 -0
- slm/templates/account/password_reset_from_key_done.html +17 -0
- slm/templates/admin/base.html +7 -0
- slm/templates/messages.html +8 -0
- slm/templates/rest_framework/README +16 -0
- slm/templates/rest_framework/admin/detail.html +10 -0
- slm/templates/rest_framework/admin/dict_value.html +11 -0
- slm/templates/rest_framework/admin/list.html +32 -0
- slm/templates/rest_framework/admin/list_value.html +11 -0
- slm/templates/rest_framework/admin/simple_list_value.html +2 -0
- slm/templates/rest_framework/admin.html +282 -0
- slm/templates/rest_framework/api.html +3 -0
- slm/templates/rest_framework/base.html +334 -0
- slm/templates/rest_framework/docs/auth/basic.html +42 -0
- slm/templates/rest_framework/docs/auth/session.html +40 -0
- slm/templates/rest_framework/docs/auth/token.html +41 -0
- slm/templates/rest_framework/docs/document.html +37 -0
- slm/templates/rest_framework/docs/error.html +71 -0
- slm/templates/rest_framework/docs/index.html +55 -0
- slm/templates/rest_framework/docs/interact.html +57 -0
- slm/templates/rest_framework/docs/langs/javascript-intro.html +5 -0
- slm/templates/rest_framework/docs/langs/javascript.html +15 -0
- slm/templates/rest_framework/docs/langs/python-intro.html +3 -0
- slm/templates/rest_framework/docs/langs/python.html +13 -0
- slm/templates/rest_framework/docs/langs/shell-intro.html +3 -0
- slm/templates/rest_framework/docs/langs/shell.html +6 -0
- slm/templates/rest_framework/docs/link.html +113 -0
- slm/templates/rest_framework/docs/sidebar.html +78 -0
- slm/templates/rest_framework/filters/base.html +16 -0
- slm/templates/rest_framework/filters/ordering.html +17 -0
- slm/templates/rest_framework/filters/search.html +13 -0
- slm/templates/rest_framework/horizontal/checkbox.html +23 -0
- slm/templates/rest_framework/horizontal/checkbox_multiple.html +32 -0
- slm/templates/rest_framework/horizontal/dict_field.html +11 -0
- slm/templates/rest_framework/horizontal/fieldset.html +16 -0
- slm/templates/rest_framework/horizontal/form.html +6 -0
- slm/templates/rest_framework/horizontal/input.html +21 -0
- slm/templates/rest_framework/horizontal/list_field.html +11 -0
- slm/templates/rest_framework/horizontal/list_fieldset.html +13 -0
- slm/templates/rest_framework/horizontal/radio.html +42 -0
- slm/templates/rest_framework/horizontal/select.html +36 -0
- slm/templates/rest_framework/horizontal/select_multiple.html +38 -0
- slm/templates/rest_framework/horizontal/textarea.html +21 -0
- slm/templates/rest_framework/inline/checkbox.html +8 -0
- slm/templates/rest_framework/inline/checkbox_multiple.html +14 -0
- slm/templates/rest_framework/inline/dict_field.html +9 -0
- slm/templates/rest_framework/inline/fieldset.html +6 -0
- slm/templates/rest_framework/inline/form.html +8 -0
- slm/templates/rest_framework/inline/input.html +9 -0
- slm/templates/rest_framework/inline/list_field.html +9 -0
- slm/templates/rest_framework/inline/list_fieldset.html +3 -0
- slm/templates/rest_framework/inline/radio.html +25 -0
- slm/templates/rest_framework/inline/select.html +24 -0
- slm/templates/rest_framework/inline/select_multiple.html +25 -0
- slm/templates/rest_framework/inline/textarea.html +9 -0
- slm/templates/rest_framework/login.html +3 -0
- slm/templates/rest_framework/login_base.html +65 -0
- slm/templates/rest_framework/pagination/numbers.html +47 -0
- slm/templates/rest_framework/pagination/previous_and_next.html +21 -0
- slm/templates/rest_framework/raw_data_form.html +11 -0
- slm/templates/rest_framework/schema.js +3 -0
- slm/templates/rest_framework/vertical/checkbox.html +16 -0
- slm/templates/rest_framework/vertical/checkbox_multiple.html +30 -0
- slm/templates/rest_framework/vertical/dict_field.html +7 -0
- slm/templates/rest_framework/vertical/fieldset.html +13 -0
- slm/templates/rest_framework/vertical/form.html +6 -0
- slm/templates/rest_framework/vertical/input.html +17 -0
- slm/templates/rest_framework/vertical/list_field.html +7 -0
- slm/templates/rest_framework/vertical/list_fieldset.html +7 -0
- slm/templates/rest_framework/vertical/radio.html +40 -0
- slm/templates/rest_framework/vertical/select.html +34 -0
- slm/templates/rest_framework/vertical/select_multiple.html +31 -0
- slm/templates/rest_framework/vertical/textarea.html +17 -0
- slm/templates/slm/about.html +21 -0
- slm/templates/slm/alerts/alert.html +15 -0
- slm/templates/slm/alerts/geodesymlinvalid.html +8 -0
- slm/templates/slm/alerts/importalert.html +10 -0
- slm/templates/slm/alerts.html +18 -0
- slm/templates/slm/auth_menu.html +41 -0
- slm/templates/slm/base.html +195 -0
- slm/templates/slm/emails/alert_issued.html +31 -0
- slm/templates/slm/emails/alert_issued.txt +9 -0
- slm/templates/slm/emails/base.html +6 -0
- slm/templates/slm/emails/changes_rejected.txt +7 -0
- slm/templates/slm/emails/review_requested.txt +7 -0
- slm/templates/slm/forms/widgets/auto_complete.html +21 -0
- slm/templates/slm/forms/widgets/auto_complete_multiple.html +18 -0
- slm/templates/slm/forms/widgets/checkbox_multiple.html +6 -0
- slm/templates/slm/forms/widgets/inline_multi.html +1 -0
- slm/templates/slm/forms/widgets/splitdatetime.html +14 -0
- slm/templates/slm/forms/widgets/time24.html +37 -0
- slm/templates/slm/help.html +54 -0
- slm/templates/slm/messages.html +13 -0
- slm/templates/slm/new_site.html +88 -0
- slm/templates/slm/profile.html +57 -0
- slm/templates/slm/register.html +40 -0
- slm/templates/slm/reports/file_log.html +43 -0
- slm/templates/slm/reports/head_log.html +23 -0
- slm/templates/slm/reports/head_report.html +55 -0
- slm/templates/slm/reports/index_log.html +23 -0
- slm/templates/slm/reports/index_report.html +71 -0
- slm/templates/slm/station/alert.html +8 -0
- slm/templates/slm/station/alerts.html +19 -0
- slm/templates/slm/station/base.html +104 -0
- slm/templates/slm/station/download.html +87 -0
- slm/templates/slm/station/edit.html +283 -0
- slm/templates/slm/station/form.html +110 -0
- slm/templates/slm/station/log.html +18 -0
- slm/templates/slm/station/review.html +461 -0
- slm/templates/slm/station/upload.html +295 -0
- slm/templates/slm/station/uploads/attachment.html +20 -0
- slm/templates/slm/station/uploads/geodesyml.html +1 -0
- slm/templates/slm/station/uploads/image.html +27 -0
- slm/templates/slm/station/uploads/json.html +0 -0
- slm/templates/slm/station/uploads/legacy.html +77 -0
- slm/templates/slm/top_nav.html +14 -0
- slm/templates/slm/user_activity.html +16 -0
- slm/templates/slm/widgets/alert_scroll.html +135 -0
- slm/templates/slm/widgets/filelist.html +258 -0
- slm/templates/slm/widgets/legend.html +12 -0
- slm/templates/slm/widgets/log_scroll.html +88 -0
- slm/templates/slm/widgets/stationlist.html +233 -0
- slm/templatetags/__init__.py +0 -0
- slm/templatetags/jinja2.py +9 -0
- slm/templatetags/slm.py +459 -0
- slm/urls.py +148 -0
- slm/utils.py +299 -0
- slm/validators.py +297 -0
- slm/views.py +654 -0
- slm/widgets.py +134 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
if (typeof slm === 'undefined' || slm == null) { var slm = {}; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
slm.iconMap = {
|
|
5
|
+
'zip': 'bi bi-file-zip',
|
|
6
|
+
'x-tar': 'bi bi-file-zip',
|
|
7
|
+
'plain': 'bi bi-filetype-txt',
|
|
8
|
+
'jpeg': 'bi bi-filetype-jpg',
|
|
9
|
+
'svg+xml': 'bi bi-filetype-svg',
|
|
10
|
+
'xml': 'bi bi-filetype-xml',
|
|
11
|
+
'json': 'bi bi-filetype-json',
|
|
12
|
+
'png': 'bi bi-filetype-png',
|
|
13
|
+
'tiff': 'bi bi-filetype-tiff',
|
|
14
|
+
'pdf': 'bi bi-filetype-pdf',
|
|
15
|
+
'gif': 'bi bi-filetype-gif',
|
|
16
|
+
'csv': 'bi bi-filetype-csv',
|
|
17
|
+
'bmp': 'bi bi-filetype-bmp',
|
|
18
|
+
'vnd.openxmlformats-officedocument.wordprocessingml.document': 'bi bi-filetype-doc',
|
|
19
|
+
'msword': 'bi bi-filetype-doc'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
slm.fileIcon = function(mimetype) {
|
|
23
|
+
if (mimetype) {
|
|
24
|
+
let subtype = mimetype.substring(mimetype.indexOf('/') + 1);
|
|
25
|
+
if (slm.iconMap.hasOwnProperty(subtype)) {
|
|
26
|
+
return slm.iconMap[subtype];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return "bi bi-file-earmark";
|
|
30
|
+
};
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { Persistable } from "./persistable.js";
|
|
2
|
+
|
|
3
|
+
export class Form extends Persistable {
|
|
4
|
+
/**
|
|
5
|
+
* This class encapsulates reading and writing json data to/from html forms.
|
|
6
|
+
* This is less trivial than you might assume and there are some special case
|
|
7
|
+
* SLM field behavior (namely composition/decomposition) and custom input
|
|
8
|
+
* widgets that are handled.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
element;
|
|
12
|
+
#initial; // the "clear" state of the form
|
|
13
|
+
fields;
|
|
14
|
+
widgets; // object keyed on field name where the values are widgets
|
|
15
|
+
last; // last serialized data
|
|
16
|
+
|
|
17
|
+
#multi;
|
|
18
|
+
#composite;
|
|
19
|
+
|
|
20
|
+
#changeCallbacks;
|
|
21
|
+
|
|
22
|
+
static ELEMENTS = ['input', 'select', 'textarea'];
|
|
23
|
+
|
|
24
|
+
static toBool = function(value) {
|
|
25
|
+
/**
|
|
26
|
+
* Convert a value to a boolean. Special string cases are handled.
|
|
27
|
+
*/
|
|
28
|
+
if (typeof value === 'string' || value instanceof String) {
|
|
29
|
+
value = value.toLowerCase();
|
|
30
|
+
if (['yes', 'y', 'true', '1', 'on'].includes(value)) {
|
|
31
|
+
return true;
|
|
32
|
+
} else if (['no', 'n', 'false', '0', 'off'].includes(value)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Boolean(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static differs = function(state1, state2) {
|
|
43
|
+
/**
|
|
44
|
+
* Returns true if the given form states differ, false otherwise.
|
|
45
|
+
*/
|
|
46
|
+
for (const [key, value] of Object.entries(state1)) {
|
|
47
|
+
if (state2.hasOwnProperty(key)) {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
if (
|
|
50
|
+
Array.isArray(state2[key]) &&
|
|
51
|
+
value.length === state2[key].length
|
|
52
|
+
) {
|
|
53
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
54
|
+
if (value[idx] !== state2[key][idx]) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
} else if (
|
|
62
|
+
Array.isArray(state2[key]) ||
|
|
63
|
+
value !== state2[key]
|
|
64
|
+
) { return true; }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static stripNulls = function(data) {
|
|
71
|
+
/**
|
|
72
|
+
* Strip empty arrays and values from the query data.
|
|
73
|
+
* @type {{}}
|
|
74
|
+
*/
|
|
75
|
+
const stripped = {};
|
|
76
|
+
for (const [key, value] of Object.entries(data)) {
|
|
77
|
+
if (value) { stripped[key] = value;}
|
|
78
|
+
}
|
|
79
|
+
return stripped;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static toQueryString = function(data) {
|
|
83
|
+
/**
|
|
84
|
+
* Convert query data to a url query string. No ? will be added
|
|
85
|
+
* to the front. This will strip nulls.
|
|
86
|
+
*/
|
|
87
|
+
const params = [];
|
|
88
|
+
for (const [key, value] of Object.entries(data)) {
|
|
89
|
+
if (value) {
|
|
90
|
+
params.push(`${key}=${value}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return params.join('&');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get excluded() {
|
|
97
|
+
/** fields excluded from persistence */
|
|
98
|
+
return ['csrfmiddlewaretoken'];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get initial() {
|
|
102
|
+
/**
|
|
103
|
+
* Returns a copy of the initial form settings (i.e. the "clear" state
|
|
104
|
+
* of the form.
|
|
105
|
+
*/
|
|
106
|
+
return JSON.parse(JSON.stringify(this.#initial));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
set initial(initial) {
|
|
110
|
+
/**
|
|
111
|
+
* Set the initial (i.e. clear) state of the form - some fields may
|
|
112
|
+
* have default values.
|
|
113
|
+
*
|
|
114
|
+
* The initial state of each field is determined in order of precedence
|
|
115
|
+
* by:
|
|
116
|
+
*
|
|
117
|
+
* 1) The value defined for the field in data-slm-initial on the form
|
|
118
|
+
* element.
|
|
119
|
+
* 2) The current value of the form on initialization for any excluded
|
|
120
|
+
* fields.
|
|
121
|
+
* 3) The default (see default()) value for field type.
|
|
122
|
+
*/
|
|
123
|
+
this.#initial = initial;
|
|
124
|
+
if (this.excluded.length > 0) {
|
|
125
|
+
const data = this.data;
|
|
126
|
+
for (const field of this.excluded) {
|
|
127
|
+
if (this.fields.has(field)) {
|
|
128
|
+
this.#initial[field] = data[field];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const field of this.fields) {
|
|
133
|
+
if (!this.#initial.hasOwnProperty(field)) {
|
|
134
|
+
this.#initial[field] = this.default(field);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
get data() {
|
|
140
|
+
/**
|
|
141
|
+
* Get the JSON representing the form.
|
|
142
|
+
*
|
|
143
|
+
* If multiple input elements exist with the same name and different
|
|
144
|
+
* types, that is considered a composite field. It will be combined
|
|
145
|
+
* into a single field using compose. The reverse operation is
|
|
146
|
+
* decompose.
|
|
147
|
+
*
|
|
148
|
+
* Multiple input elements that exist with the same name and the same
|
|
149
|
+
* type will be turned into arrays where the array elements are the
|
|
150
|
+
* values of the activated elements (checkboxes and selects).
|
|
151
|
+
*
|
|
152
|
+
*/
|
|
153
|
+
const data = {};
|
|
154
|
+
|
|
155
|
+
const coerceValue = function(fieldName, value) {
|
|
156
|
+
if (!this.isMulti(fieldName) && this.type(fieldName) === 'checkbox') {
|
|
157
|
+
return Form.toBool(value);
|
|
158
|
+
}
|
|
159
|
+
return value;
|
|
160
|
+
}.bind(this);
|
|
161
|
+
|
|
162
|
+
// flatten name/value objects into name: value or name: array[values]
|
|
163
|
+
for (const field of this.element.serializeArray()) {
|
|
164
|
+
let value = coerceValue(field.name, field.value);
|
|
165
|
+
if (this.isMulti(field.name)) {
|
|
166
|
+
if (Array.isArray(data[field.name])) {
|
|
167
|
+
data[field.name].push(value);
|
|
168
|
+
} else {
|
|
169
|
+
data[field.name] = [value];
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
data[field.name] = value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// compose any composite fields
|
|
177
|
+
for (const [field, value] of Object.entries(data)) {
|
|
178
|
+
if (this.isComposite(field)) {
|
|
179
|
+
data[field] = this.compose(this.type(field), value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
for (const field of this.fields) {
|
|
184
|
+
if (!data.hasOwnProperty(field)) {
|
|
185
|
+
data[field] = this.default(field);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return data;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
set data(data) {
|
|
193
|
+
/**
|
|
194
|
+
* Populates a form from the given json object. Keys should correspond
|
|
195
|
+
* to element names. Values are either singular or are arrays. Array
|
|
196
|
+
* values are expected to correspond to the value attributes of select
|
|
197
|
+
* options or checkboxes.
|
|
198
|
+
*
|
|
199
|
+
* If a form has multiple fields of different types with the same name
|
|
200
|
+
* that field value is decomposed using decompose() into a value for
|
|
201
|
+
* each input element.
|
|
202
|
+
*
|
|
203
|
+
* @type {any}
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
// form updates must be total - any missing fields will be defaulted
|
|
207
|
+
data = Object.assign(this.initial, data);
|
|
208
|
+
|
|
209
|
+
const setField = function(ipt, value) {
|
|
210
|
+
switch (ipt.prop('type')) {
|
|
211
|
+
case 'radio':
|
|
212
|
+
case 'checkbox':
|
|
213
|
+
ipt.each(function () {
|
|
214
|
+
$(this).prop('checked', Form.toBool(value));
|
|
215
|
+
});
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
ipt.val(value);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
$.each(data, function (field, value) {
|
|
223
|
+
const ipt = this.field(field);
|
|
224
|
+
if (Array.isArray(value)) {
|
|
225
|
+
switch (ipt.prop('type')) {
|
|
226
|
+
case 'select': case 'select-multiple':
|
|
227
|
+
const selected = [];
|
|
228
|
+
for (const val of value) { selected.push(`option[value="${val}"]`); }
|
|
229
|
+
ipt.find(selected.join(', ')).prop('selected', true);
|
|
230
|
+
ipt.find('option').not(selected).prop('selected', false);
|
|
231
|
+
break;
|
|
232
|
+
case 'checkbox':
|
|
233
|
+
let checked = [];
|
|
234
|
+
for (const val of value) { checked.push(`[name="${field}"][value="${val}"]:checkbox`); }
|
|
235
|
+
checked = this.element.find(checked.join(', '));
|
|
236
|
+
checked.prop('checked', true);
|
|
237
|
+
this.element.find(`[name="${field}"]:checkbox`).not(checked).prop('checked', false);
|
|
238
|
+
break;
|
|
239
|
+
default:
|
|
240
|
+
if (ipt.length > 0) {
|
|
241
|
+
throw TypeError(`Array given for form data type: ${ipt.prop('type')}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} else if (ipt.length > 1) {
|
|
245
|
+
const types = [];
|
|
246
|
+
ipt.each(function () { types.push($(this).prop('type')); });
|
|
247
|
+
const values = this.decompose(types, value);
|
|
248
|
+
ipt.map((e, i) => { setField(e, values[i]); });
|
|
249
|
+
} else { setField(ipt, value); }
|
|
250
|
+
}.bind(this));
|
|
251
|
+
|
|
252
|
+
for (const widget of Object.values(this.widgets)) {
|
|
253
|
+
widget.changed();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
constructor(element) {
|
|
258
|
+
super(element);
|
|
259
|
+
this.element = element;
|
|
260
|
+
this.#composite = {};
|
|
261
|
+
this.#multi = new Set();
|
|
262
|
+
this.#changeCallbacks = [];
|
|
263
|
+
this.widgets = {};
|
|
264
|
+
|
|
265
|
+
// Step one is to determine which names are not unique. These fields are
|
|
266
|
+
// either array-value fields or if the types differ they are composed.
|
|
267
|
+
this.fields = new Set();
|
|
268
|
+
this.element.find(Form.ELEMENTS.join(',')).each((idx, ipt) => {
|
|
269
|
+
this.fields.add($(ipt).prop('name'));
|
|
270
|
+
})
|
|
271
|
+
for (const field of this.fields) {
|
|
272
|
+
const inputs = this.element.find(this.field(field));
|
|
273
|
+
if (inputs.data('widget')) {
|
|
274
|
+
this.widgets[field] = inputs.data('widget');
|
|
275
|
+
}
|
|
276
|
+
if (inputs.length > 1) {
|
|
277
|
+
const types = new Set();
|
|
278
|
+
inputs.each((idx, element) => {
|
|
279
|
+
types.add($(element).prop('type'));
|
|
280
|
+
});
|
|
281
|
+
types.size > 1 ? this.#composite[field] = types : this.#multi.add(field);
|
|
282
|
+
} else if (inputs.get(0).hasAttribute('multiple')) {
|
|
283
|
+
this.#multi.add(field);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (this.element.data('slmInitial')) {
|
|
288
|
+
this.initial = this.element.data('slmInitial');
|
|
289
|
+
} else {
|
|
290
|
+
this.initial = {};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
this.element.data('slmForm', this);
|
|
294
|
+
|
|
295
|
+
this.element.find(':input').on('change', function() {
|
|
296
|
+
const data = this.data;
|
|
297
|
+
if (Form.differs(data, this.last)) {
|
|
298
|
+
for (const changed of this.#changeCallbacks) { changed(this); }
|
|
299
|
+
this.last = data;
|
|
300
|
+
}
|
|
301
|
+
}.bind(this));
|
|
302
|
+
|
|
303
|
+
this.last = this.data;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
decompose(types, value) {
|
|
307
|
+
switch (types) {
|
|
308
|
+
case ['date', 'time']:
|
|
309
|
+
if (value) { return value.split('T'); }
|
|
310
|
+
return ['', ''];
|
|
311
|
+
default:
|
|
312
|
+
throw TypeError(`Unexpected decomposition types: ${types}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
compose(types, inputs) {
|
|
317
|
+
switch (types) {
|
|
318
|
+
case ['date', 'time']:
|
|
319
|
+
return `${inputs.get(0).value}T${inputs.get(1).value || "00:00"}Z`
|
|
320
|
+
default:
|
|
321
|
+
throw TypeError(`Unexpected composition types: ${types}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
clear() {
|
|
326
|
+
this.data = this.initial;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
isComposite(field) {
|
|
330
|
+
return this.#composite.hasOwnProperty(field);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
isMulti(field) {
|
|
334
|
+
return this.#multi.has(field);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
type(field) {
|
|
338
|
+
if (this.isComposite(field)) {
|
|
339
|
+
return this.#composite[field];
|
|
340
|
+
}
|
|
341
|
+
return this.field(field).prop('type');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
default(field) {
|
|
345
|
+
if (this.isMulti(field)) {
|
|
346
|
+
return [];
|
|
347
|
+
} else if (this.isComposite(field)) {
|
|
348
|
+
return this.decompose(this.type(field), '');
|
|
349
|
+
}
|
|
350
|
+
switch(this.type(field)) {
|
|
351
|
+
case 'checkbox':
|
|
352
|
+
case 'radio':
|
|
353
|
+
return false;
|
|
354
|
+
default:
|
|
355
|
+
return '';
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
field(name) {
|
|
360
|
+
return this.element.find(
|
|
361
|
+
Form.ELEMENTS.join(`[name="${name}"],`) + `[name="${name}"]`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
hasChanged() {
|
|
366
|
+
/**
|
|
367
|
+
* Returns true if this form differs from its initial "clear" state and
|
|
368
|
+
* false otherwise.
|
|
369
|
+
*/
|
|
370
|
+
return Form.differs(this.data, this.initial);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
persist() {
|
|
374
|
+
/**
|
|
375
|
+
* Persist this form's current state to session memory.
|
|
376
|
+
*/
|
|
377
|
+
const current = this.data;
|
|
378
|
+
// never persist excluded fields
|
|
379
|
+
for (const field of this.excluded) {
|
|
380
|
+
if (current.hasOwnProperty(field)) {
|
|
381
|
+
delete current[field];
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
this.persisted = current;
|
|
385
|
+
for (const widget of Object.values(this.widgets)) {
|
|
386
|
+
widget.persist();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
revive() {
|
|
391
|
+
/**
|
|
392
|
+
* Revive this form's current state from session memory, if it has
|
|
393
|
+
* been persisted.
|
|
394
|
+
*/
|
|
395
|
+
this.data = this.persisted;
|
|
396
|
+
for (const widget of Object.values(this.widgets)) {
|
|
397
|
+
widget.revive();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
onChange(callback) {
|
|
402
|
+
this.#changeCallbacks.push(callback);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Persistable } from './persistable.js'
|
|
2
|
+
|
|
3
|
+
export class FormWidget extends Persistable {
|
|
4
|
+
|
|
5
|
+
#container;
|
|
6
|
+
|
|
7
|
+
get container() {
|
|
8
|
+
return this.#container;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
constructor(container) {
|
|
12
|
+
super(container.get(0).getAttribute('id'));
|
|
13
|
+
this.#container = container;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
changed() {
|
|
17
|
+
/**
|
|
18
|
+
* Deriving widgets should implement this callback which is invoked
|
|
19
|
+
* when the underlying widget's state has changed.
|
|
20
|
+
*/
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export class Persistable {
|
|
2
|
+
/**
|
|
3
|
+
* A simple interface defining a persistable component. Data is persisted
|
|
4
|
+
* in session memory.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
key;
|
|
8
|
+
|
|
9
|
+
get persisted() {
|
|
10
|
+
const store = sessionStorage.getItem(this.key);
|
|
11
|
+
if (store) {
|
|
12
|
+
return JSON.parse(sessionStorage.getItem(this.key));
|
|
13
|
+
}
|
|
14
|
+
return {}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set persisted(data) {
|
|
18
|
+
sessionStorage.setItem(this.key, JSON.stringify(data));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
constructor(key) {
|
|
22
|
+
this.key = key;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
persist() {/* Deriving classes define their own persist logic */}
|
|
26
|
+
|
|
27
|
+
revive() {
|
|
28
|
+
/*
|
|
29
|
+
* Deriving classes define their own revival logic, this method
|
|
30
|
+
* should restore persisted state to the component
|
|
31
|
+
*/
|
|
32
|
+
}
|
|
33
|
+
}
|