From 15b43986761200cce8eaee6b1835845875eed3f5 Mon Sep 17 00:00:00 2001 From: robyngit Date: Mon, 9 Sep 2024 19:48:53 -0400 Subject: [PATCH 1/2] Minor fixes to bioontology components pre release - Fix JSdocs - Only debounce the cache that happens automatically in BioontologyResults (allow "cache" to be run manually at any time). --- src/js/collections/ontologies/BioontologyResults.js | 4 ++-- src/js/views/ontologies/BioontologyBrowserView.js | 5 ++--- src/js/views/searchSelect/BioontologySelectView.js | 7 ++++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/js/collections/ontologies/BioontologyResults.js b/src/js/collections/ontologies/BioontologyResults.js index 121d5f4d5..482828f1a 100644 --- a/src/js/collections/ontologies/BioontologyResults.js +++ b/src/js/collections/ontologies/BioontologyResults.js @@ -46,9 +46,9 @@ define([ * @param {boolean} [options.autoCache] - Whether to automatically cache new items */ initialize(_attributes, options) { - this.cache = _.debounce(this.cache, CACHE_DEBOUNCE_TIME); + this.autoCache = _.debounce(this.cache, CACHE_DEBOUNCE_TIME); if (options?.autoCache !== false) { - this.listenTo(this, "add", this.cache); + this.listenTo(this, "add", this.autoCache); } }, diff --git a/src/js/views/ontologies/BioontologyBrowserView.js b/src/js/views/ontologies/BioontologyBrowserView.js index 4cbbc203a..d105f2dc3 100644 --- a/src/js/views/ontologies/BioontologyBrowserView.js +++ b/src/js/views/ontologies/BioontologyBrowserView.js @@ -36,12 +36,11 @@ define([ * @classdesc An interface to browser BioPortal ontologies and classes * @classcategory Views/Ontologies * @augments Backbone.View - * @class * @since 0.0.0 - * @screenshot views/searchSelect/BioontologyBrowserView.png + * @screenshot views/ontologies/BioontologyBrowserView.png */ const BioontologyBrowser = Backbone.View.extend( - /** @lends BioontologyBrowserView.prototype */ + /** @lends BioontologyBrowser.prototype */ { /** @inheritdoc */ type: "BioontologyBrowser", diff --git a/src/js/views/searchSelect/BioontologySelectView.js b/src/js/views/searchSelect/BioontologySelectView.js index eb2c2956e..0f0888348 100644 --- a/src/js/views/searchSelect/BioontologySelectView.js +++ b/src/js/views/searchSelect/BioontologySelectView.js @@ -35,11 +35,12 @@ define([ }; /** - * @class - * @classdesc + * @class BioontologySelectView + * @classdesc A search select view that allows users to search for ontology + * classes that are indexed in Solr and to browse BioPortal ontologies. The + * view can be configured to show class labels from multiple ontologies. * @classcategory Views/SearchSelect * @augments SearchSelect - * @class * @since 0.0.0 * @screenshot views/searchSelect/BioontologySelectView.png */ From 696bb6bfd59d66aba6ec3eb4982024c11da1ba3c Mon Sep 17 00:00:00 2001 From: robyngit Date: Mon, 9 Sep 2024 19:23:52 -0400 Subject: [PATCH 2/2] Change version to 2.31.0 & rebuild docs --- README.md | 2 +- docs/_config.yml | 2 +- docs/docs/AccessPolicy.html | 2 +- docs/docs/AccessPolicyView.html | 2 +- docs/docs/AccessRule.html | 2 +- docs/docs/AccessRuleView.html | 2 +- docs/docs/Accordion.html | 1164 ++ docs/docs/AccordionItem.html | 791 + docs/docs/AccordionItemView.html | 865 + docs/docs/AccordionView.html | 2147 +++ docs/docs/AccountSearchSelect.html | 204 + docs/docs/AccountSelectView.html | 6 +- docs/docs/Analytics.html | 2 +- docs/docs/AnnotationFilter.html | 4 +- docs/docs/AnnotationView.html | 2 +- docs/docs/AnnotatorView.html | 2 +- docs/docs/AppConfig.html | 233 +- docs/docs/AppModel.html | 26 +- docs/docs/AppView.html | 2 +- docs/docs/AssetCategories.html | 2 +- docs/docs/AssetCategory.html | 2 +- docs/docs/AssetColor.html | 2 +- docs/docs/AssetColorPalette.html | 2 +- docs/docs/AssetColors.html | 2 +- docs/docs/BioOntology.html | 204 + .../BioontologyAccordionSearchSelect.html | 1780 ++ docs/docs/BioontologyBatch.html | 205 + docs/docs/BioontologyBrowser.html | 1309 ++ docs/docs/BioontologyClass.html | 205 + docs/docs/BioontologyResults.html | 2207 +++ docs/docs/BioontologySelectView.html | 1823 ++ docs/docs/Bioontology_.html | 204 + docs/docs/BooleanFilter.html | 2 +- docs/docs/BooleanFilterView.html | 16 +- docs/docs/CatalogSearchView.html | 2 +- docs/docs/CategoricalSwatchView.html | 2 +- docs/docs/Cesium3DTileset.html | 42 +- docs/docs/CesiumGeohash.html | 42 +- docs/docs/CesiumImagery.html | 42 +- docs/docs/CesiumTerrain.html | 44 +- docs/docs/CesiumVectorData.html | 42 +- docs/docs/CesiumWidgetView.html | 2 +- docs/docs/ChoiceFilter.html | 2 +- docs/docs/ChoiceFilterView.html | 14 +- docs/docs/CitationHeaderView.html | 2 +- docs/docs/CitationListView.html | 2 +- docs/docs/CitationModalView.html | 2 +- docs/docs/CitationModel.html | 228 +- docs/docs/CitationView.html | 2 +- docs/docs/Citations.html | 2 +- docs/docs/CollectionModel.html | 306 +- docs/docs/ColorPaletteView.html | 2 +- docs/docs/ContinuousSwatchView.html | 2 +- docs/docs/DataCatalogView.html | 2287 +++ docs/docs/DataCatalogViewWithFilters.html | 102 +- docs/docs/DataItemView.html | 48 +- docs/docs/DataONEObject.html | 401 +- docs/docs/DataPackage.html | 58 +- docs/docs/DataPackageView.html | 196 +- docs/docs/DateFilter.html | 2 +- docs/docs/DateFilterView.html | 14 +- docs/docs/DraftsView.html | 2 +- docs/docs/DrawTool.html | 2 +- docs/docs/EML211.html | 356 +- docs/docs/EML211EditorView.html | 2 +- docs/docs/EMLAnnotation.html | 2 +- docs/docs/EMLAnnotations.html | 2 +- docs/docs/EMLAttribute.html | 2 +- docs/docs/EMLAttributeView.html | 2 +- docs/docs/EMLDataTable.html | 2 +- docs/docs/EMLDistribution.html | 2 +- docs/docs/EMLEntity.html | 2 +- docs/docs/EMLEntityView.html | 2 +- docs/docs/EMLGeoCoverage.html | 2 +- docs/docs/EMLMeasurementScale.html | 2 +- docs/docs/EMLMeasurementScaleView.html | 2 +- docs/docs/EMLMeasurementTypeView.html | 2 +- docs/docs/EMLMethodStep.html | 2 +- docs/docs/EMLMethods.html | 2 +- docs/docs/EMLMethodsView.html | 2 +- docs/docs/EMLMissingValueCode.html | 2 +- docs/docs/EMLMissingValueCodeView.html | 2 +- docs/docs/EMLMissingValueCodes.html | 2 +- docs/docs/EMLMissingValueCodesView.html | 2 +- docs/docs/EMLNonNumericDomain.html | 2 +- docs/docs/EMLNumericDomain.html | 2 +- docs/docs/EMLOtherEntity.html | 2 +- docs/docs/EMLOtherEntityView.html | 2 +- docs/docs/EMLParty.html | 2 +- docs/docs/EMLPartyView.html | 2 +- docs/docs/EMLSpecializedText.html | 2 +- docs/docs/EMLTaxonCoverage.html | 2 +- docs/docs/EMLTempCoverageView.html | 2 +- docs/docs/EMLTemporalCoverage.html | 2 +- docs/docs/EMLText.html | 2 +- docs/docs/EMLText211.html | 2 +- docs/docs/EMLUnit.html | 2 +- docs/docs/EMLView.html | 10 +- docs/docs/EMlGeoCoverageView_.html | 2 +- docs/docs/EditCollectionView.html | 2 +- docs/docs/EditorView.html | 2 +- docs/docs/ExpansionPanelView.html | 2 +- docs/docs/ExpansionPanelsModel.html | 2 +- docs/docs/ExternalView.html | 2 +- docs/docs/Feature.html | 2 +- docs/docs/FeatureInfoView.html | 2 +- docs/docs/Features.html | 2 +- docs/docs/Filter.html | 2 +- docs/docs/FilterEditorView.html | 24 +- docs/docs/FilterGroup.html | 2 +- docs/docs/FilterGroupView.html | 16 +- docs/docs/FilterGroupsView.html | 2 +- docs/docs/FilterView.html | 18 +- docs/docs/Filters.html | 2 +- docs/docs/FiltersMapConnector.html | 2 +- docs/docs/FiltersSearchConnector.html | 2 +- docs/docs/FooterView.html | 2 +- docs/docs/GeoBoundingBox.html | 2 +- docs/docs/GeoPoint.html | 2 +- docs/docs/GeoPoints.html | 2 +- docs/docs/GeoPointsCesiumConnector.html | 2 +- docs/docs/GeoPointsCesiumPointsConnector.html | 2 +- .../docs/GeoPointsCesiumPolygonConnector.html | 2 +- docs/docs/GeoScale.html | 2 +- docs/docs/GeoUtilities.html | 2 +- docs/docs/GeocodedLocation.html | 2 +- docs/docs/GeocoderSearch.html | 2 +- docs/docs/Geohash.html | 2 +- docs/docs/Geohashes.html | 2 +- docs/docs/GoogleAnalytics.html | 2 +- docs/docs/GoogleMapsAutocompleter.html | 2 +- docs/docs/GoogleMapsGeocoder.html | 2 +- docs/docs/GroupListView.html | 2 +- docs/docs/IconUtilities.html | 2 +- docs/docs/ImageUploaderView.html | 2 +- docs/docs/LayerCategoryListView.html | 2 +- docs/docs/LayerDetailView.html | 2 +- docs/docs/LayerDetailsView.html | 27 +- docs/docs/LayerInfoView.html | 2 +- docs/docs/LayerItemView.html | 2 +- docs/docs/LayerLegendView.html | 2 +- docs/docs/LayerListView.html | 2 +- docs/docs/LayerNavigationView.html | 2 +- docs/docs/LayerOpacityView.html | 2 +- docs/docs/LayersPanelView.html | 2 +- docs/docs/LegendContainerView.html | 2 +- docs/docs/LegendView.html | 2 +- docs/docs/LogsSearch.html | 2 +- docs/docs/LookupModel.html | 102 +- docs/docs/Map.html | 2 +- docs/docs/MapAsset.html | 126 +- docs/docs/MapAssets.html | 2 +- docs/docs/MapConfig.html | 16 +- docs/docs/MapHelpPanel.html | 2 +- docs/docs/MapInteraction.html | 24 +- docs/docs/MapModel.html | 6 +- docs/docs/MapSearchConnector.html | 2 +- docs/docs/MapSearchFiltersConnector.html | 2 +- docs/docs/MapView.html | 14 +- docs/docs/MapWidgetContainerView.html | 2 +- docs/docs/MarkdownEditorView.html | 2 +- docs/docs/MarkdownView.html | 2 +- docs/docs/MdqRunView.html | 2145 ++- docs/docs/MetacatUI.html | 4 +- docs/docs/MetadataView.html | 214 +- docs/docs/MetricModalView.html | 2 +- docs/docs/MetricView.html | 2 +- docs/docs/Metrics.html | 2 +- docs/docs/MetricsChartView.html | 2 +- docs/docs/NavbarView.html | 2 +- docs/docs/NodeSelect.html | 6 +- docs/docs/NumericFilter.html | 2 +- docs/docs/NumericFilterView.html | 16 +- docs/docs/ObjectFormat.html | 2 +- docs/docs/ObjectFormatSelect.html | 6 +- docs/docs/ObjectFormats.html | 2 +- docs/docs/PortEditorDataView.html | 2 +- docs/docs/PortEditorImageView.html | 2 +- docs/docs/PortEditorLogosView.html | 2 +- docs/docs/PortEditorMdSectionView.html | 2 +- docs/docs/PortEditorSectionView.html | 2 +- docs/docs/PortEditorSectionsView.html | 2 +- docs/docs/PortEditorSettingsView.html | 2 +- docs/docs/PortalDataView.html | 2 +- docs/docs/PortalEditorView.html | 2 +- docs/docs/PortalHeaderView.html | 2 +- docs/docs/PortalImage.html | 2 +- docs/docs/PortalListView.html | 2 +- docs/docs/PortalLogosView.html | 2 +- docs/docs/PortalMembersView.html | 2 +- docs/docs/PortalModel.html | 236 +- docs/docs/PortalSectionModel.html | 2 +- docs/docs/PortalSectionView.html | 2 +- docs/docs/PortalUsagesView.html | 2 +- docs/docs/PortalView.html | 2 +- docs/docs/PortalVisualizationsView.html | 2 +- docs/docs/PortalsSearchView.html | 2 +- docs/docs/Prediction.html | 2 +- docs/docs/PredictionView.html | 2 +- docs/docs/PredictionsListView.html | 2 +- docs/docs/Project.html | 2 +- docs/docs/ProjectList.html | 2 +- docs/docs/ProjectView.html | 2 +- docs/docs/QualityCheck.html | 2 +- docs/docs/QualityReport.html | 2 +- docs/docs/QueryBuilderView.html | 2 +- docs/docs/QueryField.html | 2 +- docs/docs/QueryFieldSearchSelect.html | 204 + docs/docs/QueryFieldSelectView.html | 1362 +- docs/docs/QueryFields.html | 183 +- docs/docs/QueryRuleView.html | 317 +- docs/docs/Quota.html | 2 +- docs/docs/Quotas.html | 2 +- docs/docs/RegisterCitationView.html | 2 +- docs/docs/ScaleBarView.html | 2 +- docs/docs/ScienceMetadata.html | 404 +- docs/docs/ScienceMetadataView.html | 2 +- docs/docs/Search.html | 2 +- docs/docs/SearchInputView.html | 2 +- docs/docs/SearchParams.html | 2 +- docs/docs/SearchResultView.html | 2 +- docs/docs/SearchResultsPagerView.html | 2 +- docs/docs/SearchResultsView.html | 2 +- docs/docs/SearchSelect.html | 204 + docs/docs/SearchSelectOptions.html | 193 + docs/docs/SearchSelectView.html | 5000 ++++++ docs/docs/SearchView.html | 2 +- docs/docs/SelectOptionModel.html | 203 + docs/docs/SemanticFilterView.html | 543 +- docs/docs/SeparatorView.html | 1594 ++ docs/docs/ShareUrlView.html | 2 +- docs/docs/SignInView.html | 2 +- docs/docs/SolrAutocomplete.html | 204 + docs/docs/SolrResult.html | 168 +- docs/docs/SolrResults.html | 2 +- docs/docs/SorterView.html | 2 +- docs/docs/SpatialFilter.html | 2 +- docs/docs/Stats.html | 2 +- docs/docs/Subscription.html | 2 +- docs/docs/TOCView.html | 2 +- docs/docs/TableEditorView.html | 2 +- docs/docs/ToggleFilter.html | 2 +- docs/docs/ToggleFilterView.html | 16 +- docs/docs/ToolbarView.html | 2 +- docs/docs/UIRouter.html | 2 +- docs/docs/Units.html | 2 +- docs/docs/Usage.html | 2 +- docs/docs/Usages.html | 2 +- docs/docs/UserGroup.html | 2 +- docs/docs/UserGroupView.html | 2 +- docs/docs/UserView.html | 2 +- docs/docs/Utilities.html | 620 +- docs/docs/VectorFilter.html | 2 +- docs/docs/VectorFilters.html | 2 +- docs/docs/ViewfinderModel.html | 2 +- docs/docs/ViewfinderView.html | 2 +- docs/docs/ZoomPresetModel.html | 2 +- docs/docs/ZoomPresetView.html | 2 +- docs/docs/ZoomPresets.html | 2 +- docs/docs/ZoomPresetsListView.html | 2 +- docs/docs/docs_other_addtlDocs.jsdoc.html | 2 +- docs/docs/global.html | 13896 +++++++++++++++- docs/docs/index.html | 2 +- docs/docs/src_js_app.js.html | 8 +- .../src_js_collections_AccessPolicy.js.html | 2 +- .../docs/src_js_collections_Citations.js.html | 19 +- .../src_js_collections_DataPackage.js.html | 1414 +- docs/docs/src_js_collections_Filters.js.html | 2 +- .../src_js_collections_ObjectFormats.js.html | 2 +- .../src_js_collections_ProjectList.js.html | 2 +- .../src_js_collections_QualityReport.js.html | 2 +- .../src_js_collections_SolrResults.js.html | 2 +- docs/docs/src_js_collections_Units.js.html | 2 +- .../docs/src_js_collections_UserGroup.js.html | 2 +- ...c_js_collections_bookkeeper_Quotas.js.html | 2 +- ...c_js_collections_bookkeeper_Usages.js.html | 2 +- ...s_collections_maps_AssetCategories.js.html | 2 +- ...rc_js_collections_maps_AssetColors.js.html | 2 +- .../src_js_collections_maps_Features.js.html | 2 +- .../src_js_collections_maps_GeoPoints.js.html | 2 +- .../src_js_collections_maps_Geohashes.js.html | 2 +- .../src_js_collections_maps_MapAssets.js.html | 2 +- ..._js_collections_maps_VectorFilters.js.html | 2 +- ...ctions_maps_viewfinder_ZoomPresets.js.html | 2 +- ...ctions_metadata_eml_EMLAnnotations.js.html | 2 +- ..._metadata_eml_EMLMissingValueCodes.js.html | 2 +- ...ions_ontologies_BioontologyResults.js.html | 306 + ...ollections_queryFields_QueryFields.js.html | 150 +- ...s_searchSelect_SearchSelectOptions.js.html | 234 + docs/docs/src_js_common_IconUtilities.js.html | 2 +- docs/docs/src_js_common_SearchParams.js.html | 2 +- docs/docs/src_js_common_Utilities.js.html | 98 +- docs/docs/src_js_models_AccessRule.js.html | 2 +- docs/docs/src_js_models_AppModel.js.html | 79 +- docs/docs/src_js_models_CitationModel.js.html | 141 +- .../src_js_models_CollectionModel.js.html | 2 +- docs/docs/src_js_models_DataONEObject.js.html | 1447 +- docs/docs/src_js_models_LogsSearch.js.html | 2 +- docs/docs/src_js_models_LookupModel.js.html | 3 +- docs/docs/src_js_models_Map.js.html | 2 +- docs/docs/src_js_models_MetricsModel.js.html | 2 +- .../src_js_models_QualityCheckModel.js.html | 2 +- docs/docs/src_js_models_Search.js.html | 2 +- docs/docs/src_js_models_SolrResult.js.html | 34 +- docs/docs/src_js_models_Stats.js.html | 2 +- docs/docs/src_js_models_UserModel.js.html | 2 +- .../src_js_models_accordion_Accordion.js.html | 168 + ..._js_models_accordion_AccordionItem.js.html | 129 + .../src_js_models_analytics_Analytics.js.html | 2 +- ...s_models_analytics_GoogleAnalytics.js.html | 2 +- .../src_js_models_bookkeeper_Quota.js.html | 2 +- ..._js_models_bookkeeper_Subscription.js.html | 2 +- .../src_js_models_bookkeeper_Usage.js.html | 2 +- ...Bioontology-Accordion-SearchSelect.js.html | 279 + ...c_js_models_connectors_Filters-Map.js.html | 2 +- ...s_models_connectors_Filters-Search.js.html | 2 +- ...models_connectors_GeoPoints-Cesium.js.html | 2 +- ..._connectors_GeoPoints-CesiumPoints.js.html | 2 +- ...connectors_GeoPoints-CesiumPolygon.js.html | 2 +- ...dels_connectors_Map-Search-Filters.js.html | 2 +- ...rc_js_models_connectors_Map-Search.js.html | 2 +- ...rc_js_models_filters_BooleanFilter.js.html | 2 +- ...src_js_models_filters_ChoiceFilter.js.html | 2 +- .../src_js_models_filters_DateFilter.js.html | 2 +- .../docs/src_js_models_filters_Filter.js.html | 2 +- .../src_js_models_filters_FilterGroup.js.html | 2 +- ...rc_js_models_filters_NumericFilter.js.html | 2 +- ...rc_js_models_filters_SpatialFilter.js.html | 2 +- ...src_js_models_filters_ToggleFilter.js.html | 2 +- ...src_js_models_formats_ObjectFormat.js.html | 2 +- ...s_models_geocoder_GeocodedLocation.js.html | 2 +- ..._js_models_geocoder_GeocoderSearch.js.html | 2 +- ...s_geocoder_GoogleMapsAutocompleter.js.html | 2 +- ...models_geocoder_GoogleMapsGeocoder.js.html | 2 +- .../src_js_models_geocoder_Prediction.js.html | 2 +- .../src_js_models_maps_AssetCategory.js.html | 2 +- .../src_js_models_maps_AssetColor.js.html | 2 +- ...c_js_models_maps_AssetColorPalette.js.html | 2 +- ...s_models_maps_ExpansionPanelsModel.js.html | 2 +- docs/docs/src_js_models_maps_Feature.js.html | 2 +- .../src_js_models_maps_GeoBoundingBox.js.html | 2 +- docs/docs/src_js_models_maps_GeoPoint.js.html | 2 +- docs/docs/src_js_models_maps_GeoScale.js.html | 2 +- .../src_js_models_maps_GeoUtilities.js.html | 2 +- docs/docs/src_js_models_maps_Geohash.js.html | 2 +- docs/docs/src_js_models_maps_Map.js.html | 5 +- .../src_js_models_maps_MapInteraction.js.html | 13 +- .../src_js_models_maps_VectorFilter.js.html | 2 +- ...models_maps_assets_Cesium3DTileset.js.html | 2 +- ...s_models_maps_assets_CesiumGeohash.js.html | 2 +- ...s_models_maps_assets_CesiumImagery.js.html | 2 +- ...s_models_maps_assets_CesiumTerrain.js.html | 2 +- ...odels_maps_assets_CesiumVectorData.js.html | 2 +- ...src_js_models_maps_assets_MapAsset.js.html | 9 +- ...ls_maps_viewfinder_ViewfinderModel.js.html | 2 +- ...ls_maps_viewfinder_ZoomPresetModel.js.html | 2 +- ...js_models_metadata_ScienceMetadata.js.html | 2 +- ...c_js_models_metadata_eml211_EML211.js.html | 2 +- ...dels_metadata_eml211_EMLAnnotation.js.html | 2 +- ...odels_metadata_eml211_EMLAttribute.js.html | 2 +- ...odels_metadata_eml211_EMLDataTable.js.html | 2 +- ...ls_metadata_eml211_EMLDistribution.js.html | 2 +- ...s_models_metadata_eml211_EMLEntity.js.html | 2 +- ...els_metadata_eml211_EMLGeoCoverage.js.html | 2 +- ...etadata_eml211_EMLMeasurementScale.js.html | 2 +- ..._models_metadata_eml211_EMLMethods.js.html | 2 +- ...etadata_eml211_EMLMissingValueCode.js.html | 2 +- ...etadata_eml211_EMLNonNumericDomain.js.html | 2 +- ...s_metadata_eml211_EMLNumericDomain.js.html | 2 +- ...els_metadata_eml211_EMLOtherEntity.js.html | 2 +- ...js_models_metadata_eml211_EMLParty.js.html | 2 +- ...s_metadata_eml211_EMLTaxonCoverage.js.html | 2 +- ...etadata_eml211_EMLTemporalCoverage.js.html | 2 +- ..._js_models_metadata_eml211_EMLText.js.html | 2 +- ..._js_models_metadata_eml211_EMLUnit.js.html | 2 +- ..._js_models_metadata_eml220_EMLText.js.html | 2 +- ..._models_metadata_eml_EMLMethodStep.js.html | 2 +- ...ls_metadata_eml_EMLSpecializedText.js.html | 2 +- ...c_js_models_ontologies_Bioontology.js.html | 283 + ...models_ontologies_BioontologyBatch.js.html | 383 + ...models_ontologies_BioontologyClass.js.html | 224 + ...els_ontologies_BioontologyOntology.js.html | 150 + .../src_js_models_portals_PortalImage.js.html | 2 +- .../src_js_models_portals_PortalModel.js.html | 2 +- ..._models_portals_PortalSectionModel.js.html | 2 +- ...dels_portals_PortalVizSectionModel.js.html | 2 +- .../src_js_models_projects_Project.js.html | 2 +- ...c_js_models_queryFields_QueryField.js.html | 2 +- ...s_searchSelect_AccountSearchSelect.js.html | 225 + ...earchSelect_QueryFieldSearchSelect.js.html | 362 + ...s_models_searchSelect_SearchSelect.js.html | 348 + ...ls_searchSelect_SearchSelectOption.js.html | 102 + ...dels_searchSelect_SolrAutocomplete.js.html | 142 + docs/docs/src_js_routers_router.js.html | 2 +- .../src_js_views_AccessPolicyView.js.html | 2 +- docs/docs/src_js_views_AccessRuleView.js.html | 2 +- docs/docs/src_js_views_AnnotationView.js.html | 2 +- docs/docs/src_js_views_AppView.js.html | 2 +- .../src_js_views_CitationHeaderView.js.html | 2 +- .../src_js_views_CitationListView.js.html | 2 +- docs/docs/src_js_views_CitationView.js.html | 2 +- .../src_js_views_ColorPaletteView.js.html | 2 +- .../docs/src_js_views_DataCatalogView.js.html | 1331 +- ...s_views_DataCatalogViewWithFilters.js.html | 2 +- docs/docs/src_js_views_DataItemView.js.html | 26 +- .../docs/src_js_views_DataPackageView.js.html | 408 +- docs/docs/src_js_views_DraftsView.js.html | 2 +- .../src_js_views_EditCollectionView.js.html | 2 +- docs/docs/src_js_views_EditorView.js.html | 2 +- docs/docs/src_js_views_FooterView.js.html | 2 +- docs/docs/src_js_views_GroupListView.js.html | 2 +- .../src_js_views_ImageUploaderView.js.html | 2 +- .../src_js_views_MarkdownEditorView.js.html | 2 +- docs/docs/src_js_views_MarkdownView.js.html | 2 +- docs/docs/src_js_views_MdqRunView.js.html | 659 +- docs/docs/src_js_views_MetadataView.js.html | 1992 ++- .../docs/src_js_views_MetricModalView.js.html | 2 +- docs/docs/src_js_views_MetricView.js.html | 2 +- .../src_js_views_MetricsChartView.js.html | 2 +- docs/docs/src_js_views_NavbarView.js.html | 2 +- .../src_js_views_RegisterCitationView.js.html | 2 +- docs/docs/src_js_views_SignInView.js.html | 2 +- docs/docs/src_js_views_StatsView.js.html | 37 +- docs/docs/src_js_views_TOCView.js.html | 2 +- .../docs/src_js_views_TableEditorView.js.html | 2 +- docs/docs/src_js_views_UserGroupView.js.html | 2 +- docs/docs/src_js_views_UserView.js.html | 2 +- ..._views_accordion_AccordionItemView.js.html | 183 + ...c_js_views_accordion_AccordionView.js.html | 309 + ..._views_citations_CitationModalView.js.html | 2 +- ...js_views_filters_BooleanFilterView.js.html | 2 +- ..._js_views_filters_ChoiceFilterView.js.html | 2 +- ...rc_js_views_filters_DateFilterView.js.html | 2 +- ..._js_views_filters_FilterEditorView.js.html | 22 +- ...c_js_views_filters_FilterGroupView.js.html | 6 +- ..._js_views_filters_FilterGroupsView.js.html | 2 +- .../src_js_views_filters_FilterView.js.html | 3 +- ...js_views_filters_NumericFilterView.js.html | 2 +- ...s_views_filters_SemanticFilterView.js.html | 176 +- ..._js_views_filters_ToggleFilterView.js.html | 2 +- ...src_js_views_maps_CesiumWidgetView.js.html | 2 +- .../src_js_views_maps_DrawToolView.js.html | 2 +- ...c_js_views_maps_ExpansionPanelView.js.html | 2 +- .../src_js_views_maps_FeatureInfoView.js.html | 2 +- .../src_js_views_maps_HelpPanelView.js.html | 2 +- ...s_views_maps_LayerCategoryListView.js.html | 2 +- .../src_js_views_maps_LayerDetailView.js.html | 2 +- ...src_js_views_maps_LayerDetailsView.js.html | 108 +- .../src_js_views_maps_LayerInfoView.js.html | 2 +- .../src_js_views_maps_LayerItemView.js.html | 2 +- .../src_js_views_maps_LayerListView.js.html | 2 +- ..._js_views_maps_LayerNavigationView.js.html | 2 +- ...src_js_views_maps_LayerOpacityView.js.html | 2 +- .../src_js_views_maps_LayersPanelView.js.html | 2 +- .../docs/src_js_views_maps_LegendView.js.html | 2 +- docs/docs/src_js_views_maps_MapView.js.html | 7 +- ..._views_maps_MapWidgetContainerView.js.html | 2 +- .../src_js_views_maps_ScaleBarView.js.html | 2 +- .../src_js_views_maps_SearchInputView.js.html | 2 +- .../src_js_views_maps_ShareUrlView.js.html | 2 +- .../src_js_views_maps_ToolbarView.js.html | 2 +- ..._maps_legend_CategoricalSwatchView.js.html | 2 +- ...s_maps_legend_ContinuousSwatchView.js.html | 2 +- ..._views_maps_legend_LayerLegendView.js.html | 2 +- ...ws_maps_legend_LegendContainerView.js.html | 2 +- ...ews_maps_viewfinder_PredictionView.js.html | 2 +- ...aps_viewfinder_PredictionsListView.js.html | 2 +- ...s_views_maps_viewfinder_SearchView.js.html | 2 +- ...ews_maps_viewfinder_ViewfinderView.js.html | 2 +- ...ews_maps_viewfinder_ZoomPresetView.js.html | 2 +- ...aps_viewfinder_ZoomPresetsListView.js.html | 2 +- ...js_views_metadata_EML211EditorView.js.html | 2 +- ...etadata_EML211MissingValueCodeView.js.html | 2 +- ...tadata_EML211MissingValueCodesView.js.html | 2 +- .../src_js_views_metadata_EML211View.js.html | 10 +- ...js_views_metadata_EMLAttributeView.js.html | 2 +- ...rc_js_views_metadata_EMLEntityView.js.html | 2 +- ..._views_metadata_EMLGeoCoverageView.js.html | 2 +- ...s_metadata_EMLMeasurementScaleView.js.html | 2 +- ...ws_metadata_EMLMeasurementTypeView.js.html | 2 +- ...c_js_views_metadata_EMLMethodsView.js.html | 2 +- ..._views_metadata_EMLOtherEntityView.js.html | 2 +- ...src_js_views_metadata_EMLPartyView.js.html | 2 +- ...views_metadata_EMLTempCoverageView.js.html | 2 +- ...views_metadata_ScienceMetadataView.js.html | 2 +- ..._ontologies_BioontologyBrowserView.js.html | 294 + ...rc_js_views_portals_PortalDataView.js.html | 2 +- ..._js_views_portals_PortalHeaderView.js.html | 2 +- ...rc_js_views_portals_PortalListView.js.html | 2 +- ...c_js_views_portals_PortalLogosView.js.html | 2 +- ...js_views_portals_PortalMembersView.js.html | 2 +- ...js_views_portals_PortalMetricsView.js.html | 2 +- ...js_views_portals_PortalSectionView.js.html | 2 +- ..._js_views_portals_PortalUsagesView.js.html | 2 +- .../src_js_views_portals_PortalView.js.html | 2 +- ...s_portals_PortalVisualizationsView.js.html | 2 +- ...js_views_portals_PortalsSearchView.js.html | 2 +- ..._portals_editor_PortEditorDataView.js.html | 2 +- ...portals_editor_PortEditorImageView.js.html | 2 +- ...portals_editor_PortEditorLogosView.js.html | 2 +- ...als_editor_PortEditorMdSectionView.js.html | 2 +- ...rtals_editor_PortEditorSectionView.js.html | 2 +- ...tals_editor_PortEditorSectionsView.js.html | 2 +- ...tals_editor_PortEditorSettingsView.js.html | 2 +- ...ws_portals_editor_PortalEditorView.js.html | 2 +- .../src_js_views_projects_ProjectView.js.html | 2 +- ...iews_queryBuilder_QueryBuilderView.js.html | 168 +- ...s_views_queryBuilder_QueryRuleView.js.html | 1783 +- ...ews_searchSelect_AccountSelectView.js.html | 330 +- ..._searchSelect_AnnotationFilterView.js.html | 17 +- ...searchSelect_BioontologySelectView.js.html | 323 + ..._views_searchSelect_NodeSelectView.js.html | 125 +- ...earchSelect_ObjectFormatSelectView.js.html | 158 +- ..._searchSelect_QueryFieldSelectView.js.html | 491 +- ...earchSelect_SearchSelectHeaderView.js.html | 266 + ...earchSelect_SearchSelectOptionView.js.html | 229 + ...archSelect_SearchSelectOptionsView.js.html | 379 + ...iews_searchSelect_SearchSelectView.js.html | 758 + ...s_views_searchSelect_SeparatorView.js.html | 237 + ..._searchSelect_SolrAutocompleteView.js.html | 96 + ..._js_views_search_CatalogSearchView.js.html | 2 +- ...c_js_views_search_SearchResultView.js.html | 2 +- ...iews_search_SearchResultsPagerView.js.html | 2 +- ..._js_views_search_SearchResultsView.js.html | 2 +- .../src_js_views_search_SorterView.js.html | 2 +- docs/docs/src_loader.js.html | 2 +- docs/index.md | 2 +- package.json | 2 +- src/index.html | 2 +- .../ontologies/BioontologyResults.js | 2 +- .../searchSelect/SearchSelectOptions.js | 2 +- src/js/common/Semantic.js | 2 +- src/js/common/Utilities.js | 4 +- src/js/models/AppModel.js | 6 +- src/js/models/accordion/Accordion.js | 2 +- src/js/models/accordion/AccordionItem.js | 2 +- .../Bioontology-Accordion-SearchSelect.js | 2 +- src/js/models/ontologies/Bioontology.js | 2 +- src/js/models/ontologies/BioontologyBatch.js | 2 +- src/js/models/ontologies/BioontologyClass.js | 2 +- .../models/ontologies/BioontologyOntology.js | 2 +- .../searchSelect/AccountSearchSelect.js | 2 +- .../searchSelect/QueryFieldSearchSelect.js | 2 +- src/js/models/searchSelect/SearchSelect.js | 2 +- .../models/searchSelect/SearchSelectOption.js | 2 +- .../models/searchSelect/SolrAutocomplete.js | 2 +- src/js/views/MdqRunView.js | 4 +- src/js/views/accordion/AccordionItemView.js | 2 +- src/js/views/accordion/AccordionView.js | 2 +- src/js/views/filters/SemanticFilterView.js | 6 +- .../ontologies/BioontologyBrowserView.js | 2 +- .../searchSelect/AnnotationFilterView.js | 2 +- .../searchSelect/BioontologySelectView.js | 4 +- src/js/views/searchSelect/NodeSelectView.js | 2 +- .../searchSelect/ObjectFormatSelectView.js | 2 +- .../searchSelect/SearchSelectHeaderView.js | 2 +- .../searchSelect/SearchSelectOptionView.js | 2 +- .../searchSelect/SearchSelectOptionsView.js | 2 +- src/js/views/searchSelect/SearchSelectView.js | 38 +- src/js/views/searchSelect/SeparatorView.js | 2 +- .../searchSelect/SolrAutocompleteView.js | 2 +- 561 files changed, 54258 insertions(+), 10086 deletions(-) create mode 100644 docs/docs/Accordion.html create mode 100644 docs/docs/AccordionItem.html create mode 100644 docs/docs/AccordionItemView.html create mode 100644 docs/docs/AccordionView.html create mode 100644 docs/docs/AccountSearchSelect.html create mode 100644 docs/docs/BioOntology.html create mode 100644 docs/docs/BioontologyAccordionSearchSelect.html create mode 100644 docs/docs/BioontologyBatch.html create mode 100644 docs/docs/BioontologyBrowser.html create mode 100644 docs/docs/BioontologyClass.html create mode 100644 docs/docs/BioontologyResults.html create mode 100644 docs/docs/BioontologySelectView.html create mode 100644 docs/docs/Bioontology_.html create mode 100644 docs/docs/DataCatalogView.html create mode 100644 docs/docs/QueryFieldSearchSelect.html create mode 100644 docs/docs/SearchSelect.html create mode 100644 docs/docs/SearchSelectOptions.html create mode 100644 docs/docs/SearchSelectView.html create mode 100644 docs/docs/SelectOptionModel.html create mode 100644 docs/docs/SeparatorView.html create mode 100644 docs/docs/SolrAutocomplete.html create mode 100644 docs/docs/src_js_collections_ontologies_BioontologyResults.js.html create mode 100644 docs/docs/src_js_collections_searchSelect_SearchSelectOptions.js.html create mode 100644 docs/docs/src_js_models_accordion_Accordion.js.html create mode 100644 docs/docs/src_js_models_accordion_AccordionItem.js.html create mode 100644 docs/docs/src_js_models_connectors_Bioontology-Accordion-SearchSelect.js.html create mode 100644 docs/docs/src_js_models_ontologies_Bioontology.js.html create mode 100644 docs/docs/src_js_models_ontologies_BioontologyBatch.js.html create mode 100644 docs/docs/src_js_models_ontologies_BioontologyClass.js.html create mode 100644 docs/docs/src_js_models_ontologies_BioontologyOntology.js.html create mode 100644 docs/docs/src_js_models_searchSelect_AccountSearchSelect.js.html create mode 100644 docs/docs/src_js_models_searchSelect_QueryFieldSearchSelect.js.html create mode 100644 docs/docs/src_js_models_searchSelect_SearchSelect.js.html create mode 100644 docs/docs/src_js_models_searchSelect_SearchSelectOption.js.html create mode 100644 docs/docs/src_js_models_searchSelect_SolrAutocomplete.js.html create mode 100644 docs/docs/src_js_views_accordion_AccordionItemView.js.html create mode 100644 docs/docs/src_js_views_accordion_AccordionView.js.html create mode 100644 docs/docs/src_js_views_ontologies_BioontologyBrowserView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_BioontologySelectView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_SearchSelectHeaderView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_SearchSelectOptionView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_SearchSelectOptionsView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_SearchSelectView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_SeparatorView.js.html create mode 100644 docs/docs/src_js_views_searchSelect_SolrAutocompleteView.js.html diff --git a/README.md b/README.md index 439d5ed28..fad8811e3 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ MetacatUI is an open source, community project. We [welcome contributions](https Cite this software as: -> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.30.0). Arctic Data Center. [doi:10.18739/A2SJ19S83](https://doi.org/10.18739/A2SJ19S83) +> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.31.0). Arctic Data Center. [doi:10.18739/A2SJ19S83](https://doi.org/10.18739/A2SJ19S83) ## Screenshots diff --git a/docs/_config.yml b/docs/_config.yml index 73a793da9..7b90810bc 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,3 +1,3 @@ url: "/metacatui" highlighter: "rouge" -version: "2.30.0" +version: "2.31.0" diff --git a/docs/docs/AccessPolicy.html b/docs/docs/AccessPolicy.html index 458f56d2a..5175e8d1f 100644 --- a/docs/docs/AccessPolicy.html +++ b/docs/docs/AccessPolicy.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AccessPolicyView.html b/docs/docs/AccessPolicyView.html index 27c8b7b2f..0cfea5a6a 100644 --- a/docs/docs/AccessPolicyView.html +++ b/docs/docs/AccessPolicyView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AccessRule.html b/docs/docs/AccessRule.html index cf67f2647..b3433e77e 100644 --- a/docs/docs/AccessRule.html +++ b/docs/docs/AccessRule.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AccessRuleView.html b/docs/docs/AccessRuleView.html index df7b4f965..8f5f1c35b 100644 --- a/docs/docs/AccessRuleView.html +++ b/docs/docs/AccessRuleView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Accordion.html b/docs/docs/Accordion.html new file mode 100644 index 000000000..6b6983cfe --- /dev/null +++ b/docs/docs/Accordion.html @@ -0,0 +1,1164 @@ + + + + + MetacatUI Dev Docs: Class: Accordion + + + + + + + + + + + + + + +
+ +

Class: Accordion

+ + + + + + +
+ +
+ +

Accordion()

+ +
A model representing an accordion with nested accordion items
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new Accordion() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • + +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + +
+ Note: Do not set a "easing" attribute on this model. It seems to break +semanticUI accordion. +
+ + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
exclusive + + +boolean + + + + Only allow one section open at a time.
on + + +string + + + + Event on title that will cause accordion to +open. Commonly set to "click".
animateChildren + + +boolean + + + + Whether child content opacity +should be animated. Note: may cause performance issues with many child +elements.
closeNested + + +boolean + + + + Close open nested accordion content +when an element closes.
collapsible + + +boolean + + + + Allow active sections to collapse.
duration + + +number + + + + Duration in milliseconds of the opening +animation.
onOpening + + +function + + + + Callback function before an element +opens. Takes the active content as an argument.
onOpen + + +function + + + + Callback function after an element is +open. Takes the active content as an argument.
onClosing + + +function + + + + Callback function before an element +closes. Takes the active content as an argument.
onClose + + +function + + + + Callback function after an element is +closed. Takes the active content as an argument.
onChanging + + +function + + + + Callback function before an element +opens or closes. Takes the active content as an argument.
onChange + + +function + + + + Callback function when an element opens +or closes. Takes the active content as an argument.
styled + + +boolean + + + + Whether to use Semantic UI styles for the +accordion.
inverted + + +boolean + + + + Whether to use an inverted color scheme +for the accordion (dark background with light text).
fluid + + +boolean + + + + Whether the accordion should take up the +full width of its container.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Default attributes for an Accordion model. +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + getChildren(id) → {Array.<AccordianItem>} +

+ + + + + + +
+ Get the children of an item by its id +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +string + + + + The id of the parent item
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An array of AccordianItem models +
+ + + +
+
+ Type +
+
+ +Array.<AccordianItem> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getRootItems() → {Array.<AccordianItem>} +

+ + + + + + +
+ Get the root items of the accordion. Root items are those without a +parent attribute or with an empty string as the parent attribute. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An array of AccordianItem models +
+ + + +
+
+ Type +
+
+ +Array.<AccordianItem> + + +
+
+ + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/AccordionItem.html b/docs/docs/AccordionItem.html new file mode 100644 index 000000000..ba99306d5 --- /dev/null +++ b/docs/docs/AccordionItem.html @@ -0,0 +1,791 @@ + + + + + MetacatUI Dev Docs: Class: AccordionItem + + + + + + + + + + + + + + +
+ +

Class: AccordionItem

+ + + + + + +
+ +
+ +

AccordionItem()

+ +
A model representing a single item in a nested Semantic UI +accordion
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new AccordionItem() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
itemId + + +string + + + + The unique identifier for the item. This is +required in order for any child items to be nested under this item. If +not provided, it will be generated from the title.
title + + +string + + + + The title of the item.
content + + +string + + + + Content for the dropdown item. This will +be ignored if there are child items.
parent + + +string + + + + The parent item's itemId. If blank or null, +this item is a top-level item. +TODO:
description + + +string + + + + The tooltip content.
subTitle + + +string + + + + The tag to show next to the title.
selectable + + +boolean + + + + Whether the item is selectable.
hasChildren + + +boolean + + + + Whether the item has children.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Default attributes for an AccordionItem model. +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setIdFromTitle() +

+ + + + + + +
+ Sets the itemId from the title, replacing spaces with dashes and +removing any non-alphanumeric characters. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/AccordionItemView.html b/docs/docs/AccordionItemView.html new file mode 100644 index 000000000..8bf80c7fd --- /dev/null +++ b/docs/docs/AccordionItemView.html @@ -0,0 +1,865 @@ + + + + + MetacatUI Dev Docs: Class: AccordionItemView + + + + + + + + + + + + + + +
+ +

Class: AccordionItemView

+ + + + + + +
+ +
+ +

AccordionItemView()

+ +
A view representing an accordion item with a title and content
+ + + + + +
+

Screenshot

+ + + +
+ + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new AccordionItemView() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.View
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ An HTML string to use for an icon indicating that the accordion item is +collapsible. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + tagName +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + updateContent(content, clearopt) +

+ + + + + + +
+ Change the content of the accordion item. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
content + + +string +| + +HTMLElement +| + +Backbone.View + + + + + + + + + + The content to +display.
clear + + +boolean + + + + + + <optional>
+ + + + + +
Whether to clear the existing content.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/AccordionView.html b/docs/docs/AccordionView.html new file mode 100644 index 000000000..798facebe --- /dev/null +++ b/docs/docs/AccordionView.html @@ -0,0 +1,2147 @@ + + + + + MetacatUI Dev Docs: Class: AccordionView + + + + + + + + + + + + + + +
+ +

Class: AccordionView

+ + + + + + +
+ +
+ +

AccordionView()

+ +
An extension of the Semantic UI accordion that allows for +defining contents with a Backbone model, and adds tooltips and other +features.
+ + + + + +
+

Screenshot

+ + + +
+ + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new AccordionView() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.View
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + tagName +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + addItem(model, container) +

+ + + + + + +
+ Adds an item to the container element for the accordion +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
model + + +AccordionItem + + + + An AccordionItem model
container + + +HTMLElement + + + + The container element for the +accordion
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addItems(models, container) +

+ + + + + + +
+ Adds items to the container element for the accordion +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
models + + +Array.<AccordionItem> + + + + An array of AccordionItem models
container + + +HTMLElement + + + + The container element for the +accordion
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addNewItem(model) +

+ + + + + + +
+ Handles adding a new item to the accordion when the items collection +has new models added to it. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
model + + +AccordionItem + + + + The new AccordionItem model
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + clearAllItems() +

+ + + + + + +
+ Removes all items from the accordion and clears the itemViews object. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + createAccordion(items) → {HTMLElement} +

+ + + + + + +
+ Creates a container for the accordion with the necessary classes for +Semantic UI and renders any items belonging to the accordion. This can +be used to create the root accordion or nested accordions. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
items + + +Array.<AccordionItem> + + + + An array of AccordionItem models
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The container element for the accordion +
+ + + +
+
+ Type +
+
+ +HTMLElement + + +
+
+ + + + + + + + + + + + + +

+ + + + + createContainer() → {HTMLElement} +

+ + + + + + +
+ Creates a container element for the accordion with the necessary +classes +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The container element for the accordion +
+ + + +
+
+ Type +
+
+ +HTMLElement + + +
+
+ + + + + + + + + + + + + +

+ + + + + initialize(options) +

+ + + + + + +
+ Initializes the AccordionView with the model and listens for changes +to the items collection. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object + + + + Options for the view +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
model + + +Accordion + + + + + + <optional>
+ + + + + +
The Accordion model for the view. If +not provided, a new Accordion model will be created.
modelData + + +object + + + + + + <optional>
+ + + + + +
Optional data to initialize the +Accordion model with. Only used if options.model is not provided.
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initializeAccordion() +

+ + + + + + +
+ Initializes the Semantic UI accordion module with the settings from the +model. The module handles applying accordion behavior to the view and +any new DOM elements that are added. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + refreshContent(itemId) +

+ + + + + + +
+ Refreshes the content of an item in the accordion. If the item has +children, it will create a new accordion with the children. Otherwise, +it will update the content with the item's model content attribute. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
itemId + + +string + + + + The model itemId for the item
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + removeItem(model) +

+ + + + + + +
+ Handles removing an item from the accordion when the items collection +has models removed from it. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
model + + +AccordionItem + + + + The removed AccordionItem model
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + viewFromContentEl(contentEl) → {AccordionItemView} +

+ + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
contentEl + + +HTMLElement + + + + A content element from an item
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The view associated with the item +
+ + + +
+
+ Type +
+
+ +AccordionItemView + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/AccountSearchSelect.html b/docs/docs/AccountSearchSelect.html new file mode 100644 index 000000000..5ff03972b --- /dev/null +++ b/docs/docs/AccountSearchSelect.html @@ -0,0 +1,204 @@ + + + + + MetacatUI Dev Docs: Class: AccountSearchSelect + + + + + + + + + + + + + + +
+ +

Class: AccountSearchSelect

+ + + + + + +
+ +
+ +

AccountSearchSelect()

+ +
An extension of SearchSelect that sets the options to the query +fields (e.g. Solr fields) available for searching.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new AccountSearchSelect() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/AccountSelectView.html b/docs/docs/AccountSelectView.html index b313f3734..6a6d9a700 100644 --- a/docs/docs/AccountSelectView.html +++ b/docs/docs/AccountSelectView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -134,7 +134,7 @@

Source:
@@ -174,7 +174,7 @@

Extends

diff --git a/docs/docs/Analytics.html b/docs/docs/Analytics.html index 6eb65507e..d97cbd381 100644 --- a/docs/docs/Analytics.html +++ b/docs/docs/Analytics.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AnnotationFilter.html b/docs/docs/AnnotationFilter.html index 4caa3fb24..a3bc7114d 100644 --- a/docs/docs/AnnotationFilter.html +++ b/docs/docs/AnnotationFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -122,6 +122,8 @@

+
Deprecated:
  • since 2.30.0
+ diff --git a/docs/docs/AnnotationView.html b/docs/docs/AnnotationView.html index e619ad140..a99a1d321 100644 --- a/docs/docs/AnnotationView.html +++ b/docs/docs/AnnotationView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AnnotatorView.html b/docs/docs/AnnotatorView.html index 47447bc63..52b58f948 100644 --- a/docs/docs/AnnotatorView.html +++ b/docs/docs/AnnotatorView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AppConfig.html b/docs/docs/AppConfig.html index 81973e9e3..2c125cf1b 100644 --- a/docs/docs/AppConfig.html +++ b/docs/docs/AppConfig.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -818,7 +818,7 @@
Type:
Source:
@@ -1429,7 +1429,7 @@
Type:
Source:
@@ -1771,7 +1771,7 @@
Type:
Source:
@@ -1874,6 +1874,99 @@
Type:
+

+ + + + + bioportalApiBaseUrl :string +

+ + + + +
+ The Bioportal REST API URL, which is used for looking up ontology information +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + +
Default Value:
+
    +
  • "https://data.bioontology.org"
  • +
+ + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +

@@ -1934,7 +2027,94 @@
Type:
Source:
+ + + + + + + + + + + + + + + + +

+ + + + + bioportalOntologies :Array.<{label: string, ontology: string, subTree: string, icon: string}> +

+ + + + +
+ The list of Bioportal ontologies that are available for searching & +labeling data in the repository. These are the ontologies that will +be displayed in the bioontology browser, and the ontologies that a +user can search within when querying data with the sem_annotation +field. Set a subTree property to limit the ontology to a particular +class. For the full list of possible ontologies, see the Bioportal +website: https://bioportal.bioontology.org/ontologies +
+ + + +
Type:
+
    +
  • + +Array.<{label: string, ontology: string, subTree: string, icon: string}> + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -2000,7 +2180,7 @@
Type:
- +
Deprecated:
  • since 2.31.0
@@ -2008,10 +2188,7 @@
Type:
-
Default Value:
-
    -
  • "https://data.bioontology.org/search"
  • -
+ @@ -2100,7 +2277,7 @@
Type:
Source:
@@ -2182,7 +2359,7 @@
Type:
Source:
@@ -2264,7 +2441,7 @@
Type:
Source:
@@ -2346,7 +2523,7 @@
Type:
Source:
@@ -2428,7 +2605,7 @@
Type:
Source:
@@ -2595,7 +2772,7 @@
Type:
Source:
@@ -3276,7 +3453,7 @@
Type:
Source:
@@ -3950,7 +4127,7 @@
Type:
Source:
@@ -4406,7 +4583,7 @@
Type:
Source:
@@ -7514,7 +7691,7 @@
Type:
Source:
@@ -7686,7 +7863,7 @@
Type:
Source:
@@ -8031,7 +8208,7 @@
Type:
Source:
@@ -11572,7 +11749,7 @@
Type:
Source:
@@ -13951,7 +14128,7 @@
Type:
Source:
@@ -14278,7 +14455,7 @@

Source:
@@ -14356,7 +14533,7 @@

Type:
Source:
@@ -16205,7 +16382,7 @@
Type:
Source:
@@ -16300,7 +16477,7 @@
Type:
Source:
diff --git a/docs/docs/AppModel.html b/docs/docs/AppModel.html index b08e8c0b0..f66ffafd5 100644 --- a/docs/docs/AppModel.html +++ b/docs/docs/AppModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -300,7 +300,7 @@
Parameters:
Source:
@@ -471,7 +471,7 @@
Parameters:
Source:
@@ -666,7 +666,7 @@
Parameters:
Source:
@@ -760,7 +760,7 @@

Source:
@@ -933,7 +933,7 @@

Parameters:
Source:
@@ -1047,7 +1047,7 @@

Source:
@@ -1193,7 +1193,7 @@

Parameters:
Source:
@@ -1362,7 +1362,7 @@
Parameters:
Source:
@@ -1530,7 +1530,7 @@
Parameters:
Source:
@@ -1627,7 +1627,7 @@

Source:
@@ -1724,7 +1724,7 @@

Source:
@@ -1820,7 +1820,7 @@

Source:
diff --git a/docs/docs/AppView.html b/docs/docs/AppView.html index a0854ccf1..efd4668c9 100644 --- a/docs/docs/AppView.html +++ b/docs/docs/AppView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AssetCategories.html b/docs/docs/AssetCategories.html index 9f5635020..0c7c001df 100644 --- a/docs/docs/AssetCategories.html +++ b/docs/docs/AssetCategories.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AssetCategory.html b/docs/docs/AssetCategory.html index ca8098334..74180ddcc 100644 --- a/docs/docs/AssetCategory.html +++ b/docs/docs/AssetCategory.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AssetColor.html b/docs/docs/AssetColor.html index 295726d30..4b81bd41d 100644 --- a/docs/docs/AssetColor.html +++ b/docs/docs/AssetColor.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AssetColorPalette.html b/docs/docs/AssetColorPalette.html index a154b0a43..35f71d790 100644 --- a/docs/docs/AssetColorPalette.html +++ b/docs/docs/AssetColorPalette.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/AssetColors.html b/docs/docs/AssetColors.html index f93d3a906..899034cc5 100644 --- a/docs/docs/AssetColors.html +++ b/docs/docs/AssetColors.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/BioOntology.html b/docs/docs/BioOntology.html new file mode 100644 index 000000000..f44bdd242 --- /dev/null +++ b/docs/docs/BioOntology.html @@ -0,0 +1,204 @@ + + + + + MetacatUI Dev Docs: Class: BioOntology + + + + + + + + + + + + + + +
+ +

Class: BioOntology

+ + + + + + +
+ +
+ +

BioOntology()

+ +
This model represents an ontology from the BioPortal API, see +https://data.bioontology.org/documentation#Ontology
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioOntology() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BioontologyAccordionSearchSelect.html b/docs/docs/BioontologyAccordionSearchSelect.html new file mode 100644 index 000000000..e2050635e --- /dev/null +++ b/docs/docs/BioontologyAccordionSearchSelect.html @@ -0,0 +1,1780 @@ + + + + + MetacatUI Dev Docs: Class: BioontologyAccordionSearchSelect + + + + + + + + + + + + + + +
+ +

Class: BioontologyAccordionSearchSelect

+ + + + + + +
+ +
+ +

BioontologyAccordionSearchSelect()

+ +
Manages interactions between the BioPortal API and UI components. +It connects the SearchSelect model, which specifies the ontology for querying, +with the Accordion model that displays the search results. Changes in the selected +ontology trigger a new search, updating the Accordion with formatted results. +This model also tracks selected ontology classes for use across the application, +primarily in the BioontologyBrowser view.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioontologyAccordionSearchSelect() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + connect() +

+ + + + + + +
+ Connects the three models together. When the bioontology results change, +the accordion display model is updated to reflect the new results. When +the selected ontology model changes in the searchSelect, the bioontology +model is updated to reflect the new ontology. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + defaults() +

+ + + + + + +
+ Default model attributes +
+ + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bioontology + + +Bioontology + + + + The Bioontology model
accordion + + +Accordion + + + + The Accordion model
searchSelect + + +SearchSelect + + + + The SearchSelect model
selectedClass + + +BioontologyClass + + + + The selected ontology class
accordionRoot + + +string + + + + The root-level ontology or subtree when +the Bioontology model is first fetched (can change when searching subtrees).
defaultSubtree + + +string + + + + The default subtree to display when +if no subtree is specified in the ontology options.
ontologyOptions + + +Array + + + + An array of objects specifying the +ontologies to choose from in the SearchSel
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + fetchChildren(itemModel) +

+ + + + + + +
+ Fetches the children of an ontology class from the BioPortal API. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
itemModel + + +Backbone.Model + + + + The model of the ontology class to +fetch children for.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setAccordionRoot(subTreeopt) +

+ + + + + + +
+ Sets the accordionRoot attribute to the root ontology or subtree when +the Bioontology model is first fetched. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
subTree + + +string + + + + + + <optional>
+ + + + + +
The root ontology or subtree. If not +provided, current subTree of the Bioontology model is used or the +default subtree.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setSelectedClass(itemModel) +

+ + + + + + +
+ Selects a class in the accordion and sets the selectedClass attribute +in this connector to the selected class. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
itemModel + + +Backbone.Model + + + + The model of the selected class.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setupAccordion() +

+ + + + + + +
+ Sets up the Accordion model with the first ontology and fetches the +ontology classes. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setupBioontology(firstOntology) +

+ + + + + + +
+ Sets up the Bioontology model with the first ontology and fetches the +ontology classes. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
firstOntology + + +object + + + + The first ontology object in the +ontologyOptions array.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setupSearchSelect(options, selected) +

+ + + + + + +
+ Sets up the SearchSelect model with the ontology options and the first +ontology. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Array.<object> + + + + An array of ontology options objects to +populate a search select model.
selected + + +string + + + + The value of the first ontology to select.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + switchOntology(newOntology) +

+ + + + + + +
+ Switches the ontology in the bioontology model to the selected ontology +and fetches the new ontology classes. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
newOntology + + +BioontolgyClass + + + + The selected ontology model, +with ontology and subTree attributes.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + syncAccordion() +

+ + + + + + +
+ Syncs the accordion display model with the bioontology results model. +This method is called when the bioontology results model changes. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BioontologyBatch.html b/docs/docs/BioontologyBatch.html new file mode 100644 index 000000000..f803f1cde --- /dev/null +++ b/docs/docs/BioontologyBatch.html @@ -0,0 +1,205 @@ + + + + + MetacatUI Dev Docs: Class: BioontologyBatch + + + + + + + + + + + + + + +
+ +

Class: BioontologyBatch

+ + + + + + +
+ +
+ +

BioontologyBatch()

+ +
A model that fetches data from the BioPortal API using the batch +endpoint. This can be used to store data about classes that have been +fetched from BioPortal, and to fetch additional classes as needed.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioontologyBatch() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BioontologyBrowser.html b/docs/docs/BioontologyBrowser.html new file mode 100644 index 000000000..af8a4ed91 --- /dev/null +++ b/docs/docs/BioontologyBrowser.html @@ -0,0 +1,1309 @@ + + + + + MetacatUI Dev Docs: Class: BioontologyBrowser + + + + + + + + + + + + + + +
+ +

Class: BioontologyBrowser

+ + + + + + +
+ +
+ +

BioontologyBrowser()

+ +
An interface to browser BioPortal ontologies and classes
+ + + + + +
+

Screenshot

+ + + +
+ + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioontologyBrowser() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.View
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + noTermHTML +

+ + + + +
+ The HTML string to display when no term is selected +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + styles +

+ + + + +
+ Extra CSS styles for this view. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + classInfoTemplate(vars) → {string} +

+ + + + + + +
+ Given variables, returns the HTML string the panel that shows details +about a class +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
vars + + +object + + + + The variables to use in the template +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
label + + +string + + + + The label of the class
description + + +string + + + + The description of the class
id + + +string + + + + The ID of the class
uiLink + + +string + + + + The link to the class on BioPortal
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The HTML string for the class info panel +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + handleSelectButtonClick() +

+ + + + + + +
+ Called when the select button is clicked and triggers the selected +event with the selected class model as the argument +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + +
Fires:
+
    +
  • BioontologyBrowser#event:selected
  • +
+ + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize(options) +

+ + + + + + +
+ Initialize the BioontologyBrowser view +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object + + + + Options for the view +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ontologyOptions + + +object + + + + The ontologies (or classes) that +a user can select terms from. Each ontology should have a label and an +ontology acronym, and an optional subtree root.
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Example
+ +
const browser = new BioontologyBrowser({
+ ontologyOptions: [
+  {
+    label: "Measurement Types (ECSO)",
+    ontology: "ECSO",
+    subTree: "http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#MeasurementType"
+   }, { ... } ]
+});
+ + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + updateClassInfoEl(transitionTime) +

+ + + + + + +
+ Update the class info panel with the currently selected class +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transitionTime + + +number + + + + The time in milliseconds for the fade +transition between changing info in the panel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BioontologyClass.html b/docs/docs/BioontologyClass.html new file mode 100644 index 000000000..c88a81279 --- /dev/null +++ b/docs/docs/BioontologyClass.html @@ -0,0 +1,205 @@ + + + + + MetacatUI Dev Docs: Class: BioontologyClass + + + + + + + + + + + + + + +
+ +

Class: BioontologyClass

+ + + + + + +
+ +
+ +

BioontologyClass()

+ +
This model is designed to handle ontology class data from the +BioPortal API. All attributes not documented here are detailed on the +BioPortal API docs: https://data.bioontology.org/documentation.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioontologyClass() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BioontologyResults.html b/docs/docs/BioontologyResults.html new file mode 100644 index 000000000..e99835114 --- /dev/null +++ b/docs/docs/BioontologyResults.html @@ -0,0 +1,2207 @@ + + + + + MetacatUI Dev Docs: Class: BioontologyResults + + + + + + + + + + + + + + +
+ +

Class: BioontologyResults

+ + + + + + +
+ +
+ +

BioontologyResults()

+ +
A collection of items returned from the BioPortal API. So far +this collection is capable of storing Bioontology Classes and Ontologies.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioontologyResults() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Collection
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + cache() +

+ + + + + + +
+ Store the collection in the browser's storage +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + cacheWithRetry(cache) +

+ + + + + + +
+ If the cache is full, remove the oldest 100 items and try to cache again +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cache + + +Array.<object> + + + + The cache to store
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + classes() → {Array.<BioontologyClass>} +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ All BioontologyClass models in this collection +
+ + + +
+
+ Type +
+
+ +Array.<BioontologyClass> + + +
+
+ + + + + + + + + + + + + +

+ + + + + classesToAccordionItems(root) → {Array.<object>} +

+ + + + + + +
+ Convert all classes in the collection attributes to use in the +Accordion model +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
root + + +string + + + + The root ontology or subtree
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The classes as Accordion items +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + clearCache() +

+ + + + + + +
+ Remove all items from the browser's storage +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + fetchOntologyDetails(ontologies, includeopt, includeViewsopt, displayContextopt, displayLinksopt) +

+ + + + + + +
+ Fetches information for all ontologies in the collection. params use +the defaults in the BioontologyOntology model if not provided. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
ontologies + + +Array.<string> + + + + + + + + + + The acronyms of the ontologies to fetch, +otherwise all ontologies in the collection will be fetched.
include + + +Array.<string> + + + + + + <optional>
+ + + + + +
The fields to include in the response.
includeViews + + +boolean + + + + + + <optional>
+ + + + + +
Whether to include views
displayContext + + +boolean + + + + + + <optional>
+ + + + + +
Whether to include context.
displayLinks + + +boolean + + + + + + <optional>
+ + + + + +
Whether to include links.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + fetchOntologyNames(checkCacheopt) +

+ + + + + + +
+ Fetches the names of all ontologies in the collection that do not have +a name. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
checkCache + + +boolean + + + + + + <optional>
+ + + + + +
Whether to check the browser's +storage for the names of the ontologies before fetching them.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + fetchOntologyNamesFromCache(acronyms) → {Array.<BioontologyOntology>} +

+ + + + + + +
+ Fetches the names of the ontologies from the browser's storage cache +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
acronyms + + +Array.<string> + + + + The acronyms of the ontologies to fetch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The ontologies with names +
+ + + +
+
+ Type +
+
+ +Array.<BioontologyOntology> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getItemsFromCache(ids) → {Array.<object>} +

+ + + + + + +
+ Retrieve classes & ontologies from the browser's storage, if available +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ids + + +Array.<string> + + + + The unique identifiers of the items to get, +otherwise all items available in the cache will be restored.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The items from the cache +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + initialize(_attributes, options) +

+ + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
_attributes + + +object + + + + The attributes to initialize the collection with
options + + +object + + + + The options to initialize the collection with +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
autoCache + + +boolean + + + + + + <optional>
+ + + + + +
Whether to automatically cache new items
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + model() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + ontologies() → {Array.<BioontologyOntology>} +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ All BioontologyOntology models in this collection +
+ + + +
+
+ Type +
+
+ +Array.<BioontologyOntology> + + +
+
+ + + + + + + + + + + + + +

+ + + + + restoreFromCache(ids, silent) → {Array.<BioontologyClass>} +

+ + + + + + +
+ Restore classes & ontologies from the browser's storage and adds them to +the collection. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ids + + +Array.<string> + + + + The unique identifiers of the items to restore, +otherwise all items available in the cache will be restored.
silent + + +boolean + + + + Whether to suppress the "add" event
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The restored items +
+ + + +
+
+ Type +
+
+ +Array.<BioontologyClass> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BioontologySelectView.html b/docs/docs/BioontologySelectView.html new file mode 100644 index 000000000..be7e8959b --- /dev/null +++ b/docs/docs/BioontologySelectView.html @@ -0,0 +1,1823 @@ + + + + + MetacatUI Dev Docs: Class: BioontologySelectView + + + + + + + + + + + + + + +
+ +

Class: BioontologySelectView

+ + + + + + +
+ +
+ +

BioontologySelectView()

+ +
A search select view that allows users to search for ontology +classes that are indexed in Solr and to browse BioPortal ontologies. The +view can be configured to show class labels from multiple ontologies.
+ + + + + +
+

Screenshot

+ + + +
+ + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new BioontologySelectView() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + ontologies :Array.<{label: string, ontology: string, subTree: string}> +

+ + + + +
+ The ontologies that can be searched or browsed. Each ontology needs a +"label" and a "ontology" (acronym) property. Optionally, a "subTree" +property can be provided to search a specific sub-tree of the ontology. +
+ + + +
Type:
+
    +
  • + +Array.<{label: string, ontology: string, subTree: string}> + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + queryField :string +

+ + + + +
+ The name of the field in the Solr schema that the user is searching. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + showClassLabels :boolean +

+ + + + +
+ Set this to false to avoid fetching class labels from BioPortal. The +labels will be displayed as the values that are returned from the Solr +query. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + addListeners() +

+ + + + + + +
+ Listen to when a class is selected in the browser & when the button is +clicked to open the browser +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addOptionDetails(classes) +

+ + + + + + +
+ Add the details of the ontology classes to the options in the select +element +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Backbone.Collection +| + +Array + + + + The collection of classes to add +to the options
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + fetchClassLabels() +

+ + + + + + +
+ Fetch the labels select element from BioPortal +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + hideOntologyBrowser() +

+ + + + + + +
+ Hide the ontology browser modal +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize(optsopt) +

+ + + + + + +
+ Initialize the view +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
opts + + +object + + + + + + <optional>
+ + + + + +
The options to initialize the view with +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
showClassLabels + + +boolean + + + + + + <optional>
+ + + + + +
Set to false to avoid +fetching class labels from BioPortal
queryField + + +string + + + + + + <optional>
+ + + + + +
The name of the field in the Solr +schema that the user is searching
ontologies + + +Array.<object> + + + + + + <optional>
+ + + + + +
The ontoloties (& sub-trees) to +allow users to search for.
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + renderButton() +

+ + + + + + +
+ Create the button to open the ontology browser +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + renderOntologyModal() +

+ + + + + + +
+ Render the ontology browser modal +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + selectClass(ontologyClass) +

+ + + + + + +
+ Set the value of the select element to the given ontology class +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ontologyClass + + +OntologyClass + + + + The class model to select
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showOntologyBrowser() +

+ + + + + + +
+ Show the ontology browser modal +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/Bioontology_.html b/docs/docs/Bioontology_.html new file mode 100644 index 000000000..500f62e5a --- /dev/null +++ b/docs/docs/Bioontology_.html @@ -0,0 +1,204 @@ + + + + + MetacatUI Dev Docs: Class: Bioontology + + + + + + + + + + + + + + +
+ +

Class: Bioontology

+ + + + + + +
+ +
+ +

Bioontology()

+ +
A model that fetches data from the BioPortal API for a given +ontology.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new Bioontology() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/BooleanFilter.html b/docs/docs/BooleanFilter.html index 45b2d49c9..6d28edc2a 100644 --- a/docs/docs/BooleanFilter.html +++ b/docs/docs/BooleanFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/BooleanFilterView.html b/docs/docs/BooleanFilterView.html index aa2b806b2..109d221eb 100644 --- a/docs/docs/BooleanFilterView.html +++ b/docs/docs/BooleanFilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1389,7 +1389,7 @@
Parameters:
Source:
@@ -1533,7 +1533,7 @@
Parameters:
Source:
@@ -1706,7 +1706,7 @@
Parameters:
Source:
@@ -2212,7 +2212,7 @@
Parameters:
Source:
@@ -2361,7 +2361,7 @@
Parameters:
Source:
@@ -2527,7 +2527,7 @@
Parameters:
Source:
@@ -2872,7 +2872,7 @@
Parameters:
Source:
diff --git a/docs/docs/CatalogSearchView.html b/docs/docs/CatalogSearchView.html index 8ffa28015..1c1ced23a 100644 --- a/docs/docs/CatalogSearchView.html +++ b/docs/docs/CatalogSearchView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/CategoricalSwatchView.html b/docs/docs/CategoricalSwatchView.html index ba1c7f0b8..cae3985ab 100644 --- a/docs/docs/CategoricalSwatchView.html +++ b/docs/docs/CategoricalSwatchView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Cesium3DTileset.html b/docs/docs/Cesium3DTileset.html index 0a791ee1a..39a89b9cf 100644 --- a/docs/docs/Cesium3DTileset.html +++ b/docs/docs/Cesium3DTileset.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -693,7 +693,7 @@
Parameters:
Source:
@@ -869,7 +869,7 @@
Parameters:
Source:
@@ -1191,7 +1191,7 @@
Parameters:
Source:
@@ -1364,7 +1364,7 @@
Parameters:
Source:
@@ -1565,7 +1565,7 @@
Parameters:
Source:
@@ -1744,7 +1744,7 @@
Parameters:
Source:
@@ -2157,7 +2157,7 @@

Source:
@@ -2451,7 +2451,7 @@

Parameters:
Source:
@@ -2745,7 +2745,7 @@
Parameters:
Source:
@@ -3374,7 +3374,7 @@

Source:
@@ -3635,7 +3635,7 @@

Source:
@@ -3760,7 +3760,7 @@

Source:
@@ -3863,7 +3863,7 @@

Source:
@@ -4018,7 +4018,7 @@

Parameters:
Source:
@@ -4219,7 +4219,7 @@

Source:
@@ -4319,7 +4319,7 @@

Source:
@@ -4659,7 +4659,7 @@

Parameters:
Source:
@@ -4817,7 +4817,7 @@
Parameters:
Source:
@@ -4939,7 +4939,7 @@

Source:
@@ -5113,7 +5113,7 @@

Parameters:
Source:
diff --git a/docs/docs/CesiumGeohash.html b/docs/docs/CesiumGeohash.html index 92c9cea12..70793773a 100644 --- a/docs/docs/CesiumGeohash.html +++ b/docs/docs/CesiumGeohash.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -719,7 +719,7 @@
Parameters:
Source:
@@ -1425,7 +1425,7 @@
Parameters:
Source:
@@ -1772,7 +1772,7 @@
Parameters:
Source:
@@ -1945,7 +1945,7 @@
Parameters:
Source:
@@ -2146,7 +2146,7 @@
Parameters:
Source:
@@ -2325,7 +2325,7 @@
Parameters:
Source:
@@ -2801,7 +2801,7 @@

Source:
@@ -2975,7 +2975,7 @@

Parameters:
Source:
@@ -3571,7 +3571,7 @@
Parameters:
Source:
@@ -4555,7 +4555,7 @@

Source:
@@ -4816,7 +4816,7 @@

Source:
@@ -4941,7 +4941,7 @@

Source:
@@ -5221,7 +5221,7 @@

Source:
@@ -5590,7 +5590,7 @@

Parameters:
Source:
@@ -5792,7 +5792,7 @@

Source:
@@ -5892,7 +5892,7 @@

Source:
@@ -7364,7 +7364,7 @@

Parameters:
Source:
@@ -7522,7 +7522,7 @@
Parameters:
Source:
@@ -7768,7 +7768,7 @@

Source:
@@ -8191,7 +8191,7 @@

Parameters:
Source:
diff --git a/docs/docs/CesiumImagery.html b/docs/docs/CesiumImagery.html index 035c3e541..8d89d6cec 100644 --- a/docs/docs/CesiumImagery.html +++ b/docs/docs/CesiumImagery.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -595,7 +595,7 @@
Parameters:
Source:
@@ -771,7 +771,7 @@
Parameters:
Source:
@@ -1092,7 +1092,7 @@
Parameters:
Source:
@@ -1265,7 +1265,7 @@
Parameters:
Source:
@@ -1466,7 +1466,7 @@
Parameters:
Source:
@@ -1645,7 +1645,7 @@
Parameters:
Source:
@@ -1890,7 +1890,7 @@

Source:
@@ -2064,7 +2064,7 @@

Parameters:
Source:
@@ -2402,7 +2402,7 @@
Parameters:
Source:
@@ -2625,7 +2625,7 @@

Source:
@@ -3198,7 +3198,7 @@

Source:
@@ -3323,7 +3323,7 @@

Source:
@@ -3426,7 +3426,7 @@

Source:
@@ -3581,7 +3581,7 @@

Parameters:
Source:
@@ -3782,7 +3782,7 @@

Source:
@@ -3882,7 +3882,7 @@

Source:
@@ -4031,7 +4031,7 @@

Parameters:
Source:
@@ -4189,7 +4189,7 @@
Parameters:
Source:
@@ -4311,7 +4311,7 @@

Source:
@@ -4485,7 +4485,7 @@

Parameters:
Source:
diff --git a/docs/docs/CesiumTerrain.html b/docs/docs/CesiumTerrain.html index 4c9a60758..643190568 100644 --- a/docs/docs/CesiumTerrain.html +++ b/docs/docs/CesiumTerrain.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -584,7 +584,7 @@
Parameters:
Source:
@@ -760,7 +760,7 @@
Parameters:
Source:
@@ -1081,7 +1081,7 @@
Parameters:
Source:
@@ -1254,7 +1254,7 @@
Parameters:
Source:
@@ -1455,7 +1455,7 @@
Parameters:
Source:
@@ -1634,7 +1634,7 @@
Parameters:
Source:
@@ -1760,7 +1760,7 @@

Source:
@@ -2054,7 +2054,7 @@

Parameters:
Source:
@@ -2227,7 +2227,7 @@
Parameters:
Source:
@@ -2353,7 +2353,7 @@

Source:
@@ -2647,7 +2647,7 @@

Source:
@@ -2772,7 +2772,7 @@

Source:
@@ -2875,7 +2875,7 @@

Source:
@@ -3030,7 +3030,7 @@

Parameters:
Source:
@@ -3132,7 +3132,7 @@

Source:
@@ -3234,7 +3234,7 @@

Source:
@@ -3334,7 +3334,7 @@

Source:
@@ -3483,7 +3483,7 @@

Parameters:
Source:
@@ -3641,7 +3641,7 @@
Parameters:
Source:
@@ -3763,7 +3763,7 @@

Source:
@@ -3937,7 +3937,7 @@

Parameters:
Source:
diff --git a/docs/docs/CesiumVectorData.html b/docs/docs/CesiumVectorData.html index 8a41c36e5..7c24b4667 100644 --- a/docs/docs/CesiumVectorData.html +++ b/docs/docs/CesiumVectorData.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -740,7 +740,7 @@
Parameters:
Source:
@@ -1431,7 +1431,7 @@
Parameters:
Source:
@@ -1773,7 +1773,7 @@
Parameters:
Source:
@@ -1946,7 +1946,7 @@
Parameters:
Source:
@@ -2147,7 +2147,7 @@
Parameters:
Source:
@@ -2326,7 +2326,7 @@
Parameters:
Source:
@@ -2792,7 +2792,7 @@

Source:
@@ -2966,7 +2966,7 @@

Parameters:
Source:
@@ -3547,7 +3547,7 @@
Parameters:
Source:
@@ -4506,7 +4506,7 @@

Source:
@@ -4767,7 +4767,7 @@

Source:
@@ -4892,7 +4892,7 @@

Source:
@@ -5167,7 +5167,7 @@

Source:
@@ -5526,7 +5526,7 @@

Parameters:
Source:
@@ -5728,7 +5728,7 @@

Source:
@@ -5828,7 +5828,7 @@

Source:
@@ -7255,7 +7255,7 @@

Parameters:
Source:
@@ -7413,7 +7413,7 @@
Parameters:
Source:
@@ -7654,7 +7654,7 @@

Source:
@@ -8072,7 +8072,7 @@

Parameters:
Source:
diff --git a/docs/docs/CesiumWidgetView.html b/docs/docs/CesiumWidgetView.html index 280f016e2..6f3f94a10 100644 --- a/docs/docs/CesiumWidgetView.html +++ b/docs/docs/CesiumWidgetView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ChoiceFilter.html b/docs/docs/ChoiceFilter.html index 37b40507d..0bf1c88dc 100644 --- a/docs/docs/ChoiceFilter.html +++ b/docs/docs/ChoiceFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ChoiceFilterView.html b/docs/docs/ChoiceFilterView.html index cc79e0cd6..d533a4784 100644 --- a/docs/docs/ChoiceFilterView.html +++ b/docs/docs/ChoiceFilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1842,7 +1842,7 @@
Parameters:
Source:
@@ -1986,7 +1986,7 @@
Parameters:
Source:
@@ -2159,7 +2159,7 @@
Parameters:
Source:
@@ -2910,7 +2910,7 @@
Parameters:
Source:
@@ -3225,7 +3225,7 @@
Parameters:
Source:
@@ -3670,7 +3670,7 @@
Parameters:
Source:
diff --git a/docs/docs/CitationHeaderView.html b/docs/docs/CitationHeaderView.html index 9311d3480..a59edfc79 100644 --- a/docs/docs/CitationHeaderView.html +++ b/docs/docs/CitationHeaderView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/CitationListView.html b/docs/docs/CitationListView.html index 09d3059e2..91fe05d51 100644 --- a/docs/docs/CitationListView.html +++ b/docs/docs/CitationListView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/CitationModalView.html b/docs/docs/CitationModalView.html index 441e5c320..e32997d3d 100644 --- a/docs/docs/CitationModalView.html +++ b/docs/docs/CitationModalView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/CitationModel.html b/docs/docs/CitationModel.html index 522038e1c..36c66fb07 100644 --- a/docs/docs/CitationModel.html +++ b/docs/docs/CitationModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -197,7 +197,7 @@

- defaults :Object + defaults :object

@@ -213,7 +213,7 @@
Type:
- - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - bytesToSize() -

- - - - - - -
- Converts the number of bytes into a human readable format and -updates the `sizeStr` attribute -
- - - - - - - - - - - - - -
- - - - - - -
Inherited From:
-
- - - - - - - - - - - - - - - - - - - - - -
Source:
-
@@ -915,7 +815,7 @@
Parameters:
Source:
@@ -1016,8 +916,6 @@
Parameters:
- Default - Description @@ -1053,12 +951,6 @@
Parameters:
- - - changePermission - - - The action (read, write, or changePermission) to check if the current user has authorization to perform. By default checks for the highest level of permission. @@ -1093,10 +985,6 @@
Parameters:
- - - - Additional options for this function. See the properties below. @@ -1219,7 +1107,7 @@
Properties:
Source:
@@ -1399,7 +1287,7 @@
Parameters:
Source:
@@ -1637,7 +1525,7 @@

Source:
@@ -1736,7 +1624,7 @@

Source:
@@ -2227,7 +2115,7 @@

Source:
@@ -2626,7 +2514,7 @@

Parameters:
Source:
@@ -2777,7 +2665,7 @@
Parameters:
Source:
@@ -2898,7 +2786,7 @@

Source:
@@ -3023,7 +2911,7 @@

Source:
@@ -3151,7 +3039,7 @@

Source:
@@ -3260,7 +3148,7 @@

Source:
@@ -3362,7 +3250,7 @@

Source:
@@ -3567,7 +3455,7 @@

Source:
@@ -3727,7 +3615,7 @@

Parameters:
Source:
@@ -3993,7 +3881,7 @@
Properties:
Source:
@@ -4092,7 +3980,7 @@

Source:
@@ -4352,7 +4240,7 @@

Parameters:
Source:
@@ -4476,7 +4364,7 @@

Source:
@@ -4646,7 +4534,7 @@

Parameters:
Source:
@@ -4763,7 +4651,7 @@

Source:
@@ -4885,7 +4773,7 @@

Source:
@@ -5002,7 +4890,7 @@

Source:
@@ -5126,7 +5014,7 @@

Source:
@@ -5296,7 +5184,7 @@

Parameters:
Source:
@@ -5415,7 +5303,7 @@

Source:
@@ -5643,7 +5531,7 @@

Parameters:
Source:
@@ -6344,7 +6232,7 @@
Parameters:
Source:
@@ -6537,7 +6425,7 @@

Source:
@@ -6578,7 +6466,7 @@

- save() + save(attributes, options)

@@ -6598,6 +6486,68 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + +
options + +
+ + @@ -6636,7 +6586,7 @@

Source:
@@ -6735,7 +6685,7 @@

Source:
@@ -6852,7 +6802,7 @@

Source:
@@ -6952,7 +6902,7 @@

Source:
@@ -7105,7 +7055,7 @@

Parameters:
Source:
@@ -7146,7 +7096,7 @@

- toJson() + toJson(xml)

@@ -7166,6 +7116,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xml + +
+ + @@ -7204,7 +7198,7 @@

Source:
@@ -7375,7 +7369,7 @@

Parameters:
Source:
@@ -7720,7 +7714,7 @@
Parameters:
Source:
@@ -7868,7 +7862,7 @@
Parameters:
Source:
@@ -7967,7 +7961,7 @@

Source:
@@ -8241,7 +8235,7 @@

Source:
diff --git a/docs/docs/ColorPaletteView.html b/docs/docs/ColorPaletteView.html index c50fef446..5c10bd75d 100644 --- a/docs/docs/ColorPaletteView.html +++ b/docs/docs/ColorPaletteView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ContinuousSwatchView.html b/docs/docs/ContinuousSwatchView.html index 1d679293a..6446c7501 100644 --- a/docs/docs/ContinuousSwatchView.html +++ b/docs/docs/ContinuousSwatchView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/DataCatalogView.html b/docs/docs/DataCatalogView.html new file mode 100644 index 000000000..bd47e623a --- /dev/null +++ b/docs/docs/DataCatalogView.html @@ -0,0 +1,2287 @@ + + + + + MetacatUI Dev Docs: Class: DataCatalogView + + + + + + + + + + + + + + +
+ +

Class: DataCatalogView

+ + + + + + +
+ +
+ +

DataCatalogView()

+ + + + + +
+ +
+
+ + + + + + +

+ + + + + new DataCatalogView() +

+ + + + + + +
+ This view is deprecated and will eventually be removed in a future version (likely 3.0.0) +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Deprecated:
  • Yes
+ + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.View
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + fixedHeight :boolean +

+ + + + +
+ If true, the view height will be adjusted to fit the height of the window +If false, the view height will be fixed via CSS +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + solrError500Message :string +

+ + + + +
+ The user-friendly text to show when a solr request gives a status 500 +error. If none is provided, then the error message that is returned from +solr will be displayed. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.15.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + solrErrorTitle :string +

+ + + + +
+ The general error message to show as a title in the error box when there +is an error fetching results from solr +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.15.0
+ + + + + + + + + + + + + + + + + + + + + +
Default Value:
+
    +
  • "Something went wrong while getting the list of datasets"
  • +
+ + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + template :Underscore.template +

+ + + + +
+ The templates for this view +
+ + + +
Type:
+
    +
  • + +Underscore.template + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + addAll() +

+ + + + + + +
+ Add all items in the **SearchResults** collection +This loads the first 25, then waits for the map to be +fully loaded and then loads the remaining items. +Without this delay, the app waits until all records are processed +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addAnnotationFilter() +

+ + + + + + +
+ addAnnotationFilter - Add the annotation filter to the view +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addMarkers() +

+ + + + + + +
+ Get the details on each marker +And create an infowindow for that marker +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addOne(result) +

+ + + + + + +
+ Add a single SolrResult item to the list by creating a view for it and appending its element to the DOM. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
result + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addTileInfoWindows() +

+ + + + + + +
+ Get the details on each tile - a list of ids and titles for each dataset contained in that tile +And create an infowindow for that tile +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + closeInfoWindows(except) +

+ + + + + + +
+ Iterate over each infowindow that we have stored in the view and close it. +Pass an infoWindow object to this function to keep that infoWindow open/skip it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ + +infoWindow + + + + An infoWindow to keep open
except + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + drawTile(options, geohash, label) +

+ + + + + + +
+ With the options and label object given, add a single tile to the map and set its event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object + + + +
geohash + + +string + + + +
label + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + drawTiles() +

+ + + + + + +
+ Create a tile for each geohash facet. A separate tile label is added to the map with the count of the facet. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + getResults(page) +

+ + + + + + +
+ getResults gets all the current search filters from the searchModel, creates a Solr query, and runs that query. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
page + + +number + + + + The page of search results to get results for
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + hideResultOnMap(e) +

+ + + + + + +
+ Hide the marker, infoWindow, and bounding coordinates polygon on + the map when the user stops hovering on the marker icon in the result list +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
e + + +Event + + + + The event that brought us to this function
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + removeMarkers() +

+ + + + + + +
+ Iterate over all the markers in the view and remove them from the map and view +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + removeTiles() +

+ + + + + + +
+ Remove all the tiles and text from the map +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showError(model, response) +

+ + + + + + +
+ When the SearchResults collection has an error getting the results, +show an error message instead of search results +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
model + + +SolrResult + + + +
response + + +XMLHttpRequest.response + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showResultOnMap(e) +

+ + + + + + +
+ Show the marker, infoWindow, and bounding coordinates polygon on + the map when the user hovers on the marker icon in the result list +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
e + + +Event + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/DataCatalogViewWithFilters.html b/docs/docs/DataCatalogViewWithFilters.html index 7209c99e5..a4cfeef64 100644 --- a/docs/docs/DataCatalogViewWithFilters.html +++ b/docs/docs/DataCatalogViewWithFilters.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -426,7 +426,7 @@

- fixedHeight :Boolean + fixedHeight :boolean

@@ -443,7 +443,7 @@
Type:
- - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - bytesToSize() -

- - - - - - -
- Converts the number of bytes into a human readable format and -updates the `sizeStr` attribute -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
@@ -500,7 +405,7 @@
Parameters:
Source:
@@ -601,8 +506,6 @@
Parameters:
- Default - Description @@ -638,12 +541,6 @@
Parameters:
- - - changePermission - - - The action (read, write, or changePermission) to check if the current user has authorization to perform. By default checks for the highest level of permission. @@ -678,10 +575,6 @@
Parameters:
- - - - Additional options for this function. See the properties below. @@ -799,7 +692,7 @@
Properties:
Source:
@@ -974,7 +867,7 @@
Parameters:
Source:
@@ -1092,7 +985,7 @@

Source:
@@ -1186,7 +1079,7 @@

Source:
@@ -1299,7 +1192,7 @@

Source:
@@ -1350,7 +1243,7 @@

- fetch() + fetch(options)

@@ -1370,6 +1263,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + +
+ + @@ -1403,7 +1340,7 @@

Source:
@@ -1592,7 +1529,7 @@

Parameters:
Source:
@@ -1738,7 +1675,7 @@
Parameters:
Source:
@@ -1854,7 +1791,7 @@

Source:
@@ -1974,7 +1911,7 @@

Source:
@@ -2097,7 +2034,7 @@

Source:
@@ -2201,7 +2138,7 @@

Source:
@@ -2298,7 +2235,7 @@

Source:
@@ -2402,7 +2339,7 @@

Source:
@@ -2557,7 +2494,7 @@

Parameters:
Source:
@@ -2818,7 +2755,7 @@
Properties:
Source:
@@ -2912,7 +2849,7 @@

Source:
@@ -3073,7 +3010,7 @@

Parameters:
Source:
@@ -3192,7 +3129,7 @@

Source:
@@ -3357,7 +3294,7 @@

Parameters:
Source:
@@ -3469,7 +3406,7 @@

Source:
@@ -3586,7 +3523,7 @@

Source:
@@ -3698,7 +3635,7 @@

Source:
@@ -3817,7 +3754,7 @@

Source:
@@ -3982,7 +3919,7 @@

Parameters:
Source:
@@ -4096,7 +4033,7 @@

Source:
@@ -4319,7 +4256,7 @@

Parameters:
Source:
@@ -4360,7 +4297,7 @@

- parse() + parse(response)

@@ -4381,6 +4318,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
response + +
+ + @@ -4414,7 +4395,7 @@

Source:
@@ -4560,7 +4541,7 @@

Parameters:
Source:
@@ -4654,7 +4635,7 @@

Source:
@@ -4695,7 +4676,7 @@

- save() + save(attributes, options)

@@ -4715,6 +4696,68 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + +
options + +
+ + @@ -4748,7 +4791,7 @@

Source:
@@ -4842,7 +4885,7 @@

Source:
@@ -4954,7 +4997,7 @@

Source:
@@ -5049,7 +5092,7 @@

Source:
@@ -5197,7 +5240,7 @@

Parameters:
Source:
@@ -5238,7 +5281,7 @@

- toJson() + toJson(xml)

@@ -5258,6 +5301,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xml + +
+ + @@ -5291,7 +5378,7 @@

Source:
@@ -5457,7 +5544,7 @@

Parameters:
Source:
@@ -5632,7 +5719,7 @@
Parameters:
Source:
@@ -5775,7 +5862,7 @@
Parameters:
Source:
@@ -5869,7 +5956,7 @@

Source:
@@ -5963,7 +6050,7 @@

Source:
@@ -6057,7 +6144,7 @@

Source:
diff --git a/docs/docs/DataPackage.html b/docs/docs/DataPackage.html index 86c75cab9..962716a8f 100644 --- a/docs/docs/DataPackage.html +++ b/docs/docs/DataPackage.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -248,7 +248,7 @@
Type:
Source:
@@ -326,7 +326,7 @@
Type:
Source:
@@ -405,7 +405,7 @@
Type:
Source:
@@ -484,7 +484,7 @@
Type:
Source:
@@ -640,7 +640,7 @@
Type:
Source:
@@ -718,7 +718,7 @@
Type:
Source:
@@ -787,7 +787,7 @@

Source:
@@ -868,7 +868,7 @@

Type:
Source:
@@ -948,7 +948,7 @@
Type:
Source:
@@ -1026,7 +1026,7 @@
Type:
Source:
@@ -1095,7 +1095,7 @@

Source:
@@ -1175,7 +1175,7 @@

Type:
Source:
@@ -1482,7 +1482,7 @@
Parameters:
Source:
@@ -1576,7 +1576,7 @@
Parameters:
-Object +object @@ -1715,7 +1715,7 @@
Properties:
Source:
@@ -1810,7 +1810,7 @@

Source:
@@ -1956,7 +1956,7 @@

Parameters:
Source:
@@ -2077,7 +2077,7 @@

Source:
@@ -2349,7 +2349,7 @@

Parameters:
Source:
@@ -2559,7 +2559,7 @@
Parameters:
Source:
@@ -2653,7 +2653,7 @@

Source:
@@ -2757,7 +2757,7 @@

Source:
@@ -2851,7 +2851,7 @@

Parameters:
-Object +object @@ -2905,7 +2905,7 @@
Properties
-Boolean +boolean @@ -2938,7 +2938,7 @@
Properties
-Boolean +boolean @@ -3006,7 +3006,7 @@
Properties
Source:
@@ -3166,7 +3166,7 @@
Parameters:
Source:
@@ -3260,7 +3260,7 @@

Source:
diff --git a/docs/docs/DataPackageView.html b/docs/docs/DataPackageView.html index 56844b87a..4e786dcb1 100644 --- a/docs/docs/DataPackageView.html +++ b/docs/docs/DataPackageView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -131,7 +131,7 @@

Source:
@@ -255,7 +255,7 @@

Type:
Source:
@@ -341,7 +341,7 @@

Source:
@@ -382,7 +382,7 @@

- addFilesAndFolders() + addFilesAndFolders(sortedFilePathObj)

@@ -402,6 +402,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sortedFilePathObj + +
+ + @@ -435,7 +479,7 @@

Source:
@@ -527,7 +571,7 @@

Parameters:
-Object +object @@ -581,7 +625,7 @@
Parameters:
Source:
@@ -622,7 +666,7 @@

- addOne() + addOne(item, dataPackage)

@@ -642,6 +686,68 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
item + +
dataPackage + +
+ + @@ -675,7 +781,7 @@

Source:
@@ -772,7 +878,7 @@

Source:
@@ -918,7 +1024,7 @@

Parameters:
Source:
@@ -1064,7 +1170,7 @@
Parameters:
Source:
@@ -1210,7 +1316,7 @@
Parameters:
Source:
@@ -1356,7 +1462,7 @@
Parameters:
Source:
@@ -1453,7 +1559,7 @@

Source:
@@ -1547,7 +1653,7 @@

Source:
@@ -1685,7 +1791,7 @@

Parameters:
Source:
@@ -1779,7 +1885,7 @@

Source:
@@ -1873,7 +1979,7 @@

Source:
@@ -1970,7 +2076,7 @@

Source:
@@ -2011,7 +2117,7 @@

- toggleRows() + toggleRows(event)

@@ -2031,6 +2137,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + +
+ + @@ -2064,7 +2214,7 @@

Source:
diff --git a/docs/docs/DateFilter.html b/docs/docs/DateFilter.html index 8cdf1b675..f65fa15a6 100644 --- a/docs/docs/DateFilter.html +++ b/docs/docs/DateFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/DateFilterView.html b/docs/docs/DateFilterView.html index b548e60df..d5ca55f3f 100644 --- a/docs/docs/DateFilterView.html +++ b/docs/docs/DateFilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1490,7 +1490,7 @@
Parameters:
Source:
@@ -1663,7 +1663,7 @@
Parameters:
Source:
@@ -2263,7 +2263,7 @@
Parameters:
Source:
@@ -2412,7 +2412,7 @@
Parameters:
Source:
@@ -2578,7 +2578,7 @@
Parameters:
Source:
@@ -2904,7 +2904,7 @@
Parameters:
Source:
diff --git a/docs/docs/DraftsView.html b/docs/docs/DraftsView.html index 48001a5bd..40d28a0dd 100644 --- a/docs/docs/DraftsView.html +++ b/docs/docs/DraftsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/DrawTool.html b/docs/docs/DrawTool.html index 02494475d..c379f833f 100644 --- a/docs/docs/DrawTool.html +++ b/docs/docs/DrawTool.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EML211.html b/docs/docs/EML211.html index 8e73769ea..6df61a3a7 100644 --- a/docs/docs/EML211.html +++ b/docs/docs/EML211.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -491,107 +491,7 @@

Source:
- - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - bytesToSize() -

- - - - - - -
- Converts the number of bytes into a human readable format and -updates the `sizeStr` attribute -
- - - - - - - - - - - - - -
- - - - - - -
Inherited From:
-
- - - - - - - - - - - - - - - - - - - - - -
Source:
-
@@ -751,7 +651,7 @@
Parameters:
Source:
@@ -852,8 +752,6 @@
Parameters:
- Default - Description @@ -889,12 +787,6 @@
Parameters:
- - - changePermission - - - The action (read, write, or changePermission) to check if the current user has authorization to perform. By default checks for the highest level of permission. @@ -929,10 +821,6 @@
Parameters:
- - - - Additional options for this function. See the properties below. @@ -1055,7 +943,7 @@
Properties:
Source:
@@ -1235,7 +1123,7 @@
Parameters:
Source:
@@ -1358,7 +1246,7 @@

Source:
@@ -1457,7 +1345,7 @@

Source:
@@ -1575,7 +1463,7 @@

Source:
@@ -2010,7 +1898,7 @@

Parameters:
Source:
@@ -2161,7 +2049,7 @@
Parameters:
Source:
@@ -2282,7 +2170,7 @@

Source:
@@ -2407,7 +2295,7 @@

Source:
@@ -2652,7 +2540,7 @@

Source:
@@ -2761,7 +2649,7 @@

Source:
@@ -2863,7 +2751,7 @@

Source:
@@ -3118,7 +3006,7 @@

Source:
@@ -3278,7 +3166,7 @@

Parameters:
Source:
@@ -3544,7 +3432,7 @@
Properties:
Source:
@@ -3643,7 +3531,7 @@

Source:
@@ -3809,7 +3697,7 @@

Parameters:
Source:
@@ -3933,7 +3821,7 @@

Source:
@@ -4103,7 +3991,7 @@

Parameters:
Source:
@@ -4220,7 +4108,7 @@

Source:
@@ -4342,7 +4230,7 @@

Source:
@@ -4459,7 +4347,7 @@

Source:
@@ -4583,7 +4471,7 @@

Source:
@@ -4753,7 +4641,7 @@

Parameters:
Source:
@@ -5158,7 +5046,7 @@

Source:
@@ -5386,7 +5274,7 @@

Parameters:
Source:
@@ -5427,7 +5315,7 @@

- parse() + parse(response)

@@ -5448,6 +5336,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
response + +
+ + @@ -5486,7 +5418,7 @@

Source:
@@ -5637,7 +5569,7 @@

Parameters:
Source:
@@ -5736,7 +5668,7 @@

Source:
@@ -5777,7 +5709,7 @@

- save() + save(attributes, options)

@@ -5797,6 +5729,68 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + +
options + +
+ + @@ -5835,7 +5829,7 @@

Source:
@@ -5934,7 +5928,7 @@

Source:
@@ -6051,7 +6045,7 @@

Source:
@@ -6151,7 +6145,7 @@

Source:
@@ -6304,7 +6298,7 @@

Parameters:
Source:
@@ -6511,7 +6505,7 @@

- toJson() + toJson(xml)

@@ -6531,6 +6525,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xml + +
+ + @@ -6569,7 +6607,7 @@

Source:
@@ -6740,7 +6778,7 @@

Parameters:
Source:
@@ -6920,7 +6958,7 @@
Parameters:
Source:
@@ -7068,7 +7106,7 @@
Parameters:
Source:
@@ -7167,7 +7205,7 @@

Source:
@@ -7266,7 +7304,7 @@

Source:
@@ -7365,7 +7403,7 @@

Source:
diff --git a/docs/docs/EML211EditorView.html b/docs/docs/EML211EditorView.html index fc6b5927c..b7948f992 100644 --- a/docs/docs/EML211EditorView.html +++ b/docs/docs/EML211EditorView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLAnnotation.html b/docs/docs/EMLAnnotation.html index d055828ad..948cca8db 100644 --- a/docs/docs/EMLAnnotation.html +++ b/docs/docs/EMLAnnotation.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLAnnotations.html b/docs/docs/EMLAnnotations.html index f2ca64fed..8fa527aab 100644 --- a/docs/docs/EMLAnnotations.html +++ b/docs/docs/EMLAnnotations.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLAttribute.html b/docs/docs/EMLAttribute.html index 7a5ae8c23..399e2f443 100644 --- a/docs/docs/EMLAttribute.html +++ b/docs/docs/EMLAttribute.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLAttributeView.html b/docs/docs/EMLAttributeView.html index f467b64db..0cb8836d2 100644 --- a/docs/docs/EMLAttributeView.html +++ b/docs/docs/EMLAttributeView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLDataTable.html b/docs/docs/EMLDataTable.html index 253bbdd7e..3e4b13141 100644 --- a/docs/docs/EMLDataTable.html +++ b/docs/docs/EMLDataTable.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLDistribution.html b/docs/docs/EMLDistribution.html index a13e4fd6b..d91217bca 100644 --- a/docs/docs/EMLDistribution.html +++ b/docs/docs/EMLDistribution.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLEntity.html b/docs/docs/EMLEntity.html index a5cfaa587..d565ec84a 100644 --- a/docs/docs/EMLEntity.html +++ b/docs/docs/EMLEntity.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLEntityView.html b/docs/docs/EMLEntityView.html index 0ae30afbe..591ab3fe8 100644 --- a/docs/docs/EMLEntityView.html +++ b/docs/docs/EMLEntityView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLGeoCoverage.html b/docs/docs/EMLGeoCoverage.html index bfaca2ce7..43a708e8a 100644 --- a/docs/docs/EMLGeoCoverage.html +++ b/docs/docs/EMLGeoCoverage.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMeasurementScale.html b/docs/docs/EMLMeasurementScale.html index faa473fd7..57995b856 100644 --- a/docs/docs/EMLMeasurementScale.html +++ b/docs/docs/EMLMeasurementScale.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMeasurementScaleView.html b/docs/docs/EMLMeasurementScaleView.html index 184897177..16cd71d8a 100644 --- a/docs/docs/EMLMeasurementScaleView.html +++ b/docs/docs/EMLMeasurementScaleView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMeasurementTypeView.html b/docs/docs/EMLMeasurementTypeView.html index f18d65c99..2d14a565e 100644 --- a/docs/docs/EMLMeasurementTypeView.html +++ b/docs/docs/EMLMeasurementTypeView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMethodStep.html b/docs/docs/EMLMethodStep.html index 5f53d423d..d48f6f105 100644 --- a/docs/docs/EMLMethodStep.html +++ b/docs/docs/EMLMethodStep.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMethods.html b/docs/docs/EMLMethods.html index 7b98d344e..ac6df0500 100644 --- a/docs/docs/EMLMethods.html +++ b/docs/docs/EMLMethods.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMethodsView.html b/docs/docs/EMLMethodsView.html index 5f49a1d96..599eca041 100644 --- a/docs/docs/EMLMethodsView.html +++ b/docs/docs/EMLMethodsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMissingValueCode.html b/docs/docs/EMLMissingValueCode.html index 910273d09..e964aa632 100644 --- a/docs/docs/EMLMissingValueCode.html +++ b/docs/docs/EMLMissingValueCode.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMissingValueCodeView.html b/docs/docs/EMLMissingValueCodeView.html index 9e6d58608..00ce74471 100644 --- a/docs/docs/EMLMissingValueCodeView.html +++ b/docs/docs/EMLMissingValueCodeView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMissingValueCodes.html b/docs/docs/EMLMissingValueCodes.html index 980a61097..efd33b02b 100644 --- a/docs/docs/EMLMissingValueCodes.html +++ b/docs/docs/EMLMissingValueCodes.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLMissingValueCodesView.html b/docs/docs/EMLMissingValueCodesView.html index 8ff47ee9d..ac3c27b7e 100644 --- a/docs/docs/EMLMissingValueCodesView.html +++ b/docs/docs/EMLMissingValueCodesView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLNonNumericDomain.html b/docs/docs/EMLNonNumericDomain.html index 38cdca871..db8b5f17f 100644 --- a/docs/docs/EMLNonNumericDomain.html +++ b/docs/docs/EMLNonNumericDomain.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLNumericDomain.html b/docs/docs/EMLNumericDomain.html index fb6e95c79..73b02caa3 100644 --- a/docs/docs/EMLNumericDomain.html +++ b/docs/docs/EMLNumericDomain.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLOtherEntity.html b/docs/docs/EMLOtherEntity.html index 2555158c0..f2dc24c6c 100644 --- a/docs/docs/EMLOtherEntity.html +++ b/docs/docs/EMLOtherEntity.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLOtherEntityView.html b/docs/docs/EMLOtherEntityView.html index 743677a2f..9ce738fe4 100644 --- a/docs/docs/EMLOtherEntityView.html +++ b/docs/docs/EMLOtherEntityView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLParty.html b/docs/docs/EMLParty.html index 71112e81e..73a6caf54 100644 --- a/docs/docs/EMLParty.html +++ b/docs/docs/EMLParty.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLPartyView.html b/docs/docs/EMLPartyView.html index 011f1cba4..30bb4462b 100644 --- a/docs/docs/EMLPartyView.html +++ b/docs/docs/EMLPartyView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLSpecializedText.html b/docs/docs/EMLSpecializedText.html index 2f84c949b..9659dfc84 100644 --- a/docs/docs/EMLSpecializedText.html +++ b/docs/docs/EMLSpecializedText.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLTaxonCoverage.html b/docs/docs/EMLTaxonCoverage.html index 8d9d07600..8371edb67 100644 --- a/docs/docs/EMLTaxonCoverage.html +++ b/docs/docs/EMLTaxonCoverage.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLTempCoverageView.html b/docs/docs/EMLTempCoverageView.html index 47cd0f94b..0857e4ce9 100644 --- a/docs/docs/EMLTempCoverageView.html +++ b/docs/docs/EMLTempCoverageView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLTemporalCoverage.html b/docs/docs/EMLTemporalCoverage.html index 600a32054..a4e62b6f4 100644 --- a/docs/docs/EMLTemporalCoverage.html +++ b/docs/docs/EMLTemporalCoverage.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLText.html b/docs/docs/EMLText.html index 5805b035c..1cd40d49b 100644 --- a/docs/docs/EMLText.html +++ b/docs/docs/EMLText.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLText211.html b/docs/docs/EMLText211.html index 707a0dfd0..437fbfb48 100644 --- a/docs/docs/EMLText211.html +++ b/docs/docs/EMLText211.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLUnit.html b/docs/docs/EMLUnit.html index daa9d788a..ff5057045 100644 --- a/docs/docs/EMLUnit.html +++ b/docs/docs/EMLUnit.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EMLView.html b/docs/docs/EMLView.html index 8c2d804a4..d4fa7b2e7 100644 --- a/docs/docs/EMLView.html +++ b/docs/docs/EMLView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -743,7 +743,7 @@
Parameters:
Source:
@@ -901,7 +901,7 @@
Parameters:
Source:
@@ -1011,7 +1011,7 @@

Source:
@@ -2217,7 +2217,7 @@

Parameters:
Source:
diff --git a/docs/docs/EMlGeoCoverageView_.html b/docs/docs/EMlGeoCoverageView_.html index 9f91d5aa3..5dc3b996b 100644 --- a/docs/docs/EMlGeoCoverageView_.html +++ b/docs/docs/EMlGeoCoverageView_.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EditCollectionView.html b/docs/docs/EditCollectionView.html index 5e629343c..cad25c5d4 100644 --- a/docs/docs/EditCollectionView.html +++ b/docs/docs/EditCollectionView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/EditorView.html b/docs/docs/EditorView.html index 9ef771b7d..ef8a49542 100644 --- a/docs/docs/EditorView.html +++ b/docs/docs/EditorView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ExpansionPanelView.html b/docs/docs/ExpansionPanelView.html index 0b7a77b2a..6d825948f 100644 --- a/docs/docs/ExpansionPanelView.html +++ b/docs/docs/ExpansionPanelView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ExpansionPanelsModel.html b/docs/docs/ExpansionPanelsModel.html index 6ba45628c..568c060a2 100644 --- a/docs/docs/ExpansionPanelsModel.html +++ b/docs/docs/ExpansionPanelsModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ExternalView.html b/docs/docs/ExternalView.html index 010d3bccf..509649dea 100644 --- a/docs/docs/ExternalView.html +++ b/docs/docs/ExternalView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Feature.html b/docs/docs/Feature.html index 01cb7d029..2ec772505 100644 --- a/docs/docs/Feature.html +++ b/docs/docs/Feature.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FeatureInfoView.html b/docs/docs/FeatureInfoView.html index 8a546d397..33c303178 100644 --- a/docs/docs/FeatureInfoView.html +++ b/docs/docs/FeatureInfoView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Features.html b/docs/docs/Features.html index 4cbc36033..934fec600 100644 --- a/docs/docs/Features.html +++ b/docs/docs/Features.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Filter.html b/docs/docs/Filter.html index 39e8ae6bb..5b314f4e5 100644 --- a/docs/docs/Filter.html +++ b/docs/docs/Filter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FilterEditorView.html b/docs/docs/FilterEditorView.html index 0240cfc4d..c105e804f 100644 --- a/docs/docs/FilterEditorView.html +++ b/docs/docs/FilterEditorView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1937,7 +1937,7 @@
Parameters:
Source:
@@ -2084,7 +2084,7 @@
Parameters:
Source:
@@ -2230,7 +2230,7 @@
Parameters:
Source:
@@ -2542,7 +2542,7 @@
Parameters:
Source:
@@ -2710,7 +2710,7 @@
Parameters:
Source:
@@ -2858,7 +2858,7 @@
Parameters:
Source:
@@ -3003,7 +3003,7 @@
Parameters:
Source:
@@ -3193,7 +3193,7 @@

Source:
@@ -3569,7 +3569,7 @@

Parameters:
Source:
@@ -4175,7 +4175,7 @@
Parameters:
Source:
@@ -4320,7 +4320,7 @@
Parameters:
Source:
diff --git a/docs/docs/FilterGroup.html b/docs/docs/FilterGroup.html index 04359130a..841aab1a8 100644 --- a/docs/docs/FilterGroup.html +++ b/docs/docs/FilterGroup.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FilterGroupView.html b/docs/docs/FilterGroupView.html index 619396507..dd2b0145c 100644 --- a/docs/docs/FilterGroupView.html +++ b/docs/docs/FilterGroupView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -120,7 +120,7 @@

Source:
@@ -250,7 +250,7 @@

Type:
Source:
@@ -332,7 +332,7 @@
Type:
Source:
@@ -410,7 +410,7 @@
Type:
Source:
@@ -488,7 +488,7 @@
Type:
Source:
@@ -626,7 +626,7 @@
Parameters:
Source:
@@ -746,7 +746,7 @@

Source:
diff --git a/docs/docs/FilterGroupsView.html b/docs/docs/FilterGroupsView.html index 2ecc88628..71f0cdb58 100644 --- a/docs/docs/FilterGroupsView.html +++ b/docs/docs/FilterGroupsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FilterView.html b/docs/docs/FilterView.html index 6ad0736b8..d29b9c8ca 100644 --- a/docs/docs/FilterView.html +++ b/docs/docs/FilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1324,7 +1324,7 @@
Parameters:
Source:
@@ -1463,7 +1463,7 @@
Parameters:
Source:
@@ -1631,7 +1631,7 @@
Parameters:
Source:
@@ -2122,7 +2122,7 @@
Parameters:
Source:
@@ -2266,7 +2266,7 @@
Parameters:
Source:
@@ -2427,7 +2427,7 @@
Parameters:
Source:
@@ -2522,7 +2522,7 @@

Source:
@@ -2669,7 +2669,7 @@

Parameters:
Source:
diff --git a/docs/docs/Filters.html b/docs/docs/Filters.html index 8c7e48455..0a0bee167 100644 --- a/docs/docs/Filters.html +++ b/docs/docs/Filters.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FiltersMapConnector.html b/docs/docs/FiltersMapConnector.html index 278f10e54..ba6cbb9a1 100644 --- a/docs/docs/FiltersMapConnector.html +++ b/docs/docs/FiltersMapConnector.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FiltersSearchConnector.html b/docs/docs/FiltersSearchConnector.html index df48ff525..25644dd36 100644 --- a/docs/docs/FiltersSearchConnector.html +++ b/docs/docs/FiltersSearchConnector.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/FooterView.html b/docs/docs/FooterView.html index 5ddcdde0c..75ad29740 100644 --- a/docs/docs/FooterView.html +++ b/docs/docs/FooterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoBoundingBox.html b/docs/docs/GeoBoundingBox.html index dcddec2b5..5819c8c22 100644 --- a/docs/docs/GeoBoundingBox.html +++ b/docs/docs/GeoBoundingBox.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoPoint.html b/docs/docs/GeoPoint.html index 55f0a516c..1db75630c 100644 --- a/docs/docs/GeoPoint.html +++ b/docs/docs/GeoPoint.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoPoints.html b/docs/docs/GeoPoints.html index 3e8d6acfa..0160e12f3 100644 --- a/docs/docs/GeoPoints.html +++ b/docs/docs/GeoPoints.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoPointsCesiumConnector.html b/docs/docs/GeoPointsCesiumConnector.html index a80926e15..ccc041548 100644 --- a/docs/docs/GeoPointsCesiumConnector.html +++ b/docs/docs/GeoPointsCesiumConnector.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoPointsCesiumPointsConnector.html b/docs/docs/GeoPointsCesiumPointsConnector.html index 05ab0d9eb..93d9eb360 100644 --- a/docs/docs/GeoPointsCesiumPointsConnector.html +++ b/docs/docs/GeoPointsCesiumPointsConnector.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoPointsCesiumPolygonConnector.html b/docs/docs/GeoPointsCesiumPolygonConnector.html index 28a873633..74248c130 100644 --- a/docs/docs/GeoPointsCesiumPolygonConnector.html +++ b/docs/docs/GeoPointsCesiumPolygonConnector.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoScale.html b/docs/docs/GeoScale.html index 53a997897..d1db151d7 100644 --- a/docs/docs/GeoScale.html +++ b/docs/docs/GeoScale.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeoUtilities.html b/docs/docs/GeoUtilities.html index f21a8891c..86bb4fc9e 100644 --- a/docs/docs/GeoUtilities.html +++ b/docs/docs/GeoUtilities.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeocodedLocation.html b/docs/docs/GeocodedLocation.html index d56ba5893..5bff92e8b 100644 --- a/docs/docs/GeocodedLocation.html +++ b/docs/docs/GeocodedLocation.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GeocoderSearch.html b/docs/docs/GeocoderSearch.html index 726045462..6d58f8877 100644 --- a/docs/docs/GeocoderSearch.html +++ b/docs/docs/GeocoderSearch.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Geohash.html b/docs/docs/Geohash.html index 158e54aa7..10a749796 100644 --- a/docs/docs/Geohash.html +++ b/docs/docs/Geohash.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Geohashes.html b/docs/docs/Geohashes.html index 63dbd14fd..eb3c3cb92 100644 --- a/docs/docs/Geohashes.html +++ b/docs/docs/Geohashes.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GoogleAnalytics.html b/docs/docs/GoogleAnalytics.html index db7b0f45f..ccfbb6e3d 100644 --- a/docs/docs/GoogleAnalytics.html +++ b/docs/docs/GoogleAnalytics.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GoogleMapsAutocompleter.html b/docs/docs/GoogleMapsAutocompleter.html index 604080957..f535b7dc2 100644 --- a/docs/docs/GoogleMapsAutocompleter.html +++ b/docs/docs/GoogleMapsAutocompleter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GoogleMapsGeocoder.html b/docs/docs/GoogleMapsGeocoder.html index c2a7075d4..330a44c8c 100644 --- a/docs/docs/GoogleMapsGeocoder.html +++ b/docs/docs/GoogleMapsGeocoder.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/GroupListView.html b/docs/docs/GroupListView.html index 3d830fd9c..83caa83e9 100644 --- a/docs/docs/GroupListView.html +++ b/docs/docs/GroupListView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/IconUtilities.html b/docs/docs/IconUtilities.html index 800381a6e..6e519c0de 100644 --- a/docs/docs/IconUtilities.html +++ b/docs/docs/IconUtilities.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ImageUploaderView.html b/docs/docs/ImageUploaderView.html index a15bdb8dc..d399256d6 100644 --- a/docs/docs/ImageUploaderView.html +++ b/docs/docs/ImageUploaderView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/LayerCategoryListView.html b/docs/docs/LayerCategoryListView.html index 50305d168..009d6e634 100644 --- a/docs/docs/LayerCategoryListView.html +++ b/docs/docs/LayerCategoryListView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/LayerDetailView.html b/docs/docs/LayerDetailView.html index 7a728b82c..925afeb17 100644 --- a/docs/docs/LayerDetailView.html +++ b/docs/docs/LayerDetailView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/LayerDetailsView.html b/docs/docs/LayerDetailsView.html index e926e062e..f0e341bf0 100644 --- a/docs/docs/LayerDetailsView.html +++ b/docs/docs/LayerDetailsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -279,7 +279,7 @@

- classes :Object + classes :object

@@ -295,7 +295,7 @@
Type:
+ + + + + + + + +

+ + + + + loadingTemplate :function +

+ + + + +
+ The template to use to indicate that the view is loading +
+ + + +
Type:
+
    +
  • + +function + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + pid :string +

+ + + + +
+ The identifier of the object to be assessed +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + suiteId :string +

+ + + + +
+ The currently selected/requested suite +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + suiteIdList :Array.<string> +

+ + + + +
+ The list of all potential suites for this theme +
+ + + +
Type:
+
    +
  • + +Array.<string> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + template :function +

+ + + + +
+ The main template for this view +
+ + + +
Type:
+
    +
  • + +function + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + addCheckItems(groupedResults) +

+ + + + + + +
+ Add the check result item els to the view +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
groupedResults + + +object + + + + The results grouped by status
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + createCheckItem(result, className, iconClass) → {string} +

+ + + + + + +
+ Create a check item element +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
result + + +object + + + + The check result
className + + +string + + + + The class name for the check item
iconClass + + +string + + + + The class
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The HTML for the check item +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + drawScoreChart(results, groupedResults) +

+ + + + + + +
+ Draw a donut chart showing the distribution of checks by status +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
results + + +Array + + + + The array of check results
groupedResults + + +object + + + + The results grouped by status
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + getHTMLFromMarkdown(markdown) → {Promise} +

+ + + + + + +
+ Get the HTML from markdown +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
markdown + + +string + + + + The markdown to convert to HTML
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves with the HTML +
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + + + + +

+ + + + + getOutputHTML(outputs) → {string} +

+ + + + + + +
+ Get the HTML for the output +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
outputs + + +Array + + + + The outputs from the quality service
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The HTML for the output +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + handleQualityReportError() +

+ + + + + + +
+ Handles errors that occur when fetching the quality report +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + hideLoading() +

+ + + + + + +
+ Remove the loading image and message. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + insertBreadcrumbs() +

+ + + + + + +
+ Insert breadcrumbs into the view +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + - - - - @@ -263,32 +2093,34 @@
Type:
-

- - - - suiteId :string -

+ + +

+ + + + + renderQualityReport() +

+ + +
- The currently selected/requested suite + Render the quality report once it has been fetched
-
Type:
-
    -
  • - -string -
  • -
+ + + @@ -323,7 +2155,7 @@
Type:
Source:
@@ -338,35 +2170,51 @@
Type:
+ + + + + + + + + + + + + + -

- - - - suiteIdList :Array.<string> -

+ + + +

+ + + + + show() +

+ +
- The list of all potential suites for this theme + Show the view
-
Type:
-
    -
  • - -Array.<string> -
  • -
+ + + @@ -401,7 +2249,7 @@
Type:
Source:
@@ -417,11 +2265,19 @@
Type:
- - - -

Methods

+ + + + + + + + + + + + @@ -429,12 +2285,12 @@

Methods

-

- +

+ - hideLoading() + showCitation()

@@ -443,7 +2299,7 @@

- Remove the loading image and message. + Render a citation view for the object and display it in the view
@@ -487,7 +2343,7 @@

Source:
@@ -581,7 +2437,7 @@

Source:
@@ -659,8 +2515,6 @@

Parameters:
- Default - Description @@ -694,10 +2548,6 @@
Parameters:
- - - - The new message to display @@ -731,12 +2581,6 @@
Parameters:
- - - true - - - If set to true, and an email contact is configured in MetacatUI, then the contact email will be shown at the bottom of the message. @@ -771,12 +2615,6 @@
Parameters:
- - - true - - - If set to true, a link back to the dataset will be appended to the end of the message. @@ -823,7 +2661,150 @@
Parameters:
Source:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + switchSuite(event) → {boolean} +

+ + + + + + +
+ Handles the event when the user selects a different suite +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + The event object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -848,6 +2829,28 @@
Parameters:
+
Returns:
+ + +
+ False, to prevent the default action +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + diff --git a/docs/docs/MetacatUI.html b/docs/docs/MetacatUI.html index 8799e1d2a..16aaf4120 100644 --- a/docs/docs/MetacatUI.html +++ b/docs/docs/MetacatUI.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -671,7 +671,7 @@
Type:
Source:
diff --git a/docs/docs/MetadataView.html b/docs/docs/MetadataView.html index 017ffac04..9febc35b0 100644 --- a/docs/docs/MetadataView.html +++ b/docs/docs/MetadataView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -344,7 +344,7 @@

Source:
@@ -440,7 +440,7 @@

Source:
@@ -534,7 +534,7 @@

Source:
@@ -726,7 +726,7 @@

Parameters:
Source:
@@ -922,7 +922,7 @@
Parameters:
Source:
@@ -1147,7 +1147,7 @@
Parameters:
Source:
@@ -1372,7 +1372,7 @@
Parameters:
Source:
@@ -1470,7 +1470,7 @@

Source:
@@ -1511,7 +1511,7 @@

- generateSchemaOrgGeo() + generateSchemaOrgGeo(north, east, south, west)

@@ -1534,6 +1534,104 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
north + +
east + +
south + +
west + +
+ + @@ -1567,7 +1665,7 @@

Source:
@@ -1713,7 +1811,7 @@

Parameters:
Source:
@@ -1809,7 +1907,7 @@

Source:
@@ -1925,7 +2023,7 @@

Parameters:
-Object +object @@ -2051,7 +2149,7 @@
Properties
Source:
@@ -2114,7 +2212,7 @@

- getCanonicalDOIIRI(identifier:) → {string|null} + getCanonicalDOIIRI(identifier:, identifier) → {string|null}

@@ -2180,6 +2278,24 @@
Parameters:
+ + + + identifier + + + + + + + + + + + + + + @@ -2217,7 +2333,7 @@
Parameters:
Source:
@@ -2488,7 +2604,7 @@

Source:
@@ -2659,7 +2775,7 @@

Parameters:
Source:
@@ -2777,7 +2893,7 @@

Source:
@@ -2874,7 +2990,7 @@

Source:
@@ -3024,7 +3140,7 @@

Parameters:
Source:
@@ -3196,7 +3312,7 @@
Parameters:
Source:
@@ -3237,7 +3353,7 @@

- previewData() + previewData(e)

@@ -3259,6 +3375,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
e + +
+ + @@ -3292,7 +3452,7 @@

Source:
@@ -3391,7 +3551,7 @@

Source:
@@ -3512,7 +3672,7 @@

Source:
diff --git a/docs/docs/MetricModalView.html b/docs/docs/MetricModalView.html index ffcdb9d6e..354f668e1 100644 --- a/docs/docs/MetricModalView.html +++ b/docs/docs/MetricModalView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/MetricView.html b/docs/docs/MetricView.html index 3e351a8b0..a52d036a7 100644 --- a/docs/docs/MetricView.html +++ b/docs/docs/MetricView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Metrics.html b/docs/docs/Metrics.html index d60d98200..adc36188e 100644 --- a/docs/docs/Metrics.html +++ b/docs/docs/Metrics.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/MetricsChartView.html b/docs/docs/MetricsChartView.html index 357a44719..42e711e23 100644 --- a/docs/docs/MetricsChartView.html +++ b/docs/docs/MetricsChartView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/NavbarView.html b/docs/docs/NavbarView.html index faf481cb3..c0fc545c4 100644 --- a/docs/docs/NavbarView.html +++ b/docs/docs/NavbarView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/NodeSelect.html b/docs/docs/NodeSelect.html index 0e7957680..d2575c088 100644 --- a/docs/docs/NodeSelect.html +++ b/docs/docs/NodeSelect.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -134,7 +134,7 @@

Source:
@@ -174,7 +174,7 @@

Extends

diff --git a/docs/docs/NumericFilter.html b/docs/docs/NumericFilter.html index e0cbab3e4..4e15765ed 100644 --- a/docs/docs/NumericFilter.html +++ b/docs/docs/NumericFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/NumericFilterView.html b/docs/docs/NumericFilterView.html index 9f3f545e6..416d513c6 100644 --- a/docs/docs/NumericFilterView.html +++ b/docs/docs/NumericFilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1468,7 +1468,7 @@
Parameters:
Source:
@@ -1612,7 +1612,7 @@
Parameters:
Source:
@@ -1785,7 +1785,7 @@
Parameters:
Source:
@@ -2385,7 +2385,7 @@
Parameters:
Source:
@@ -2534,7 +2534,7 @@
Parameters:
Source:
@@ -2700,7 +2700,7 @@
Parameters:
Source:
@@ -3098,7 +3098,7 @@
Parameters:
Source:
diff --git a/docs/docs/ObjectFormat.html b/docs/docs/ObjectFormat.html index c083b3332..4df54b6ae 100644 --- a/docs/docs/ObjectFormat.html +++ b/docs/docs/ObjectFormat.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ObjectFormatSelect.html b/docs/docs/ObjectFormatSelect.html index 6c47039fb..e0b0686c6 100644 --- a/docs/docs/ObjectFormatSelect.html +++ b/docs/docs/ObjectFormatSelect.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -134,7 +134,7 @@

Source:
@@ -174,7 +174,7 @@

Extends

diff --git a/docs/docs/ObjectFormats.html b/docs/docs/ObjectFormats.html index d557684f1..2faab4164 100644 --- a/docs/docs/ObjectFormats.html +++ b/docs/docs/ObjectFormats.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorDataView.html b/docs/docs/PortEditorDataView.html index 7c96e480f..efac36b6d 100644 --- a/docs/docs/PortEditorDataView.html +++ b/docs/docs/PortEditorDataView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorImageView.html b/docs/docs/PortEditorImageView.html index b9732df48..c2408d36c 100644 --- a/docs/docs/PortEditorImageView.html +++ b/docs/docs/PortEditorImageView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorLogosView.html b/docs/docs/PortEditorLogosView.html index 27b368fae..9f14c951c 100644 --- a/docs/docs/PortEditorLogosView.html +++ b/docs/docs/PortEditorLogosView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorMdSectionView.html b/docs/docs/PortEditorMdSectionView.html index e57554f48..dde1f1981 100644 --- a/docs/docs/PortEditorMdSectionView.html +++ b/docs/docs/PortEditorMdSectionView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorSectionView.html b/docs/docs/PortEditorSectionView.html index 91ad92f60..2785c7d5e 100644 --- a/docs/docs/PortEditorSectionView.html +++ b/docs/docs/PortEditorSectionView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorSectionsView.html b/docs/docs/PortEditorSectionsView.html index 0236788f4..cb8d81da5 100644 --- a/docs/docs/PortEditorSectionsView.html +++ b/docs/docs/PortEditorSectionsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortEditorSettingsView.html b/docs/docs/PortEditorSettingsView.html index d399bce1f..6b7c20bc9 100644 --- a/docs/docs/PortEditorSettingsView.html +++ b/docs/docs/PortEditorSettingsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalDataView.html b/docs/docs/PortalDataView.html index c5af870d2..da6c368a1 100644 --- a/docs/docs/PortalDataView.html +++ b/docs/docs/PortalDataView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalEditorView.html b/docs/docs/PortalEditorView.html index 35bcd9a0c..53e5ed57d 100644 --- a/docs/docs/PortalEditorView.html +++ b/docs/docs/PortalEditorView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalHeaderView.html b/docs/docs/PortalHeaderView.html index 510915dc0..64992176b 100644 --- a/docs/docs/PortalHeaderView.html +++ b/docs/docs/PortalHeaderView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalImage.html b/docs/docs/PortalImage.html index e98410fec..bb1f4383e 100644 --- a/docs/docs/PortalImage.html +++ b/docs/docs/PortalImage.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalListView.html b/docs/docs/PortalListView.html index e63ace53c..d73533f49 100644 --- a/docs/docs/PortalListView.html +++ b/docs/docs/PortalListView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalLogosView.html b/docs/docs/PortalLogosView.html index 6c316cf8a..70c587134 100644 --- a/docs/docs/PortalLogosView.html +++ b/docs/docs/PortalLogosView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalMembersView.html b/docs/docs/PortalMembersView.html index 496f47c84..81c0ff6ef 100644 --- a/docs/docs/PortalMembersView.html +++ b/docs/docs/PortalMembersView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalModel.html b/docs/docs/PortalModel.html index e095f5ea6..6dd91962b 100644 --- a/docs/docs/PortalModel.html +++ b/docs/docs/PortalModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -752,107 +752,7 @@

Source:
- - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - bytesToSize() -

- - - - - - -
- Converts the number of bytes into a human readable format and -updates the `sizeStr` attribute -
- - - - - - - - - - - - - -
- - - - - - -
Inherited From:
-
- - - - - - - - - - - - - - - - - - - - - -
Source:
-
@@ -1255,7 +1155,7 @@
Parameters:
Source:
@@ -1356,8 +1256,6 @@
Parameters:
- Default - Description @@ -1393,12 +1291,6 @@
Parameters:
- - - changePermission - - - The action (read, write, or changePermission) to check if the current user has authorization to perform. By default checks for the highest level of permission. @@ -1433,10 +1325,6 @@
Parameters:
- - - - Additional options for this function. See the properties below. @@ -1559,7 +1447,7 @@
Properties:
Source:
@@ -2193,7 +2081,7 @@
Parameters:
Source:
@@ -2579,7 +2467,7 @@

Source:
@@ -3013,7 +2901,7 @@

Source:
@@ -3593,7 +3481,7 @@

Parameters:
Source:
@@ -3744,7 +3632,7 @@
Parameters:
Source:
@@ -3865,7 +3753,7 @@

Source:
@@ -3990,7 +3878,7 @@

Source:
@@ -4118,7 +4006,7 @@

Source:
@@ -4227,7 +4115,7 @@

Source:
@@ -4329,7 +4217,7 @@

Source:
@@ -4857,7 +4745,7 @@

Source:
@@ -5212,7 +5100,7 @@

Parameters:
Source:
@@ -5478,7 +5366,7 @@
Properties:
Source:
@@ -5577,7 +5465,7 @@

Source:
@@ -6052,7 +5940,7 @@

Parameters:
Source:
@@ -6176,7 +6064,7 @@

Source:
@@ -6346,7 +6234,7 @@

Parameters:
Source:
@@ -6463,7 +6351,7 @@

Source:
@@ -6585,7 +6473,7 @@

Source:
@@ -6702,7 +6590,7 @@

Source:
@@ -6826,7 +6714,7 @@

Source:
@@ -6996,7 +6884,7 @@

Parameters:
Source:
@@ -7115,7 +7003,7 @@

Source:
@@ -7343,7 +7231,7 @@

Parameters:
Source:
@@ -8728,7 +8616,7 @@
Parameters:
Source:
@@ -8926,7 +8814,7 @@

Source:
@@ -9555,7 +9443,7 @@

Source:
@@ -9772,7 +9660,7 @@

Source:
@@ -9925,7 +9813,7 @@

Parameters:
Source:
@@ -10068,7 +9956,7 @@

- toJson() + toJson(xml)

@@ -10088,6 +9976,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xml + +
+ + @@ -10126,7 +10058,7 @@

Source:
@@ -10297,7 +10229,7 @@

Parameters:
Source:
@@ -10647,7 +10579,7 @@
Parameters:
Source:
@@ -10889,7 +10821,7 @@
Parameters:
Source:
@@ -10988,7 +10920,7 @@

Source:
@@ -11267,7 +11199,7 @@

Source:
diff --git a/docs/docs/PortalSectionModel.html b/docs/docs/PortalSectionModel.html index 517eea1a5..7bdd9861f 100644 --- a/docs/docs/PortalSectionModel.html +++ b/docs/docs/PortalSectionModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalSectionView.html b/docs/docs/PortalSectionView.html index aeb268d5b..75c7351f7 100644 --- a/docs/docs/PortalSectionView.html +++ b/docs/docs/PortalSectionView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalUsagesView.html b/docs/docs/PortalUsagesView.html index d505e35ac..ed2c0957b 100644 --- a/docs/docs/PortalUsagesView.html +++ b/docs/docs/PortalUsagesView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalView.html b/docs/docs/PortalView.html index fcbcde875..5fa0a0779 100644 --- a/docs/docs/PortalView.html +++ b/docs/docs/PortalView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalVisualizationsView.html b/docs/docs/PortalVisualizationsView.html index 0e3960339..b3f7cde18 100644 --- a/docs/docs/PortalVisualizationsView.html +++ b/docs/docs/PortalVisualizationsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PortalsSearchView.html b/docs/docs/PortalsSearchView.html index 01be6cf14..4889fc0f3 100644 --- a/docs/docs/PortalsSearchView.html +++ b/docs/docs/PortalsSearchView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Prediction.html b/docs/docs/Prediction.html index f0cfa72d6..6bb9491f7 100644 --- a/docs/docs/Prediction.html +++ b/docs/docs/Prediction.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PredictionView.html b/docs/docs/PredictionView.html index c49f16606..ad937425c 100644 --- a/docs/docs/PredictionView.html +++ b/docs/docs/PredictionView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/PredictionsListView.html b/docs/docs/PredictionsListView.html index 300c278ea..d174909b8 100644 --- a/docs/docs/PredictionsListView.html +++ b/docs/docs/PredictionsListView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Project.html b/docs/docs/Project.html index d734f92e9..6dcdd0d2a 100644 --- a/docs/docs/Project.html +++ b/docs/docs/Project.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ProjectList.html b/docs/docs/ProjectList.html index 56b03a821..789189e20 100644 --- a/docs/docs/ProjectList.html +++ b/docs/docs/ProjectList.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ProjectView.html b/docs/docs/ProjectView.html index 18d08bbdf..f45254efa 100644 --- a/docs/docs/ProjectView.html +++ b/docs/docs/ProjectView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/QualityCheck.html b/docs/docs/QualityCheck.html index 86247edf6..3dd9a9930 100644 --- a/docs/docs/QualityCheck.html +++ b/docs/docs/QualityCheck.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/QualityReport.html b/docs/docs/QualityReport.html index 29199caf2..eebb43873 100644 --- a/docs/docs/QualityReport.html +++ b/docs/docs/QualityReport.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/QueryBuilderView.html b/docs/docs/QueryBuilderView.html index f4374ac7e..2f3dff3ac 100644 --- a/docs/docs/QueryBuilderView.html +++ b/docs/docs/QueryBuilderView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/QueryField.html b/docs/docs/QueryField.html index 6d5fd0655..1c68280fa 100644 --- a/docs/docs/QueryField.html +++ b/docs/docs/QueryField.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/QueryFieldSearchSelect.html b/docs/docs/QueryFieldSearchSelect.html new file mode 100644 index 000000000..c7984471d --- /dev/null +++ b/docs/docs/QueryFieldSearchSelect.html @@ -0,0 +1,204 @@ + + + + + MetacatUI Dev Docs: Class: QueryFieldSearchSelect + + + + + + + + + + + + + + +
+ +

Class: QueryFieldSearchSelect

+ + + + + + +
+ +
+ +

QueryFieldSearchSelect()

+ +
An extension of SearchSelect that sets the options to the query +fields (e.g. Solr fields) available for searching.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new QueryFieldSearchSelect() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/QueryFieldSelectView.html b/docs/docs/QueryFieldSelectView.html index 0b4fa9192..6127b9e4d 100644 --- a/docs/docs/QueryFieldSelectView.html +++ b/docs/docs/QueryFieldSelectView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -48,8 +48,8 @@

Class: QueryFieldSelectView

QueryFieldSelectView()

-
A select interface that allows the user to search for and -select metadata field(s).
+
A select interface that allows the user to search for and select +metadata field(s).
@@ -134,7 +134,7 @@

Source:
@@ -174,7 +174,7 @@

Extends

@@ -195,119 +195,19 @@

Members

-

- +

+ - addFields :Array.<AdditionalField> + ModelType

-
- A list of additional fields which are not retrieved from the query service -index, but which should be added to the list of options. This can be used to -add abstracted fields which are a combination of multiple query fields, or to -add a duplicate field that has a different label. -
- - - -

Type:
- - - - - - -
- - - - -
Since:
-
  • 2.15.0
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

- - - - - categoriesToAlphabetize :Array.<string> -

- - - - -
- The names of categories that should have items sorted alphabetically. Names -must exactly match those in the -Query Field model -
- -
Type:
-
    -
  • - -Array.<string> - - -
  • -
- @@ -317,9 +217,6 @@
Type:
-
Since:
-
  • 2.15.0
- @@ -344,7 +241,7 @@
Type:
Source:
@@ -367,28 +264,14 @@

- className :string + className

-
- className - the class names for this view element -
- - - -
Type:
-
    -
  • - -string -
  • -
- @@ -422,7 +305,7 @@
Type:
Source:
@@ -440,34 +323,19 @@
Type:
-

- +

+ - commonFields :Array.<string> + tooltipSettings

-
- A list of query fields names to display at the top of the menu, above -all other category headers -
- - - -

Type:
-
    -
  • - -Array.<string> -
  • -
- @@ -501,7 +369,7 @@
Type:
Source:
@@ -519,32 +387,18 @@
Type:
-

- +

+ - excludeFields :Array.<string> + type

-
- A list of query fields names to exclude from the list of options -
- - - -

Type:
-
    -
  • - -Array.<string> - -
  • -
@@ -579,7 +433,7 @@
Type:
Source:
@@ -596,190 +450,37 @@
Type:
- -

- - - - - excludeNonSearchable :boolean -

- - - - -
- Whether or not to exclude fields which are not searchable. Set to -false to keep query fields that are not searchable in the returned list -
- - - -
Type:
-
    -
  • - -boolean - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - -
- - - - - +

Methods

-

- - - - - inputLabel :string -

- - - - -
- Label for the input element -
- - - -
Type:
-
    -
  • - -string - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
+

+ + + + tooltipHTML() +

-
- - - - - - - - -

- - - - placeholderText :string -

-
- Text to show in the input field before any value has been entered -
-
Type:
-
    -
  • - -string -
  • -
@@ -814,1016 +515,7 @@
Type:
Source:
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
Default Value:
-
    -
  • "accordion"
  • -
- - - -
Source:
-
- - - - - -
See:
-
- -
- - - -
- - - - - - - - -

- - - - - type :string -

- - - - -
- The type of View this is -
- - - -
Type:
-
    -
  • - -string - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

- - - - - addTooltip(element, position) → {jQuery} -

- - - - - - -
- addTooltip - Add a tooltip to a given element using the description in the -options object that's set on the view. This overwrites the prototype addTooltip -function so that we can use popovers with more details for query select fields. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
element - - -HTMLElement - - - - The HTML element a tooltip should be added
position - - -string - - - - how to position the tooltip - top | bottom | left | -right
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- The element with a tooltip wrapped by jQuery -
- - - -
-
- Type -
-
- -jQuery - - -
-
- - - - - - - - - - - - - -

- - - - - fieldToOption(field) → {object} -

- - - - - - -
- fieldToOption - Converts an object that represents a QueryField model in the -format specified by the SearchableSelectView.options -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
field - - -object - - - - An object with properties corresponding to a QueryField -model
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- An object in the format specified by -SearchableSelectView.options -
- - - -
-
- Type -
-
- -object - - -
-
- - - - - - - - - - - - - -

- - - - - initialize(options) -

- - - - - - -
- Creates a new QueryFieldSelectView -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - A literal object with options to pass to the view
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - isValidOption(value) → {boolean} -

- - - - - - -
- isValidOption - Checks if a value is one of the values given in view.options -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
value - - -string - - - - The value to check
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- returns true if the value is one of the values given in view.options -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

- - - - - postRender() -

- - - - - - -
- postRender - Updates the view once the dropdown UI has loaded. Processes the -QueryFields given the options passed to this view, then updates the menu and -selection. Processing the fields takes some time, which is why we allow the -view to render before starting that process. This prevents slowing down the -rendering of parent views. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - processFields() -

- - - - - - -
- Retrieves the queryFields collection if not already fetched, then organizes the -fields based on the options passed to this view. -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 2.17.0
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
diff --git a/docs/docs/QueryFields.html b/docs/docs/QueryFields.html index b14d62ffe..b6d9c24e4 100644 --- a/docs/docs/QueryFields.html +++ b/docs/docs/QueryFields.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -127,7 +127,7 @@

Source:
@@ -238,7 +238,7 @@

Source:
@@ -374,7 +374,7 @@

Parameters:
Source:
@@ -437,7 +437,7 @@

- fetch() + fetch(options) → {Array}

@@ -457,6 +457,55 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object + + + + Options to pass to the fetch method
+ + @@ -490,7 +539,7 @@

Source:
@@ -515,6 +564,28 @@

+

Returns:
+ + +
+ The array of Query Field attributes to be added to the collection. +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + @@ -637,7 +708,7 @@
Parameters:
Source:
@@ -690,100 +761,6 @@
Returns:
- - - - - - -

- - - - - initialize() -

- - - - - - -
- initialize - Creates a new QueryFields collection -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - @@ -897,7 +874,7 @@
Parameters:
Source:
@@ -1013,7 +990,7 @@

Source:
diff --git a/docs/docs/QueryRuleView.html b/docs/docs/QueryRuleView.html index 028d4b8f7..dc2a3250c 100644 --- a/docs/docs/QueryRuleView.html +++ b/docs/docs/QueryRuleView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -134,7 +134,7 @@

Source:
@@ -255,7 +255,7 @@

Type:
Source:
@@ -333,7 +333,7 @@
Type:
Source:
@@ -411,7 +411,7 @@
Type:
Source:
@@ -504,7 +504,7 @@
Type:
Source:
@@ -585,7 +585,7 @@
Type:
Source:
@@ -670,7 +670,7 @@
Type:
Source:
@@ -748,7 +748,7 @@
Type:
Source:
@@ -827,7 +827,7 @@
Type:
Source:
@@ -905,7 +905,7 @@
Type:
Source:
@@ -984,7 +984,7 @@
Type:
Source:
@@ -1067,7 +1067,7 @@
Type:
Source:
@@ -1145,7 +1145,7 @@
Type:
Source:
@@ -1179,7 +1179,7 @@

which should be added to the list of options. This can be used to add abstracted fields which are a combination of multiple query fields, or to add a duplicate field that has a different label. These special fields are passed on -to QueryFieldSelectView#addFields. +to QueryFieldSelectView#addFields.

@@ -1230,7 +1230,7 @@
Type:
Source:
@@ -1308,7 +1308,7 @@
Type:
Source:
@@ -1390,7 +1390,7 @@
Type:
Source:
@@ -1468,7 +1468,7 @@
Type:
Source:
@@ -1555,7 +1555,7 @@

Source:
@@ -1596,7 +1596,7 @@

- addOperatorSelect(selectedOperator) + addOperatorSelect(operator)

@@ -1642,7 +1642,7 @@
Parameters:
- selectedOperator + operator @@ -1700,7 +1700,7 @@
Parameters:
Source:
@@ -1794,7 +1794,7 @@

Source:
@@ -1888,7 +1888,7 @@

Source:
@@ -1982,7 +1982,7 @@

Source:
@@ -2023,7 +2023,7 @@

- convertFromSpecialFields(fields, fields) → {Array.<string>|Array.<string>} + convertFromSpecialFields(fields) → {Array.<string>}

@@ -2090,29 +2090,6 @@
Parameters:
- The list of field names to convert - - - - - - - fields - - - - - -Array.<string> - - - - - - - - - The list of fields to convert to actual query service index fields @@ -2158,7 +2135,7 @@
Parameters:
Source:
@@ -2184,33 +2161,13 @@
Parameters:
Returns:
-
    -
  • -
    - - The converted list of field names. If there were no -special fields detected, or if there's an error, then then the field names are -returned unchanged. -
    - - -
    -
    - Type -
    -
    -Array.<string> - - -
    -
    -
  • - -
  • - Returns the list of fields with any special field -replaced with real fields from the query service index +replaced with real fields from the query service index. If there were no +special fields detected, or if there's an error, then then the field names are +returned unchanged.
    @@ -2226,8 +2183,8 @@
    Returns:
- - + + @@ -2244,7 +2201,7 @@

- convertToSpecialFields(fields, fields) → {Array.<string>|Array.<string>} + convertToSpecialFields(fields) → {Array.<string>}

@@ -2253,11 +2210,9 @@

- Takes a list of query field names, checks if the model matches any of the -special fields, and if it does, returns the list of fields with the actual -field names replaced with the -special field name. This function is the -opposite of QueryRuleView#convertFromSpecialFields + Converts a list of query field names to special field names based on matches +from the special fields defined. If a field matches a special field's subfields, +it is replaced by the special field name.
@@ -2313,30 +2268,6 @@

Parameters:
- - - - fields - - - - - -Array.<string> - - - - - - - - - - The list of fields to convert to special fields, if -the model matches any of the special field objects - - - @@ -2350,9 +2281,6 @@
Parameters:
-
Since:
-
  • 2.15.0
- @@ -2377,7 +2305,7 @@
Parameters:
Source:
@@ -2403,33 +2331,11 @@
Parameters:
Returns:
-
    -
  • -
    - - The converted list of field names. If there were no -special fields detected, or if there's an error, then then the field names are -returned unchanged. -
    - - -
    -
    - Type -
    -
    -Array.<string> - - -
    -
    -
  • - -
  • - - Returns the list of fields with actual query field names -replaced with special field names, if any match + - The converted list of field names. If no special fields are +detected, then the field names are returned unchanged.
    @@ -2445,8 +2351,8 @@
    Returns:
    -
  • -
+ + @@ -2463,7 +2369,7 @@

- events() → {Object} + events() → {object}

@@ -2516,7 +2422,7 @@

Source:
@@ -2556,7 +2462,7 @@

Returns:
-Object +object
@@ -2683,7 +2589,7 @@
Parameters:
Source:
@@ -2746,7 +2652,7 @@

- getOperatorOptions(fieldsopt) + getOperatorOptions(inputFieldsopt) → {Array.<object>}

@@ -2794,7 +2700,7 @@
Parameters:
- fields + inputFields @@ -2865,7 +2771,7 @@
Parameters:
Source:
@@ -2890,6 +2796,29 @@
Parameters:
+
Returns:
+ + +
+ - Returns an array of operator options that are allowed for +this view's filter model +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + @@ -2915,8 +2844,7 @@

- Selects a color from the -rule colour palette array, given an + Selects a color from the QueryRuleView#ruleColorPalette, given an index. If the index is greater than the length of the palette, then the palette is effectively repeated until long enough (i.e. colours will be recycled). If no index in provided, the first colour in the palette will be selected. @@ -2947,8 +2875,6 @@
Parameters:
- Default - Description @@ -2984,12 +2910,6 @@
Parameters:
- - - 0 - - - The position of the rule within the Filters collection. @@ -3024,12 +2944,6 @@
Parameters:
- - - "#57b39c" - - - A default colour to use in case there is problem with this function (hex color code beginning with '#'). @@ -3073,7 +2987,7 @@
Parameters:
Source:
@@ -3190,7 +3104,7 @@

Source:
@@ -3378,7 +3292,7 @@

Parameters:
Source:
@@ -3445,7 +3359,7 @@

- handleFieldChange(newFields) + handleFieldChange(fields)

@@ -3454,10 +3368,10 @@

- handleFieldChange - Called when the Query Field Select View triggers a change + Called when the Query Field Select View triggers a change event. Updates the model with the new fields, and if required, 1) converts the filter model to a different type based on the types of fields - selected, 2) updates the operator select and the value select +selected, 2) updates the operator select and the value select
@@ -3493,7 +3407,7 @@

Parameters:
- newFields + fields @@ -3550,7 +3464,7 @@
Parameters:
Source:
@@ -3695,7 +3609,7 @@
Parameters:
Source:
@@ -3839,7 +3753,7 @@
Parameters:
Source:
@@ -3931,7 +3845,7 @@
Parameters:
-Object +object @@ -3982,7 +3896,7 @@
Parameters:
Source:
@@ -4023,7 +3937,7 @@

- previewRemove() + previewRemove(e)

@@ -4044,6 +3958,55 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
e + + +Event + + + + The mouseover or mouseout event
+ + @@ -4077,7 +4040,7 @@

Source:
@@ -4221,7 +4184,7 @@

Parameters:
Source:
@@ -4316,7 +4279,7 @@

Source:
@@ -4410,7 +4373,7 @@

Source:
@@ -4529,7 +4492,7 @@

Source:
diff --git a/docs/docs/Quota.html b/docs/docs/Quota.html index c68eb91ae..7b0153c87 100644 --- a/docs/docs/Quota.html +++ b/docs/docs/Quota.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Quotas.html b/docs/docs/Quotas.html index f9deaad67..56f42be9c 100644 --- a/docs/docs/Quotas.html +++ b/docs/docs/Quotas.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/RegisterCitationView.html b/docs/docs/RegisterCitationView.html index fff6480c6..fb52b753a 100644 --- a/docs/docs/RegisterCitationView.html +++ b/docs/docs/RegisterCitationView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ScaleBarView.html b/docs/docs/ScaleBarView.html index 01a4e162c..4d43793ba 100644 --- a/docs/docs/ScaleBarView.html +++ b/docs/docs/ScaleBarView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ScienceMetadata.html b/docs/docs/ScienceMetadata.html index bbb8cc1b6..760c001d6 100644 --- a/docs/docs/ScienceMetadata.html +++ b/docs/docs/ScienceMetadata.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -253,107 +253,7 @@

Source:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - bytesToSize() -

- - - - - - -
- Converts the number of bytes into a human readable format and -updates the `sizeStr` attribute -
- - - - - - - - - - - - - -
- - - - - - -
Inherited From:
-
- - - - - - - - - - - - - - - - - - - - - -
Source:
-
@@ -513,7 +413,7 @@
Parameters:
Source:
@@ -614,8 +514,6 @@
Parameters:
- Default - Description @@ -651,12 +549,6 @@
Parameters:
- - - changePermission - - - The action (read, write, or changePermission) to check if the current user has authorization to perform. By default checks for the highest level of permission. @@ -691,10 +583,6 @@
Parameters:
- - - - Additional options for this function. See the properties below. @@ -817,7 +705,7 @@
Properties:
Source:
@@ -997,7 +885,7 @@
Parameters:
Source:
@@ -1120,7 +1008,7 @@

Source:
@@ -1219,7 +1107,7 @@

Source:
@@ -1337,7 +1225,7 @@

Source:
@@ -1388,7 +1276,7 @@

- fetch() + fetch(options)

@@ -1408,6 +1296,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + +
+ + @@ -1446,7 +1378,7 @@

Source:
@@ -1640,7 +1572,7 @@

Parameters:
Source:
@@ -1791,7 +1723,7 @@
Parameters:
Source:
@@ -1912,7 +1844,7 @@

Source:
@@ -2037,7 +1969,7 @@

Source:
@@ -2165,7 +2097,7 @@

Source:
@@ -2274,7 +2206,7 @@

Source:
@@ -2376,7 +2308,7 @@

Source:
@@ -2485,7 +2417,7 @@

Source:
@@ -2645,7 +2577,7 @@

Parameters:
Source:
@@ -2911,7 +2843,7 @@
Properties:
Source:
@@ -3010,7 +2942,7 @@

Source:
@@ -3176,7 +3108,7 @@

Parameters:
Source:
@@ -3300,7 +3232,7 @@

Source:
@@ -3470,7 +3402,7 @@

Parameters:
Source:
@@ -3587,7 +3519,7 @@

Source:
@@ -3709,7 +3641,7 @@

Source:
@@ -3826,7 +3758,7 @@

Source:
@@ -3950,7 +3882,7 @@

Source:
@@ -4120,7 +4052,7 @@

Parameters:
Source:
@@ -4239,7 +4171,7 @@

Source:
@@ -4467,7 +4399,7 @@

Parameters:
Source:
@@ -4508,7 +4440,7 @@

- parse() + parse(response)

@@ -4529,6 +4461,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
response + +
+ + @@ -4567,7 +4543,7 @@

Source:
@@ -4718,7 +4694,7 @@

Parameters:
Source:
@@ -4817,7 +4793,7 @@

Source:
@@ -4858,7 +4834,7 @@

- save() + save(attributes, options)

@@ -4878,6 +4854,68 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + +
options + +
+ + @@ -4916,7 +4954,7 @@

Source:
@@ -5015,7 +5053,7 @@

Source:
@@ -5132,7 +5170,7 @@

Source:
@@ -5232,7 +5270,7 @@

Source:
@@ -5385,7 +5423,7 @@

Parameters:
Source:
@@ -5426,7 +5464,7 @@

- toJson() + toJson(xml)

@@ -5446,6 +5484,50 @@

+

Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xml + +
+ + @@ -5484,7 +5566,7 @@

Source:
@@ -5655,7 +5737,7 @@

Parameters:
Source:
@@ -5835,7 +5917,7 @@
Parameters:
Source:
@@ -5983,7 +6065,7 @@
Parameters:
Source:
@@ -6082,7 +6164,7 @@

Source:
@@ -6181,7 +6263,7 @@

Source:
@@ -6280,7 +6362,7 @@

Source:
diff --git a/docs/docs/ScienceMetadataView.html b/docs/docs/ScienceMetadataView.html index e73f1c3ae..438dbe5c7 100644 --- a/docs/docs/ScienceMetadataView.html +++ b/docs/docs/ScienceMetadataView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Search.html b/docs/docs/Search.html index d7f76e4cf..861b7a503 100644 --- a/docs/docs/Search.html +++ b/docs/docs/Search.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SearchInputView.html b/docs/docs/SearchInputView.html index 4b0bd080a..8c12bc3a9 100644 --- a/docs/docs/SearchInputView.html +++ b/docs/docs/SearchInputView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SearchParams.html b/docs/docs/SearchParams.html index f337022fb..abe70eef9 100644 --- a/docs/docs/SearchParams.html +++ b/docs/docs/SearchParams.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SearchResultView.html b/docs/docs/SearchResultView.html index d4b72142b..773b08dc9 100644 --- a/docs/docs/SearchResultView.html +++ b/docs/docs/SearchResultView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SearchResultsPagerView.html b/docs/docs/SearchResultsPagerView.html index d64b6ab4e..6026d4d03 100644 --- a/docs/docs/SearchResultsPagerView.html +++ b/docs/docs/SearchResultsPagerView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SearchResultsView.html b/docs/docs/SearchResultsView.html index ada01a548..6ea97f870 100644 --- a/docs/docs/SearchResultsView.html +++ b/docs/docs/SearchResultsView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SearchSelect.html b/docs/docs/SearchSelect.html new file mode 100644 index 000000000..418aa9ff5 --- /dev/null +++ b/docs/docs/SearchSelect.html @@ -0,0 +1,204 @@ + + + + + MetacatUI Dev Docs: Class: SearchSelect + + + + + + + + + + + + + + +
+ +

Class: SearchSelect

+ + + + + + +
+ +
+ +

SearchSelect()

+ +
A model for managing dropdown options and state for a search +select component.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new SearchSelect() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/SearchSelectOptions.html b/docs/docs/SearchSelectOptions.html new file mode 100644 index 000000000..7de47bd19 --- /dev/null +++ b/docs/docs/SearchSelectOptions.html @@ -0,0 +1,193 @@ + + + + + MetacatUI Dev Docs: Class: SearchSelectOptions + + + + + + + + + + + + + + +
+ +

Class: SearchSelectOptions

+ + + + + + +
+ +
+ +

SearchSelectOptions()

+ +
A collection for managing dropdown options in a search +select view.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new SearchSelectOptions() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/SearchSelectView.html b/docs/docs/SearchSelectView.html new file mode 100644 index 000000000..c875a4771 --- /dev/null +++ b/docs/docs/SearchSelectView.html @@ -0,0 +1,5000 @@ + + + + + MetacatUI Dev Docs: Class: SearchSelectView + + + + + + + + + + + + + + +
+ +

Class: SearchSelectView

+ + + + + + +
+ +
+ +

SearchSelectView()

+ +
A select interface that allows the user to search from within +the options, and optionally select multiple items. Also allows the items to +be grouped, and to display an icon or image for each item.
+ + + + + +
+

Screenshot

+ + + +
+ + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new SearchSelectView() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.14.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.View
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + ModelType :Backbone.Model +

+ + + + +
+ The constructor function for the model that this view uses. Must be a +SearchSelect or an extension of it. +
+ + + +
Type:
+
    +
  • + +Backbone.Model + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + tooltipSettings :object|boolean +

+ + + + +
+ Options and selected values for the search select interface show a +tooltip with the description of the option when the user hovers over +the option. This object is passed to the Formantic UI popup module to +configure the tooltip. Set to false to disable tooltips. +
+ + + +
Type:
+
    +
  • + +object +| + +boolean + + +
  • +
+ + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + addClickToTexts() +

+ + + + + + +
+ Because we've modified the text elements to be hoverable to show the +tooltip, we needed to move them to a higher z-index which blocks the +click action on the dropdown input element. This function ensures that +the dropdown is shown when any part of the input is clicked, including +the selected text elements in a single-select dropdown. +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addSeparator(el) +

+ + + + + + +
+ Add a separator before the given label element +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
el + + +HTMLElement + + + + The label element to add a separator before
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addSeparators() +

+ + + + + + +
+ Add separators between labels in the dropdown if required +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addTooltip(element, settings) +

+ + + + + + +
+ Add a tooltip to a given element using the description in the options +object that's set on the view. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
element + + +HTMLElement + + + + The HTML element a tooltip should be +added
settings + + +object + + + + Additional settings to override those set in +view.tooltipSettings.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addTooltipsToSelectionEls() +

+ + + + + + +
+ Add tooltips to the selected labels or text elements +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + checkForInvalidSelections() +

+ + + + + + +
+ Show an error message if the user has selected an invalid value +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + createIcon() → {HTMLElement} +

+ + + + + + +
+ Create the icon element for the select interface +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The icon element +
+ + + +
+
+ Type +
+
+ +HTMLElement + + +
+
+ + + + + + + + + + + + + +

+ + + + + createInput() → {HTMLElement} +

+ + + + + + +
+ Create the hidden input element that will store the selected values +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The input element +
+ + + +
+
+ Type +
+
+ +HTMLElement + + +
+
+ + + + + + + + + + + + + +

+ + + + + createLabel() → {HTMLElement|null} +

+ + + + + + +
+ Create the label for the search select interface +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The label element, or null if no label is +specified. +
+ + + +
+
+ Type +
+
+ +HTMLElement +| + +null + + +
+
+ + + + + + + + + + + + + +

+ + + + + createMenu() → {OptionsView} +

+ + + + + + +
+ Create the dropdown menu for the select interface +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The dropdown menu +
+ + + +
+
+ Type +
+
+ +OptionsView + + +
+
+ + + + + + + + + + + + + +

+ + + + + createModel(options) +

+ + + + + + +
+ Create a new SearchSelect model and set it on the view. If a model +already exists, it will be destroyed. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object + + + + The options to pass to the model
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + createPlaceholder() → {HTMLElement} +

+ + + + + + +
+ Create the placeholder element for the select interface +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The placeholder element +
+ + + +
+
+ Type +
+
+ +HTMLElement + + +
+
+ + + + + + + + + + + + + +

+ + + + + createSelectContainer() → {HTMLElement} +

+ + + + + + +
+ Create the container for the select interface +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The select container element +
+ + + +
+
+ Type +
+
+ +HTMLElement + + +
+
+ + + + + + + + + + + + + +

+ + + + + createSeparator() → {JQuery} +

+ + + + + + +
+ Create the HTML for a separator element to insert between two labels. +The view.separatorClass is added to the separator element. +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.15.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Returns the separator as a jQuery element +
+ + + +
+
+ Type +
+
+ +JQuery + + +
+
+ + + + + + + + + + + + + +

+ + + + + enable() +

+ + + + + + +
+ Visually indicate that the select interface is enabled +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + getLabels() → {Array.<HTMLElement>} +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The selected label elements in a multi-select dropdown +
+ + + +
+
+ Type +
+
+ +Array.<HTMLElement> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getTexts() → {Array.<HTMLElement>} +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The selected text element in a single-select dropdown +
+ + + +
+
+ Type +
+
+ +Array.<HTMLElement> + + +
+
+ + + + + + + + + + + + + +

+ + + + + hideLoading() +

+ + + + + + +
+ Remove the loading spinner set by the showLoading +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + inactivate() +

+ + + + + + +
+ Visually indicate that the select interface is inactive +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + listenToModel() +

+ + + + + + +
+ Update the view when certain model attributes change +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + listenToSelectUI() +

+ + + + + + +
+ Listen to events from the select UI interface and update the model +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + optionFromSelectionEl(el) → {SearchSelectOption|null} +

+ + + + + + +
+ Get the option model given a dropdown text or label element. Label +elements are used for multi-select dropdowns, the value is a data +attribute. Text elements are for single-select dropdowns, so the value +is the current selection. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
el + + +HTMLElement + + + + The text or label element
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The option model or null if not +found +
+ + + +
+
+ Type +
+
+ +SearchSelectOption +| + +null + + +
+
+ + + + + + + + + + + + + +

+ + + + + removeAllSeparators() +

+ + + + + + +
+ Remove all messages from the view +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + removeMessages() +

+ + + + + + +
+ Remove all messages and classes set by the showMessage function +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + renderSelectUI() +

+ + + + + + +
+ Initialize the dropdown interface +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + reset(silentopt, closeMenuopt) +

+ + + + + + +
+ Remove the selected values from the dropdown interface +and from the model. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
silent + + +boolean + + + + + + <optional>
+ + + + + +
Set to true to prevent the dropdown and the +model from triggering change events
closeMenu + + +boolean + + + + + + <optional>
+ + + + + +
Set to true to close the dropdown menu
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showInvalidSelectionError(opts) +

+ + + + + + +
+ Show a message indicated that some of the selected values are not valid +choices. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
opts + + +Array.<string> + + + + The values that are not valid choices
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showLoading() +

+ + + + + + +
+ Visually indicate that dropdown options are loading +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showMessage(message, type, removeOnChange) +

+ + + + + + +
+ Show an error, warning, or informational message, and highlight the +select interface in an appropriate colour. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + +string + + + + The message to display. Use an empty string to +only highlight the select interface without showing any message text.
type + + +string + + + + one of "error", "warning", or "info"
removeOnChange + + +boolean + + + + set to true to remove the message as +soon as the user changes the selection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + showSelected(silentopt) +

+ + + + + + +
+ Update the dropdown interface with the selected values from the model +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
silent + + +boolean + + + + + + <optional>
+ + + + + +
Set to true to prevent the dropdown from +triggering a change event (an infinite loop can occur if this is not set, +as the dropdown will trigger a change event, which will update the model).
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + splitModelViewOptions(options) → {object} +

+ + + + + + +
+ Split the options passed to the view into model and view attributes. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object + + + + The options passed to the view
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An object with two keys: modelAttrs and viewAttrs +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + tooltipHTML(option, _$element) → {string|null} +

+ + + + + + +
+ Create HTML for a tooltip for a given option. By default this method +returns the description of the option, but can be overridden in +extended SearchSelectViews to return a custom HTML string based on +the option. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
option + + +SearchSelectOption + + + + The option to create a tooltip for
_$element + + +JQuery + + + + The element to attach the tooltip to
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An HTML string to use for the content of the +tooltip. +
+ + + +
+
+ Type +
+
+ +string +| + +null + + +
+
+ + + + + + + + + + + + + +

+ + + + + updateMenuMode(forceopt) +

+ + + + + + +
+ Convert the submenu style to the style set in the model +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
force + + +boolean + + + + + + <optional>
+ + + + + +
Set to true to force the view to update
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + updateOptions(options) +

+ + + + + + +
+ Change the options available in the dropdown menu and re-render. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +SearchSelectOptions + + + + The new options
+ + + + + + +
+ + + + +
Since:
+
  • 2.24.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/SearchView.html b/docs/docs/SearchView.html index 2226faae0..61b094df6 100644 --- a/docs/docs/SearchView.html +++ b/docs/docs/SearchView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SelectOptionModel.html b/docs/docs/SelectOptionModel.html new file mode 100644 index 000000000..93e99aaf0 --- /dev/null +++ b/docs/docs/SelectOptionModel.html @@ -0,0 +1,203 @@ + + + + + MetacatUI Dev Docs: Class: SelectOptionModel + + + + + + + + + + + + + + +
+ +

Class: SelectOptionModel

+ + + + + + +
+ +
+ +

SelectOptionModel()

+ +
A model for representing an option in a search select dropdown.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new SelectOptionModel() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/SemanticFilterView.html b/docs/docs/SemanticFilterView.html index 8dcf78b6c..ca50eb5ab 100644 --- a/docs/docs/SemanticFilterView.html +++ b/docs/docs/SemanticFilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -49,7 +49,9 @@

Class: SemanticFilterView

SemanticFilterView()

Render a specialized view of a single Filter model using the - AnnotationFilterView.
+BioontologySelectView. Essentially acts as a connector between the Filter +model and the Bioontology model. Uses logic from both the FilterView and +the BioontologySelectView.
@@ -134,7 +136,7 @@

Source:
@@ -195,6 +197,70 @@

Members

+

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + +

@@ -773,10 +839,8 @@
Type:
- - -
Overrides:
-
  • +
    Inherited From:
    +
    @@ -797,6 +861,8 @@
    Type:
    + +
    Source:
    • @@ -860,10 +926,8 @@
      Type:
      - - -
      Overrides:
      -
      • +
        Inherited From:
        +
        @@ -884,6 +948,8 @@
        Type:
        + +
        Source:
        • @@ -905,20 +971,19 @@
          Type:
          -

          - +

          + - template :Underscore.Template + ontologies :Array.<{label: string, ontology: string, subTree: string}>

          - Reference to template for this view. HTML files are converted to Underscore.js -templates + The ontologies to search for terms in.
          @@ -927,7 +992,7 @@

          Type:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + onSubViewSelection() +

+ + + + + + +
+ Update the filter model when a class is selected in the +BioontologySelectView. Clear the selection/search input from the +SelectView and collapse the menu. +
+ + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + +
Source:
@@ -2026,7 +2147,7 @@

- render() + render() → {SemanticFilterView}

@@ -2035,11 +2156,10 @@

- Render an instance of a Semantic Filter View. - -Note that this View doesn't have a template and instead delegates to -the AnnotationFilterView which renders a SearchableSelectView which -renders an NCBOTree. + Render an instance of a Semantic Filter View. Note that this View +doesn't have a template and instead delegates to the +BioontologySelectView which renders a SearchSelectView which renders +the BioontologySelectView.
@@ -2091,7 +2211,7 @@

Source:
@@ -2116,6 +2236,28 @@

+

Returns:
+ + +
+ This instance +
+ + + +
+
+ Type +
+
+ +SemanticFilterView + + +
+
+ + @@ -2142,12 +2284,10 @@

Set the human-readable label for a term URI. - For most uses of the Filter model, the value(s) set on the model can be shown directly in the UI. But for Semantic searches, we need to be able to display a human-readable label for the value because the value is likely an opaque URI. - Rather than fetch and/or store all the possible labels for all possible URIs, we store a label for whichever terms the user chooses and keep that around until we need it in the UI. @@ -2269,7 +2409,7 @@
Parameters:
Source:
@@ -2465,7 +2605,7 @@
Parameters:
Source:
@@ -2614,7 +2754,106 @@
Parameters:
Source:
+ + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + template() +

+ + + + + + +
+ override the template function and use subView instead +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -2780,7 +3019,7 @@
Parameters:
Source:
@@ -2880,7 +3119,7 @@

Source:
@@ -3032,7 +3271,7 @@

Parameters:
Source:
diff --git a/docs/docs/SeparatorView.html b/docs/docs/SeparatorView.html new file mode 100644 index 000000000..e62a01cc6 --- /dev/null +++ b/docs/docs/SeparatorView.html @@ -0,0 +1,1594 @@ + + + + + MetacatUI Dev Docs: Class: SeparatorView + + + + + + + + + + + + + + +
+ +

Class: SeparatorView

+ + + + + + +
+ +
+ +

SeparatorView()

+ +
Text that separates selected terms in a search select dropdown, +such as "AND" or "OR". These may be used to represent boolean operators in +a search query. The separator can be clicked to toggle between possible +values set in the SearchSelect model.
+ + + + + +
+

Screenshot

+ + + +
+ + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new SeparatorView() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.View
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

+ + + + + className +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + mouseEnterCallback :function +

+ + + + +
+ Callback function to run when the user hovers. If not set, the default +behavior is to highlight the separator. +
+ + + +
Type:
+
    +
  • + +function + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + mouseOutCallback :function +

+ + + + +
+ Callback function to run when the user stops hovering. If not set, the +default behavior is to unhighlight the separator. +
+ + + +
Type:
+
    +
  • + +function + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + tagName +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

+ + + + + tooltipSettings :object|boolean +

+ + + + +
+ Settings is passed to the Formantic UI popup module to configure a +tooltip shown when the user hovers over the separator. Set to `false` +to disable tooltips. +
+ + + +
Type:
+
    +
  • + +object +| + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + +

+ + + + + type +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + activate() +

+ + + + + + +
+ Add event listeners to the element to allow the user to change the +separator text by clicking on it. Add visual indicators to show that +the separator is clickable. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + addTooltip() +

+ + + + + + +
+ Create and attach a tooltip +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + deactivate() +

+ + + + + + +
+ Remove event listeners and visual indicators +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + highlight() +

+ + + + + + +
+ Visually emphasize the separator +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + remove() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + render() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setText() +

+ + + + + + +
+ Update the text of the separator element to match the model +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + unhighlight() +

+ + + + + + +
+ Visually de-emphasize the separator +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + updateText() +

+ + + + + + +
+ Update the text shown in the separator element +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/ShareUrlView.html b/docs/docs/ShareUrlView.html index 35c641286..2982f7128 100644 --- a/docs/docs/ShareUrlView.html +++ b/docs/docs/ShareUrlView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SignInView.html b/docs/docs/SignInView.html index 2d052339b..33b238268 100644 --- a/docs/docs/SignInView.html +++ b/docs/docs/SignInView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SolrAutocomplete.html b/docs/docs/SolrAutocomplete.html new file mode 100644 index 000000000..f64b46b38 --- /dev/null +++ b/docs/docs/SolrAutocomplete.html @@ -0,0 +1,204 @@ + + + + + MetacatUI Dev Docs: Class: SolrAutocomplete + + + + + + + + + + + + + + +
+ +

Class: SolrAutocomplete

+ + + + + + +
+ +
+ +

SolrAutocomplete()

+ +
An extension of SearchSelect that limits the options to the +available values within a given Solr field.
+ + + + + +
+ +
+
+ + + + +

Constructor

+ + + +

+ + + + + new SolrAutocomplete() +

+ + + + + + + + + + + + + + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Backbone.Model
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/docs/SolrResult.html b/docs/docs/SolrResult.html index 3b515f960..0072d8afc 100644 --- a/docs/docs/SolrResult.html +++ b/docs/docs/SolrResult.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -187,172 +187,6 @@

Methods

-

- - - - - bytesToSize(integer, integer) -

- - - - - - -
- Convert number of bytes into human readable format -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
integer - - bytes Number of bytes to convert
integer - - precision Number of digits after the decimal separator
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- string -
- - - - - - - - - - - - - - -

diff --git a/docs/docs/SolrResults.html b/docs/docs/SolrResults.html index c30804376..f06fc78ba 100644 --- a/docs/docs/SolrResults.html +++ b/docs/docs/SolrResults.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SorterView.html b/docs/docs/SorterView.html index 715107157..bae4dfcee 100644 --- a/docs/docs/SorterView.html +++ b/docs/docs/SorterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/SpatialFilter.html b/docs/docs/SpatialFilter.html index 7d20325b3..9bf7afaa3 100644 --- a/docs/docs/SpatialFilter.html +++ b/docs/docs/SpatialFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Stats.html b/docs/docs/Stats.html index 9a9764166..0ce31609e 100644 --- a/docs/docs/Stats.html +++ b/docs/docs/Stats.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Subscription.html b/docs/docs/Subscription.html index de891b659..20bf53bd8 100644 --- a/docs/docs/Subscription.html +++ b/docs/docs/Subscription.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/TOCView.html b/docs/docs/TOCView.html index 7428bfba1..f5a5bdb82 100644 --- a/docs/docs/TOCView.html +++ b/docs/docs/TOCView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/TableEditorView.html b/docs/docs/TableEditorView.html index fa3718a3b..ac0fd2c09 100644 --- a/docs/docs/TableEditorView.html +++ b/docs/docs/TableEditorView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ToggleFilter.html b/docs/docs/ToggleFilter.html index 33f68dbd1..d26c171ab 100644 --- a/docs/docs/ToggleFilter.html +++ b/docs/docs/ToggleFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ToggleFilterView.html b/docs/docs/ToggleFilterView.html index 4dfed673d..b4c44106d 100644 --- a/docs/docs/ToggleFilterView.html +++ b/docs/docs/ToggleFilterView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -1389,7 +1389,7 @@
Parameters:
Source:
@@ -1533,7 +1533,7 @@
Parameters:
Source:
@@ -1706,7 +1706,7 @@
Parameters:
Source:
@@ -2402,7 +2402,7 @@
Parameters:
Source:
@@ -2551,7 +2551,7 @@
Parameters:
Source:
@@ -2717,7 +2717,7 @@
Parameters:
Source:
@@ -2969,7 +2969,7 @@
Parameters:
Source:
diff --git a/docs/docs/ToolbarView.html b/docs/docs/ToolbarView.html index e7f039a9d..d2b0d098f 100644 --- a/docs/docs/ToolbarView.html +++ b/docs/docs/ToolbarView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/UIRouter.html b/docs/docs/UIRouter.html index 61f37f92f..cd0e7d746 100644 --- a/docs/docs/UIRouter.html +++ b/docs/docs/UIRouter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Units.html b/docs/docs/Units.html index 7f750c096..bccf1fe3a 100644 --- a/docs/docs/Units.html +++ b/docs/docs/Units.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Usage.html b/docs/docs/Usage.html index 29caa8853..5bc9ec0d2 100644 --- a/docs/docs/Usage.html +++ b/docs/docs/Usage.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Usages.html b/docs/docs/Usages.html index 32f187793..4be877741 100644 --- a/docs/docs/Usages.html +++ b/docs/docs/Usages.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/UserGroup.html b/docs/docs/UserGroup.html index 780f4ae45..87e601a30 100644 --- a/docs/docs/UserGroup.html +++ b/docs/docs/UserGroup.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/UserGroupView.html b/docs/docs/UserGroupView.html index 8963af66c..eec6d518b 100644 --- a/docs/docs/UserGroupView.html +++ b/docs/docs/UserGroupView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/UserView.html b/docs/docs/UserView.html index 31110de57..30c5bfd69 100644 --- a/docs/docs/UserView.html +++ b/docs/docs/UserView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/Utilities.html b/docs/docs/Utilities.html index d1d02c824..17b9b21ad 100644 --- a/docs/docs/Utilities.html +++ b/docs/docs/Utilities.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -97,7 +97,7 @@

Utilities

Source:
@@ -136,6 +136,399 @@

Methods

+

+ + + + + bytesToSize(integer, integer, bytes, precision) +

+ + + + + + +
+ Convert number of bytes into human readable format +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
integer + + bytes Number of bytes to convert
integer + + precision Number of digits after the decimal separator
bytes + +
precision + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ string +
+ + + + + + + + + + + + + + + +

+ + + + + deepEqual(a, b) → {boolean} +

+ + + + + + +
+ Checks if two objects are deeply equal. Simpler than the _.isEqual function. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
a + + +object + + + + The first object to compare
b + + +object + + + + The second object to compare
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the objects are deeply equal +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + +

@@ -244,7 +637,7 @@
Parameters:
Source:
@@ -436,7 +829,7 @@

Parameters:
Source:
@@ -604,7 +997,7 @@
Parameters:
Source:
@@ -772,7 +1165,7 @@
Parameters:
Source:
@@ -1011,7 +1404,196 @@
Parameters:
Source:
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + toJSONWithoutDefaults(model, removePropsopt) → {object} +

+ + + + + + +
+ Removes default values from a model's JSON representation +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
model + + +Backbone.Model + + + + + + + + + + The model to remove defaults from
removeProps + + +Array.<string> + + + + + + <optional>
+ + + + + +
An array of additional properties to remove from the model
+ + + + + + +
+ + + + +
Since:
+
  • 2.31.0
+ + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -1036,6 +1618,28 @@
Parameters:
+
Returns:
+ + +
+ The JSON representation of the model with defaults removed +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + @@ -1161,7 +1765,7 @@
Parameters:
Source:
diff --git a/docs/docs/VectorFilter.html b/docs/docs/VectorFilter.html index 88d690bca..ae22bd417 100644 --- a/docs/docs/VectorFilter.html +++ b/docs/docs/VectorFilter.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/VectorFilters.html b/docs/docs/VectorFilters.html index 71851f4e4..3978673bb 100644 --- a/docs/docs/VectorFilters.html +++ b/docs/docs/VectorFilters.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ViewfinderModel.html b/docs/docs/ViewfinderModel.html index ce69555d0..70a86a26a 100644 --- a/docs/docs/ViewfinderModel.html +++ b/docs/docs/ViewfinderModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ViewfinderView.html b/docs/docs/ViewfinderView.html index ec697f08f..fe518f9f1 100644 --- a/docs/docs/ViewfinderView.html +++ b/docs/docs/ViewfinderView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ZoomPresetModel.html b/docs/docs/ZoomPresetModel.html index 25bf52ffa..fb8844b0c 100644 --- a/docs/docs/ZoomPresetModel.html +++ b/docs/docs/ZoomPresetModel.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ZoomPresetView.html b/docs/docs/ZoomPresetView.html index a3cd263bd..e73d5eb16 100644 --- a/docs/docs/ZoomPresetView.html +++ b/docs/docs/ZoomPresetView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ZoomPresets.html b/docs/docs/ZoomPresets.html index c1da05041..15c27a9bd 100644 --- a/docs/docs/ZoomPresets.html +++ b/docs/docs/ZoomPresets.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/ZoomPresetsListView.html b/docs/docs/ZoomPresetsListView.html index 114bc5635..1f4175e04 100644 --- a/docs/docs/ZoomPresetsListView.html +++ b/docs/docs/ZoomPresetsListView.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/docs_other_addtlDocs.jsdoc.html b/docs/docs/docs_other_addtlDocs.jsdoc.html index 3c3549b9d..d808be76c 100644 --- a/docs/docs/docs_other_addtlDocs.jsdoc.html +++ b/docs/docs/docs_other_addtlDocs.jsdoc.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/global.html b/docs/docs/global.html index b5af99e95..1441bbafc 100644 --- a/docs/docs/global.html +++ b/docs/docs/global.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -201,6 +201,70 @@
Type:
+

+ + + + + model +

+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + +

@@ -239,213 +303,13661 @@
Properties:
Name - Type + Type + + + + + + Description + + + + + + + + + taxonRankName + + + + + +string + + + + + + + + + + The name of the taxonomic rank, for +example, Domain, Kingdom, etc. + + + + + + + taxonRankValue + + + + + +string + + + + + + + + + + The value for the given taxonomic rank, +for example, Animalia, Chordata, etc. + + + + + + + commonName + + + + + +Array.<string> + + + + + + + + + + Common name(s) for the taxon, for example +["Animal"] + + + + + + + taxonId + + + + + +Array.<Object> + + + + + + + + + + A taxon identifier from a controlled +vocabulary, for example, ITIS, NCBI, etc. +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
provider + + +string + + + + The provider of the taxon identifier, +given as a URI, for example http://www.itis.gov
value + + +string + + + + The identifier from the provider, for +example, 180092
+ + + + + + + + + taxonomicClassification + + + + + +Array.<Object> + + + + + + + + + + A nested taxonomic +classification, since taxonomy is represented as a hierarchy in EML. + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

+ + + + + addClassesFromResponse(response, ontologyopt) → {Promise.<void>} +

+ + + + + + +
+ Add classes from a response to the collection. This method is async and +will return a promise that resolves when the collection has been updated. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
response + + +object + + + + + + + + + + The response from the BioPortal API
ontology + + +string +| + +object + + + + + + <optional>
+ + + + + +
Provide to include the ontology acronym +to store as an attribute on the class models
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves when the collection has +been updated +
+ + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +

+ + + + + addFields(fieldsJSON) → {Array.<object>} +

+ + + + + + +
+ Adds fields to the fieldsJSON array that are specified in the addFields +property of this model +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fieldsJSON + + +Array.<object> + + + + JSON returned from QueryFields.toJSON()
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The fieldsJSON array with additional fields added +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + addSelected(value, options) +

+ + + + + + +
+ Add a selected value and ensures it's not already in the list. If this is +not a multi-select dropdown, the selected value will replace any existing +value. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value to add to the selected list.
options + + +object + + + + Additional options to be passed to the set +method.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + buildChildrenUrl(ontology, subTree) → {string} +

+ + + + + + +
+ Build the URL component for a "children" query +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ontology + + +string + + + + The ontology to query, encoded
subTree + + +string + + + + The subTree to query, encoded
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The URL component for the query +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + buildSearchUrl(searchTerm, ontology, subTree) → {string} +

+ + + + + + +
+ Build the URL component for a "search" query +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
searchTerm + + +string + + + + The search term, encoded
ontology + + +string + + + + The ontology to query, encoded
subTree + + +string + + + + The subTree to query, encoded
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The URL component +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + canChangeSeparator() → {boolean} +

+ + + + + + +
+ Checks if it's possible to update the separator that is used between +selected values. For this to be possible, there must be more than one +separator option available. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Returns true if the separator can be changed, false +otherwise. +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

+ + + + + changeSubmenuOnSearch() +

+ + + + + + +
+ Set a listener to change the current submenu style to "list" when a +search term is present, and revert to the original style when the search +term is removed. This is to ensure that the dropdown displays the list +style with only the search results when a user is searching. This is only +necessary if the submenu style is not already set to "list". +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + couldBeLatLong(value) → {boolean} +

+ + + + + + +
+ Determine whether the user could be typing a lat, long pair. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + is the currently entered query string.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Whether the current value could be a lat,long pair +due to the string NOT containing characters (e.g. a-z) that could not +be in a lat,long pair. +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

+ + + + + createBatchPayload(classes, ontology) → {string} +

+ + + + + + +
+ Create a payload for a batch request to the BioPortal API. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Array.<string> + + + + The classes to fetch
ontology + + +string +| + +object + + + + The ontology acronym or object with +acronym stored in the "ontology" property
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The JSON stringified payload +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + createHeaders() → {object} +

+ + + + + + +
+ Create the headers for a request to the BioPortal API. +
+ + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
Content-Type + + +string + + + + The content type of the request
Authorization + + +string + + + + The authorization header with the API +key
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The headers object +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + +
+ The default attributes for this model. All attributes not documented here +are detailed on the BioPortal API docs: +https://data.bioontology.org/documentation. +
+ + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
queryType + + +"children" +| + +"search" +| + +"ontology" + + + + The type of query +to perform. Only "children", "search", and "ontology" are supported.
searchTerm + + +string + + + + The term to search for. Only used when +queryType is "search".
collection + + +BioontologyResults + + + + The collection classes +returned from the query.
subTree + + +string + + + + The class ID to get the children of. Only +used when queryType is "children". e.g. +http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#MeasurementType
ontology + + +string + + + + The ontology acronym to query. e.g. "ECSO"
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The default attributes for this model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + +
+ The default attributes for this model. All attributes not documented here +are detailed on the BioPortal API docs: +https://data.bioontology.org/documentation. +
+ + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
collection + + +Backbone.Collection + + + + The collection of classes +fetched from BioPortal
apiKey + + +string + + + + The API key to use for requests to BioPortal. +If not set, the appModel's API key will be used.
apiBaseURL + + +string + + + + The base URL for the BioPortal API.
ontologyPrefix + + +string + + + + A string to prepend to ontology +acronyms to form the full ontology ID for batch requests. Note that this +is not the same as the ontology URL, as the ID starts with http not +https.
ontologies + + +Array.<string> + + + + The ontologies to search for classes +in, in order of priority. Only the acronyms are needed.
include + + +Array.<string> + + + + The fields to include in the response.
classesToFetch + + +Array.<string> + + + + The classes (classIds) to fetch +from BioPortal.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The default attributes for this model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + +
+ The default attributes for the OntologyClassModel. See also: +https://data.bioontology.org/documentation. +
+ + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +string + + + + The unique identifier for the ontology class.
prefLabel + + +string + + + + The preferred label for the ontology class.
definition + + +Array.<string> + + + + Definitions of the ontology class.
synonym + + +Array.<string> + + + + Synonyms of the ontology class.
obsolete + + +boolean + + + + Indicates if the class is obsolete.
subClassOf + + +Array.<string> + + + + An array of identifiers for parent classes in the ontology.
parents + + +Array.<object> + + + + Detailed parent class information including identifiers and links.
cui + + +Array.<string> + + + + Concept Unique Identifiers associated with the class.
semanticType + + +Array.<stringp> + + + + Semantic types associated with the class.
label + + +string + + + + Label of the class (may be empty).
prefixIRI + + +string + + + + Prefix IRI if available.
notation + + +string + + + + Notation number associated with the class.
xref + + +string + + + + External reference identifiers.
created + + +string + + + + Creation date of the class entry.
modified + + +string + + + + Last modification date of the class entry.
properties + + +object + + + + Additional properties specific to the ontology class.
'@id' + + +string + + + + The unique identifier for the ontology class.
'@type' + + +string + + + + The type of the entity in RDF/OWL.
links + + +object + + + + A collection of links related to the ontology class for API interaction.
'@context' + + +object + + + + Context for understanding the property values and relations.
ancestors + + +Array + + + + An array of ancestor classes of the ontology class.
children + + +Array + + + + An array of child classes of the ontology class.
notes + + +Array + + + + Additional notes associated with the ontology class.
childrenCount + + +number + + + + The number of children of the ontology class.
hasChildren + + +boolean + + + + Boolean indicating whether the ontology class has children.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The default attributes for this model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + +
+ The default attributes for the BioOntology model. For definitions, +see https://data.bioontology.org/documentation +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The default attributes +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
addFields + + +Array.<AdditionalField> + + + + A list of additional fields +which are not retrieved from the query service index, but which should be +added to the list of options. This can be used to add abstracted fields +which are a combination of multiple query fields, or to add a duplicate +field that has a different label.
commonFields + + +Array.<string> + + + + A list of query fields names to +display at the top of the menu, above all other category headers
categoriesToAlphabetize + + +Array.<string> + + + + The names of categories +that should have items sorted alphabetically. Names must exactly match +those in the Query Field model
excludeNonSearchable + + +boolean + + + + Whether or not to exclude +fields which are not searchable. Set to false to keep query fields that +are not searchable in the returned list
submenuStyle + + +string + + + + The submenu style is set to "accordion" +by default for this submodel
excludeFields + + +Array.<string> + + + + A list of query field names to +exclude from the list of options.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The default attributes for this model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
allowMulti + + +boolean + + + + Whether to allow users to select more +than one value.
allowAdditions + + +boolean + + + + Allows users to add their own +options not listed in options.
clearable + + +boolean + + + + Whether the dropdown can be cleared by +the user after selection.
submenuStyle + + +string + + + + Determines the display style of items +in categories ("list", "popout", "accordion").
hideEmptyCategoriesOnSearch + + +boolean + + + + Displays category +headers in the dropdown even with no results.
options + + +SearchSelectOptions + + + + Collection of +SearchSelectOption models that represent choices a user can select from.
selected + + +Array.<string> + + + + Currently selected values in the +dropdown.
separatorOptions + + +Array.<string> +| + +boolean + + + + For select inputs where +multiple values are allowed (allowMulti is true), a list of options that +can be used as separators between values. To turn off this feature, set +to false or an empty array.
separator + + +string + + + + The current separator to use between +selected values, must be one of the separatorOptions.
searchTerm + + +string + + + + The current search term being used to +filter options, if any. This will be updated by the view.
originalSubmenuStyle + + +string + + + + A reference to the original +submenu style since the submenu style can change during search. This will +be set automatically by the model during initialization.
apiSettings + + +object +| + +boolean + + + + Settings for retrieving data via +API, false if not using remote content.
placeholderText + + +string + + + + Text to show in the input field before +any value has been entered.
inputLabel + + +string + + + + Label for the input element.
buttonStyle + + +boolean + + + + Set this to true to render the dropdown +as more of a button-like interface. This works best for single-select +dropdowns.
icon + + +string +| + +boolean + + + + Set this to a FontAwesome icon to use +instead of the default dropdown (down arrow) icon. Works will with the +buttonStyle option.
fluid + + +boolean + + + + Set this to true to make the dropdown take up +the full width of its container.
compact + + +boolean + + + + Set this to true to make the dropdown more +compact, e.g. for the filter bar in the catalog search.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Default attributes for a SearchSelect model. +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() → {object} +

+ + + + + + + + + + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
icon + + +string + + + + The name of a Font Awesome 3.2.1 icon to display to +the left of the label (e.g. "lemon", "heart")
image + + +string + + + + The complete path to an image to use instead of an +icon. If both icon and image are provided, the icon will be used.
label + + +string + + + + The label to show for the option
description + + +string + + + + A description of the option, displayed as a +tooltip when the user hovers over the label
value + + +string + + + + If the value differs from the label, the value to +return when this option is selected (otherwise label is returned)
category + + +string + + + + If the option is part of a category, the name of +the category to display in the dropdown
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The default properties for a SearchSelectOption +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + defaults() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + encodeIfPresent(value) → {string} +

+ + + + + + +
+ Encode a value if it is exists +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value to encode
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The encoded value or null if the value is falsy +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + excludeFields(fieldsJSON) → {Array.<object>} +

+ + + + + + +
+ Filters out any objects in the fieldsJSON array that have a ".name" +property that matches one of the strings in the fieldsToExclude array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fieldsJSON + + +Array.<object> + + + + JSON returned from QueryFields.toJSON()
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The filtered fieldsJSON array +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + fetchClasses(classes) → {Promise.<Array.<Backbone.Model>>} +

+ + + + + + +
+ Fetch classes from the BioPortal API. This method is async and will +return a promise that resolves when the classes have been fetched. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Array.<string> + + + + The classes to fetch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves to an array +of Backbone models +
+ + + +
+
+ Type +
+
+ +Promise.<Array.<Backbone.Model>> + + +
+
+ + + + + + + + + + + + + +

+ + + + + fetchClassesFromOntology(classes, ontology) → {Promise.<object>} +

+ + + + + + +
+ Make a batch request for a given set of classes and a single ontology. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Array.<string> + + + + The classes to fetch
ontology + + +string + + + + The ontology to search in
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves to the response from +the BioPortal API +
+ + + +
+
+ Type +
+
+ +Promise.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + fetchFromOntologies() → {Promise.<Array.<object>>} +

+ + + + + + +
+ Fetch classes from the BioPortal API. This method is async and will +return a promise that resolves when the classes have been fetched. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves to an array of +objects containing the classes fetched from BioPortal +
+ + + +
+
+ Type +
+
+ +Promise.<Array.<object>> + + +
+
+ + + + + + + + + + + + + +

+ + + + + fetchQueryFields() → {Promise} +

+ + + + + + +
+ Fetches the query fields from the query service +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves with the query fields +collection +
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + + + + +

+ + + + + fieldToOption(field) → {object} +

+ + + + + + +
+ Converts an object that represents a QueryField model to the format +specified by the SearchSelectView.options +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
field + + +object + + + + An object with properties corresponding to a +QueryField model
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An object with properties that match the format +specified by the SearchSelectView.options +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + filterClassesToFetch() +

+ + + + + + +
+ If some of the classes to fetch are already in the collection, remove +them from the list of classes to fetch. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + finalizeFetch() +

+ + + + + + +
+ Finalize the fetch process. This will set the status to "fetched" and +trigger the "fetchComplete" event. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + formatResult(rawResult, forTemplate) → {object} +

+ + + + + + +
+ Formats a single result from the account lookup service +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rawResult + + +object + + + + The result from the account lookup service
forTemplate + + +boolean + + + + See formatResults
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - The formatted result +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + formatResults(results, forTemplate) → {Array.<object>} +

+ + + + + + +
+ Formats the results from the account lookup service for the dropdown +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
results + + +Array.<object> + + + + The results from the account lookup service
forTemplate + + +boolean + + + + Whether to format the results for the +template in the SearchSelect view or directly for Formantic-UI
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - The formatted results +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getAccountDetails(searchTerm) → {Promise.<Array.<object>>} +

+ + + + + + +
+ Promisify the getAccountsAutocomplete function from the LookupModel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
searchTerm + + +string + + + + The account ID, name, or partial name to search for
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - A promise that resolves with the results +
+ + + +
+
+ Type +
+
+ +Promise.<Array.<object>> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getCachedClasses(classes) → {Array.<Backbone.Model>} +

+ + + + + + +
+ Get the models for classes that have already been fetched from BioPortal. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Array.<string> + + + + The class IDs to get models for
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The models for the classes that have already +been fetched +
+ + + +
+
+ Type +
+
+ +Array.<Backbone.Model> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getCategoryNames() → {Array.<string>} +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An array of unique category names. +
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getChildren(classId) +

+ + + + + + +
+ Get the children of a given class ID and add them to the collection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classId + + +string + + + + The class ID to get the children of
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + getClasses(classes) → {Promise.<Array.<Backbone.Model>>} +

+ + + + + + +
+ Gets the models for given classes. For classes that exist already, the +model will be fetched from the collection. For classes that do not exist +yet, the bioportal API will be queried. The promise will resolve when all +models have been fetched. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Array.<string> + + + + The classes to fetch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ A promise that resolves to an array +of Backbone models +
+ + + +
+
+ Type +
+
+ +Promise.<Array.<Backbone.Model>> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getIncludeParam(queryType) → {string} +

+ + + + + + +
+ Construct the include url parameter for the BioPortal API +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
queryType + + +string + + + + The type of query to perform
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The include parameter for the BioPortal API +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

+ + + + + getNextPage() +

+ + + + + + +
+ Fetch the next page of results from the BioPortal API and add them to the +collection +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + getNextSeparator() → {string|null} +

+ + + + + + +
+ Get the next separator in the list of separator options. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - The next separator in the list of separator +options, or null if none. +
+ + + +
+
+ Type +
+
+ +string +| + +null + + +
+
+ + + + + + + + + + + + + +

+ + + + + getOptionByLabelOrValue(value) → {SearchSelectOption} +

+ + + + + + +
+ Get an option by its label or value. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value or label of the option to get.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The first option that has a matching value +or label. +
+ + + +
+
+ Type +
+
+ +SearchSelectOption + + +
+
+ + + + + + + + + + + + + +

+ + + + + getOptionsByCategory(category) → {Array.<SearchSelectOption>} +

+ + + + + + +
+ Get the select options that belong to a given category. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
category + + +string + + + + The category to get options for.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An array of options in the specified +category. +
+ + + +
+
+ Type +
+
+ +Array.<SearchSelectOption> + + +
+
+ + + + + + + + + + + + + +

+ + + + + getQueryFieldOptions() +

+ + + + + + +
+ Fetches the query fields from the query service, converts them to the +format required by the SearchSelectView, and sets them as the options +for this model +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + getSelectedModels() → {Array.<SearchSelectOption>} +

+ + + + + + +
+ Get the selected models from the options collection. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - The selected models from the options +collection. +
+ + + +
+
+ Type +
+
+ +Array.<SearchSelectOption> + + +
+
+ + + + + + + + + + + + + +

+ + + + + hasInvalidSelections() → {boolean|Array.<string>} +

+ + + + + + +
+ Check if there are any invalid selections in the selected values. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Returns false if there are no invalid +selections, or an array of invalid selection strings if there are any. +
+ + + +
+
+ Type +
+
+ +boolean +| + +Array.<string> + + +
+
+ + + + + + + + + + + + + +

+ + + + + initialize(_models, _options) +

+ + + + + + +
+ Initializes with option models, objects, or categorized options. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
_models + + +Array.<SearchSelectOption> +| + +Array.<object> +| + +object + + + + The options to +add to the collection. This can be an array of SearchSelectOption models, +an array of attributes for options models, or an object where each key is +a category and each value is an array of options. All will be +automatically converted to SearchSelectOption models for the collection.
_options + + +object + + + + The options for the collection. +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
parse + + +boolean + + + + Whether to parse the incoming data into +the expected format.
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Examples
+ +
// Initialize with an array of attributes
+const options = new SearchSelectOptions([
+ { label: "Option 1" },
+ { label: "Option 2" }
+]);
+ +
// Initialize with an object of categorized options
+const options = new SearchSelectOptions({
+  "Category A": [
+    { label: "Option 1" },
+    { label: "Option 2" }
+  "Category B": [
+    { label: "Option 3" },
+    { label: "Option 4" }
+});
+ + + + + + + + + +

+ + + + + initialize(attributes, _options) +

+ + + + + + +
+ Initialize the Bioontology mode +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + + +object + + + + The model attributes +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
apiKey + + +string + + + + An alternative API key to use. If not +set, the appModel's API key will be used.
+ +
_options + + +object + + + + The options object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize(attributes, _options) +

+ + + + + + +
+ Initialize the Bioontology mode +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + + +object + + + + The model attributes +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
apiKey + + +string + + + + An alternative API key to use. If not +set, the appModel's API key will be used.
+ +
_options + + +object + + + + The options object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize(attributes, options) +

+ + + + + + +
+ Initializes the QueryFieldSearchSelect model +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributes + + +object + + + + A literal object with model attributes
options + + +object + + + + A literal object with options +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
collectionQuery + + +boolean + + + + Set this to true to +automatically set the excludeFields and addFields to the collection query +defaults set in the appModel. See +AppModel#collectionQueryExcludeFields and +AppModel#collectionQuerySpecialFields.
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initialize() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + initializeFetch(classes) +

+ + + + + + +
+ Initialize the fetch process. This will set the status to "fetching" and +set the list of classes to fetch to the provided classes. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
classes + + +Array.<string> + + + + The classes to fetch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + isValidValue(value) → {boolean} +

+ + + + + + +
+ Checks if a given matches either a label or value in the collection of +options. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value or label to check for.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Returns true if the value is found in the +collection, false otherwise. +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

+ + + + + isValidValue(value) → {boolean} +

+ + + + + + +
+ Extends the isValidValue method of the SearchSelect model to allow for +the addition of fields that are excluded by default, if they are selected +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Returns true if the value is valid, false otherwise +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

+ + + + + isValidValue(value) → {boolean} +

+ + + + + + +
+ Checks if a value is one of the values in the options. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value to check for.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Returns true if the value is found in the +collection, false otherwise. +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

+ + + + + moveClassesToNotFound() +

+ + + + + + +
+ Move the classes that were not found to the list of classes not found. This +should be called after all classes have been fetched. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + optionsAsJSON(categorized) → {object|Array.<object>} +

+ + + + + + +
+ Returns the options as a JSON object. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
categorized + + +boolean + + + + Whether to return the options as +categorized. See @link{SearchSelectOptions#toJSON} for more information.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - The options as a JSON object. +
+ + + +
+
+ Type +
+
+ +object +| + +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + parse(data) → {Array} +

+ + + + + + +
+ Parses the incoming options data. This can handle both an array of +options (uncategorized) or an object with categories (categorized). +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Array.<object> +| + +object + + + + Either an array of option objects or an +object with categories.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ An array of option objects suitable for the collection. +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

+ + + + + parse(response, options) → {object} +

+ + + + + + +
+ Parse the response from the BioPortal API +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
response + + +object + + + + The response from the BioPortal API
options + + +object + + + + The options object +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
replaceCollection + + +boolean + + + + Whether to replace the +collection or add to it. Adds to it by default.
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The parsed response +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + parse() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + parse() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + recordError(error) +

+ + + + + + +
+ Record an error that occurred during the fetch process. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
error + + +Error + + + + The error that occurred
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + removeSelected(value, options) +

+ + + + + + +
+ Remove a value from the selected list. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value to remove from the selected list.
options + + +object + + + + Additional options to be passed to the set +method.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + renameCategory(oldCategory, newCategory) +

+ + + + + + +
+ Change the name of a category for all options in the collection. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
oldCategory + + +string + + + + The category to rename.
newCategory + + +string + + + + The new name for the category.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + resetPageInfo() +

+ + + + + + +
+ Clears the pagination info that has been fetched from the BioPortal API +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + responseAsync(settings, callback) +

+ + + + + + +
+ Handles the async response for the Accounts lookup +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
settings + + +object + + + + The settings object passed by Formantic-UI
callback + + +function + + + + The callback function passed by Formantic-UI
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + separatorRequired(value) → {boolean} +

+ + + + + + +
+ Determines if a separator is needed for the newly created, yet to be attached label. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + + The value of the label.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Returns true if a separator should be created, otherwise false. +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

+ + + + + setAddedFieldDetails(option) +

+ + + + + + +
+ For options that are added fields, not real query fields from the query +service, this method sets fields and types attributes on the option model +that are the real query fields that the added field represents. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
option + + +SearchSelectOption + + + + The option model to update
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setNextSeparator() +

+ + + + + + +
+ Set the next separator in the list of separator options. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setOptionsForPreselected() +

+ + + + + + +
+ Use the account lookup service to match the pre-selected values to the +account holder's name to use as a label. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setOptionsForPreselected() +

+ + + + + + +
+ This method is set for extended models that fetch options asynchronously +on search. This method should be overridden to fetch options from the API +for the values that are currently selected in the dropdown. This allows +those values to be populated with the correct label and icon. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + setSelected(values, options) +

+ + + + + + +
+ Change the values that are selected in the dropdown. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
values + + +string +| + +Array.<string> + + + + The value(s) to select.
options + + +object + + + + Additional options to be passed to the set +method.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + sortByProp(prop) +

+ + + + + + +
+ Sort the options by a given property. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
prop + + +string + + + + The property to sort by.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + sortFields(unsortedOptions) → {Array.<object>} +

+ + + + + + +
+ Sorts the fieldsJSON array by categoryOrder and then alphabetically +within each category if the category is specified in the +categoriesToAlphabetize property of this model. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
unsortedOptions + + +Array.<object> + + + + An array of objects that represent +attributes for SearchSelectOptions.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The sorted options +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + toAccordionItem() → {object} +

+ + + + + + +
+ Reformat for an accordion item +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Attributes for an accordion item model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + toJSON(categorizedopt) → {object|Array.<object>} +

+ + + + + + +
+ Return JSON representation of the collection. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
categorized + + +boolean + + + + + + <optional>
+ + + + + +
Whether to return the options as an object +with categories as keys (true) or as an array with categories as a +property on each option (false). If set to categorized, and the options +have no category, they will be placed in a default category with an empty +string key.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ JSON representation of the collection. +
+ + + +
+
+ Type +
+
+ +object +| + +Array.<object> + + +
+
+ + + + + + + + + + + + + +

+ + + + + toSearchSelectOption() → {object} +

+ + + + + + +
+ Reformat for a searchSelect option +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Attributes for a searchSelect option model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + toSearchSelectOption() → {object} +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Attributes for a searchSelect option model +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

+ + + + + updateOptions(options) +

+ + + + + + +
+ Update the options for the dropdown. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +object +| + +Array.<object> + + + + The new options to set for the dropdown
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + url() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + url() +

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + - + - Description - - + +

+ + - + + url() +

- - - taxonRankName - + - - - -string - - - - - The name of the taxonomic rank, for -example, Domain, Kingdom, etc. - - - - - taxonRankValue - - - - -string - - - - - The value for the given taxonomic rank, -for example, Animalia, Chordata, etc. - + +
- - - commonName - + - - - -Array.<string> + + - - + - + - + - Common name(s) for the taxon, for example -["Animal"] - + - - - taxonId - + - - - -Array.<Object> + + - - + +
Source:
+
+ - + - + - A taxon identifier from a controlled -vocabulary, for example, ITIS, NCBI, etc. -
Properties
+ +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + - -
NameTypeDescription
provider - - -string - - The provider of the taxon identifier, -given as a URI, for example http://www.itis.gov
value - - -string - - The identifier from the provider, for -example, 180092
+

+ + - - + + url() +

+ - - - taxonomicClassification - - - - -Array.<Object> - - - - - A nested taxonomic -classification, since taxonomy is represented as a hierarchy in EML. - - - - + + + @@ -479,7 +13991,7 @@
Properties
Source:
@@ -495,34 +14007,12 @@
Properties
- - - - -

Methods

- - - - - - -

- - - - couldBeLatLong(value) → {boolean} -

- - -
- Determine whether the user could be typing a lat, long pair. -
@@ -531,54 +14021,36 @@

+ + -

Parameters:
- - - - - - - - + +

+ + - + + waitForFetchComplete() → {Promise.<boolean>} +

+ - + - - - - - - - - - +
+ Wait for the fetch process to complete. This will return a promise that +resolves when the fetch process is complete. +
- - - - - - - -
NameTypeDescription
value - - -string - - is the currently entered query string.
@@ -614,7 +14086,7 @@
Parameters:
Source:
@@ -643,9 +14115,8 @@
Returns:
- Whether the current value could be a lat,long pair -due to the string NOT containing characters (e.g. a-z) that could not -be in a lat,long pair. + A promise that resolves to true if the fetch +process is complete, and false if it is not complete
@@ -656,7 +14127,7 @@
Returns:
-boolean +Promise.<boolean>
@@ -688,9 +14159,10 @@

- An additional field object contains the properties an additional query field to -add that are required to render it correctly. An additional query field is one -that does not actually exist in the query service index. + An additional field object contains the properties an additional query +field to add that are required to render it correctly. An additional +query field is one that does not actually exist in the query service +index.
@@ -699,7 +14171,7 @@

Type:

Source: src/js/collections/queryFields/QueryFields.jsSource: src/js/collections/queryFields/QueryFields.js { - var fieldModel = MetacatUI.queryFields.findWhere({ - name: newField, - }); - types.push(fieldModel.get("filterType")); - }); - - // Test of all the fields are of the same type - var allEqual = types.every((val, i, arr) => val === arr[0]); + if (!fields || fields.length === 0 || fields[0] === "") { + return defaultFilterType; + } - if (allEqual) { - return types[0]; + fields.forEach((newField) => { + const fieldModel = MetacatUI.queryFields.findWhere({ + name: newField, + }); + const newType = fieldModel?.get("filterType"); + if (newType) { + types.push(newType); } else { - return defaultFilterType; + // TODO: + // console.log("ERROR! No filter type found for field", newField); } - } catch (e) { - console.log( - "Failed to detect the required filter type in a Query Fields" + - " Collection, error message: " + - e, - ); + }); + + // Test of all the fields are of the same type + const allEqual = types.every((val, i, arr) => val === arr[0]); + + if (allEqual) { + return types[0]; } + return defaultFilterType; }, }, ); diff --git a/docs/docs/src_js_collections_searchSelect_SearchSelectOptions.js.html b/docs/docs/src_js_collections_searchSelect_SearchSelectOptions.js.html new file mode 100644 index 000000000..23dc2b4a7 --- /dev/null +++ b/docs/docs/src_js_collections_searchSelect_SearchSelectOptions.js.html @@ -0,0 +1,234 @@ + + + + + MetacatUI Dev Docs: Source: src/js/collections/searchSelect/SearchSelectOptions.js + + + + + + + + + + + + + + +
+ +

Source: src/js/collections/searchSelect/SearchSelectOptions.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "models/searchSelect/SearchSelectOption"], (
+  Backbone,
+  SearchSelectOption,
+) => {
+  /**
+   * @class SearchSelectOptions
+   * @classdesc A collection for managing dropdown options in a search
+   * select view.
+   * @classcategory Collections/SearchSelect
+   * @since 2.31.0
+   */
+  const SearchSelectOptions = Backbone.Collection.extend({
+    /** @lends SearchSelectOptions.prototype */
+
+    /** @inheritdoc */
+    model: SearchSelectOption,
+
+    /**
+     * Initializes with option models, objects, or categorized options.
+     * @param {SearchSelectOption[]|object[]|object} _models - The options to
+     * add to the collection. This can be an array of SearchSelectOption models,
+     * an array of attributes for options models, or an object where each key is
+     * a category and each value is an array of options. All will be
+     * automatically converted to SearchSelectOption models for the collection.
+     * @param {object} _options - The options for the collection.
+     * @param {boolean} _options.parse - Whether to parse the incoming data into
+     * the expected format.
+     * @example
+     * // Initialize with an array of attributes
+     * const options = new SearchSelectOptions([
+     *  { label: "Option 1" },
+     *  { label: "Option 2" }
+     * ]);
+     * @example
+     * // Initialize with an object of categorized options
+     * const options = new SearchSelectOptions({
+     *   "Category A": [
+     *     { label: "Option 1" },
+     *     { label: "Option 2" }
+     *   "Category B": [
+     *     { label: "Option 3" },
+     *     { label: "Option 4" }
+     * });
+     */
+    initialize(_models, _options) {},
+
+    /**
+     * Parses the incoming options data. This can handle both an array of
+     * options (uncategorized) or an object with categories (categorized).
+     * @param {object[] | object} data - Either an array of option objects or an
+     * object with categories.
+     * @returns {Array} An array of option objects suitable for the collection.
+     */
+    parse(data) {
+      let parsedData = [];
+
+      if (Array.isArray(data)) {
+        parsedData = data;
+      } else if (typeof data === "object") {
+        Object.keys(data).forEach((category) => {
+          data[category].forEach((opt) => {
+            // Add the category to the option object
+            parsedData.push({ ...opt, category });
+          });
+        });
+      }
+      return parsedData;
+    },
+
+    /**
+     * @returns {string[]} An array of unique category names.
+     */
+    getCategoryNames() {
+      const categories = this.pluck("category");
+      return [...new Set(categories)];
+    },
+
+    /**
+     * Get the select options that belong to a given category.
+     * @param {string} category - The category to get options for.
+     * @returns {SearchSelectOption[]} An array of options in the specified
+     * category.
+     */
+    getOptionsByCategory(category) {
+      return this.filter((option) => option.get("category") === category);
+    },
+
+    /**
+     * Change the name of a category for all options in the collection.
+     * @param {string} oldCategory The category to rename.
+     * @param {string} newCategory The new name for the category.
+     */
+    renameCategory(oldCategory, newCategory) {
+      const oldOptions = this.getOptionsByCategory(oldCategory);
+      oldOptions.forEach((option) => option.set("category", newCategory));
+    },
+
+    /**
+     * Sort the options by a given property.
+     * @param {string} prop - The property to sort by.
+     */
+    sortByProp(prop) {
+      this.comparator = (model) => model.get(prop);
+      this.sort();
+    },
+
+    /**
+     * Checks if a given matches either a label or value in the collection of
+     * options.
+     * @param {string} value - The value or label to check for.
+     * @returns {boolean} - Returns true if the value is found in the
+     * collection, false otherwise.
+     */
+    isValidValue(value) {
+      return this.some(
+        (option) =>
+          option.get("value") === value || option.get("label") === value,
+      );
+    },
+
+    /**
+     * Get an option by its label or value.
+     * @param {string} value - The value or label of the option to get.
+     * @returns {SearchSelectOption} The first option that has a matching value
+     * or label.
+     */
+    getOptionByLabelOrValue(value) {
+      let optModel = this.find(
+        (option) =>
+          option.get("value") === value || option.get("label") === value,
+      );
+      if (!optModel) {
+        // try converting the value to a string
+        optModel = this.find(
+          (option) =>
+            option.get("value") === String(value) ||
+            option.get("label") === String(value),
+        );
+      }
+      return optModel;
+    },
+
+    /**
+     * Return JSON representation of the collection.
+     * @param {boolean} [categorized] Whether to return the options as an object
+     * with categories as keys (true) or as an array with categories as a
+     * property on each option (false). If set to categorized, and the options
+     * have no category, they will be placed in a default category with an empty
+     * string key.
+     * @returns {object|object[]} JSON representation of the collection.
+     */
+    toJSON(categorized = false) {
+      if (!categorized) {
+        return this.map((option) => option.toJSON());
+      }
+
+      let categories = this.getCategoryNames();
+      if (categories.length === 0) categories = [""];
+      const categorizedOptions = {};
+
+      categories.forEach((category) => {
+        const options = this.getOptionsByCategory(category);
+        categorizedOptions[category] = options.map((option) => option.toJSON());
+      });
+
+      return categorizedOptions;
+    },
+  });
+
+  return SearchSelectOptions;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_common_IconUtilities.js.html b/docs/docs/src_js_common_IconUtilities.js.html index 59f68a64a..ac7b4ab6a 100644 --- a/docs/docs/src_js_common_IconUtilities.js.html +++ b/docs/docs/src_js_common_IconUtilities.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_common_SearchParams.js.html b/docs/docs/src_js_common_SearchParams.js.html index a0c8d20a4..0e7163257 100644 --- a/docs/docs/src_js_common_SearchParams.js.html +++ b/docs/docs/src_js_common_SearchParams.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_common_Utilities.js.html b/docs/docs/src_js_common_Utilities.js.html index 5321b8db0..9807d050e 100644 --- a/docs/docs/src_js_common_Utilities.js.html +++ b/docs/docs/src_js_common_Utilities.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -44,8 +44,13 @@

Source: src/js/common/Utilities.js

-
define([], () => {
-  "use strict";
+            
"use strict";
+
+define([], () => {
+  const KIBIBYTE = 1024;
+  const MEBIBYTE = KIBIBYTE * 1024;
+  const GIBIBYTE = MEBIBYTE * 1024;
+  const TEBIBYTE = GIBIBYTE * 1024;
 
   /**
    * @namespace Utilities
@@ -202,6 +207,93 @@ 

Source: src/js/common/Utilities.js

} return 0; // No decimal places }, + + /** + * Checks if two objects are deeply equal. Simpler than the _.isEqual function. + * @param {object} a - The first object to compare + * @param {object} b - The second object to compare + * @returns {boolean} True if the objects are deeply equal + * @since 2.31.0 + */ + deepEqual(a, b) { + if (a === b) return true; + + if (Array.isArray(a) && Array.isArray(b)) { + // Quick check for empty arrays + if (a.length === 0 && b.length === 0) return true; + if (a.length !== b.length) return false; + return a.every((value, index) => this.deepEqual(value, b[index])); + } + + if ( + typeof a === "object" && + a !== null && + typeof b === "object" && + b !== null + ) { + const keysA = Object.keys(a); + const keysB = Object.keys(b); + + if (keysA.length !== keysB.length) return false; + + return keysA.every( + (key) => keysB.includes(key) && this.deepEqual(a[key], b[key]), + ); + } + + return false; + }, + + /** + * Removes default values from a model's JSON representation + * @param {Backbone.Model} model - The model to remove defaults from + * @param {string[]} [removeProps] - An array of additional properties to remove from the model + * @returns {object} The JSON representation of the model with defaults removed + * @since 2.31.0 + */ + toJSONWithoutDefaults(model, removeProps = []) { + const json = model.toJSON(); + const defaults = model.defaults(); + + Object.keys(defaults).forEach((key) => { + if (removeProps.includes(key)) { + delete json[key]; + } else if (this.deepEqual(json[key], defaults[key])) { + delete json[key]; + } + }); + + return json; + }, + + /** + * Convert number of bytes into human readable format + * @param integer bytes Number of bytes to convert + * @param integer precision Number of digits after the decimal separator + * @param bytes + * @param precision + * @returns string + */ + bytesToSize(bytes, precision = 0) { + if (typeof bytes === "undefined") return `0 B`; + + if (bytes >= 0 && bytes < KIBIBYTE) { + return `${bytes} B`; + } + if (bytes >= KIBIBYTE && bytes < MEBIBYTE) { + return `${(bytes / KIBIBYTE).toFixed(precision)} KiB`; + } + if (bytes >= MEBIBYTE && bytes < GIBIBYTE) { + return `${(bytes / MEBIBYTE).toFixed(precision)} MiB`; + } + if (bytes >= GIBIBYTE && bytes < TEBIBYTE) { + return `${(bytes / GIBIBYTE).toFixed(precision)} GiB`; + } + if (bytes >= TEBIBYTE) { + return `${(bytes / TEBIBYTE).toFixed(precision)} TiB`; + } + return `${bytes} B`; + }, }; return Utilities; diff --git a/docs/docs/src_js_models_AccessRule.js.html b/docs/docs/src_js_models_AccessRule.js.html index eb1c3518b..2fddcc30a 100644 --- a/docs/docs/src_js_models_AccessRule.js.html +++ b/docs/docs/src_js_models_AccessRule.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_AppModel.js.html b/docs/docs/src_js_models_AppModel.js.html index 0165d0a20..34f78a2bc 100644 --- a/docs/docs/src_js_models_AppModel.js.html +++ b/docs/docs/src_js_models_AppModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -2147,9 +2147,17 @@

Source: src/js/models/AppModel.js

/** * The Bioportal REST API URL, which is set dynamically only if a bioportalAPIKey is configured * @type {string} - * @default "https://data.bioontology.org/search" + * @deprecated since 2.31.0 */ bioportalSearchUrl: "https://data.bioontology.org/search", + /** + * The Bioportal REST API URL, which is used for looking up ontology information + * @see {@link https://data.bioontology.org/documentation} + * @type {string} + * @default "https://data.bioontology.org" + * @since 2.31.0 + */ + bioportalApiBaseUrl: "https://data.bioontology.org", /** * This attribute stores cache of ontology information that is looked up in Bioportal, so that duplicate REST calls don't need to be made. * @type {object} @@ -2161,6 +2169,73 @@

Source: src/js/models/AppModel.js

*/ showAnnotationIndicator: false, + /** + * The list of Bioportal ontologies that are available for searching & + * labeling data in the repository. These are the ontologies that will + * be displayed in the bioontology browser, and the ontologies that a + * user can search within when querying data with the sem_annotation + * field. Set a subTree property to limit the ontology to a particular + * class. For the full list of possible ontologies, see the Bioportal + * website: https://bioportal.bioontology.org/ontologies + * @type {Array.<{label: string, ontology: string, subTree: string, icon: string}>} + * @since 2.31.0 + */ + bioportalOntologies: [ + { + label: "The Ecosystem Ontology", + ontology: "ECSO", + icon: "leaf", + }, + { + label: "Sensitive Data", + ontology: "SENSO", + icon: "lock", + }, + { + label: "Salmon", + ontology: "SALMON", + icon: "anchor", + }, + { + label: "Arctic Report Card", + ontology: "ARCRC", + icon: "asterisk", + }, + { + label: "ADC Academic Disciplines", + ontology: "ADCAD", + icon: "briefcase", + }, + { + label: "MOSAiC", + ontology: "MOSAIC", + icon: "barcode", + }, + { + label: "NCBI Organismal Classification", + ontology: "NCBITAXON", + }, + { + label: "The State of Alaska's Salmon and People", + ontology: "SASAP", + icon: "group", + }, + { + label: "Chemical Entities of Biological Interest", + ontology: "CHEBI", + icon: "beaker", + }, + { + label: "Scientific Workflow Provenance", + ontology: "ProvONE", + icon: "code", + }, + { + label: "Extensible Observation Ontology", + ontology: "OBOE", + }, + ], + /** * A list of unsupported User-Agent regular expressions for browsers that will not work well with MetacatUI. * A warning message will display on the page for anyone using one of these browsers. diff --git a/docs/docs/src_js_models_CitationModel.js.html b/docs/docs/src_js_models_CitationModel.js.html index 34083e347..5549a683f 100644 --- a/docs/docs/src_js_models_CitationModel.js.html +++ b/docs/docs/src_js_models_CitationModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -46,12 +46,12 @@

Source: src/js/models/CitationModel.js

"use strict";
 
-define(["jquery", "underscore", "backbone", "collections/Citations"], function (
+define(["jquery", "underscore", "backbone", "collections/Citations"], (
   $,
   _,
   Backbone,
   Citations,
-) {
+) => {
   /**
    * @class CitationModel
    * @classdesc A Citation Model represents a single Citation Object returned by
@@ -60,10 +60,10 @@ 

Source: src/js/models/CitationModel.js

* those models. A Citation Model can represent a citation to a local * MetacatUI object, or an external document or publication. * @classcategory Models - * @extends Backbone.Model + * @augments Backbone.Model * @see https://app.swaggerhub.com/apis/nenuji/data-metrics */ - var Citation = Backbone.Model.extend( + const Citation = Backbone.Model.extend( /** @lends CitationModel.prototype */ { /** * The name of this type of model @@ -74,7 +74,7 @@

Source: src/js/models/CitationModel.js

/** * The default Citation fields * @name CitationModel#defaults - * @type {Object} + * @type {object} * @property {string} origin - text of authors who published the source * dataset / document / article * @property {string[]} originArray - array of authors who published the @@ -125,7 +125,7 @@

Source: src/js/models/CitationModel.js

* the URL to the DOI landing page for the object being cited. This will * automatically be set when the seriesId attribute is set. */ - defaults: function () { + defaults() { return { origin: null, originArray: [], @@ -153,10 +153,10 @@

Source: src/js/models/CitationModel.js

* functions that return the value of an attribute for this Citation Model * given a source model. The source model can be a SolrResultsModel, a * DataONEObjectModel, or an extension of either of those models. - * @returns {Object} - An object that maps the name of the CitationModel + * @returns {object} - An object that maps the name of the CitationModel * attribute to the function that returns the value for that attribute. */ - attrGetters: function () { + attrGetters() { return { year_of_publishing: this.getYearFromSourceModel, title: this.getTitleFromSourceModel, @@ -171,11 +171,11 @@

Source: src/js/models/CitationModel.js

/** * Override the default Backbone.Model.parse() method to convert the * citationMetadata object into a nested collection of CitationModels. - * @param {Object} response - The response from the metrics-service API - * @param {Object} options - Options to pass to the parse() method. - * @returns {Object} The parsed response + * @param {object} response - The response from the metrics-service API + * @param {object} options - Options to pass to the parse() method. + * @returns {object} The parsed response */ - parse: function (response) { + parse(response) { try { // strings that need formatting when coming from the metrics-service: const toFormat = ["journal", "page", "volume", "publisher"]; @@ -193,7 +193,7 @@

Source: src/js/models/CitationModel.js

sID = this.URLtoDOI(sID); } if (!sID.startsWith("doi:")) { - sID = "doi:" + sID; + sID = `doi:${sID}`; } response.source_id = sID; } @@ -201,6 +201,11 @@

Source: src/js/models/CitationModel.js

// Format the citation metadata = DataONE datasets cited by this // citation (external document) const cm = response.citationMetadata; + + // We use the inline require here in addition to the define above to + // avoid an issue caused by the circular dependency between + // CitationModel and Citations + const Citations = require("collections/Citations"); if (cm) { if (cm && !(cm instanceof Citations)) { const citationMetadata = Object.entries(cm).map(([pid, data]) => { @@ -225,11 +230,10 @@

Source: src/js/models/CitationModel.js

// exists for the given PID. // DOIs from the metrics service are not prefixed with "doi:" if (this.isDOI(pid) && !pid.startsWith("doi:")) { - pid = "doi:" + pid; + pid = `doi:${pid}`; } item.pid = pid; - item.view_url = - MetacatUI.root + "/view/" + encodeURIComponent(pid); + item.view_url = `${MetacatUI.root}/view/${encodeURIComponent(pid)}`; return item; }); @@ -253,15 +257,14 @@

Source: src/js/models/CitationModel.js

* including: origin and originArray; pid and pid_url; seriesId and * seriesId_url. This method will prevent the sourceModel attribute from * being set here. - * - * @param {string|Object} key - The attribute name to set, or an object of + * @param {string | object} key - The attribute name to set, or an object of * attribute names and values to set. - * @param {string|number|Object} val - The value to set the attribute to. - * @param {Object} options - Options to pass to the set() method. + * @param {string | number | object} val - The value to set the attribute to. + * @param {object} options - Options to pass to the set() method. * @see https://backbonejs.org/#Model-set * @since 2.23.0 */ - set: function (key, val, options) { + set(key, val, options) { try { if (key == null) return this; @@ -294,7 +297,7 @@

Source: src/js/models/CitationModel.js

) { const strToArray = this.originToArray(attrs.origin); const arrayToStr = this.originArrayToString(attrs.originArray); - if (!!arrayToStr) { + if (arrayToStr) { attrs.origin = arrayToStr; } else { attrs.originArray = strToArray; @@ -413,9 +416,10 @@

Source: src/js/models/CitationModel.js

* SolrResult or a model that is a DataONEObject or an extended * DataONEObject. If no model is passed, then the model will be reset to the * default attributes. + * @param newSourceModel * @since 2.23.0 */ - populateFromModel: function (newSourceModel) { + populateFromModel(newSourceModel) { try { // Populate this model from the new sourceModel @@ -449,7 +453,7 @@

Source: src/js/models/CitationModel.js

* dateUploaded (both in SolrResult & ScienceMetadata/EML models). Lastly * check datePublished (found in ScienceMetadata/EML models only.) * @param {Backbone.Model} sourceModel - The model to get the year from - * @returns {Number} - The year + * @returns {number} - The year * @since 2.23.0 */ getYearFromSourceModel(sourceModel) { @@ -472,7 +476,7 @@

Source: src/js/models/CitationModel.js

/** * Get the title from the sourceModel * @param {Backbone.Model} sourceModel - The model to get the title from - * @returns {String} - The title + * @returns {string} - The title * @since 2.23.0 */ getTitleFromSourceModel(sourceModel) { @@ -490,8 +494,8 @@

Source: src/js/models/CitationModel.js

ext = ext ? ext[0].replace(".", "").toUpperCase() : ext; // Remove the extension and replace underscores with spaces fn = fn.replace(extRegex, "").replace(/_+/g, " "); - title = fn ? fn : title; - title = title && ext ? title + " [" + ext + "]" : title; + title = fn || title; + title = title && ext ? `${title} [${ext}]` : title; } return title; } catch (error) { @@ -512,7 +516,7 @@

Source: src/js/models/CitationModel.js

* If it is, then use the repository name. If there is no datasource * attribute, then use the current member node's name. * @param {Backbone.Model} sourceModel - The model to get the journal from - * @returns {String} - The journal + * @returns {string} - The journal * @since 2.23.0 */ getJournalFromSourceModel(sourceModel) { @@ -590,7 +594,7 @@

Source: src/js/models/CitationModel.js

/** * Get the pid from the sourceModel. First look for id, then identifier. * @param {Backbone.Model} sourceModel - The model to get the pid from - * @returns {String} - The pid + * @returns {string} - The pid * @since 2.23.0 */ getPidFromSourceModel(sourceModel) { @@ -612,7 +616,7 @@

Source: src/js/models/CitationModel.js

* Get the seriesId from the sourceModel. Simply looks for the seriesId * attribute. * @param {Backbone.Model} sourceModel - The model to get the seriesId from - * @returns {String} - The seriesId + * @returns {string} - The seriesId * @since 2.23.0 */ getSeriesIdFromSourceModel(sourceModel) { @@ -635,7 +639,7 @@

Source: src/js/models/CitationModel.js

* models, as well as Portal models. If the sourceModel doesn't have a * createViewURL() method, then use the default viewUrl (null) * @param {Backbone.Model} sourceModel - The model to get the viewUrl from - * @returns {String} - The viewUrl, or null if the sourceModel doesn't have + * @returns {string} - The viewUrl, or null if the sourceModel doesn't have * a createViewURL() method. * @since 2.23.0 */ @@ -643,9 +647,8 @@

Source: src/js/models/CitationModel.js

try { if (sourceModel && sourceModel.createViewURL) { return sourceModel.createViewURL(); - } else { - return this.defaults().viewUrl; } + return this.defaults().viewUrl; } catch (error) { console.log( "Error getting the viewUrl from the sourceModel. Model and error:", @@ -662,7 +665,7 @@

Source: src/js/models/CitationModel.js

* @returns {string} Returns the author as a string if it was an EMLParty * with any incorrectly escaped characters corrected. */ - formatAuthor: function (author) { + formatAuthor(author) { try { // Update the origin array asynchonously if the author is an ORCID if (this.isOrcid(author)) this.originArrayFromOrcid(author); @@ -695,7 +698,7 @@

Source: src/js/models/CitationModel.js

* it exists. * @since 2.23.0 */ - formatTitle: function (title) { + formatTitle(title) { if (!title) return ""; return title.replace(/\.+$/, "").trim(); }, @@ -709,7 +712,7 @@

Source: src/js/models/CitationModel.js

* with an empty string. * @since 2.23.0 */ - formatMetricsServiceString: function (str) { + formatMetricsServiceString(str) { if (!str) return ""; // The metrics service returns "NULL" if there is no data str = str === "NULL" ? "" : str; @@ -734,13 +737,13 @@

Source: src/js/models/CitationModel.js

* K. W. Li", "J.R. Lovvorn". Last name prefixes like "van" or "de" are * stored as a "non-dropping particle". See: * {@link https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html#name-variables} - * * @param {str} author The author string to convert - * @returns {Object} Returns an object with the author's name in CSL JSON + * @param str + * @returns {object} Returns an object with the author's name in CSL JSON * format. * @since 2.23.0 */ - nameStrToCSLJSON: function (str) { + nameStrToCSLJSON(str) { if (!str) return null; const name = {}; str = this.formatMetricsServiceString(str); @@ -749,7 +752,7 @@

Source: src/js/models/CitationModel.js

// name, first name". Move the first name to the front of the string. if (str.split(",").length == 2) { const parts = str.split(","); - str = parts[1].trim() + " " + parts[0].trim(); + str = `${parts[1].trim()} ${parts[0].trim()}`; } const parts = str @@ -784,12 +787,12 @@

Source: src/js/models/CitationModel.js

/** * Given a date, extract the year as a number. - * @param {Date|String|Number} date The date to extract the year from - * @returns {Number} Returns the year as a number, or null if the date is + * @param {Date | string | number} date The date to extract the year from + * @returns {number} Returns the year as a number, or null if the date is * invalid. * @since 2.23.0 */ - yearFromDate: function (date) { + yearFromDate(date) { try { if (!date) return null; // If Date is already a year (Number object with 4 digits), return it @@ -797,7 +800,7 @@

Source: src/js/models/CitationModel.js

return date; } // If it is a string with 4 digits, return it as an integer. Use regex. - if (typeof date == "string" && /^\d{4}$/.test(date)) { + if (typeof date === "string" && /^\d{4}$/.test(date)) { return parseInt(date); } // Check if the date is a Date object @@ -821,7 +824,7 @@

Source: src/js/models/CitationModel.js

* @returns {boolean} Returns true if the ORCID is valid, false otherwise * @since 2.23.0 */ - isOrcid: function (orcid) { + isOrcid(orcid) { try { if (!orcid) return false; const regex = new RegExp( @@ -840,7 +843,7 @@

Source: src/js/models/CitationModel.js

* @param {string} orcid The ORCID to get the name for * @since 2.23.0 */ - originArrayFromOrcid: function (orcid) { + originArrayFromOrcid(orcid) { try { const request = { term: orcid }; const model = this; @@ -849,7 +852,7 @@

Source: src/js/models/CitationModel.js

let name = null; if (response) { if (Array.isArray(response)) { - const label = response[0].label; + const { label } = response[0]; if (label) { // Name is the format "Min Liew // (http://orcid.org/0000-0002-5156-4610)" We want to return @@ -880,7 +883,7 @@

Source: src/js/models/CitationModel.js

* the given node * @since 2.23.0 */ - isFromNode: function (node) { + isFromNode(node) { try { const sourceModel = this.get("sourceModel"); return ( @@ -907,12 +910,12 @@

Source: src/js/models/CitationModel.js

* @returns {Array} - An array of authors * @since 2.23.0 */ - originToArray: function (origin) { + originToArray(origin) { try { if (!origin) { return this.defaults().originArray; } - let originArray = origin ? origin.split(", ") : []; + const originArray = origin ? origin.split(", ") : []; return originArray.map((author) => this.formatAuthor(author)); } catch (error) { console.log( @@ -925,11 +928,12 @@

Source: src/js/models/CitationModel.js

/** * Convert the origin array to a string. + * @param originArray * @returns {string} - The origin string. If a falsy value is passed in, * then the default origin attribute of the model is returned. * @since 2.23.0 */ - originArrayToString: function (originArray) { + originArrayToString(originArray) { try { if (!originArray || !originArray.length) { return this.defaults().origin; @@ -941,9 +945,9 @@

Source: src/js/models/CitationModel.js

.map((a) => { if (!a) return null; const ndp = a["non-dropping-particle"]; - let name = - (a.given ? a.given + " " : "") + - (ndp ? ndp + " " : "") + + const name = + (a.given ? `${a.given} ` : "") + + (ndp ? `${ndp} ` : "") + (a.family ? a.family : ""); return (name || a.literal || "").trim(); }) @@ -967,7 +971,7 @@

Source: src/js/models/CitationModel.js

* @see AppModel#archivedContentIsIndexed * @since 2.23.0 */ - isArchivedAndNotIndexed: function () { + isArchivedAndNotIndexed() { return this.isArchived() && !this.archivedContentIsIndexed(); }, @@ -978,7 +982,7 @@

Source: src/js/models/CitationModel.js

* that is true. * @since 2.23.0 */ - isArchived: function () { + isArchived() { return ( this.sourceModel && this.sourceModel.get && @@ -993,7 +997,7 @@

Source: src/js/models/CitationModel.js

* index. * @since 2.23.0 */ - archivedContentIsIndexed: function () { + archivedContentIsIndexed() { return MetacatUI.appModel.get("archivedContentIsIndexed"); }, @@ -1004,7 +1008,7 @@

Source: src/js/models/CitationModel.js

* @returns {string} - The DOI string without any prefixes. * @since 2.23.0 */ - removeAllDOIPrefixes: function (str) { + removeAllDOIPrefixes(str) { if (!str) return ""; // Remove https and http prefixes str = str.replace(/^(https?:\/\/)?/, ""); @@ -1018,10 +1022,11 @@

Source: src/js/models/CitationModel.js

/** * Check if a string is a valid DOI. * @param {string} doi - The string to check. + * @param str * @returns {boolean} - True if the string is a valid DOI, false otherwise. * @since 2.23.0 */ - isDOI: function (str) { + isDOI(str) { return MetacatUI.appModel.isDOI(str); }, @@ -1035,7 +1040,7 @@

Source: src/js/models/CitationModel.js

* @returns {string} - The DOI URL * @since 2.23.0 */ - DOItoURL: function (str) { + DOItoURL(str) { return MetacatUI.appModel.DOItoURL(str); }, @@ -1048,7 +1053,7 @@

Source: src/js/models/CitationModel.js

* @returns {string} - The DOI string, including the "doi:" prefix * @since 2.23.0 */ - URLtoDOI: function (url) { + URLtoDOI(url) { return MetacatUI.appModel.URLtoDOI(url); }, @@ -1058,7 +1063,7 @@

Source: src/js/models/CitationModel.js

* of the pid, if it is a DOI. Otherwise, returns null. * @since 2.23.0 */ - findDOI: function () { + findDOI() { try { if (!this.sourceModel || !this.sourceModel.isDOI) return null; const seriesID = this.get("seriesId"); @@ -1080,8 +1085,8 @@

Source: src/js/models/CitationModel.js

* @returns {boolean} - True if the citation has a DOI * @since 2.23.0 */ - hasDOI: function () { - return this.findDOI() ? true : false; + hasDOI() { + return !!this.findDOI(); }, /** @@ -1093,7 +1098,7 @@

Source: src/js/models/CitationModel.js

* @since 2.23.0 * @see DataONEObject#getUploadStatus */ - getUploadStatus: function () { + getUploadStatus() { return this.sourceModel ? this.sourceModel.get("uploadStatus") : null; }, @@ -1104,7 +1109,7 @@

Source: src/js/models/CitationModel.js

* @returns {string} Returns the URL for the citation or an empty string. * @since 2.23.0 */ - getURL: function () { + getURL() { const urlSources = ["view_url", "source_url", "sid_url", "pid_url"]; for (let i = 0; i < urlSources.length; i++) { const url = this.get(urlSources[i]); @@ -1121,7 +1126,7 @@

Source: src/js/models/CitationModel.js

* empty string. * @since 2.23.0 */ - getID: function () { + getID() { const idSources = ["pid", "seriesId", "source_url"]; for (let i = 0; i < idSources.length; i++) { const id = this.get(idSources[i]); diff --git a/docs/docs/src_js_models_CollectionModel.js.html b/docs/docs/src_js_models_CollectionModel.js.html index 2c7a4f524..85f9300c8 100644 --- a/docs/docs/src_js_models_CollectionModel.js.html +++ b/docs/docs/src_js_models_CollectionModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_DataONEObject.js.html b/docs/docs/src_js_models_DataONEObject.js.html index bf81e15bf..dd04496e9 100644 --- a/docs/docs/src_js_models_DataONEObject.js.html +++ b/docs/docs/src_js_models_DataONEObject.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -52,19 +52,20 @@

Source: src/js/models/DataONEObject.js

"he", "collections/AccessPolicy", "collections/ObjectFormats", + "common/Utilities", "md5", -], function ($, _, Backbone, uuid, he, AccessPolicy, ObjectFormats, md5) { +], ($, _, Backbone, uuid, he, AccessPolicy, ObjectFormats, Utilities, md5) => { /** - * @class DataONEObject - * @classdesc A DataONEObject represents a DataONE object, such as a data file, + * @class DataONEObject + * @classdesc A DataONEObject represents a DataONE object, such as a data file, a science metadata object, or a resource map. It stores the system metadata attributes for the object, performs updates to the system metadata, and other basic DataONE API functions. This model can be extended to provide specific functionality for different object types, such as the {@link ScienceMetadata} model and the {@link EML211} model. - * @classcategory Models - * @augments Backbone.Model - */ + * @classcategory Models + * @augments Backbone.Model + */ var DataONEObject = Backbone.Model.extend( /** @lends DataONEObject.prototype */ { type: "DataONEObject", @@ -72,7 +73,7 @@

Source: src/js/models/DataONEObject.js

PROV: "http://www.w3.org/ns/prov#", PROVONE: "http://purl.dataone.org/provone/2015/01/15/ontology#", - defaults: function () { + defaults() { return { // System Metadata attributes serialVersion: null, @@ -84,7 +85,7 @@

Source: src/js/models/DataONEObject.js

checksumAlgorithm: "MD5", submitter: null, rightsHolder: null, - accessPolicy: [], //An array of accessPolicy literal JS objects + accessPolicy: [], // An array of accessPolicy literal JS objects replicationAllowed: null, replicationPolicy: [], obsoletes: null, @@ -108,7 +109,7 @@

Source: src/js/models/DataONEObject.js

readPermission: null, isPublic: null, dateModified: null, - id: "urn:uuid:" + uuid.v4(), + id: `urn:uuid:${uuid.v4()}`, sizeStr: null, type: "", // Data, Metadata, or DataPackage formatType: "", @@ -121,30 +122,30 @@

Source: src/js/models/DataONEObject.js

nodeLevel: 0, // Indicates hierarchy level in the view for indentation sortOrder: 2, // Metadata: 1, Data: 2, DataPackage: 3 synced: false, // True if the full model has been synced - uploadStatus: null, //c=complete, p=in progress, q=queued, e=error, w=warning, no upload status=not in queue + uploadStatus: null, // c=complete, p=in progress, q=queued, e=error, w=warning, no upload status=not in queue uploadProgress: null, - sysMetaUploadStatus: null, //c=complete, p=in progress, q=queued, e=error, l=loading, no upload status=not in queue + sysMetaUploadStatus: null, // c=complete, p=in progress, q=queued, e=error, l=loading, no upload status=not in queue percentLoaded: 0, // Percent the file is read before caclculating the md5 sum uploadFile: null, // The file reference to be uploaded (JS object: File) errorMessage: null, sysMetaErrorCode: null, // The status code given when there is an error updating the system metadata numSaveAttempts: 0, - notFound: false, //Whether or not this object was found in the system + notFound: false, // Whether or not this object was found in the system originalAttrs: [], // An array of original attributes in a DataONEObject changed: false, // If any attributes have been changed, including attrs in nested objects hasContentChanges: false, // If attributes outside of originalAttrs have been changed sysMetaXML: null, // A cached original version of the fetched system metadata document objectXML: null, // A cached version of the object fetched from the server isAuthorized: null, // If the stated permission is authorized by the user - isAuthorized_read: null, //If the user has permission to read - isAuthorized_write: null, //If the user has permission to write - isAuthorized_changePermission: null, //If the user has permission to changePermission - createSeriesId: false, //If true, a seriesId will be created when this object is saved. - collections: [], //References to collections that this model is in - possibleAuthMNs: [], //A list of possible authoritative MNs of this object + isAuthorized_read: null, // If the user has permission to read + isAuthorized_write: null, // If the user has permission to write + isAuthorized_changePermission: null, // If the user has permission to changePermission + createSeriesId: false, // If true, a seriesId will be created when this object is saved. + collections: [], // References to collections that this model is in + possibleAuthMNs: [], // A list of possible authoritative MNs of this object useAltRepo: false, - isLoadingFiles: false, //Only relevant to Resource Map objects. Is true if there is at least one file still loading into the package. - numLoadingFiles: 0, //Only relevant to Resource Map objects. The number of files still loading into the package. + isLoadingFiles: false, // Only relevant to Resource Map objects. Is true if there is at least one file still loading into the package. + numLoadingFiles: 0, // Only relevant to Resource Map objects. The number of files still loading into the package. provSources: [], provDerivations: [], prov_generated: [], @@ -165,13 +166,20 @@

Source: src/js/models/DataONEObject.js

}; }, - initialize: function (attrs, options) { - if (typeof attrs == "undefined") var attrs = {}; + initialize(attrs, options) { + if (typeof attrs === "undefined") var attrs = {}; this.set("accessPolicy", this.createAccessPolicy()); - this.on("change:size", this.bytesToSize); - if (attrs.size) this.bytesToSize(); + const model = this; + this.on("change:size", () => { + const size = Utilities.bytesToSize(model.get("size")); + model.set("sizeStr", size); + }); + if (attrs.size) { + const size = Utilities.bytesToSize(model.get("size")); + model.set("sizeStr", size); + } // Cache an array of original attribute names to help in handleChange() if (this.type == "DataONEObject") @@ -184,10 +192,10 @@

Source: src/js/models/DataONEObject.js

this.on("successSaving", this.updateRelationships); - //Save a reference to this DataONEObject model in the metadataEntity model - //whenever the metadataEntity is set + // Save a reference to this DataONEObject model in the metadataEntity model + // whenever the metadataEntity is set this.on("change:metadataEntity", function () { - var entityMetadataModel = this.get("metadataEntity"); + const entityMetadataModel = this.get("metadataEntity"); if (entityMetadataModel) entityMetadataModel.set("dataONEObject", this); @@ -197,8 +205,8 @@

Source: src/js/models/DataONEObject.js

this.set("synced", true); }); - //Find Member Node object that might be the authoritative MN - //This is helpful when MetacatUI may be displaying content from multiple MNs + // Find Member Node object that might be the authoritative MN + // This is helpful when MetacatUI may be displaying content from multiple MNs this.setPossibleAuthMNs(); }, @@ -207,7 +215,7 @@

Source: src/js/models/DataONEObject.js

* camel-cased sys meta node names (valid in DataONE). * Used during parse() and serialize() */ - nodeNameMap: function () { + nodeNameMap() { return { accesspolicy: "accessPolicy", accessrule: "accessRule", @@ -236,70 +244,67 @@

Source: src/js/models/DataONEObject.js

* Returns the URL string where this DataONEObject can be fetched from or saved to * @returns {string} */ - url: function () { + url() { // With no id, we can't do anything if (!this.get("id") && !this.get("seriesid")) return ""; - //Get the active alternative repository, if one is configured - var activeAltRepo = MetacatUI.appModel.getActiveAltRepo(); + // Get the active alternative repository, if one is configured + const activeAltRepo = MetacatUI.appModel.getActiveAltRepo(); - //Start the base URL string - var baseUrl = ""; + // Start the base URL string + let baseUrl = ""; // Determine if we're updating a new/existing object, // or just its system metadata // New uploads use the object service URL if (this.isNew()) { - //Use the object service URL from the alt repo + // Use the object service URL from the alt repo if (this.get("useAltRepo") && activeAltRepo) { baseUrl = activeAltRepo.objectServiceUrl; } - //If this MetacatUI deployment is pointing to a MN, use the object service URL from the AppModel + // If this MetacatUI deployment is pointing to a MN, use the object service URL from the AppModel else { baseUrl = MetacatUI.appModel.get("objectServiceUrl"); } - //Return the full URL + // Return the full URL return baseUrl; - } else { - if (this.hasUpdates()) { - if (this.get("hasContentChanges")) { - //Use the object service URL from the alt repo - if (this.get("useAltRepo") && activeAltRepo) { - baseUrl = activeAltRepo.objectServiceUrl; - } else { - baseUrl = MetacatUI.appModel.get("objectServiceUrl"); - } - - // Exists on the server, use MN.update() - return baseUrl + encodeURIComponent(this.get("oldPid")); - } else { - //Use the meta service URL from the alt repo - if (this.get("useAltRepo") && activeAltRepo) { - baseUrl = activeAltRepo.metaServiceUrl; - } else { - baseUrl = MetacatUI.appModel.get("metaServiceUrl"); - } - - // Exists on the server, use MN.updateSystemMetadata() - return baseUrl + encodeURIComponent(this.get("id")); - } - } else { - //Use the meta service URL from the alt repo + } + if (this.hasUpdates()) { + if (this.get("hasContentChanges")) { + // Use the object service URL from the alt repo if (this.get("useAltRepo") && activeAltRepo) { - baseUrl = activeAltRepo.metaServiceUrl; + baseUrl = activeAltRepo.objectServiceUrl; } else { - baseUrl = MetacatUI.appModel.get("metaServiceUrl"); + baseUrl = MetacatUI.appModel.get("objectServiceUrl"); } - // Use MN.getSystemMetadata() - return ( - baseUrl + - (encodeURIComponent(this.get("id")) || - encodeURIComponent(this.get("seriesid"))) - ); + // Exists on the server, use MN.update() + return baseUrl + encodeURIComponent(this.get("oldPid")); + } + // Use the meta service URL from the alt repo + if (this.get("useAltRepo") && activeAltRepo) { + baseUrl = activeAltRepo.metaServiceUrl; + } else { + baseUrl = MetacatUI.appModel.get("metaServiceUrl"); } + + // Exists on the server, use MN.updateSystemMetadata() + return baseUrl + encodeURIComponent(this.get("id")); } + // Use the meta service URL from the alt repo + if (this.get("useAltRepo") && activeAltRepo) { + baseUrl = activeAltRepo.metaServiceUrl; + } else { + baseUrl = MetacatUI.appModel.get("metaServiceUrl"); + } + + // Use MN.getSystemMetadata() + return ( + baseUrl + + (encodeURIComponent(this.get("id")) || + encodeURIComponent(this.get("seriesid"))) + ); }, /** @@ -307,29 +312,30 @@

Source: src/js/models/DataONEObject.js

* @returns PackageURL string for this DataONE Object * @since 2.28.0 */ - getPackageURL: function () { - var url = null; + getPackageURL() { + let url = null; // With no id, we can't do anything if (!this.get("id") && !this.get("seriesid")) return url; - //If we haven't set a packageServiceURL upon app initialization and we are querying a CN, then the packageServiceURL is dependent on the MN this package is from + // If we haven't set a packageServiceURL upon app initialization and we are querying a CN, then the packageServiceURL is dependent on the MN this package is from if ( MetacatUI.appModel.get("d1Service").toLowerCase().indexOf("cn/") > -1 && MetacatUI.nodeModel.get("members").length ) { - var source = this.get("datasource"), - node = _.find(MetacatUI.nodeModel.get("members"), { - identifier: source, - }); + const source = this.get("datasource"); + const node = _.find(MetacatUI.nodeModel.get("members"), { + identifier: source, + }); - //If this node has MNRead v2 services... + // If this node has MNRead v2 services... if (node && node.readv2) - url = - node.baseURL + - "/v2/packages/application%2Fbagit-097/" + - encodeURIComponent(this.get("id")); + url = `${ + node.baseURL + }/v2/packages/application%2Fbagit-097/${encodeURIComponent( + this.get("id"), + )}`; } else if (MetacatUI.appModel.get("packageServiceUrl")) url = MetacatUI.appModel.get("packageServiceUrl") + @@ -340,63 +346,53 @@

Source: src/js/models/DataONEObject.js

/** * Overload Backbone.Model.fetch, so that we can set custom options for each fetch() request + * @param options */ - fetch: function (options) { + fetch(options) { if (!options) var options = {}; else var options = _.clone(options); options.url = this.url(); - //If we are using the Solr service to retrieve info about this object, then construct a query - if (typeof options != "undefined" && options.solrService) { - //Get basic information - var query = ""; + // If we are using the Solr service to retrieve info about this object, then construct a query + if (typeof options !== "undefined" && options.solrService) { + // Get basic information + let query = ""; - //Do not search for seriesId when it is not configured in this model/app + // Do not search for seriesId when it is not configured in this model/app if (typeof this.get("seriesid") === "undefined") - query += 'id:"' + encodeURIComponent(this.get("id")) + '"'; - //If there is no seriesid set, then search for pid or sid + query += `id:"${encodeURIComponent(this.get("id"))}"`; + // If there is no seriesid set, then search for pid or sid else if (!this.get("seriesid")) - query += - '(id:"' + - encodeURIComponent(this.get("id")) + - '" OR seriesId:"' + - encodeURIComponent(this.get("id")) + - '")'; - //If a seriesId is specified, then search for that + query += `(id:"${encodeURIComponent( + this.get("id"), + )}" OR seriesId:"${encodeURIComponent(this.get("id"))}")`; + // If a seriesId is specified, then search for that else if (this.get("seriesid") && this.get("id").length > 0) - query += - '(seriesId:"' + - encodeURIComponent(this.get("seriesid")) + - '" AND id:"' + - encodeURIComponent(this.get("id")) + - '")'; - //If only a seriesId is specified, then just search for the most recent version + query += `(seriesId:"${encodeURIComponent( + this.get("seriesid"), + )}" AND id:"${encodeURIComponent(this.get("id"))}")`; + // If only a seriesId is specified, then just search for the most recent version else if (this.get("seriesid") && !this.get("id")) - query += - 'seriesId:"' + - encodeURIComponent(this.get("id")) + - '" -obsoletedBy:*'; - - //The fields to return - var fl = "formatId,formatType,documents,isDocumentedBy,id,seriesId"; - - //Use the Solr query URL - var solrOptions = { - url: - MetacatUI.appModel.get("queryServiceUrl") + - "q=" + - query + - "&fl=" + - fl + - "&wt=json", + query += `seriesId:"${encodeURIComponent( + this.get("id"), + )}" -obsoletedBy:*`; + + // The fields to return + const fl = "formatId,formatType,documents,isDocumentedBy,id,seriesId"; + + // Use the Solr query URL + const solrOptions = { + url: `${MetacatUI.appModel.get( + "queryServiceUrl", + )}q=${query}&fl=${fl}&wt=json`, }; - //Merge with the options passed to this function + // Merge with the options passed to this function var fetchOptions = _.extend(options, solrOptions); - } else if (typeof options != "undefined") { - //Use custom options for retreiving XML - //Merge with the options passed to this function + } else if (typeof options !== "undefined") { + // Use custom options for retreiving XML + // Merge with the options passed to this function var fetchOptions = _.extend( { dataType: "text", @@ -404,37 +400,38 @@

Source: src/js/models/DataONEObject.js

options, ); } else { - //Use custom options for retreiving XML + // Use custom options for retreiving XML var fetchOptions = _.extend({ dataType: "text", }); } - //Add the authorization options + // Add the authorization options fetchOptions = _.extend( fetchOptions, MetacatUI.appUserModel.createAjaxSettings(), ); - //Call Backbone.Model.fetch to retrieve the info + // Call Backbone.Model.fetch to retrieve the info return Backbone.Model.prototype.fetch.call(this, fetchOptions); }, /** * This function is called by Backbone.Model.fetch. * It deserializes the incoming XML from the /meta REST endpoint and converts it into JSON. + * @param response */ - parse: function (response) { + parse(response) { // If the response is XML - if (typeof response == "string" && response.indexOf("<") == 0) { - var responseDoc = $.parseHTML(response), - systemMetadata; + if (typeof response === "string" && response.indexOf("<") == 0) { + const responseDoc = $.parseHTML(response); + let systemMetadata; - //Save the raw XML in case it needs to be used later + // Save the raw XML in case it needs to be used later this.set("sysMetaXML", response); - //Find the XML node for the system metadata - for (var i = 0; i < responseDoc.length; i++) { + // Find the XML node for the system metadata + for (let i = 0; i < responseDoc.length; i++) { if ( responseDoc[i].nodeType == 1 && responseDoc[i].localName.indexOf("systemmetadata") > -1 @@ -444,14 +441,14 @@

Source: src/js/models/DataONEObject.js

} } - //Parse the XML to JSON - var sysMetaValues = this.toJson(systemMetadata); + // Parse the XML to JSON + const sysMetaValues = this.toJson(systemMetadata); - //Convert the JSON to a camel-cased version, which matches Solr and is easier to work with in code + // Convert the JSON to a camel-cased version, which matches Solr and is easier to work with in code _.each( Object.keys(sysMetaValues), function (key) { - var camelCasedKey = this.nodeNameMap()[key]; + const camelCasedKey = this.nodeNameMap()[key]; if (camelCasedKey) { sysMetaValues[camelCasedKey] = sysMetaValues[key]; delete sysMetaValues[key]; @@ -460,14 +457,14 @@

Source: src/js/models/DataONEObject.js

this, ); - //Save the checksum from the system metadata in a separate attribute on the model + // Save the checksum from the system metadata in a separate attribute on the model sysMetaValues.originalChecksum = sysMetaValues.checksum; sysMetaValues.checksum = this.defaults().checksum; - //Save the identifier as the id attribute + // Save the identifier as the id attribute sysMetaValues.id = sysMetaValues.identifier; - //Parse the Access Policy + // Parse the Access Policy if ( this.get("accessPolicy") && AccessPolicy.prototype.isPrototypeOf(this.get("accessPolicy")) @@ -477,7 +474,7 @@

Source: src/js/models/DataONEObject.js

); sysMetaValues.accessPolicy = this.get("accessPolicy"); } else { - //Create a new AccessPolicy collection, if there isn't one already. + // Create a new AccessPolicy collection, if there isn't one already. sysMetaValues.accessPolicy = this.createAccessPolicy( $(systemMetadata).find("accesspolicy"), ); @@ -486,58 +483,62 @@

Source: src/js/models/DataONEObject.js

return sysMetaValues; // If the response is a list of Solr docs - } else if ( + } + if ( typeof response === "object" && response.response && response.response.docs ) { - //If no objects were found in the index, mark as notFound and exit + // If no objects were found in the index, mark as notFound and exit if (!response.response.docs.length) { this.set("notFound", true); this.trigger("notFound"); return; } - //Get the Solr document (there should be only one) - var doc = response.response.docs[0]; + // Get the Solr document (there should be only one) + const doc = response.response.docs[0]; - //Take out any empty values - _.each(Object.keys(doc), function (field) { + // Take out any empty values + _.each(Object.keys(doc), (field) => { if (!doc[field] && doc[field] !== 0) delete doc[field]; }); - //Remove any erroneous white space from fields + // Remove any erroneous white space from fields this.removeWhiteSpaceFromSolrFields(doc); return doc; } // Default to returning the raw response - else return response; + return response; }, - /** A utility function for converting XML to JSON */ - toJson: function (xml) { + /** + * A utility function for converting XML to JSON + * @param xml + */ + toJson(xml) { // Create the return object - var obj = {}; + let obj = {}; // do children if (xml.hasChildNodes()) { - for (var i = 0; i < xml.childNodes.length; i++) { - var item = xml.childNodes.item(i); + for (let i = 0; i < xml.childNodes.length; i++) { + const item = xml.childNodes.item(i); - //If it's an empty text node, skip it + // If it's an empty text node, skip it if (item.nodeType == 3 && !item.nodeValue.trim()) continue; - //Get the node name - var nodeName = item.localName; + // Get the node name + const nodeName = item.localName; - //If it's a new container node, convert it to JSON and add as a new object attribute - if (typeof obj[nodeName] == "undefined" && item.nodeType == 1) { + // If it's a new container node, convert it to JSON and add as a new object attribute + if (typeof obj[nodeName] === "undefined" && item.nodeType == 1) { obj[nodeName] = this.toJson(item); } - //If it's a new text node, just store the text value and add as a new object attribute + // If it's a new text node, just store the text value and add as a new object attribute else if ( - typeof obj[nodeName] == "undefined" && + typeof obj[nodeName] === "undefined" && item.nodeType == 3 ) { obj = @@ -547,16 +548,16 @@

Source: src/js/models/DataONEObject.js

? true : item.nodeValue; } - //If this node name is already stored as an object attribute... - else if (typeof obj[nodeName] != "undefined") { - //Cache what we have now - var old = obj[nodeName]; + // If this node name is already stored as an object attribute... + else if (typeof obj[nodeName] !== "undefined") { + // Cache what we have now + let old = obj[nodeName]; if (!Array.isArray(old)) old = [old]; - //Create a new object to store this node info + // Create a new object to store this node info var newNode = {}; - //Add the new node info to the existing array we have now + // Add the new node info to the existing array we have now if (item.nodeType == 1) { newNode = this.toJson(item); var newArray = old.concat(newNode); @@ -565,22 +566,22 @@

Source: src/js/models/DataONEObject.js

var newArray = old.concat(newNode); } - //Store the attributes for this node - _.each(item.attributes, function (attr) { + // Store the attributes for this node + _.each(item.attributes, (attr) => { newNode[attr.localName] = attr.nodeValue; }); - //Replace the old array with the updated one + // Replace the old array with the updated one obj[nodeName] = newArray; - //Exit + // Exit continue; } - //Store the attributes for this node - /*_.each(item.attributes, function(attr){ + // Store the attributes for this node + /* _.each(item.attributes, function(attr){ obj[nodeName][attr.localName] = attr.nodeValue; - });*/ + }); */ } } return obj; @@ -591,38 +592,39 @@

Source: src/js/models/DataONEObject.js

@param {object} json - the JSON object to convert to XML @param {Element} containerNode - an HTML element to insertt the resulting XML into @returns {Element} The updated HTML Element - */ - toXML: function (json, containerNode) { - if (typeof json == "string") { + */ + toXML(json, containerNode) { + if (typeof json === "string") { containerNode.textContent = json; return containerNode; } - for (var i = 0; i < Object.keys(json).length; i++) { - var key = Object.keys(json)[i], - contents = json[key] || json[key]; + for (let i = 0; i < Object.keys(json).length; i++) { + const key = Object.keys(json)[i]; + const contents = json[key] || json[key]; - var node = document.createElement(key); + let node = document.createElement(key); - //Skip this attribute if it is not populated + // Skip this attribute if it is not populated if (!contents || (Array.isArray(contents) && !contents.length)) continue; - //If it's a simple text node - if (typeof contents == "string") { + // If it's a simple text node + if (typeof contents === "string") { containerNode.textContent = contents; return containerNode; - } else if (Array.isArray(contents)) { - var allNewNodes = []; + } + if (Array.isArray(contents)) { + const allNewNodes = []; - for (var ii = 0; ii < contents.length; ii++) { + for (let ii = 0; ii < contents.length; ii++) { allNewNodes.push(this.toXML(contents[ii], $(node).clone()[0])); } if (allNewNodes.length) node = allNewNodes; - } else if (typeof contents == "object") { + } else if (typeof contents === "object") { $(node).append(this.toXML(contents, node)); - var attributeNames = _.without(Object.keys(json[key]), "content"); + const attributeNames = _.without(Object.keys(json[key]), "content"); } $(containerNode).append(node); @@ -633,21 +635,23 @@

Source: src/js/models/DataONEObject.js

/** * Saves the DataONEObject System Metadata to the server + * @param attributes + * @param options */ - save: function (attributes, options) { + save(attributes, options) { // Set missing file names before saving if (!this.get("fileName")) { this.setMissingFileName(); } else { - //Replace all non-alphanumeric characters with underscores - var fileNameWithoutExt = this.get("fileName").substring( - 0, - this.get("fileName").lastIndexOf("."), - ), - extension = this.get("fileName").substring( - this.get("fileName").lastIndexOf("."), - this.get("fileName").length, - ); + // Replace all non-alphanumeric characters with underscores + const fileNameWithoutExt = this.get("fileName").substring( + 0, + this.get("fileName").lastIndexOf("."), + ); + const extension = this.get("fileName").substring( + this.get("fileName").lastIndexOf("."), + this.get("fileName").length, + ); this.set( "fileName", fileNameWithoutExt.replace(/[^a-zA-Z0-9]/g, "_") + extension, @@ -659,51 +663,51 @@

Source: src/js/models/DataONEObject.js

return; } - //Set the upload transfer as in progress + // Set the upload transfer as in progress this.set("uploadProgress", 2); this.set("uploadStatus", "p"); - //Check if the checksum has been calculated yet. + // Check if the checksum has been calculated yet. if (!this.get("checksum")) { - //When it is calculated, restart this function + // When it is calculated, restart this function this.on("checksumCalculated", this.save); - //Calculate the checksum for this file + // Calculate the checksum for this file this.calculateChecksum(); - //Exit this function until the checksum is done + // Exit this function until the checksum is done return; } - //Create a FormData object to send data with our XHR - var formData = new FormData(); + // Create a FormData object to send data with our XHR + const formData = new FormData(); - //If this is not a new object, update the id. New DataONEObjects will have an id + // If this is not a new object, update the id. New DataONEObjects will have an id // created during initialize. if (!this.isNew()) { this.updateID(); formData.append("pid", this.get("oldPid")); formData.append("newPid", this.get("id")); } else { - //Create an ID if there isn't one + // Create an ID if there isn't one if (!this.get("id")) { - this.set("id", "urn:uuid:" + uuid.v4()); + this.set("id", `urn:uuid:${uuid.v4()}`); } - //Add the identifier to the XHR data + // Add the identifier to the XHR data formData.append("pid", this.get("id")); } - //Create the system metadata XML - var sysMetaXML = this.serializeSysMeta(); + // Create the system metadata XML + const sysMetaXML = this.serializeSysMeta(); - //Send the system metadata as a Blob - var xmlBlob = new Blob([sysMetaXML], { type: "application/xml" }); - //Add the system metadata XML to the XHR data + // Send the system metadata as a Blob + const xmlBlob = new Blob([sysMetaXML], { type: "application/xml" }); + // Add the system metadata XML to the XHR data formData.append("sysmeta", xmlBlob, "sysmeta.xml"); // Create the new object (MN.create()) formData.append("object", this.get("uploadFile"), this.get("fileName")); - var model = this; + const model = this; // On create(), add to the package and the metadata // Note: This should be added to the parent collection @@ -719,8 +723,8 @@

Source: src/js/models/DataONEObject.js

this, ); - //Put together the AJAX and Backbone.save() options - var requestSettings = { + // Put together the AJAX and Backbone.save() options + let requestSettings = { url: this.url(), cache: false, contentType: false, @@ -728,15 +732,15 @@

Source: src/js/models/DataONEObject.js

processData: false, data: formData, parse: false, - xhr: function () { - var xhr = new window.XMLHttpRequest(); + xhr() { + const xhr = new window.XMLHttpRequest(); - //Upload progress + // Upload progress xhr.upload.addEventListener( "progress", - function (evt) { + (evt) => { if (evt.lengthComputable) { - var percentComplete = (evt.loaded / evt.total) * 100; + const percentComplete = (evt.loaded / evt.total) * 100; model.set("uploadProgress", percentComplete); } @@ -747,24 +751,24 @@

Source: src/js/models/DataONEObject.js

return xhr; }, success: this.onSuccessfulSave, - error: function (model, response, xhr) { - //Reset the identifier changes + error(model, response, xhr) { + // Reset the identifier changes model.resetID(); - //Reset the checksum, if this is a model that needs to be serialized with each save. + // Reset the checksum, if this is a model that needs to be serialized with each save. if (model.serialize) { model.set("checksum", model.defaults().checksum); } model.set("numSaveAttempts", model.get("numSaveAttempts") + 1); - var numSaveAttempts = model.get("numSaveAttempts"); + const numSaveAttempts = model.get("numSaveAttempts"); if ( numSaveAttempts < 3 && (response.status == 408 || response.status == 0) ) { - //Try saving again in 10, 40, and 90 seconds + // Try saving again in 10, 40, and 90 seconds setTimeout( - function () { + () => { model.save.call(model); }, numSaveAttempts * numSaveAttempts * 10000, @@ -772,11 +776,11 @@

Source: src/js/models/DataONEObject.js

} else { model.set("numSaveAttempts", 0); - var parsedResponse = $(response.responseText) + let parsedResponse = $(response.responseText) .not("style, title") .text(); - //When there is no network connection (status == 0), there will be no response text + // When there is no network connection (status == 0), there will be no response text if (!parsedResponse) parsedResponse = "There was a network issue that prevented this file from uploading. " + @@ -784,10 +788,10 @@

Source: src/js/models/DataONEObject.js

model.set("errorMessage", parsedResponse); - //Set the model status as e for error + // Set the model status as e for error model.set("uploadStatus", "e"); - //Trigger a custom event for the model save error + // Trigger a custom event for the model save error model.trigger("errorSaving", parsedResponse); // Track this error in our analytics @@ -800,13 +804,13 @@

Source: src/js/models/DataONEObject.js

}, }; - //Add the user settings + // Add the user settings requestSettings = _.extend( requestSettings, MetacatUI.appUserModel.createAjaxSettings(), ); - //Send the Save request + // Send the Save request Backbone.Model.prototype.save.call(this, null, requestSettings); }, @@ -818,8 +822,8 @@

Source: src/js/models/DataONEObject.js

* @param {XMLHttpRequest.response} [response] The XHR response object * @param {XMLHttpRequest} [xhr] The XHR that was just completed successfully */ - onSuccessfulSave: function (model, response, xhr) { - if (typeof model == "undefined") { + onSuccessfulSave(model, response, xhr) { + if (typeof model === "undefined") { var model = this; } @@ -837,13 +841,13 @@

Source: src/js/models/DataONEObject.js

// Reset the content changes status model.set("hasContentChanges", false); - //Reset the model isNew attribute + // Reset the model isNew attribute model.set("isNew", false); // Reset oldPid so we can replace again model.set("oldPid", null); - //Set the last-calculated checksum as the original checksum + // Set the last-calculated checksum as the original checksum model.set("originalChecksum", model.get("checksum")); model.set("checksum", model.defaults().checksum); }, @@ -851,39 +855,39 @@

Source: src/js/models/DataONEObject.js

/** * Updates the DataONEObject System Metadata to the server */ - updateSysMeta: function () { - //Update the upload status to "p" for "in progress" + updateSysMeta() { + // Update the upload status to "p" for "in progress" this.set("uploadStatus", "p"); - //Update the system metadata upload status to "p" as well, so the app + // Update the system metadata upload status to "p" as well, so the app // knows that the system metadata, specifically, is being updated. this.set("sysMetaUploadStatus", "p"); - var formData = new FormData(); + const formData = new FormData(); - //Add the identifier to the XHR data + // Add the identifier to the XHR data formData.append("pid", this.get("id")); - var sysMetaXML = this.serializeSysMeta(); + const sysMetaXML = this.serializeSysMeta(); - //Send the system metadata as a Blob - var xmlBlob = new Blob([sysMetaXML], { type: "application/xml" }); - //Add the system metadata XML to the XHR data + // Send the system metadata as a Blob + const xmlBlob = new Blob([sysMetaXML], { type: "application/xml" }); + // Add the system metadata XML to the XHR data formData.append("sysmeta", xmlBlob, "sysmeta.xml"); - var model = this; + const model = this; - var baseUrl = "", - activeAltRepo = MetacatUI.appModel.getActiveAltRepo(); - //Use the meta service URL from the alt repo + let baseUrl = ""; + const activeAltRepo = MetacatUI.appModel.getActiveAltRepo(); + // Use the meta service URL from the alt repo if (activeAltRepo) { baseUrl = activeAltRepo.metaServiceUrl; } - //If this MetacatUI deployment is pointing to a MN, use the meta service URL from the AppModel + // If this MetacatUI deployment is pointing to a MN, use the meta service URL from the AppModel else { baseUrl = MetacatUI.appModel.get("metaServiceUrl"); } - var requestSettings = { + let requestSettings = { url: baseUrl + encodeURIComponent(this.get("id")), cache: false, contentType: false, @@ -892,29 +896,29 @@

Source: src/js/models/DataONEObject.js

processData: false, data: formData, parse: false, - success: function () { + success() { model.set("numSaveAttempts", 0); - //Fetch the system metadata from the server so we have a fresh copy of the newest sys meta. + // Fetch the system metadata from the server so we have a fresh copy of the newest sys meta. model.fetch({ systemMetadataOnly: true }); model.set("sysMetaErrorCode", null); - //Update the upload status to "c" for "complete" + // Update the upload status to "c" for "complete" model.set("uploadStatus", "c"); model.set("sysMetaUploadStatus", "c"); - //Trigger a custom event that the sys meta was updated + // Trigger a custom event that the sys meta was updated model.trigger("sysMetaUpdated"); }, - error: function (xhr, status, statusCode) { + error(xhr, status, statusCode) { model.set("numSaveAttempts", model.get("numSaveAttempts") + 1); - var numSaveAttempts = model.get("numSaveAttempts"); + const numSaveAttempts = model.get("numSaveAttempts"); if (numSaveAttempts < 3 && (statusCode == 408 || statusCode == 0)) { - //Try saving again in 10, 40, and 90 seconds + // Try saving again in 10, 40, and 90 seconds setTimeout( - function () { + () => { model.updateSysMeta.call(model); }, numSaveAttempts * numSaveAttempts * 10000, @@ -922,11 +926,11 @@

Source: src/js/models/DataONEObject.js

} else { model.set("numSaveAttempts", 0); - var parsedResponse = $(xhr.responseText) + let parsedResponse = $(xhr.responseText) .not("style, title") .text(); - //When there is no network connection (status == 0), there will be no response text + // When there is no network connection (status == 0), there will be no response text if (!parsedResponse) parsedResponse = "There was a network issue that prevented this file from updating. " + @@ -954,67 +958,67 @@

Source: src/js/models/DataONEObject.js

}, }; - //Add the user settings + // Add the user settings requestSettings = _.extend( requestSettings, MetacatUI.appUserModel.createAjaxSettings(), ); - //Send the XHR + // Send the XHR $.ajax(requestSettings); }, /** * Check if the current user is authorized to perform an action on this object. This function doesn't return * the result of the check, but it sends an XHR, updates this model, and triggers a change event. - * @param {string} [action=changePermission] - The action (read, write, or changePermission) to check + * @param {string} [action] - The action (read, write, or changePermission) to check * if the current user has authorization to perform. By default checks for the highest level of permission. * @param {object} [options] Additional options for this function. See the properties below. - * @property {function} options.onSuccess - A function to execute when the checkAuthority API is successfully completed - * @property {function} options.onError - A function to execute when the checkAuthority API returns an error, or when no PID or SID can be found for this object. - * @return {boolean} + * @property {Function} options.onSuccess - A function to execute when the checkAuthority API is successfully completed + * @property {Function} options.onError - A function to execute when the checkAuthority API returns an error, or when no PID or SID can be found for this object. + * @returns {boolean} */ - checkAuthority: function (action = "changePermission", options) { + checkAuthority(action = "changePermission", options) { try { // return false - if neither PID nor SID is present to check the authority if (this.get("id") == null && this.get("seriesId") == null) { return false; } - if (typeof options == "undefined") { + if (typeof options === "undefined") { var options = {}; } // If onError or onSuccess options were provided by the user, // check that they are functions first, so we don't try to use // some other type of variable as a function later on. - ["onError", "onSuccess"].forEach(function (userFunction) { + ["onError", "onSuccess"].forEach((userFunction) => { if (typeof options[userFunction] !== "function") { options[userFunction] = null; } }); // If PID is not present - check authority with seriesId - var identifier = this.get("id"); + let identifier = this.get("id"); if (identifier == null) { identifier = this.get("seriesId"); } - //If there are alt repositories configured, find the possible authoritative + // If there are alt repositories configured, find the possible authoritative // Member Node for this DataONEObject. if (MetacatUI.appModel.get("alternateRepositories").length) { - //Get the array of possible authoritative MNs - var possibleAuthMNs = this.get("possibleAuthMNs"); + // Get the array of possible authoritative MNs + const possibleAuthMNs = this.get("possibleAuthMNs"); - //If there are no possible authoritative MNs, use the auth service URL from the AppModel + // If there are no possible authoritative MNs, use the auth service URL from the AppModel if (!possibleAuthMNs.length) { baseUrl = MetacatUI.appModel.get("authServiceUrl"); } else { - //Use the auth service URL from the top possible auth MN + // Use the auth service URL from the top possible auth MN baseUrl = possibleAuthMNs[0].authServiceUrl; } } else { - //Get the auth service URL from the AppModel + // Get the auth service URL from the AppModel baseUrl = MetacatUI.appModel.get("authServiceUrl"); } @@ -1022,41 +1026,41 @@

Source: src/js/models/DataONEObject.js

return false; } - var onSuccess = - options.onSuccess || - function (data, textStatus, xhr) { - model.set("isAuthorized_" + action, true); - model.set("isAuthorized", true); - model.trigger("change:isAuthorized"); - }, - onError = - options.onError || - function (xhr, textStatus, errorThrown) { - if (errorThrown == 404) { - var possibleAuthMNs = model.get("possibleAuthMNs"); - if (possibleAuthMNs.length) { - //Remove the first MN from the array, since it didn't contain the object, so it's not the auth MN - possibleAuthMNs.shift(); - } - - //If there are no other possible auth MNs to check, trigger this model as Not Found. - if (possibleAuthMNs.length == 0 || !possibleAuthMNs) { - model.set("notFound", true); - model.trigger("notFound"); - } - //If there's more MNs to check, try again - else { - model.checkAuthority(action, options); - } - } else { - model.set("isAuthorized_" + action, false); - model.set("isAuthorized", false); + const onSuccess = + options.onSuccess || + function (data, textStatus, xhr) { + model.set(`isAuthorized_${action}`, true); + model.set("isAuthorized", true); + model.trigger("change:isAuthorized"); + }; + const onError = + options.onError || + function (xhr, textStatus, errorThrown) { + if (errorThrown == 404) { + const possibleAuthMNs = model.get("possibleAuthMNs"); + if (possibleAuthMNs.length) { + // Remove the first MN from the array, since it didn't contain the object, so it's not the auth MN + possibleAuthMNs.shift(); + } + + // If there are no other possible auth MNs to check, trigger this model as Not Found. + if (possibleAuthMNs.length == 0 || !possibleAuthMNs) { + model.set("notFound", true); + model.trigger("notFound"); } - }; + // If there's more MNs to check, try again + else { + model.checkAuthority(action, options); + } + } else { + model.set(`isAuthorized_${action}`, false); + model.set("isAuthorized", false); + } + }; var model = this; - var requestSettings = { - url: baseUrl + encodeURIComponent(identifier) + "?action=" + action, + const requestSettings = { + url: `${baseUrl + encodeURIComponent(identifier)}?action=${action}`, type: "GET", success: onSuccess, error: onError, @@ -1068,7 +1072,7 @@

Source: src/js/models/DataONEObject.js

), ); } catch (e) { - //Log an error to the console + // Log an error to the console console.error("Couldn't check the authority for this user: ", e); // Track this error in our analytics @@ -1079,8 +1083,8 @@

Source: src/js/models/DataONEObject.js

true, ); - //Set the user as unauthorized - model.set("isAuthorized_" + action, false); + // Set the user as unauthorized + model.set(`isAuthorized_${action}`, false); model.set("isAuthorized", false); return false; } @@ -1090,21 +1094,21 @@

Source: src/js/models/DataONEObject.js

* Using the attributes set on this DataONEObject model, serializes the system metadata XML * @returns {string} */ - serializeSysMeta: function () { - //Get the system metadata XML that currently exists in the system - var sysMetaXML = this.get("sysMetaXML"), // sysmeta as string - xml, // sysmeta as DOM object - accessPolicyXML, // The generated access policy XML - previousSiblingNode, // A DOM node indicating any previous sibling - rightsHolderNode, // A DOM node for the rights holder field - accessPolicyNode, // A DOM node for the access policy - replicationPolicyNode, // A DOM node for the replication policy - obsoletesNode, // A DOM node for the obsoletes field - obsoletedByNode, // A DOM node for the obsoletedBy field - fileNameNode, // A DOM node for the file name - xmlString, // The system metadata document as a string - nodeNameMap, // The map of camelCase to lowercase attributes - extension; // the file name extension for this object + serializeSysMeta() { + // Get the system metadata XML that currently exists in the system + const sysMetaXML = this.get("sysMetaXML"); // sysmeta as string + let xml; // sysmeta as DOM object + let accessPolicyXML; // The generated access policy XML + let previousSiblingNode; // A DOM node indicating any previous sibling + let rightsHolderNode; // A DOM node for the rights holder field + let accessPolicyNode; // A DOM node for the access policy + let replicationPolicyNode; // A DOM node for the replication policy + let obsoletesNode; // A DOM node for the obsoletes field + let obsoletedByNode; // A DOM node for the obsoletedBy field + let fileNameNode; // A DOM node for the file name + let xmlString; // The system metadata document as a string + let nodeNameMap; // The map of camelCase to lowercase attributes + let extension; // the file name extension for this object if (typeof sysMetaXML === "undefined" || sysMetaXML === null) { xml = this.createSysMeta(); @@ -1112,7 +1116,7 @@

Source: src/js/models/DataONEObject.js

xml = $($.parseHTML(sysMetaXML)); } - //Update the system metadata values + // Update the system metadata values xml.find("serialversion").text(this.get("serialVersion") || "0"); xml.find("identifier").text(this.get("newPid") || this.get("id")); xml @@ -1122,53 +1126,53 @@

Source: src/js/models/DataONEObject.js

); xml.find("formatid").text(this.get("formatId") || this.getFormatId()); - //If there is a seriesId, add it + // If there is a seriesId, add it if (this.get("seriesId")) { - //Get the seriesId XML node - var seriesIdNode = xml.find("seriesId"); + // Get the seriesId XML node + let seriesIdNode = xml.find("seriesId"); - //If it doesn't exist, create one + // If it doesn't exist, create one if (!seriesIdNode.length) { seriesIdNode = $(document.createElement("seriesid")); xml.find("identifier").before(seriesIdNode); } - //Add the seriesId string to the XML node + // Add the seriesId string to the XML node seriesIdNode.text(this.get("seriesId")); } - //If there is no size, get it + // If there is no size, get it if (!this.get("size") && this.get("uploadFile")) { this.set("size", this.get("uploadFile").size); } - //Get the size of the file, if there is one + // Get the size of the file, if there is one if (this.get("uploadFile")) { xml.find("size").text(this.get("uploadFile").size); } - //Otherwise, use the last known size + // Otherwise, use the last known size else { xml.find("size").text(this.get("size")); } - //Save the original checksum + // Save the original checksum if (!this.get("checksum") && this.get("originalChecksum")) { xml.find("checksum").text(this.get("originalChecksum")); } - //Update the checksum and checksum algorithm + // Update the checksum and checksum algorithm else { xml.find("checksum").text(this.get("checksum")); xml.find("checksum").attr("algorithm", this.get("checksumAlgorithm")); } - //Update the rightsholder + // Update the rightsholder xml .find("rightsholder") .text( this.get("rightsHolder") || MetacatUI.appUserModel.get("username"), ); - //Write the access policy + // Write the access policy accessPolicyXML = this.get("accessPolicy").serialize(); // Get the access policy node, if it exists @@ -1182,7 +1186,7 @@

Source: src/js/models/DataONEObject.js

previousSiblingNode.after(accessPolicyNode); } - //Replace the old access policy with the new one if it exists + // Replace the old access policy with the new one if it exists if (accessPolicyXML) { accessPolicyNode.replaceWith(accessPolicyXML); } else { @@ -1214,10 +1218,8 @@

Source: src/js/models/DataONEObject.js

); previousSiblingNode.after(obsoletesNode); } - } else { - if (obsoletesNode) { - obsoletesNode.remove(); - } + } else if (obsoletesNode) { + obsoletesNode.remove(); } if (obsoletesNode) { @@ -1226,7 +1228,7 @@

Source: src/js/models/DataONEObject.js

obsoletedByNode = xml.find("obsoletedby"); - //remove the obsoletedBy node if it exists + // remove the obsoletedBy node if it exists // TODO: Verify this is what we want to do if (obsoletedByNode) { obsoletedByNode.remove(); @@ -1237,41 +1239,38 @@

Source: src/js/models/DataONEObject.js

.find("dateuploaded") .text(this.get("dateUploaded") || new Date().toISOString()); - //Get the filename node + // Get the filename node fileNameNode = xml.find("filename"); - //If the filename node doesn't exist, then create one + // If the filename node doesn't exist, then create one if (!fileNameNode.length) { fileNameNode = $(document.createElement("filename")); xml.find("dateuploaded").after(fileNameNode); } - //Set the object file name + // Set the object file name $(fileNameNode).text(this.get("fileName")); xmlString = $(document.createElement("div")).append(xml.clone()).html(); - //Now camel case the nodes + // Now camel case the nodes nodeNameMap = this.nodeNameMap(); _.each( Object.keys(nodeNameMap), - function (name, i) { - var originalXMLString = xmlString; + (name, i) => { + const originalXMLString = xmlString; - //Camel case node names - var regEx = new RegExp("<" + name, "g"); - xmlString = xmlString.replace(regEx, "<" + nodeNameMap[name]); - var regEx = new RegExp(name + ">", "g"); - xmlString = xmlString.replace(regEx, nodeNameMap[name] + ">"); + // Camel case node names + var regEx = new RegExp(`<${name}`, "g"); + xmlString = xmlString.replace(regEx, `<${nodeNameMap[name]}`); + var regEx = new RegExp(`${name}>`, "g"); + xmlString = xmlString.replace(regEx, `${nodeNameMap[name]}>`); - //If node names haven't been changed, then find an attribute + // If node names haven't been changed, then find an attribute if (xmlString == originalXMLString) { - var regEx = new RegExp(" " + name + "=", "g"); - xmlString = xmlString.replace( - regEx, - " " + nodeNameMap[name] + "=", - ); + var regEx = new RegExp(` ${name}=`, "g"); + xmlString = xmlString.replace(regEx, ` ${nodeNameMap[name]}=`); } }, this, @@ -1285,16 +1284,16 @@

Source: src/js/models/DataONEObject.js

/** * Get the object format identifier for this object */ - getFormatId: function () { - var formatId = "application/octet-stream", // default to untyped data - objectFormats = { - mediaTypes: [], // The list of potential formatIds based on mediaType matches - extensions: [], // The list of possible formatIds based onextension matches - }, - fileName = this.get("fileName"), // the fileName for this object - ext; // The extension of the filename for this object + getFormatId() { + let formatId = "application/octet-stream"; // default to untyped data + const objectFormats = { + mediaTypes: [], // The list of potential formatIds based on mediaType matches + extensions: [], // The list of possible formatIds based onextension matches + }; + const fileName = this.get("fileName"); // the fileName for this object + let ext; // The extension of the filename for this object - objectFormats["mediaTypes"] = MetacatUI.objectFormats.where({ + objectFormats.mediaTypes = MetacatUI.objectFormats.where({ formatId: this.get("mediaType"), }); if ( @@ -1306,17 +1305,17 @@

Source: src/js/models/DataONEObject.js

fileName.lastIndexOf(".") + 1, fileName.length, ); - objectFormats["extensions"] = MetacatUI.objectFormats.where({ + objectFormats.extensions = MetacatUI.objectFormats.where({ extension: ext, }); } if ( - objectFormats["mediaTypes"].length > 0 && - objectFormats["extensions"].length > 0 + objectFormats.mediaTypes.length > 0 && + objectFormats.extensions.length > 0 ) { - var firstMediaType = objectFormats["mediaTypes"][0].get("formatId"); - var firstExtension = objectFormats["extensions"][0].get("formatId"); + const firstMediaType = objectFormats.mediaTypes[0].get("formatId"); + const firstExtension = objectFormats.extensions[0].get("formatId"); // Check if they're equal if (firstMediaType === firstExtension) { formatId = firstMediaType; @@ -1332,19 +1331,19 @@

Source: src/js/models/DataONEObject.js

} } - if (objectFormats["mediaTypes"].length > 0) { - formatId = objectFormats["mediaTypes"][0].get("formatId"); + if (objectFormats.mediaTypes.length > 0) { + formatId = objectFormats.mediaTypes[0].get("formatId"); console.log("returning default mediaType"); console.log(formatId); return formatId; } - if (objectFormats["extensions"].length > 0) { - //If this is a "nc" file, assume it is a netCDF-3 file. + if (objectFormats.extensions.length > 0) { + // If this is a "nc" file, assume it is a netCDF-3 file. if (ext == "nc") { formatId = "netCDF-3"; } else { - formatId = objectFormats["extensions"][0].get("formatId"); + formatId = objectFormats.extensions[0].get("formatId"); } return formatId; } @@ -1357,8 +1356,8 @@

Source: src/js/models/DataONEObject.js

* @returns format String * @since 2.28.0 */ - getFormat: function () { - var formatMap = { + getFormat() { + const formatMap = { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "Microsoft Excel OpenXML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document": @@ -1420,12 +1419,12 @@

Source: src/js/models/DataONEObject.js

* Build a fresh system metadata document for this object when it is new * Return it as a DOM object */ - createSysMeta: function () { - var sysmetaDOM, // The DOM - sysmetaXML = []; // The document as a string array + createSysMeta() { + let sysmetaDOM; // The DOM + const sysmetaXML = []; // The document as a string array sysmetaXML.push( - //'<?xml version="1.0" encoding="UTF-8"?>', + // '<?xml version="1.0" encoding="UTF-8"?>', "<d1_v2.0:systemmetadata", ' xmlns:d1_v2.0="http://ns.dataone.org/service/types/v2.0"', ' xmlns:d1="http://ns.dataone.org/service/types/v1">', @@ -1447,30 +1446,30 @@

Source: src/js/models/DataONEObject.js

/** * Create an access policy for this DataONEObject using the default access * policy set in the AppModel. - * * @param {Element} [accessPolicyXML] - An <accessPolicy> XML node * that contains a list of access rules. - * @return {AccessPolicy} - an AccessPolicy collection that represents the + * @returns {AccessPolicy} - an AccessPolicy collection that represents the * given XML or the default policy set in the AppModel. */ - createAccessPolicy: function (accessPolicyXML) { - //Create a new AccessPolicy collection - var accessPolicy = new AccessPolicy(); + createAccessPolicy(accessPolicyXML) { + // Create a new AccessPolicy collection + const accessPolicy = new AccessPolicy(); accessPolicy.dataONEObject = this; - //If there is no access policy XML sent, + // If there is no access policy XML sent, if (this.isNew() && !accessPolicyXML) { try { - //If the app is configured to inherit the access policy from the parent metadata, + // If the app is configured to inherit the access policy from the parent metadata, // then get the parent metadata and copy it's AccessPolicy - let scienceMetadata = this.get("isDocumentedByModels"); + const scienceMetadata = this.get("isDocumentedByModels"); if ( MetacatUI.appModel.get("inheritAccessPolicy") && scienceMetadata && scienceMetadata.length ) { - let sciMetaAccessPolicy = scienceMetadata[0].get("accessPolicy"); + const sciMetaAccessPolicy = + scienceMetadata[0].get("accessPolicy"); if (sciMetaAccessPolicy) { accessPolicy.copyAccessPolicy(sciMetaAccessPolicy); @@ -1478,7 +1477,7 @@

Source: src/js/models/DataONEObject.js

accessPolicy.createDefaultPolicy(); } } - //Otherwise, set the default access policy using the AppModel configuration + // Otherwise, set the default access policy using the AppModel configuration else { accessPolicy.createDefaultPolicy(); } @@ -1490,12 +1489,12 @@

Source: src/js/models/DataONEObject.js

accessPolicy.createDefaultPolicy(); } } else { - //Parse the access policy XML to create AccessRule models from the XML + // Parse the access policy XML to create AccessRule models from the XML accessPolicy.parse(accessPolicyXML); } - //Listen to changes on the collection and trigger a change on this model - var self = this; + // Listen to changes on the collection and trigger a change on this model + const self = this; this.listenTo(accessPolicy, "change update", function () { self.trigger("change"); this.addToUploadQueue(); @@ -1506,7 +1505,6 @@

Source: src/js/models/DataONEObject.js

/** * Update identifiers for this object - * * @param {string} id - Optional identifier to update with. Generated * automatically when not given. * @@ -1519,44 +1517,42 @@

Source: src/js/models/DataONEObject.js

* PID will be such as the case where we want to update a matching * EML entity when replacing files. */ - updateID: function (id) { + updateID(id) { // Only run once until oldPid is reset if (this.get("oldPid")) { return; } - //Save the attributes so we can reset the ID later + // Save the attributes so we can reset the ID later this.attributeCache = this.toJSON(); - //Set the old identifier - var oldPid = this.get("id"), - selfDocuments, - selfDocumentedBy, - documentedModels, - documentedModel, - index; + // Set the old identifier + const oldPid = this.get("id"); + let selfDocuments; + let selfDocumentedBy; + let documentedModels; + let documentedModel; + let index; - //Save the current id as the old pid + // Save the current id as the old pid this.set("oldPid", oldPid); - //Create a new seriesId, if there isn't one, and if this model specifies that one is required + // Create a new seriesId, if there isn't one, and if this model specifies that one is required if (!this.get("seriesId") && this.get("createSeriesId")) { - this.set("seriesId", "urn:uuid:" + uuid.v4()); + this.set("seriesId", `urn:uuid:${uuid.v4()}`); } // Check to see if the old pid documents or is documented by itself selfDocuments = _.contains(this.get("documents"), oldPid); selfDocumentedBy = _.contains(this.get("isDocumentedBy"), oldPid); - //Set the new identifier + // Set the new identifier if (id) { this.set("id", id); + } else if (this.get("type") == "DataPackage") { + this.set("id", `resource_map_urn:uuid:${uuid.v4()}`); } else { - if (this.get("type") == "DataPackage") { - this.set("id", "resource_map_urn:uuid:" + uuid.v4()); - } else { - this.set("id", "urn:uuid:" + uuid.v4()); - } + this.set("id", `urn:uuid:${uuid.v4()}`); } // Remove the old pid from the documents list if present @@ -1583,7 +1579,7 @@

Source: src/js/models/DataONEObject.js

_.each( this.get("documents"), function (id) { - (documentedModels = MetacatUI.rootDataPackage.where({ id: id })), + (documentedModels = MetacatUI.rootDataPackage.where({ id })), documentedModel; if (documentedModels.length > 0) { @@ -1608,21 +1604,21 @@

Source: src/js/models/DataONEObject.js

this.trigger("change:id"); - //Update the obsoletes and obsoletedBy + // Update the obsoletes and obsoletedBy this.set("obsoletes", oldPid); this.set("obsoletedBy", null); // Update the latest version of this object this.set("latestVersion", this.get("id")); - //Set the archived option to false + // Set the archived option to false this.set("archived", false); }, /** * Resets the identifier for this model. This undos all of the changes made in {DataONEObject#updateID} */ - resetID: function () { + resetID() { if (!this.attributeCache) return false; this.set("oldPid", this.attributeCache.oldPid, { silent: true }); @@ -1636,7 +1632,7 @@

Source: src/js/models/DataONEObject.js

silent: true, }); - //Reset the attribute cache + // Reset the attribute cache this.attributeCache = {}; }, @@ -1644,28 +1640,28 @@

Source: src/js/models/DataONEObject.js

* Checks if this system metadata XML has updates that need to be synced with the server. * @returns {boolean} */ - hasUpdates: function () { + hasUpdates() { if (this.isNew()) return true; // Compare the new system metadata XML to the old system metadata XML - //Check if there is system metadata first + // Check if there is system metadata first if (!this.get("sysMetaXML")) { return false; } - var D1ObjectClone = this.clone(), - // Make sure we are using the parse function in the DataONEObject model. - // Sometimes hasUpdates is called from extensions of the D1Object model, - // (e.g. from the portal model), and the parse function is overwritten - oldSysMetaAttrs = new DataONEObject().parse( - D1ObjectClone.get("sysMetaXML"), - ); + const D1ObjectClone = this.clone(); + // Make sure we are using the parse function in the DataONEObject model. + // Sometimes hasUpdates is called from extensions of the D1Object model, + // (e.g. from the portal model), and the parse function is overwritten + const oldSysMetaAttrs = new DataONEObject().parse( + D1ObjectClone.get("sysMetaXML"), + ); D1ObjectClone.set(oldSysMetaAttrs); - var oldSysMeta = D1ObjectClone.serializeSysMeta(); - var newSysMeta = this.serializeSysMeta(); + const oldSysMeta = D1ObjectClone.serializeSysMeta(); + const newSysMeta = this.serializeSysMeta(); if (oldSysMeta === "") return false; @@ -1678,42 +1674,42 @@

Source: src/js/models/DataONEObject.js

@param {DataONEObject} [model] @param {object} options Furhter options for this function @property {boolean} options.force If true, a change will be handled regardless if the attribute actually changed - */ - handleChange: function (model, options) { + */ + handleChange(model, options) { if (!model) var model = this; - var sysMetaAttrs = [ - "serialVersion", - "identifier", - "formatId", - "formatType", - "size", - "checksum", - "checksumAlgorithm", - "submitter", - "rightsHolder", - "accessPolicy", - "replicationAllowed", - "replicationPolicy", - "obsoletes", - "obsoletedBy", - "archived", - "dateUploaded", - "dateSysMetadataModified", - "originMemberNode", - "authoritativeMemberNode", - "replica", - "seriesId", - "mediaType", - "fileName", - ], - nonSysMetaNonContentAttrs = _.difference( - model.get("originalAttrs"), - sysMetaAttrs, - ), - allChangedAttrs = Object.keys(model.changedAttributes()), - changedSysMetaOrContentAttrs = [], //sysmeta or content attributes that have changed - changedContentAttrs = []; // attributes from sub classes like ScienceMetadata or EML211 ... + const sysMetaAttrs = [ + "serialVersion", + "identifier", + "formatId", + "formatType", + "size", + "checksum", + "checksumAlgorithm", + "submitter", + "rightsHolder", + "accessPolicy", + "replicationAllowed", + "replicationPolicy", + "obsoletes", + "obsoletedBy", + "archived", + "dateUploaded", + "dateSysMetadataModified", + "originMemberNode", + "authoritativeMemberNode", + "replica", + "seriesId", + "mediaType", + "fileName", + ]; + const nonSysMetaNonContentAttrs = _.difference( + model.get("originalAttrs"), + sysMetaAttrs, + ); + const allChangedAttrs = Object.keys(model.changedAttributes()); + let changedSysMetaOrContentAttrs = []; // sysmeta or content attributes that have changed + let changedContentAttrs = []; // attributes from sub classes like ScienceMetadata or EML211 ... // Get a list of all changed sysmeta and content attributes changedSysMetaOrContentAttrs = _.difference( @@ -1752,19 +1748,19 @@

Source: src/js/models/DataONEObject.js

/** * Returns true if this DataONE object is new. A DataONE object is new * if there is no upload date and it's been synced (i.e. been fetched) - * @return {boolean} + * @returns {boolean} */ - isNew: function () { - //If the model is explicitly marked as not new, return false + isNew() { + // If the model is explicitly marked as not new, return false if (this.get("isNew") === false) { return false; } - //If the model is explicitly marked as new, return true - else if (this.get("isNew") === true) { + // If the model is explicitly marked as new, return true + if (this.get("isNew") === true) { return true; } - //Check if there is an upload date that was retrieved from the server + // Check if there is an upload date that was retrieved from the server return ( this.get("dateUploaded") === this.defaults().dateUploaded && this.get("synced") @@ -1774,12 +1770,12 @@

Source: src/js/models/DataONEObject.js

/** * Updates the upload status attribute on this model and marks the collection as changed */ - addToUploadQueue: function () { + addToUploadQueue() { if (!this.get("synced")) { return; } - //Add this item to the queue + // Add this item to the queue if ( this.get("uploadStatus") == "c" || this.get("uploadStatus") == "e" || @@ -1787,10 +1783,10 @@

Source: src/js/models/DataONEObject.js

) { this.set("uploadStatus", "q"); - //Mark each DataPackage collection this model is in as changed + // Mark each DataPackage collection this model is in as changed _.each( this.get("collections"), - function (collection) { + (collection) => { if (collection.packageModel) collection.packageModel.set("changed", true); }, @@ -1803,12 +1799,12 @@

Source: src/js/models/DataONEObject.js

* Updates the progress percentage when the model is getting uploaded * @param {ProgressEvent} e - The ProgressEvent when this file is being uploaded */ - updateProgress: function (e) { + updateProgress(e) { if (e.lengthComputable) { - var max = e.total; - var current = e.loaded; + const max = e.total; + const current = e.loaded; - var Percentage = (current * 100) / max; + const Percentage = (current * 100) / max; if (Percentage >= 100) { // process completed @@ -1819,25 +1815,28 @@

Source: src/js/models/DataONEObject.js

/** * Updates the relationships with other models when this model has been updated */ - updateRelationships: function () { + updateRelationships() { _.each( this.get("collections"), function (collection) { - //Get the old id for this model - var oldId = this.get("oldPid"); + // Get the old id for this model + const oldId = this.get("oldPid"); if (!oldId) return; - //Find references to the old id in the documents relationship - var outdatedModels = collection.filter(function (m) { - return _.contains(m.get("documents"), oldId); - }); + // Find references to the old id in the documents relationship + const outdatedModels = collection.filter((m) => + _.contains(m.get("documents"), oldId), + ); - //Update the documents array in each model + // Update the documents array in each model _.each( outdatedModels, function (model) { - var updatedDocuments = _.without(model.get("documents"), oldId); + const updatedDocuments = _.without( + model.get("documents"), + oldId, + ); updatedDocuments.push(this.get("id")); model.set("documents", updatedDocuments); @@ -1850,19 +1849,19 @@

Source: src/js/models/DataONEObject.js

}, /** - * Finds the latest version of this object by travesing the obsolescence chain - * @param {string} [latestVersion] - The identifier of the latest known object in the version chain. + * Finds the latest version of this object by travesing the obsolescence chain + * @param {string} [latestVersion] - The identifier of the latest known object in the version chain. If not supplied, this model's `id` will be used. - * @param {string} [possiblyNewer] - The identifier of the object that obsoletes the latestVersion. It's "possibly" newer, because it may be private/inaccessible - */ - findLatestVersion: function (latestVersion, possiblyNewer) { - var baseUrl = "", - activeAltRepo = MetacatUI.appModel.getActiveAltRepo(); - //Use the meta service URL from the alt repo + * @param {string} [possiblyNewer] - The identifier of the object that obsoletes the latestVersion. It's "possibly" newer, because it may be private/inaccessible + */ + findLatestVersion(latestVersion, possiblyNewer) { + let baseUrl = ""; + const activeAltRepo = MetacatUI.appModel.getActiveAltRepo(); + // Use the meta service URL from the alt repo if (activeAltRepo) { baseUrl = activeAltRepo.metaServiceUrl; } - //If this MetacatUI deployment is pointing to a MN, use the meta service URL from the AppModel + // If this MetacatUI deployment is pointing to a MN, use the meta service URL from the AppModel else { baseUrl = MetacatUI.appModel.get("metaServiceUrl"); } @@ -1871,7 +1870,7 @@

Source: src/js/models/DataONEObject.js

return; } - //If there is no system metadata, then retrieve it first + // If there is no system metadata, then retrieve it first if (!this.get("sysMetaXML")) { this.once("sync", this.findLatestVersion); this.once("systemMetadataSync", this.findLatestVersion); @@ -1883,47 +1882,47 @@

Source: src/js/models/DataONEObject.js

return; } - //If no pid was supplied, use this model's id - if (!latestVersion || typeof latestVersion != "string") { + // If no pid was supplied, use this model's id + if (!latestVersion || typeof latestVersion !== "string") { var latestVersion = this.get("id"); var possiblyNewer = this.get("obsoletedBy"); } - //If this isn't obsoleted by anything, then there is no newer version - if (!possiblyNewer || typeof latestVersion != "string") { + // If this isn't obsoleted by anything, then there is no newer version + if (!possiblyNewer || typeof latestVersion !== "string") { this.set("latestVersion", latestVersion); - //Trigger an event that will fire whether or not the latestVersion + // Trigger an event that will fire whether or not the latestVersion // attribute was actually changed this.trigger("latestVersionFound", this); - //Remove the listeners now that we found the latest version + // Remove the listeners now that we found the latest version this.stopListening("sync", this.findLatestVersion); this.stopListening("systemMetadataSync", this.findLatestVersion); return; } - var model = this; + const model = this; - //Get the system metadata for the possibly newer version - var requestSettings = { + // Get the system metadata for the possibly newer version + const requestSettings = { url: baseUrl + encodeURIComponent(possiblyNewer), type: "GET", - success: function (data) { + success(data) { // the response may have an obsoletedBy element - var obsoletedBy = $(data).find("obsoletedBy").text(); + const obsoletedBy = $(data).find("obsoletedBy").text(); - //If there is an even newer version, then get it and rerun this function + // If there is an even newer version, then get it and rerun this function if (obsoletedBy) { model.findLatestVersion(possiblyNewer, obsoletedBy); } - //If there isn't a newer version, then this is it + // If there isn't a newer version, then this is it else { model.set("latestVersion", possiblyNewer); model.trigger("latestVersionFound", model); - //Remove the listeners now that we found the latest version + // Remove the listeners now that we found the latest version model.stopListening("sync", model.findLatestVersion); model.stopListening( "systemMetadataSync", @@ -1931,8 +1930,8 @@

Source: src/js/models/DataONEObject.js

); } }, - error: function (xhr) { - //If this newer version isn't accessible, link to the latest version that is + error(xhr) { + // If this newer version isn't accessible, link to the latest version that is if (xhr.status == "401") { model.set("latestVersion", latestVersion); model.trigger("latestVersionFound", model); @@ -1953,139 +1952,100 @@

Source: src/js/models/DataONEObject.js

* @param {string|Element} xml - The XML to format * @returns {string} The formatted XML string */ - formatXML: function (xml) { - var nodeNameMap = this.nodeNameMap(), - xmlString = ""; + formatXML(xml) { + const nodeNameMap = this.nodeNameMap(); + let xmlString = ""; - //XML must be provided for this function + // XML must be provided for this function if (!xml) return ""; - //Support XML strings - else if (typeof xml == "string") xmlString = xml; - //Support DOMs - else if (typeof xml == "object" && xml.nodeType) { - //XML comments should be formatted with start and end carets - if (xml.nodeType == 8) xmlString = "<" + xml.nodeValue + ">"; - //XML nodes have the entire XML string available in the outerHTML attribute + // Support XML strings + if (typeof xml === "string") xmlString = xml; + // Support DOMs + else if (typeof xml === "object" && xml.nodeType) { + // XML comments should be formatted with start and end carets + if (xml.nodeType == 8) xmlString = `<${xml.nodeValue}>`; + // XML nodes have the entire XML string available in the outerHTML attribute else if (xml.nodeType == 1) xmlString = xml.outerHTML; - //Text node types are left as-is + // Text node types are left as-is else if (xml.nodeType == 3) return xml.nodeValue; } - //Return empty strings if something went wrong + // Return empty strings if something went wrong if (!xmlString) return ""; _.each( Object.keys(nodeNameMap), - function (name, i) { - var originalXMLString = xmlString; - - //Check for this node name whe it's an opening XML node, e.g. `<name>` - var regEx = new RegExp("<" + name + ">", "g"); - xmlString = xmlString.replace(regEx, "<" + nodeNameMap[name] + ">"); - - //Check for this node name when it's an opening XML node, e.g. `<name ` - regEx = new RegExp("<" + name + " ", "g"); - xmlString = xmlString.replace(regEx, "<" + nodeNameMap[name] + " "); - - //Check for this node name when it's preceeded by a namespace, e.g. `:name ` - regEx = new RegExp(":" + name + " ", "g"); - xmlString = xmlString.replace(regEx, ":" + nodeNameMap[name] + " "); - - //Check for this node name when it's a closing tag preceeded by a namespace, e.g. `:name>` - regEx = new RegExp(":" + name + ">", "g"); - xmlString = xmlString.replace(regEx, ":" + nodeNameMap[name] + ">"); - - //Check for this node name when it's a closing XML tag, e.g. `</name>` - regEx = new RegExp("</" + name + ">", "g"); - xmlString = xmlString.replace( - regEx, - "</" + nodeNameMap[name] + ">", - ); + (name, i) => { + const originalXMLString = xmlString; - //If node names haven't been changed, then find an attribute, e.g. ` name=` + // Check for this node name whe it's an opening XML node, e.g. `<name>` + let regEx = new RegExp(`<${name}>`, "g"); + xmlString = xmlString.replace(regEx, `<${nodeNameMap[name]}>`); + + // Check for this node name when it's an opening XML node, e.g. `<name ` + regEx = new RegExp(`<${name} `, "g"); + xmlString = xmlString.replace(regEx, `<${nodeNameMap[name]} `); + + // Check for this node name when it's preceeded by a namespace, e.g. `:name ` + regEx = new RegExp(`:${name} `, "g"); + xmlString = xmlString.replace(regEx, `:${nodeNameMap[name]} `); + + // Check for this node name when it's a closing tag preceeded by a namespace, e.g. `:name>` + regEx = new RegExp(`:${name}>`, "g"); + xmlString = xmlString.replace(regEx, `:${nodeNameMap[name]}>`); + + // Check for this node name when it's a closing XML tag, e.g. `</name>` + regEx = new RegExp(`</${name}>`, "g"); + xmlString = xmlString.replace(regEx, `</${nodeNameMap[name]}>`); + + // If node names haven't been changed, then find an attribute, e.g. ` name=` if (xmlString == originalXMLString) { - regEx = new RegExp(" " + name + "=", "g"); - xmlString = xmlString.replace( - regEx, - " " + nodeNameMap[name] + "=", - ); + regEx = new RegExp(` ${name}=`, "g"); + xmlString = xmlString.replace(regEx, ` ${nodeNameMap[name]}=`); } }, this, ); - //Take each XML node text value and decode any XML entities - var regEx = new RegExp("&[0-9a-zA-Z]+;", "g"); - xmlString = xmlString.replace(regEx, function (match) { - return he.encode(he.decode(match)); - }); + // Take each XML node text value and decode any XML entities + const regEx = new RegExp("&[0-9a-zA-Z]+;", "g"); + xmlString = xmlString.replace(regEx, (match) => + he.encode(he.decode(match)), + ); return xmlString; }, - /** - * Converts the number of bytes into a human readable format and - * updates the `sizeStr` attribute - * @returns: None - * - */ - bytesToSize: function () { - var kibibyte = 1024; - var mebibyte = kibibyte * 1024; - var gibibyte = mebibyte * 1024; - var tebibyte = gibibyte * 1024; - var precision = 0; - - var bytes = this.get("size"); - - if (bytes >= 0 && bytes < kibibyte) { - this.set("sizeStr", bytes + " B"); - } else if (bytes >= kibibyte && bytes < mebibyte) { - this.set("sizeStr", (bytes / kibibyte).toFixed(precision) + " KiB"); - } else if (bytes >= mebibyte && bytes < gibibyte) { - precision = 2; - this.set("sizeStr", (bytes / mebibyte).toFixed(precision) + " MiB"); - } else if (bytes >= gibibyte && bytes < tebibyte) { - precision = 2; - this.set("sizeStr", (bytes / gibibyte).toFixed(precision) + " GiB"); - } else if (bytes >= tebibyte) { - precision = 2; - this.set("sizeStr", (bytes / tebibyte).toFixed(precision) + " TiB"); - } else { - this.set("sizeStr", bytes + " B"); - } - }, - /** * This method will download this object while * sending the user's auth token in the request. * @returns None * @since: 2.28.0 */ - downloadWithCredentials: function () { - //if(this.get("isPublic")) return; + downloadWithCredentials() { + // if(this.get("isPublic")) return; - //Get info about this object - var url = this.get("url"), - model = this; + // Get info about this object + const url = this.get("url"); + const model = this; - //Create an XHR - var xhr = new XMLHttpRequest(); + // Create an XHR + const xhr = new XMLHttpRequest(); - //Open and send the request with the user's auth token + // Open and send the request with the user's auth token xhr.open("GET", url); if (MetacatUI.appUserModel.get("loggedIn")) xhr.withCredentials = true; - //When the XHR is ready, create a link with the raw data (Blob) and click the link to download + // When the XHR is ready, create a link with the raw data (Blob) and click the link to download xhr.onload = function () { if (this.status == 404) { this.onerror.call(this); return; } - //Get the file name to save this file as - var filename = xhr.getResponseHeader("Content-Disposition"); + // Get the file name to save this file as + let filename = xhr.getResponseHeader("Content-Disposition"); if (!filename) { filename = @@ -2098,16 +2058,16 @@

Source: src/js/models/DataONEObject.js

.substring(filename.indexOf("filename=") + 9) .replace(/"/g, ""); - //Replace any whitespaces + // Replace any whitespaces filename = filename.trim().replace(/ /g, "_"); - //For IE, we need to use the navigator API + // For IE, we need to use the navigator API if (navigator && navigator.msSaveOrOpenBlob) { navigator.msSaveOrOpenBlob(xhr.response, filename); } - //Other browsers can download it via a link + // Other browsers can download it via a link else { - var a = document.createElement("a"); + const a = document.createElement("a"); a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob // Set the file name. @@ -2142,7 +2102,7 @@

Source: src/js/models/DataONEObject.js

xhr.onprogress = function (e) { if (e.lengthComputable) { - var percent = (e.loaded / e.total) * 100; + const percent = (e.loaded / e.total) * 100; model.set("downloadPercent", percent); } }; @@ -2152,7 +2112,7 @@

Source: src/js/models/DataONEObject.js

if (MetacatUI.appUserModel.get("loggedIn")) xhr.setRequestHeader( "Authorization", - "Bearer " + MetacatUI.appUserModel.get("token"), + `Bearer ${MetacatUI.appUserModel.get("token")}`, ); xhr.send(); @@ -2161,8 +2121,10 @@

Source: src/js/models/DataONEObject.js

/** * Creates a file name for this DataONEObject and updates the `fileName` attribute */ - setMissingFileName: function () { - var objectFormats, filename, extension; + setMissingFileName() { + let objectFormats; + let filename; + let extension; objectFormats = MetacatUI.objectFormats.where({ formatId: this.get("formatId"), @@ -2171,28 +2133,28 @@

Source: src/js/models/DataONEObject.js

extension = objectFormats[0].get("extension"); } - //Science metadata file names will use the title + // Science metadata file names will use the title if (this.get("type") == "Metadata") { filename = Array.isArray(this.get("title")) && this.get("title").length ? this.get("title")[0] : this.get("id"); } - //Resource maps will use a "resource_map_" prefix + // Resource maps will use a "resource_map_" prefix else if (this.get("type") == "DataPackage") { - filename = "resource_map_" + this.get("id"); + filename = `resource_map_${this.get("id")}`; extension = ".rdf.xml"; } - //All other object types will just use the id + // All other object types will just use the id else { filename = this.get("id"); } - //Replace all non-alphanumeric characters with underscores + // Replace all non-alphanumeric characters with underscores filename = filename.replace(/[^a-zA-Z0-9]/g, "_"); if (typeof extension !== "undefined") { - filename = filename + "." + extension; + filename = `${filename}.${extension}`; } this.set("fileName", filename); @@ -2200,24 +2162,22 @@

Source: src/js/models/DataONEObject.js

/** * Creates a URL for viewing more information about this object - * @return {string} + * @returns {string} */ - createViewURL: function () { - return ( - MetacatUI.root + - "/view/" + - encodeURIComponent(this.get("seriesId") || this.get("id")) - ); + createViewURL() { + return `${MetacatUI.root}/view/${encodeURIComponent( + this.get("seriesId") || this.get("id"), + )}`; }, /** * Check if the seriesID or PID matches a DOI regex, and if so, return * a canonical IRI for the DOI. - * @return {string|null} - The canonical IRI for the DOI, or null if + * @returns {string|null} - The canonical IRI for the DOI, or null if * neither the seriesId nor the PID match a DOI regex. * @since 2.26.0 */ - getCanonicalDOIIRI: function () { + getCanonicalDOIIRI() { const id = this.get("id"); const seriesId = this.get("seriesId"); let DOI = null; @@ -2229,14 +2189,14 @@

Source: src/js/models/DataONEObject.js

/** * Converts the identifier string to a string safe to use in an XML id attribute * @param {string} [id] - The ID string - * @return {string} - The XML-safe string + * @returns {string} - The XML-safe string */ - getXMLSafeID: function (id) { - if (typeof id == "undefined") { + getXMLSafeID(id) { + if (typeof id === "undefined") { var id = this.get("id"); } - //Replace XML id attribute invalid characters and patterns in the identifier + // Replace XML id attribute invalid characters and patterns in the identifier id = id .replace(/</g, "-") .replace(/:/g, "-") @@ -2245,14 +2205,14 @@

Source: src/js/models/DataONEObject.js

return id; }, - /**** Provenance-related functions ****/ + /** ** Provenance-related functions */ /** * Returns true if this provenance field points to a source of this data or metadata object * @param {string} field * @returns {boolean} */ - isSourceField: function (field) { - if (typeof field == "undefined" || !field) return false; + isSourceField(field) { + if (typeof field === "undefined" || !field) return false; // Is the field we are checking a prov field? if (!_.contains(MetacatUI.appSearchModel.getProvFields(), field)) return false; @@ -2265,7 +2225,7 @@

Source: src/js/models/DataONEObject.js

field == "prov_wasInformedBy" ) return true; - else return false; + return false; }, /** @@ -2273,8 +2233,8 @@

Source: src/js/models/DataONEObject.js

* @param {string} field * @returns {boolean} */ - isDerivationField: function (field) { - if (typeof field == "undefined" || !field) return false; + isDerivationField(field) { + if (typeof field === "undefined" || !field) return false; if (!_.contains(MetacatUI.appSearchModel.getProvFields(), field)) return false; @@ -2285,42 +2245,44 @@

Source: src/js/models/DataONEObject.js

field == "prov_generated" ) return true; - else return false; + return false; }, /** * Returns a plain-english version of the general format - either image, program, metadata, PDF, annotation or data */ - getType: function () { - //The list of formatIds that are images + getType() { + // The list of formatIds that are images - //The list of formatIds that are images - var pdfIds = ["application/pdf"]; - var annotationIds = [ + // The list of formatIds that are images + const pdfIds = ["application/pdf"]; + const annotationIds = [ "http://docs.annotatorjs.org/en/v1.2.x/annotation-format.html", ]; // Type has already been set, use that. if (this.get("type").toLowerCase() == "metadata") return "metadata"; - //Determine the type via provONE - var instanceOfClass = this.get("prov_instanceOfClass"); + // Determine the type via provONE + const instanceOfClass = this.get("prov_instanceOfClass"); if ( typeof instanceOfClass !== "undefined" && Array.isArray(instanceOfClass) && instanceOfClass.length ) { - var programClass = _.filter(instanceOfClass, function (className) { - return className.indexOf("#Program") > -1; - }); + const programClass = _.filter( + instanceOfClass, + (className) => className.indexOf("#Program") > -1, + ); if (typeof programClass !== "undefined" && programClass.length) return "program"; - } else { - if (this.get("prov_generated").length || this.get("prov_used").length) - return "program"; - } + } else if ( + this.get("prov_generated").length || + this.get("prov_used").length + ) + return "program"; - //Determine the type via file format + // Determine the type via file format if (this.isSoftware()) return "program"; if (this.isData()) return "data"; @@ -2329,20 +2291,20 @@

Source: src/js/models/DataONEObject.js

if (_.contains(pdfIds, this.get("formatId"))) return "PDF"; if (_.contains(annotationIds, this.get("formatId"))) return "annotation"; - else return "data"; + return "data"; }, /** * Checks the formatId of this model and determines if it is an image. * @returns {boolean} true if this data object is an image, false if it is other */ - isImage: function () { - //The list of formatIds that are images - var imageIds = ["image/gif", "image/jp2", "image/jpeg", "image/png"]; + isImage() { + // The list of formatIds that are images + const imageIds = ["image/gif", "image/jp2", "image/jpeg", "image/png"]; - //Does this data object match one of these IDs? + // Does this data object match one of these IDs? if (_.indexOf(imageIds, this.get("formatId")) == -1) return false; - else return true; + return true; }, /** @@ -2352,8 +2314,8 @@

Source: src/js/models/DataONEObject.js

* as images {@link DataONEObject#isImage} or software {@link DataONEObject#isSoftware}. * @returns {boolean} true if this data object is a data file, false if it is other */ - isData: function () { - var dataIds = [ + isData() { + const dataIds = [ "application/atom+xml", "application/mathematica", "application/msword", @@ -2400,9 +2362,9 @@

Source: src/js/models/DataONEObject.js

"video/x-ms-wmv", ]; - //Does this data object match one of these IDs? + // Does this data object match one of these IDs? if (_.indexOf(dataIds, this.get("formatId")) == -1) return false; - else return true; + return true; }, /** @@ -2412,9 +2374,9 @@

Source: src/js/models/DataONEObject.js

* as images {@link DataONEObject#isImage} for display purposes. * @returns {boolean} true if this data object is a software file, false if it is other */ - isSoftware: function () { - //The list of formatIds that are programs - var softwareIds = [ + isSoftware() { + // The list of formatIds that are programs + const softwareIds = [ "text/x-python", "text/x-rsrc", "text/x-matlab", @@ -2422,22 +2384,22 @@

Source: src/js/models/DataONEObject.js

"application/R", "application/x-ipynb+json", ]; - //Does this data object match one of these IDs? + // Does this data object match one of these IDs? if (_.indexOf(softwareIds, this.get("formatId")) == -1) return false; - else return true; + return true; }, /** * Checks the formatId of this model and determines if it a PDF. * @returns {boolean} true if this data object is a pdf, false if it is other */ - isPDF: function () { - //The list of formatIds that are images - var ids = ["application/pdf"]; + isPDF() { + // The list of formatIds that are images + const ids = ["application/pdf"]; - //Does this data object match one of these IDs? + // Does this data object match one of these IDs? if (_.indexOf(ids, this.get("formatId")) == -1) return false; - else return true; + return true; }, /** @@ -2449,7 +2411,7 @@

Source: src/js/models/DataONEObject.js

* see https://github.com/DataONEorg/sem-prov-ontologies/blob/master/provenance/ProvONE/v1/provone.html * @param {string} className */ - setProvClass: function (className) { + setProvClass(className) { className = className.toLowerCase(); className = className.charAt(0).toUpperCase() + className.slice(1); @@ -2480,10 +2442,7 @@

Source: src/js/models/DataONEObject.js

) { this.set("prov_instanceOfClass", [this.PROV + className]); } else { - message = - "The given class name: " + - className + - " is not in the known ProvONE or PROV classes."; + message = `The given class name: ${className} is not in the known ProvONE or PROV classes.`; throw new Error(message); } }, @@ -2491,17 +2450,17 @@

Source: src/js/models/DataONEObject.js

/** * Calculate a checksum for the object * @param {string} [algorithm] The algorithm to use, defaults to MD5 - * @return {string} A checksum plain JS object with value and algorithm attributes + * @returns {string} A checksum plain JS object with value and algorithm attributes */ - calculateChecksum: function (algorithm) { + calculateChecksum(algorithm) { var algorithm = algorithm || "MD5"; - var checksum = { algorithm: undefined, value: undefined }; - var hash; // The checksum hash - var file; // The file to be read by slicing - var reader; // The FileReader used to read each slice - var offset = 0; // Byte offset for reading slices - var sliceSize = Math.pow(2, 20); // 1MB slices - var model = this; + const checksum = { algorithm: undefined, value: undefined }; + let hash; // The checksum hash + let file; // The file to be read by slicing + let reader; // The FileReader used to read each slice + let offset = 0; // Byte offset for reading slices + const sliceSize = 2 ** 20; // 1MB slices + const model = this; // Do we have a file? if (this.get("uploadFile") instanceof Blob) { @@ -2509,7 +2468,7 @@

Source: src/js/models/DataONEObject.js

reader = new FileReader(); /* Handle load errors */ reader.onerror = function (event) { - console.log("Error reading: " + event); + console.log(`Error reading: ${event}`); }; /* Show progress */ reader.onprogress = function (event) {}; @@ -2540,8 +2499,7 @@

Source: src/js/models/DataONEObject.js

// TODO: Support SHA-1 // break; default: - message = - "The given algorithm: " + algorithm + " is not supported."; + message = `The given algorithm: ${algorithm} is not supported.`; throw new Error(message); } @@ -2549,9 +2507,12 @@

Source: src/js/models/DataONEObject.js

* A helper function internal to calculateChecksum() used to slice * the file at the next offset by slice size */ + /** + * + */ function _seek() { - var calculated = false; - var slice; + let calculated = false; + let slice; // Digest the checksum when we're done calculating if (offset >= file.size) { hash.digest(); @@ -2567,11 +2528,10 @@

Source: src/js/models/DataONEObject.js

/** * Checks if the pid or sid or given string is a DOI - * * @param {string} customString - Optional. An identifier string to check instead of the id and seriesId attributes on the model * @returns {boolean} True if it is a DOI */ - isDOI: function (customString) { + isDOI(customString) { return ( isDOI(customString) || isDOI(this.get("id")) || @@ -2583,58 +2543,55 @@

Source: src/js/models/DataONEObject.js

* Creates an array of objects that represent Member Nodes that could possibly be this * object's authoritative MN. This function updates the `possibleAuthMNs` attribute on this model. */ - setPossibleAuthMNs: function () { - //Only do this for Coordinating Node MetacatUIs. + setPossibleAuthMNs() { + // Only do this for Coordinating Node MetacatUIs. if (MetacatUI.appModel.get("alternateRepositories").length) { - //Set the possibleAuthMNs attribute - var possibleAuthMNs = []; + // Set the possibleAuthMNs attribute + const possibleAuthMNs = []; - //If a datasource is already found for this Portal, move that to the top of the list of auth MNs - var datasource = this.get("datasource") || ""; + // If a datasource is already found for this Portal, move that to the top of the list of auth MNs + const datasource = this.get("datasource") || ""; if (datasource) { - //Find the MN object that matches the datasource node ID - var datasourceMN = _.findWhere( + // Find the MN object that matches the datasource node ID + const datasourceMN = _.findWhere( MetacatUI.appModel.get("alternateRepositories"), { identifier: datasource }, ); if (datasourceMN) { - //Clone the MN object and add it to the array - var clonedDatasourceMN = Object.assign({}, datasourceMN); + // Clone the MN object and add it to the array + const clonedDatasourceMN = { ...datasourceMN }; possibleAuthMNs.push(clonedDatasourceMN); } } - //If there is an active alternate repo, move that to the top of the list of auth MNs - var activeAltRepo = + // If there is an active alternate repo, move that to the top of the list of auth MNs + const activeAltRepo = MetacatUI.appModel.get("activeAlternateRepositoryId") || ""; if (activeAltRepo) { - var activeAltRepoMN = _.findWhere( + const activeAltRepoMN = _.findWhere( MetacatUI.appModel.get("alternateRepositories"), { identifier: activeAltRepo }, ); if (activeAltRepoMN) { - //Clone the MN object and add it to the array - var clonedActiveAltRepoMN = Object.assign({}, activeAltRepoMN); + // Clone the MN object and add it to the array + const clonedActiveAltRepoMN = { ...activeAltRepoMN }; possibleAuthMNs.push(clonedActiveAltRepoMN); } } - //Add all the other alternate repositories to the list of auth MNs - var otherPossibleAuthMNs = _.reject( + // Add all the other alternate repositories to the list of auth MNs + const otherPossibleAuthMNs = _.reject( MetacatUI.appModel.get("alternateRepositories"), - function (mn) { - return ( - mn.identifier == datasource || mn.identifier == activeAltRepo - ); - }, + (mn) => + mn.identifier == datasource || mn.identifier == activeAltRepo, ); - //Clone each MN object and add to the array - _.each(otherPossibleAuthMNs, function (mn) { - var clonedMN = Object.assign({}, mn); + // Clone each MN object and add to the array + _.each(otherPossibleAuthMNs, (mn) => { + const clonedMN = { ...mn }; possibleAuthMNs.push(clonedMN); }); - //Update this model + // Update this model this.set("possibleAuthMNs", possibleAuthMNs); } }, @@ -2646,13 +2603,13 @@

Source: src/js/models/DataONEObject.js

* models were created with `id`s with new line and white space characters (e.g. `\n urn:uuid:1234...`) * @param {object} json - The Solr document as a JS Object, which will be directly altered */ - removeWhiteSpaceFromSolrFields: function (json) { - if (typeof json.resourceMap == "string") { + removeWhiteSpaceFromSolrFields(json) { + if (typeof json.resourceMap === "string") { json.resourceMap = json.resourceMap.trim(); } else if (Array.isArray(json.resourceMap)) { - let newResourceMapIds = []; - _.each(json.resourceMap, function (rMapId) { - if (typeof rMapId == "string") { + const newResourceMapIds = []; + _.each(json.resourceMap, (rMapId) => { + if (typeof rMapId === "string") { newResourceMapIds.push(rMapId.trim()); } }); @@ -2667,15 +2624,15 @@

Source: src/js/models/DataONEObject.js

* Generate a unique identifier to be used as an XML id attribute * @returns {string} The identifier string that was generated */ - generateId: function () { - var idStr = ""; // the id to return - var length = 30; // the length of the generated string - var chars = + generateId() { + let idStr = ""; // the id to return + const length = 30; // the length of the generated string + const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".split( "", ); - for (var i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { idStr += chars[Math.floor(Math.random() * chars.length)]; } return idStr; diff --git a/docs/docs/src_js_models_LogsSearch.js.html b/docs/docs/src_js_models_LogsSearch.js.html index 5bdef946e..451c152ee 100644 --- a/docs/docs/src_js_models_LogsSearch.js.html +++ b/docs/docs/src_js_models_LogsSearch.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_LookupModel.js.html b/docs/docs/src_js_models_LookupModel.js.html index 42a91e916..ff9225eac 100644 --- a/docs/docs/src_js_models_LookupModel.js.html +++ b/docs/docs/src_js_models_LookupModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -67,6 +67,7 @@

Source: src/js/models/LookupModel.js

initialize: function () {}, + /** @deprecated */ bioportalSearch: function (request, response, localValues, allValues) { // make sure we have something to lookup if (!MetacatUI.appModel.get("bioportalAPIKey")) { diff --git a/docs/docs/src_js_models_Map.js.html b/docs/docs/src_js_models_Map.js.html index 7884c8ae4..835b1c44f 100644 --- a/docs/docs/src_js_models_Map.js.html +++ b/docs/docs/src_js_models_Map.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_MetricsModel.js.html b/docs/docs/src_js_models_MetricsModel.js.html index 0dad23ba8..5df323e05 100644 --- a/docs/docs/src_js_models_MetricsModel.js.html +++ b/docs/docs/src_js_models_MetricsModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_QualityCheckModel.js.html b/docs/docs/src_js_models_QualityCheckModel.js.html index 9a0d5d7a4..b3c4c3f76 100644 --- a/docs/docs/src_js_models_QualityCheckModel.js.html +++ b/docs/docs/src_js_models_QualityCheckModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_Search.js.html b/docs/docs/src_js_models_Search.js.html index 35305727f..25f9bb2d4 100644 --- a/docs/docs/src_js_models_Search.js.html +++ b/docs/docs/src_js_models_Search.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_SolrResult.js.html b/docs/docs/src_js_models_SolrResult.js.html index e0e9a737e..f2f0eb707 100644 --- a/docs/docs/src_js_models_SolrResult.js.html +++ b/docs/docs/src_js_models_SolrResult.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -905,38 +905,6 @@

Source: src/js/models/SolrResult.js

//If nothing works so far, return an empty array return []; }, - - /****************************/ - - /** - * Convert number of bytes into human readable format - * - * @param integer bytes Number of bytes to convert - * @param integer precision Number of digits after the decimal separator - * @return string - */ - bytesToSize: function (bytes, precision) { - var kibibyte = 1024; - var mebibyte = kibibyte * 1024; - var gibibyte = mebibyte * 1024; - var tebibyte = gibibyte * 1024; - - if (typeof bytes === "undefined") var bytes = this.get("size"); - - if (bytes >= 0 && bytes < kibibyte) { - return bytes + " B"; - } else if (bytes >= kibibyte && bytes < mebibyte) { - return (bytes / kibibyte).toFixed(precision) + " KiB"; - } else if (bytes >= mebibyte && bytes < gibibyte) { - return (bytes / mebibyte).toFixed(precision) + " MiB"; - } else if (bytes >= gibibyte && bytes < tebibyte) { - return (bytes / gibibyte).toFixed(precision) + " GiB"; - } else if (bytes >= tebibyte) { - return (bytes / tebibyte).toFixed(precision) + " TiB"; - } else { - return bytes + " B"; - } - }, }, ); return SolrResult; diff --git a/docs/docs/src_js_models_Stats.js.html b/docs/docs/src_js_models_Stats.js.html index 02d395089..c072a59f1 100644 --- a/docs/docs/src_js_models_Stats.js.html +++ b/docs/docs/src_js_models_Stats.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_UserModel.js.html b/docs/docs/src_js_models_UserModel.js.html index e422ae3fb..31f76919a 100644 --- a/docs/docs/src_js_models_UserModel.js.html +++ b/docs/docs/src_js_models_UserModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_accordion_Accordion.js.html b/docs/docs/src_js_models_accordion_Accordion.js.html new file mode 100644 index 000000000..d3fb42096 --- /dev/null +++ b/docs/docs/src_js_models_accordion_Accordion.js.html @@ -0,0 +1,168 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/accordion/Accordion.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/accordion/Accordion.js

+ + + + + + +
+
+
define(["backbone", "models/accordion/AccordionItem"], (
+  Backbone,
+  AccordionItem,
+) => {
+  /**
+   * @class Accordion
+   * @classdesc A model representing an accordion with nested accordion items
+   * @classcategory Models
+   * @augments Backbone.Model
+   * @constructs
+   * @augments Backbone.Model
+   * @since 2.31.0
+   */
+  const Accordion = Backbone.Model.extend(
+    /** @lends Accordion.prototype */
+    {
+      /** @inheritdoc */
+      type: "Accordion",
+
+      /**
+       * Note: Do not set a "easing" attribute on this model. It seems to break
+       * semanticUI accordion.
+       * @returns {object} Default attributes for an Accordion model.
+       * @property {boolean} exclusive - Only allow one section open at a time.
+       * @property {string} on - Event on title that will cause accordion to
+       * open. Commonly set to "click".
+       * @property {boolean} animateChildren - Whether child content opacity
+       * should be animated. Note: may cause performance issues with many child
+       * elements.
+       * @property {boolean} closeNested - Close open nested accordion content
+       * when an element closes.
+       * @property {boolean} collapsible - Allow active sections to collapse.
+       * @property {number} duration - Duration in milliseconds of the opening
+       * animation.
+       * @see {@link https://fomantic-ui.com/modules/accordion.html#settings}
+       * for more information on accordion settings.
+       * @see {@link https://api.jqueryui.com/easings/} for easing options.
+       * @property {Function} onOpening - Callback function before an element
+       * opens. Takes the active content as an argument.
+       * @property {Function} onOpen - Callback function after an element is
+       * open. Takes the active content as an argument.
+       * @property {Function} onClosing - Callback function before an element
+       * closes. Takes the active content as an argument.
+       * @property {Function} onClose - Callback function after an element is
+       * closed. Takes the active content as an argument.
+       * @property {Function} onChanging - Callback function before an element
+       * opens or closes. Takes the active content as an argument.
+       * @property {Function} onChange - Callback function when an element opens
+       * or closes. Takes the active content as an argument.
+       * @property {boolean} styled - Whether to use Semantic UI styles for the
+       * accordion.
+       * @property {boolean} inverted - Whether to use an inverted color scheme
+       * for the accordion (dark background with light text).
+       * @property {boolean} fluid - Whether the accordion should take up the
+       * full width of its container.
+       */
+      defaults() {
+        return {
+          exclusive: true,
+          on: "click",
+          animateChildren: true,
+          closeNested: true,
+          collapsible: true,
+          duration: 300,
+          onOpening: null,
+          onOpen: null,
+          onClosing: null,
+          onClose: null,
+          onChanging: null,
+          onChange: null,
+          styled: true,
+          inverted: false,
+          fluid: true,
+        };
+      },
+
+      /** @inheritdoc */
+      initialize(attributes, _options) {
+        const items = attributes?.items || [];
+        const collection = new Backbone.Collection(items, {
+          model: AccordionItem,
+        });
+        this.set("items", collection);
+      },
+
+      /**
+       * Get the children of an item by its id
+       * @param {string} id - The id of the parent item
+       * @returns {AccordianItem[]} An array of AccordianItem models
+       */
+      getChildren(id) {
+        return this.get("items").where({ parent: id });
+      },
+
+      /**
+       * Get the root items of the accordion. Root items are those without a
+       * parent attribute or with an empty string as the parent attribute.
+       * @returns {AccordianItem[]} An array of AccordianItem models
+       */
+      getRootItems() {
+        return this.get("items").filter((item) => !item.get("parent"));
+      },
+    },
+  );
+
+  return Accordion;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_accordion_AccordionItem.js.html b/docs/docs/src_js_models_accordion_AccordionItem.js.html new file mode 100644 index 000000000..b02e4e42c --- /dev/null +++ b/docs/docs/src_js_models_accordion_AccordionItem.js.html @@ -0,0 +1,129 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/accordion/AccordionItem.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/accordion/AccordionItem.js

+ + + + + + +
+
+
define(["backbone"], (Backbone) => {
+  /**
+   * @class AccordionItem
+   * @classdesc A model representing a single item in a nested Semantic UI
+   * accordion
+   * @classcategory Models/Accordion
+   * @augments Backbone.Model
+   * @constructs
+   * @since 2.31.0
+   */
+  const AccordionItem = Backbone.Model.extend(
+    /** @lends AccordionItem.prototype */
+    {
+      /** @inheritdoc */
+      type: "AccordionItem",
+
+      /**
+       * @returns {object} Default attributes for an AccordionItem model.
+       * @property {string} itemId - The unique identifier for the item. This is
+       * required in order for any child items to be nested under this item. If
+       * not provided, it will be generated from the title.
+       * @property {string} title - The title of the item.
+       * @property {string} content - Content for the dropdown item. This will
+       * be ignored if there are child items.
+       * @property {string} parent - The parent item's itemId. If blank or null,
+       * this item is a top-level item.
+       * TODO:
+       * @property {string} description - The tooltip content.
+       * @property {string} subTitle - The tag to show next to the title.
+       * @property {boolean} selectable - Whether the item is selectable.
+       * @property {boolean} hasChildren - Whether the item has children.
+       */
+      defaults() {
+        return {
+          itemId: "",
+          title: "",
+          content: "",
+          parent: "",
+          // TODO: Add and make use of these attributes
+          // description: "", // tooltip content
+          // subTitle: "", // show as tag next to title
+          // selectable: false,
+          // hasChildren: false,
+        };
+      },
+
+      /** @inheritdoc */
+      initialize(_attributes, _options) {
+        // if there's no itemId on the model or passed in, set it from the title
+        if (!this.get("itemId")) {
+          this.setIdFromTitle();
+        }
+      },
+
+      /**
+       * Sets the itemId from the title, replacing spaces with dashes and
+       * removing any non-alphanumeric characters.
+       */
+      setIdFromTitle() {
+        const title = this.get("title");
+        let id = title.replace(/\s/g, "-").toLowerCase();
+        id = id.replace(/[^a-z0-9-]/g, "");
+        this.set("itemId", id);
+      },
+    },
+  );
+  return AccordionItem;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_analytics_Analytics.js.html b/docs/docs/src_js_models_analytics_Analytics.js.html index e4fc7d9e3..880b9cd95 100644 --- a/docs/docs/src_js_models_analytics_Analytics.js.html +++ b/docs/docs/src_js_models_analytics_Analytics.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_analytics_GoogleAnalytics.js.html b/docs/docs/src_js_models_analytics_GoogleAnalytics.js.html index de73ee37d..f85c1bb86 100644 --- a/docs/docs/src_js_models_analytics_GoogleAnalytics.js.html +++ b/docs/docs/src_js_models_analytics_GoogleAnalytics.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_bookkeeper_Quota.js.html b/docs/docs/src_js_models_bookkeeper_Quota.js.html index 9a952d3f8..1c186615c 100644 --- a/docs/docs/src_js_models_bookkeeper_Quota.js.html +++ b/docs/docs/src_js_models_bookkeeper_Quota.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_bookkeeper_Subscription.js.html b/docs/docs/src_js_models_bookkeeper_Subscription.js.html index 842f45224..b150d8fa1 100644 --- a/docs/docs/src_js_models_bookkeeper_Subscription.js.html +++ b/docs/docs/src_js_models_bookkeeper_Subscription.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_bookkeeper_Usage.js.html b/docs/docs/src_js_models_bookkeeper_Usage.js.html index b6edfeca9..d096c8508 100644 --- a/docs/docs/src_js_models_bookkeeper_Usage.js.html +++ b/docs/docs/src_js_models_bookkeeper_Usage.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_Bioontology-Accordion-SearchSelect.js.html b/docs/docs/src_js_models_connectors_Bioontology-Accordion-SearchSelect.js.html new file mode 100644 index 000000000..c13c2c2ce --- /dev/null +++ b/docs/docs/src_js_models_connectors_Bioontology-Accordion-SearchSelect.js.html @@ -0,0 +1,279 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/connectors/Bioontology-Accordion-SearchSelect.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/connectors/Bioontology-Accordion-SearchSelect.js

+ + + + + + +
+
+
"use strict";
+
+define([
+  "backbone",
+  "models/ontologies/Bioontology",
+  "models/accordion/Accordion",
+  "models/searchSelect/SearchSelect",
+], (Backbone, Bioontology, Accordion, SearchSelect) =>
+  /**
+   * @class BioontologyAccordionSearchSelect
+   * @classdesc Manages interactions between the BioPortal API and UI components.
+   * It connects the SearchSelect model, which specifies the ontology for querying,
+   * with the Accordion model that displays the search results. Changes in the selected
+   * ontology trigger a new search, updating the Accordion with formatted results.
+   * This model also tracks selected ontology classes for use across the application,
+   * primarily in the BioontologyBrowser view.
+   * @name  BioontologyAccordionSearchSelect
+   * @augments Backbone.Model
+   * @class
+   * @classcategory Models/Connectors
+   * @since 2.31.0
+   */
+  Backbone.Model.extend(
+    /** @lends  BioontologyAccordionSearchSelect.prototype */ {
+      /**
+       * Default model attributes
+       * @type {object}
+       * @property {Bioontology} bioontology - The Bioontology model
+       * @property {Accordion} accordion - The Accordion model
+       * @property {SearchSelect} searchSelect - The SearchSelect model
+       * @property {BioontologyClass} selectedClass - The selected ontology class
+       * @property {string} accordionRoot - The root-level ontology or subtree when
+       * the Bioontology model is first fetched (can change when searching subtrees).
+       * @property {string} defaultSubtree - The default subtree to display when
+       * if no subtree is specified in the ontology options.
+       * @property {Array} ontologyOptions - An array of objects specifying the
+       * ontologies to choose from in the SearchSel
+       */
+      defaults() {
+        return {
+          bioontology: null,
+          accordion: null,
+          searchSelect: null,
+          selectedClass: null,
+          accordionRoot: null,
+          defaultSubtree: "http://www.w3.org/2002/07/owl#Thing",
+          ontologyOptions: [
+            {
+              label: "Measurement Type",
+              ontology: "ECSO",
+              subTree:
+                "http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#MeasurementType",
+            },
+          ],
+        };
+      },
+
+      /** @inheritdoc */
+      initialize(attrs, _options) {
+        // Each ontology needs a unique value for the searchSelect component
+        const defaults = this.defaults();
+        const ontologyOptions =
+          attrs?.ontologyOptions || defaults.ontologyOptions;
+        const updatedOntologyOptions = ontologyOptions.map((option, index) => ({
+          ...option,
+          value: `ontology-${index}`,
+        }));
+        const firstOntology = updatedOntologyOptions[0] || {};
+        const firstOntologyValue = firstOntology.value || "";
+
+        this.setupBioontology(firstOntology);
+        this.setupAccordion();
+        this.setupSearchSelect(updatedOntologyOptions, firstOntologyValue);
+        this.setAccordionRoot();
+        this.connect();
+      },
+
+      /**
+       * Sets up the Bioontology model with the first ontology and fetches the
+       * ontology classes.
+       * @param {object} firstOntology - The first ontology object in the
+       * ontologyOptions array.
+       */
+      setupBioontology(firstOntology) {
+        const bioontology = new Bioontology({
+          ontology: firstOntology.ontology,
+          subTree: firstOntology.subTree,
+        });
+        this.set("bioontology", bioontology);
+      },
+
+      /**
+       * Sets up the Accordion model with the first ontology and fetches the
+       * ontology classes.
+       */
+      setupAccordion() {
+        const accordion = new Accordion({
+          onOpening: this.fetchChildren.bind(this),
+          onChanging: this.setSelectedClass.bind(this),
+          items: [{ title: "loading..." }],
+        });
+        this.set("accordion", accordion);
+      },
+
+      /**
+       * Sets up the SearchSelect model with the ontology options and the first
+       * ontology.
+       * @param {object[]} options - An array of ontology options objects to
+       * populate a search select model.
+       * @param {string} selected - The value of the first ontology to select.
+       */
+      setupSearchSelect(options, selected) {
+        const searchSelect = new SearchSelect({
+          buttonStyle: true,
+          icon: "sitemap",
+          allowMulti: false,
+          allowAdditions: false,
+          clearable: false,
+          selected: [selected],
+          inputLabel: "Browse for an ontology or class",
+          options,
+        });
+        this.set("searchSelect", searchSelect);
+      },
+
+      /**
+       * Sets the accordionRoot attribute to the root ontology or subtree when
+       * the Bioontology model is first fetched.
+       * @param {string} [subTree] - The root ontology or subtree. If not
+       * provided, current subTree of the Bioontology model is used or the
+       * default subtree.
+       */
+      setAccordionRoot(subTree) {
+        const root =
+          subTree ||
+          this.get("bioontology").get("subTree") ||
+          this.get("defaultSubtree");
+        this.set("accordionRoot", root);
+      },
+
+      /**
+       * Connects the three models together. When the bioontology results change,
+       * the accordion display model is updated to reflect the new results. When
+       * the selected ontology model changes in the searchSelect, the bioontology
+       * model is updated to reflect the new ontology.
+       */
+      connect() {
+        this.listenTo(
+          this.get("bioontology").get("collection"),
+          "update reset",
+          this.syncAccordion,
+        );
+        this.listenTo(
+          this.get("searchSelect"),
+          "change:selected",
+          (model, _selected) => {
+            const ontology = model.getSelectedModels()[0];
+            this.switchOntology(ontology);
+          },
+        );
+      },
+
+      /**
+       * Fetches the children of an ontology class from the BioPortal API.
+       * @param {Backbone.Model} itemModel - The model of the ontology class to
+       * fetch children for.
+       */
+      fetchChildren(itemModel) {
+        if (itemModel.get("hasChildren") && !itemModel.get("childrenFetched")) {
+          const classId = itemModel.get("itemId");
+          this.get("bioontology").getChildren(classId);
+          itemModel.set("childrenFetched", true);
+        }
+      },
+
+      /**
+       * Selects a class in the accordion and sets the selectedClass attribute
+       * in this connector to the selected class.
+       * @param {Backbone.Model} itemModel - The model of the selected class.
+       */
+      setSelectedClass(itemModel) {
+        const ontologyId = itemModel.get("itemId");
+        const ontClass = this.get("bioontology")
+          .get("collection")
+          .get(ontologyId);
+        this.set("selectedClass", ontClass);
+      },
+
+      /**
+       * Syncs the accordion display model with the bioontology results model.
+       * This method is called when the bioontology results model changes.
+       */
+      syncAccordion() {
+        const root = this.get("accordionRoot");
+        const ontologyResults = this.get("bioontology").get("collection");
+        const data = ontologyResults.classesToAccordionItems(root);
+        this.get("accordion").get("items").set(data);
+      },
+
+      /**
+       * Switches the ontology in the bioontology model to the selected ontology
+       * and fetches the new ontology classes.
+       * @param {BioontolgyClass} newOntology - The selected ontology model,
+       * with ontology and subTree attributes.
+       */
+      switchOntology(newOntology) {
+        const bioontology = this.get("bioontology");
+        const newOntologyName = newOntology.get("ontology");
+        const newSubtree = newOntology.get("subTree");
+
+        bioontology.resetPageInfo();
+        bioontology.set("ontology", newOntologyName);
+        bioontology.set("subTree", newSubtree);
+        this.setAccordionRoot(newSubtree || this.get("defaultSubtree"));
+        bioontology.fetch({ replaceCollection: true });
+      },
+    },
+  ));
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_connectors_Filters-Map.js.html b/docs/docs/src_js_models_connectors_Filters-Map.js.html index f2daebd63..7f4f6972a 100644 --- a/docs/docs/src_js_models_connectors_Filters-Map.js.html +++ b/docs/docs/src_js_models_connectors_Filters-Map.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_Filters-Search.js.html b/docs/docs/src_js_models_connectors_Filters-Search.js.html index ace39269e..eae824425 100644 --- a/docs/docs/src_js_models_connectors_Filters-Search.js.html +++ b/docs/docs/src_js_models_connectors_Filters-Search.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_GeoPoints-Cesium.js.html b/docs/docs/src_js_models_connectors_GeoPoints-Cesium.js.html index 251d771fb..bbbd9362e 100644 --- a/docs/docs/src_js_models_connectors_GeoPoints-Cesium.js.html +++ b/docs/docs/src_js_models_connectors_GeoPoints-Cesium.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_GeoPoints-CesiumPoints.js.html b/docs/docs/src_js_models_connectors_GeoPoints-CesiumPoints.js.html index 40f1c5143..bb6bb0865 100644 --- a/docs/docs/src_js_models_connectors_GeoPoints-CesiumPoints.js.html +++ b/docs/docs/src_js_models_connectors_GeoPoints-CesiumPoints.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_GeoPoints-CesiumPolygon.js.html b/docs/docs/src_js_models_connectors_GeoPoints-CesiumPolygon.js.html index 035f11c6d..3a2d3802f 100644 --- a/docs/docs/src_js_models_connectors_GeoPoints-CesiumPolygon.js.html +++ b/docs/docs/src_js_models_connectors_GeoPoints-CesiumPolygon.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_Map-Search-Filters.js.html b/docs/docs/src_js_models_connectors_Map-Search-Filters.js.html index 7ada43ce1..19e9e78fb 100644 --- a/docs/docs/src_js_models_connectors_Map-Search-Filters.js.html +++ b/docs/docs/src_js_models_connectors_Map-Search-Filters.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_connectors_Map-Search.js.html b/docs/docs/src_js_models_connectors_Map-Search.js.html index 0476c1cee..2e0f1bc12 100644 --- a/docs/docs/src_js_models_connectors_Map-Search.js.html +++ b/docs/docs/src_js_models_connectors_Map-Search.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_BooleanFilter.js.html b/docs/docs/src_js_models_filters_BooleanFilter.js.html index 066423ead..5c89f8d26 100644 --- a/docs/docs/src_js_models_filters_BooleanFilter.js.html +++ b/docs/docs/src_js_models_filters_BooleanFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_ChoiceFilter.js.html b/docs/docs/src_js_models_filters_ChoiceFilter.js.html index 506c53bba..fd82568d7 100644 --- a/docs/docs/src_js_models_filters_ChoiceFilter.js.html +++ b/docs/docs/src_js_models_filters_ChoiceFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_DateFilter.js.html b/docs/docs/src_js_models_filters_DateFilter.js.html index 05f06ceba..8cdc9f8b5 100644 --- a/docs/docs/src_js_models_filters_DateFilter.js.html +++ b/docs/docs/src_js_models_filters_DateFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_Filter.js.html b/docs/docs/src_js_models_filters_Filter.js.html index 69a1df78e..e9865ad45 100644 --- a/docs/docs/src_js_models_filters_Filter.js.html +++ b/docs/docs/src_js_models_filters_Filter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_FilterGroup.js.html b/docs/docs/src_js_models_filters_FilterGroup.js.html index 5494b7afb..a0256012e 100644 --- a/docs/docs/src_js_models_filters_FilterGroup.js.html +++ b/docs/docs/src_js_models_filters_FilterGroup.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_NumericFilter.js.html b/docs/docs/src_js_models_filters_NumericFilter.js.html index 65212be23..3c51670a6 100644 --- a/docs/docs/src_js_models_filters_NumericFilter.js.html +++ b/docs/docs/src_js_models_filters_NumericFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_SpatialFilter.js.html b/docs/docs/src_js_models_filters_SpatialFilter.js.html index 85446165f..58f2fac74 100644 --- a/docs/docs/src_js_models_filters_SpatialFilter.js.html +++ b/docs/docs/src_js_models_filters_SpatialFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_filters_ToggleFilter.js.html b/docs/docs/src_js_models_filters_ToggleFilter.js.html index e6849e532..ae8c0c984 100644 --- a/docs/docs/src_js_models_filters_ToggleFilter.js.html +++ b/docs/docs/src_js_models_filters_ToggleFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_formats_ObjectFormat.js.html b/docs/docs/src_js_models_formats_ObjectFormat.js.html index 5567dd701..53e744dcc 100644 --- a/docs/docs/src_js_models_formats_ObjectFormat.js.html +++ b/docs/docs/src_js_models_formats_ObjectFormat.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_geocoder_GeocodedLocation.js.html b/docs/docs/src_js_models_geocoder_GeocodedLocation.js.html index c3269f05c..f2ccc44f1 100644 --- a/docs/docs/src_js_models_geocoder_GeocodedLocation.js.html +++ b/docs/docs/src_js_models_geocoder_GeocodedLocation.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_geocoder_GeocoderSearch.js.html b/docs/docs/src_js_models_geocoder_GeocoderSearch.js.html index 791c366af..1cc41b7aa 100644 --- a/docs/docs/src_js_models_geocoder_GeocoderSearch.js.html +++ b/docs/docs/src_js_models_geocoder_GeocoderSearch.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_geocoder_GoogleMapsAutocompleter.js.html b/docs/docs/src_js_models_geocoder_GoogleMapsAutocompleter.js.html index 84ed24ff9..1f70d3ff0 100644 --- a/docs/docs/src_js_models_geocoder_GoogleMapsAutocompleter.js.html +++ b/docs/docs/src_js_models_geocoder_GoogleMapsAutocompleter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_geocoder_GoogleMapsGeocoder.js.html b/docs/docs/src_js_models_geocoder_GoogleMapsGeocoder.js.html index c856f98b0..3bb57d5f3 100644 --- a/docs/docs/src_js_models_geocoder_GoogleMapsGeocoder.js.html +++ b/docs/docs/src_js_models_geocoder_GoogleMapsGeocoder.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_geocoder_Prediction.js.html b/docs/docs/src_js_models_geocoder_Prediction.js.html index 31c5fbab7..067560a0b 100644 --- a/docs/docs/src_js_models_geocoder_Prediction.js.html +++ b/docs/docs/src_js_models_geocoder_Prediction.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_AssetCategory.js.html b/docs/docs/src_js_models_maps_AssetCategory.js.html index 612bcb4ba..1bd0198f6 100644 --- a/docs/docs/src_js_models_maps_AssetCategory.js.html +++ b/docs/docs/src_js_models_maps_AssetCategory.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_AssetColor.js.html b/docs/docs/src_js_models_maps_AssetColor.js.html index 8bcc570a5..98c71d570 100644 --- a/docs/docs/src_js_models_maps_AssetColor.js.html +++ b/docs/docs/src_js_models_maps_AssetColor.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_AssetColorPalette.js.html b/docs/docs/src_js_models_maps_AssetColorPalette.js.html index 1e85c9b62..3845c02d6 100644 --- a/docs/docs/src_js_models_maps_AssetColorPalette.js.html +++ b/docs/docs/src_js_models_maps_AssetColorPalette.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_ExpansionPanelsModel.js.html b/docs/docs/src_js_models_maps_ExpansionPanelsModel.js.html index 628e70c4c..314facaa0 100644 --- a/docs/docs/src_js_models_maps_ExpansionPanelsModel.js.html +++ b/docs/docs/src_js_models_maps_ExpansionPanelsModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_Feature.js.html b/docs/docs/src_js_models_maps_Feature.js.html index dea6e6504..b08c5d0da 100644 --- a/docs/docs/src_js_models_maps_Feature.js.html +++ b/docs/docs/src_js_models_maps_Feature.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_GeoBoundingBox.js.html b/docs/docs/src_js_models_maps_GeoBoundingBox.js.html index 091c8eb08..cb1acfeb7 100644 --- a/docs/docs/src_js_models_maps_GeoBoundingBox.js.html +++ b/docs/docs/src_js_models_maps_GeoBoundingBox.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_GeoPoint.js.html b/docs/docs/src_js_models_maps_GeoPoint.js.html index c6c84721b..51e16baa5 100644 --- a/docs/docs/src_js_models_maps_GeoPoint.js.html +++ b/docs/docs/src_js_models_maps_GeoPoint.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_GeoScale.js.html b/docs/docs/src_js_models_maps_GeoScale.js.html index 1f025e7ed..abb87b946 100644 --- a/docs/docs/src_js_models_maps_GeoScale.js.html +++ b/docs/docs/src_js_models_maps_GeoScale.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_GeoUtilities.js.html b/docs/docs/src_js_models_maps_GeoUtilities.js.html index 73a943b58..433ac0312 100644 --- a/docs/docs/src_js_models_maps_GeoUtilities.js.html +++ b/docs/docs/src_js_models_maps_GeoUtilities.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_Geohash.js.html b/docs/docs/src_js_models_maps_Geohash.js.html index 3b050114c..86a8311e3 100644 --- a/docs/docs/src_js_models_maps_Geohash.js.html +++ b/docs/docs/src_js_models_maps_Geohash.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_Map.js.html b/docs/docs/src_js_models_maps_Map.js.html index ccf596358..be75accf8 100644 --- a/docs/docs/src_js_models_maps_Map.js.html +++ b/docs/docs/src_js_models_maps_Map.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -441,7 +441,8 @@

Source: src/js/models/maps/Map.js

getLayerGroups() { if (this.has("layerCategories")) { return this.get("layerCategories").getMapAssets(); - } else if (this.has("layers")) { + } + if (this.has("layers")) { return [this.get("layers")]; } return []; diff --git a/docs/docs/src_js_models_maps_MapInteraction.js.html b/docs/docs/src_js_models_maps_MapInteraction.js.html index 90e484252..e2f0786d3 100644 --- a/docs/docs/src_js_models_maps_MapInteraction.js.html +++ b/docs/docs/src_js_models_maps_MapInteraction.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -74,7 +74,7 @@

Source: src/js/models/maps/MapInteraction.js

* @since 2.27.0 * @extends Backbone.Model */ - var MapInteraction = Backbone.Model.extend( + const MapInteraction = Backbone.Model.extend( /** @lends MapInteraction.prototype */ { /** * The type of model this is. @@ -209,7 +209,7 @@

Source: src/js/models/maps/MapInteraction.js

/** * Handles a mouse click on the map. If the user has clicked on a feature, - * the feature is set as the 'clickedFeatures' attribute. If the map is + * the feature is set as the 'clickedFeatures' attribute. If the map or layer is * configured to show details when a feature is clicked, the feature is * also set as the 'selectedFeatures' attribute. * @param {MapInteraction} m - The MapInteraction model. @@ -221,7 +221,12 @@

Source: src/js/models/maps/MapInteraction.js

// Clone the models in hovered features and set them as clicked features const hoveredFeatures = this.get("hoveredFeatures").models; this.setClickedFeatures(hoveredFeatures); - const clickAction = this.get("mapModel")?.get("clickFeatureAction"); + let clickAction = this.get("hoveredFeatures") + ?.models[0].get("mapAsset") + ?.get("clickFeatureAction"); + if (clickAction == null) { + clickAction = this.get("mapModel")?.get("clickFeatureAction"); + } if (clickAction === "showDetails") { this.selectFeatures(hoveredFeatures); } else if (clickAction === "zoom") { diff --git a/docs/docs/src_js_models_maps_VectorFilter.js.html b/docs/docs/src_js_models_maps_VectorFilter.js.html index 47da14c1e..a0e0027a7 100644 --- a/docs/docs/src_js_models_maps_VectorFilter.js.html +++ b/docs/docs/src_js_models_maps_VectorFilter.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_assets_Cesium3DTileset.js.html b/docs/docs/src_js_models_maps_assets_Cesium3DTileset.js.html index 6e233c64e..21a594c83 100644 --- a/docs/docs/src_js_models_maps_assets_Cesium3DTileset.js.html +++ b/docs/docs/src_js_models_maps_assets_Cesium3DTileset.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_assets_CesiumGeohash.js.html b/docs/docs/src_js_models_maps_assets_CesiumGeohash.js.html index 6a5f4431a..98591da1c 100644 --- a/docs/docs/src_js_models_maps_assets_CesiumGeohash.js.html +++ b/docs/docs/src_js_models_maps_assets_CesiumGeohash.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_assets_CesiumImagery.js.html b/docs/docs/src_js_models_maps_assets_CesiumImagery.js.html index 156b20fce..c8c269ac6 100644 --- a/docs/docs/src_js_models_maps_assets_CesiumImagery.js.html +++ b/docs/docs/src_js_models_maps_assets_CesiumImagery.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_assets_CesiumTerrain.js.html b/docs/docs/src_js_models_maps_assets_CesiumTerrain.js.html index 0fcd87e7b..8ef04b572 100644 --- a/docs/docs/src_js_models_maps_assets_CesiumTerrain.js.html +++ b/docs/docs/src_js_models_maps_assets_CesiumTerrain.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_assets_CesiumVectorData.js.html b/docs/docs/src_js_models_maps_assets_CesiumVectorData.js.html index bf6df2c40..e1a07d551 100644 --- a/docs/docs/src_js_models_maps_assets_CesiumVectorData.js.html +++ b/docs/docs/src_js_models_maps_assets_CesiumVectorData.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_assets_MapAsset.js.html b/docs/docs/src_js_models_maps_assets_MapAsset.js.html index e25068646..afea4e19a 100644 --- a/docs/docs/src_js_models_maps_assets_MapAsset.js.html +++ b/docs/docs/src_js_models_maps_assets_MapAsset.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -152,6 +152,11 @@

Source: src/js/models/maps/assets/MapAsset.js

* especially when there was an error. * @property {boolean} [hideInLayerList = false] Set to true to hide this asset * from the layer list. + * @property {boolean} [showOpacitySlider = true] Set to true to show opacity slider + * for the layer. + * @property {"showDetails"|"zoom"} [clickFeatureAction = null] The action to take when a user clicks on a feature on the layer. The + * available options are "showDetails" (show the feature details in the + * sidebar) or "zoom" (zoom to the feature's location). */ defaults() { return { @@ -176,6 +181,8 @@

Source: src/js/models/maps/assets/MapAsset.js

status: null, statusDetails: null, hideInLayerList: false, + showOpacitySlider: true, + clickFeatureAction: null, }; }, diff --git a/docs/docs/src_js_models_maps_viewfinder_ViewfinderModel.js.html b/docs/docs/src_js_models_maps_viewfinder_ViewfinderModel.js.html index 1e0ad486e..921362ac6 100644 --- a/docs/docs/src_js_models_maps_viewfinder_ViewfinderModel.js.html +++ b/docs/docs/src_js_models_maps_viewfinder_ViewfinderModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_maps_viewfinder_ZoomPresetModel.js.html b/docs/docs/src_js_models_maps_viewfinder_ZoomPresetModel.js.html index aa08309c8..68200bcc4 100644 --- a/docs/docs/src_js_models_maps_viewfinder_ZoomPresetModel.js.html +++ b/docs/docs/src_js_models_maps_viewfinder_ZoomPresetModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_ScienceMetadata.js.html b/docs/docs/src_js_models_metadata_ScienceMetadata.js.html index 61591a10f..689a058a5 100644 --- a/docs/docs/src_js_models_metadata_ScienceMetadata.js.html +++ b/docs/docs/src_js_models_metadata_ScienceMetadata.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EML211.js.html b/docs/docs/src_js_models_metadata_eml211_EML211.js.html index 3ba6c771d..23fd62138 100644 --- a/docs/docs/src_js_models_metadata_eml211_EML211.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EML211.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLAnnotation.js.html b/docs/docs/src_js_models_metadata_eml211_EMLAnnotation.js.html index e8f384ce6..a1a69b5f4 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLAnnotation.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLAnnotation.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLAttribute.js.html b/docs/docs/src_js_models_metadata_eml211_EMLAttribute.js.html index aecb785dd..32b0ccf5e 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLAttribute.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLAttribute.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLDataTable.js.html b/docs/docs/src_js_models_metadata_eml211_EMLDataTable.js.html index 954912a1b..2aa812f1d 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLDataTable.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLDataTable.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLDistribution.js.html b/docs/docs/src_js_models_metadata_eml211_EMLDistribution.js.html index 0ec3d8bfe..f6ec05bfc 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLDistribution.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLDistribution.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLEntity.js.html b/docs/docs/src_js_models_metadata_eml211_EMLEntity.js.html index d52bf032e..54f2d758b 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLEntity.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLEntity.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLGeoCoverage.js.html b/docs/docs/src_js_models_metadata_eml211_EMLGeoCoverage.js.html index a2d729ef3..c3d70ac33 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLGeoCoverage.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLGeoCoverage.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLMeasurementScale.js.html b/docs/docs/src_js_models_metadata_eml211_EMLMeasurementScale.js.html index 5198da563..a888daaaa 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLMeasurementScale.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLMeasurementScale.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLMethods.js.html b/docs/docs/src_js_models_metadata_eml211_EMLMethods.js.html index bfecba302..8c56d74f4 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLMethods.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLMethods.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLMissingValueCode.js.html b/docs/docs/src_js_models_metadata_eml211_EMLMissingValueCode.js.html index 5b5a0a2f9..1dcde4011 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLMissingValueCode.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLMissingValueCode.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLNonNumericDomain.js.html b/docs/docs/src_js_models_metadata_eml211_EMLNonNumericDomain.js.html index d93aa313b..9e66b6ace 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLNonNumericDomain.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLNonNumericDomain.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLNumericDomain.js.html b/docs/docs/src_js_models_metadata_eml211_EMLNumericDomain.js.html index 02ca1da44..98403dcc0 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLNumericDomain.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLNumericDomain.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLOtherEntity.js.html b/docs/docs/src_js_models_metadata_eml211_EMLOtherEntity.js.html index dc10a718b..fd2512d4a 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLOtherEntity.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLOtherEntity.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLParty.js.html b/docs/docs/src_js_models_metadata_eml211_EMLParty.js.html index 129c91b4f..2548f4c82 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLParty.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLParty.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLTaxonCoverage.js.html b/docs/docs/src_js_models_metadata_eml211_EMLTaxonCoverage.js.html index 9309509fb..faca2c829 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLTaxonCoverage.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLTaxonCoverage.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLTemporalCoverage.js.html b/docs/docs/src_js_models_metadata_eml211_EMLTemporalCoverage.js.html index 5c3394765..b82091e9f 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLTemporalCoverage.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLTemporalCoverage.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLText.js.html b/docs/docs/src_js_models_metadata_eml211_EMLText.js.html index fa46c5aec..5430cb919 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLText.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLText.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml211_EMLUnit.js.html b/docs/docs/src_js_models_metadata_eml211_EMLUnit.js.html index 56a5deced..b8063bf1c 100644 --- a/docs/docs/src_js_models_metadata_eml211_EMLUnit.js.html +++ b/docs/docs/src_js_models_metadata_eml211_EMLUnit.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml220_EMLText.js.html b/docs/docs/src_js_models_metadata_eml220_EMLText.js.html index d635f61ee..6e772c763 100644 --- a/docs/docs/src_js_models_metadata_eml220_EMLText.js.html +++ b/docs/docs/src_js_models_metadata_eml220_EMLText.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml_EMLMethodStep.js.html b/docs/docs/src_js_models_metadata_eml_EMLMethodStep.js.html index 81d4e86c7..90d8d61f1 100644 --- a/docs/docs/src_js_models_metadata_eml_EMLMethodStep.js.html +++ b/docs/docs/src_js_models_metadata_eml_EMLMethodStep.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_metadata_eml_EMLSpecializedText.js.html b/docs/docs/src_js_models_metadata_eml_EMLSpecializedText.js.html index 8aadec192..7f71ef926 100644 --- a/docs/docs/src_js_models_metadata_eml_EMLSpecializedText.js.html +++ b/docs/docs/src_js_models_metadata_eml_EMLSpecializedText.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_ontologies_Bioontology.js.html b/docs/docs/src_js_models_ontologies_Bioontology.js.html new file mode 100644 index 000000000..445a29a04 --- /dev/null +++ b/docs/docs/src_js_models_ontologies_Bioontology.js.html @@ -0,0 +1,283 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/ontologies/Bioontology.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/ontologies/Bioontology.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "collections/ontologies/BioontologyResults"], (
+  Backbone,
+  BioontologyResults,
+) => {
+  /**
+   * @class Bioontology
+   * @classdesc A model that fetches data from the BioPortal API for a given
+   * ontology.
+   * @classcategory Models/Ontologies
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const Bioontology = Backbone.Model.extend({
+    /** @lends Bioontology.prototype */
+
+    /**
+     * The default attributes for this model. All attributes not documented here
+     * are detailed on the BioPortal API docs:
+     * https://data.bioontology.org/documentation.
+     * @returns {object} The default attributes for this model
+     * @property {"children"|"search"|"ontology"} queryType - The type of query
+     * to perform. Only "children", "search", and "ontology" are supported.
+     * @property {string} searchTerm - The term to search for. Only used when
+     * queryType is "search".
+     * @property {BioontologyResults} collection - The collection classes
+     * returned from the query.
+     * @property {string} subTree - The class ID to get the children of. Only
+     * used when queryType is "children". e.g.
+     * http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#MeasurementType
+     * @property {string} ontology - The ontology acronym to query. e.g. "ECSO"
+     */
+    defaults() {
+      return {
+        page: 1,
+        pageCount: null,
+        prevPage: null,
+        nextPage: null,
+        links: {},
+        collection: new BioontologyResults(),
+        apiKey: null,
+        apiBaseURL: MetacatUI.appModel.get("bioportalApiBaseUrl"),
+        subTree: "",
+        ontology: "ECSO",
+        pageSize: 500,
+        displayContext: false,
+        displayLinks: false,
+        include: ["prefLabel", "definition", "subClassOf", "hasChildren"],
+        queryType: "children",
+        searchTerm: "",
+      };
+    },
+
+    /**
+     * Initialize the Bioontology mode
+     * @param {object} attributes - The model attributes
+     * @param {string} attributes.apiKey - An alternative API key to use. If not
+     * set, the appModel's API key will be used.
+     * @param {object} _options - The options object
+     */
+    initialize(attributes, _options) {
+      // Fall back to the appModel's API key if one is not provided
+      if (!attributes?.apiKey && !this.get("apiKey")) {
+        this.set("apiKey", MetacatUI.appModel.get("bioportalAPIKey"));
+      }
+    },
+
+    /** @inheritdoc */
+    url() {
+      const queryType = this.get("queryType");
+
+      const subTree = this.encodeIfPresent(this.get("subTree"));
+      const ontology = this.encodeIfPresent(this.get("ontology"));
+      const searchTerm = this.encodeIfPresent(this.get("searchTerm"));
+
+      let queryUrl = "";
+      if (queryType === "children") {
+        queryUrl = this.buildChildrenUrl(ontology, subTree);
+      } else if (queryType === "search" && searchTerm) {
+        queryUrl = this.buildSearchUrl(searchTerm, ontology, subTree);
+      } else if (queryType === "ontology") {
+        queryUrl = `/ontologies/${ontology}?`;
+      }
+
+      const paramStr = new URLSearchParams({
+        apikey: this.get("apiKey"),
+        pagesize: this.get("pageSize"),
+        display_context: this.get("displayContext") === true,
+        display_links: this.get("displayLinks") === true,
+        include: this.getIncludeParam(queryType),
+      }).toString();
+      const root = this.get("apiBaseURL");
+      return `${root}${queryUrl}${paramStr}`;
+    },
+
+    /**
+     * Encode a value if it is exists
+     * @param {string} value - The value to encode
+     * @returns {string} The encoded value or null if the value is falsy
+     */
+    encodeIfPresent(value) {
+      return value ? encodeURIComponent(value) : null;
+    },
+
+    /**
+     * Construct the include url parameter for the BioPortal API
+     * @param {string} queryType - The type of query to perform
+     * @returns {string} The include parameter for the BioPortal API
+     */
+    getIncludeParam(queryType) {
+      let include = this.get("include");
+      if (queryType === "search") {
+        // subClassOf and hasChildren does not work with search queries
+        include = include.filter(
+          (item) => item !== "subClassOf" && item !== "hasChildren",
+        );
+      }
+      return include?.length ? include.join(",") : null;
+    },
+
+    /**
+     * Build the URL component for a "children" query
+     * @param {string} ontology - The ontology to query, encoded
+     * @param {string} subTree - The subTree to query, encoded
+     * @returns {string} The URL component for the query
+     */
+    buildChildrenUrl(ontology, subTree) {
+      if (ontology) {
+        return subTree
+          ? `/ontologies/${ontology}/classes/${subTree}/children?`
+          : `/ontologies/${ontology}/classes/roots?`;
+      }
+      return "";
+    },
+
+    /**
+     * Build the URL component for a "search" query
+     * @param {string} searchTerm - The search term, encoded
+     * @param {string} ontology - The ontology to query, encoded
+     * @param {string} subTree - The subTree to query, encoded
+     * @returns {string} The URL component
+     */
+    buildSearchUrl(searchTerm, ontology, subTree) {
+      let searchUrl = `/search?q=${searchTerm}*`;
+      if (ontology) {
+        searchUrl += `&ontologies=${ontology}&ontology=${ontology}`;
+      }
+      if (subTree) {
+        searchUrl += `&subtree_root_id=${subTree}`;
+      }
+      return `${searchUrl}&`;
+    },
+
+    /**
+     * Parse the response from the BioPortal API
+     * @param {object} response - The response from the BioPortal API
+     * @param {object} options - The options object
+     * @param {boolean} options.replaceCollection - Whether to replace the
+     * collection or add to it. Adds to it by default.
+     * @returns {object} The parsed response
+     */
+    parse(response, options) {
+      let parsedResponse = response;
+
+      // when querying for the "roots" (no subTree) of an ontology, the
+      // collection is the response itself
+      if (!parsedResponse.collection) {
+        parsedResponse = {
+          collection: response,
+        };
+
+        // In this case, there is also no returned pagination info.
+        // Ensure any previous pagination info is reset to defaults.
+        this.resetPageInfo();
+      }
+
+      const collection = this.get("collection") || new BioontologyResults();
+
+      if (options.replaceCollection === true) {
+        collection.reset(parsedResponse.collection, { parse: true });
+      } else {
+        collection.add(parsedResponse.collection, { parse: true });
+      }
+      parsedResponse.collection = collection;
+      return parsedResponse;
+    },
+
+    /**
+     * Fetch the next page of results from the BioPortal API and add them to the
+     * collection
+     */
+    getNextPage() {
+      const nextPage = this.get("nextPage");
+      if (nextPage) {
+        this.set("page", nextPage);
+        this.fetch();
+      }
+    },
+
+    /**
+     * Get the children of a given class ID and add them to the collection
+     * @param {string} classId - The class ID to get the children of
+     */
+    getChildren(classId) {
+      this.set("subTree", classId);
+      this.set("queryType", "children");
+      this.fetch();
+    },
+
+    /**
+     * Clears the pagination info that has been fetched from the BioPortal API
+     */
+    resetPageInfo() {
+      const defaults = this.defaults();
+      const pageAttrs = ["page", "pageCount", "prevPage", "nextPage"];
+      pageAttrs.forEach((attr) => this.set(attr, defaults[attr]));
+    },
+  });
+
+  return Bioontology;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_ontologies_BioontologyBatch.js.html b/docs/docs/src_js_models_ontologies_BioontologyBatch.js.html new file mode 100644 index 000000000..1469c238a --- /dev/null +++ b/docs/docs/src_js_models_ontologies_BioontologyBatch.js.html @@ -0,0 +1,383 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/ontologies/BioontologyBatch.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/ontologies/BioontologyBatch.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "collections/ontologies/BioontologyResults"], (
+  Backbone,
+  BioontologyResults,
+) => {
+  /**
+   * @class BioontologyBatch
+   * @classdesc A model that fetches data from the BioPortal API using the batch
+   * endpoint. This can be used to store data about classes that have been
+   * fetched from BioPortal, and to fetch additional classes as needed.
+   * @classcategory Models/Ontologies
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const BioontologyBatch = Backbone.Model.extend({
+    /** @lends BioontologyBatch.prototype */
+
+    /**
+     * The default attributes for this model. All attributes not documented here
+     * are detailed on the BioPortal API docs:
+     * https://data.bioontology.org/documentation.
+     * @returns {object} The default attributes for this model
+     * @property {Backbone.Collection} collection - The collection of classes
+     * fetched from BioPortal
+     * @property {string} apiKey - The API key to use for requests to BioPortal.
+     * If not set, the appModel's API key will be used.
+     * @property {string} apiBaseURL - The base URL for the BioPortal API.
+     * @property {string} ontologyPrefix - A string to prepend to ontology
+     * acronyms to form the full ontology ID for batch requests. Note that this
+     * is not the same as the ontology URL, as the ID starts with http not
+     * https.
+     * @property {string[]} ontologies - The ontologies to search for classes
+     * in, in order of priority. Only the acronyms are needed.
+     * @property {string[]} include - The fields to include in the response.
+     * @property {string[]} classesToFetch - The classes (classIds) to fetch
+     * from BioPortal.
+     */
+    defaults() {
+      return {
+        collection: new BioontologyResults(),
+        apiKey: null,
+        apiBaseURL: MetacatUI.appModel.get("bioportalApiBaseUrl"),
+        ontologyPrefix: "http://data.bioontology.org/ontologies/",
+        ontologies: MetacatUI.appModel.get("bioportalOntologies"),
+        include: ["prefLabel", "definition", "subClassOf", "hasChildren"],
+        classesToFetch: [],
+      };
+    },
+
+    /**
+     * Initialize the Bioontology mode
+     * @param {object} attributes - The model attributes
+     * @param {string} attributes.apiKey - An alternative API key to use. If not
+     * set, the appModel's API key will be used.
+     * @param {object} _options - The options object
+     */
+    initialize(attributes, _options) {
+      // Fall back to the appModel's API key if one is not provided
+      if (!attributes?.apiKey && !this.get("apiKey")) {
+        this.set("apiKey", MetacatUI.appModel.get("bioportalAPIKey"));
+      }
+    },
+
+    /** @inheritdoc */
+    url() {
+      return `${this.get("apiBaseURL")}/batch`;
+    },
+
+    /**
+     * Add classes from a response to the collection. This method is async and
+     * will return a promise that resolves when the collection has been updated.
+     * @param {object} response - The response from the BioPortal API
+     * @param {string|object} [ontology] - Provide to include the ontology acronym
+     * to store as an attribute on the class models
+     * @returns {Promise<void>} A promise that resolves when the collection has
+     * been updated
+     */
+    async addClassesFromResponse(response, ontology) {
+      const collection = this.get("collection");
+      let parsedResponse = Object.values(response).flat();
+      const updated = new Promise((resolve) => {
+        this.listenToOnce(this.get("collection"), "update", resolve);
+      });
+      if (ontology) {
+        parsedResponse = parsedResponse.map((cls) => ({
+          ...cls,
+          ontology,
+        }));
+      }
+      collection.add(parsedResponse, { parse: true });
+      return updated;
+    },
+
+    /**
+     * Create a payload for a batch request to the BioPortal API.
+     * @param {string[]} classes - The classes to fetch
+     * @param {string|object} ontology - The ontology acronym or object with
+     * acronym stored in the "ontology" property
+     * @returns {string} The JSON stringified payload
+     */
+    createBatchPayload(classes, ontology) {
+      const acronym =
+        typeof ontology === "object" ? ontology.ontology : ontology;
+      const ontologyId = `${this.get("ontologyPrefix")}${acronym}`;
+      const payload = {
+        "http://www.w3.org/2002/07/owl#Class": {
+          collection: classes.map((cls) => ({
+            class: cls,
+            ontology: ontologyId,
+          })),
+          display: this.get("include")?.join(",") || "prefLabel,definition",
+        },
+      };
+      return JSON.stringify(payload);
+    },
+
+    /**
+     * Create the headers for a request to the BioPortal API.
+     * @returns {object} The headers object
+     * @property {string} Content-Type - The content type of the request
+     * @property {string} Authorization - The authorization header with the API
+     * key
+     */
+    createHeaders() {
+      return {
+        "Content-Type": "application/json",
+        Authorization: `apikey token=${this.get("apiKey")}`,
+      };
+    },
+
+    /**
+     * If some of the classes to fetch are already in the collection, remove
+     * them from the list of classes to fetch.
+     */
+    filterClassesToFetch() {
+      const classesToFetch = this.get("classesToFetch");
+      const collection = this.get("collection");
+      const existingClasses = collection.pluck("@id");
+      this.set(
+        "classesToFetch",
+        classesToFetch.filter((cls) => !existingClasses.includes(cls)),
+      );
+    },
+
+    /**
+     * Make a batch request for a given set of classes and a single ontology.
+     * @param {string[]} classes - The classes to fetch
+     * @param {string} ontology - The ontology to search in
+     * @returns {Promise<object>} A promise that resolves to the response from
+     * the BioPortal API
+     */
+    async fetchClassesFromOntology(classes, ontology) {
+      try {
+        const payload = this.createBatchPayload(classes, ontology);
+        const response = await fetch(this.url(), {
+          method: "POST",
+          headers: this.createHeaders(),
+          body: payload,
+        });
+        if (!response.ok) {
+          throw new Error(`HTTP error! status: ${response.status}`);
+        }
+        return await response.json();
+      } catch (error) {
+        this.recordError(error);
+        return null;
+      }
+    },
+
+    /**
+     * Record an error that occurred during the fetch process.
+     * @param {Error} error - The error that occurred
+     */
+    recordError(error) {
+      const currentErrors = this.get("errors") || [];
+      this.set("errors", [...currentErrors, error]);
+    },
+
+    /**
+     * Move the classes that were not found to the list of classes not found. This
+     * should be called after all classes have been fetched.
+     */
+    moveClassesToNotFound() {
+      const classesNotFound = this.get("classesNotFound") || [];
+      const leftOverClasses = this.get("classesToFetch") || [];
+      this.set("classesNotFound", [...classesNotFound, ...leftOverClasses]);
+      this.set("classesToFetch", []);
+    },
+
+    /**
+     * Wait for the fetch process to complete. This will return a promise that
+     * resolves when the fetch process is complete.
+     * @returns {Promise<boolean>} A promise that resolves to true if the fetch
+     * process is complete, and false if it is not complete
+     */
+    async waitForFetchComplete() {
+      if (this.get("status") === "fetching") {
+        await new Promise((resolve) => {
+          this.listenToOnce(this, "fetchComplete", resolve);
+        });
+        return true;
+      }
+      return false;
+    },
+
+    /**
+     * Initialize the fetch process. This will set the status to "fetching" and
+     * set the list of classes to fetch to the provided classes.
+     * @param {string[]} classes - The classes to fetch
+     */
+    initializeFetch(classes) {
+      this.set("status", "fetching");
+      const leftOverClasses = this.get("classesToFetch");
+      this.set("classesNotFound", leftOverClasses);
+      this.set("classesToFetch", classes);
+      this.filterClassesToFetch();
+    },
+
+    /**
+     * Fetch classes from the BioPortal API. This method is async and will
+     * return a promise that resolves when the classes have been fetched.
+     * @returns {Promise<object[]>} A promise that resolves to an array of
+     * objects containing the classes fetched from BioPortal
+     */
+    async fetchFromOntologies() {
+      const ontologies = this.get("ontologies");
+      const responses = [];
+
+      ontologies.forEach(async (ontology) => {
+        const classesToFetch = this.get("classesToFetch");
+        if (!classesToFetch.length) {
+          return;
+        }
+
+        const response = await this.fetchClassesFromOntology(
+          classesToFetch,
+          ontology,
+        ).catch((error) => {
+          this.recordError(error);
+          return null;
+        });
+        if (response) {
+          responses.push(response);
+          await this.addClassesFromResponse(
+            response,
+            ontology.label || ontology,
+          );
+          // Update the list of classes to fetch based on what was found
+          this.filterClassesToFetch();
+        }
+      });
+
+      return responses;
+    },
+
+    /**
+     * Finalize the fetch process. This will set the status to "fetched" and
+     * trigger the "fetchComplete" event.
+     */
+    finalizeFetch() {
+      this.moveClassesToNotFound();
+      this.set("status", "fetched");
+      this.trigger("fetchComplete");
+    },
+
+    /**
+     * Fetch classes from the BioPortal API. This method is async and will
+     * return a promise that resolves when the classes have been fetched.
+     * @param {string[]} classes - The classes to fetch
+     * @returns {Promise<Backbone.Model[]>} A promise that resolves to an array
+     * of Backbone models
+     */
+    async fetchClasses(classes) {
+      try {
+        if (await this.waitForFetchComplete()) {
+          return this.fetchClasses(classes);
+        }
+        this.initializeFetch(classes);
+        const responses = await this.fetchFromOntologies();
+        return responses.flatMap((response) =>
+          response ? response.classes : [],
+        );
+      } catch (error) {
+        this.recordError(error);
+        return [];
+      } finally {
+        this.finalizeFetch();
+      }
+    },
+
+    /**
+     * Gets the models for given classes. For classes that exist already, the
+     * model will be fetched from the collection. For classes that do not exist
+     * yet, the bioportal API will be queried. The promise will resolve when all
+     * models have been fetched.
+     * @param {string[]} classes - The classes to fetch
+     * @returns {Promise<Backbone.Model[]>} A promise that resolves to an array
+     * of Backbone models
+     */
+    async getClasses(classes) {
+      const existingClasses = this.getCachedClasses(classes);
+      const newClasses = await this.fetchClasses(classes);
+      return [...existingClasses, ...newClasses];
+    },
+
+    /**
+     * Get the models for classes that have already been fetched from BioPortal.
+     * @param {string[]} classes - The class IDs to get models for
+     * @returns {Backbone.Model[]} The models for the classes that have already
+     * been fetched
+     */
+    getCachedClasses(classes) {
+      const collection = this.get("collection");
+      collection.restoreFromCache(classes);
+      const models = collection.filter((model) => classes.includes(model.id));
+      return models;
+    },
+  });
+
+  return BioontologyBatch;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_ontologies_BioontologyClass.js.html b/docs/docs/src_js_models_ontologies_BioontologyClass.js.html new file mode 100644 index 000000000..408b68344 --- /dev/null +++ b/docs/docs/src_js_models_ontologies_BioontologyClass.js.html @@ -0,0 +1,224 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/ontologies/BioontologyClass.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/ontologies/BioontologyClass.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone"], (Backbone) => {
+  /**
+   * @class BioontologyClass
+   * @classdesc This model is designed to handle ontology class data from the
+   * BioPortal API. All attributes not documented here are detailed on the
+   * BioPortal API docs: https://data.bioontology.org/documentation.
+   * @classcategory Models/Ontologies
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const BioontologyClass = Backbone.Model.extend({
+    /** @lends BioontologyClass.prototype */
+
+    type: "BioontologyClass",
+
+    /**
+     * The default attributes for the OntologyClassModel. See also:
+     * https://data.bioontology.org/documentation.
+     * @returns {object} The default attributes for this model
+     * @property {string} id - The unique identifier for the ontology class.
+     * @property {string} prefLabel - The preferred label for the ontology class.
+     * @property {string[]} definition - Definitions of the ontology class.
+     * @property {string[]} synonym - Synonyms of the ontology class.
+     * @property {boolean} obsolete - Indicates if the class is obsolete.
+     * @property {string[]} subClassOf - An array of identifiers for parent classes in the ontology.
+     * @property {object[]} parents - Detailed parent class information including identifiers and links.
+     * @property {string[]} cui - Concept Unique Identifiers associated with the class.
+     * @property {stringp[]} semanticType - Semantic types associated with the class.
+     * @property {string} label - Label of the class (may be empty).
+     * @property {string} prefixIRI - Prefix IRI if available.
+     * @property {string} notation - Notation number associated with the class.
+     * @property {string} xref - External reference identifiers.
+     * @property {string} created - Creation date of the class entry.
+     * @property {string} modified - Last modification date of the class entry.
+     * @property {object} properties - Additional properties specific to the ontology class.
+     * @property {string} '@id' - The unique identifier for the ontology class.
+     * @property {string} '@type' - The type of the entity in RDF/OWL.
+     * @property {object} links - A collection of links related to the ontology class for API interaction.
+     * @property {object} '@context' - Context for understanding the property values and relations.
+     * @property {Array} ancestors - An array of ancestor classes of the ontology class.
+     * @property {Array} children - An array of child classes of the ontology class.
+     * @property {Array} notes - Additional notes associated with the ontology class.
+     * @property {number} childrenCount - The number of children of the ontology class.
+     * @property {boolean} hasChildren - Boolean indicating whether the ontology class has children.
+     */
+    defaults() {
+      return {
+        id: "",
+        prefLabel: "",
+        definition: [],
+        synonym: [],
+        obsolete: false,
+        subClassOf: [],
+        parents: [],
+        cui: [],
+        semanticType: [],
+        label: [],
+        prefixIRI: null,
+        notation: "",
+        xref: null,
+        created: null,
+        modified: null,
+        properties: {},
+        "@id": "",
+        "@type": "http://www.w3.org/2002/07/owl#Class",
+        links: {
+          self: "",
+          ontology: "",
+          children: "",
+          parents: "",
+          descendants: "",
+          ancestors: "",
+          instances: "",
+          tree: "",
+          notes: "",
+          mappings: "",
+          ui: "",
+        },
+        "@context": {
+          "@vocab": "http://data.bioontology.org/metadata/",
+          label: "http://www.w3.org/2000/01/rdf-schema#label",
+          prefLabel: "http://www.w3.org/2004/02/skos/core#prefLabel",
+          synonym: "http://www.w3.org/2004/02/skos/core#altLabel",
+          definition: "http://www.w3.org/2004/02/skos/core#definition",
+          obsolete: "http://www.w3.org/2002/07/owl#deprecated",
+          notation: "http://www.w3.org/2004/02/skos/core#notation",
+          prefixIRI: "http://data.bioontology.org/metadata/prefixIRI",
+          parents: "http://www.w3.org/2000/01/rdf-schema#parents",
+          subClassOf: "http://www.w3.org/2000/01/rdf-schema#subClassOf",
+          semanticType:
+            "http://bioportal.bioontology.org/ontologies/umls/hasSTY",
+          cui: "http://bioportal.bioontology.org/ontologies/umls/cui",
+          xref: "http://www.geneontology.org/formats/oboInOwl#hasDbXref",
+          created: "http://purl.org/dc/terms/created",
+          modified: "http://purl.org/dc/terms/modified",
+          "@language": "en",
+        },
+        ancestors: [],
+        children: [],
+        notes: [],
+        childrenCount: 0,
+        hasChildren: false,
+      };
+    },
+
+    /** @inheritdoc */
+    url() {
+      // TODO: We could create a mechanism to fetch more info for a specific
+      // class here.
+    },
+
+    /** @inheritdoc */
+    parse(response, _options) {
+      const parsedResponse = response;
+      // Use the ontology ID as the model ID
+      parsedResponse.id = response["@id"];
+      return parsedResponse;
+    },
+
+    /**
+     * Reformat for a searchSelect option
+     * @returns {object} Attributes for a searchSelect option model
+     */
+    toSearchSelectOption() {
+      return {
+        label: this.get("prefLabel") || this.get("label") || this.get("@id"),
+        description: this.get("definition")?.[0] || "",
+        value: this.get("@id"),
+        category: this.get("ontology") || "",
+      };
+    },
+
+    /**
+     * Reformat for an accordion item
+     * @returns {object} Attributes for an accordion item model
+     */
+    toAccordionItem() {
+      const title = this.get("prefLabel");
+      const definitions = this.get("definition");
+      const description = definitions?.length ? definitions[0] : "";
+      const hasChildren = this.get("hasChildren");
+      const itemId = this.get("@id");
+      const parents = this.get("subClassOf");
+
+      const content = hasChildren ? "loading..." : "";
+      const parent = parents?.length ? parents[0] : "";
+
+      return {
+        title,
+        description,
+        hasChildren,
+        itemId,
+        parent,
+        content,
+        // ID needed to prevent re-adding existing items on sync
+        id: itemId,
+      };
+    },
+  });
+  return BioontologyClass;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_ontologies_BioontologyOntology.js.html b/docs/docs/src_js_models_ontologies_BioontologyOntology.js.html new file mode 100644 index 000000000..870348146 --- /dev/null +++ b/docs/docs/src_js_models_ontologies_BioontologyOntology.js.html @@ -0,0 +1,150 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/ontologies/BioontologyOntology.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/ontologies/BioontologyOntology.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone"], (Backbone) => {
+  /**
+   * @class BioOntology
+   * @classdesc This model represents an ontology from the BioPortal API, see
+   * https://data.bioontology.org/documentation#Ontology
+   * @classcategory Models/Ontologies
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const BioOntology = Backbone.Model.extend({
+    /** @lends BioOntology.prototype */
+
+    type: "BioontologyOntology",
+
+    /**
+     * The default attributes for the BioOntology model. For definitions,
+     * see https://data.bioontology.org/documentation
+     * @returns {object} The default attributes
+     */
+    defaults() {
+      return {
+        acronym: "",
+        name: "",
+        administeredBy: "",
+        flat: true,
+        summaryOnly: true,
+        ontologyType: "",
+        submissions: [],
+        projects: [],
+        notes: [],
+        reviews: [],
+        provisionalClasses: [],
+        subscriptions: [],
+        group: "",
+        viewingRestriction: "",
+        doNotUpdate: "",
+        hasDomain: "",
+        acl: [],
+        viewOf: "",
+        views: [],
+        include: ["name"],
+        include_views: false,
+        displayContext: false,
+        displayLinks: false,
+        apiKey: MetacatUI.appModel.get("bioportalAPIKey"),
+        apiBaseURL: MetacatUI.appModel.get("bioportalApiBaseUrl"),
+      };
+    },
+
+    /** @inheritdoc */
+    url() {
+      const ontologyId = this.get("acronym");
+      const apikey =
+        this.get("apiKey") || MetacatUI.appModel.get("bioportalAPIKey");
+      const baseUrl =
+        this.get("apiBaseURL") || MetacatUI.appModel.get("bioportalApiBaseUrl");
+      const include = this.get("include")?.join(",") || "name";
+      const paramStr = new URLSearchParams({
+        apikey,
+        include,
+        include_views: this.get("include_views"),
+        display_context: this.get("displayContext"),
+        display_links: this.get("displayLinks"),
+      }).toString();
+      return `${baseUrl}/ontologies/${ontologyId}?${paramStr}`;
+    },
+
+    /** @inheritdoc */
+    parse(response, _options) {
+      const parsedResponse = response;
+      parsedResponse.id = response?.acronym;
+      return parsedResponse;
+    },
+
+    /** @returns {object} Attributes for a searchSelect option model */
+    toSearchSelectOption() {
+      return {
+        label: this.get("name") || this.get("acronym"),
+        description: this.get("definition")?.[0] || "",
+        value: this.get("acronym"),
+        // TODO: Add extras like ontology acronym & # results in catalog. Use to
+        // populate a tooltip & description for the option item.
+      };
+    },
+  });
+  return BioOntology;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_portals_PortalImage.js.html b/docs/docs/src_js_models_portals_PortalImage.js.html index 925bb9f07..27323f2a9 100644 --- a/docs/docs/src_js_models_portals_PortalImage.js.html +++ b/docs/docs/src_js_models_portals_PortalImage.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_portals_PortalModel.js.html b/docs/docs/src_js_models_portals_PortalModel.js.html index 8ba73ff61..db55eb4dd 100644 --- a/docs/docs/src_js_models_portals_PortalModel.js.html +++ b/docs/docs/src_js_models_portals_PortalModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_portals_PortalSectionModel.js.html b/docs/docs/src_js_models_portals_PortalSectionModel.js.html index 0679dfa32..2d245fd29 100644 --- a/docs/docs/src_js_models_portals_PortalSectionModel.js.html +++ b/docs/docs/src_js_models_portals_PortalSectionModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_portals_PortalVizSectionModel.js.html b/docs/docs/src_js_models_portals_PortalVizSectionModel.js.html index a6787d89f..c5cc8fdf4 100644 --- a/docs/docs/src_js_models_portals_PortalVizSectionModel.js.html +++ b/docs/docs/src_js_models_portals_PortalVizSectionModel.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_projects_Project.js.html b/docs/docs/src_js_models_projects_Project.js.html index 18ffb7f79..0a24e2579 100644 --- a/docs/docs/src_js_models_projects_Project.js.html +++ b/docs/docs/src_js_models_projects_Project.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_queryFields_QueryField.js.html b/docs/docs/src_js_models_queryFields_QueryField.js.html index 521fb7203..69ff2bd8c 100644 --- a/docs/docs/src_js_models_queryFields_QueryField.js.html +++ b/docs/docs/src_js_models_queryFields_QueryField.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_models_searchSelect_AccountSearchSelect.js.html b/docs/docs/src_js_models_searchSelect_AccountSearchSelect.js.html new file mode 100644 index 000000000..084528023 --- /dev/null +++ b/docs/docs/src_js_models_searchSelect_AccountSearchSelect.js.html @@ -0,0 +1,225 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/searchSelect/AccountSearchSelect.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/searchSelect/AccountSearchSelect.js

+ + + + + + +
+
+
"use strict";
+
+define(["models/searchSelect/SearchSelect", "models/LookupModel"], (
+  SearchSelect,
+  LookupModel,
+) => {
+  /**
+   * @class AccountSearchSelect
+   * @classdesc An extension of SearchSelect that sets the options to the query
+   * fields (e.g. Solr fields) available for searching.
+   * @classcategory Models/SearchSelect
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const AccountSearchSelect = SearchSelect.extend({
+    /** @lends AccountSearchSelect.prototype */
+
+    /** @inheritdoc */
+    defaults() {
+      return {
+        ...SearchSelect.prototype.defaults(),
+        placeholderText: "Start typing a name",
+        inputLabel: "Search for a person or group",
+        allowMulti: true,
+        allowAdditions: false,
+        apiSettings: {
+          responseAsync: this.responseAsync.bind(this),
+        },
+      };
+    },
+
+    /** @inheritdoc */
+    initialize() {
+      if (!MetacatUI.appLookupModel)
+        MetacatUI.appLookupModel = new LookupModel();
+      SearchSelect.prototype.initialize.call(this);
+    },
+
+    /**
+     * Handles the async response for the Accounts lookup
+     * @param {object} settings - The settings object passed by Formantic-UI
+     * @param {Function} callback - The callback function passed by Formantic-UI
+     */
+    responseAsync(settings, callback) {
+      const model = this;
+
+      // The search term that the user has typed into the input
+      const searchTerm = settings.urlData.query;
+      // To return, fail unless we have results
+      const results = { success: false };
+
+      // Only use the account lookup service is the user has typed at least two
+      // characters. Otherwise, the callback function is never called.
+      if (searchTerm.length < 2) callback(results);
+
+      model
+        .getAccountDetails(searchTerm)
+        .then((response) => {
+          if (response && response.length) {
+            results.results = model.formatResults(response, false);
+            results.success = true;
+          }
+          callback(results);
+        })
+        .catch(() => {
+          callback(results);
+        });
+    },
+
+    /**
+     * Formats the results from the account lookup service for the dropdown
+     * @param {object[]} results - The results from the account lookup service
+     * @param {boolean} forTemplate - Whether to format the results for the
+     * template in the SearchSelect view or directly for Formantic-UI
+     * @returns {object[]} - The formatted results
+     */
+    formatResults(results, forTemplate = false) {
+      return results.map((result) => this.formatResult(result, forTemplate));
+    },
+
+    /**
+     * Formats a single result from the account lookup service
+     * @param {object} rawResult - The result from the account lookup service
+     * @param {boolean} forTemplate - See formatResults
+     * @returns {object} - The formatted result
+     */
+    formatResult(rawResult, forTemplate = false) {
+      // clone the result
+      const result = { ...rawResult };
+
+      let icon = "";
+      if (result.type === "person") {
+        icon = "user";
+      } else if (result.type === "group") {
+        icon = "group";
+      }
+
+      // Get the ID which is saved in the parentheses of the label
+      const idRegex = /\(([^)]+)\)$/;
+      const match = result.label.match(idRegex);
+      const id = match?.[1] || "";
+
+      // The label will be the name without the ID
+      const accountName = result.label.replace(idRegex, "").trim();
+
+      // Result for the template in the SearchSelect view
+      if (forTemplate) {
+        return {
+          ...result,
+          description: `Account ID: ${id}`,
+          label: accountName,
+          icon,
+        };
+      }
+      // Result for a Formantic-UI item
+      const formatIcon = icon
+        ? `<i class="icon icon-on-left icon-${icon}"></i>`
+        : "";
+      return {
+        name: `${formatIcon} ${accountName}`,
+        value: result.value,
+        description: id,
+        descriptionVertical: true,
+        text: `${formatIcon} ${accountName}`,
+      };
+    },
+
+    /**
+     * Promisify the getAccountsAutocomplete function from the LookupModel
+     * @param {string} searchTerm - The account ID, name, or partial name to search for
+     * @returns {Promise<object[]>} - A promise that resolves with the results
+     */
+    async getAccountDetails(searchTerm) {
+      return new Promise((resolve, reject) => {
+        MetacatUI.appLookupModel.getAccountsAutocomplete(
+          { term: searchTerm },
+          (results) => {
+            if (results) {
+              resolve(results);
+            } else {
+              reject(new Error("Failed to fetch account details"));
+            }
+          },
+        );
+      });
+    },
+
+    /**
+     * Use the account lookup service to match the pre-selected values to the
+     * account holder's name to use as a label.
+     */
+    async setOptionsForPreselected() {
+      const selected = this.get("selected");
+      if (!selected?.length) return;
+      const results = await Promise.all(
+        selected.map((accountId) => this.getAccountDetails(accountId)),
+      );
+      const formattedResults = this.formatResults(results.flat(), true);
+      this.updateOptions(formattedResults);
+    },
+  });
+
+  return AccountSearchSelect;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_searchSelect_QueryFieldSearchSelect.js.html b/docs/docs/src_js_models_searchSelect_QueryFieldSearchSelect.js.html new file mode 100644 index 000000000..9e3d42d0b --- /dev/null +++ b/docs/docs/src_js_models_searchSelect_QueryFieldSearchSelect.js.html @@ -0,0 +1,362 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/searchSelect/QueryFieldSearchSelect.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/searchSelect/QueryFieldSearchSelect.js

+ + + + + + +
+
+
"use strict";
+
+define([
+  "models/searchSelect/SearchSelect",
+  "collections/queryFields/QueryFields",
+], (SearchSelect, QueryFields) => {
+  /**
+   * @class QueryFieldSearchSelect
+   * @classdesc An extension of SearchSelect that sets the options to the query
+   * fields (e.g. Solr fields) available for searching.
+   * @classcategory Models/SearchSelect
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const QueryFieldSearchSelect = SearchSelect.extend({
+    /** @lends QueryFieldSearchSelect.prototype */
+
+    /**
+     * An additional field object contains the properties an additional query
+     * field to add that are required to render it correctly. An additional
+     * query field is one that does not actually exist in the query service
+     * index.
+     * @typedef {object} AdditionalField
+     * @property {string} name - A unique ID to represent this field. It must
+     * not match the name of any other query fields.
+     * @property {string[]} fields - The list of real query fields that this
+     * abstracted field will represent. It must exactly match the names of the
+     * query fields that actually exist.
+     * @property {string} label - A user-facing label to display.
+     * @property {string} description - A description for this field.
+     * @property {string} category - The name of the category under which to
+     * place this field. It must match one of the category names for an existing
+     * query field.
+     * @since 2.15.0
+     */
+
+    /**
+     * @returns {object} The default attributes for this model
+     * @property {AdditionalField[]} addFields - A list of additional fields
+     * which are not retrieved from the query service index, but which should be
+     * added to the list of options. This can be used to add abstracted fields
+     * which are a combination of multiple query fields, or to add a duplicate
+     * field that has a different label.
+     * @property {string[]} commonFields - A list of query fields names to
+     * display at the top of the menu, above all other category headers
+     * @property {string[]} categoriesToAlphabetize - The names of categories
+     * that should have items sorted alphabetically. Names must exactly match
+     * those in the {@link QueryField#categoriesMap Query Field model}
+     * @property {boolean} excludeNonSearchable - Whether or not to exclude
+     * fields which are not searchable. Set to false to keep query fields that
+     * are not searchable in the returned list
+     * @property {string} submenuStyle - The submenu style is set to "accordion"
+     * by default for this submodel
+     * @property {string[]} excludeFields - A list of query field names to
+     * exclude from the list of options.
+     */
+    defaults() {
+      return {
+        ...SearchSelect.prototype.defaults(),
+        placeholderText: "Search for or select a field",
+        inputLabel: "Select one or more metadata fields to query",
+        addFields: [],
+        commonFields: ["text", "documents-special-field"],
+        categoriesToAlphabetize: ["General"],
+        excludeNonSearchable: true,
+        submenuStyle: "accordion",
+        excludeFields: [],
+      };
+    },
+
+    /**
+     * Initializes the QueryFieldSearchSelect model
+     * @param {object} attributes - A literal object with model attributes
+     * @param {object} options - A literal object with options
+     * @param {boolean} options.collectionQuery - Set this to true to
+     * automatically set the excludeFields and addFields to the collection query
+     * defaults set in the appModel. See
+     * {@link AppModel#collectionQueryExcludeFields} and
+     * {@link AppModel#collectionQuerySpecialFields}.
+     */
+    initialize(attributes, options = {}) {
+      if (options.collectionQuery) {
+        this.set(
+          "excludeFields",
+          MetacatUI.appModel.get("collectionQueryExcludeFields"),
+        );
+        this.set(
+          "addFields",
+          MetacatUI.appModel.get("collectionQuerySpecialFields"),
+        );
+      }
+      this.getQueryFieldOptions();
+      SearchSelect.prototype.initialize.call(this, attributes, options);
+    },
+
+    /**
+     * Fetches the query fields from the query service, converts them to the
+     * format required by the SearchSelectView, and sets them as the options
+     * for this model
+     */
+    async getQueryFieldOptions() {
+      const queryFields = await this.fetchQueryFields();
+      const fields = queryFields.toJSON();
+      const excludedFields = this.excludeFields(fields);
+      const addedFields = this.addFields(excludedFields);
+      const options = addedFields.map(this.fieldToOption);
+      const sortedOptions = this.sortFields(options);
+      this.updateOptions(sortedOptions);
+    },
+
+    /**
+     * Fetches the query fields from the query service
+     * @returns {Promise} A promise that resolves with the query fields
+     * collection
+     */
+    async fetchQueryFields() {
+      return new Promise((resolve) => {
+        if (MetacatUI.queryFields?.length) {
+          resolve(MetacatUI.queryFields);
+          return;
+        }
+        if (!MetacatUI.queryFields) MetacatUI.queryFields = new QueryFields();
+        MetacatUI.queryFields.fetch({
+          success: () => resolve(MetacatUI.queryFields),
+          error: () => resolve([]),
+        });
+      });
+    },
+
+    /**
+     * Filters out any objects in the fieldsJSON array that have a ".name"
+     * property that matches one of the strings in the fieldsToExclude array
+     * @param {object[]} fieldsJSON - JSON returned from QueryFields.toJSON()
+     * @returns {object[]} The filtered fieldsJSON array
+     */
+    excludeFields(fieldsJSON) {
+      const fieldsToExclude = this.get("excludeFields");
+      const excludeNonSearchable = this.get("excludeNonSearchable");
+
+      let filteredJSON = fieldsJSON;
+      if (fieldsToExclude?.length) {
+        filteredJSON = fieldsJSON.filter(
+          (field) => !fieldsToExclude.includes(field.name),
+        );
+      }
+      if (excludeNonSearchable) {
+        filteredJSON = filteredJSON.filter(
+          (field) => field.searchable !== false && field.searchable !== "false",
+        );
+      }
+      return filteredJSON;
+    },
+
+    /**
+     * Adds fields to the fieldsJSON array that are specified in the addFields
+     * property of this model
+     * @param {object[]} fieldsJSON - JSON returned from QueryFields.toJSON()
+     * @returns {object[]} The fieldsJSON array with additional fields added
+     */
+    addFields(fieldsJSON) {
+      const fieldsToAdd = this.get("addFields");
+      if (!fieldsToAdd?.length) return fieldsJSON;
+
+      const fieldsWithCategoryInfo = fieldsToAdd.map((fieldToAdd) => {
+        const field = { ...fieldToAdd };
+        if (field.category) {
+          const categoryInfo = fieldsJSON.find(
+            (f) => f.category === field.category,
+          );
+          if (categoryInfo) {
+            field.icon = field.icon || categoryInfo.icon;
+            field.categoryOrder =
+              field.categoryOrder || categoryInfo.categoryOrder;
+          }
+        }
+        return field;
+      });
+
+      return fieldsJSON.concat(fieldsWithCategoryInfo);
+    },
+
+    /**
+     * Converts an object that represents a QueryField model to the format
+     * specified by the SearchSelectView.options
+     * @param  {object} field An object with properties corresponding to a
+     * QueryField model
+     * @returns {object} An object with properties that match the format
+     * specified by the SearchSelectView.options
+     */
+    fieldToOption(field) {
+      if (!field) return {};
+      return {
+        label: field.label || field.name,
+        value: field.name,
+        description: field.friendlyDescription || field.description,
+        icon: field.icon,
+        category: field.category,
+        categoryOrder: field.categoryOrder,
+        type: field.type,
+      };
+    },
+
+    /**
+     * Sorts the fieldsJSON array by categoryOrder and then alphabetically
+     * within each category if the category is specified in the
+     * categoriesToAlphabetize property of this model.
+     * @param {object[]} unsortedOptions - An array of objects that represent
+     * attributes for SearchSelectOptions.
+     * @returns {object[]} The sorted options
+     */
+    sortFields(unsortedOptions) {
+      const options = unsortedOptions;
+      const commonFields = this.get("commonFields");
+      if (commonFields?.length) {
+        commonFields.forEach((commonFieldName) => {
+          const i = options.findIndex(
+            (field) => field.value === commonFieldName,
+          );
+          if (i > 0) {
+            options[i] = {
+              ...options[i],
+              category: "",
+              categoryOrder: 0,
+              icon: "star",
+            };
+          }
+        });
+      }
+
+      options.sort((a, b) => a.categoryOrder - b.categoryOrder);
+
+      const sortCategories = this.get("categoriesToAlphabetize");
+      if (sortCategories?.length) {
+        sortCategories.forEach((categoryName) => {
+          const category = options.filter(
+            (field) => field.category === categoryName,
+          );
+          category.sort((a, b) =>
+            a.label.toLowerCase().localeCompare(b.label.toLowerCase()),
+          );
+          const categoryIndex = options.findIndex(
+            (field) => field.category === categoryName,
+          );
+          options.splice(categoryIndex, category.length, ...category);
+        });
+      }
+
+      return options;
+    },
+
+    /**
+     * For options that are added fields, not real query fields from the query
+     * service, this method sets fields and types attributes on the option model
+     * that are the real query fields that the added field represents.
+     * @param {SearchSelectOption} option - The option model to update
+     */
+    setAddedFieldDetails(option) {
+      const addFields = this.get("addFields");
+      const addedField = addFields?.find(
+        (field) => field.name === option?.get("value"),
+      );
+      if (!addedField) return;
+
+      const specialField = { ...addedField };
+      const { fields } = specialField;
+
+      const types = fields.map((fieldName) => {
+        const realField = MetacatUI.queryFields.findWhere({ name: fieldName });
+        return realField ? realField.get("type") : "special field";
+      });
+
+      option.set({
+        fields,
+        types,
+      });
+    },
+
+    /**
+     * Extends the isValidValue method of the SearchSelect model to allow for
+     * the addition of fields that are excluded by default, if they are selected
+     * @param {string} value - The value to check
+     * @returns {boolean} - Returns true if the value is valid, false otherwise
+     */
+    isValidValue(value) {
+      const excludedFields = this.get("excludeFields");
+
+      if (!excludedFields || !excludedFields.includes(value)) {
+        return SearchSelect.prototype.isValidValue.call(this, value);
+      }
+
+      let newField = MetacatUI.queryFields.findWhere({ name: value });
+      if (newField) {
+        newField = this.fieldToOption(newField.toJSON());
+      }
+      this.get("options").add(newField);
+      return true;
+    },
+  });
+
+  return QueryFieldSearchSelect;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_searchSelect_SearchSelect.js.html b/docs/docs/src_js_models_searchSelect_SearchSelect.js.html new file mode 100644 index 000000000..5ec70f332 --- /dev/null +++ b/docs/docs/src_js_models_searchSelect_SearchSelect.js.html @@ -0,0 +1,348 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/searchSelect/SearchSelect.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/searchSelect/SearchSelect.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "collections/searchSelect/SearchSelectOptions"], (
+  Backbone,
+  SearchSelectOptions,
+) => {
+  /**
+   * @class SearchSelect
+   * @classdesc A model for managing dropdown options and state for a search
+   * select component.
+   * @classcategory Models/SearchSelect
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const SearchSelect = Backbone.Model.extend({
+    /** @lends SearchSelect.prototype */
+
+    /**
+     * @returns {object} Default attributes for a SearchSelect model.
+     * @property {boolean} allowMulti - Whether to allow users to select more
+     * than one value.
+     * @property {boolean} allowAdditions - Allows users to add their own
+     * options not listed in options.
+     * @property {boolean} clearable - Whether the dropdown can be cleared by
+     * the user after selection.
+     * @property {string} submenuStyle - Determines the display style of items
+     * in categories ("list", "popout", "accordion").
+     * @property {boolean} hideEmptyCategoriesOnSearch - Displays category
+     * headers in the dropdown even with no results.
+     * @property {SearchSelectOptions} options - Collection of
+     * SearchSelectOption models that represent choices a user can select from.
+     * @property {string[]} selected - Currently selected values in the
+     * dropdown.
+     * @property {string[]|boolean} separatorOptions - For select inputs where
+     * multiple values are allowed (allowMulti is true), a list of options that
+     * can be used as separators between values. To turn off this feature, set
+     * to false or an empty array.
+     * @property {string} separator - The current separator to use between
+     * selected values, must be one of the separatorOptions.
+     * @property {string} searchTerm - The current search term being used to
+     * filter options, if any. This will be updated by the view.
+     * @property {string} originalSubmenuStyle - A reference to the original
+     * submenu style since the submenu style can change during search. This will
+     * be set automatically by the model during initialization.
+     * @property {object|boolean} apiSettings - Settings for retrieving data via
+     * API, false if not using remote content.
+     * @see
+     * {@link https://fomantic-ui.com/modules/dropdown.html#remote-settings}
+     * @see {@link https://fomantic-ui.com/behaviors/api.html#/settings}
+     * @property {string} placeholderText Text to show in the input field before
+     * any value has been entered.
+     * @property {string} inputLabel Label for the input element.
+     * @property {boolean} buttonStyle Set this to true to render the dropdown
+     * as more of a button-like interface. This works best for single-select
+     * dropdowns.
+     * @property {string|boolean} icon Set this to a FontAwesome icon to use
+     * instead of the default dropdown (down arrow) icon. Works will with the
+     * buttonStyle option.
+     * @property {boolean} fluid Set this to true to make the dropdown take up
+     * the full width of its container.
+     * @property {boolean} compact Set this to true to make the dropdown more
+     * compact, e.g. for the filter bar in the catalog search.
+     */
+    defaults() {
+      return {
+        allowMulti: true,
+        allowAdditions: false,
+        clearable: true,
+        submenuStyle: "list",
+        hideEmptyCategoriesOnSearch: true,
+        options: new SearchSelectOptions(),
+        selected: [],
+        separatorOptions: ["AND", "OR"],
+        separator: "",
+        searchTerm: "",
+        originalSubmenuStyle: "",
+        apiSettings: false,
+        placeholderText: "Search for or select a value",
+        inputLabel: "Select a value",
+        buttonStyle: false,
+        icon: false,
+        fluid: true,
+        compact: false,
+      };
+    },
+
+    /** @inheritdoc */
+    initialize(attributes, _options) {
+      this.setOptionsForPreselected();
+      const optionsData = attributes?.options;
+      // Select options must be parsed if they are not already
+      // SearchSelectOption collections
+      if (optionsData && !(optionsData instanceof SearchSelectOptions)) {
+        this.set(
+          "options",
+          new SearchSelectOptions(optionsData, { parse: true }),
+        );
+      }
+      // Save a reference to the original submenu style to revert to when search
+      // term is removed
+      const originalSubmenuStyle = this.get("submenuStyle");
+      this.set("originalSubmenuStyle", originalSubmenuStyle);
+      // Set a listener to change the submenu style when a user is searching
+      if (originalSubmenuStyle !== "list") {
+        this.changeSubmenuOnSearch();
+      }
+    },
+
+    /**
+     * Set a listener to change the current submenu style to "list" when a
+     * search term is present, and revert to the original style when the search
+     * term is removed. This is to ensure that the dropdown displays the list
+     * style with only the search results when a user is searching. This is only
+     * necessary if the submenu style is not already set to "list".
+     */
+    changeSubmenuOnSearch() {
+      this.listenTo(this, "change:searchTerm", (model, searchTerm) => {
+        const originalSubmenuStyle = this.get("originalSubmenuStyle");
+        const submenuStyle = searchTerm ? "list" : originalSubmenuStyle;
+        model.set("submenuStyle", submenuStyle);
+      });
+    },
+
+    /**
+     * Update the options for the dropdown.
+     * @param {object|object[]} options The new options to set for the dropdown
+     */
+    updateOptions(options) {
+      const parse = typeof options === "object" && !Array.isArray(options);
+      this.get("options").reset(options, { parse });
+    },
+
+    /**
+     * Returns the options as a JSON object.
+     * @param {boolean} categorized - Whether to return the options as
+     * categorized. See @link{SearchSelectOptions#toJSON} for more information.
+     * @returns {object|object[]} - The options as a JSON object.
+     */
+    optionsAsJSON(categorized = false) {
+      return this.get("options").toJSON(categorized);
+    },
+
+    /**
+     * Checks if a value is one of the values in the options.
+     * @param {string} value - The value to check for.
+     * @returns {boolean} - Returns true if the value is found in the
+     * collection, false otherwise.
+     */
+    isValidValue(value) {
+      if (this.get("allowAdditions")) return true;
+      return this.get("options").isValidValue(value);
+    },
+
+    /**
+     * Check if there are any invalid selections in the selected values.
+     * @returns {boolean | string[]} - Returns false if there are no invalid
+     * selections, or an array of invalid selection strings if there are any.
+     */
+    hasInvalidSelections() {
+      if (this.get("allowAdditions")) return false;
+      const selected = this.get("selected");
+      if (!selected || !selected.length) return false;
+      const invalidSelections = selected.filter(
+        (value) => !this.isValidValue(value),
+      );
+      return invalidSelections.length ? invalidSelections : false;
+    },
+
+    /**
+     * Add a selected value and ensures it's not already in the list. If this is
+     * not a multi-select dropdown, the selected value will replace any existing
+     * value.
+     * @param {string} value - The value to add to the selected list.
+     * @param {object} options - Additional options to be passed to the set
+     * method.
+     */
+    addSelected(value, options = {}) {
+      const selected = this.get("selected");
+      if (selected.includes(value)) return;
+      const newSelected = this.get("allowMulti")
+        ? [...selected, value]
+        : [value];
+      this.setSelected(newSelected, options);
+    },
+
+    /**
+     * Change the values that are selected in the dropdown.
+     * @param {string|string[]} values - The value(s) to select.
+     * @param {object} options - Additional options to be passed to the set
+     * method.
+     */
+    setSelected(values, options = {}) {
+      const newValues = !Array.isArray(values) ? [values] : values;
+      const selected = [...newValues];
+      this.set({ selected }, options);
+    },
+
+    /**
+     * Remove a value from the selected list.
+     * @param {string} value - The value to remove from the selected list.
+     * @param {object} options - Additional options to be passed to the set
+     * method.
+     */
+    removeSelected(value, options = {}) {
+      const selected = this.get("selected");
+      const newSelected = selected.filter((val) => val !== value);
+      this.set({ selected: newSelected }, options);
+    },
+
+    /**
+     * Determines if a separator is needed for the newly created, yet to be attached label.
+     * @param {string} value - The value of the label.
+     * @returns {boolean} - Returns true if a separator should be created, otherwise false.
+     */
+    separatorRequired(value) {
+      // must have at least a current separator
+      if (!this.get("separator")) return false;
+      const selected = this.get("selected");
+      return (
+        this.get("allowMulti") && selected?.length > 1 && selected[0] !== value
+      );
+    },
+
+    /**
+     * Checks if it's possible to update the separator that is used between
+     * selected values. For this to be possible, there must be more than one
+     * separator option available.
+     * @returns {boolean} - Returns true if the separator can be changed, false
+     * otherwise.
+     */
+    canChangeSeparator() {
+      return (
+        this.get("separatorOptions") && this.get("separatorOptions").length > 1
+      );
+    },
+
+    /**
+     * Get the next separator in the list of separator options.
+     * @returns {string|null} - The next separator in the list of separator
+     * options, or null if none.
+     */
+    getNextSeparator() {
+      const separators = this.get("separatorOptions");
+      const currentSeparator = this.get("separator");
+      if (!currentSeparator || !separators || !separators.length) return null;
+      const currentIndex = separators.indexOf(currentSeparator);
+      let nextIndex = currentIndex + 1;
+      if (nextIndex >= separators.length) {
+        nextIndex = 0;
+      }
+      return separators[nextIndex];
+    },
+
+    /**
+     * Set the next separator in the list of separator options.
+     */
+    setNextSeparator() {
+      const nextSeparator = this.getNextSeparator();
+      if (!nextSeparator) return;
+      this.set("separator", nextSeparator);
+    },
+
+    /**
+     * Get the selected models from the options collection.
+     * @returns {SearchSelectOption[]} - The selected models from the options
+     * collection.
+     */
+    getSelectedModels() {
+      const selected = this.get("selected");
+      return this.get("options").filter((model) =>
+        selected.includes(model.get("value")),
+      );
+    },
+
+    /**
+     * This method is set for extended models that fetch options asynchronously
+     * on search. This method should be overridden to fetch options from the API
+     * for the values that are currently selected in the dropdown. This allows
+     * those values to be populated with the correct label and icon.
+     */
+    setOptionsForPreselected() {
+      // This method should be overridden in extended models
+    },
+  });
+
+  return SearchSelect;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_searchSelect_SearchSelectOption.js.html b/docs/docs/src_js_models_searchSelect_SearchSelectOption.js.html new file mode 100644 index 000000000..1c5deb29f --- /dev/null +++ b/docs/docs/src_js_models_searchSelect_SearchSelectOption.js.html @@ -0,0 +1,102 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/searchSelect/SearchSelectOption.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/searchSelect/SearchSelectOption.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone"], (Backbone) => {
+  /**
+   * @class SelectOptionModel
+   * @classdesc A model for representing an option in a search select dropdown.
+   * @classcategory Models/SearchSelect
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const SearchSelectOption = Backbone.Model.extend({
+    /** @lends SearchSelectOption.prototype */
+
+    /**
+     * @returns {object} The default properties for a SearchSelectOption
+     * @property {string} icon - The name of a Font Awesome 3.2.1 icon to display to
+     * the left of the label (e.g. "lemon", "heart")
+     * @property {string} image - The complete path to an image to use instead of an
+     * icon. If both icon and image are provided, the icon will be used.
+     * @property {string} label - The label to show for the option
+     * @property {string} description - A description of the option, displayed as a
+     * tooltip when the user hovers over the label
+     * @property {string} value - If the value differs from the label, the value to
+     * return when this option is selected (otherwise label is returned)
+     * @property {string} category - If the option is part of a category, the name of
+     * the category to display in the dropdown
+     */
+    defaults() {
+      return {
+        icon: "",
+        image: "",
+        label: "",
+        description: "",
+        value: "",
+        category: "",
+      };
+    },
+  });
+
+  return SearchSelectOption;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_models_searchSelect_SolrAutocomplete.js.html b/docs/docs/src_js_models_searchSelect_SolrAutocomplete.js.html new file mode 100644 index 000000000..ee877ed76 --- /dev/null +++ b/docs/docs/src_js_models_searchSelect_SolrAutocomplete.js.html @@ -0,0 +1,142 @@ + + + + + MetacatUI Dev Docs: Source: src/js/models/searchSelect/SolrAutocomplete.js + + + + + + + + + + + + + + +
+ +

Source: src/js/models/searchSelect/SolrAutocomplete.js

+ + + + + + +
+
+
"use strict";
+
+define(["models/searchSelect/SearchSelect", "collections/SolrResults"], (
+  SearchSelect,
+  SolrResults,
+) => {
+  /**
+   * @class SolrAutocomplete
+   * @classdesc An extension of SearchSelect that limits the options to the
+   * available values within a given Solr field.
+   * @classcategory Models/SearchSelect
+   * @since 2.31.0
+   * @augments Backbone.Model
+   */
+  const SolrAutocomplete = SearchSelect.extend({
+    /** @lends SolrAutocomplete.prototype */
+
+    /** @inheritdoc */
+    defaults() {
+      return {
+        ...SearchSelect.prototype.defaults(),
+        placeholderText: "Start typing a term...",
+        inputLabel: "Search for a term",
+        allowMulti: false,
+        allowAdditions: true,
+        queryField: "",
+      };
+    },
+
+    /** @inheritdoc */
+    initialize(attributes, options) {
+      const queryField = attributes?.queryField || this.get("queryField");
+      if (!queryField) {
+        throw new Error("queryField is required.");
+      }
+      this.set(
+        "searchResults",
+        new SolrResults([], {
+          rows: 1,
+          fields: [queryField],
+          query: `${queryField}:*`,
+          facet: [queryField],
+        }),
+      );
+      this.getSearchResults();
+      SearchSelect.prototype.initialize.call(this, attributes, options);
+    },
+
+    getSearchResults() {
+      const results = this.get("searchResults");
+      this.listenToOnce(results, "sync", this.formatOptions);
+      results.query();
+    },
+
+    formatOptions() {
+      const results = this.get("searchResults");
+      const queryField = this.get("queryField");
+      const facetArray = results.facetCounts[queryField];
+      const formattedFacets = [];
+
+      for (let i = 0; i < facetArray.length; i += 2) {
+        // Array format is [term, count, term, count, ...]
+        const term = facetArray[i];
+        const count = facetArray[i + 1];
+
+        formattedFacets.push({
+          label: term,
+          value: term,
+          description: `${count} matching results`,
+          numResults: count,
+        });
+      }
+
+      formattedFacets.sort((a, b) => b.numResults - a.numResults);
+
+      this.updateOptions(formattedFacets);
+    },
+  });
+
+  return SolrAutocomplete;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_routers_router.js.html b/docs/docs/src_js_routers_router.js.html index dd969ce6f..8602420da 100644 --- a/docs/docs/src_js_routers_router.js.html +++ b/docs/docs/src_js_routers_router.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_AccessPolicyView.js.html b/docs/docs/src_js_views_AccessPolicyView.js.html index b07676c44..398cd37aa 100644 --- a/docs/docs/src_js_views_AccessPolicyView.js.html +++ b/docs/docs/src_js_views_AccessPolicyView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_AccessRuleView.js.html b/docs/docs/src_js_views_AccessRuleView.js.html index c41f3f1c0..70a21ffc9 100644 --- a/docs/docs/src_js_views_AccessRuleView.js.html +++ b/docs/docs/src_js_views_AccessRuleView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_AnnotationView.js.html b/docs/docs/src_js_views_AnnotationView.js.html index b09002d7f..6318f823c 100644 --- a/docs/docs/src_js_views_AnnotationView.js.html +++ b/docs/docs/src_js_views_AnnotationView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_AppView.js.html b/docs/docs/src_js_views_AppView.js.html index efbaa0f20..52727cf56 100644 --- a/docs/docs/src_js_views_AppView.js.html +++ b/docs/docs/src_js_views_AppView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_CitationHeaderView.js.html b/docs/docs/src_js_views_CitationHeaderView.js.html index 6301d649d..6fef679c4 100644 --- a/docs/docs/src_js_views_CitationHeaderView.js.html +++ b/docs/docs/src_js_views_CitationHeaderView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_CitationListView.js.html b/docs/docs/src_js_views_CitationListView.js.html index cdbde9991..c2ac4121f 100644 --- a/docs/docs/src_js_views_CitationListView.js.html +++ b/docs/docs/src_js_views_CitationListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_CitationView.js.html b/docs/docs/src_js_views_CitationView.js.html index 317eaccc4..fe8b8ffb3 100644 --- a/docs/docs/src_js_views_CitationView.js.html +++ b/docs/docs/src_js_views_CitationView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_ColorPaletteView.js.html b/docs/docs/src_js_views_ColorPaletteView.js.html index 9f9e0360b..68daf1544 100644 --- a/docs/docs/src_js_views_ColorPaletteView.js.html +++ b/docs/docs/src_js_views_ColorPaletteView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_DataCatalogView.js.html b/docs/docs/src_js_views_DataCatalogView.js.html index 1c145b885..e520f6518 100644 --- a/docs/docs/src_js_views_DataCatalogView.js.html +++ b/docs/docs/src_js_views_DataCatalogView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -53,7 +53,7 @@

Source: src/js/views/DataCatalogView.js

"models/MetricsModel", "common/Utilities", "views/SearchResultView", - "views/searchSelect/AnnotationFilterView", + "views/searchSelect/BioontologySelectView", "text!templates/search.html", "text!templates/statCounts.html", "text!templates/pager.html", @@ -62,7 +62,7 @@

Source: src/js/views/DataCatalogView.js

"text!templates/loading.html", "gmaps", "nGeohash", -], function ( +], ( $, _, Backbone, @@ -71,7 +71,7 @@

Source: src/js/views/DataCatalogView.js

MetricsModel, Utilities, SearchResultView, - AnnotationFilter, + BioontologySelectView, CatalogTemplate, CountTemplate, PagerTemplate, @@ -80,18 +80,18 @@

Source: src/js/views/DataCatalogView.js

LoadingTemplate, gmaps, nGeohash, -) { +) => { "use strict"; /** * @class DataCatalogView * @classcategory Views - * @extends Backbone.View - * @constructor + * @augments Backbone.View + * @class * @deprecated * @description This view is deprecated and will eventually be removed in a future version (likely 3.0.0) */ - var DataCatalogView = Backbone.View.extend( + const DataCatalogView = Backbone.View.extend( /** @lends DataCatalogView.prototype */ { el: "#Content", @@ -101,7 +101,7 @@

Source: src/js/views/DataCatalogView.js

/** * If true, the view height will be adjusted to fit the height of the window * If false, the view height will be fixed via CSS - * @type {Boolean} + * @type {boolean} */ fixedHeight: false, @@ -202,13 +202,13 @@

Source: src/js/views/DataCatalogView.js

"mouseover .prevent-popover-runoff": "preventPopoverRunoff", }, - initialize: function (options) { - var view = this; + initialize(options) { + const view = this; // Get all the options and apply them to this view if (options) { - var optionKeys = Object.keys(options); - _.each(optionKeys, function (key, i) { + const optionKeys = Object.keys(options); + _.each(optionKeys, (key, i) => { view[key] = options[key]; }); } @@ -217,13 +217,13 @@

Source: src/js/views/DataCatalogView.js

// Render the main view and/or re-render subviews. Don't call .html() here // so we don't lose state, rather use .setElement(). Delegate rendering // and event handling to sub views - render: function () { + render() { // Use the global models if there are no other models specified at time of render if ( MetacatUI.appModel.get("searchHistory").length > 0 && (!this.searchModel || Object.keys(this.searchModel).length == 0) ) { - var lastSearchModels = _.last( + const lastSearchModels = _.last( MetacatUI.appModel.get("searchHistory"), ); @@ -289,12 +289,12 @@

Source: src/js/views/DataCatalogView.js

} // Populate the search template with some model attributes - var loadingHTML = this.loadingTemplate({ + const loadingHTML = this.loadingTemplate({ msg: "Retrieving member nodes...", }); - var templateVars = { - gmaps: gmaps, + const templateVars = { + gmaps, mode: MetacatUI.appModel.get("searchMode"), useMapBounds: this.searchModel.get("useGeohash"), username: MetacatUI.appUserModel.get("username"), @@ -309,16 +309,16 @@

Source: src/js/views/DataCatalogView.js

dataSourceTitle: MetacatUI.theme == "dataone" ? "Member Node" : "Data source", }; - var cel = this.template( + const cel = this.template( _.extend(this.searchModel.toJSON(), templateVars), ); this.$el.html(cel); - //Hide the filters that are disabled in the AppModel settings + // Hide the filters that are disabled in the AppModel settings _.each( this.$(".filter-contain[data-category]"), - function (filterEl) { + (filterEl) => { if ( !_.contains( MetacatUI.appModel.get("defaultSearchFilters"), @@ -342,18 +342,18 @@

Source: src/js/views/DataCatalogView.js

this.renderMap(); // Initialize the tooltips - var tooltips = $(".tooltip-this"); + const tooltips = $(".tooltip-this"); // Find the tooltips that are on filter labels - add a slight delay to those - var groupedTooltips = _.groupBy(tooltips, function (t) { - return ( + const groupedTooltips = _.groupBy( + tooltips, + (t) => ($(t).prop("tagName") == "LABEL" || $(t).parent().prop("tagName") == "LABEL") && - $(t).parents(".filter-container").length > 0 - ); - }); - var forFilterLabel = true, - forOtherElements = false; + $(t).parents(".filter-container").length > 0, + ); + const forFilterLabel = true; + const forOtherElements = false; $(groupedTooltips[forFilterLabel]).tooltip({ delay: { @@ -374,7 +374,7 @@

Source: src/js/views/DataCatalogView.js

this.toggleFilterCollapse(); // Iterate through each search model text attribute and show UI filter for each - var categories = [ + const categories = [ "all", "attribute", "creator", @@ -385,26 +385,26 @@

Source: src/js/views/DataCatalogView.js

"annotation", "isPrivate", ]; - var thisTerm = null; + let thisTerm = null; - for (var i = 0; i < categories.length; i++) { + for (let i = 0; i < categories.length; i++) { thisTerm = this.searchModel.get(categories[i]); if (thisTerm === undefined || thisTerm === null) break; - for (var x = 0; x < thisTerm.length; x++) { + for (let x = 0; x < thisTerm.length; x++) { this.showFilter(categories[i], thisTerm[x]); } } // List the Member Node filters - var view = this; + const view = this; _.each( _.contains( MetacatUI.appModel.get("defaultSearchFilters"), "dataSource", ), - function (source, i) { + (source, i) => { view.showFilter("dataSource", source); }, ); @@ -460,32 +460,35 @@

Source: src/js/views/DataCatalogView.js

/** * addAnnotationFilter - Add the annotation filter to the view */ - addAnnotationFilter: function () { - if (MetacatUI.appModel.get("bioportalAPIKey")) { - var view = this; - var popoverTriggerSelector = - "[data-category='annotation'] .expand-collapse-control"; - if (!this.$el.find(popoverTriggerSelector)) { - return; - } - var annotationFilter = new AnnotationFilter({ - popoverTriggerSelector: popoverTriggerSelector, - }); - this.$el.find(popoverTriggerSelector).append(annotationFilter.el); - annotationFilter.render(); - annotationFilter.off("annotationSelected"); - annotationFilter.on("annotationSelected", function (event, item) { - $("#annotation_input").val(item.value); - view.updateTextFilters(event, item); - }); - } + addAnnotationFilter() { + const view = this; + if (!MetacatUI.appModel.get("bioportalAPIKey")) return; + const containerSelector = + "[data-category='annotation'] .expand-collapse-control + .filter-input-contain"; + const container = this.$el.find(containerSelector); + if (!container) return; + const annotationFilter = new BioontologySelectView({ + inputLabel: "", + compact: true, + }).render(); + container.append(annotationFilter.el); + const bioModel = annotationFilter.model; + this.stopListening(bioModel, "change:selected"); + this.listenTo(bioModel, "change:selected", (model, selected) => { + const value = selected?.[0] || ""; + const option = model.get("options").getOptionByLabelOrValue(value); + const filterLabel = option?.get("label") || ""; + const mockEvent = { target: annotationFilter.el }; + const item = { value, filterLabel }; + view.updateTextFilters(mockEvent, item); + }); }, // Linked Data Object for appending the jsonld into the browser DOM - getLinkedData: function () { + getLinkedData() { // Find the MN info from the CN Node list - var members = MetacatUI.nodeModel.get("members"); - for (var i = 0; i < members.length; i++) { + const members = MetacatUI.nodeModel.get("members"); + for (let i = 0; i < members.length; i++) { if ( members[i].identifier == MetacatUI.nodeModel.get("currentMemberNode") @@ -495,7 +498,7 @@

Source: src/js/views/DataCatalogView.js

} // JSON Linked Data Object - let elJSON = { + const elJSON = { "@context": { "@vocab": "http://schema.org/", }, @@ -504,7 +507,7 @@

Source: src/js/views/DataCatalogView.js

if (nodeModelObject) { // "keywords": "", // "provider": "", - let conditionalData = { + const conditionalData = { description: nodeModelObject.description, identifier: nodeModelObject.identifier, image: nodeModelObject.logo, @@ -517,22 +520,21 @@

Source: src/js/views/DataCatalogView.js

// Check if the jsonld already exists from the previous data view // If not create a new script tag and append otherwise replace the text for the script if (!document.getElementById("jsonld")) { - var el = document.createElement("script"); + const el = document.createElement("script"); el.type = "application/ld+json"; el.id = "jsonld"; el.text = JSON.stringify(elJSON); document.querySelector("head").appendChild(el); } else { - var script = document.getElementById("jsonld"); + const script = document.getElementById("jsonld"); script.text = JSON.stringify(elJSON); } - return; }, /* * Sets the height on elements in the main content area to fill up the entire area minus header and footer */ - setAutoHeight: function () { + setAutoHeight() { // If we are in list mode, don't determine the height of any elements because we are not "full screen" if ( MetacatUI.appModel.get("searchMode") == "list" || @@ -544,14 +546,14 @@

Source: src/js/views/DataCatalogView.js

// Get the heights of the header, navbar, and footer var otherHeight = 0; - $(".auto-height-member").each(function (i, el) { + $(".auto-height-member").each((i, el) => { if ($(el).css("display") != "none") { otherHeight += $(el).outerHeight(true); } }); // Get the remaining height left based on the window size - var remainingHeight = $(window).outerHeight(true) - otherHeight; + let remainingHeight = $(window).outerHeight(true) - otherHeight; if (remainingHeight < 0) remainingHeight = $(window).outerHeight(true) || 300; else if (remainingHeight <= 120) @@ -568,12 +570,12 @@

Source: src/js/views/DataCatalogView.js

var otherHeight = 0; $("#map-container.auto-height") .children() - .each(function (i, el) { + .each((i, el) => { if ($(el).attr("id") != "map-canvas") { otherHeight += $(el).outerHeight(true); } }); - var newMapHeight = remainingHeight - otherHeight; + const newMapHeight = remainingHeight - otherHeight; if (newMapHeight > 100) { $("#map-canvas").height(remainingHeight - otherHeight); } @@ -590,9 +592,9 @@

Source: src/js/views/DataCatalogView.js

* PERFORMING SEARCH * ================================================================================================== */ - triggerSearch: function () { + triggerSearch() { // Set the sort order - var sortOrder = $("#sortOrder").val(); + const sortOrder = $("#sortOrder").val(); if (sortOrder) { this.searchModel.set("sortOrder", sortOrder); } @@ -602,7 +604,7 @@

Source: src/js/views/DataCatalogView.js

if (!this.isSubView) { // make sure the browser knows where we are - var route = Backbone.history.fragment; + const route = Backbone.history.fragment; if (route.indexOf("data") < 0) { MetacatUI.uiRouter.navigate("data", { trigger: false, @@ -617,7 +619,7 @@

Source: src/js/views/DataCatalogView.js

return false; }, - triggerOnEnter: function (e) { + triggerOnEnter(e) { if (e.keyCode != 13) return; // Update the filters @@ -628,15 +630,15 @@

Source: src/js/views/DataCatalogView.js

* getResults gets all the current search filters from the searchModel, creates a Solr query, and runs that query. * @param {number} page - The page of search results to get results for */ - getResults: function (page) { + getResults(page) { // Set the sort order based on user choice - var sortOrder = this.searchModel.get("sortOrder"); + const sortOrder = this.searchModel.get("sortOrder"); if (sortOrder) { this.searchResults.setSort(sortOrder); } // Specify which fields to retrieve - var fields = ""; + let fields = ""; fields += "id,"; fields += "seriesId,"; fields += "title,"; @@ -667,13 +669,12 @@

Source: src/js/views/DataCatalogView.js

this.searchResults.setfields(fields); // Get the query - var query = this.searchModel.getQuery(); + const query = this.searchModel.getQuery(); // Specify which facets to retrieve if (gmaps && this.map) { // If we have Google Maps enabled - var geohashLevel = - "geohash_" + this.mapModel.determineGeohashLevel(this.map.zoom); + const geohashLevel = `geohash_${this.mapModel.determineGeohashLevel(this.map.zoom)}`; this.searchResults.facet.push(geohashLevel); } @@ -705,18 +706,18 @@

Source: src/js/views/DataCatalogView.js

* After the search results have been returned, * check if any of them are derived data or have derivations */ - checkForProv: function () { - var maps = [], - hasSources = [], - hasDerivations = [], - mainSearchResults = this.searchResults; + checkForProv() { + let maps = []; + let hasSources = []; + let hasDerivations = []; + const mainSearchResults = this.searchResults; // Get a list of all the resource map IDs from the SolrResults collection maps = this.searchResults.pluck("resourceMap"); maps = _.compact(_.flatten(maps)); // Create a new Search model with a search that finds all members of these packages/resource maps - var provSearchModel = new SearchModel({ + const provSearchModel = new SearchModel({ formatType: [ { value: "DATA", @@ -729,30 +730,25 @@

Source: src/js/views/DataCatalogView.js

}); // Create a new Solr Results model to store the results of this supplemental query - var provSearchResults = new SearchResults(null, { + const provSearchResults = new SearchResults(null, { query: provSearchModel.getQuery(), searchLogs: false, usePOST: true, rows: 150, - fields: provSearchModel.getProvFlList() + ",id,resourceMap", + fields: `${provSearchModel.getProvFlList()},id,resourceMap`, }); // Trigger a search on that Solr Results model - this.listenTo(provSearchResults, "reset", function (results) { + this.listenTo(provSearchResults, "reset", (results) => { if (results.models.length == 0) return; // See if any of the results have a value for a prov field - results.forEach(function (result) { + results.forEach((result) => { if (!result.getSources().length || !result.getDerivations()) return; - _.each(result.get("resourceMap"), function (rMapID) { + _.each(result.get("resourceMap"), (rMapID) => { if (_.contains(maps, rMapID)) { - var match = mainSearchResults.filter( - function (mainSearchResult) { - return _.contains( - mainSearchResult.get("resourceMap"), - rMapID, - ); - }, + const match = mainSearchResults.filter((mainSearchResult) => + _.contains(mainSearchResult.get("resourceMap"), rMapID), ); if (match && match.length && result.getSources().length > 0) hasSources.push(match[0].get("id")); @@ -768,16 +764,16 @@

Source: src/js/views/DataCatalogView.js

// If they do, find their corresponding result row here and add // the prov icon (or just change the class to active) - _.each(hasSources, function (metadataID) { - var metadataDoc = mainSearchResults.findWhere({ + _.each(hasSources, (metadataID) => { + const metadataDoc = mainSearchResults.findWhere({ id: metadataID, }); if (metadataDoc) { metadataDoc.set("prov_hasSources", true); } }); - _.each(hasDerivations, function (metadataID) { - var metadataDoc = mainSearchResults.findWhere({ + _.each(hasDerivations, (metadataID) => { + const metadataDoc = mainSearchResults.findWhere({ id: metadataID, }); if (metadataDoc) { @@ -788,7 +784,7 @@

Source: src/js/views/DataCatalogView.js

provSearchResults.toPage(0); }, - cacheSearch: function () { + cacheSearch() { MetacatUI.appModel.get("searchHistory").push({ search: this.searchModel.clone(), map: this.mapModel ? this.mapModel.clone() : null, @@ -801,15 +797,15 @@

Source: src/js/views/DataCatalogView.js

* FILTERS * ================================================================================================== */ - updateCheckboxFilter: function (e, category, value) { + updateCheckboxFilter(e, category, value) { if (!this.filters) return; - var checkbox = e.target; - var checked = $(checkbox).prop("checked"); + const checkbox = e.target; + const checked = $(checkbox).prop("checked"); - if (typeof category == "undefined") + if (typeof category === "undefined") var category = $(checkbox).attr("data-category"); - if (typeof value == "undefined") var value = $(checkbox).attr("value"); + if (typeof value === "undefined") var value = $(checkbox).attr("value"); // If the user just unchecked the box, then remove this filter if (!checked) { @@ -818,28 +814,28 @@

Source: src/js/views/DataCatalogView.js

} // If the user just checked the box, then add this filter else { - var currentValue = this.searchModel.get(category); + const currentValue = this.searchModel.get(category); // Get the description - var desc = + let desc = $(checkbox).attr("data-description") || $(checkbox).attr("title"); - if (typeof desc == "undefined" || !desc) desc = ""; + if (typeof desc === "undefined" || !desc) desc = ""; // Get the label - var labl = $(checkbox).attr("data-label"); - if (typeof labl == "undefined" || !labl) labl = ""; + let labl = $(checkbox).attr("data-label"); + if (typeof labl === "undefined" || !labl) labl = ""; // Make the filter object - var filter = { + const filter = { description: desc, label: labl, - value: value, + value, }; // If this filter category is an array, add this value to the array if (Array.isArray(currentValue)) { currentValue.push(filter); this.searchModel.set(category, currentValue); - this.searchModel.trigger("change:" + category); + this.searchModel.trigger(`change:${category}`); } else { // If it isn't an array, then just update the model with a simple value this.searchModel.set(category, filter); @@ -859,13 +855,13 @@

Source: src/js/views/DataCatalogView.js

this.triggerSearch(); }, - updateBooleanFilters: function (e) { + updateBooleanFilters(e) { if (!this.filters) return; // Get the category - var checkbox = e.target; - var category = $(checkbox).attr("data-category"); - var currentValue = this.searchModel.get(category); + const checkbox = e.target; + const category = $(checkbox).attr("data-category"); + const currentValue = this.searchModel.get(category); // If this filter is not enabled, exit this function if ( @@ -874,15 +870,16 @@

Source: src/js/views/DataCatalogView.js

return false; } - //The year filter is handled in a different way + // The year filter is handled in a different way if (category == "pubYear" || category == "dataYear") return; // If the checkbox has a value, then update as a string value not boolean - var value = $(checkbox).attr("value"); + let value = $(checkbox).attr("value"); if (value) { this.updateCheckboxFilter(e, category, value); return; - } else value = $(checkbox).prop("checked"); + } + value = $(checkbox).prop("checked"); this.searchModel.set(category, value); @@ -905,42 +902,42 @@

Source: src/js/views/DataCatalogView.js

this.triggerSearch(); // Track this event - MetacatUI.analytics?.trackEvent("search", "filter, " + category, value); + MetacatUI.analytics?.trackEvent("search", `filter, ${category}`, value); }, // Update the UI year slider and input values // Also update the model - updateYearRange: function (e) { + updateYearRange(e) { if (!this.filters) return; - var viewRef = this, - userAction = !(typeof e === "undefined"), - model = this.searchModel, - pubYearChecked = $("#publish_year").prop("checked"), - dataYearChecked = $("#data_year").prop("checked"); + const viewRef = this; + const userAction = !(typeof e === "undefined"); + const model = this.searchModel; + const pubYearChecked = $("#publish_year").prop("checked"); + const dataYearChecked = $("#data_year").prop("checked"); // If the year range slider has not been created yet if (!userAction && !$("#year-range").hasClass("ui-slider")) { var defaultMin = - typeof this.searchModel.defaults == "function" - ? this.searchModel.defaults().yearMin - : 1800, - defaultMax = - typeof this.searchModel.defaults == "function" - ? this.searchModel.defaults().yearMax - : new Date().getUTCFullYear(); - - //jQueryUI slider + typeof this.searchModel.defaults === "function" + ? this.searchModel.defaults().yearMin + : 1800; + var defaultMax = + typeof this.searchModel.defaults === "function" + ? this.searchModel.defaults().yearMax + : new Date().getUTCFullYear(); + + // jQueryUI slider $("#year-range").slider({ range: true, disabled: false, - min: defaultMin, //sets the minimum on the UI slider on initialization - max: defaultMax, //sets the maximum on the UI slider on initialization + min: defaultMin, // sets the minimum on the UI slider on initialization + max: defaultMax, // sets the maximum on the UI slider on initialization values: [ this.searchModel.get("yearMin"), this.searchModel.get("yearMax"), - ], //where the left and right slider handles are - stop: function (event, ui) { + ], // where the left and right slider handles are + stop(event, ui) { // When the slider is changed, update the input values $("#min_year").val(ui.values[0]); $("#max_year").val(ui.values[1]); @@ -967,7 +964,7 @@

Source: src/js/views/DataCatalogView.js

$("#publish_year").attr("data-category"), true, false, - ui.values[0] + " to " + ui.values[1], + `${ui.values[0]} to ${ui.values[1]}`, { replace: true, }, @@ -978,7 +975,7 @@

Source: src/js/views/DataCatalogView.js

$("#data_year").attr("data-category"), true, false, - ui.values[0] + " to " + ui.values[1], + `${ui.values[0]} to ${ui.values[1]}`, { replace: true, }, @@ -1005,7 +1002,7 @@

Source: src/js/views/DataCatalogView.js

}); return; } - var year = new Date( + const year = new Date( this.statsModel.get("firstBeginDate"), ).getUTCFullYear(); if (typeof year !== "undefined") { @@ -1027,7 +1024,7 @@

Source: src/js/views/DataCatalogView.js

"pubYear", true, false, - $("#min_year").val() + " to " + $("#max_year").val(), + `${$("#min_year").val()} to ${$("#max_year").val()}`, { replace: true, }, @@ -1038,7 +1035,7 @@

Source: src/js/views/DataCatalogView.js

"dataYear", true, false, - $("#min_year").val() + " to " + $("#max_year").val(), + `${$("#min_year").val()} to ${$("#max_year").val()}`, { replace: true, }, @@ -1057,7 +1054,7 @@

Source: src/js/views/DataCatalogView.js

}); return; } - var year = new Date( + const year = new Date( this.statsModel.get("lastEndDate"), ).getUTCFullYear(); if (typeof year !== "undefined") { @@ -1079,7 +1076,7 @@

Source: src/js/views/DataCatalogView.js

"pubYear", true, false, - $("#min_year").val() + " to " + $("#max_year").val(), + `${$("#min_year").val()} to ${$("#max_year").val()}`, { replace: true, }, @@ -1090,7 +1087,7 @@

Source: src/js/views/DataCatalogView.js

"dataYear", true, false, - $("#min_year").val() + " to " + $("#max_year").val(), + `${$("#min_year").val()} to ${$("#max_year").val()}`, { replace: true, }, @@ -1142,8 +1139,8 @@

Source: src/js/views/DataCatalogView.js

} // If either of the year inputs have changed or if just one of the year types were unchecked else { - var minVal = $("#min_year").val(); - var maxVal = $("#max_year").val(); + const minVal = $("#min_year").val(); + const maxVal = $("#max_year").val(); // Update the search model to match what is in the text inputs this.searchModel.set("yearMin", minVal); @@ -1164,7 +1161,7 @@

Source: src/js/views/DataCatalogView.js

$("#data_year").attr("data-category"), true, true, - minVal + " to " + maxVal, + `${minVal} to ${maxVal}`, { replace: true, }, @@ -1174,7 +1171,7 @@

Source: src/js/views/DataCatalogView.js

MetacatUI.analytics?.trackEvent( "search", "filter, Data Year", - minVal + " to " + maxVal, + `${minVal} to ${maxVal}`, ); } else { // Add the filter elements @@ -1183,7 +1180,7 @@

Source: src/js/views/DataCatalogView.js

$("#publish_year").attr("data-category"), true, true, - minVal + " to " + maxVal, + `${minVal} to ${maxVal}`, { replace: true, }, @@ -1193,7 +1190,7 @@

Source: src/js/views/DataCatalogView.js

MetacatUI.analytics?.trackEvent( "search", "filter, Publication Year", - minVal + " to " + maxVal, + `${minVal} to ${maxVal}`, ); } else { this.hideFilter($("#publish_year").attr("data-category"), true); @@ -1204,7 +1201,7 @@

Source: src/js/views/DataCatalogView.js

$("#data_year").attr("data-category"), true, true, - minVal + " to " + maxVal, + `${minVal} to ${maxVal}`, { replace: true, }, @@ -1214,7 +1211,7 @@

Source: src/js/views/DataCatalogView.js

MetacatUI.analytics?.trackEvent( "search", "filter, Data Year", - minVal + " to " + maxVal, + `${minVal} to ${maxVal}`, ); } else { this.hideFilter($("#data_year").attr("data-category"), true); @@ -1230,15 +1227,15 @@

Source: src/js/views/DataCatalogView.js

} }, - updateTextFilters: function (e, item) { + updateTextFilters(e, item) { if (!this.filters) return; // Get the search/filter category - var category = $(e.target).attr("data-category"); + let category = $(e.target).attr("data-category"); // Try the parent elements if not found if (!category) { - var parents = $(e.target) + const parents = $(e.target) .parents() .each(function () { category = $(this).attr("data-category"); @@ -1253,12 +1250,12 @@

Source: src/js/views/DataCatalogView.js

} // Get the input element - var input = this.$el.find("#" + category + "_input"); + const input = this.$el.find(`#${category}_input`); // Get the value of the associated input - var term = !item || !item.value ? input.val() : item.value; - var label = !item || !item.filterLabel ? null : item.filterLabel; - var filterDesc = !item || !item.desc ? null : item.desc; + const term = !item || !item.value ? input.val() : item.value; + const label = !item || !item.filterLabel ? null : item.filterLabel; + const filterDesc = !item || !item.desc ? null : item.desc; // Check that something was actually entered if (term == "" || term == " ") { @@ -1274,20 +1271,18 @@

Source: src/js/views/DataCatalogView.js

} // Get the current searchModel array for this category - var filtersArray = _.clone(this.searchModel.get(category)); + const filtersArray = _.clone(this.searchModel.get(category)); - if (typeof filtersArray == "undefined") { + if (typeof filtersArray === "undefined") { console.error( - "The filter category '" + - category + - "' does not exist in the Search model. Not sending this search term.", + `The filter category '${category}' does not exist in the Search model. Not sending this search term.`, ); return false; } // Check if this entry is a duplicate - var duplicate = (function () { - for (var i = 0; i < filtersArray.length; i++) { + const duplicate = (function () { + for (let i = 0; i < filtersArray.length; i++) { if (filtersArray[i].value === term) { return true; } @@ -1296,14 +1291,14 @@

Source: src/js/views/DataCatalogView.js

if (duplicate) { // Display a quick message - if ($("#duplicate-" + category + "-alert").length <= 0) { - $("#current-" + category + "-filters").prepend( + if ($(`#duplicate-${category}-alert`).length <= 0) { + $(`#current-${category}-filters`).prepend( "<div class='alert alert-block' id='duplicate-' + category + '-alert'>" + "You are already using that filter" + "</div>", ); - $("#duplicate-" + category + "-alert") + $(`#duplicate-${category}-alert`) .delay(2000) .fadeOut(500, function () { this.remove(); @@ -1314,10 +1309,10 @@

Source: src/js/views/DataCatalogView.js

} // Add the new entry to the array of current filters - var filter = { + const filter = { value: term, filterLabel: label, - label: label, + label, description: filterDesc, }; filtersArray.push(filter); @@ -1338,19 +1333,19 @@

Source: src/js/views/DataCatalogView.js

this.triggerSearch(); // Track this event - MetacatUI.analytics?.trackEvent("search", "filter, " + category, term); + MetacatUI.analytics?.trackEvent("search", `filter, ${category}`, term); }, // Removes a specific filter term from the searchModel - removeFilter: function (e) { + removeFilter(e) { // Get the parent element that stores the filter term - var filterNode = $(e.target).parent(); + const filterNode = $(e.target).parent(); // Find this filter's category and value - var category = - filterNode.attr("data-category") || - filterNode.parent().attr("data-category"), - value = $(filterNode).attr("data-term"); + const category = + filterNode.attr("data-category") || + filterNode.parent().attr("data-category"); + const value = $(filterNode).attr("data-term"); // Remove this filter from the searchModel this.searchModel.removeFromModel(category, value); @@ -1359,25 +1354,26 @@

Source: src/js/views/DataCatalogView.js

this.hideFilter(category, value); // If there is an associated checkbox with this filter, uncheck it - var assocCheckbox, - checkboxes = this.$( - "input[type='checkbox'][data-category='" + category + "']", - ); + let assocCheckbox; + const checkboxes = this.$( + `input[type='checkbox'][data-category='${category}']`, + ); - //If there are more than one checkboxes in this category, match by value + // If there are more than one checkboxes in this category, match by value if (checkboxes.length > 1) { - assocCheckbox = _.find(checkboxes, function (checkbox) { - return $(checkbox).val() == value; - }); + assocCheckbox = _.find( + checkboxes, + (checkbox) => $(checkbox).val() == value, + ); } - //If there is only one checkbox in this category, default to it + // If there is only one checkbox in this category, default to it else if (checkboxes.length == 1) { assocCheckbox = checkboxes[0]; } - //If there is an associated checkbox, uncheck it + // If there is an associated checkbox, uncheck it if (assocCheckbox) { - //Uncheck it + // Uncheck it $(assocCheckbox).prop("checked", false); } @@ -1389,8 +1385,8 @@

Source: src/js/views/DataCatalogView.js

}, // Clear all the currently applied filters - resetFilters: function () { - var viewRef = this; + resetFilters() { + const viewRef = this; this.allowSearch = true; @@ -1405,7 +1401,7 @@

Source: src/js/views/DataCatalogView.js

// Then reset the model this.searchModel.clear(); - //Reset the map model + // Reset the map model if (this.mapModel) { this.mapModel.clear(); } @@ -1415,7 +1411,7 @@

Source: src/js/views/DataCatalogView.js

this.searchModel.get("yearMin"), this.searchModel.get("yearMax"), ]); - //and the year inputs + // and the year inputs $("#min_year").val(this.searchModel.get("yearMin")); $("#max_year").val(this.searchModel.get("yearMax")); @@ -1440,32 +1436,30 @@

Source: src/js/views/DataCatalogView.js

this.triggerSearch(); }, - hideEl: function (element) { + hideEl(element) { // Fade out and remove the element - $(element).fadeOut("slow", function () { + $(element).fadeOut("slow", () => { $(element).remove(); }); }, // Removes a specified filter node from the DOM - hideFilter: function (category, value) { + hideFilter(category, value) { if (!this.filters) return; if (typeof value === "undefined") { var filterNode = this.$( - ".current-filters[data-category='" + category + "']", + `.current-filters[data-category='${category}']`, ).children(".current-filter"); } else { var filterNode = this.$( - ".current-filters[data-category='" + category + "']", - ).children("[data-term='" + value + "']"); + `.current-filters[data-category='${category}']`, + ).children(`[data-term='${value}']`); } // Try finding it a different way if (!filterNode || !filterNode.length) { - filterNode = this.$( - ".current-filter[data-category='" + category + "']", - ); + filterNode = this.$(`.current-filter[data-category='${category}']`); } // Remove the filter node from the DOM @@ -1473,29 +1467,21 @@

Source: src/js/views/DataCatalogView.js

}, // Adds a specified filter node to the DOM - showFilter: function ( - category, - term, - checkForDuplicates, - label, - options, - ) { + showFilter(category, term, checkForDuplicates, label, options) { if (!this.filters) return; - var viewRef = this; + const viewRef = this; if (typeof term === "undefined") return false; // Get the element to add the UI filter node to // The pattern is #current-<category>-filters - var filterContainer = this.$el.find( - "#current-" + category + "-filters", - ); + const filterContainer = this.$el.find(`#current-${category}-filters`); // Allow the option to only display this exact filter category and term once to the DOM // Helpful when adding a filter that is not stored in the search model (for display only) if (checkForDuplicates) { - var duplicate = false; + let duplicate = false; // Get the current terms from the DOM and check against the new term filterContainer.children().each(function () { @@ -1510,8 +1496,8 @@

Source: src/js/views/DataCatalogView.js

} } - var value = null, - desc = null; + let value = null; + let desc = null; // See if this filter is an object and extract the filter attributes if (typeof term === "object") { @@ -1542,7 +1528,7 @@

Source: src/js/views/DataCatalogView.js

desc = label; } - var categoryLabel = this.searchModel.fieldLabels[category]; + let categoryLabel = this.searchModel.fieldLabels[category]; if ( typeof categoryLabel === "undefined" && category == "additionalCriteria" @@ -1551,7 +1537,7 @@

Source: src/js/views/DataCatalogView.js

if (typeof categoryLabel === "undefined") categoryLabel = category; // Add a filter node to the DOM - var filterEl = viewRef.currentFilterTemplate({ + const filterEl = viewRef.currentFilterTemplate({ category: Utilities.encodeHTML(categoryLabel), value: Utilities.encodeHTML(value), label: Utilities.encodeHTML(label), @@ -1560,7 +1546,7 @@

Source: src/js/views/DataCatalogView.js

// Add the filter to the page - either replace or tack on if (options && options.replace) { - var currentFilter = filterContainer.find(".current-filter"); + const currentFilter = filterContainer.find(".current-filter"); if (currentFilter.length > 0) { currentFilter.replaceWith(filterEl); } else { @@ -1576,53 +1562,46 @@

Source: src/js/views/DataCatalogView.js

show: 800, }, }); - - return; }, /* * Get the member node list from the model and list the members in the filter list */ - listDataSources: function () { + listDataSources() { if (!this.filters) return; if (MetacatUI.nodeModel.get("members").length < 1) return; // Get the member nodes - var members = _.sortBy( - MetacatUI.nodeModel.get("members"), - function (m) { - if (m.name) { - return m.name.toLowerCase(); - } else { - return ""; - } - }, - ); - var filteredMembers = _.reject(members, function (m) { - return m.status != "operational"; + const members = _.sortBy(MetacatUI.nodeModel.get("members"), (m) => { + if (m.name) { + return m.name.toLowerCase(); + } + return ""; }); + const filteredMembers = _.reject( + members, + (m) => m.status != "operational", + ); // Get the current search filters for data source - var currentFilters = this.searchModel.get("dataSource"); + const currentFilters = this.searchModel.get("dataSource"); // Create an HTML list - var listMax = 4, - numHidden = filteredMembers.length - listMax, - list = $(document.createElement("ul")).addClass("checkbox-list"); + const listMax = 4; + const numHidden = filteredMembers.length - listMax; + const list = $(document.createElement("ul")).addClass("checkbox-list"); // Add a checkbox and label for each member node in the node model - _.each(filteredMembers, function (member, i) { - var listItem = document.createElement("li"), - input = document.createElement("input"), - label = document.createElement("label"); + _.each(filteredMembers, (member, i) => { + const listItem = document.createElement("li"); + const input = document.createElement("input"); + const label = document.createElement("label"); // If this member node is already a data source filter, then the checkbox is checked - var checked = _.findWhere(currentFilters, { + const checked = !!_.findWhere(currentFilters, { value: member.identifier, - }) - ? true - : false; + }); // Create a textual label for this data source $(label) @@ -1662,9 +1641,9 @@

Source: src/js/views/DataCatalogView.js

// Insert a "More" link after a certain amount to enable users to expand the list if (i == listMax) { - var moreLink = document.createElement("a"); + const moreLink = document.createElement("a"); $(moreLink) - .html("Show " + numHidden + " more") + .html(`Show ${numHidden} more`) .addClass("more-link pointer toggle-list") .append( $(document.createElement("i")).addClass("icon icon-expand-alt"), @@ -1678,7 +1657,7 @@

Source: src/js/views/DataCatalogView.js

}); if (numHidden > 0) { - var lessLink = document.createElement("a"); + const lessLink = document.createElement("a"); $(lessLink) .html("Collapse member nodes") .addClass("less-link toggle-list pointer hidden") @@ -1690,28 +1669,30 @@

Source: src/js/views/DataCatalogView.js

} // Add the list of checkboxes to the placeholder - var container = $(".member-nodes-placeholder"); + const container = $(".member-nodes-placeholder"); $(container).html(list); $(".tooltip-this").tooltip(); }, - resetDataSourceList: function () { + resetDataSourceList() { if (!this.filters) return; // Reset the Member Nodes checkboxes - var mnFilterContainer = $("#member-nodes-container"), - defaultMNs = this.searchModel.get("dataSource"); + const mnFilterContainer = $("#member-nodes-container"); + const defaultMNs = this.searchModel.get("dataSource"); // Make sure the member node filter exists if (!mnFilterContainer || mnFilterContainer.length == 0) return false; if (typeof defaultMNs === "undefined" || !defaultMNs) return false; // Reset each member node checkbox - var boxes = $(mnFilterContainer).find(".filter").prop("checked", false); + const boxes = $(mnFilterContainer) + .find(".filter") + .prop("checked", false); // Check the member node checkboxes that are defaults in the search model - _.each(defaultMNs, function (member, i) { - var value = null; + _.each(defaultMNs, (member, i) => { + let value = null; // Allow for string search model filter values and object filter values if (typeof member !== "object" && member) value = member; @@ -1720,20 +1701,20 @@

Source: src/js/views/DataCatalogView.js

else value = member.value; $(mnFilterContainer) - .find("checkbox[value='" + value + "']") + .find(`checkbox[value='${value}']`) .prop("checked", true); }); return true; }, - toggleList: function (e) { + toggleList(e) { if (!this.filters) return; - var link = e.target, - controls = $(link).parents("ul").find(".toggle-list"), - list = $(link).parents("ul"), - isHidden = !list.find(".more-link").is(".hidden"); + const link = e.target; + const controls = $(link).parents("ul").find(".toggle-list"); + const list = $(link).parents("ul"); + const isHidden = !list.find(".more-link").is(".hidden"); // Hide/Show the list if (isHidden) { @@ -1747,9 +1728,9 @@

Source: src/js/views/DataCatalogView.js

}, // add additional criteria to the search model based on link click - additionalCriteria: function (e) { + additionalCriteria(e) { // Get the clicked node - var targetNode = $(e.target); + const targetNode = $(e.target); // If this additional criteria is already applied, remove it if (targetNode.hasClass("active")) { @@ -1758,10 +1739,10 @@

Source: src/js/views/DataCatalogView.js

} // Get the filter criteria - var term = targetNode.attr("data-term"); + const term = targetNode.attr("data-term"); // Find this element's category in the data-category attribute - var category = targetNode.attr("data-category"); + const category = targetNode.attr("data-category"); // style the selection $(".keyword-search-link").removeClass("active"); @@ -1779,26 +1760,26 @@

Source: src/js/views/DataCatalogView.js

return false; }, - removeAdditionalCriteria: function (e) { + removeAdditionalCriteria(e) { // Get the clicked node - var targetNode = $(e.target); + const targetNode = $(e.target); // Reference to model - var model = this.searchModel; + const model = this.searchModel; // remove the styling $(".keyword-search-link").removeClass("active"); $(".keyword-search-link").parent().removeClass("active"); // Get the term - var term = targetNode.attr("data-term"); + const term = targetNode.attr("data-term"); // Get the current search model additional criteria - var current = this.searchModel.get("additionalCriteria"); + const current = this.searchModel.get("additionalCriteria"); // If this term is in the current search model (should be)... if (_.contains(current, term)) { - //then remove it - var newTerms = _.without(current, term); + // then remove it + const newTerms = _.without(current, term); model.set("additionalCriteria", newTerms); } @@ -1810,24 +1791,21 @@

Source: src/js/views/DataCatalogView.js

}, // Get the facet counts - getAutocompletes: function (e) { + getAutocompletes(e) { if (!e) return; // Get the text input to determine the filter type - var input = $(e.target), - category = input.attr("data-category"); + const input = $(e.target); + const category = input.attr("data-category"); if (!this.filters || !category) return; - var viewRef = this; + const viewRef = this; // Create the facet query by using our current search query - var facetQuery = - "q=" + - this.searchResults.currentquery + - "&rows=0" + - this.searchModel.getFacetQuery(category) + - "&wt=json&"; + const facetQuery = `q=${ + this.searchResults.currentquery + }&rows=0${this.searchModel.getFacetQuery(category)}&wt=json&`; // If we've cached these filter results, then use the cache instead of sending a new request if (!MetacatUI.appSearchModel.autocompleteCache) @@ -1841,25 +1819,25 @@

Source: src/js/views/DataCatalogView.js

} // Get the facet counts for the autocomplete - var requestSettings = { + const requestSettings = { url: MetacatUI.appModel.get("queryServiceUrl") + facetQuery, type: "GET", dataType: "json", - success: function (data, textStatus, xhr) { - var suggestions = [], - facetLimit = 999; + success(data, textStatus, xhr) { + let suggestions = []; + const facetLimit = 999; // Get all the facet counts - _.each(category.split(","), function (c) { - if (typeof c == "string") c = [c]; - _.each(c, function (thisCategory) { + _.each(category.split(","), (c) => { + if (typeof c === "string") c = [c]; + _.each(c, (thisCategory) => { // Get the field name(s) - var fieldNames = + let fieldNames = MetacatUI.appSearchModel.facetNameMap[thisCategory]; - if (typeof fieldNames == "string") fieldNames = [fieldNames]; + if (typeof fieldNames === "string") fieldNames = [fieldNames]; // Get the facet counts - _.each(fieldNames, function (fieldName) { + _.each(fieldNames, (fieldName) => { suggestions.push(data.facet_counts.facet_fields[fieldName]); }); }); @@ -1867,24 +1845,24 @@

Source: src/js/views/DataCatalogView.js

suggestions = _.flatten(suggestions); // Format the suggestions - var rankedSuggestions = new Array(); + const rankedSuggestions = new Array(); for ( - var i = 0; + let i = 0; i < Math.min(suggestions.length - 1, facetLimit); i += 2 ) { - //The label is the item value - var label = suggestions[i]; + // The label is the item value + let label = suggestions[i]; - //For all categories except the 'all' category, display the facet count + // For all categories except the 'all' category, display the facet count if (category != "all") { - label += " (" + suggestions[i + 1] + ")"; + label += ` (${suggestions[i + 1]})`; } - //Push the autocomplete item to the array + // Push the autocomplete item to the array rankedSuggestions.push({ value: suggestions[i], - label: label, + label, }); } @@ -1904,14 +1882,14 @@

Source: src/js/views/DataCatalogView.js

); }, - setupAutocomplete: function (input, rankedSuggestions) { - var viewRef = this; + setupAutocomplete(input, rankedSuggestions) { + const viewRef = this; - //Override the _renderItem() function which renders a single autocomplete item. + // Override the _renderItem() function which renders a single autocomplete item. // We want to use the 'title' HTML attribute on each item. // This method must create a new <li> element, append it to the menu, and return it. $.widget("custom.autocomplete", $.ui.autocomplete, { - _renderItem: function (ul, item) { + _renderItem(ul, item) { return $(document.createElement("li")) .attr("title", item.label) .append(item.label) @@ -1919,25 +1897,23 @@

Source: src/js/views/DataCatalogView.js

}, }); input.autocomplete({ - source: function (request, response) { - var term = $.ui.autocomplete.escapeRegex(request.term), - startsWithMatcher = new RegExp("^" + term, "i"), - startsWith = $.grep(rankedSuggestions, function (value) { - return startsWithMatcher.test( - value.label || value.value || value, - ); - }), - containsMatcher = new RegExp(term, "i"), - contains = $.grep(rankedSuggestions, function (value) { - return ( - $.inArray(value, startsWith) < 0 && - containsMatcher.test(value.label || value.value || value) - ); - }); + source(request, response) { + const term = $.ui.autocomplete.escapeRegex(request.term); + const startsWithMatcher = new RegExp(`^${term}`, "i"); + const startsWith = $.grep(rankedSuggestions, (value) => + startsWithMatcher.test(value.label || value.value || value), + ); + const containsMatcher = new RegExp(term, "i"); + const contains = $.grep( + rankedSuggestions, + (value) => + $.inArray(value, startsWith) < 0 && + containsMatcher.test(value.label || value.value || value), + ); response(startsWith.concat(contains)); }, - select: function (event, ui) { + select(event, ui) { // set the text field input.val(ui.item.value); // add to the filter immediately @@ -1953,7 +1929,7 @@

Source: src/js/views/DataCatalogView.js

}); }, - hideClearButton: function () { + hideClearButton() { if (!this.filters) return; // Hide the current filters panel @@ -1964,7 +1940,7 @@

Source: src/js/views/DataCatalogView.js

this.setAutoHeight(); }, - showClearButton: function () { + showClearButton() { if (!this.filters) return; // Show the current filters panel @@ -1988,7 +1964,7 @@

Source: src/js/views/DataCatalogView.js

* ================================================================================================== */ // Update all the statistics throughout the page - updateStats: function () { + updateStats() { if (this.searchResults.header != null) { this.$statcounts = this.$("#statcounts"); this.$statcounts.html( @@ -2006,9 +1982,9 @@

Source: src/js/views/DataCatalogView.js

this.updatePager(); }, - updatePager: function () { + updatePager() { if (this.searchResults.header != null) { - var pageCount = Math.ceil( + const pageCount = Math.ceil( this.searchResults.header.get("numFound") / this.searchResults.header.get("rows"), ); @@ -2027,10 +2003,10 @@

Source: src/js/views/DataCatalogView.js

this.$("#resultspager").html(""); this.$(".resultspager").html(""); } else { - var pages = new Array(pageCount); + const pages = new Array(pageCount); // mark current page correctly, avoid NaN - var currentPage = -1; + let currentPage = -1; try { currentPage = Math.floor( (this.searchResults.header.get("start") / @@ -2038,39 +2014,39 @@

Source: src/js/views/DataCatalogView.js

pageCount, ); } catch (ex) { - console.log("Exception when calculating pages:" + ex.message); + console.log(`Exception when calculating pages:${ex.message}`); } // Populate the pagination element in the UI this.$(".resultspager").html( this.pagerTemplate({ - pages: pages, - currentPage: currentPage, + pages, + currentPage, }), ); this.$("#resultspager").html( this.pagerTemplate({ - pages: pages, - currentPage: currentPage, + pages, + currentPage, }), ); } } }, - updatePageNumber: function (page) { + updatePageNumber(page) { MetacatUI.appModel.set("page", page); if (!this.isSubView) { - var route = Backbone.history.fragment, - subroutePos = route.indexOf("/page/"), - newPage = parseInt(page) + 1; + let route = Backbone.history.fragment; + const subroutePos = route.indexOf("/page/"); + const newPage = parseInt(page) + 1; - //replace the last number with the new one + // replace the last number with the new one if (page > 0 && subroutePos > -1) { route = route.replace(/\d+$/, newPage); } else if (page > 0) { - route += "/page/" + newPage; + route += `/page/${newPage}`; } else if (subroutePos >= 0) { route = route.substring(0, subroutePos); } @@ -2080,35 +2056,35 @@

Source: src/js/views/DataCatalogView.js

}, // Next page of results - nextpage: function () { + nextpage() { this.loading(); this.searchResults.nextpage(); this.$resultsview.show(); this.updateStats(); - var page = MetacatUI.appModel.get("page"); + let page = MetacatUI.appModel.get("page"); page++; this.updatePageNumber(page); }, // Previous page of results - prevpage: function () { + prevpage() { this.loading(); this.searchResults.prevpage(); this.$resultsview.show(); this.updateStats(); - var page = MetacatUI.appModel.get("page"); + let page = MetacatUI.appModel.get("page"); page--; this.updatePageNumber(page); }, - navigateToPage: function (event) { - var page = $(event.target).attr("page"); + navigateToPage(event) { + const page = $(event.target).attr("page"); this.showPage(page); }, - showPage: function (page) { + showPage(page) { this.loading(); this.searchResults.toPage(page); this.$resultsview.show(); @@ -2122,7 +2098,7 @@

Source: src/js/views/DataCatalogView.js

* THE MAP * ================================================================================================== */ - renderMap: function () { + renderMap() { // If gmaps isn't enabled or loaded with an error, use list mode if (!gmaps || this.mode == "list") { this.ready = true; @@ -2138,8 +2114,8 @@

Source: src/js/views/DataCatalogView.js

// Get the map options and create the map gmaps.visualRefresh = true; - var mapOptions = this.mapModel.get("mapOptions"); - var defaultZoom = mapOptions.zoom; + const mapOptions = this.mapModel.get("mapOptions"); + const defaultZoom = mapOptions.zoom; $("#map-container").append("<div id='map-canvas'></div>"); this.map = new gmaps.Map($("#map-canvas")[0], mapOptions); this.mapModel.set("map", this.map); @@ -2150,61 +2126,61 @@

Source: src/js/views/DataCatalogView.js

this.$(this.mapFilterToggle).hide(); // Store references - var mapRef = this.map; - var viewRef = this; + const mapRef = this.map; + const viewRef = this; - google.maps.event.addListener(mapRef, "zoom_changed", function () { + google.maps.event.addListener(mapRef, "zoom_changed", () => { // If the map is zoomed in further than the default zoom level, // than we want to mark the map as zoomed in if (viewRef.map.getZoom() > defaultZoom) { viewRef.hasZoomed = true; } - //If we are at the default zoom level or higher, than do not mark the map + // If we are at the default zoom level or higher, than do not mark the map // as zoomed in else { viewRef.hasZoomed = false; } }); - google.maps.event.addListener(mapRef, "dragend", function () { + google.maps.event.addListener(mapRef, "dragend", () => { viewRef.hasDragged = true; }); - google.maps.event.addListener(mapRef, "idle", function () { + google.maps.event.addListener(mapRef, "idle", () => { // Remove all markers from the map - for (var i = 0; i < viewRef.resultMarkers.length; i++) { + for (let i = 0; i < viewRef.resultMarkers.length; i++) { viewRef.resultMarkers[i].setMap(null); } viewRef.resultMarkers = new Array(); - //Check if the user has interacted with the map just now, and if so, we + // Check if the user has interacted with the map just now, and if so, we // want to alter the geohash filter (changing the geohash values or resetting it completely) - var alterGeohashFilter = + const alterGeohashFilter = viewRef.allowSearch || viewRef.hasZoomed || viewRef.hasDragged; if (!alterGeohashFilter) { return; } - //Determine if the map needs to be recentered. The map only needs to be + // Determine if the map needs to be recentered. The map only needs to be // recentered if it is not at the default lat,long center point AND it // is not zoomed in or dragged to a new center point - var setGeohashFilter = + const setGeohashFilter = viewRef.hasZoomed && viewRef.isMapFilterEnabled(); - //If we are using the geohash filter defined by this map, then + // If we are using the geohash filter defined by this map, then // apply the filter and trigger a new search if (setGeohashFilter) { viewRef.$(viewRef.mapFilterToggle).show(); // Get the Google map bounding box - var boundingBox = mapRef.getBounds(); + const boundingBox = mapRef.getBounds(); // Set the search model spatial filters // Encode the Google Map bounding box into geohash - var north = boundingBox.getNorthEast().lat(), - west = boundingBox.getSouthWest().lng(), - south = boundingBox.getSouthWest().lat(), - east = boundingBox.getNorthEast().lng(); + const north = boundingBox.getNorthEast().lat(); + const west = boundingBox.getSouthWest().lng(); + const south = boundingBox.getSouthWest().lat(); + const east = boundingBox.getNorthEast().lng(); viewRef.searchModel.set("north", north); viewRef.searchModel.set("west", west); @@ -2216,12 +2192,12 @@

Source: src/js/views/DataCatalogView.js

viewRef.mapModel.get("mapOptions").zoom = mapRef.getZoom(); // Determine the precision of geohashes to search for - var zoom = mapRef.getZoom(); + const zoom = mapRef.getZoom(); - var precision = viewRef.mapModel.getSearchPrecision(zoom); + const precision = viewRef.mapModel.getSearchPrecision(zoom); // Get all the geohash tiles contained in the map bounds - var geohashBBoxes = nGeohash.bboxes( + const geohashBBoxes = nGeohash.bboxes( south, west, north, @@ -2233,10 +2209,10 @@

Source: src/js/views/DataCatalogView.js

viewRef.searchModel.set("geohashes", geohashBBoxes); viewRef.searchModel.set("geohashLevel", precision); - //Start back at page 0 + // Start back at page 0 MetacatUI.appModel.set("page", 0); - //Mark the view as ready to start a search + // Mark the view as ready to start a search viewRef.ready = true; // Trigger a new search @@ -2244,37 +2220,35 @@

Source: src/js/views/DataCatalogView.js

viewRef.allowSearch = false; } else { - //Reset the map filter + // Reset the map filter viewRef.resetMap(); - //Start back at page 0 + // Start back at page 0 MetacatUI.appModel.set("page", 0); - //Mark the view as ready to start a search + // Mark the view as ready to start a search viewRef.ready = true; // Trigger a new search viewRef.triggerSearch(); viewRef.allowSearch = false; - - return; } }); }, // Resets the model and view settings related to the map - resetMap: function () { + resetMap() { if (!gmaps) { return; } // First reset the model // The categories pertaining to the map - var categories = ["east", "west", "north", "south"]; + const categories = ["east", "west", "north", "south"]; // Loop through each and remove the filters from the model - for (var i = 0; i < categories.length; i++) { + for (let i = 0; i < categories.length; i++) { this.searchModel.set(categories[i], null); } @@ -2285,18 +2259,18 @@

Source: src/js/views/DataCatalogView.js

this.allowSearch = false; }, - isMapFilterEnabled: function () { - var toggleInput = this.$("input" + this.mapFilterToggle); + isMapFilterEnabled() { + const toggleInput = this.$(`input${this.mapFilterToggle}`); if (typeof toggleInput === "undefined" || !toggleInput) return; return $(toggleInput).prop("checked"); }, - toggleMapFilter: function (e, a) { - var toggleInput = this.$("input" + this.mapFilterToggle); + toggleMapFilter(e, a) { + const toggleInput = this.$(`input${this.mapFilterToggle}`); if (typeof toggleInput === "undefined" || !toggleInput) return; - var isOn = $(toggleInput).prop("checked"); + let isOn = $(toggleInput).prop("checked"); // If the user clicked on the label, then change the checkbox for them if (e.target.tagName != "INPUT") { @@ -2311,25 +2285,25 @@

Source: src/js/views/DataCatalogView.js

}, /** - * Show the marker, infoWindow, and bounding coordinates polygon on + * Show the marker, infoWindow, and bounding coordinates polygon on the map when the user hovers on the marker icon in the result list - * @param {Event} e - */ - showResultOnMap: function (e) { + * @param {Event} e + */ + showResultOnMap(e) { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Get the attributes about this dataset - var resultRow = e.target, - id = $(resultRow).attr("data-id"); + let resultRow = e.target; + let id = $(resultRow).attr("data-id"); // The mouseover event might be triggered by a nested element, so loop through the parents to find the id - if (typeof id == "undefined") { + if (typeof id === "undefined") { $(resultRow) .parents() .each(function () { - if (typeof $(this).attr("data-id") != "undefined") { + if (typeof $(this).attr("data-id") !== "undefined") { id = $(this).attr("data-id"); resultRow = this; } @@ -2337,24 +2311,25 @@

Source: src/js/views/DataCatalogView.js

} // Find the tile for this data set and highlight it on the map - var resultGeohashes = this.searchResults + const resultGeohashes = this.searchResults .findWhere({ - id: id, + id, }) .get("geohash_9"); - for (var i = 0; i < resultGeohashes.length; i++) { - var thisGeohash = resultGeohashes[i], - latLong = nGeohash.decode(thisGeohash), - position = new google.maps.LatLng( - latLong.latitude, - latLong.longitude, - ), - containingTileGeohash = _.find(this.tileGeohashes, function (g) { - return thisGeohash.indexOf(g) == 0; - }), - containingTile = _.findWhere(this.tiles, { - geohash: containingTileGeohash, - }); + for (let i = 0; i < resultGeohashes.length; i++) { + var thisGeohash = resultGeohashes[i]; + const latLong = nGeohash.decode(thisGeohash); + const position = new google.maps.LatLng( + latLong.latitude, + latLong.longitude, + ); + const containingTileGeohash = _.find( + this.tileGeohashes, + (g) => thisGeohash.indexOf(g) == 0, + ); + const containingTile = _.findWhere(this.tiles, { + geohash: containingTileGeohash, + }); // If this is a geohash for a georegion outside the map, do not highlight a tile or display a marker if (typeof containingTile === "undefined") continue; @@ -2362,40 +2337,40 @@

Source: src/js/views/DataCatalogView.js

this.highlightTile(containingTile); // Set up the options for each marker - var markerOptions = { - position: position, + const markerOptions = { + position, icon: this.mapModel.get("markerImage"), zIndex: 99999, map: this.map, }; // Create the marker and add to the map - var marker = new google.maps.Marker(markerOptions); + const marker = new google.maps.Marker(markerOptions); this.resultMarkers.push(marker); } }, /** - * Hide the marker, infoWindow, and bounding coordinates polygon on + * Hide the marker, infoWindow, and bounding coordinates polygon on the map when the user stops hovering on the marker icon in the result list - * @param {Event} e - The event that brought us to this function - */ - hideResultOnMap: function (e) { + * @param {Event} e - The event that brought us to this function + */ + hideResultOnMap(e) { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Get the attributes about this dataset - var resultRow = e.target, - id = $(resultRow).attr("data-id"); + let resultRow = e.target; + let id = $(resultRow).attr("data-id"); // The mouseover event might be triggered by a nested element, so loop through the parents to find the id - if (typeof id == "undefined") { + if (typeof id === "undefined") { $(e.target) .parents() .each(function () { - if (typeof $(this).attr("data-id") != "undefined") { + if (typeof $(this).attr("data-id") !== "undefined") { id = $(this).attr("data-id"); resultRow = this; } @@ -2403,19 +2378,20 @@

Source: src/js/views/DataCatalogView.js

} // Get the map tile for this result and un-highlight it - var resultGeohashes = this.searchResults + const resultGeohashes = this.searchResults .findWhere({ - id: id, + id, }) .get("geohash_9"); - for (var i = 0; i < resultGeohashes.length; i++) { - var thisGeohash = resultGeohashes[i], - containingTileGeohash = _.find(this.tileGeohashes, function (g) { - return thisGeohash.indexOf(g) == 0; - }), - containingTile = _.findWhere(this.tiles, { - geohash: containingTileGeohash, - }); + for (let i = 0; i < resultGeohashes.length; i++) { + var thisGeohash = resultGeohashes[i]; + const containingTileGeohash = _.find( + this.tileGeohashes, + (g) => thisGeohash.indexOf(g) == 0, + ); + const containingTile = _.findWhere(this.tiles, { + geohash: containingTileGeohash, + }); // If this is a geohash for a georegion outside the map, do not unhighlight a tile if (typeof containingTile === "undefined") continue; @@ -2425,7 +2401,7 @@

Source: src/js/views/DataCatalogView.js

} // Remove all markers from the map - _.each(this.resultMarkers, function (marker) { + _.each(this.resultMarkers, (marker) => { marker.setMap(null); }); this.resultMarkers = new Array(); @@ -2433,8 +2409,8 @@

Source: src/js/views/DataCatalogView.js

/** * Create a tile for each geohash facet. A separate tile label is added to the map with the count of the facet. - **/ - drawTiles: function () { + */ + drawTiles() { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; @@ -2442,6 +2418,10 @@

Source: src/js/views/DataCatalogView.js

TextOverlay.prototype = new google.maps.OverlayView(); + /** + * + * @param options + */ function TextOverlay(options) { // Now initialize all properties. this.bounds_ = options.bounds; @@ -2449,7 +2429,7 @@

Source: src/js/views/DataCatalogView.js

this.text = options.text; this.color = options.color; - var length = options.text.toString().length; + const { length } = options.text.toString(); if (length == 1) this.width = 8; else if (length == 2) this.width = 17; else if (length == 3) this.width = 25; @@ -2467,7 +2447,7 @@

Source: src/js/views/DataCatalogView.js

TextOverlay.prototype.onAdd = function () { // Create the DIV and set some basic attributes. - var div = document.createElement("div"); + const div = document.createElement("div"); div.style.color = this.color; div.style.fontSize = "15px"; div.style.position = "absolute"; @@ -2482,7 +2462,7 @@

Source: src/js/views/DataCatalogView.js

// We add an overlay to a map via one of the map's panes. // We'll add this overlay to the overlayLayer pane. - var panes = this.getPanes(); + const panes = this.getPanes(); panes.overlayLayer.appendChild(div); }; @@ -2490,28 +2470,28 @@

Source: src/js/views/DataCatalogView.js

// Size and position the overlay. We use a southwest and northeast // position of the overlay to peg it to the correct position and size. // We need to retrieve the projection from this overlay to do this. - var overlayProjection = this.getProjection(); + const overlayProjection = this.getProjection(); // Retrieve the southwest and northeast coordinates of this overlay // in latlngs and convert them to pixels coordinates. // We'll use these coordinates to resize the DIV. - var sw = overlayProjection.fromLatLngToDivPixel( + const sw = overlayProjection.fromLatLngToDivPixel( this.bounds_.getSouthWest(), ); - var ne = overlayProjection.fromLatLngToDivPixel( + const ne = overlayProjection.fromLatLngToDivPixel( this.bounds_.getNorthEast(), ); // Resize the image's DIV to fit the indicated dimensions. - var div = this.div_; - var width = this.width; - var height = 20; - - div.style.left = sw.x - width / 2 + "px"; - div.style.top = ne.y - height / 2 + "px"; - div.style.width = width + "px"; - div.style.height = height + "px"; - div.style.width = width + "px"; - div.style.height = height + "px"; + const div = this.div_; + const { width } = this; + const height = 20; + + div.style.left = `${sw.x - width / 2}px`; + div.style.top = `${ne.y - height / 2}px`; + div.style.width = `${width}px`; + div.style.height = `${height}px`; + div.style.width = `${width}px`; + div.style.height = `${height}px`; }; TextOverlay.prototype.onRemove = function () { @@ -2520,16 +2500,17 @@

Source: src/js/views/DataCatalogView.js

}; // Determine the geohash level we will use to draw tiles - var currentZoom = this.map.getZoom(), - geohashLevelNum = this.mapModel.determineGeohashLevel(currentZoom), - geohashLevel = "geohash_" + geohashLevelNum, - geohashes = this.searchResults.facetCounts[geohashLevel]; + const currentZoom = this.map.getZoom(); + const geohashLevelNum = + this.mapModel.determineGeohashLevel(currentZoom); + const geohashLevel = `geohash_${geohashLevelNum}`; + const geohashes = this.searchResults.facetCounts[geohashLevel]; // Save the current geohash level in the map model this.mapModel.set("tileGeohashLevel", geohashLevelNum); // Get all the geohashes contained in the map - var mapBBoxes = _.flatten( + const mapBBoxes = _.flatten( _.values(this.searchModel.get("geohashGroups")), ); @@ -2541,10 +2522,10 @@

Source: src/js/views/DataCatalogView.js

var filteredTileGeohashes = []; for (var i = 0; i < geohashes.length - 1; i += 2) { // Get the geohash for this tile - var tileGeohash = geohashes[i], - isInsideMap = false, - index = 0, - searchString = tileGeohash; + var tileGeohash = geohashes[i]; + let isInsideMap = false; + let index = 0; + let searchString = tileGeohash; // Find if any of the bounding boxes/geohashes inside our map contain this tile geohash while (!isInsideMap && searchString.length > 0) { @@ -2563,59 +2544,56 @@

Source: src/js/views/DataCatalogView.js

} } - //If there are no tiles on the page, the map may have failed to render, so exit. + // If there are no tiles on the page, the map may have failed to render, so exit. if ( - typeof filteredTileGeohashes == "undefined" || + typeof filteredTileGeohashes === "undefined" || !filteredTileGeohashes.length ) { return; } // Make a copy of the array that is geohash counts only - var countsOnly = []; + const countsOnly = []; for (var i = 1; i < filteredTileGeohashes.length; i += 2) { countsOnly.push(filteredTileGeohashes[i]); } // Create a range of lightness to make different colors on the tiles - var lightnessMin = this.mapModel.get("tileLightnessMin"), - lightnessMax = this.mapModel.get("tileLightnessMax"), - lightnessRange = lightnessMax - lightnessMin; + const lightnessMin = this.mapModel.get("tileLightnessMin"); + const lightnessMax = this.mapModel.get("tileLightnessMax"); + const lightnessRange = lightnessMax - lightnessMin; // Get some stats on our tile counts so we can normalize them to create a color scale - var findMedian = function (nums) { + const findMedian = function (nums) { if (nums.length % 2 == 0) { return (nums[nums.length / 2 - 1] + nums[nums.length / 2]) / 2; - } else { - return nums[nums.length / 2 - 0.5]; } + return nums[nums.length / 2 - 0.5]; }; - var sortedCounts = countsOnly.sort(function (a, b) { - return a - b; - }), - maxCount = sortedCounts[sortedCounts.length - 1], - minCount = sortedCounts[0]; + const sortedCounts = countsOnly.sort((a, b) => a - b); + const maxCount = sortedCounts[sortedCounts.length - 1]; + const minCount = sortedCounts[0]; - var viewRef = this; + const viewRef = this; // Now draw a tile for each geohash facet for (var i = 0; i < filteredTileGeohashes.length - 1; i += 2) { // Convert this geohash to lat,long values - var tileGeohash = filteredTileGeohashes[i], - decodedGeohash = nGeohash.decode(tileGeohash), - latLngCenter = new google.maps.LatLng( - decodedGeohash.latitude, - decodedGeohash.longitude, - ), - geohashBox = nGeohash.decode_bbox(tileGeohash), - swLatLng = new google.maps.LatLng(geohashBox[0], geohashBox[1]), - neLatLng = new google.maps.LatLng(geohashBox[2], geohashBox[3]), - bounds = new google.maps.LatLngBounds(swLatLng, neLatLng), - tileCount = filteredTileGeohashes[i + 1], - drawMarkers = this.mapModel.get("drawMarkers"), - marker, - count, - color; + var tileGeohash = filteredTileGeohashes[i]; + const decodedGeohash = nGeohash.decode(tileGeohash); + const latLngCenter = new google.maps.LatLng( + decodedGeohash.latitude, + decodedGeohash.longitude, + ); + const geohashBox = nGeohash.decode_bbox(tileGeohash); + const swLatLng = new google.maps.LatLng(geohashBox[0], geohashBox[1]); + const neLatLng = new google.maps.LatLng(geohashBox[2], geohashBox[3]); + const bounds = new google.maps.LatLngBounds(swLatLng, neLatLng); + const tileCount = filteredTileGeohashes[i + 1]; + const drawMarkers = this.mapModel.get("drawMarkers"); + var marker; + var count; + var color; // Normalize the range of tiles counts and convert them to a lightness domain of 20-70% lightness. if (maxCount - minCount == 0) { @@ -2627,11 +2605,10 @@

Source: src/js/views/DataCatalogView.js

lightnessMin; } - var color = - "hsl(" + this.mapModel.get("tileHue") + "," + lightness + "%,50%)"; + var color = `hsl(${this.mapModel.get("tileHue")},${lightness}%,50%)`; // Add the count to the tile - var countLocation = new google.maps.LatLngBounds( + const countLocation = new google.maps.LatLngBounds( latLngCenter, latLngCenter, ); @@ -2645,22 +2622,22 @@

Source: src/js/views/DataCatalogView.js

}); // Set up the default tile options - var tileOptions = { + const tileOptions = { fillColor: color, strokeColor: color, map: this.map, visible: true, - bounds: bounds, + bounds, }; // Merge these options with any tile options set in the map model - var modelTileOptions = this.mapModel.get("tileOptions"); - for (var attr in modelTileOptions) { + const modelTileOptions = this.mapModel.get("tileOptions"); + for (const attr in modelTileOptions) { tileOptions[attr] = modelTileOptions[attr]; } // Draw this tile - var tile = this.drawTile(tileOptions, tileGeohash, count); + const tile = this.drawTile(tileOptions, tileGeohash, count); // Save the geohashes for tiles in the view for later this.tileGeohashes.push(tileGeohash); @@ -2678,47 +2655,51 @@

Source: src/js/views/DataCatalogView.js

* @param {object} options * @param {string} geohash * @param {string} label - **/ - drawTile: function (options, geohash, label) { + */ + drawTile(options, geohash, label) { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Add the tile for these datasets to the map - var tile = new google.maps.Rectangle(options); + const tile = new google.maps.Rectangle(options); - var viewRef = this; + const viewRef = this; // Save our tiles in the view - var tileObject = { + const tileObject = { text: label, shape: tile, - geohash: geohash, - options: options, + geohash, + options, }; this.tiles.push(tileObject); // Change styles when the tile is hovered on - google.maps.event.addListener(tile, "mouseover", function (event) { + google.maps.event.addListener(tile, "mouseover", (event) => { viewRef.highlightTile(tileObject); }); // Change the styles back after the tile is hovered on - google.maps.event.addListener(tile, "mouseout", function (event) { + google.maps.event.addListener(tile, "mouseout", (event) => { viewRef.unhighlightTile(tileObject); }); // If we are at the max zoom, we will display an info window. If not, we will zoom in. if (!this.mapModel.isMaxZoom(viewRef.map)) { - /** Set up some helper functions for zooming in on the map **/ - var myFitBounds = function (myMap, bounds) { + /** + * Set up some helper functions for zooming in on the map + * @param myMap + * @param bounds + */ + const myFitBounds = function (myMap, bounds) { myMap.fitBounds(bounds); // calling fitBounds() here to center the map for the bounds - var overlayHelper = new google.maps.OverlayView(); + const overlayHelper = new google.maps.OverlayView(); overlayHelper.draw = function () { if (!this.ready) { - var extraZoom = getExtraZoom( + const extraZoom = getExtraZoom( this.getProjection(), bounds, myMap.getBounds(), @@ -2738,11 +2719,11 @@

Source: src/js/views/DataCatalogView.js

actualBounds, ) { // in: LatLngBounds bounds -> out: height and width as a Point - var getSizeInPixels = function (bounds) { - var sw = projection.fromLatLngToContainerPixel( + const getSizeInPixels = function (bounds) { + const sw = projection.fromLatLngToContainerPixel( bounds.getSouthWest(), ); - var ne = projection.fromLatLngToContainerPixel( + const ne = projection.fromLatLngToContainerPixel( bounds.getNorthEast(), ); return new google.maps.Point( @@ -2751,8 +2732,8 @@

Source: src/js/views/DataCatalogView.js

); }; - var expectedSize = getSizeInPixels(expectedBounds), - actualSize = getSizeInPixels(actualBounds); + const expectedSize = getSizeInPixels(expectedBounds); + const actualSize = getSizeInPixels(actualBounds); if ( Math.floor(expectedSize.x) == 0 || @@ -2761,9 +2742,9 @@

Source: src/js/views/DataCatalogView.js

return 0; } - var qx = actualSize.x / expectedSize.x; - var qy = actualSize.y / expectedSize.y; - var min = Math.min(qx, qy); + const qx = actualSize.x / expectedSize.x; + const qy = actualSize.y / expectedSize.y; + const min = Math.min(qx, qy); if (min < 1) { return 0; @@ -2773,24 +2754,24 @@

Source: src/js/views/DataCatalogView.js

}; // Zoom in when the tile is clicked on - gmaps.event.addListener(tile, "click", function (clickEvent) { + gmaps.event.addListener(tile, "click", (clickEvent) => { // Change the center viewRef.map.panTo(clickEvent.latLng); // Get this tile's bounds - var tileBounds = tile.getBounds(); + const tileBounds = tile.getBounds(); // Get the current map bounds - var mapBounds = viewRef.map.getBounds(); + const mapBounds = viewRef.map.getBounds(); // Change the zoom - //viewRef.map.fitBounds(tileBounds); + // viewRef.map.fitBounds(tileBounds); myFitBounds(viewRef.map, tileBounds); // Track this event MetacatUI.analytics?.trackEvent( "map", "clickTile", - "geohash : " + tileObject.geohash, + `geohash : ${tileObject.geohash}`, ); }); } @@ -2798,12 +2779,12 @@

Source: src/js/views/DataCatalogView.js

return tile; }, - highlightTile: function (tile) { + highlightTile(tile) { // Change the tile style on hover tile.shape.setOptions(this.mapModel.get("tileOnHover")); // Change the label color on hover - var div = tile.text.div_; + const div = tile.text.div_; if (div) { div.style.color = this.mapModel.get("tileLabelColorOnHover"); tile.text.div_ = div; @@ -2811,12 +2792,12 @@

Source: src/js/views/DataCatalogView.js

} }, - unhighlightTile: function (tile) { + unhighlightTile(tile) { // Change back the tile to it's original styling tile.shape.setOptions(tile.options); // Change back the label color - var div = tile.text.div_; + const div = tile.text.div_; div.style.color = this.mapModel.get("tileLabelColor"); tile.text.div_ = div; $(div).css("color", this.mapModel.get("tileLabelColor")); @@ -2826,47 +2807,43 @@

Source: src/js/views/DataCatalogView.js

* Get the details on each marker * And create an infowindow for that marker */ - addMarkers: function () { + addMarkers() { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Clone the Search model - var searchModelClone = this.searchModel.clone(), - geohashLevel = this.mapModel.get("tileGeohashLevel"), - viewRef = this, - markers = this.markers; + const searchModelClone = this.searchModel.clone(); + const geohashLevel = this.mapModel.get("tileGeohashLevel"); + const viewRef = this; + const { markers } = this; // Change the geohash filter to match our tiles searchModelClone.set("geohashLevel", geohashLevel); searchModelClone.set("geohashes", this.markerGeohashes); // Now run a query to get a list of documents that are represented by our markers - var query = - "q=" + - searchModelClone.getQuery() + - "&fl=id,title,geohash_9,abstract,geohash_" + - geohashLevel + - "&rows=1000" + - "&wt=json"; - - var requestSettings = { + const query = + `q=${searchModelClone.getQuery()}&fl=id,title,geohash_9,abstract,geohash_${geohashLevel}&rows=1000` + + `&wt=json`; + + const requestSettings = { url: MetacatUI.appModel.get("queryServiceUrl") + query, - success: function (data, textStatus, xhr) { - var docs = data.response.docs; - var uniqueGeohashes = viewRef.markerGeohashes; + success(data, textStatus, xhr) { + const { docs } = data.response; + let uniqueGeohashes = viewRef.markerGeohashes; // Create a marker and infoWindow for each document - _.each(docs, function (doc, key, list) { - var marker, - drawMarkersAt = []; + _.each(docs, (doc, key, list) => { + let marker; + const drawMarkersAt = []; // Find the tile place that this document belongs to // For each geohash value at the current geohash level for this document, - _.each(doc.geohash_9, function (geohash, key, list) { + _.each(doc.geohash_9, (geohash, key, list) => { // Loop through each unique tile location to find its match - for (var i = 0; i <= uniqueGeohashes.length; i++) { + for (let i = 0; i <= uniqueGeohashes.length; i++) { if (uniqueGeohashes[i] == geohash.substr(0, geohashLevel)) { drawMarkersAt.push(geohash); uniqueGeohashes = _.without(uniqueGeohashes, geohash); @@ -2875,14 +2852,14 @@

Source: src/js/views/DataCatalogView.js

}); _.each(drawMarkersAt, function (markerGeohash, key, list) { - var decodedGeohash = nGeohash.decode(markerGeohash), - latLng = new google.maps.LatLng( - decodedGeohash.latitude, - decodedGeohash.longitude, - ); + const decodedGeohash = nGeohash.decode(markerGeohash); + const latLng = new google.maps.LatLng( + decodedGeohash.latitude, + decodedGeohash.longitude, + ); // Set up the options for each marker - var markerOptions = { + const markerOptions = { position: latLng, icon: this.mapModel.get("markerImage"), zIndex: 99999, @@ -2890,7 +2867,7 @@

Source: src/js/views/DataCatalogView.js

}; // Create the marker and add to the map - var marker = new google.maps.Marker(markerOptions); + const marker = new google.maps.Marker(markerOptions); }); }); }, @@ -2907,60 +2884,51 @@

Source: src/js/views/DataCatalogView.js

* Get the details on each tile - a list of ids and titles for each dataset contained in that tile * And create an infowindow for that tile */ - addTileInfoWindows: function () { + addTileInfoWindows() { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Clone the Search model - var searchModelClone = this.searchModel.clone(), - geohashLevel = this.mapModel.get("tileGeohashLevel"), - geohashName = "geohash_" + geohashLevel, - viewRef = this, - infoWindows = []; + const searchModelClone = this.searchModel.clone(); + const geohashLevel = this.mapModel.get("tileGeohashLevel"); + const geohashName = `geohash_${geohashLevel}`; + const viewRef = this; + const infoWindows = []; // Change the geohash filter to match our tiles searchModelClone.set("geohashLevel", geohashLevel); searchModelClone.set("geohashes", this.tileGeohashes); // Now run a query to get a list of documents that are represented by our tiles - var query = - "q=" + - searchModelClone.getQuery() + - "&fl=id,title,geohash_9," + - geohashName + - "&rows=1000" + - "&wt=json"; - - var requestSettings = { + const query = + `q=${searchModelClone.getQuery()}&fl=id,title,geohash_9,${geohashName}&rows=1000` + + `&wt=json`; + + const requestSettings = { url: MetacatUI.appModel.get("queryServiceUrl") + query, - success: function (data, textStatus, xhr) { + success(data, textStatus, xhr) { // Make an infoWindow for each doc - var docs = data.response.docs; + const { docs } = data.response; // For each tile, loop through the docs to find which ones to include in its infoWindow - _.each(viewRef.tiles, function (tile, key, list) { - var infoWindowContent = ""; + _.each(viewRef.tiles, (tile, key, list) => { + let infoWindowContent = ""; - _.each(docs, function (doc, key, list) { - var docGeohashes = doc[geohashName]; + _.each(docs, (doc, key, list) => { + const docGeohashes = doc[geohashName]; if (docGeohashes) { // Is this document in this tile? - for (var i = 0; i < docGeohashes.length; i++) { + for (let i = 0; i < docGeohashes.length; i++) { if (docGeohashes[i] == tile.geohash) { // Add this doc to the infoWindow content - infoWindowContent += - "<a href='" + - MetacatUI.root + - "/view/" + - encodeURIComponent(doc.id) + - "'>" + - doc.title + - "</a> (" + - doc.id + - ") <br/>"; + infoWindowContent += `<a href='${ + MetacatUI.root + }/view/${encodeURIComponent(doc.id)}'>${doc.title}</a> (${ + doc.id + }) <br/>`; break; } } @@ -2968,21 +2936,19 @@

Source: src/js/views/DataCatalogView.js

}); // The center of the tile - var decodedGeohash = nGeohash.decode(tile.geohash), - tileCenter = new google.maps.LatLng( - decodedGeohash.latitude, - decodedGeohash.longitude, - ); + const decodedGeohash = nGeohash.decode(tile.geohash); + const tileCenter = new google.maps.LatLng( + decodedGeohash.latitude, + decodedGeohash.longitude, + ); // The infowindow - var infoWindow = new gmaps.InfoWindow({ + const infoWindow = new gmaps.InfoWindow({ content: - "<div class='gmaps-infowindow'>" + - "<h4> Datasets located here </h4>" + - "<p>" + - infoWindowContent + - "</p>" + - "</div>", + `<div class='gmaps-infowindow'>` + + `<h4> Datasets located here </h4>` + + `<p>${infoWindowContent}</p>` + + `</div>`, isOpen: false, disableAutoPan: false, maxWidth: 250, @@ -2996,7 +2962,7 @@

Source: src/js/views/DataCatalogView.js

tile.shape, "click", function (clickEvent) { - //--- We are at max zoom, display an infowindow ----// + // --- We are at max zoom, display an infowindow ----// if (this.mapModel.isMaxZoom(viewRef.map)) { // Find the infowindow that belongs to this tile in the view infoWindow.open(viewRef.map); @@ -3006,13 +2972,13 @@

Source: src/js/views/DataCatalogView.js

viewRef.closeInfoWindows(infoWindow); } - //------ We are not at max zoom, so zoom into this tile ----// + // ------ We are not at max zoom, so zoom into this tile ----// else { // Change the center viewRef.map.panTo(clickEvent.latLng); // Get this tile's bounds - var bounds = tile.shape.getBounds(); + const bounds = tile.shape.getBounds(); // Change the zoom viewRef.map.fitBounds(bounds); @@ -3021,7 +2987,7 @@

Source: src/js/views/DataCatalogView.js

); // Close the infowindow upon any click on the map - gmaps.event.addListener(viewRef.map, "click", function () { + gmaps.event.addListener(viewRef.map, "click", () => { infoWindow.close(); infoWindow.isOpen = false; }); @@ -3044,13 +3010,14 @@

Source: src/js/views/DataCatalogView.js

* Iterate over each infowindow that we have stored in the view and close it. * Pass an infoWindow object to this function to keep that infoWindow open/skip it * @param {infoWindow} - An infoWindow to keep open + * @param except */ - closeInfoWindows: function (except) { - var infoWindowLists = [this.markerInfoWindows, this.tileInfoWindows]; + closeInfoWindows(except) { + const infoWindowLists = [this.markerInfoWindows, this.tileInfoWindows]; - _.each(infoWindowLists, function (infoWindows, key, list) { + _.each(infoWindowLists, (infoWindows, key, list) => { // Iterate over all the marker infowindows and close all of them except for this one - for (var i = 0; i < infoWindows.length; i++) { + for (let i = 0; i < infoWindows.length; i++) { if (infoWindows[i].isOpen && infoWindows[i] != except) { // Close this info window and stop looking, since only one of each kind should be open anyway infoWindows[i].close(); @@ -3063,15 +3030,15 @@

Source: src/js/views/DataCatalogView.js

/** * Remove all the tiles and text from the map - **/ - removeTiles: function () { + */ + removeTiles() { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Remove the tile from the map - _.each(this.tiles, function (tile, key, list) { + _.each(this.tiles, (tile, key, list) => { if (tile.shape) tile.shape.setMap(null); if (tile.text) tile.text.setMap(null); }); @@ -3085,14 +3052,14 @@

Source: src/js/views/DataCatalogView.js

/** * Iterate over all the markers in the view and remove them from the map and view */ - removeMarkers: function () { + removeMarkers() { // Exit if maps are not in use if (this.mode != "map" || !gmaps) { return false; } // Remove the marker from the map - _.each(this.markers, function (marker, key, list) { + _.each(this.markers, (marker, key, list) => { marker.marker.setMap(null); }); @@ -3108,17 +3075,18 @@

Source: src/js/views/DataCatalogView.js

* ================================================================================================== */ - /** Add all items in the **SearchResults** collection + /** + * Add all items in the **SearchResults** collection * This loads the first 25, then waits for the map to be * fully loaded and then loads the remaining items. * Without this delay, the app waits until all records are processed */ - addAll: function () { + addAll() { // After the map is done loading, then load the rest of the results into the list if (this.ready) this.renderAll(); else { - var viewRef = this; - var intervalID = setInterval(function () { + const viewRef = this; + var intervalID = setInterval(() => { if (viewRef.ready) { clearInterval(intervalID); viewRef.renderAll(); @@ -3127,10 +3095,10 @@

Source: src/js/views/DataCatalogView.js

} // After all the results are loaded, query for our facet counts in the background - //this.getAutocompletes(); + // this.getAutocompletes(); }, - renderAll: function () { + renderAll() { // do this first to indicate coming results this.updateStats(); @@ -3142,7 +3110,7 @@

Source: src/js/views/DataCatalogView.js

this.$results.removeClass("loading"); // If there are no results, display so - var numFound = this.searchResults.length; + const numFound = this.searchResults.length; if (numFound == 0) { // Add a No Results Found message this.$results.html("<p id='no-results-found'>No results found.</p>"); @@ -3161,12 +3129,12 @@

Source: src/js/views/DataCatalogView.js

!MetacatUI.appSearchResults.length ) { $("#no-results-found").after( - "<h3>Where are my data sets?</h3><p>If you are a previous ACADIS Gateway user, " + - "you will need to take additional steps to access your data sets in the new NSF Arctic Data Center." + - "<a href='mailto:support@arcticdata.io'>Send us a message at support@arcticdata.io</a> with your old ACADIS " + - "Gateway username and your ORCID identifier (" + - MetacatUI.appUserModel.get("username") + - "), we will help.</p>", + `<h3>Where are my data sets?</h3><p>If you are a previous ACADIS Gateway user, ` + + `you will need to take additional steps to access your data sets in the new NSF Arctic Data Center.` + + `<a href='mailto:support@arcticdata.io'>Send us a message at support@arcticdata.io</a> with your old ACADIS ` + + `Gateway username and your ORCID identifier (${MetacatUI.appUserModel.get( + "username", + )}), we will help.</p>`, ); } } @@ -3176,7 +3144,7 @@

Source: src/js/views/DataCatalogView.js

// Clear the results list before we start adding new rows this.$results.html(""); - //--First map all the results-- + // --First map all the results-- if (gmaps && this.mapModel) { // Draw all the tiles on the map to represent the datasets this.drawTiles(); @@ -3185,25 +3153,25 @@

Source: src/js/views/DataCatalogView.js

$("#map-container").removeClass("loading"); } - var pid_list = new Array(); + const pid_list = new Array(); - //--- Add all the results to the list --- + // --- Add all the results to the list --- for (i = 0; i < this.searchResults.length; i++) { pid_list.push(this.searchResults.models[i].get("id")); } if (MetacatUI.appModel.get("displayDatasetMetrics")) { - var metricsModel = new MetricsModel({ - pid_list: pid_list, + const metricsModel = new MetricsModel({ + pid_list, type: "catalog", }); metricsModel.fetch(); this.metricsModel = metricsModel; } - //--- Add all the results to the list --- + // --- Add all the results to the list --- for (i = 0; i < this.searchResults.length; i++) { - var element = this.searchResults.models[i]; + const element = this.searchResults.models[i]; if (typeof element !== "undefined") this.addOne(element, this.metricsModel); } @@ -3218,8 +3186,9 @@

Source: src/js/views/DataCatalogView.js

/** * Add a single SolrResult item to the list by creating a view for it and appending its element to the DOM. + * @param result */ - addOne: function (result) { + addOne(result) { // Get the view and package service URL's this.$view_service = MetacatUI.appModel.get("viewServiceUrl"); this.$package_service = MetacatUI.appModel.get("packageServiceUrl"); @@ -3228,7 +3197,7 @@

Source: src/js/views/DataCatalogView.js

package_service: this.$package_service, }); - var view = new SearchResultView({ + const view = new SearchResultView({ model: result, metricsModel: this.metricsModel, }); @@ -3240,23 +3209,23 @@

Source: src/js/views/DataCatalogView.js

if ( gmaps && this.mapModel && - typeof result.get("geohash_9") != "undefined" && + typeof result.get("geohash_9") !== "undefined" && result.get("geohash_9") != null ) { - var title = result.get("title"); + const title = result.get("title"); - for (var i = 0; i < result.get("geohash_9").length; i++) { - var centerGeohash = result.get("geohash_9")[i], - decodedGeohash = nGeohash.decode(centerGeohash), - position = new google.maps.LatLng( - decodedGeohash.latitude, - decodedGeohash.longitude, - ), - marker = new gmaps.Marker({ - position: position, - icon: this.mapModel.get("markerImage"), - zIndex: 99999, - }); + for (let i = 0; i < result.get("geohash_9").length; i++) { + const centerGeohash = result.get("geohash_9")[i]; + const decodedGeohash = nGeohash.decode(centerGeohash); + const position = new google.maps.LatLng( + decodedGeohash.latitude, + decodedGeohash.longitude, + ); + const marker = new gmaps.Marker({ + position, + icon: this.mapModel.get("markerImage"), + zIndex: 99999, + }); } } }, @@ -3267,9 +3236,9 @@

Source: src/js/views/DataCatalogView.js

* @param {SolrResult} model * @param {XMLHttpRequest.response} response */ - showError: function (model, response) { - var errorMessage = ""; - var statusCode = response.status; + showError(model, response) { + let errorMessage = ""; + let statusCode = response.status; if (!statusCode) { statusCode = parseInt(response.statusText); @@ -3287,17 +3256,14 @@

Source: src/js/views/DataCatalogView.js

errorMessage = ""; } } finally { - if (typeof errorMessage == "string" && errorMessage.length) { - errorMessage = "<p>Error details: " + errorMessage + "</p>"; + if (typeof errorMessage === "string" && errorMessage.length) { + errorMessage = `<p>Error details: ${errorMessage}</p>`; } } } MetacatUI.appView.showAlert( - "<h4><i class='icon icon-frown'></i>" + - this.solrErrorTitle + - ".</h4>" + - errorMessage, + `<h4><i class='icon icon-frown'></i>${this.solrErrorTitle}.</h4>${errorMessage}`, "alert-error", this.$results, ); @@ -3310,7 +3276,7 @@

Source: src/js/views/DataCatalogView.js

* STYLING THE UI * ================================================================================================== */ - toggleMapMode: function (e) { + toggleMapMode(e) { if (typeof e === "object") { e.preventDefault(); } @@ -3335,7 +3301,7 @@

Source: src/js/views/DataCatalogView.js

}, // Communicate that the page is loading - loading: function () { + loading() { $("#map-container").addClass("loading"); this.$results.addClass("loading"); @@ -3347,22 +3313,24 @@

Source: src/js/views/DataCatalogView.js

}, // Toggles the collapseable filters sidebar and result list in the default theme - collapse: function (e) { - var id = $(e.target).attr("data-collapse"); + collapse(e) { + const id = $(e.target).attr("data-collapse"); - $("#" + id).toggleClass("collapsed"); + $(`#${id}`).toggleClass("collapsed"); }, - toggleFilterCollapse: function (e) { + toggleFilterCollapse(e) { + let container = this.$(".filter-contain.collapsable"); if (typeof e !== "undefined") { - var container = $(e.target).parents(".filter-contain.collapsable"); - } else { - var container = this.$(".filter-contain.collapsable"); + container = $(e.target).parents(".filter-contain.collapsable"); } // If we can't find a container, then don't do anything if (container.length < 1) return; + const isAnnoContainer = + $(container).attr("data-category") === "annotation"; + // Expand if ($(container).is(".collapsed")) { // Toggle the visibility of the collapse/expand icons @@ -3374,6 +3342,11 @@

Source: src/js/views/DataCatalogView.js

// Increase the height of the container to expand it $(container).css("max-height", "3000px"); + + // For annotation container, allow overflow for the dropdown + if (isAnnoContainer) { + $(container).css("overflow", "visible"); + } } // Collapse else { @@ -3387,15 +3360,17 @@

Source: src/js/views/DataCatalogView.js

} else { $(container).css("max-height", "1.5em"); } + if (isAnnoContainer) { + $(container).css("overflow", "hidden"); + } } $(container).toggleClass("collapsed"); }, - /* * Either hides or shows the "clear all filters" button */ - toggleClearButton: function () { + toggleClearButton() { if (this.searchModel.filterCount() > 0) { this.showClearButton(); } else { @@ -3404,7 +3379,7 @@

Source: src/js/views/DataCatalogView.js

}, // Move the popover element up the page a bit if it runs off the bottom of the page - preventPopoverRunoff: function (e) { + preventPopoverRunoff(e) { // In map view only (because all elements are fixed and you can't scroll) if (this.mode == "map") { var viewportHeight = $("#map-container").outerHeight(); @@ -3413,9 +3388,9 @@

Source: src/js/views/DataCatalogView.js

} if ($(".popover").length > 0) { - var offset = $(".popover").offset(); - var popoverHeight = $(".popover").outerHeight(); - var topPosition = offset.top; + const offset = $(".popover").offset(); + const popoverHeight = $(".popover").outerHeight(); + const topPosition = offset.top; // If pixels are cut off the top of the page, readjust its vertical position if (topPosition < 0) { @@ -3424,11 +3399,11 @@

Source: src/js/views/DataCatalogView.js

}); } else { // Else, let's check if it is cut off at the bottom - var totalHeight = topPosition + popoverHeight; + const totalHeight = topPosition + popoverHeight; - var pixelsHidden = totalHeight - viewportHeight; + const pixelsHidden = totalHeight - viewportHeight; - var newTopPosition = topPosition - pixelsHidden - 40; + const newTopPosition = topPosition - pixelsHidden - 40; // If pixels are cut off the bottom of the page, readjust its vertical position if (pixelsHidden > 0) { @@ -3440,7 +3415,7 @@

Source: src/js/views/DataCatalogView.js

} }, - onClose: function () { + onClose() { this.stopListening(); $(".DataCatalog").removeClass("DataCatalog"); diff --git a/docs/docs/src_js_views_DataCatalogViewWithFilters.js.html b/docs/docs/src_js_views_DataCatalogViewWithFilters.js.html index a6c789da9..f97c70015 100644 --- a/docs/docs/src_js_views_DataCatalogViewWithFilters.js.html +++ b/docs/docs/src_js_views_DataCatalogViewWithFilters.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_DataItemView.js.html b/docs/docs/src_js_views_DataItemView.js.html index b9f085356..938f2db1e 100644 --- a/docs/docs/src_js_views_DataItemView.js.html +++ b/docs/docs/src_js_views_DataItemView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -647,33 +647,15 @@

Source: src/js/views/DataItemView.js

this.$el.attr("data-packageId", this.dataPackageId); } - //Download button - attributes.downloadUrl = undefined; - if ( - this.model.get("dataUrl") !== undefined || - this.model.get("url") !== undefined || - this.model.url() !== undefined - ) { - if (this.model.get("dataUrl") !== undefined) { - attributes.downloadUrl = this.model.get("dataUrl"); - } else if (this.model.get("url") !== undefined) { - attributes.downloadUrl = this.model.get("url"); - } else if (this.model.url() !== undefined) { - var downloadUrl = this.model.url(); - attributes.downloadUrl = downloadUrl.replace( - "/meta/", - "/object/", - ); - } - } + // Download button this.downloadButtonView = new DownloadButtonView({ model: this.model, view: "actionsView", }); this.downloadButtonView.render(); - let id = this.model.get("id"); - let infoLink = + const id = this.model.get("id"); + const infoLink = MetacatUI.root + "/view/" + encodeURIComponent(this.currentlyViewing) + diff --git a/docs/docs/src_js_views_DataPackageView.js.html b/docs/docs/src_js_views_DataPackageView.js.html index 7426dd126..0ccd4711f 100644 --- a/docs/docs/src_js_views_DataPackageView.js.html +++ b/docs/docs/src_js_views_DataPackageView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -50,6 +50,7 @@

Source: src/js/views/DataPackageView.js

"backbone", "localforage", "collections/DataPackage", + "common/Utilities", "models/DataONEObject", "models/PackageModel", "models/metadata/ScienceMetadata", @@ -60,12 +61,13 @@

Source: src/js/views/DataPackageView.js

"text!templates/dataPackage.html", "text!templates/dataPackageStart.html", "text!templates/dataPackageHeader.html", -], function ( +], ( $, _, Backbone, LocalForage, DataPackage, + Utilities, DataONEObject, PackageModel, ScienceMetadata, @@ -76,7 +78,7 @@

Source: src/js/views/DataPackageView.js

DataPackageTemplate, DataPackageStartTemplate, DataPackageHeaderTemplate, -) { +) => { "use strict"; /** @@ -85,7 +87,7 @@

Source: src/js/views/DataPackageView.js

* a file/folder browser * @classcategory Views * @screenshot views/DataPackageView.png - * @extends Backbone.View + * @augments Backbone.View */ var DataPackageView = Backbone.View.extend( /** @lends DataPackageView.prototype */ { @@ -126,11 +128,11 @@

Source: src/js/views/DataPackageView.js

/* Flag indicating the open or closed state of the package rows */ isOpen: true, - initialize: function (options) { + initialize(options) { if (options === undefined || !options) var options = {}; if (!options.edit) { - //The edit option will allow the user to edit the table + // The edit option will allow the user to edit the table this.edit = options.edit || false; this.mode = "view"; this.packageId = options.packageId || null; @@ -153,18 +155,18 @@

Source: src/js/views/DataPackageView.js

this.listenTo(this.packageModel, "changeAll", this.render); } else { - //Get the options sent to this view - if (typeof options == "object") { - //The edit option will allow the user to edit the table + // Get the options sent to this view + if (typeof options === "object") { + // The edit option will allow the user to edit the table this.edit = options.edit || false; this.mode = "edit"; - //The data package to render + // The data package to render this.dataPackage = options.dataPackage || new DataPackage(); this.parentEditorView = options.parentEditorView || null; } - //Create a new DataPackage collection if one wasn't sent + // Create a new DataPackage collection if one wasn't sent else if (!this.dataPackage) { this.dataPackage = new DataPackage(); } @@ -176,7 +178,7 @@

Source: src/js/views/DataPackageView.js

/** * Render the DataPackage HTML */ - render: function () { + render() { this.$el.addClass("download-contents table-condensed"); this.$el.append( this.template({ @@ -204,13 +206,13 @@

Source: src/js/views/DataPackageView.js

this.addAll(); if (this.edit) { - //If this is a new data package, then display a message and button + // If this is a new data package, then display a message and button if ( (this.dataPackage.length == 1 && this.dataPackage.models[0].isNew()) || !this.dataPackage.length ) { - var messageRow = this.startMessageTemplate(); + const messageRow = this.startMessageTemplate(); this.$("tbody").append(messageRow); @@ -219,7 +221,7 @@

Source: src/js/views/DataPackageView.js

}); } - //Render the Share control(s) + // Render the Share control(s) this.renderShareControl(); } else { // check for nessted datasets @@ -234,13 +236,14 @@

Source: src/js/views/DataPackageView.js

/** * Add a single DataItemView row to the DataPackageView + * @param item + * @param dataPackage */ - addOne: function (item, dataPackage) { + addOne(item, dataPackage) { if (!item) return false; - //Don't add duplicate rows - if (this.$(".data-package-item[data-id='" + item.id + "']").length) - return; + // Don't add duplicate rows + if (this.$(`.data-package-item[data-id='${item.id}']`).length) return; // Don't add data package if ( @@ -250,18 +253,21 @@

Source: src/js/views/DataPackageView.js

return; } - var dataItemView, scimetaParent, parentRow, delayed_models; + let dataItemView; + let scimetaParent; + let parentRow; + let delayed_models; if (_.contains(Object.keys(this.subviews), item.id)) { return false; // Don't double render } - var itemPath = null, - view = this; + let itemPath = null; + const view = this; if (!_.isEmpty(this.atLocationObj)) { itemPath = this.atLocationObj[item.get("id")]; if (itemPath[0] != "/") { - itemPath = "/" + itemPath; + itemPath = `/${itemPath}`; } } @@ -272,37 +278,37 @@

Source: src/js/views/DataPackageView.js

if (typeof dataPackageId === "undefined") dataPackageId = this.dataPackage.id; - var insertInfoIcon = this.edit + const insertInfoIcon = this.edit ? false : view.dataEntities.includes(item.id); dataItemView = new DataItemView({ model: item, metricsModel: this.metricsModel, - itemPath: itemPath, - insertInfoIcon: insertInfoIcon, + itemPath, + insertInfoIcon, currentlyViewing: this.currentlyViewing, mode: this.mode, parentEditorView: this.parentEditorView, - dataPackageId: dataPackageId, + dataPackageId, }); this.subviews[item.id] = dataItemView; // keep track of all views if (this.edit) { - //Get the science metadata that documents this item + // Get the science metadata that documents this item scimetaParent = item.get("isDocumentedBy"); - //If this item is not documented by a science metadata object, + // If this item is not documented by a science metadata object, // and there is only one science metadata doc in the package, then assume it is // documented by that science metadata doc - if (typeof scimetaParent == "undefined" || !scimetaParent) { - //Get the science metadata models - var metadataIds = this.dataPackage.sciMetaPids; + if (typeof scimetaParent === "undefined" || !scimetaParent) { + // Get the science metadata models + const metadataIds = this.dataPackage.sciMetaPids; - //If there is only one science metadata model in the package, then use it + // If there is only one science metadata model in the package, then use it if (metadataIds.length == 1) scimetaParent = metadataIds[0]; } - //Otherwise, get the first science metadata doc that documents this object + // Otherwise, get the first science metadata doc that documents this object else { scimetaParent = scimetaParent[0]; } @@ -322,7 +328,7 @@

Source: src/js/views/DataPackageView.js

} else { // Find the parent row by it's id, stored in a custom attribute if (scimetaParent) - parentRow = this.$("[data-id='" + scimetaParent + "']"); + parentRow = this.$(`[data-id='${scimetaParent}']`); if (typeof parentRow !== "undefined" && parentRow.length) { // This is a data row, insert below it's metadata parent folder @@ -331,7 +337,7 @@

Source: src/js/views/DataPackageView.js

// Remove it from the delayedModels list if necessary if (_.contains(Object.keys(this.delayedModels), scimetaParent)) { delayed_models = this.delayedModels[scimetaParent]; - var index = _.indexOf(delayed_models, item); + const index = _.indexOf(delayed_models, item); delayed_models = delayed_models.splice(index, 1); // Put the shortened array back if delayed models remains @@ -345,9 +351,7 @@

Source: src/js/views/DataPackageView.js

this.trigger("addOne"); } else { console.warn( - "Couldn't render " + - item.id + - ". Delayed until parent is rendered.", + `Couldn't render ${item.id}. Delayed until parent is rendered.`, ); // Postpone the data row until the parent is rendered delayed_models = this.delayedModels[scimetaParent]; @@ -376,8 +380,8 @@

Source: src/js/views/DataPackageView.js

/** * Render the Data Package View and insert it into this view */ - renderDataPackage: function () { - var view = this; + renderDataPackage() { + const view = this; if (MetacatUI.rootDataPackage.packageModel.isNew()) { view.renderMember(this.model); @@ -389,23 +393,23 @@

Source: src/js/views/DataPackageView.js

this.listenTo(model, "sync", view.renderMember); else if (model.get("synced")) view.renderMember(model); - //Listen for changes on this member + // Listen for changes on this member model.on("change:fileName", model.addToUploadQueue); }); - //Render the Data Package view + // Render the Data Package view this.dataPackageView = new DataPackageView({ edit: true, dataPackage: MetacatUI.rootDataPackage, parentEditorView: this, }); - //Render the view - var $packageTableContainer = this.$("#data-package-container"); + // Render the view + const $packageTableContainer = this.$("#data-package-container"); $packageTableContainer.html(this.dataPackageView.render().el); - //Make the view resizable on the bottom - var handle = $(document.createElement("div")) + // Make the view resizable on the bottom + const handle = $(document.createElement("div")) .addClass("ui-resizable-handle ui-resizable-s") .attr("title", "Drag to resize") .append( @@ -416,15 +420,15 @@

Source: src/js/views/DataPackageView.js

handles: { s: handle }, minHeight: 100, maxHeight: 900, - resize: function () { + resize() { view.emlView.resizeTOC(); }, }); - var tableHeight = ($(window).height() - $("#Navbar").height()) * 0.4; - $packageTableContainer.css("height", tableHeight + "px"); + const tableHeight = ($(window).height() - $("#Navbar").height()) * 0.4; + $packageTableContainer.css("height", `${tableHeight}px`); - var table = this.dataPackageView.$el; + const table = this.dataPackageView.$el; this.listenTo(this.dataPackageView, "addOne", function () { if ( table.outerHeight() > $packageTableContainer.outerHeight() && @@ -440,7 +444,7 @@

Source: src/js/views/DataPackageView.js

if (this.emlView) this.emlView.resizeTOC(); - //Save the view as a subview + // Save the view as a subview this.subviews.push(this.dataPackageView); this.listenTo( @@ -453,12 +457,12 @@

Source: src/js/views/DataPackageView.js

/** * Add all rows to the DataPackageView */ - addAll: function () { + addAll() { this.$el.find("#data-package-table-body").html(""); // clear the table first this.dataPackage.sort(); if (!this.edit) { - var atLocationObj = this.dataPackage.getAtLocation(); + const atLocationObj = this.dataPackage.getAtLocation(); this.atLocationObj = atLocationObj; // form path to D1 object dictionary @@ -474,11 +478,11 @@

Source: src/js/views/DataPackageView.js

} }, this); - for (let key of Object.keys(this.atLocationObj)) { - var path = this.atLocationObj[key]; - var pathArray = path.split("/"); + for (const key of Object.keys(this.atLocationObj)) { + const path = this.atLocationObj[key]; + const pathArray = path.split("/"); pathArray.pop(); - var parentPath = pathArray.join("/"); + const parentPath = pathArray.join("/"); if (filePathObj.hasOwnProperty(parentPath)) { filePathObj[parentPath].push(key); } else { @@ -489,31 +493,33 @@

Source: src/js/views/DataPackageView.js

} // add top level data package row to the package table - var tableRow = null, - view = this, - title = this.packageTitle, - packageUrl = null; + let tableRow = null; + const view = this; + let title = this.packageTitle; + let packageUrl = null; if (title === "") { - let metadataObj = _.filter(this.dataPackage.models, function (m) { - return m.get("id") == view.currentlyViewing; - }); + const metadataObj = _.filter( + this.dataPackage.models, + (m) => m.get("id") == view.currentlyViewing, + ); if (metadataObj.length > 0) { title = metadataObj[0].get("title"); - let metaId = metadataObj[0].get("id"); + const metaId = metadataObj[0].get("id"); this.metaId = metaId; } else { title = this.dataPackage.get("id"); } } - let titleTooltip = title; + const titleTooltip = title; title = title.length > 150 - ? title.slice(0, 75) + - "..." + - title.slice(title.length - 75, title.length) + ? `${title.slice(0, 75)}...${title.slice( + title.length - 75, + title.length, + )}` : title; // set the package URL @@ -522,20 +528,21 @@

Source: src/js/views/DataPackageView.js

MetacatUI.appModel.get("packageServiceUrl") + encodeURIComponent(view.dataPackage.id); - var disablePackageDownloads = this.disablePackageDownloads; + const { disablePackageDownloads } = this; tableRow = this.dataPackageHeaderTemplate({ id: view.dataPackage.id, - title: title, - titleTooltip: titleTooltip, + title, + titleTooltip, downloadUrl: packageUrl, - disablePackageDownloads: disablePackageDownloads, + disablePackageDownloads, + disablePackageUrl: true, }); this.$el.append(tableRow); if (this.atLocationObj !== undefined && filePathObj !== undefined) { // sort the filePath by length - var sortedFilePathObj = Object.keys(filePathObj) + const sortedFilePathObj = Object.keys(filePathObj) .sort() .reduce((obj, key) => { obj[key] = filePathObj[key]; @@ -554,23 +561,25 @@

Source: src/js/views/DataPackageView.js

/** * Add all the files and folders + * @param sortedFilePathObj */ - addFilesAndFolders: function (sortedFilePathObj) { + addFilesAndFolders(sortedFilePathObj) { if (!sortedFilePathObj) return false; - var insertedPath = new Array(); - let pathMap = new Object(); + const insertedPath = new Array(); + const pathMap = new Object(); pathMap[""] = ""; - for (let key of Object.keys(sortedFilePathObj)) { + for (const key of Object.keys(sortedFilePathObj)) { // add folder - var pathArray = key.split("/"); - //skip the first empty value + const pathArray = key.split("/"); + // skip the first empty value for (let i = 0; i < pathArray.length; i++) { if (pathArray[i].length < 1) continue; if (!(pathArray[i] in pathMap)) { // insert path - var dataItemView, itemPath; + var dataItemView; + var itemPath; // root if (i == 0) { @@ -582,7 +591,7 @@

Source: src/js/views/DataPackageView.js

dataItemView = new DataItemView({ mode: this.mode, itemName: pathArray[i], - itemPath: itemPath, + itemPath, itemType: "folder", parentEditorView: this.parentEditorView, dataPackageId: this.dataPackage.id, @@ -594,12 +603,12 @@

Source: src/js/views/DataPackageView.js

this.trigger("addOne"); - pathMap[pathArray[i]] = itemPath + "/" + pathArray[i]; + pathMap[pathArray[i]] = `${itemPath}/${pathArray[i]}`; } } // add files in the folder - var itemArray = sortedFilePathObj[key]; + const itemArray = sortedFilePathObj[key]; // Add metadata object at the top of the file table if ( @@ -607,12 +616,12 @@

Source: src/js/views/DataPackageView.js

this.metaId !== "undefined" && itemArray.includes(this.metaId) ) { - let item = this.metaId; + const item = this.metaId; this.addOne(this.dataPackage.get(item)); } for (let i = 0; i < itemArray.length; i++) { - let item = itemArray[i]; + const item = itemArray[i]; this.addOne(this.dataPackage.get(item)); } } @@ -620,10 +629,9 @@

Source: src/js/views/DataPackageView.js

/** Remove the subview represented by the given model item. - @param item The model representing the sub view to be removed - */ - removeOne: function (item) { + */ + removeOne(item) { if (_.contains(Object.keys(this.subviews), item.id)) { // Remove the view and the its reference in the subviews list this.subviews[item.id].remove(); @@ -631,8 +639,8 @@

Source: src/js/views/DataPackageView.js

} }, - handleAddFiles: function (e) { - //Pass this on to the DataItemView for the root data package + handleAddFiles(e) { + // Pass this on to the DataItemView for the root data package this.$(".data-package-item.folder") .first() .data("view") @@ -643,7 +651,7 @@

Source: src/js/views/DataPackageView.js

* Renders a control that opens the AccessPolicyView for editing permissions on this package * @since 2.15.0 */ - renderShareControl: function () { + renderShareControl() { if ( this.parentEditorView && !this.parentEditorView.isAccessPolicyEditEnabled() @@ -655,31 +663,32 @@

Source: src/js/views/DataPackageView.js

/** * Close subviews as needed */ - onClose: function () { + onClose() { // Close each subview _.each( Object.keys(this.subviews), function (id) { - var subview = this.subviews[id]; + const subview = this.subviews[id]; subview.onClose(); }, this, ); - //Reset the subviews from the view completely (by removing it from the prototype) + // Reset the subviews from the view completely (by removing it from the prototype) this.__proto__.subviews = {}; }, /** Show or hide the data rows associated with the event row science metadata - */ - toggleRows: function (event) { + * @param event + */ + toggleRows(event) { if (this.isOpen) { // Get the DataItemView associated with each id _.each( Object.keys(this.subviews), function (id) { - var subview = this.subviews[id]; + const subview = this.subviews[id]; if (subview.model.get("type") === "Data" && subview.remove) { // Remove the view from the DOM @@ -707,7 +716,7 @@

Source: src/js/views/DataPackageView.js

this.isOpen = false; } else { // Add sub rows to the view - var dataModels = this.dataPackage.where({ type: "Data" }); + const dataModels = this.dataPackage.where({ type: "Data" }); _.each( dataModels, function (model) { @@ -741,23 +750,23 @@

Source: src/js/views/DataPackageView.js

* @param {Event} e - The event object. * @since 2.28.0 */ - expand: function (e) { + expand(e) { // Don't do anything... e.preventDefault(); - var view = this; - var eventEl = $(e.target).parents("td"); - var rowEl = $(e.target).parents("tr"); + const view = this; + const eventEl = $(e.target).parents("td"); + const rowEl = $(e.target).parents("tr"); - var parentId = rowEl.data("id"); - var children = "tr[data-parent='" + parentId + "']"; + const parentId = rowEl.data("id"); + const children = `tr[data-parent='${parentId}']`; this.$(children).fadeIn(); this.$(eventEl) .children() .children(".expand-control") - .fadeOut(function () { + .fadeOut(() => { view .$(eventEl) .children() @@ -770,7 +779,7 @@

Source: src/js/views/DataPackageView.js

.children() .children() .children(".collapse-control") - .fadeOut(function () { + .fadeOut(() => { view .$(children) .children() @@ -783,25 +792,24 @@

Source: src/js/views/DataPackageView.js

/** * Collapse function to hide rows when a user clicks on a collapse control. * @param {Event} e - The event object. - * * @since 2.28.0 */ - collapse: function (e) { + collapse(e) { // Don't do anything... e.preventDefault(); - var view = this; - var eventEl = $(e.target).parents("td"); - var rowEl = $(e.target).parents("tr"); + const view = this; + const eventEl = $(e.target).parents("td"); + const rowEl = $(e.target).parents("tr"); - var parentId = rowEl.data("id"); - var children = "tr[data-parent^='" + parentId + "']"; + const parentId = rowEl.data("id"); + const children = `tr[data-parent^='${parentId}']`; this.$(children).fadeOut(); this.$(eventEl) .children() .children(".collapse-control") - .fadeOut(function () { + .fadeOut(() => { view.$(eventEl).children().children(".expand-control").fadeIn(); view.$(".tooltip-this").tooltip(); }); @@ -810,25 +818,24 @@

Source: src/js/views/DataPackageView.js

/** * Expand all function to show all child rows when a user clicks on an expand-all control. * @param {Event} e - The event object. - * * @since 2.28.0 */ - expandAll: function (e) { + expandAll(e) { // Don't do anything... e.preventDefault(); - var view = this; - var eventEl = $(e.target).parents("td"); - var rowEl = $(e.target).parents("tr"); + const view = this; + const eventEl = $(e.target).parents("td"); + const rowEl = $(e.target).parents("tr"); - var parentId = rowEl.data("id"); - var children = "tr[data-packageid='" + parentId + "']"; + const parentId = rowEl.data("id"); + const children = `tr[data-packageid='${parentId}']`; this.$(children).fadeIn(); this.$(eventEl) .children(".d1package-expand") - .fadeOut(function () { + .fadeOut(() => { view.$(eventEl).children(".d1package-collapse").fadeIn("fast"); view.$(".tooltip-this").tooltip(); }); @@ -837,7 +844,7 @@

Source: src/js/views/DataPackageView.js

.children() .children() .children(".collapse-control") - .fadeOut(function () { + .fadeOut(() => { view .$(children) .children() @@ -850,31 +857,30 @@

Source: src/js/views/DataPackageView.js

/** * Collapse all function to hide all child rows when a user clicks on a collapse-all control. * @param {Event} e - The event object. - * * @since 2.28.0 */ - collapseAll: function (e) { + collapseAll(e) { // Don't do anything... e.preventDefault(); - var view = this; - var eventEl = $(e.target).parents("td"); - var rowEl = $(e.target).parents("tr"); + const view = this; + const eventEl = $(e.target).parents("td"); + const rowEl = $(e.target).parents("tr"); - var parentId = rowEl.data("id"); - var children = "tr[data-packageid='" + parentId + "']"; + const parentId = rowEl.data("id"); + const children = `tr[data-packageid='${parentId}']`; this.$(children).each(function () { $(this).fadeOut(); - let childId = $(this).data("id"); - let grandchildren = "tr[data-parent^='" + childId + "']"; + const childId = $(this).data("id"); + const grandchildren = `tr[data-parent^='${childId}']`; $(grandchildren).fadeOut(); }); this.$(eventEl) .children(".d1package-collapse") - .fadeOut(function () { + .fadeOut(() => { view.$(eventEl).children(".d1package-expand").fadeIn(); view.$(".tooltip-this").tooltip(); }); @@ -882,27 +888,26 @@

Source: src/js/views/DataPackageView.js

/** * Check for private members and disable download buttons if necessary. - * * @since 2.28.0 */ - checkForPrivateMembers: function () { + checkForPrivateMembers() { try { - var packageModel = this.model, - packageCollection = this.dataPackage; + const packageModel = this.model; + const packageCollection = this.dataPackage; if (!packageModel || !packageCollection) { return; } - var numMembersFromSolr = packageModel.get("members").length, - numMembersFromRDF = packageCollection.length; + const numMembersFromSolr = packageModel.get("members").length; + const numMembersFromRDF = packageCollection.length; if (numMembersFromRDF > numMembersFromSolr) { - var downloadButtons = this.$(".btn.download"); + const downloadButtons = this.$(".btn.download"); - for (var i = 0; i < downloadButtons.length; i++) { - var btn = downloadButtons[i]; - var downloadURL = $(btn).attr("href"); + for (let i = 0; i < downloadButtons.length; i++) { + const btn = downloadButtons[i]; + const downloadURL = $(btn).attr("href"); if ( downloadURL.indexOf(packageModel.get("id")) > -1 || @@ -933,24 +938,23 @@

Source: src/js/views/DataPackageView.js

/** * Retrieves and processes nested packages for the current package. - * * @since 2.28.0 */ - getNestedPackages: function () { - var nestedPackages = new Array(); - var nestedPackageIds = new Array(); + getNestedPackages() { + const nestedPackages = new Array(); + const nestedPackageIds = new Array(); this.nestedPackages = nestedPackages; // get all the child packages for this resource map - var childPackages = this.dataPackage.filter(function (m) { - return m.get("formatType") === "RESOURCE"; - }); + const childPackages = this.dataPackage.filter( + (m) => m.get("formatType") === "RESOURCE", + ); // iterate over the list of child packages and add their members - for (var ite in childPackages) { - var childPkg = childPackages[ite]; + for (const ite in childPackages) { + const childPkg = childPackages[ite]; if (!nestedPackageIds.includes(childPkg.get("id"))) { - var nestedPackage = new PackageModel(); + const nestedPackage = new PackageModel(); nestedPackage.set("id", childPkg.get("id")); nestedPackage.setURL(); nestedPackage.getMembers(); @@ -969,64 +973,63 @@

Source: src/js/views/DataPackageView.js

/** * Adds a nested data package to the package table. - * - * @param {Object} dataPackage - The data package to be added. + * @param {object} dataPackage - The data package to be added. * @since 2.28.0 */ - addNestedPackages: function (dataPackage) { + addNestedPackages(dataPackage) { /** * Generates the table row for the data package header. - * * @type {null|Element} */ - var tableRow = null, - /** - * Reference to the current view. - * - * @type {Object} - */ - view = this, - /** - * The title of the data package. - * - * @type {null|string} - */ - title = null, - /** - * The URL of the data package. - * - * @type {null|string} - */ - packageUrl = null; + let tableRow = null; + /** + * Reference to the current view. + * @type {object} + */ + var view = this; + /** + * The title of the data package. + * @type {null|string} + */ + let title = null; + /** + * The URL of the data package. + * @type {null|string} + */ + let packageUrl = null; + /** + * The URL of the nested data package. + * @type {null|string} + */ + let nestedPackageUrl = null; /** * The members of the data package. - * * @type {Array} */ - var members = dataPackage.get("members"); + let members = dataPackage.get("members"); /** * Filters out metadata objects from the members. - * * @type {Array} */ - let metadataObj = _.filter(members, function (m) { - return m.get("type") == "Metadata" || m.get("type") == "metadata"; - }); + const metadataObj = _.filter( + members, + (m) => m.get("type") == "Metadata" || m.get("type") == "metadata", + ); title = metadataObj[0].get("title"); /** * The tooltip for the title (used for long titles). - * * @type {string} */ - let titleTooltip = title; + const titleTooltip = title; title = title.length > 150 - ? title.slice(0, 75) + - "..." + - title.slice(title.length - 75, title.length) + ? `${title.slice(0, 75)}...${title.slice( + title.length - 75, + title.length, + )}` : title; // Set the package URL @@ -1035,17 +1038,22 @@

Source: src/js/views/DataPackageView.js

MetacatUI.appModel.get("packageServiceUrl") + encodeURIComponent(dataPackage.id); + // Set the nested package URL + if (MetacatUI.root !== undefined && dataPackage.id !== undefined) + nestedPackageUrl = `${MetacatUI.root}/view/${encodeURIComponent(dataPackage.id)}`; + /** * The HTML content for the data package header. - * * @type {string} */ tableRow = this.dataPackageHeaderTemplate({ id: dataPackage.id, - title: title, - titleTooltip: titleTooltip, + title, + titleTooltip, disablePackageDownloads: false, downloadUrl: packageUrl, + disablePackageUrl: false, + packageUrl: nestedPackageUrl, }); this.$el.append(tableRow); @@ -1060,25 +1068,25 @@

Source: src/js/views/DataPackageView.js

this.downloadButtonView.render(); // Add the downloadButtonView el to the span - this.$el.find(".downloadAction").html(this.downloadButtonView.el); + this.$el + .find(`.downloadAction[data-id='${dataPackage.id}']`) + .html(this.downloadButtonView.el); // Filter out the packages from the member list - members = _.filter(members, function (m) { - return m.type != "Package"; - }); + members = _.filter(members, (m) => m.type != "Package"); // Add each member to the package table view var view = this; - _.each(members, function (m) { + _.each(members, (m) => { // Update the size to bytes format - m.set({ size: m.bytesToSize(m.get("size")) }); + m.set({ size: Utilities.bytesToSize(m.get("size")) }); // Add each item of this nested package to the package table view view.addOne(m, dataPackage); }); }, - /*showDownloadProgress: function(e){ + /* showDownloadProgress: function(e){ e.preventDefault(); var button = $(e.target); @@ -1087,7 +1095,7 @@

Source: src/js/views/DataPackageView.js

return true; - }*/ + } */ }, ); return DataPackageView; diff --git a/docs/docs/src_js_views_DraftsView.js.html b/docs/docs/src_js_views_DraftsView.js.html index 0de2c3645..c9b3ec481 100644 --- a/docs/docs/src_js_views_DraftsView.js.html +++ b/docs/docs/src_js_views_DraftsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_EditCollectionView.js.html b/docs/docs/src_js_views_EditCollectionView.js.html index f67d39d97..2a4580a2a 100644 --- a/docs/docs/src_js_views_EditCollectionView.js.html +++ b/docs/docs/src_js_views_EditCollectionView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_EditorView.js.html b/docs/docs/src_js_views_EditorView.js.html index 34c183c3c..2987ce2d9 100644 --- a/docs/docs/src_js_views_EditorView.js.html +++ b/docs/docs/src_js_views_EditorView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_FooterView.js.html b/docs/docs/src_js_views_FooterView.js.html index abe064587..4e8c44af3 100644 --- a/docs/docs/src_js_views_FooterView.js.html +++ b/docs/docs/src_js_views_FooterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_GroupListView.js.html b/docs/docs/src_js_views_GroupListView.js.html index 515db65c6..421198595 100644 --- a/docs/docs/src_js_views_GroupListView.js.html +++ b/docs/docs/src_js_views_GroupListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_ImageUploaderView.js.html b/docs/docs/src_js_views_ImageUploaderView.js.html index 02f5bc98a..f01705f62 100644 --- a/docs/docs/src_js_views_ImageUploaderView.js.html +++ b/docs/docs/src_js_views_ImageUploaderView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_MarkdownEditorView.js.html b/docs/docs/src_js_views_MarkdownEditorView.js.html index f143d9ac2..320ea2a77 100644 --- a/docs/docs/src_js_views_MarkdownEditorView.js.html +++ b/docs/docs/src_js_views_MarkdownEditorView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_MarkdownView.js.html b/docs/docs/src_js_views_MarkdownView.js.html index 141bff1bb..a127f5c39 100644 --- a/docs/docs/src_js_views_MarkdownView.js.html +++ b/docs/docs/src_js_views_MarkdownView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_MdqRunView.js.html b/docs/docs/src_js_views_MdqRunView.js.html index 3ec76b08f..d3e8d0977 100644 --- a/docs/docs/src_js_views_MdqRunView.js.html +++ b/docs/docs/src_js_views_MdqRunView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -44,7 +44,9 @@

Source: src/js/views/MdqRunView.js

-
define([
+            
"use strict";
+
+define([
   "jquery",
   "underscore",
   "backbone",
@@ -53,10 +55,10 @@ 

Source: src/js/views/MdqRunView.js

"DonutChart", "views/CitationView", "text!templates/mdqRun.html", - "text!templates/mdqSuites.html", "text!templates/loading-metrics.html", "collections/QualityReport", -], function ( + "views/MarkdownView", +], ( $, _, Backbone, @@ -65,42 +67,73 @@

Source: src/js/views/MdqRunView.js

DonutChart, CitationView, MdqRunTemplate, - SuitesTemplate, LoadingTemplate, QualityReport, -) { - "use strict"; + MarkdownView, +) => { + const MSG_ERROR_GENERATING_REPORT = + "There was an error generating the assessment report."; + const MSG_QUEUED_REPORT = + "The assessment report is in the Assessment Server queue to be generated."; + const MSG_REPORT_NOT_READY = + "The assessment report for this dataset is not ready yet. Try checking back in 24 hours to see these results."; + const MSG_ERROR_GENERAL = + "There was an error retrieving the assessment report for this dataset."; + const MSG_ERROR_DETAILS = "The Assessment Server reported this error: "; + const QUEUE_ERROR_DETAILS = " It was queued at: "; /** * @class MdqRunView * @classdesc A view that fetches and displays a Metadata Assessment Report * @classcategory Views * @name MdqRunView - * @extends Backbone.View + * @augments Backbone.View * @constructs */ - var MdqRunView = Backbone.View.extend( + const MdqRunView = Backbone.View.extend( /** @lends MdqRunView.prototype */ { + /** @inheritdoc */ el: "#Content", + /** @inheritdoc */ events: { "change #suiteId": "switchSuite", }, - url: null, + /** + * The identifier of the object to be assessed + * @type {string} + */ pid: null, + /** * The currently selected/requested suite * @type {string} */ suiteId: null, + /** * The list of all potential suites for this theme * @type {string[]} */ suiteIdList: [], + + /** + * The template to use to indicate that the view is loading + * @type {Function} + */ loadingTemplate: _.template(LoadingTemplate), + + /** + * The main template for this view + * @type {Function} + */ template: _.template(MdqRunTemplate), + + /** + * The selector for the element that will contain the breadcrumbs + * @type {string} + */ breadcrumbContainer: "#breadcrumb-container", /** @@ -111,13 +144,16 @@

Source: src/js/views/MdqRunView.js

*/ loadingContainer: "#mdqResult", - initialize: function () {}, - - switchSuite: function (event) { - var select = $(event.target); - var suiteId = $(select).val(); + /** + * Handles the event when the user selects a different suite + * @param {Event} event The event object + * @returns {boolean} False, to prevent the default action + */ + switchSuite(event) { + const select = $(event.target); + const suiteId = $(select).val(); MetacatUI.uiRouter.navigate( - "quality/s=" + suiteId + "/" + encodeURIComponent(this.pid), + `quality/s=${suiteId}/${encodeURIComponent(this.pid)}`, { trigger: false }, ); this.suiteId = suiteId; @@ -125,20 +161,20 @@

Source: src/js/views/MdqRunView.js

return false; }, - render: function () { - var viewRef = this; + /** @inheritdoc */ + render() { + const viewRef = this; // The suite use for rendering can initially be set via the theme AppModel. // If a suite id is request via the metacatui route, then we have to display that // suite, and in addition have to display all possible suites for this theme in // a selection list, if the user wants to view a different one. + this.suiteIdList = MetacatUI.appModel.get("mdqSuiteIds"); if (!this.suiteId) { - this.suiteId = MetacatUI.appModel.get("mdqSuiteIds")[0]; + this.suiteId = this.suiteIdList?.[0]; } - this.suiteIdList = MetacatUI.appModel.get("mdqSuiteIds"); this.suiteLabels = MetacatUI.appModel.get("mdqSuiteLabels"); - //this.url = this.mdqRunsServiceUrl + "/" + this.suiteId + "/" + this.pid; // Insert the basic template this.$el.html(this.template({})); @@ -148,217 +184,367 @@

Source: src/js/views/MdqRunView.js

this.showLoading(); if (!this.pid) { - var searchLink = $(document.createElement("a")) - .attr("href", MetacatUI.root + "/data") + const searchLink = $(document.createElement("a")) + .attr("href", `${MetacatUI.root}/data`) .text("Search our database"); - var message = $(document.createElement("span")) + const message = $(document.createElement("span")) .text(" to see an assessment report for a dataset") .prepend(searchLink); this.showMessage(message, true, false); return; } - // Fetch a quality report from the quality server and display it. - var qualityUrl = - MetacatUI.appModel.get("mdqRunsServiceUrl") + - viewRef.suiteId + - "/" + - viewRef.pid; - var qualityReport = new QualityReport([], { + const root = MetacatUI.appModel.get("mdqRunsServiceUrl"); + + const qualityUrl = `${root}${viewRef.suiteId}/${viewRef.pid}`; + const qualityReport = new QualityReport([], { url: qualityUrl, pid: viewRef.pid, }); + this.qualityReport = qualityReport; + + this.listenToOnce( + qualityReport, + "fetchError", + this.handleQualityReportError, + ); + this.listenToOnce( + qualityReport, + "fetchComplete", + this.renderQualityReport, + ); + qualityReport.fetch({ url: qualityUrl }); + }, - this.listenToOnce(qualityReport, "fetchError", function () { - // Inspect the results to see if a quality report was returned. - // If not, then submit a request to the quality engine to create the - // quality report for this pid/suiteId, and inform the user of this. - var msgText; - console.log("Error status: " + qualityReport.fetchResponse.status); - if (qualityReport.fetchResponse.status == 404) { - msgText = - "The assessment report for this dataset is not ready yet. Try checking back in 24 hours to see these results."; - } else { - msgText = - "There was an error retrieving the assessment report for this dataset."; - if ( - typeof qualityReport.fetchResponse.statusText !== "undefined" && - typeof qualityReport.fetchResponse.status !== "undefined" - ) { - if (qualityReport.fetchResponse.status != 0) - msgText += - "Error details: " + qualityReport.fetchResponse.statusText; + /** + * Render the quality report once it has been fetched + */ + async renderQualityReport() { + const viewRef = this; + const { qualityReport } = this; + if (qualityReport?.runStatus?.toUpperCase() !== "SUCCESS") { + this.handleQualityReportError(); + return; + } + viewRef.hideLoading(); + + // Filter out the checks with level 'METADATA', as these checks are intended + // to pass info to metadig-engine indexing (for search, faceting), and not intended for display. + qualityReport.reset( + _.reject(qualityReport.models, (model) => { + const check = model.get("check"); + if (check.level === "METADATA") { + return true; } + return false; + }), + ); + + const groupedResults = qualityReport.groupResults(qualityReport.models); + const groupedByType = qualityReport.groupByType(qualityReport.models); + + const checkCount = qualityReport.length; + const blueCount = groupedResults.BLUE?.length || 0; + const greenCount = groupedResults.GREEN?.length || 0; + const orangeCount = groupedResults.ORANGE?.length || 0; + const redCount = groupedResults.RED?.length || 0; + const extraRedText = + redCount > 0 ? " Please correct these issues." : ""; + const extraOrangeText = + orangeCount > 0 ? " Please review these warnings." : ""; + const totalPassable = checkCount - blueCount; + + const checkWord = (num) => (num === 1 ? "check" : "checks"); + const greenText = `Passed ${greenCount} ${checkWord(greenCount)} out of ${totalPassable} (excluding informational checks).`; + const orangeText = `Warning for ${orangeCount} ${checkWord(orangeCount)}. ${extraOrangeText}`; + const redText = `Failed ${redCount} ${checkWord(redCount)}. ${extraRedText}`; + const blueText = `${blueCount} informational ${checkWord(blueCount)}.`; + + const data = { + objectIdentifier: qualityReport.id, + suiteId: viewRef.suiteId, + suiteIdList: viewRef.suiteIdList, + suiteLabels: viewRef.suiteLabels, + timestamp: _.now(), + id: viewRef.pid, + groupedResults, + groupedByType, + checkCount, + greenText, + orangeText, + redText, + blueText, + }; + + viewRef.$el.html(viewRef.template(data)); + await viewRef.addCheckItems(groupedResults); + viewRef.insertBreadcrumbs(); + viewRef.drawScoreChart(qualityReport.models, groupedResults); + viewRef.showCitation(); + viewRef.show(); + // Make sure the DOM is updated before initializing the popover + requestAnimationFrame(() => { + viewRef.$(".popover-this").popover(); + }); + }, + + /** + * Add the check result item els to the view + * @param {object} groupedResults - The results grouped by status + * @since 2.31.0 + */ + async addCheckItems(groupedResults) { + const viewRef = this; + + const types = { + GREEN: { + className: "pass", + iconClass: "icon-check-sign success", + headerClass: "success", + }, + ORANGE: { + className: "warn", + iconClass: "icon-exclamation", + headerClass: "warning", + }, + RED: { + className: "fail", + iconClass: "icon-remove", + headerClass: "danger", + }, + BLUE: { + className: "info-check", + iconClass: "icon-info", + headerClass: "info", + }, + }; + + Object.keys(types).forEach(async (type) => { + const { className, iconClass, headerClass } = types[type]; + const results = groupedResults[type]; + if (results) { + // Use `map` to handle promises + const itemEls = await Promise.all( + results.map(async (result) => + viewRef.createCheckItem(result, className, iconClass), + ), + ); + + // Join the resolved HTML strings and append them + viewRef + .$(`.list-group-item.${headerClass}`) + .after(itemEls.join("")); } - this.showMessage(msgText); - }), - this.listenToOnce(qualityReport, "fetchComplete", function () { - var msgText; - if (qualityReport.runStatus != "success") { - if (qualityReport.runStatus == "failure") { - msgText = - "There was an error generating the assessment report. The Assessment Server reported this error: " + - qualityReport.errorDescription; - } else if (qualityReport.runStatus == "queued") { - msgText = - "The assessment report is in the Assessment Server queue to be generated. It was queued at: " + - qualityReport.timestamp; - } else { - msgText = - "There was an error retrieving the assessment report."; - } - this.showMessage(msgText); - return; - } else { - viewRef.hideLoading(); + }); + }, + + /** + * Create a check item element + * @param {object} result - The check result + * @param {string} className - The class name for the check item + * @param {string} iconClass - The class + * @returns {string} The HTML for the check item + * @since 2.31.0 + */ + async createCheckItem(result, className, iconClass) { + const outputs = await this.getOutputHTML(result.get("output")); + + return ` + <li class="list-group-item check ${className} collapse row-fluid"> + <span class="icon-stack span1"> + <i class="${iconClass}"></i> + </span> + <span class="span6">${outputs}</span> + <span class="span1"> + <a tabindex="0" + role="button" + class="popover-this" + data-container="body" + data-trigger="hover focus" + data-html="true" + data-title="${result.get("check").name}" + data-content="${result.get("check").description}"> + <i class="icon icon-question-sign subtle"></i> + </a> + </span> + <span class="span4"> + <span class="badge pull-right">${result.get("status")}</span> + <span class="badge pull-right">${result.get("check").level}</span> + <span class="badge pull-right">${result.get("check").type}</span> + </span> + </li> + `; + }, + + /** + * Get the HTML for the output + * @param {Array} outputs - The outputs from the quality service + * @returns {string} The HTML for the output + */ + async getOutputHTML(outputs) { + const outputHTMLs = await Promise.all( + outputs.map(async (output) => { + if (output?.type?.includes("image")) { + return `<img src="data:${output.type};base64,${output.value}" />`; + } + if (output.type === "markdown") { + return this.getHTMLFromMarkdown(output.value); } + return `<div class="check-output">${output.value}</div>`; + }), + ); - // Filter out the checks with level 'METADATA', as these checks are intended - // to pass info to metadig-engine indexing (for search, faceting), and not intended for display. - qualityReport.reset( - _.reject(qualityReport.models, function (model) { - var check = model.get("check"); - if (check.level == "METADATA") { - return true; - } else { - return false; - } - }), - ); + return outputHTMLs.join(""); + }, - var groupedResults = qualityReport.groupResults( - qualityReport.models, - ); - var groupedByType = qualityReport.groupByType(qualityReport.models); - - var data = { - objectIdentifier: qualityReport.id, - suiteId: viewRef.suiteId, - suiteIdList: viewRef.suiteIdList, - suiteLabels: viewRef.suiteLabels, - groupedResults: groupedResults, - groupedByType: groupedByType, - timestamp: _.now(), - id: viewRef.pid, - checkCount: qualityReport.length, - }; - - viewRef.$el.html(viewRef.template(data)); - viewRef.insertBreadcrumbs(); - viewRef.drawScoreChart(qualityReport.models, groupedResults); - viewRef.showCitation(); - viewRef.show(); - viewRef.$(".popover-this").popover(); + /** + * Get the HTML from markdown + * @param {string} markdown - The markdown to convert to HTML + * @returns {Promise} A promise that resolves with the HTML + */ + getHTMLFromMarkdown(markdown) { + const markdownView = new MarkdownView({ + markdown, + showTOC: false, + }).render(); + + return new Promise((resolve) => { + this.listenToOnce(markdownView, "mdRendered", () => { + resolve(markdownView.el.innerHTML); }); + }); + }, + + /** + * Handles errors that occur when fetching the quality report + */ + handleQualityReportError() { + const { qualityReport } = this; + let status = + qualityReport.runStatus || qualityReport.fetchResponse?.status; + + if (typeof status === "string") { + status = status.toUpperCase(); + } + + const description = + qualityReport.errorDescription || + qualityReport.fetchResponse?.statusText || + ""; + const time = qualityReport.timestamp; + + const errorReport = description + ? `${MSG_ERROR_DETAILS}${description}` + : ""; + const queueTime = time ? `${QUEUE_ERROR_DETAILS} ${time}` : ""; + + let msgText = ""; + + if (status === "FAILURE") { + msgText = `${MSG_ERROR_GENERATING_REPORT}`; + if (errorReport) { + msgText += ` ${errorReport}`; + } + } else if (status === "QUEUED" || status === "PROCESSING") { + msgText = `${MSG_QUEUED_REPORT} `; + if (queueTime) { + msgText += ` ${queueTime}`; + } + } else if (status === 404) { + msgText = MSG_REPORT_NOT_READY; + } else { + msgText = MSG_ERROR_GENERAL; + if (errorReport) { + msgText += ` ${errorReport}`; + } + } + this.showMessage(msgText); }, /** * Updates the message in the loading image * @param {string} message The new message to display - * @param {boolean} [showHelp=true] If set to true, and an email contact is configured + * @param {boolean} [showHelp] If set to true, and an email contact is configured * in MetacatUI, then the contact email will be shown at the bottom of the message. - * @param {boolean} [showLink=true] If set to true, a link back to the dataset will be + * @param {boolean} [showLink] If set to true, a link back to the dataset will be * appended to the end of the message. * @since 2.15.0 */ - showMessage: function (message, showHelp = true, showLink = true) { - try { - var view = this; - var messageEl = this.loadingEl.find(".message"); + showMessage(message, showHelp = true, showLink = true) { + const view = this; + const messageEl = this.loadingEl.find(".message"); - if (!messageEl) { - return; - } + if (!messageEl) { + return; + } - // Update the message - messageEl.html(message); + // Update the message + messageEl.html(message); - // Create a link back to the data set - if (showLink) { - var viewURL = "/view/" + encodeURIComponent(this.pid); - var backLink = $(document.createElement("a")).text( - " Return to the dataset", - ); - backLink.on("click", function () { - view.hideLoading(); - MetacatUI.uiRouter.navigate(viewURL, { - trigger: true, - replace: true, - }); + // Create a link back to the data set + if (showLink) { + const viewURL = `/view/${encodeURIComponent(this.pid)}`; + const backLink = $(document.createElement("a")).text( + " Return to the dataset", + ); + backLink.on("click", () => { + view.hideLoading(); + MetacatUI.uiRouter.navigate(viewURL, { + trigger: true, + replace: true, }); - messageEl.append(backLink); - } + }); + messageEl.append(backLink); + } - // Show how the user can get more help - if (showHelp) { - var emailAddress = MetacatUI.appModel.get("emailContact"); - // Don't show help if there's no contact email configured - if (emailAddress) { - var helpEl = $( - "<p class='webmaster-email' style='margin-top:20px'>" + - "<i class='icon-envelope-alt icon icon-on-left'></i>" + - "Need help? Email us at </p>", - ); - var emailLink = $(document.createElement("a")) - .attr("href", "mailto:" + emailAddress) - .text(emailAddress); - helpEl.append(emailLink); - messageEl.append(helpEl); - } + // Show how the user can get more help + if (showHelp) { + const emailAddress = MetacatUI.appModel.get("emailContact"); + // Don't show help if there's no contact email configured + if (emailAddress) { + const helpEl = $( + "<p class='webmaster-email' style='margin-top:20px'>" + + "<i class='icon-envelope-alt icon icon-on-left'></i>" + + "Need help? Email us at </p>", + ); + const emailLink = $(document.createElement("a")) + .attr("href", `mailto:${emailAddress}`) + .text(emailAddress); + helpEl.append(emailLink); + messageEl.append(helpEl); } - } catch (error) { - console.log( - "There was an error showing a message in a MdqRunView" + - ". Error details: " + - error, - ); } }, /** * Render a loading image with message */ - showLoading: function () { - try { - var loadingEl = this.loadingTemplate({ - message: "Retrieving assessment report...", - character: "none", - type: "barchart", - }); - this.loadingEl = $(loadingEl); - this.$el.find(this.loadingContainer).html(this.loadingEl); - } catch (error) { - console.log( - "There was an error showing the loading image in a MdqRunView" + - ". Error details: " + - error, - ); - } + showLoading() { + const loadingEl = this.loadingTemplate({ + message: "Retrieving assessment report...", + character: "none", + type: "barchart", + }); + this.loadingEl = $(loadingEl); + this.$el.find(this.loadingContainer).html(this.loadingEl); }, /** * Remove the loading image and message. */ - hideLoading: function () { - try { - this.loadingEl.remove(); - } catch (error) { - console.log( - "There was an error hiding a loading image in a MdqRunView" + - ". Error details: " + - error, - ); - } + hideLoading() { + this.loadingEl.remove(); }, - showCitation: function () { - var solrResultModel = new SolrResult({ + /** Render a citation view for the object and display it in the view */ + showCitation() { + const solrResultModel = new SolrResult({ id: this.pid, }); - this.listenTo(solrResultModel, "sync", function () { - var citationView = new CitationView({ + this.listenTo(solrResultModel, "sync", () => { + const citationView = new CitationView({ model: solrResultModel, createLink: false, createTitleLink: true, @@ -371,15 +557,20 @@

Source: src/js/views/MdqRunView.js

solrResultModel.getInfo(); }, - show: function () { - var view = this; + /** Show the view */ + show() { this.$el.hide(); this.$el.fadeIn({ duration: "slow" }); }, - drawScoreChart: function (results, groupedResults) { - var dataCount = results.length; - var data = [ + /** + * Draw a donut chart showing the distribution of checks by status + * @param {Array} results - The array of check results + * @param {object} groupedResults - The results grouped by status + */ + drawScoreChart(results, groupedResults) { + const dataCount = results.length; + const data = [ { label: "Pass", count: groupedResults.GREEN.length, @@ -402,95 +593,53 @@

Source: src/js/views/MdqRunView.js

}, ]; - var svgClass = "data"; + const svgClass = "data"; - //If d3 isn't supported in this browser or didn't load correctly, insert a text title instead + // If d3 isn't supported in this browser or didn't load correctly, insert a text title instead if (!d3) { this.$(".format-charts-data").html( - "<h2 class='" + - svgClass + - " fallback'>" + - MetacatUI.appView.commaSeparateNumber(dataCount) + - " data files</h2>", + `<h2 class='${svgClass} fallback'>${MetacatUI.appView.commaSeparateNumber( + dataCount, + )} data files</h2>`, ); return; } - //Draw a donut chart - var donut = new DonutChart({ + // Draw a donut chart + const donut = new DonutChart({ id: "data-chart", - data: data, + data, total: dataCount, titleText: "checks", titleCount: dataCount, - svgClass: svgClass, + svgClass, countClass: "data", height: 250, width: 250, keepOrder: true, - formatLabel: function (name) { + formatLabel(name) { return name; }, }); this.$(".format-charts-data").html(donut.render().el); }, - insertBreadcrumbs: function () { - var breadcrumbs = $(document.createElement("ol")) - .addClass("breadcrumb") - .append( - $(document.createElement("li")) - .addClass("home") - .append( - $(document.createElement("a")) - .attr("href", MetacatUI.root ? MetacatUI.root : "/") - .addClass("home") - .text("Home"), - ), - ) - .append( - $(document.createElement("li")) - .addClass("search") - .append( - $(document.createElement("a")) - .attr( - "href", - MetacatUI.root + - "/data" + - (MetacatUI.appModel.get("page") > 0 - ? "/page/" + - (parseInt(MetacatUI.appModel.get("page")) + 1) - : ""), - ) - .addClass("search") - .text("Search"), - ), - ) - .append( - $(document.createElement("li")).append( - $(document.createElement("a")) - .attr( - "href", - MetacatUI.root + "/view/" + encodeURIComponent(this.pid), - ) - .addClass("inactive") - .text("Metadata"), - ), - ) - .append( - $(document.createElement("li")).append( - $(document.createElement("a")) - .attr( - "href", - MetacatUI.root + "/quality/" + encodeURIComponent(this.pid), - ) - .addClass("inactive") - .text("Assessment Report"), - ), - ); - - this.$(this.breadcrumbContainer).html(breadcrumbs); + /** + * Insert breadcrumbs into the view + */ + insertBreadcrumbs() { + const encodedPid = encodeURIComponent(this.pid); + const root = MetacatUI.root || "/"; + const breadcrumbs = ` + <ol class="breadcrumb"> + <li class="home"><a href="${root || "/"}" class="home">Home</a></li> + <li class="search"><a href="${root}/data" class="search">Search</a></li> + <li class="inactive"><a href="${root}/view/${encodedPid}" class="inactive">Metadata</a></li> + <li class="inactive"><a href="${root}/quality/${encodedPid}" class="inactive">Assessment Report</a></li> + </ol> + `; + this.el.querySelector(this.breadcrumbContainer).innerHTML = breadcrumbs; }, }, ); diff --git a/docs/docs/src_js_views_MetadataView.js.html b/docs/docs/src_js_views_MetadataView.js.html index 6de3f6227..a4cece9c9 100644 --- a/docs/docs/src_js_views_MetadataView.js.html +++ b/docs/docs/src_js_views_MetadataView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -84,7 +84,7 @@

Source: src/js/views/MetadataView.js

"text!templates/metaTagsHighwirePress.html", "uuid", "views/MetricView", -], function ( +], ( $, $ui, _, @@ -124,18 +124,18 @@

Source: src/js/views/MetadataView.js

metaTagsHighwirePressTemplate, uuid, MetricView, -) { +) => { "use strict"; /** * @class MetadataView * @classdesc A human-readable view of a science metadata file * @classcategory Views - * @extends Backbone.View - * @constructor + * @augments Backbone.View + * @class * @screenshot views/MetadataView.png */ - var MetadataView = Backbone.View.extend( + const MetadataView = Backbone.View.extend( /** @lends MetadataView.prototype */ { subviews: [], @@ -162,7 +162,7 @@

Source: src/js/views/MetadataView.js

type: "Metadata", - //Templates + // Templates template: _.template(MetadataTemplate), alertTemplate: _.template(AlertTemplate), doiTemplate: _.template(PublishDoiTemplate), @@ -202,7 +202,7 @@

Source: src/js/views/MetadataView.js

"click #save-metadata-prov": "saveProv", }, - initialize: function (options) { + initialize(options) { if (options === undefined || !options) var options = {}; this.pid = @@ -214,13 +214,13 @@

Source: src/js/views/MetadataView.js

}, // Render the main metadata view - render: function () { + render() { this.stopListening(); MetacatUI.appModel.set("headerType", "default"); // this.showLoading("Loading..."); - //Reset various properties of this view first + // Reset various properties of this view first this.classMap = new Array(); this.subviews = new Array(); this.model.set(this.model.defaults); @@ -231,18 +231,18 @@

Source: src/js/views/MetadataView.js

this.listenTo(MetacatUI.appUserModel, "change:loggedIn", this.render); - //Listen to when the metadata has been rendered + // Listen to when the metadata has been rendered this.once("metadataLoaded", function () { this.createAnnotationViews(); this.insertMarkdownViews(); }); - //Listen to when the package table has been rendered + // Listen to when the package table has been rendered this.once("dataPackageRendered", function () { - var packageTableContainer = this.$("#data-package-container"); + const packageTableContainer = this.$("#data-package-container"); $(packageTableContainer).children(".loading").remove(); - //Scroll to the element on the page that is in the hash fragment (if there is one) + // Scroll to the element on the page that is in the hash fragment (if there is one) this.scrollToFragment(); }); @@ -257,11 +257,11 @@

Source: src/js/views/MetadataView.js

* table view, if there is one. * @param {string} pid - The PID of the resource map */ - getDataPackage: function (pid) { - //Create a DataONEObject model to use in the DataPackage collection. - var dataOneObject = new ScienceMetadata({ id: this.model.get("id") }); + getDataPackage(pid) { + // Create a DataONEObject model to use in the DataPackage collection. + const dataOneObject = new ScienceMetadata({ id: this.model.get("id") }); - var view = this; + const view = this; // Create a new data package with this id this.dataPackage = new DataPackage([dataOneObject], { id: pid }); @@ -281,7 +281,7 @@

Source: src/js/views/MetadataView.js

this.listenToOnce(this.dataPackage, "complete", function () { this.dataPackageSynced = true; this.trigger("changed:dataPackageSynced"); - var dataPackageView = _.findWhere(this.subviews, { + const dataPackageView = _.findWhere(this.subviews, { type: "DataPackage", }); if (dataPackageView) { @@ -290,16 +290,16 @@

Source: src/js/views/MetadataView.js

} }); - this.listenToOnce(this.dataPackage, "fetchFailed", function () { + this.listenToOnce(this.dataPackage, "fetchFailed", () => { view.dataPackageSynced = false; // stop listening to the fetch complete view.stopListening(view.dataPackage, "complete"); - //Remove the loading elements + // Remove the loading elements view.$(view.tableContainer).find(".loading").remove(); - //Show an error message + // Show an error message MetacatUI.appView.showAlert( "Error retrieving files for this data package.", "alert-error", @@ -327,15 +327,15 @@

Source: src/js/views/MetadataView.js

* Retrieves information from the index about this object, given the id (passed from the URL) * When the object info is retrieved from the index, we set up models depending on the type of object this is */ - getModel: function (pid) { - //Get the pid and sid - if (typeof pid === "undefined" || !pid) var pid = this.pid; + getModel(pid) { + // Get the pid and sid + if (typeof pid === "undefined" || !pid) var { pid } = this; if (typeof this.seriesId !== "undefined" && this.seriesId) var sid = this.seriesId; - //Get the package ID + // Get the package ID this.model.set({ id: pid, seriesId: sid }); - var model = this.model; + const { model } = this; this.listenToOnce(model, "sync", function () { if ( @@ -345,94 +345,89 @@

Source: src/js/views/MetadataView.js

this.model = model; this.renderMetadata(); } else if (this.model.get("formatType") == "DATA") { - //Get the metadata pids that document this data object - var isDocBy = this.model.get("isDocumentedBy"); + // Get the metadata pids that document this data object + const isDocBy = this.model.get("isDocumentedBy"); - //If there is only one metadata pid that documents this data object, then + // If there is only one metadata pid that documents this data object, then // get that metadata model for this view. if (isDocBy && isDocBy.length == 1) { this.navigateWithFragment(_.first(isDocBy), this.pid); return; } - //If more than one metadata doc documents this data object, it is most likely + // If more than one metadata doc documents this data object, it is most likely // multiple versions of the same metadata. So we need to find the latest version. - else if (isDocBy && isDocBy.length > 1) { - var view = this; - - require([ - "collections/Filters", - "collections/SolrResults", - ], function (Filters, SolrResults) { - //Create a search for the metadata docs that document this data object - var searchFilters = new Filters([ - { - values: isDocBy, - fields: ["id", "seriesId"], - operator: "OR", - fieldsOperator: "OR", - matchSubstring: false, - }, - ]), - //Create a list of search results - searchResults = new SolrResults([], { - rows: isDocBy.length, - query: searchFilters.getQuery(), - fields: "obsoletes,obsoletedBy,id", - }); + if (isDocBy && isDocBy.length > 1) { + const view = this; + + require(["collections/Filters", "collections/SolrResults"], ( + Filters, + SolrResults, + ) => { + // Create a search for the metadata docs that document this data object + const searchFilters = new Filters([ + { + values: isDocBy, + fields: ["id", "seriesId"], + operator: "OR", + fieldsOperator: "OR", + matchSubstring: false, + }, + ]); + // Create a list of search results + const searchResults = new SolrResults([], { + rows: isDocBy.length, + query: searchFilters.getQuery(), + fields: "obsoletes,obsoletedBy,id", + }); - //When the search results are returned, process those results - view.listenToOnce( - searchResults, - "sync", - function (searchResults) { - //Keep track of the latest version of the metadata doc(s) - var latestVersions = []; - - //Iterate over each search result and find the latest version of each metadata version chain - searchResults.each(function (searchResult) { - //If this metadata isn't obsoleted by another object, it is the latest version - if (!searchResult.get("obsoletedBy")) { - latestVersions.push(searchResult.get("id")); - } - //If it is obsoleted by another object but that newer object does not document this data, then this is the latest version - else if ( - !_.contains(isDocBy, searchResult.get("obsoletedBy")) - ) { - latestVersions.push(searchResult.get("id")); - } - }, view); - - //If at least one latest version was found (should always be the case), - if (latestVersions.length) { - //Set that metadata pid as this view's pid and get that metadata model. - // TODO: Support navigation to multiple metadata docs. This should be a rare occurence, but - // it is possible that more than one metadata version chain documents a data object, and we need - // to show the user that the data is involved in multiple datasets. - view.navigateWithFragment(latestVersions[0], view.pid); + // When the search results are returned, process those results + view.listenToOnce(searchResults, "sync", (searchResults) => { + // Keep track of the latest version of the metadata doc(s) + const latestVersions = []; + + // Iterate over each search result and find the latest version of each metadata version chain + searchResults.each((searchResult) => { + // If this metadata isn't obsoleted by another object, it is the latest version + if (!searchResult.get("obsoletedBy")) { + latestVersions.push(searchResult.get("id")); } - //If a latest version wasn't found, which should never happen, but just in case, default to the - // last metadata pid in the isDocumentedBy field (most liekly to be the most recent since it was indexed last). - else { - view.navigateWithFragment(_.last(isDocBy), view.pid); + // If it is obsoleted by another object but that newer object does not document this data, then this is the latest version + else if ( + !_.contains(isDocBy, searchResult.get("obsoletedBy")) + ) { + latestVersions.push(searchResult.get("id")); } - }, - ); + }, view); + + // If at least one latest version was found (should always be the case), + if (latestVersions.length) { + // Set that metadata pid as this view's pid and get that metadata model. + // TODO: Support navigation to multiple metadata docs. This should be a rare occurence, but + // it is possible that more than one metadata version chain documents a data object, and we need + // to show the user that the data is involved in multiple datasets. + view.navigateWithFragment(latestVersions[0], view.pid); + } + // If a latest version wasn't found, which should never happen, but just in case, default to the + // last metadata pid in the isDocumentedBy field (most liekly to be the most recent since it was indexed last). + else { + view.navigateWithFragment(_.last(isDocBy), view.pid); + } + }); - //Send the query to the Solr search service + // Send the query to the Solr search service searchResults.query(); }); return; - } else { - this.noMetadata(this.model); } + this.noMetadata(this.model); } else if (this.model.get("formatType") == "RESOURCE") { - var packageModel = new Package({ id: this.model.get("id") }); + const packageModel = new Package({ id: this.model.get("id") }); packageModel.on( "complete", function () { - var metadata = packageModel.getMetadata(); + const metadata = packageModel.getMetadata(); if (!metadata) { this.noMetadata(packageModel); @@ -450,23 +445,23 @@

Source: src/js/views/MetadataView.js

return; } - //Get the package information + // Get the package information this.getPackageDetails(model.get("resourceMap")); }); - //Listen to 404 and 401 errors when we get the metadata object + // Listen to 404 and 401 errors when we get the metadata object this.listenToOnce(model, "404", this.showNotFound); this.listenToOnce(model, "401", this.showIsPrivate); - //Fetch the model + // Fetch the model model.getInfo(); }, - renderMetadata: function () { - var pid = this.model.get("id"); + renderMetadata() { + const pid = this.model.get("id"); this.hideLoading(); - //Load the template which holds the basic structure of the view + // Load the template which holds the basic structure of the view this.$el.html(this.template()); this.$(this.tableContainer).html( this.loadingTemplate({ @@ -474,11 +469,11 @@

Source: src/js/views/MetadataView.js

}), ); - //Insert the breadcrumbs + // Insert the breadcrumbs this.insertBreadcrumbs(); - //Insert the citation + // Insert the citation this.insertCitation(); - //Insert the data source logo + // Insert the data source logo this.insertDataSource(); // is this the latest version? (includes DOI link when needed) this.showLatestVersion(); @@ -489,11 +484,11 @@

Source: src/js/views/MetadataView.js

// If we're displaying the metrics well then display copy citation and edit button // inside the well if (MetacatUI.appModel.get("displayDatasetMetrics")) { - //Insert Metrics Stats into the dataset landing pages + // Insert Metrics Stats into the dataset landing pages this.insertMetricsControls(); } - //Show loading icon in metadata section + // Show loading icon in metadata section this.$(this.metadataContainer).html( this.loadingTemplate({ msg: "Retrieving metadata ..." }), ); @@ -507,15 +502,15 @@

Source: src/js/views/MetadataView.js

MetacatUI.appModel.get("viewServiceUrl") + encodeURIComponent(pid); if (endpoint && typeof endpoint !== "undefined") { - var viewRef = this; - var loadSettings = { + const viewRef = this; + const loadSettings = { url: endpoint, - success: function (response, status, xhr) { + success(response, status, xhr) { try { - //If the user has navigated away from the MetadataView, then don't render anything further + // If the user has navigated away from the MetadataView, then don't render anything further if (MetacatUI.appView.currentView != viewRef) return; - //Our fallback is to show the metadata details from the Solr index + // Our fallback is to show the metadata details from the Solr index if ( status == "error" || !response || @@ -523,7 +518,7 @@

Source: src/js/views/MetadataView.js

) viewRef.renderMetadataFromIndex(); else { - //Check for a response that is a 200 OK status, but is an error msg + // Check for a response that is a 200 OK status, but is an error msg if ( response.length < 250 && response.indexOf("Error transforming document") > -1 && @@ -532,8 +527,8 @@

Source: src/js/views/MetadataView.js

viewRef.renderMetadataFromIndex(); return; } - //Mark this as a metadata doc with no stylesheet, or one that is at least different than usual EML and FGDC - else if (response.indexOf('id="Metadata"') == -1) { + // Mark this as a metadata doc with no stylesheet, or one that is at least different than usual EML and FGDC + if (response.indexOf('id="Metadata"') == -1) { viewRef.$el.addClass("container no-stylesheet"); if (viewRef.model.get("indexed")) { @@ -542,12 +537,15 @@

Source: src/js/views/MetadataView.js

} } - //Now show the response from the view service + // Now show the response from the view service viewRef.$(viewRef.metadataContainer).html(response); - viewRef.storeEntityPIDs(response); + _.each($(response).find(".entitydetails"), (entityEl) => { + const entityId = $(entityEl).data("id"); + viewRef.storeEntityPIDs(entityEl, entityId); + }); - //If there is no info from the index and there is no metadata doc rendered either, then display a message + // If there is no info from the index and there is no metadata doc rendered either, then display a message if ( viewRef.$el.is(".no-stylesheet") && viewRef.model.get("archived") && @@ -563,7 +561,7 @@

Source: src/js/views/MetadataView.js

viewRef.trigger("metadataLoaded"); - //Add a map of the spatial coverage + // Add a map of the spatial coverage if (gmaps) viewRef.insertSpatialCoverageMap(); // Injects Clipboard objects into DOM elements returned from the View Service @@ -578,7 +576,7 @@

Source: src/js/views/MetadataView.js

viewRef.renderMetadataFromIndex(); } }, - error: function (xhr, textStatus, errorThrown) { + error(xhr, textStatus, errorThrown) { viewRef.renderMetadataFromIndex(); }, }; @@ -590,7 +588,7 @@

Source: src/js/views/MetadataView.js

// Insert the Linked Data into the header of the page. if (MetacatUI.appModel.get("isJSONLDEnabled")) { - var json = this.generateJSONLD(); + const json = this.generateJSONLD(); this.insertJSONLD(json); } @@ -598,76 +596,76 @@

Source: src/js/views/MetadataView.js

}, /* If there is no view service available, then display the metadata fields from the index */ - renderMetadataFromIndex: function () { - var metadataFromIndex = new MetadataIndex({ + renderMetadataFromIndex() { + const metadataFromIndex = new MetadataIndex({ pid: this.pid, parentView: this, }); this.subviews.push(metadataFromIndex); - //Add the metadata HTML + // Add the metadata HTML this.$(this.metadataContainer).html(metadataFromIndex.render().el); - var view = this; + const view = this; - this.listenTo(metadataFromIndex, "complete", function () { - //Add the package contents + this.listenTo(metadataFromIndex, "complete", () => { + // Add the package contents view.insertPackageDetails(); - //Add a map of the spatial coverage + // Add a map of the spatial coverage if (gmaps) view.insertSpatialCoverageMap(); }); }, - removeCitation: function () { - var citation = "", - citationEl = null; + removeCitation() { + let citation = ""; + let citationEl = null; - //Find the citation element + // Find the citation element if (this.$(".citation").length > 0) { - //Get the text for the citation + // Get the text for the citation citation = this.$(".citation").text(); - //Save this element in the view + // Save this element in the view citationEl = this.$(".citation"); } - //Older versions of Metacat (v2.4.3 and older) will not have the citation class in the XSLT. Find the citation another way + // Older versions of Metacat (v2.4.3 and older) will not have the citation class in the XSLT. Find the citation another way else { - //Find the DOM element with the citation - var wells = this.$(".well"), - viewRef = this; + // Find the DOM element with the citation + const wells = this.$(".well"); + const viewRef = this; - //Find the div.well with the citation. If we never find it, we don't insert the list of contents - _.each(wells, function (well) { + // Find the div.well with the citation. If we never find it, we don't insert the list of contents + _.each(wells, (well) => { if ( (!citationEl && $(well).find("#viewMetadataCitationLink").length > 0) || $(well).children(".row-fluid > .span10 > a") ) { - //Save this element in the view + // Save this element in the view citationEl = well; - //Mark this in the DOM for CSS styling + // Mark this in the DOM for CSS styling $(well).addClass("citation"); - //Save the text of the citation + // Save the text of the citation citation = $(well).text(); } }); - //Remove the unnecessary classes that are used in older versions of Metacat (2.4.3 and older) - var citationText = $(citationEl).find(".span10"); + // Remove the unnecessary classes that are used in older versions of Metacat (2.4.3 and older) + const citationText = $(citationEl).find(".span10"); $(citationText).removeClass("span10").addClass("span12"); } - //Set the document title to the citation + // Set the document title to the citation MetacatUI.appModel.set("title", citation); citationEl.remove(); }, - insertBreadcrumbs: function () { - var breadcrumbs = $(document.createElement("ol")) + insertBreadcrumbs() { + const breadcrumbs = $(document.createElement("ol")) .addClass("breadcrumb") .append( $(document.createElement("li")) @@ -686,12 +684,13 @@

Source: src/js/views/MetadataView.js

$(document.createElement("a")) .attr( "href", - MetacatUI.root + - "/data" + - (MetacatUI.appModel.get("page") > 0 - ? "/page/" + - (parseInt(MetacatUI.appModel.get("page")) + 1) - : ""), + `${MetacatUI.root}/data${ + MetacatUI.appModel.get("page") > 0 + ? `/page/${ + parseInt(MetacatUI.appModel.get("page")) + 1 + }` + : "" + }`, ) .addClass("search") .text("Search"), @@ -702,7 +701,7 @@

Source: src/js/views/MetadataView.js

$(document.createElement("a")) .attr( "href", - MetacatUI.root + "/view/" + encodeURIComponent(this.pid), + `${MetacatUI.root}/view/${encodeURIComponent(this.pid)}`, ) .addClass("inactive") .text("Metadata"), @@ -714,11 +713,11 @@

Source: src/js/views/MetadataView.js

$(document.createElement("a")) .attr( "href", - MetacatUI.root + - "/data/page/" + - (MetacatUI.appModel.get("page") > 0 + `${MetacatUI.root}/data/page/${ + MetacatUI.appModel.get("page") > 0 ? parseInt(MetacatUI.appModel.get("page")) + 1 - : ""), + : "" + }`, ) .attr("title", "Back") .addClass("back") @@ -736,16 +735,16 @@

Source: src/js/views/MetadataView.js

/* * When the metadata object doesn't exist, display a message to the user */ - showNotFound: function () { - //If the model was found, exit this function + showNotFound() { + // If the model was found, exit this function if (!this.model.get("notFound")) { return; } try { - //Check if a query string was in the URL and if so, try removing it in the identifier + // Check if a query string was in the URL and if so, try removing it in the identifier if (this.model.get("id").match(/\?\S+\=\S+/g) && !this.findTries) { - let newID = this.model.get("id").replace(/\?\S+\=\S+/g, ""); + const newID = this.model.get("id").replace(/\?\S+\=\S+/g, ""); this.onClose(); this.model.set("id", newID); this.pid = newID; @@ -757,38 +756,38 @@

Source: src/js/views/MetadataView.js

console.warn("Caught error while determining query string", e); } - //Construct a message that shows this object doesn't exist - var msg = - "<h4>Nothing was found.</h4>" + - "<p id='metadata-view-not-found-message'>The dataset identifier '" + - Utilities.encodeHTML(this.model.get("id")) + - "' " + - "does not exist or it may have been removed. <a>Search for " + - "datasets that mention " + - Utilities.encodeHTML(this.model.get("id")) + - "</a></p>"; + // Construct a message that shows this object doesn't exist + const msg = + `<h4>Nothing was found.</h4>` + + `<p id='metadata-view-not-found-message'>The dataset identifier '${Utilities.encodeHTML( + this.model.get("id"), + )}' ` + + `does not exist or it may have been removed. <a>Search for ` + + `datasets that mention ${Utilities.encodeHTML( + this.model.get("id"), + )}</a></p>`; - //Remove the loading message + // Remove the loading message this.hideLoading(); - //Show the not found error message + // Show the not found error message this.showError(msg); - //Add the pid to the link href. Add via JS so it is Attribute-encoded to prevent XSS attacks + // Add the pid to the link href. Add via JS so it is Attribute-encoded to prevent XSS attacks this.$("#metadata-view-not-found-message a").attr( "href", - MetacatUI.root + - "/data/query=" + - encodeURIComponent(this.model.get("id")), + `${MetacatUI.root}/data/query=${encodeURIComponent( + this.model.get("id"), + )}`, ); }, /* * When the metadata object is private, display a message to the user */ - showIsPrivate: function () { - //If we haven't checked the logged-in status of the user yet, wait a bit - //until we show a 401 msg, in case this content is their private content + showIsPrivate() { + // If we haven't checked the logged-in status of the user yet, wait a bit + // until we show a 401 msg, in case this content is their private content if (!MetacatUI.appUserModel.get("checked")) { this.listenToOnce( MetacatUI.appUserModel, @@ -798,7 +797,7 @@

Source: src/js/views/MetadataView.js

return; } - //If the user is logged in, the message will display that this dataset is private. + // If the user is logged in, the message will display that this dataset is private. if (MetacatUI.appUserModel.get("loggedIn")) { var msg = '<span class="icon-stack private tooltip-this" data-toggle="tooltip"' + @@ -808,33 +807,31 @@

Source: src/js/views/MetadataView.js

'<i class="icon icon-lock icon-stack-top"></i>' + "</span> This is a private dataset."; } - //If the user isn't logged in, display a log in link. + // If the user isn't logged in, display a log in link. else { var msg = - '<span class="icon-stack private tooltip-this" data-toggle="tooltip"' + - 'data-placement="top" data-container="#metadata-controls-container"' + - 'title="" data-original-title="This is a private dataset.">' + - '<i class="icon icon-circle icon-stack-base private"></i>' + - '<i class="icon icon-lock icon-stack-top"></i>' + - "</span> This is a private dataset. If you believe you have permission " + - 'to access this dataset, then <a href="' + - MetacatUI.root + - '/signin">sign in</a>.'; + `<span class="icon-stack private tooltip-this" data-toggle="tooltip"` + + `data-placement="top" data-container="#metadata-controls-container"` + + `title="" data-original-title="This is a private dataset.">` + + `<i class="icon icon-circle icon-stack-base private"></i>` + + `<i class="icon icon-lock icon-stack-top"></i>` + + `</span> This is a private dataset. If you believe you have permission ` + + `to access this dataset, then <a href="${MetacatUI.root}/signin">sign in</a>.`; } - //Remove the loading message + // Remove the loading message this.hideLoading(); - //Show the not found error message + // Show the not found error message this.showError(msg); }, - getPackageDetails: function (packageIDs) { - var completePackages = 0; + getPackageDetails(packageIDs) { + let completePackages = 0; - //This isn't a package, but just a lonely metadata doc... + // This isn't a package, but just a lonely metadata doc... if (!packageIDs || !packageIDs.length) { - var thisPackage = new Package({ id: null, members: [this.model] }); + const thisPackage = new Package({ id: null, members: [this.model] }); thisPackage.flagComplete(); this.packageModels = [thisPackage]; this.insertPackageDetails(thisPackage, { @@ -844,32 +841,30 @@

Source: src/js/views/MetadataView.js

_.each( packageIDs, function (thisPackageID, i) { - //Create a model representing the data package - var thisPackage = new Package({ id: thisPackageID }); + // Create a model representing the data package + const thisPackage = new Package({ id: thisPackageID }); - //Listen for any parent packages + // Listen for any parent packages this.listenToOnce( thisPackage, "change:parentPackageMetadata", this.insertParentLink, ); - //When the package info is fully retrieved + // When the package info is fully retrieved this.listenToOnce( thisPackage, "complete", function (thisPackage) { - //When all packages are fully retrieved + // When all packages are fully retrieved completePackages++; if (completePackages >= packageIDs.length) { - var latestPackages = _.filter( + const latestPackages = _.filter( this.packageModels, - function (m) { - return !_.contains(packageIDs, m.get("obsoletedBy")); - }, + (m) => !_.contains(packageIDs, m.get("obsoletedBy")), ); - //Set those packages as the most recent package + // Set those packages as the most recent package this.packageModels = latestPackages; this.insertPackageDetails(latestPackages); @@ -877,13 +872,13 @@

Source: src/js/views/MetadataView.js

}, ); - //Save the package in the view + // Save the package in the view this.packageModels.push(thisPackage); - //Make sure we get archived content, too + // Make sure we get archived content, too thisPackage.set("getArchivedMembers", true); - //Get the members + // Get the members thisPackage.getMembers({ getParentMetadata: true }); }, this, @@ -891,19 +886,19 @@

Source: src/js/views/MetadataView.js

} }, - alterMarkup: function () { - //Find the taxonomic range and give it a class for styling - for older versions of Metacat only (v2.4.3 and older) + alterMarkup() { + // Find the taxonomic range and give it a class for styling - for older versions of Metacat only (v2.4.3 and older) if (!this.$(".taxonomicCoverage").length) this.$('h4:contains("Taxonomic Range")') .parent() .addClass("taxonomicCoverage"); - //Remove ecogrid links and replace them with workable links + // Remove ecogrid links and replace them with workable links this.replaceEcoGridLinks(); - //Find the tab links for attribute names - this.$(".attributeListTable tr a").on("shown", function (e) { - //When the attribute link is clicked on, highlight the tab as active + // Find the tab links for attribute names + this.$(".attributeListTable tr a").on("shown", (e) => { + // When the attribute link is clicked on, highlight the tab as active $(e.target) .parents(".attributeListTable") .find(".active") @@ -911,7 +906,7 @@

Source: src/js/views/MetadataView.js

$(e.target).parents("tr").first().addClass("active"); }); - //Mark the first row in each attribute list table as active since the first attribute is displayed at first + // Mark the first row in each attribute list table as active since the first attribute is displayed at first this.$(".attributeListTable tr:first-child()").addClass("active"); // Add explanation text to the alternate identifier @@ -925,7 +920,7 @@

Source: src/js/views/MetadataView.js

* @returns {jQuery} The jQuery object for the icon element. * @since 2.26.0 */ - renderAltIdentifierHelpText: function () { + renderAltIdentifierHelpText() { try { // Find the HTML element that contains the alternate identifier. const altIdentifierLabel = this.$( @@ -963,17 +958,17 @@

Source: src/js/views/MetadataView.js

/* * Inserts a table with all the data package member information and sends the call to display annotations */ - insertPackageDetails: function (packages, options) { + insertPackageDetails(packages, options) { if (typeof options === "undefined") { var options = {}; } - //Don't insert the package details twice - var view = this; - var tableEls = this.$(view.tableContainer).children().not(".loading"); + // Don't insert the package details twice + const view = this; + const tableEls = this.$(view.tableContainer).children().not(".loading"); if (tableEls.length > 0) return; - //wait for the metadata to load - var metadataEls = this.$(view.metadataContainer).children(); + // wait for the metadata to load + const metadataEls = this.$(view.metadataContainer).children(); if (!metadataEls.length || metadataEls.first().is(".loading")) { this.once("metadataLoaded", function () { view.insertPackageDetails(this.packageModels, options); @@ -983,26 +978,26 @@

Source: src/js/views/MetadataView.js

if (!packages) var packages = this.packageModels; - //Get the entity names from this page/metadata + // Get the entity names from this page/metadata this.getEntityNames(packages); _.each( packages, function (packageModel) { - //If the package model is not complete, don't do anything + // If the package model is not complete, don't do anything if (!packageModel.complete) return; - //Insert a package table for each package in viewRef dataset - var nestedPckgs = packageModel.getNestedPackages(), - nestedPckgsToDisplay = []; + // Insert a package table for each package in viewRef dataset + const nestedPckgs = packageModel.getNestedPackages(); + let nestedPckgsToDisplay = []; - //If this metadata is not archived, filter out archived packages + // If this metadata is not archived, filter out archived packages if (!this.model.get("archived")) { - nestedPckgsToDisplay = _.reject(nestedPckgs, function (pkg) { - return pkg.get("archived"); - }); + nestedPckgsToDisplay = _.reject(nestedPckgs, (pkg) => + pkg.get("archived"), + ); } else { - //Display all packages is this metadata is archived + // Display all packages is this metadata is archived nestedPckgsToDisplay = nestedPckgs; } @@ -1014,16 +1009,16 @@

Source: src/js/views/MetadataView.js

) ) { var title = packageModel.get("id") - ? '<span class="subtle">Package: ' + - packageModel.get("id") + - "</span>" + ? `<span class="subtle">Package: ${packageModel.get( + "id", + )}</span>` : ""; - options.title = "Files in this dataset " + title; + options.title = `Files in this dataset ${title}`; options.nested = true; this.insertPackageTable(packageModel, options); } } else { - //If this metadata is not archived, then don't display archived packages + // If this metadata is not archived, then don't display archived packages if ( !( !this.model.get("archived") && @@ -1031,24 +1026,24 @@

Source: src/js/views/MetadataView.js

) ) { var title = packageModel.get("id") - ? '<span class="subtle">Package: ' + - packageModel.get("id") + - "</span>" + ? `<span class="subtle">Package: ${packageModel.get( + "id", + )}</span>` : ""; - options.title = "Files in this dataset " + title; + options.title = `Files in this dataset ${title}`; this.insertPackageTable(packageModel, options); } } - //Remove the extra download button returned from the XSLT since the package table will have all the download links + // Remove the extra download button returned from the XSLT since the package table will have all the download links $("#downloadPackage").remove(); }, this, ); - //If this metadata doc is not in a package, but is just a lonely metadata doc... + // If this metadata doc is not in a package, but is just a lonely metadata doc... if (!packages.length) { - var packageModel = new Package({ + const packageModel = new Package({ members: [this.model], }); packageModel.complete = true; @@ -1057,7 +1052,7 @@

Source: src/js/views/MetadataView.js

this.insertPackageTable(packageModel, options); } - //Insert the data details sections + // Insert the data details sections this.insertDataDetails(); // Get data package, if there is one, before checking write permissions @@ -1071,20 +1066,20 @@

Source: src/js/views/MetadataView.js

try { // Get the most recent package to display the provenance graphs if (packages.length) { - //Find the most recent Package model and fetch it + // Find the most recent Package model and fetch it let mostRecentPackage = _.find( packages, (p) => !p.get("obsoletedBy"), ); - //If all of the packages are obsoleted, then use the last package in the array, + // If all of the packages are obsoleted, then use the last package in the array, // which is most likely the most recent. /** @todo Use the DataONE version API to find the most recent package in the version chain */ if (!mostRecentPackage) { mostRecentPackage = packages[packages.length - 1]; } - //Get the data package only if it is not the same as the previously fetched package + // Get the data package only if it is not the same as the previously fetched package if (mostRecentPackage.get("id") != packages[0].get("id")) this.getDataPackage(mostRecentPackage.get("id")); } @@ -1095,16 +1090,16 @@

Source: src/js/views/MetadataView.js

); } - //Initialize tooltips in the package table(s) + // Initialize tooltips in the package table(s) this.$(".tooltip-this").tooltip(); return this; }, - insertPackageTable: function (packageModel, options) { - var view = this; + insertPackageTable(packageModel, options) { + const view = this; if (this.dataPackage == null || !this.dataPackageSynced) { - this.listenToOnce(this, "changed:dataPackageSynced", function () { + this.listenToOnce(this, "changed:dataPackageSynced", () => { view.insertPackageTable(packageModel, options); }); return; @@ -1129,46 +1124,45 @@

Source: src/js/views/MetadataView.js

nested = false, disablePackageDownloads = false; - //** Draw the package table **// - var tableView = new DataPackageView({ + //* * Draw the package table **// + const tableView = new DataPackageView({ edit: false, dataPackage: this.dataPackage, currentlyViewing: this.pid, dataEntities: this.entities, - disablePackageDownloads: disablePackageDownloads, + disablePackageDownloads, parentView: this, - title: title, + title, packageTitle: this.model.get("title"), - nested: nested, + nested, metricsModel: this.metricsModel, }); - //Get the package table container - var tablesContainer = this.$(this.tableContainer); + // Get the package table container + const tablesContainer = this.$(this.tableContainer); - //After the first table, start collapsing them - var numTables = $(tablesContainer).find( + // After the first table, start collapsing them + const numTables = $(tablesContainer).find( "table.download-contents", ).length; if (numTables == 1) { var tableContainer = $(document.createElement("div")).attr( "id", - "additional-tables-for-" + this.cid, + `additional-tables-for-${this.cid}`, ); tableContainer.hide(); $(tablesContainer).append(tableContainer); } else if (numTables > 1) - var tableContainer = this.$("#additional-tables-for-" + this.cid); + var tableContainer = this.$(`#additional-tables-for-${this.cid}`); else var tableContainer = tablesContainer; - //Insert the package table HTML + // Insert the package table HTML $(tableContainer).empty(); $(tableContainer).append(tableView.render().el); // Add Package Download // create an instance of DownloadButtonView to handle package downloads this.downloadButtonView = new DownloadButtonView({ - id: packageModel.get("id"), model: packageModel, view: "actionsView", }); @@ -1187,39 +1181,39 @@

Source: src/js/views/MetadataView.js

this.subviews.push(tableView); - //Trigger a custom event in this view that indicates the package table has been rendered + // Trigger a custom event in this view that indicates the package table has been rendered this.trigger("dataPackageRendered"); }, - insertParentLink: function (packageModel) { - var parentPackageMetadata = packageModel.get("parentPackageMetadata"), - view = this; + insertParentLink(packageModel) { + const parentPackageMetadata = packageModel.get("parentPackageMetadata"); + const view = this; - _.each(parentPackageMetadata, function (m, i) { - var title = m.get("title"), - icon = $(document.createElement("i")).addClass( - "icon icon-on-left icon-level-up", - ), - link = $(document.createElement("a")) - .attr( - "href", - MetacatUI.root + "/view/" + encodeURIComponent(m.get("id")), - ) - .addClass("parent-link") - .text("Parent dataset: " + title) - .prepend(icon); + _.each(parentPackageMetadata, (m, i) => { + const title = m.get("title"); + const icon = $(document.createElement("i")).addClass( + "icon icon-on-left icon-level-up", + ); + const link = $(document.createElement("a")) + .attr( + "href", + `${MetacatUI.root}/view/${encodeURIComponent(m.get("id"))}`, + ) + .addClass("parent-link") + .text(`Parent dataset: ${title}`) + .prepend(icon); view.$(view.parentLinkContainer).append(link); }); }, - insertSpatialCoverageMap: function (customCoordinates) { - //Find the geographic region container. Older versions of Metacat (v2.4.3 and less) will not have it classified so look for the header text + insertSpatialCoverageMap(customCoordinates) { + // Find the geographic region container. Older versions of Metacat (v2.4.3 and less) will not have it classified so look for the header text if (!this.$(".geographicCoverage").length) { - //For EML - var title = this.$('h4:contains("Geographic Region")'); + // For EML + let title = this.$('h4:contains("Geographic Region")'); - //For FGDC + // For FGDC if (title.length == 0) { title = this.$('label:contains("Bounding Coordinates")'); } @@ -1232,11 +1226,11 @@

Source: src/js/views/MetadataView.js

var directions = new Array("north", "south", "east", "west"); } - for (var i = 0; i < georegionEls.length; i++) { + for (let i = 0; i < georegionEls.length; i++) { var georegion = georegionEls[i]; if (typeof customCoordinates !== "undefined") { - //Extract the coordinates + // Extract the coordinates var n = customCoordinates[0]; var s = customCoordinates[1]; var e = customCoordinates[2]; @@ -1244,16 +1238,16 @@

Source: src/js/views/MetadataView.js

} else { var coordinates = new Array(); - _.each(directions, function (direction) { - //Parse text for older versions of Metacat (v2.4.3 and earlier) + _.each(directions, (direction) => { + // Parse text for older versions of Metacat (v2.4.3 and earlier) if (parseText) { - var labelEl = $(georegion).find( - 'label:contains("' + direction + '")', + const labelEl = $(georegion).find( + `label:contains("${direction}")`, ); if (labelEl.length) { var coordinate = $(labelEl).next().html(); if ( - typeof coordinate != "undefined" && + typeof coordinate !== "undefined" && coordinate.indexOf("&nbsp;") > -1 ) coordinate = coordinate.substring( @@ -1263,115 +1257,62 @@

Source: src/js/views/MetadataView.js

} } else { var coordinate = $(georegion) - .find("." + direction + "BoundingCoordinate") + .find(`.${direction}BoundingCoordinate`) .attr("data-value"); } - //Save our coordinate value + // Save our coordinate value coordinates.push(coordinate); }); - //Extract the coordinates + // Extract the coordinates var n = coordinates[0]; var s = coordinates[1]; var e = coordinates[2]; var w = coordinates[3]; } - //Create Google Map LatLng objects out of our coordinates - var latLngSW = new gmaps.LatLng(s, w); - var latLngNE = new gmaps.LatLng(n, e); - var latLngNW = new gmaps.LatLng(n, w); - var latLngSE = new gmaps.LatLng(s, e); + // Create Google Map LatLng objects out of our coordinates + const latLngSW = new gmaps.LatLng(s, w); + const latLngNE = new gmaps.LatLng(n, e); + const latLngNW = new gmaps.LatLng(n, w); + const latLngSE = new gmaps.LatLng(s, e); - //Get the centertroid location of this data item - var bounds = new gmaps.LatLngBounds(latLngSW, latLngNE); - var latLngCEN = bounds.getCenter(); + // Get the centertroid location of this data item + const bounds = new gmaps.LatLngBounds(latLngSW, latLngNE); + const latLngCEN = bounds.getCenter(); - //If there isn't a center point found, don't draw the map. - if (typeof latLngCEN == "undefined") { + // If there isn't a center point found, don't draw the map. + if (typeof latLngCEN === "undefined") { return; } - //Get the map path color - var pathColor = MetacatUI.appModel.get("datasetMapPathColor"); + // Get the map path color + let pathColor = MetacatUI.appModel.get("datasetMapPathColor"); if (pathColor) { - pathColor = "color:" + pathColor + "|"; + pathColor = `color:${pathColor}|`; } else { pathColor = ""; } - //Get the map path fill color - var fillColor = MetacatUI.appModel.get("datasetMapFillColor"); + // Get the map path fill color + let fillColor = MetacatUI.appModel.get("datasetMapFillColor"); if (fillColor) { - fillColor = "fillcolor:" + fillColor + "|"; + fillColor = `fillcolor:${fillColor}|`; } else { fillColor = ""; } - //Create a google map image - var mapHTML = - "<img class='georegion-map' " + - "src='https://maps.googleapis.com/maps/api/staticmap?" + - "center=" + - latLngCEN.lat() + - "," + - latLngCEN.lng() + - "&size=800x350" + - "&maptype=terrain" + - "&markers=size:mid|color:0xDA4D3Aff|" + - latLngCEN.lat() + - "," + - latLngCEN.lng() + - "&path=" + - fillColor + - pathColor + - "weight:3|" + - latLngSW.lat() + - "," + - latLngSW.lng() + - "|" + - latLngNW.lat() + - "," + - latLngNW.lng() + - "|" + - latLngNE.lat() + - "," + - latLngNE.lng() + - "|" + - latLngSE.lat() + - "," + - latLngSE.lng() + - "|" + - latLngSW.lat() + - "," + - latLngSW.lng() + - "&visible=" + - latLngSW.lat() + - "," + - latLngSW.lng() + - "|" + - latLngNW.lat() + - "," + - latLngNW.lng() + - "|" + - latLngNE.lat() + - "," + - latLngNE.lng() + - "|" + - latLngSE.lat() + - "," + - latLngSE.lng() + - "|" + - latLngSW.lat() + - "," + - latLngSW.lng() + - "&sensor=false" + - "&key=" + - MetacatUI.mapKey + - "'/>"; - - //Find the spot in the DOM to insert our map image + // Create a google map image + const mapHTML = + `<img class='georegion-map' ` + + `src='https://maps.googleapis.com/maps/api/staticmap?` + + `center=${latLngCEN.lat()},${latLngCEN.lng()}&size=800x350` + + `&maptype=terrain` + + `&markers=size:mid|color:0xDA4D3Aff|${latLngCEN.lat()},${latLngCEN.lng()}&path=${fillColor}${pathColor}weight:3|${latLngSW.lat()},${latLngSW.lng()}|${latLngNW.lat()},${latLngNW.lng()}|${latLngNE.lat()},${latLngNE.lng()}|${latLngSE.lat()},${latLngSE.lng()}|${latLngSW.lat()},${latLngSW.lng()}&visible=${latLngSW.lat()},${latLngSW.lng()}|${latLngNW.lat()},${latLngNW.lng()}|${latLngNE.lat()},${latLngNE.lng()}|${latLngSE.lat()},${latLngSE.lng()}|${latLngSW.lat()},${latLngSW.lng()}&sensor=false` + + `&key=${MetacatUI.mapKey}'/>`; + + // Find the spot in the DOM to insert our map image if (parseText) var insertAfter = $(georegion) .find('label:contains("West")') @@ -1379,7 +1320,7 @@

Source: src/js/views/MetadataView.js

.parent().length ? $(georegion).find('label:contains("West")').parent().parent() : georegion; - //The last coordinate listed + // The last coordinate listed else var insertAfter = georegion; // Get the URL to the interactive Google Maps instance @@ -1389,7 +1330,7 @@

Source: src/js/views/MetadataView.js

$(insertAfter).append( this.mapTemplate({ map: mapHTML, - url: url, + url, }), ); @@ -1414,7 +1355,7 @@

Source: src/js/views/MetadataView.js

* @returns {string} The URL to the Google Maps instance. * @since 2.27.0 */ - getGoogleMapsUrl: function (latLngCEN, bounds) { + getGoogleMapsUrl(latLngCEN, bounds) { // Use the window width and height as a proxy for the map dimensions const mapDim = { height: $(window).height(), @@ -1431,50 +1372,60 @@

Source: src/js/views/MetadataView.js

* Returns the zoom level that will display the given bounding box at * the given dimensions. * @param {LatLngBounds} bounds - The bounding box to display. - * @param {Object} mapDim - The dimensions of the map. + * @param {object} mapDim - The dimensions of the map. * @param {number} mapDim.height - The height of the map. * @param {number} mapDim.width - The width of the map. * @returns {number} The zoom level. * @since 2.27.0 */ - getBoundsZoomLevel: function (bounds, mapDim) { - var WORLD_DIM = { height: 256, width: 256 }; - var ZOOM_MAX = 15; + getBoundsZoomLevel(bounds, mapDim) { + const WORLD_DIM = { height: 256, width: 256 }; + const ZOOM_MAX = 15; // 21 is actual max, but any closer and the map is too zoomed in to be // useful + /** + * + * @param lat + */ function latRad(lat) { - var sin = Math.sin((lat * Math.PI) / 180); - var radX2 = Math.log((1 + sin) / (1 - sin)) / 2; + const sin = Math.sin((lat * Math.PI) / 180); + const radX2 = Math.log((1 + sin) / (1 - sin)) / 2; return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2; } + /** + * + * @param mapPx + * @param worldPx + * @param fraction + */ function zoom(mapPx, worldPx, fraction) { return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2); } - var ne = bounds.getNorthEast(); - var sw = bounds.getSouthWest(); + const ne = bounds.getNorthEast(); + const sw = bounds.getSouthWest(); - var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI; + const latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI; - var lngDiff = ne.lng() - sw.lng(); - var lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360; + const lngDiff = ne.lng() - sw.lng(); + const lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360; - var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction); - var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction); + const latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction); + const lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction); return Math.min(latZoom, lngZoom, ZOOM_MAX); }, - insertCitation: function () { + insertCitation() { if (!this.model) return false; - //Create a citation header element from the model attributes - var header = new CitationHeaderView({ model: this.model }); + // Create a citation header element from the model attributes + const header = new CitationHeaderView({ model: this.model }); this.$(this.citationContainer).html(header.render().el); }, - insertDataSource: function () { + insertDataSource() { if ( !this.model || !MetacatUI.nodeModel || @@ -1483,12 +1434,12 @@

Source: src/js/views/MetadataView.js

) return; - var dataSource = MetacatUI.nodeModel.getMember(this.model), - replicaMNs = MetacatUI.nodeModel.getMembers( - this.model.get("replicaMN"), - ); + const dataSource = MetacatUI.nodeModel.getMember(this.model); + let replicaMNs = MetacatUI.nodeModel.getMembers( + this.model.get("replicaMN"), + ); - //Filter out the data source from the replica nodes + // Filter out the data source from the replica nodes if (Array.isArray(replicaMNs) && replicaMNs.length) { replicaMNs = _.without(replicaMNs, dataSource); } @@ -1496,20 +1447,20 @@

Source: src/js/views/MetadataView.js

if (dataSource && dataSource.logo) { this.$("img.data-source").remove(); - //Construct a URL to the profile of this repository - var profileURL = + // Construct a URL to the profile of this repository + const profileURL = dataSource.identifier == MetacatUI.appModel.get("nodeId") - ? MetacatUI.root + "/profile" - : MetacatUI.appModel.get("dataoneSearchUrl") + - "/portals/" + - dataSource.shortIdentifier; + ? `${MetacatUI.root}/profile` + : `${MetacatUI.appModel.get("dataoneSearchUrl")}/portals/${ + dataSource.shortIdentifier + }`; - //Insert the data source template + // Insert the data source template this.$(this.dataSourceContainer) .html( this.dataSourceTemplate({ node: dataSource, - profileURL: profileURL, + profileURL, }), ) .addClass("has-data-source"); @@ -1521,25 +1472,19 @@

Source: src/js/views/MetadataView.js

.popover({ trigger: "manual", html: true, - title: "From the " + dataSource.name + " repository", - content: function () { - var content = "<p>" + dataSource.description + "</p>"; + title: `From the ${dataSource.name} repository`, + content() { + let content = `<p>${dataSource.description}</p>`; if (replicaMNs.length) { - content += - "<h5>Exact copies hosted by " + - replicaMNs.length + - ' repositories: </h5><ul class="unstyled">'; - - _.each(replicaMNs, function (node) { - content += - '<li><a href="' + - MetacatUI.appModel.get("dataoneSearchUrl") + - "/portals/" + - node.shortIdentifier + - '" class="pointer">' + - node.name + - "</a></li>"; + content += `<h5>Exact copies hosted by ${replicaMNs.length} repositories: </h5><ul class="unstyled">`; + + _.each(replicaMNs, (node) => { + content += `<li><a href="${MetacatUI.appModel.get( + "dataoneSearchUrl", + )}/portals/${node.shortIdentifier}" class="pointer">${ + node.name + }</a></li>`; }); content += "</ul>"; @@ -1550,15 +1495,15 @@

Source: src/js/views/MetadataView.js

animation: false, }) .on("mouseenter", function () { - var _this = this; + const _this = this; $(this).popover("show"); - $(".popover").on("mouseleave", function () { + $(".popover").on("mouseleave", () => { $(_this).popover("hide"); }); }) .on("mouseleave", function () { - var _this = this; - setTimeout(function () { + const _this = this; + setTimeout(() => { if (!$(".popover:hover").length) { $(_this).popover("hide"); } @@ -1572,13 +1517,15 @@

Source: src/js/views/MetadataView.js

* Once the permission checks have finished, continue with the functions that * depend on them. */ - checkWritePermissions: function () { - var view = this, - authorization = [], - resourceMap = this.dataPackage ? this.dataPackage.packageModel : null, - modelsToCheck = [this.model, resourceMap]; - - modelsToCheck.forEach(function (model, index) { + checkWritePermissions() { + const view = this; + const authorization = []; + const resourceMap = this.dataPackage + ? this.dataPackage.packageModel + : null; + const modelsToCheck = [this.model, resourceMap]; + + modelsToCheck.forEach((model, index) => { // If there is no resource map or no EML, // then the user does not need permission to edit it. if (!model || model.get("notFound") == true) { @@ -1595,32 +1542,30 @@

Source: src/js/views/MetadataView.js

// Return to this function once we've finished checking. } else { view.stopListening(model, "change:isAuthorized_write"); - view.listenToOnce(model, "change:isAuthorized_write", function () { + view.listenToOnce(model, "change:isAuthorized_write", () => { view.checkWritePermissions(); }); view.stopListening(model, "change:notFound"); - view.listenToOnce(model, "change:notFound", function () { + view.listenToOnce(model, "change:notFound", () => { view.checkWritePermissions(); }); model.checkAuthority("write"); - return; } }); // Check that all the models were tested for authorization // Every value in the auth array must be true for the user to have full permissions - var allTrue = _.every(authorization, function (test) { - return test; - }), - // When we have completed checking each of the models that we need to check for - // permissions, every value in the authorization array should be "true" or "false", - // and the array should have the same length as the modelsToCheck array. - allBoolean = _.every(authorization, function (test) { - return typeof test === "boolean"; - }), - allChecked = - allBoolean && authorization.length === modelsToCheck.length; + const allTrue = _.every(authorization, (test) => test); + // When we have completed checking each of the models that we need to check for + // permissions, every value in the authorization array should be "true" or "false", + // and the array should have the same length as the modelsToCheck array. + const allBoolean = _.every( + authorization, + (test) => typeof test === "boolean", + ); + const allChecked = + allBoolean && authorization.length === modelsToCheck.length; // Check for and render prov diagrams now that we know whether or not the user has editor permissions // (There is a different version of the chart for users who can edit the resource map and users who cannot) @@ -1639,16 +1584,18 @@

Source: src/js/views/MetadataView.js

* Inserts control elements onto the page for the user to interact with the dataset - edit, publish, etc. * Editor permissions should already have been checked before running this function. */ - insertEditorControls: function () { - var view = this, - resourceMap = this.dataPackage ? this.dataPackage.packageModel : null, - modelsToCheck = [this.model, resourceMap], - authorized = _.every(modelsToCheck, function (model) { - // If there is no EML or no resource map, the user doesn't need permission to edit it. - return !model || model.get("notFound") == true - ? true - : model.get("isAuthorized_write") === true; - }); + insertEditorControls() { + const view = this; + const resourceMap = this.dataPackage + ? this.dataPackage.packageModel + : null; + const modelsToCheck = [this.model, resourceMap]; + const authorized = _.every(modelsToCheck, (model) => + // If there is no EML or no resource map, the user doesn't need permission to edit it. + !model || model.get("notFound") == true + ? true + : model.get("isAuthorized_write") === true, + ); // Only run this function when the user has full editor permissions // (i.e. write permission on the EML, and write permission on the resource map if there is one.) @@ -1665,23 +1612,23 @@

Source: src/js/views/MetadataView.js

} // Save the element that will contain the owner control buttons - var container = this.$(this.editorControlsContainer); + const container = this.$(this.editorControlsContainer); // Do not insert the editor controls twice container.empty(); // The PID for the EML model - var pid = this.model.get("id") || this.pid; + const pid = this.model.get("id") || this.pid; - //Insert an Edit button if the Edit button is enabled + // Insert an Edit button if the Edit button is enabled if (MetacatUI.appModel.get("displayDatasetEditButton")) { - //Check that this is an editable metadata format + // Check that this is an editable metadata format if ( _.contains( MetacatUI.appModel.get("editableFormats"), this.model.get("formatId"), ) ) { - //Insert the Edit Metadata template + // Insert the Edit Metadata template container.append( this.editMetadataTemplate({ identifier: pid, @@ -1689,7 +1636,7 @@

Source: src/js/views/MetadataView.js

}), ); } - //If this format is not editable, insert an unspported Edit Metadata template + // If this format is not editable, insert an unspported Edit Metadata template else { container.append( this.editMetadataTemplate({ @@ -1700,19 +1647,19 @@

Source: src/js/views/MetadataView.js

} try { - //Determine if this metadata can be published. + // Determine if this metadata can be published. // The Publish feature has to be enabled in the app. // The model cannot already have a DOI - var canBePublished = + let canBePublished = MetacatUI.appModel.get("enablePublishDOI") && !view.model.isDOI(); - //If publishing is enabled, check if only certain users and groups can publish metadata + // If publishing is enabled, check if only certain users and groups can publish metadata if (canBePublished) { - //Get the list of authorized publishers from the AppModel - var authorizedPublishers = MetacatUI.appModel.get( + // Get the list of authorized publishers from the AppModel + const authorizedPublishers = MetacatUI.appModel.get( "enablePublishDOIForSubjects", ); - //If the logged-in user is one of the subjects in the list or is in a group that is + // If the logged-in user is one of the subjects in the list or is in a group that is // in the list, then this metadata can be published. Otherwise, it cannot. if ( Array.isArray(authorizedPublishers) && @@ -1728,9 +1675,9 @@

Source: src/js/views/MetadataView.js

} } - //If this metadata can be published, then insert the Publish button template + // If this metadata can be published, then insert the Publish button template if (canBePublished) { - //Insert a Publish button template + // Insert a Publish button template container.append( view.doiTemplate({ isAuthorized: true, @@ -1758,14 +1705,14 @@

Source: src/js/views/MetadataView.js

* * to your XSLT and this should pick it up automatically. */ - insertCopiables: function () { - var copiables = $("#Metadata .copy"); + insertCopiables() { + const copiables = $("#Metadata .copy"); - _.each(copiables, function (copiable) { - var clipboard = new Clipboard(copiable); + _.each(copiables, (copiable) => { + const clipboard = new Clipboard(copiable); - clipboard.on("success", function (e) { - var el = $(e.trigger); + clipboard.on("success", (e) => { + const el = $(e.trigger); $(el).html( $(document.createElement("span")).addClass( @@ -1776,7 +1723,7 @@

Source: src/js/views/MetadataView.js

// Use setTimeout instead of jQuery's built-in Events system because // it didn't look flexible enough to allow me update innerHTML in // a chain - setTimeout(function () { + setTimeout(() => { $(el).html("Copy"); }, 500); }); @@ -1787,24 +1734,24 @@

Source: src/js/views/MetadataView.js

* Inserts elements users can use to interact with this dataset: * - A "Copy Citation" button to copy the citation text */ - insertControls: function () { + insertControls() { // Convert the support mdq formatId list to a version // that JS regex likes (with special characters double RegExp.escape = function (s) { return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\\\$&"); }; - var mdqFormatIds = MetacatUI.appModel.get("mdqFormatIds"); + const mdqFormatIds = MetacatUI.appModel.get("mdqFormatIds"); // Check of the current formatId is supported by the current // metadata quality suite. If not, the 'Assessment Report' button // will not be displacyed in the metadata controls panel. - var thisFormatId = this.model.get("formatId"); - var mdqFormatSupported = false; - var formatFound = false; + const thisFormatId = this.model.get("formatId"); + const mdqFormatSupported = false; + let formatFound = false; if (mdqFormatIds !== null) { - for (var ifmt = 0; ifmt < mdqFormatIds.length; ++ifmt) { - var currentFormatId = RegExp.escape(mdqFormatIds[ifmt]); - var re = new RegExp(currentFormatId); + for (let ifmt = 0; ifmt < mdqFormatIds.length; ++ifmt) { + const currentFormatId = RegExp.escape(mdqFormatIds[ifmt]); + const re = new RegExp(currentFormatId); formatFound = re.test(thisFormatId); if (formatFound) { break; @@ -1812,8 +1759,8 @@

Source: src/js/views/MetadataView.js

} } - //Get template - var controlsContainer = this.controlsTemplate({ + // Get template + const controlsContainer = this.controlsTemplate({ citationTarget: this.citationContainer, url: window.location, displayQualtyReport: @@ -1826,8 +1773,8 @@

Source: src/js/views/MetadataView.js

$(this.controlsContainer).html(controlsContainer); - //Insert the info icons - var metricsWell = this.$(".metrics-container"); + // Insert the info icons + const metricsWell = this.$(".metrics-container"); metricsWell.append( this.infoIconsTemplate({ model: this.model.toJSON(), @@ -1861,43 +1808,38 @@

Source: src/js/views/MetadataView.js

/** *Creates a button which the user can click to launch the package in Whole Tale */ - createWholeTaleButton: function () { - let self = this; - MetacatUI.appModel - .get("taleEnvironments") - .forEach(function (environment) { - var queryParams = - "?uri=" + - window.location.href + - "&title=" + - encodeURIComponent(self.model.get("title")) + - "&environment=" + - environment + - "&api=" + - MetacatUI.appModel.get("d1CNBaseUrl") + - MetacatUI.appModel.get("d1CNService"); - var composeUrl = - MetacatUI.appModel.get("dashboardUrl") + queryParams; - var anchor = $("<a>"); - anchor - .attr("href", composeUrl) - .append($("<span>").attr("class", "tab").append(environment)); - anchor.attr("target", "_blank"); - $(".analyze.dropdown-menu").append($("<li>").append(anchor)); - }); + createWholeTaleButton() { + const self = this; + MetacatUI.appModel.get("taleEnvironments").forEach((environment) => { + const queryParams = `?uri=${ + window.location.href + }&title=${encodeURIComponent( + self.model.get("title"), + )}&environment=${environment}&api=${MetacatUI.appModel.get( + "d1CNBaseUrl", + )}${MetacatUI.appModel.get("d1CNService")}`; + const composeUrl = + MetacatUI.appModel.get("dashboardUrl") + queryParams; + const anchor = $("<a>"); + anchor + .attr("href", composeUrl) + .append($("<span>").attr("class", "tab").append(environment)); + anchor.attr("target", "_blank"); + $(".analyze.dropdown-menu").append($("<li>").append(anchor)); + }); }, // Inserting the Metric Stats - insertMetricsControls: function () { - //Exit if metrics shouldn't be shown for this dataset + insertMetricsControls() { + // Exit if metrics shouldn't be shown for this dataset if (this.model.hideMetrics()) { return; } - var pid_list = []; + const pid_list = []; pid_list.push(this.pid); - var metricsModel = new MetricsModel({ - pid_list: pid_list, + const metricsModel = new MetricsModel({ + pid_list, type: "dataset", }); metricsModel.fetch(); @@ -1907,10 +1849,10 @@

Source: src/js/views/MetadataView.js

// TODO: Create a Metric Request Object if (MetacatUI.appModel.get("displayDatasetMetrics")) { - var buttonToolbar = this.$(".metrics-container"); + const buttonToolbar = this.$(".metrics-container"); if (MetacatUI.appModel.get("displayDatasetDownloadMetric")) { - var dwnldsMetricView = new MetricView({ + const dwnldsMetricView = new MetricView({ metricName: "Downloads", model: metricsModel, pid: this.pid, @@ -1920,7 +1862,7 @@

Source: src/js/views/MetadataView.js

} if (MetacatUI.appModel.get("displayDatasetCitationMetric")) { - var citationsMetricView = new MetricView({ + const citationsMetricView = new MetricView({ metricName: "Citations", model: metricsModel, pid: this.pid, @@ -1929,15 +1871,15 @@

Source: src/js/views/MetadataView.js

this.subviews.push(citationsMetricView); try { - //Check if the registerCitation=true query string is set + // Check if the registerCitation=true query string is set if (window.location.search) { if ( window.location.search.indexOf("registerCitation=true") > -1 ) { - //Open the modal for the citations + // Open the modal for the citations citationsMetricView.showMetricModal(); - //Show the register citation form + // Show the register citation form if (citationsMetricView.modalView) { citationsMetricView.modalView.on( "renderComplete", @@ -1952,7 +1894,7 @@

Source: src/js/views/MetadataView.js

} if (MetacatUI.appModel.get("displayDatasetViewMetric")) { - var viewsMetricView = new MetricView({ + const viewsMetricView = new MetricView({ metricName: "Views", model: metricsModel, pid: this.pid, @@ -1969,14 +1911,14 @@

Source: src/js/views/MetadataView.js

* The view must have the DataPackage collection set as view.dataPackage * for this function to run. */ - checkForProv: function () { + checkForProv() { if (!this.dataPackage) { return; } // Render the provenance trace using the redrawProvCharts function instead of the drawProvCharts function // just in case the prov charts have already been inserted. Redraw will make sure they are removed // before being re-inserted. - var model = this.model; + const { model } = this; if (this.dataPackage.provenanceFlag == "complete") { this.redrawProvCharts(this.dataPackage); } else { @@ -1992,7 +1934,7 @@

Source: src/js/views/MetadataView.js

* Renders ProvChartViews on the page to display provenance on a package level and on an individual object level. * This function looks at four sources for the provenance - the package sources, the package derivations, member sources, and member derivations */ - drawProvCharts: function (dataPackage) { + drawProvCharts(dataPackage) { // Set a listener to re-draw the prov charts when needed this.stopListening(this.dataPackage, "redrawProvCharts"); this.listenToOnce( @@ -2006,54 +1948,50 @@

Source: src/js/views/MetadataView.js

// If the user is authorized to edit the provenance for this package // then turn on editing, so that edit icons are displayed. - var editModeOn = + let editModeOn = this.dataPackage.packageModel.get("isAuthorized_write"); - //If this content is archived, then turn edit mode off + // If this content is archived, then turn edit mode off if (this.model.get("archived")) { editModeOn = false; } - //If none of the models in this package have the formatId attributes, + // If none of the models in this package have the formatId attributes, // we should fetch the DataPackage since it likely has only had a shallow fetch so far - var formats = _.compact(dataPackage.pluck("formatId")); + const formats = _.compact(dataPackage.pluck("formatId")); - //If the number of formatIds is less than the number of models in this collection, + // If the number of formatIds is less than the number of models in this collection, // then we need to get them. if (formats.length < dataPackage.length) { - var modelsToMerge = []; + let modelsToMerge = []; - //Get the PackageModel associated with this view + // Get the PackageModel associated with this view if (this.packageModels.length) { - //Get the PackageModel for this DataPackage - var packageModel = _.find( + // Get the PackageModel for this DataPackage + const packageModel = _.find( this.packageModels, - function (packageModel) { - return packageModel.get("id") == dataPackage.id; - }, + (packageModel) => packageModel.get("id") == dataPackage.id, ); - //Merge the SolrResult models into the DataONEObject models + // Merge the SolrResult models into the DataONEObject models if (packageModel && packageModel.get("members").length) { modelsToMerge = packageModel.get("members"); } } - //If there is at least one model to merge into this data package, do so + // If there is at least one model to merge into this data package, do so if (modelsToMerge.length) { dataPackage.mergeModels(modelsToMerge); } - //If there are no models to merge in, get them from the index + // If there are no models to merge in, get them from the index else { - //Listen to the DataPackage fetch to complete and re-execute this function + // Listen to the DataPackage fetch to complete and re-execute this function this.listenToOnce(dataPackage, "complete", function () { this.drawProvCharts(dataPackage); }); - //Create a query that searches for all the members of this DataPackage in Solr - dataPackage.solrResults.currentquery = - dataPackage.filterModel.getQuery() + - "%20AND%20-formatType:METADATA"; + // Create a query that searches for all the members of this DataPackage in Solr + dataPackage.solrResults.currentquery = `${dataPackage.filterModel.getQuery()}%20AND%20-formatType:METADATA`; dataPackage.solrResults.fields = "id,seriesId,formatId,fileName"; dataPackage.solrResults.rows = dataPackage.length; dataPackage.solrResults.sort = null; @@ -2061,36 +1999,36 @@

Source: src/js/views/MetadataView.js

dataPackage.solrResults.facet = []; dataPackage.solrResults.stats = null; - //Fetch the data package with the "fromIndex" option + // Fetch the data package with the "fromIndex" option dataPackage.fetch({ fromIndex: true }); - //Exit this function since it will be executed again when the fetch is complete + // Exit this function since it will be executed again when the fetch is complete return; } } var view = this; - //Draw two flow charts to represent the sources and derivations at a package level - var packageSources = dataPackage.sourcePackages; - var packageDerivations = dataPackage.derivationPackages; + // Draw two flow charts to represent the sources and derivations at a package level + const packageSources = dataPackage.sourcePackages; + const packageDerivations = dataPackage.derivationPackages; if (Object.keys(packageSources).length) { - var sourceProvChart = new ProvChart({ + const sourceProvChart = new ProvChart({ sources: packageSources, context: dataPackage, contextEl: this.$(this.articleContainer), - dataPackage: dataPackage, + dataPackage, parentView: view, }); this.subviews.push(sourceProvChart); this.$(this.articleContainer).before(sourceProvChart.render().el); } if (Object.keys(packageDerivations).length) { - var derivationProvChart = new ProvChart({ + const derivationProvChart = new ProvChart({ derivations: packageDerivations, context: dataPackage, contextEl: this.$(this.articleContainer), - dataPackage: dataPackage, + dataPackage, parentView: view, }); this.subviews.push(derivationProvChart); @@ -2102,8 +2040,8 @@

Source: src/js/views/MetadataView.js

dataPackage.derivations.length || editModeOn ) { - //Draw the provenance charts for each member of this package at an object level - _.each(dataPackage.toArray(), function (member, i) { + // Draw the provenance charts for each member of this package at an object level + _.each(dataPackage.toArray(), (member, i) => { // Don't draw prov charts for metadata objects. if ( member.get("type").toLowerCase() == "metadata" || @@ -2111,27 +2049,29 @@

Source: src/js/views/MetadataView.js

) { return; } - var entityDetailsSection = view.findEntityDetailsContainer(member); + const entityDetailsSection = + view.findEntityDetailsContainer(member); if (!entityDetailsSection) { return; } - //Retrieve the sources and derivations for this member - var memberSources = member.get("provSources") || new Array(), - memberDerivations = member.get("provDerivations") || new Array(); + // Retrieve the sources and derivations for this member + const memberSources = member.get("provSources") || new Array(); + const memberDerivations = + member.get("provDerivations") || new Array(); - //Make the source chart for this member. + // Make the source chart for this member. // If edit is on, then either a 'blank' sources ProvChart will be displayed if there // are no sources for this member, or edit icons will be displayed with prov icons. if (memberSources.length || editModeOn) { - var memberSourcesProvChart = new ProvChart({ + const memberSourcesProvChart = new ProvChart({ sources: memberSources, context: member, contextEl: entityDetailsSection, - dataPackage: dataPackage, + dataPackage, parentView: view, - editModeOn: editModeOn, + editModeOn, editorType: "sources", }); view.subviews.push(memberSourcesProvChart); @@ -2141,17 +2081,17 @@

Source: src/js/views/MetadataView.js

view.$(view.articleContainer).addClass("gutters"); } - //Make the derivation chart for this member + // Make the derivation chart for this member // If edit is on, then either a 'blank' derivations ProvChart will be displayed if there, // are no derivations for this member or edit icons will be displayed with prov icons. if (memberDerivations.length || editModeOn) { - var memberDerivationsProvChart = new ProvChart({ + const memberDerivationsProvChart = new ProvChart({ derivations: memberDerivations, context: member, contextEl: entityDetailsSection, - dataPackage: dataPackage, + dataPackage, parentView: view, - editModeOn: editModeOn, + editModeOn, editorType: "derivations", }); view.subviews.push(memberDerivationsProvChart); @@ -2163,44 +2103,44 @@

Source: src/js/views/MetadataView.js

}); } - //Make all of the prov chart nodes look different based on id + // Make all of the prov chart nodes look different based on id if (this.$(".prov-chart").length > 10000) { - var allNodes = this.$(".prov-chart .node"), - ids = [], - view = this, - i = 1; + const allNodes = this.$(".prov-chart .node"); + let ids = []; + var view = this; + let i = 1; $(allNodes).each(function () { ids.push($(this).attr("data-id")); }); ids = _.uniq(ids); - _.each(ids, function (id) { - var matchingNodes = view - .$(".prov-chart .node[data-id='" + id + "']") + _.each(ids, (id) => { + const matchingNodes = view + .$(`.prov-chart .node[data-id='${id}']`) .not(".editorNode"); - //var matchingEntityDetails = view.findEntityDetailsContainer(id); + // var matchingEntityDetails = view.findEntityDetailsContainer(id); - //Don't use the unique class on images since they will look a lot different anyway by their image + // Don't use the unique class on images since they will look a lot different anyway by their image if (!$(matchingNodes).first().hasClass("image")) { - var className = "uniqueNode" + i; + const className = `uniqueNode${i}`; - //Add the unique class and up the iterator + // Add the unique class and up the iterator if (matchingNodes.prop("tagName") != "polygon") $(matchingNodes).addClass(className); else $(matchingNodes).attr( "class", - $(matchingNodes).attr("class") + " " + className, + `${$(matchingNodes).attr("class")} ${className}`, ); /* if(matchingEntityDetails) - $(matchingEntityDetails).addClass(className);*/ + $(matchingEntityDetails).addClass(className); */ - //Save this id->class mapping in this view + // Save this id->class mapping in this view view.classMap.push({ - id: id, - className: className, + id, + className, }); i++; } @@ -2211,8 +2151,8 @@

Source: src/js/views/MetadataView.js

/* Step through all prov charts and re-render each one that has been marked for re-rendering. */ - redrawProvCharts: function () { - var view = this; + redrawProvCharts() { + const view = this; // Check if prov edits are active and turn on the prov save bar if so. // Alternatively, turn off save bar if there are no prov edits, which @@ -2224,11 +2164,11 @@

Source: src/js/views/MetadataView.js

this.hideEditorControls(); // Reset the edited flag for each package member - _.each(this.dataPackage.toArray(), function (item) { + _.each(this.dataPackage.toArray(), (item) => { item.selectedInEditor == false; }); } - _.each(this.subviews, function (thisView, i) { + _.each(this.subviews, (thisView, i) => { // Check if this is a ProvChartView if ( thisView.className && @@ -2241,9 +2181,11 @@

Source: src/js/views/MetadataView.js

}); // Remove prov charts from the array of subviews. - this.subviews = _.filter(this.subviews, function (item) { - return item.className && item.className.indexOf("prov-chart") == -1; - }); + this.subviews = _.filter( + this.subviews, + (item) => + item.className && item.className.indexOf("prov-chart") == -1, + ); view.drawProvCharts(this.dataPackage); }, @@ -2251,17 +2193,17 @@

Source: src/js/views/MetadataView.js

/* * When the data package collection saves successfully, tell the user */ - saveSuccess: function (savedObject) { - //We only want to perform these actions after the package saves + saveSuccess(savedObject) { + // We only want to perform these actions after the package saves if (savedObject.type != "DataPackage") return; - //Change the URL to the new id + // Change the URL to the new id MetacatUI.uiRouter.navigate( - "view/" + this.dataPackage.packageModel.get("id"), + `view/${this.dataPackage.packageModel.get("id")}`, { trigger: false, replace: true }, ); - var message = $(document.createElement("div")).append( + const message = $(document.createElement("div")).append( $(document.createElement("span")).text( "Your changes have been saved. ", ), @@ -2287,17 +2229,17 @@

Source: src/js/views/MetadataView.js

// Update the metadata table header with the new resource map id. // First find the DataPackageView for the top level package, and // then re-render it with the update resmap id. - var view = this; - var metadataId = this.packageModels[0].getMetadata().get("id"); - _.each(this.subviews, function (thisView, i) { + const view = this; + const metadataId = this.packageModels[0].getMetadata().get("id"); + _.each(this.subviews, (thisView, i) => { // Check if this is a ProvChartView if (thisView.type && thisView.type.indexOf("DataPackage") !== -1) { if (thisView.currentlyViewing == metadataId) { - var packageId = view.dataPackage.packageModel.get("id"); - var title = packageId - ? '<span class="subtle">Package: ' + packageId + "</span>" + const packageId = view.dataPackage.packageModel.get("id"); + const title = packageId + ? `<span class="subtle">Package: ${packageId}</span>` : ""; - thisView.title = "Files in this dataset " + title; + thisView.title = `Files in this dataset ${title}`; thisView.render(); } } @@ -2307,17 +2249,17 @@

Source: src/js/views/MetadataView.js

/* * When the data package collection fails to save, tell the user */ - saveError: function (errorMsg) { - var errorId = "error" + Math.round(Math.random() * 100), - message = $(document.createElement("div")).append( - "<p>Your changes could not be saved.</p>", - ); + saveError(errorMsg) { + const errorId = `error${Math.round(Math.random() * 100)}`; + const message = $(document.createElement("div")).append( + "<p>Your changes could not be saved.</p>", + ); message.append( $(document.createElement("a")) .text("See details") .attr("data-toggle", "collapse") - .attr("data-target", "#" + errorId) + .attr("data-target", `#${errorId}`) .addClass("pointer"), $(document.createElement("div")) .addClass("collapse") @@ -2326,7 +2268,7 @@

Source: src/js/views/MetadataView.js

); MetacatUI.appView.showAlert(message, "alert-error", "body", null, { - emailBody: "Error message: Data Package save error: " + errorMsg, + emailBody: `Error message: Data Package save error: ${errorMsg}`, remove: true, }); @@ -2341,11 +2283,11 @@

Source: src/js/views/MetadataView.js

/* If provenance relationships have been modified by the provenance editor (in ProvChartView), then update the ORE Resource Map and save it to the server. */ - saveProv: function () { + saveProv() { // Only call this function once per save operation. if (this.saveProvPending) return; - var view = this; + const view = this; if (this.dataPackage.provEditsPending()) { this.saveProvPending = true; // If the Data Package failed saving, display an error message @@ -2359,12 +2301,12 @@

Source: src/js/views/MetadataView.js

this.showSaving(); this.dataPackage.saveProv(); } else { - //TODO: should a dialog be displayed saying that no prov edits were made? + // TODO: should a dialog be displayed saying that no prov edits were made? } }, - showSaving: function () { - //Change the style of the save button + showSaving() { + // Change the style of the save button this.$("#save-metadata-prov") .html('<i class="icon icon-spinner icon-spin"></i> Saving...') .addClass("btn-disabled"); @@ -2372,59 +2314,59 @@

Source: src/js/views/MetadataView.js

this.$("input, textarea, select, button").prop("disabled", true); }, - hideSaving: function () { + hideSaving() { this.$("input, textarea, select, button").prop("disabled", false); - //When prov is saved, revert the Save button back to normal + // When prov is saved, revert the Save button back to normal this.$("#save-metadata-prov").html("Save").removeClass("btn-disabled"); }, - showEditorControls: function () { + showEditorControls() { this.$("#editor-footer").slideDown(); }, - hideEditorControls: function () { + hideEditorControls() { this.$("#editor-footer").slideUp(); }, - getEntityNames: function (packageModels) { - var viewRef = this; + getEntityNames(packageModels) { + const viewRef = this; - _.each(packageModels, function (packageModel) { - //Don't get entity names for larger packages - users must put the names in the system metadata + _.each(packageModels, (packageModel) => { + // Don't get entity names for larger packages - users must put the names in the system metadata if (packageModel.get("members").length > 100) return; - //If this package has a different metadata doc than the one we are currently viewing - var metadataModel = packageModel.getMetadata(); + // If this package has a different metadata doc than the one we are currently viewing + const metadataModel = packageModel.getMetadata(); if (!metadataModel) return; if (metadataModel.get("id") != viewRef.pid) { - var requestSettings = { + const requestSettings = { url: MetacatUI.appModel.get("viewServiceUrl") + encodeURIComponent(metadataModel.get("id")), - success: function (parsedMetadata, response, xhr) { - _.each(packageModel.get("members"), function (solrResult, i) { - var entityName = ""; + success(parsedMetadata, response, xhr) { + _.each(packageModel.get("members"), (solrResult, i) => { + let entityName = ""; if (solrResult.get("formatType") == "METADATA") entityName = solrResult.get("title"); - var container = viewRef.findEntityDetailsContainer( + const container = viewRef.findEntityDetailsContainer( solrResult, parsedMetadata, ); if (container) entityName = viewRef.getEntityName(container); - //Set the entity name + // Set the entity name if (entityName) { solrResult.set("fileName", entityName); - //Update the UI with the new name + // Update the UI with the new name viewRef .$( - ".entity-name-placeholder[data-id='" + - solrResult.get("id") + - "']", + `.entity-name-placeholder[data-id='${solrResult.get( + "id", + )}']`, ) .text(entityName); } @@ -2442,8 +2384,8 @@

Source: src/js/views/MetadataView.js

return; } - _.each(packageModel.get("members"), function (solrResult, i) { - var entityName = ""; + _.each(packageModel.get("members"), (solrResult, i) => { + let entityName = ""; if (solrResult.get("fileName")) entityName = solrResult.get("fileName"); @@ -2451,23 +2393,23 @@

Source: src/js/views/MetadataView.js

entityName = solrResult.get("title"); else if (solrResult.get("formatType") == "RESOURCE") return; else { - var container = viewRef.findEntityDetailsContainer(solrResult); + const container = viewRef.findEntityDetailsContainer(solrResult); if (container && container.length > 0) entityName = viewRef.getEntityName(container); else entityName = null; } - //Set the entityName, even if it's null + // Set the entityName, even if it's null solrResult.set("fileName", entityName); }); }); }, - getEntityName: function (containerEl) { + getEntityName(containerEl) { if (!containerEl) return false; - var entityName = $(containerEl) + let entityName = $(containerEl) .find(".entityName") .attr("data-entity-name"); if (typeof entityName === "undefined" || !entityName) { @@ -2481,26 +2423,25 @@

Source: src/js/views/MetadataView.js

return entityName; }, - //Checks if the metadata has entity details sections - hasEntityDetails: function () { + // Checks if the metadata has entity details sections + hasEntityDetails() { return this.$(".entitydetails").length > 0; }, /** * Finds the element in the rendered metadata that describes the given data entity. - * * @param {(DataONEObject|SolrResult|string)} model - Either a model that represents the data object or the identifier of the data object * @param {Element} [el] - The DOM element to exclusivly search inside. - * @return {Element} - The DOM element that describbbes the given data entity. + * @returns {Element} - The DOM element that describbbes the given data entity. */ - findEntityDetailsContainer: function (model, el) { - if (!el) var el = this.el; + findEntityDetailsContainer(model, el) { + if (!el) var { el } = this; - //Get the id and file name for this data object - var id = "", - fileName = ""; + // Get the id and file name for this data object + let id = ""; + let fileName = ""; - //If a model is given, get the id and file name from the object + // If a model is given, get the id and file name from the object if ( model && (DataONEObject.prototype.isPrototypeOf(model) || @@ -2509,64 +2450,68 @@

Source: src/js/views/MetadataView.js

id = model.get("id"); fileName = model.get("fileName"); } - //If a string is given instead, it must be the id of the data object - else if (typeof model == "string") { + // If a string is given instead, it must be the id of the data object + else if (typeof model === "string") { id = model; } - //Otherwise, there isn't enough info to find the element, so exit + // Otherwise, there isn't enough info to find the element, so exit else { return; } - //If we already found it earlier, return it now - var container = this.$( - ".entitydetails[data-id='" + - id + - "'], " + - ".entitydetails[data-id='" + - DataONEObject.prototype.getXMLSafeID(id) + - "']", + // If we already found it earlier, return it now + let container = this.$( + `.entitydetails[data-id='${id}'], ` + + `.entitydetails[data-id='${DataONEObject.prototype.getXMLSafeID( + id, + )}']`, ); - if (container.length) return container; + if (container.length) { + // Store the PID on this element for moreInfo icons + this.storeEntityPIDs(container, id); - //Are we looking for the main object that this MetadataView is displaying? + return container; + } + + // Are we looking for the main object that this MetadataView is displaying? if (id == this.pid) { if (this.$("#Metadata").length > 0) return this.$("#Metadata"); - else return this.el; + return this.el; } - //Metacat 2.4.2 and up will have the Online Distribution Link marked - var link = this.$(".entitydetails a[data-pid='" + id + "']"); + // Metacat 2.4.2 and up will have the Online Distribution Link marked + let link = this.$(`.entitydetails a[data-pid='${id}']`); - //Otherwise, try looking for an anchor with the id matching this object's id + // Otherwise, try looking for an anchor with the id matching this object's id if (!link.length) - link = $(el).find("a#" + id.replace(/[^A-Za-z0-9]/g, "\\$&")); + link = $(el).find(`a#${id.replace(/[^A-Za-z0-9]/g, "\\$&")}`); - //Get metadata index view - var metadataFromIndex = _.findWhere(this.subviews, { + // Get metadata index view + let metadataFromIndex = _.findWhere(this.subviews, { type: "MetadataIndex", }); if (typeof metadataFromIndex === "undefined") metadataFromIndex = null; - //Otherwise, find the Online Distribution Link the hard way + // Otherwise, find the Online Distribution Link the hard way if (link.length < 1 && !metadataFromIndex) link = $(el).find( - ".control-label:contains('Online Distribution Info') + .controls-well > a[href*='" + - id.replace(/[^A-Za-z0-9]/g, "\\$&") + - "']", + `.control-label:contains('Online Distribution Info') + .controls-well > a[href*='${id.replace( + /[^A-Za-z0-9]/g, + "\\$&", + )}']`, ); if (link.length > 0) { - //Get the container element + // Get the container element container = $(link).parents(".entitydetails"); if (container.length < 1) { - //backup - find the parent of this link that is a direct child of the form element - var firstLevelContainer = _.intersection( + // backup - find the parent of this link that is a direct child of the form element + const firstLevelContainer = _.intersection( $(link).parents("form").children(), $(link).parents(), ); - //Find the controls-well inside of that first level container, which is the well that contains info about this data object + // Find the controls-well inside of that first level container, which is the well that contains info about this data object if (firstLevelContainer.length > 0) container = $(firstLevelContainer).children(".controls-well"); @@ -2576,18 +2521,21 @@

Source: src/js/views/MetadataView.js

$(container).addClass("entitydetails"); } - //Add the id so we can easily find it later + // Add the id so we can easily find it later container.attr("data-id", id); + // Store the PID on this element for moreInfo icons + this.storeEntityPIDs(container, id); + return container; } - //----Find by file name rather than id----- + // ----Find by file name rather than id----- if (!fileName) { - //Get the name of the object first + // Get the name of the object first for (var i = 0; i < this.packageModels.length; i++) { var model = _.findWhere(this.packageModels[i].get("members"), { - id: id, + id, }); if (model) { fileName = model.get("fileName"); @@ -2597,43 +2545,48 @@

Source: src/js/views/MetadataView.js

} if (fileName) { - var possibleLocations = [ - ".entitydetails [data-object-name='" + fileName + "']", - ".entitydetails .control-label:contains('Object Name') + .controls-well:contains('" + - fileName + - "')", - ".entitydetails .control-label:contains('Entity Name') + .controls-well:contains('" + - fileName + - "')", + const possibleLocations = [ + `.entitydetails [data-object-name='${fileName}']`, + `.entitydetails .control-label:contains('Object Name') + .controls-well:contains('${fileName}')`, + `.entitydetails .control-label:contains('Entity Name') + .controls-well:contains('${fileName}')`, ]; - //Search through each possible location in the DOM where the file name might be + // Search through each possible location in the DOM where the file name might be for (var i = 0; i < possibleLocations.length; i++) { - //Get the elements in this view that match the possible location - var matches = this.$(possibleLocations[i]); + // Get the elements in this view that match the possible location + const matches = this.$(possibleLocations[i]); - //If exactly one match is found + // If exactly one match is found if (matches.length == 1) { - //Get the entity details parent element + // Get the entity details parent element container = $(matches).parents(".entitydetails").first(); - //Set the object ID on the element for easier locating later + // Set the object ID on the element for easier locating later container.attr("data-id", id); if (container.length) break; } } - if (container.length) return container; + if (container.length) { + // Store the PID on this element for moreInfo icons + this.storeEntityPIDs(container, id); + + return container; + } } - //--- The last option:---- - //If this package has only one item, we can assume the only entity details are about that item - var members = this.packageModels[0].get("members"), - dataMembers = _.filter(members, function (m) { - return m.get("formatType") == "DATA"; - }); + // --- The last option:---- + // If this package has only one item, we can assume the only entity details are about that item + const members = this.packageModels[0].get("members"); + const dataMembers = _.filter( + members, + (m) => m.get("formatType") == "DATA", + ); if (dataMembers.length == 1) { if (this.$(".entitydetails").length == 1) { this.$(".entitydetails").attr("data-id", id); + // Store the PID on this element for moreInfo icons + this.storeEntityPIDs(this.$(".entitydetails"), id); + return this.$(".entitydetails"); } } @@ -2644,79 +2597,81 @@

Source: src/js/views/MetadataView.js

/* * Inserts new image elements into the DOM via the image template. Use for displaying images that are part of this metadata's resource map. */ - insertDataDetails: function () { - //If there is a metadataIndex subview, render from there. - var metadataFromIndex = _.findWhere(this.subviews, { + insertDataDetails() { + // If there is a metadataIndex subview, render from there. + const metadataFromIndex = _.findWhere(this.subviews, { type: "MetadataIndex", }); if (typeof metadataFromIndex !== "undefined") { - _.each(this.packageModels, function (packageModel) { + _.each(this.packageModels, (packageModel) => { metadataFromIndex.insertDataDetails(packageModel); }); return; } - var viewRef = this; + const viewRef = this; - _.each(this.packageModels, function (packageModel) { - var dataDisplay = "", - images = [], - other = [], - packageMembers = packageModel.get("members"); + _.each(this.packageModels, (packageModel) => { + const dataDisplay = ""; + const images = []; + const other = []; + const packageMembers = packageModel.get("members"); - //Don't do this for large packages + // Don't do this for large packages if (packageMembers.length > 150) return; - //==== Loop over each visual object and create a dataDisplay template for it to attach to the DOM ==== - _.each(packageMembers, function (solrResult, i) { - //Don't display any info about nested packages + //= === Loop over each visual object and create a dataDisplay template for it to attach to the DOM ==== + _.each(packageMembers, (solrResult, i) => { + // Don't display any info about nested packages if (solrResult.type == "Package") return; - var objID = solrResult.get("id"); + const objID = solrResult.get("id"); if (objID == viewRef.pid) return; - //Is this a visual object (image)? - var type = + // Is this a visual object (image)? + const type = solrResult.type == "SolrResult" ? solrResult.getType() : "Data set"; if (type == "image") images.push(solrResult); - //Find the part of the HTML Metadata view that describes this data object - var anchor = $(document.createElement("a")).attr( - "id", - objID.replace(/[^A-Za-z0-9]/g, "-"), - ), - container = viewRef.findEntityDetailsContainer(objID); + // Find the part of the HTML Metadata view that describes this data object + const anchor = $(document.createElement("a")).attr( + "id", + objID.replace(/[^A-Za-z0-9]/g, "-"), + ); + const container = viewRef.findEntityDetailsContainer(objID); - var downloadButton = new DownloadButtonView({ model: solrResult }); + const downloadButton = new DownloadButtonView({ + model: solrResult, + }); downloadButton.render(); - //Insert the data display HTML and the anchor tag to mark this spot on the page + // Insert the data display HTML and the anchor tag to mark this spot on the page if (container) { - //Only show data displays for images hosted on the same origin + // Only show data displays for images hosted on the same origin if (type == "image") { - //Create the data display HTML - var dataDisplay = $.parseHTML( + // Create the data display HTML + const dataDisplay = $.parseHTML( viewRef .dataDisplayTemplate({ - type: type, + type, src: solrResult.get("url"), - objID: objID, + objID, }) .trim(), ); - //Insert into the page + // Insert into the page if ($(container).children("label").length > 0) $(container).children("label").first().after(dataDisplay); else $(container).prepend(dataDisplay); - //If this image is private, we need to load it via an XHR request + // If this image is private, we need to load it via an XHR request if (!solrResult.get("isPublic")) { - //Create an XHR - var xhr = new XMLHttpRequest(); + // Create an XHR + const xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.onload = function () { @@ -2726,12 +2681,12 @@

Source: src/js/views/MetadataView.js

.attr("src", window.URL.createObjectURL(xhr.response)); }; - //Open and send the request with the user's auth token + // Open and send the request with the user's auth token xhr.open("GET", solrResult.get("url")); xhr.responseType = "blob"; xhr.setRequestHeader( "Authorization", - "Bearer " + MetacatUI.appUserModel.get("token"), + `Bearer ${MetacatUI.appUserModel.get("token")}`, ); xhr.send(); } @@ -2739,7 +2694,7 @@

Source: src/js/views/MetadataView.js

$(container).prepend(anchor); - var nameLabel = $(container).find( + const nameLabel = $(container).find( "label:contains('Entity Name')", ); if (nameLabel.length) { @@ -2748,65 +2703,60 @@

Source: src/js/views/MetadataView.js

} }); - //==== Initialize the fancybox images ===== + //= === Initialize the fancybox images ===== // We will be checking every half-second if all the HTML has been loaded into the DOM - once they are all loaded, we can initialize the lightbox functionality. - var numImages = images.length, - //The shared lightbox options for both images - lightboxOptions = { - prevEffect: "elastic", - nextEffect: "elastic", - closeEffect: "elastic", - openEffect: "elastic", - aspectRatio: true, - closeClick: true, - afterLoad: function () { - //Create a custom HTML caption based on data stored in the DOM element - viewRef.title = - viewRef.title + - " <a href='" + - viewRef.href + - "' class='btn' target='_blank'>Download</a> "; - }, - helpers: { - title: { - type: "outside", - }, + const numImages = images.length; + // The shared lightbox options for both images + const lightboxOptions = { + prevEffect: "elastic", + nextEffect: "elastic", + closeEffect: "elastic", + openEffect: "elastic", + aspectRatio: true, + closeClick: true, + afterLoad() { + // Create a custom HTML caption based on data stored in the DOM element + viewRef.title = `${viewRef.title} <a href='${viewRef.href}' class='btn' target='_blank'>Download</a> `; + }, + helpers: { + title: { + type: "outside", }, - }; + }, + }; if (numImages > 0) { - var numImgChecks = 0, //Keep track of how many interval checks we have so we don't wait forever for images to load - lightboxImgSelector = - "a[class^='fancybox'][data-fancybox-type='image']"; + let numImgChecks = 0; // Keep track of how many interval checks we have so we don't wait forever for images to load + const lightboxImgSelector = + "a[class^='fancybox'][data-fancybox-type='image']"; - //Add additional options for images - var imgLightboxOptions = lightboxOptions; + // Add additional options for images + const imgLightboxOptions = lightboxOptions; imgLightboxOptions.type = "image"; imgLightboxOptions.perload = 1; - var initializeImgLightboxes = function () { + const initializeImgLightboxes = function () { numImgChecks++; - //Initialize what images have loaded so far after 5 seconds + // Initialize what images have loaded so far after 5 seconds if (numImgChecks == 10) { $(lightboxImgSelector).fancybox(imgLightboxOptions); } - //When 15 seconds have passed, stop checking so we don't blow up the browser + // When 15 seconds have passed, stop checking so we don't blow up the browser else if (numImgChecks > 30) { $(lightboxImgSelector).fancybox(imgLightboxOptions); window.clearInterval(imgIntervalID); return; } - //Are all of our images loaded yet? + // Are all of our images loaded yet? if (viewRef.$(lightboxImgSelector).length < numImages) return; - else { - //Initialize our lightboxes - $(lightboxImgSelector).fancybox(imgLightboxOptions); - //We're done - clear the interval - window.clearInterval(imgIntervalID); - } + // Initialize our lightboxes + $(lightboxImgSelector).fancybox(imgLightboxOptions); + + // We're done - clear the interval + window.clearInterval(imgIntervalID); }; var imgIntervalID = window.setInterval( @@ -2817,22 +2767,22 @@

Source: src/js/views/MetadataView.js

}); }, - replaceEcoGridLinks: function () { - var viewRef = this; + replaceEcoGridLinks() { + const viewRef = this; - //Find the element in the DOM housing the ecogrid link - $("a:contains('ecogrid://')").each(function (i, thisLink) { - //Get the link text - var linkText = $(thisLink).text(); + // Find the element in the DOM housing the ecogrid link + $("a:contains('ecogrid://')").each((i, thisLink) => { + // Get the link text + const linkText = $(thisLink).text(); - //Clean up the link text - var withoutPrefix = linkText.substring( - linkText.indexOf("ecogrid://") + 10, - ), - pid = withoutPrefix.substring(withoutPrefix.indexOf("/") + 1), - baseUrl = - MetacatUI.appModel.get("resolveServiceUrl") || - MetacatUI.appModel.get("objectServiceUrl"); + // Clean up the link text + const withoutPrefix = linkText.substring( + linkText.indexOf("ecogrid://") + 10, + ); + const pid = withoutPrefix.substring(withoutPrefix.indexOf("/") + 1); + const baseUrl = + MetacatUI.appModel.get("resolveServiceUrl") || + MetacatUI.appModel.get("objectServiceUrl"); $(thisLink) .attr("href", baseUrl + encodeURIComponent(pid)) @@ -2840,68 +2790,65 @@

Source: src/js/views/MetadataView.js

}); }, - publish: function (event) { + publish(event) { // target may not actually prevent click events, so double check - var disabled = $(event.target).closest("a").attr("disabled"); + const disabled = $(event.target).closest("a").attr("disabled"); if (disabled) { return false; } - var publishServiceUrl = MetacatUI.appModel.get("publishServiceUrl"); - var pid = $(event.target).closest("a").attr("pid"); - var ret = confirm( - "Are you sure you want to publish " + pid + " with a DOI?", + const publishServiceUrl = MetacatUI.appModel.get("publishServiceUrl"); + const pid = $(event.target).closest("a").attr("pid"); + const ret = confirm( + `Are you sure you want to publish ${pid} with a DOI?`, ); if (ret) { // show the loading icon - var message = "Publishing package...this may take a few moments"; + const message = "Publishing package...this may take a few moments"; this.showLoading(message); - var identifier = null; - var viewRef = this; - var requestSettings = { + let identifier = null; + const viewRef = this; + const requestSettings = { url: publishServiceUrl + pid, type: "PUT", xhrFields: { withCredentials: true, }, - success: function (data, textStatus, xhr) { + success(data, textStatus, xhr) { // the response should have new identifier in it identifier = $(data).find("d1\\:identifier, identifier").text(); if (identifier) { viewRef.hideLoading(); - var msg = - "Published data package '" + - identifier + - "'. If you are not redirected soon, you can view your <a href='" + - MetacatUI.root + - "/view/" + - encodeURIComponent(identifier) + - "'>published data package here</a>"; + const msg = `Published data package '${identifier}'. If you are not redirected soon, you can view your <a href='${ + MetacatUI.root + }/view/${encodeURIComponent( + identifier, + )}'>published data package here</a>`; viewRef.$el.find(".container").prepend( viewRef.alertTemplate({ - msg: msg, + msg, classes: "alert-success", }), ); // navigate to the new view after a few seconds - setTimeout(function () { + setTimeout(() => { // avoid a double fade out/in viewRef.$el.html(""); viewRef.showLoading(); - MetacatUI.uiRouter.navigate("view/" + identifier, { + MetacatUI.uiRouter.navigate(`view/${identifier}`, { trigger: true, }); }, 3000); } }, - error: function (xhr, textStatus, errorThrown) { + error(xhr, textStatus, errorThrown) { // show the error message, but stay on the same page - var msg = - "Publish failed: " + - $(xhr.responseText).find("description").text(); + const msg = `Publish failed: ${$(xhr.responseText) + .find("description") + .text()}`; viewRef.hideLoading(); viewRef.showError(msg); @@ -2917,25 +2864,25 @@

Source: src/js/views/MetadataView.js

} }, - //When the given ID from the URL is a resource map that has no metadata, do the following... - noMetadata: function (solrResultModel) { + // When the given ID from the URL is a resource map that has no metadata, do the following... + noMetadata(solrResultModel) { this.hideLoading(); this.$el.html(this.template()); this.pid = solrResultModel.get("resourceMap") || solrResultModel.get("id"); - //Insert breadcrumbs + // Insert breadcrumbs this.insertBreadcrumbs(); this.insertDataSource(); - //Insert a table of contents + // Insert a table of contents this.insertPackageTable(solrResultModel); this.renderMetadataFromIndex(); - //Insert a message that this data is not described by metadata + // Insert a message that this data is not described by metadata MetacatUI.appView.showAlert( "Additional information about this data is limited since metadata was not provided by the creator.", "alert-warning", @@ -2944,19 +2891,19 @@

Source: src/js/views/MetadataView.js

}, // this will lookup the latest version of the PID - showLatestVersion: function () { - //If this metadata doc is not obsoleted by a new version, then exit the function + showLatestVersion() { + // If this metadata doc is not obsoleted by a new version, then exit the function if (!this.model.get("obsoletedBy")) { return; } - var view = this; + const view = this; - //When the latest version is found, - this.listenTo(this.model, "change:newestVersion", function () { - //Make sure it has a newer version, and if so, + // When the latest version is found, + this.listenTo(this.model, "change:newestVersion", () => { + // Make sure it has a newer version, and if so, if (view.model.get("newestVersion") != view.model.get("id")) { - //Put a link to the newest version in the content + // Put a link to the newest version in the content view.$(".newer-version").replaceWith( view.versionTemplate({ pid: view.model.get("newestVersion"), @@ -2967,23 +2914,23 @@

Source: src/js/views/MetadataView.js

} }); - //Insert the newest version template with a loading message + // Insert the newest version template with a loading message this.$el.prepend( this.versionTemplate({ loading: true, }), ); - //Find the latest version of this metadata object + // Find the latest version of this metadata object this.model.findLatestVersion(); }, - showLoading: function (message) { + showLoading(message) { this.hideLoading(); MetacatUI.appView.scrollToTop(); - var loading = this.loadingTemplate({ msg: message }); + const loading = this.loadingTemplate({ msg: message }); if (!loading) return; this.$loading = $($.parseHTML(loading)); @@ -2992,18 +2939,18 @@

Source: src/js/views/MetadataView.js

this.$el.html(loading); }, - hideLoading: function () { + hideLoading() { if (this.$loading) this.$loading.remove(); if (this.$detached) this.$el.html(this.$detached); }, - showError: function (msg) { - //Remove any existing error messages + showError(msg) { + // Remove any existing error messages this.$el.children(".alert-container").remove(); this.$el.prepend( this.alertTemplate({ - msg: msg, + msg, classes: "alert-error", containerClasses: "page", includeEmail: true, @@ -3015,18 +2962,19 @@

Source: src/js/views/MetadataView.js

* When the "Metadata" button in the table is clicked while we are on the Metadata view, * we want to scroll to the anchor tag of this data object within the page instead of navigating * to the metadata page again, which refreshes the page and re-renders (more loading time) - **/ - previewData: function (e) { - //Don't go anywhere yet... + * @param e + */ + previewData(e) { + // Don't go anywhere yet... e.preventDefault(); - //Get the target and id of the click - var link = $(e.target); + // Get the target and id of the click + let link = $(e.target); if (!$(link).hasClass("preview")) link = $(link).parents("a.preview"); if (link) { var id = $(link).attr("data-id"); - if (typeof id === "undefined" || !id) return false; //This will make the app defualt to the child view previewData function + if (typeof id === "undefined" || !id) return false; // This will make the app defualt to the child view previewData function } else return false; // If we are on the Metadata view, update the URL and scroll to the @@ -3045,18 +2993,18 @@

Source: src/js/views/MetadataView.js

* element on the page set to an XML-safe version of the value in the * fragment/hash. Used to provide direct links to sub-resources on a page. */ - scrollToFragment: function () { - var hash = window.location.hash; + scrollToFragment() { + const { hash } = window.location; if (!hash || hash.length <= 1) { return; } - //Get the id from the URL hash and decode it - var idFragment = decodeURIComponent(hash.substring(1)); + // Get the id from the URL hash and decode it + const idFragment = decodeURIComponent(hash.substring(1)); - //Find the corresponding entity details section for this id - var entityDetailsEl = this.findEntityDetailsContainer(idFragment); + // Find the corresponding entity details section for this id + const entityDetailsEl = this.findEntityDetailsContainer(idFragment); if (entityDetailsEl || entityDetailsEl.length) { MetacatUI.appView.scrollTo(entityDetailsEl); @@ -3070,25 +3018,24 @@

Source: src/js/views/MetadataView.js

* is not a metadata PID but is, instead, a data PID. getModel() does * the work of finding an appropriate metadata PID for the data PID and * this method handles re-routing to the correct URL. - * * @param {string} metadata_pid - The new metadata PID * @param {string} data_pid - Optional. A data PID that's part of the * package metadata_pid exists within. */ - navigateWithFragment: function (metadata_pid, data_pid) { - var next_route = "view/" + encodeURIComponent(metadata_pid); + navigateWithFragment(metadata_pid, data_pid) { + let next_route = `view/${encodeURIComponent(metadata_pid)}`; if (typeof data_pid === "string" && data_pid.length > 0) { - next_route += "#" + encodeURIComponent(data_pid); + next_route += `#${encodeURIComponent(data_pid)}`; } MetacatUI.uiRouter.navigate(next_route, { trigger: true }); }, - closePopovers: function (e) { - //If this is a popover element or an element that has a popover, don't close anything. - //Check with the .classList attribute to account for SVG elements - var svg = $(e.target).parents("svg"); + closePopovers(e) { + // If this is a popover element or an element that has a popover, don't close anything. + // Check with the .classList attribute to account for SVG elements + const svg = $(e.target).parents("svg"); if ( _.contains(e.target.classList, "popover-this") || @@ -3099,38 +3046,38 @@

Source: src/js/views/MetadataView.js

) return; - //Close all active popovers + // Close all active popovers this.$(".popover-this.active").popover("hide"); }, - highlightNode: function (e) { - //Find the id - var id = $(e.target).attr("data-id"); + highlightNode(e) { + // Find the id + let id = $(e.target).attr("data-id"); if (typeof id === "undefined" || !id) id = $(e.target).parents("[data-id]").attr("data-id"); - //If there is no id, return + // If there is no id, return if (typeof id === "undefined") return false; - //Highlight its node - $(".prov-chart .node[data-id='" + id + "']").toggleClass("active"); + // Highlight its node + $(`.prov-chart .node[data-id='${id}']`).toggleClass("active"); - //Highlight its metadata section + // Highlight its metadata section if (MetacatUI.appModel.get("pid") == id) this.$("#Metadata").toggleClass("active"); else { - var entityDetails = this.findEntityDetailsContainer(id); + const entityDetails = this.findEntityDetailsContainer(id); if (entityDetails) entityDetails.toggleClass("active"); } }, - onClose: function () { - var viewRef = this; + onClose() { + const viewRef = this; this.stopListening(); - _.each(this.subviews, function (subview) { + _.each(this.subviews, (subview) => { if (subview.onClose) subview.onClose(); }); @@ -3142,10 +3089,10 @@

Source: src/js/views/MetadataView.js

this.$detached = null; this.$loading = null; - //Put the document title back to the default + // Put the document title back to the default MetacatUI.appModel.resetTitle(); - //Remove view-specific classes + // Remove view-specific classes this.$el.removeClass("container no-stylesheet"); this.$el.empty(); @@ -3156,18 +3103,19 @@

Source: src/js/views/MetadataView.js

* a dataset citation from the value stored in the underlying model's * origin field. */ - getAuthorText: function () { - var authors = this.model.get("origin"), - count = 0, - authorText = ""; + getAuthorText() { + const authors = this.model.get("origin"); + let count = 0; + let authorText = ""; - _.each(authors, function (author) { + _.each(authors, (author) => { count++; if (count == 6) { authorText += ", et al. "; return; - } else if (count > 6) { + } + if (count > 6) { return; } @@ -3196,29 +3144,27 @@

Source: src/js/views/MetadataView.js

* dataset citation. This method falls back to the node ID when the proper * node name cannot be fetched from the app's NodeModel instance. */ - getPublisherText: function () { - var datasource = this.model.get("datasource"), - memberNode = MetacatUI.nodeModel.getMember(datasource); + getPublisherText() { + const datasource = this.model.get("datasource"); + const memberNode = MetacatUI.nodeModel.getMember(datasource); if (memberNode) { return memberNode.name; - } else { - return datasource; } + return datasource; }, /** * Generate a string appropriate to be used as the publication date in a * dataset citation. */ - getDatePublishedText: function () { + getDatePublishedText() { // Dataset/datePublished // Prefer pubDate, fall back to dateUploaded so we have something to show if (this.model.get("pubDate") !== "") { return this.model.get("pubDate"); - } else { - return this.model.get("dateUploaded"); } + return this.model.get("dateUploaded"); }, /** @@ -3228,27 +3174,27 @@

Source: src/js/views/MetadataView.js

* Note: `insertJSONLD` should be called to do the actual inserting into the * DOM. */ - generateJSONLD: function () { - var model = this.model; + generateJSONLD() { + const { model } = this; // Determine the path (either #view or view, depending on router // configuration) for use in the 'url' property - var href = document.location.href, - route = href - .replace(document.location.origin + "/", "") - .split("/")[0]; + const { href } = document.location; + const route = href + .replace(`${document.location.origin}/`, "") + .split("/")[0]; // First: Create a minimal Schema.org Dataset with just the fields we // know will come back from Solr (System Metadata fields). // Add the rest in conditional on whether they are present. - var elJSON = { + const elJSON = { "@context": { "@vocab": "https://schema.org/", }, "@type": "Dataset", - "@id": - "https://dataone.org/datasets/" + - encodeURIComponent(model.get("id")), + "@id": `https://dataone.org/datasets/${encodeURIComponent( + model.get("id"), + )}`, datePublished: this.getDatePublishedText(), dateModified: model.get("dateModified"), publisher: { @@ -3257,9 +3203,9 @@

Source: src/js/views/MetadataView.js

}, identifier: this.generateSchemaOrgIdentifier(model.get("id")), version: model.get("version"), - url: - "https://dataone.org/datasets/" + - encodeURIComponent(model.get("id")), + url: `https://dataone.org/datasets/${encodeURIComponent( + model.get("id"), + )}`, schemaVersion: model.get("formatId"), isAccessibleForFree: true, }; @@ -3267,10 +3213,10 @@

Source: src/js/views/MetadataView.js

// Attempt to add in a sameAs property of we have high confidence the // identifier is a DOI if (this.model.isDOI(model.get("id"))) { - var doi = this.getCanonicalDOIIRI(model.get("id")); + const doi = this.getCanonicalDOIIRI(model.get("id")); if (doi) { - elJSON["sameAs"] = doi; + elJSON.sameAs = doi; } } @@ -3278,17 +3224,15 @@

Source: src/js/views/MetadataView.js

// Name if (model.get("title")) { - elJSON["name"] = model.get("title"); + elJSON.name = model.get("title"); } // Creator if (model.get("origin")) { - elJSON["creator"] = model.get("origin").map(function (creator) { - return { - "@type": "Person", - name: creator, - }; - }); + elJSON.creator = model.get("origin").map((creator) => ({ + "@type": "Person", + name: creator, + })); } // Dataset/spatialCoverage @@ -3298,7 +3242,7 @@

Source: src/js/views/MetadataView.js

model.get("southBoundCoord") && model.get("westBoundCoord") ) { - var spatialCoverage = { + const spatialCoverage = { "@type": "Place", additionalProperty: [ { @@ -3334,8 +3278,7 @@

Source: src/js/views/MetadataView.js

if (model.get("beginDate") && !model.get("endDate")) { elJSON.temporalCoverage = model.get("beginDate"); } else if (model.get("beginDate") && model.get("endDate")) { - elJSON.temporalCoverage = - model.get("beginDate") + "/" + model.get("endDate"); + elJSON.temporalCoverage = `${model.get("beginDate")}/${model.get("endDate")}`; } // Dataset/variableMeasured @@ -3347,13 +3290,10 @@

Source: src/js/views/MetadataView.js

if (model.get("abstract")) { elJSON.description = model.get("abstract"); } else { - var datasets_url = - "https://dataone.org/datasets/" + - encodeURIComponent(model.get("id")); - elJSON.description = - "No description is available. Visit " + - datasets_url + - " for complete metadata about this dataset."; + const datasets_url = `https://dataone.org/datasets/${encodeURIComponent( + model.get("id"), + )}`; + elJSON.description = `No description is available. Visit ${datasets_url} for complete metadata about this dataset.`; } // Dataset/keywords @@ -3367,7 +3307,6 @@

Source: src/js/views/MetadataView.js

/** * Insert Schema.org-compliant JSONLD for the model bound to the view into * the head tag of the page (at the end). - * * @param {object} json - JSON-LD to insert into the page * * Some notes: @@ -3376,15 +3315,15 @@

Source: src/js/views/MetadataView.js

* - If not create a new script tag and append otherwise replace the text * for the script */ - insertJSONLD: function (json) { + insertJSONLD(json) { if (!document.getElementById("jsonld")) { - var el = document.createElement("script"); + const el = document.createElement("script"); el.type = "application/ld+json"; el.id = "jsonld"; el.text = JSON.stringify(json); document.querySelector("head").appendChild(el); } else { - var script = document.getElementById("jsonld"); + const script = document.getElementById("jsonld"); script.text = JSON.stringify(json); } }, @@ -3394,15 +3333,14 @@

Source: src/js/views/MetadataView.js

* * Tries to use the PropertyValue pattern when the identifier is a DOI * and falls back to a Text value otherwise - * * @param {string} identifier - The raw identifier */ - generateSchemaOrgIdentifier: function (identifier) { + generateSchemaOrgIdentifier(identifier) { if (!this.model.isDOI()) { return identifier; } - var doi = this.getCanonicalDOIIRI(identifier); + const doi = this.getCanonicalDOIIRI(identifier); if (!doi) { return identifier; @@ -3421,20 +3359,23 @@

Source: src/js/views/MetadataView.js

* * Either generates a GeoCoordinates (when the north and east coords are * the same) or a GeoShape otherwise. + * @param north + * @param east + * @param south + * @param west */ - generateSchemaOrgGeo: function (north, east, south, west) { + generateSchemaOrgGeo(north, east, south, west) { if (north === south) { return { "@type": "GeoCoordinates", latitude: north, longitude: west, }; - } else { - return { - "@type": "GeoShape", - box: west + ", " + south + " " + east + ", " + north, - }; } + return { + "@type": "GeoShape", + box: `${west}, ${south} ${east}, ${north}`, + }; }, /** @@ -3452,46 +3393,41 @@

Source: src/js/views/MetadataView.js

* * e.g., if the east bounding coordinate is 120 W and west bounding * coordinate is 140 E, geoJSON requires we specify 140 E as 220 - * * @param {number} north - North bounding coordinate * @param {number} east - East bounding coordinate * @param {number} south - South bounding coordinate * @param {number} west - West bounding coordinate */ - generateGeoJSONString: function (north, east, south, west) { + generateGeoJSONString(north, east, south, west) { if (north === south) { return this.generateGeoJSONPoint(north, east); - } else { - return this.generateGeoJSONPolygon(north, east, south, west); } + return this.generateGeoJSONPolygon(north, east, south, west); }, /** - * Generate a GeoJSON Point object - * - * @param {number} north - North bounding coordinate - * @param {number} east - East bounding coordinate - * - * Example: - * { - * "type": "Point", - * "coordinates": [ - * -105.01621, - * 39.57422 - * ]} - - */ - generateGeoJSONPoint: function (north, east) { - var preamble = '{"type":"Point","coordinates":', - inner = "[" + east + "," + north + "]", - postamble = "}"; + * Generate a GeoJSON Point object + * @param {number} north - North bounding coordinate + * @param {number} east - East bounding coordinate + * + * Example: + * { + * "type": "Point", + * "coordinates": [ + * -105.01621, + * 39.57422 + * ]} + */ + generateGeoJSONPoint(north, east) { + const preamble = '{"type":"Point","coordinates":'; + const inner = `[${east},${north}]`; + const postamble = "}"; return preamble + inner + postamble; }, /** * Generate a GeoJSON Polygon object from - * * @param {number} north - North bounding coordinate * @param {number} east - East bounding coordinate * @param {number} south - South bounding coordinate @@ -3509,10 +3445,9 @@

Source: src/js/views/MetadataView.js

* [ 100, 1 ], * [ 100, 0 ] * ]} - * */ - generateGeoJSONPolygon: function (north, east, south, west) { - var preamble = + generateGeoJSONPolygon(north, east, south, west) { + const preamble = '{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[['; // Handle the case when the polygon wraps across the 180W/180E boundary @@ -3520,44 +3455,24 @@

Source: src/js/views/MetadataView.js

east = 360 - east; } - var inner = - "[" + - west + - "," + - south + - "]," + - "[" + - east + - "," + - south + - "]," + - "[" + - east + - "," + - north + - "]," + - "[" + - west + - "," + - north + - "]," + - "[" + - west + - "," + - south + - "]"; - - var postamble = "]]}}"; + const inner = + `[${west},${south}],` + + `[${east},${south}],` + + `[${east},${north}],` + + `[${west},${north}],` + + `[${west},${south}]`; + + const postamble = "]]}}"; return preamble + inner + postamble; }, /** * Create a canonical IRI for a DOI given a random DataONE identifier. - * * @param {string} identifier: The identifier to (possibly) create the IRI * for. - * @return {string|null} Returns null when matching the identifier to a DOI + * @param identifier + * @returns {string|null} Returns null when matching the identifier to a DOI * regex fails or a string when the match is successful * * Useful for describing resources identified by DOIs in linked open data @@ -3565,7 +3480,7 @@

Source: src/js/views/MetadataView.js

* * Note: Really could be generalized to more identifier schemes. */ - getCanonicalDOIIRI: function (identifier) { + getCanonicalDOIIRI(identifier) { return MetacatUI.appModel.DOItoURL(identifier) || null; }, @@ -3575,26 +3490,26 @@

Source: src/js/views/MetadataView.js

* Currently supports Highwire Press style tags (citation_) which is * supposedly what Google (Scholar), Mendeley, and Zotero support. */ - insertCitationMetaTags: function () { + insertCitationMetaTags() { // Generate template data to use for all templates - var title = this.model.get("title"), - authors = this.model.get("origin"), - publisher = this.getPublisherText(), - date = new Date(this.getDatePublishedText()) - .getUTCFullYear() - .toString(), - isDOI = this.model.isDOI(this.model.get("id")), - id = this.model.get("id"), - abstract = this.model.get("abstract"); + const title = this.model.get("title"); + const authors = this.model.get("origin"); + const publisher = this.getPublisherText(); + const date = new Date(this.getDatePublishedText()) + .getUTCFullYear() + .toString(); + const isDOI = this.model.isDOI(this.model.get("id")); + const id = this.model.get("id"); + const abstract = this.model.get("abstract"); // Generate HTML strings from each template - var hwpt = this.metaTagsHighwirePressTemplate({ - title: title, - authors: authors, - publisher: publisher, - date: date, - isDOI: isDOI, - id: id, + const hwpt = this.metaTagsHighwirePressTemplate({ + title, + authors, + publisher, + date, + isDOI, + id, abstract, }); @@ -3620,12 +3535,12 @@

Source: src/js/views/MetadataView.js

); }, - createAnnotationViews: function () { + createAnnotationViews() { try { - var viewRef = this; + const viewRef = this; - _.each($(".annotation"), function (annoEl) { - var newView = new AnnotationView({ + _.each($(".annotation"), (annoEl) => { + const newView = new AnnotationView({ el: annoEl, }); viewRef.subviews.push(newView); @@ -3635,11 +3550,11 @@

Source: src/js/views/MetadataView.js

} }, - insertMarkdownViews: function () { - var viewRef = this; + insertMarkdownViews() { + const viewRef = this; - _.each($(".markdown"), function (markdownEl) { - var newView = new MarkdownView({ + _.each($(".markdown"), (markdownEl) => { + const newView = new MarkdownView({ markdown: $(markdownEl).text().trim(), el: $(markdownEl).parent(), }); @@ -3653,12 +3568,27 @@

Source: src/js/views/MetadataView.js

}); }, - storeEntityPIDs: function (responseEl) { - var view = this; - _.each($(responseEl).find(".entitydetails"), function (entityEl) { - var entityId = $(entityEl).data("id"); - view.entities.push(entityId.replace("urn-uuid-", "urn:uuid:")); - }); + storeEntityPIDs(entityEl, entityId) { + let entityPID = entityId; + // Get the entity ID if it is null or undefined + if (entityPID == null) entityPID = $(entityEl).data("id"); + + // Perform clean up with the entity ID + if (entityPID && typeof entityPID === "string") { + // Check and replace urn-uuid- with urn:uuid: if the string starts with urn-uuid- + if (entityPID.startsWith("urn-uuid-")) { + entityPID = entityPID.replace("urn-uuid-", "urn:uuid:"); + } + + // Check and replace doi-10. with doi:10. if the string starts with doi-10. + if (entityPID.startsWith("doi-10.")) { + entityPID = entityPID.replace("doi-10.", "doi:10."); + } + } + + if (!this.entities.includes(entityPID)) { + this.entities.push(entityPID); + } }, }, ); diff --git a/docs/docs/src_js_views_MetricModalView.js.html b/docs/docs/src_js_views_MetricModalView.js.html index e8448a3a2..f50cf7a02 100644 --- a/docs/docs/src_js_views_MetricModalView.js.html +++ b/docs/docs/src_js_views_MetricModalView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_MetricView.js.html b/docs/docs/src_js_views_MetricView.js.html index 7c0221641..11d6e845d 100644 --- a/docs/docs/src_js_views_MetricView.js.html +++ b/docs/docs/src_js_views_MetricView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_MetricsChartView.js.html b/docs/docs/src_js_views_MetricsChartView.js.html index 1e3206b4a..8c937356c 100644 --- a/docs/docs/src_js_views_MetricsChartView.js.html +++ b/docs/docs/src_js_views_MetricsChartView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_NavbarView.js.html b/docs/docs/src_js_views_NavbarView.js.html index ded320131..4a99e72d9 100644 --- a/docs/docs/src_js_views_NavbarView.js.html +++ b/docs/docs/src_js_views_NavbarView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_RegisterCitationView.js.html b/docs/docs/src_js_views_RegisterCitationView.js.html index 078ecab52..f57392098 100644 --- a/docs/docs/src_js_views_RegisterCitationView.js.html +++ b/docs/docs/src_js_views_RegisterCitationView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_SignInView.js.html b/docs/docs/src_js_views_SignInView.js.html index 0be727837..f816125b1 100644 --- a/docs/docs/src_js_views_SignInView.js.html +++ b/docs/docs/src_js_views_SignInView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_StatsView.js.html b/docs/docs/src_js_views_StatsView.js.html index cb566bf39..6ac592240 100644 --- a/docs/docs/src_js_views_StatsView.js.html +++ b/docs/docs/src_js_views_StatsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -54,6 +54,7 @@

Source: src/js/views/StatsView.js

"DonutChart", "CircleBadge", "collections/Citations", + "common/Utilities", "models/MetricsModel", "models/Stats", "MetricsChart", @@ -73,6 +74,7 @@

Source: src/js/views/StatsView.js

DonutChart, CircleBadge, Citations, + Utilities, MetricsModel, StatsModel, MetricsChart, @@ -969,12 +971,13 @@

Source: src/js/views/StatsView.js

displayTotalSize: function () { var className = "quick-stats-count"; var count = ""; + var view = this; if (!this.model.get("totalSize")) { count = "0 bytes"; className += " no-activity"; } else { - count = this.bytesToSize(this.model.get("totalSize")); + count = Utilities.bytesToSize(view.model.get("totalSize")); } var countEl = $(document.createElement("p")) @@ -1149,36 +1152,6 @@

Source: src/js/views/StatsView.js

} }, - /** - * Convert number of bytes into human readable format - * - * @param integer bytes Number of bytes to convert - * @param integer precision Number of digits after the decimal separator - * @return string - */ - bytesToSize: function (bytes, precision) { - var kibibyte = 1024; - var mebibyte = kibibyte * 1024; - var gibibyte = mebibyte * 1024; - var tebibyte = gibibyte * 1024; - - if (typeof bytes === "undefined") var bytes = this.get("size"); - - if (bytes >= 0 && bytes < kibibyte) { - return bytes + " B"; - } else if (bytes >= kibibyte && bytes < mebibyte) { - return (bytes / kibibyte).toFixed(precision) + " KiB"; - } else if (bytes >= mebibyte && bytes < gibibyte) { - return (bytes / mebibyte).toFixed(precision) + " MiB"; - } else if (bytes >= gibibyte && bytes < tebibyte) { - return (bytes / gibibyte).toFixed(precision) + " GiB"; - } else if (bytes >= tebibyte) { - return (bytes / tebibyte).toFixed(precision) + " TiB"; - } else { - return bytes + " B"; - } - }, - renderUsageMetricsError: function () { var message = "<p class='check-back-message'><strong>This might take some time. Check back in 24 hours to see these results.</strong></p>"; diff --git a/docs/docs/src_js_views_TOCView.js.html b/docs/docs/src_js_views_TOCView.js.html index 7bfbc5b92..4602dba81 100644 --- a/docs/docs/src_js_views_TOCView.js.html +++ b/docs/docs/src_js_views_TOCView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_TableEditorView.js.html b/docs/docs/src_js_views_TableEditorView.js.html index e2422c0fd..a9a815df3 100644 --- a/docs/docs/src_js_views_TableEditorView.js.html +++ b/docs/docs/src_js_views_TableEditorView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_UserGroupView.js.html b/docs/docs/src_js_views_UserGroupView.js.html index a2c7f02cd..9205ebdc2 100644 --- a/docs/docs/src_js_views_UserGroupView.js.html +++ b/docs/docs/src_js_views_UserGroupView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_UserView.js.html b/docs/docs/src_js_views_UserView.js.html index 674269f65..9c81dcef8 100644 --- a/docs/docs/src_js_views_UserView.js.html +++ b/docs/docs/src_js_views_UserView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_accordion_AccordionItemView.js.html b/docs/docs/src_js_views_accordion_AccordionItemView.js.html new file mode 100644 index 000000000..36b8b5654 --- /dev/null +++ b/docs/docs/src_js_views_accordion_AccordionItemView.js.html @@ -0,0 +1,183 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/accordion/AccordionItemView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/accordion/AccordionItemView.js

+ + + + + + +
+
+
define(["jquery", "backbone", "semantic", "models/accordion/AccordionItem"], (
+  $,
+  Backbone,
+  Semantic,
+  AccordionItem,
+) => {
+  // Base class for the view
+  const BASE_CLASS = "accordion-item";
+
+  /**
+   * @class AccordionItemView
+   * @classdesc A view representing an accordion item with a title and content
+   * @classcategory Views/Accordion
+   * @augments Backbone.View
+   * @class
+   * @since 2.31.0
+   * @screenshot views/accordion/AccordionItemViewView.png
+   */
+  const AccordionItemView = Backbone.View.extend(
+    /** @lends AccordionItemView.prototype */
+    {
+      /** @inheritdoc */
+      type: "AccordionItemView",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /** @inheritdoc */
+      tagName: "div",
+
+      /**
+       * An HTML string to use for an icon indicating that the accordion item is
+       * collapsible.
+       * @type {string}
+       */
+      dropdownIconTemplate: `<i class="${Semantic.CLASS_NAMES.accordion.icon}"></i>`,
+
+      /** @inheritdoc */
+      initialize(options) {
+        this.model = options?.model || new AccordionItem();
+      },
+
+      /* Hide the dropdown icon */
+      hideIcon() {
+        this.iconEl.style.display = "none";
+      },
+
+      /* Show the dropdown icon */
+      showIcon() {
+        this.iconEl.style.display = "inline-block";
+      },
+
+      /** @inheritdoc */
+      render() {
+        // Icon
+        const iconContainer = document.createElement("div");
+        iconContainer.innerHTML = this.dropdownIconTemplate;
+        const iconEl = iconContainer.firstChild;
+        this.iconEl = iconEl;
+
+        // Title
+        const titleSpan = document.createElement("span");
+        titleSpan.innerHTML = this.model.get("title");
+        const titleContainer = document.createElement("div");
+        titleContainer.classList.add(Semantic.CLASS_NAMES.accordion.title);
+        titleContainer.appendChild(iconEl);
+        titleContainer.appendChild(titleSpan);
+        this.titleContainer = titleContainer;
+
+        // Content
+        const contentContainer = document.createElement("div");
+        contentContainer.classList.add(Semantic.CLASS_NAMES.accordion.content);
+        this.contentContainer = contentContainer;
+
+        // Put it all together
+        this.el.appendChild(titleContainer);
+        this.el.appendChild(contentContainer);
+        this.updateContent(this.model.get("content"));
+
+        return this;
+      },
+
+      /**
+       * Change the content of the accordion item.
+       * @param {string|HTMLElement|Backbone.View} content - The content to
+       * display.
+       * @param {boolean} [clear] - Whether to clear the existing content.
+       */
+      updateContent(content, clear = true) {
+        const { contentContainer } = this;
+        if (!contentContainer) return;
+        if (clear) {
+          contentContainer.innerHTML = "";
+          this.hideIcon();
+          contentContainer.style.padding = "0";
+        }
+        if (!content) return;
+        if (typeof content === "string") {
+          contentContainer.innerHTML = content;
+        } else if (content instanceof HTMLElement) {
+          contentContainer.appendChild(content);
+        } else if (content instanceof Backbone.View) {
+          contentContainer.appendChild(content.render().el);
+        }
+        this.showIcon();
+        contentContainer.style.padding = "";
+      },
+
+      /*
+       * Remove the view, DOM elements, and its associated popups.
+       */
+      remove() {
+        $(this.titleContainer).popup("destroy");
+        this.titleContainer.remove();
+        this.contentContainer.remove();
+        Backbone.View.prototype.remove.call(this);
+      },
+    },
+  );
+
+  return AccordionItemView;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_accordion_AccordionView.js.html b/docs/docs/src_js_views_accordion_AccordionView.js.html new file mode 100644 index 000000000..ebd6755b7 --- /dev/null +++ b/docs/docs/src_js_views_accordion_AccordionView.js.html @@ -0,0 +1,309 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/accordion/AccordionView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/accordion/AccordionView.js

+ + + + + + +
+
+
define([
+  "jquery",
+  "backbone",
+  "semantic",
+  "views/accordion/AccordionItemView",
+  "models/accordion/Accordion",
+], ($, Backbone, Semantic, AccordionItemView, AccordionModel) => {
+  // The base class for the view
+  const BASE_CLASS = "accordion-view";
+
+  /**
+   * @class AccordionView
+   * @classdesc An extension of the Semantic UI accordion that allows for
+   * defining contents with a Backbone model, and adds tooltips and other
+   * features.
+   * @classcategory Views/Accordion
+   * @augments Backbone.View
+   * @class
+   * @since 2.31.0
+   * @screenshot views/accordion/AccordionView.png
+   */
+  const AccordionView = Backbone.View.extend(
+    /** @lends AccordionView.prototype */
+    {
+      /** @inheritdoc */
+      type: "AccordionView",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /** @inheritdoc */
+      tagName: "div",
+
+      /**
+       * Initializes the AccordionView with the model and listens for changes
+       * to the items collection.
+       * @param {object} options - Options for the view
+       * @param {Accordion} [options.model] - The Accordion model for the view. If
+       * not provided, a new Accordion model will be created.
+       * @param {object} [options.modelData] - Optional data to initialize the
+       * Accordion model with. Only used if options.model is not provided.
+       */
+      initialize(options) {
+        // Set the model to the provided model or create a new one
+        this.model = options?.model || new AccordionModel(options?.modelData);
+
+        this.listenTo(this.model.get("items"), "add", this.addNewItem);
+        this.listenTo(this.model.get("items"), "remove", this.removeItem);
+      },
+
+      /** @inheritdoc */
+      render() {
+        this.initializeAccordion();
+
+        // Start rendering the root, and then the children will be rendered
+        // recursively
+        const rootItems = this.model.getRootItems();
+        const rootAccordion = this.createAccordion(rootItems);
+        this.rootAccordion = rootAccordion;
+
+        this.$el.append(rootAccordion);
+
+        return this;
+      },
+
+      /**
+       * Initializes the Semantic UI accordion module with the settings from the
+       * model. The module handles applying accordion behavior to the view and
+       * any new DOM elements that are added.
+       */
+      initializeAccordion() {
+        const view = this;
+
+        // Gather all the necessary settings from the model
+        const modelJSON = this.model.toJSON();
+        const settings = Object.fromEntries(
+          Object.entries(modelJSON).filter(([key, _]) =>
+            Semantic.ACCORDION_SETTINGS_KEYS.includes(key),
+          ),
+        );
+
+        // Pass the associated model and view to the callback functions instead
+        // only having access to the DOM element as the context
+        const createCallback = (callbackName) => {
+          const originalCallback = this.model.get(callbackName);
+          if (originalCallback) {
+            return function callbackWrapper() {
+              const contentEl = this[0];
+              const itemView = view.viewFromContentEl(contentEl);
+              const itemModel = itemView.model;
+              originalCallback(itemModel, itemView);
+            };
+          }
+          return null;
+        };
+        Semantic.ACCORDION_CALLBACKS.forEach((callbackName) => {
+          const callback = createCallback(callbackName);
+          if (callback) {
+            settings[callbackName] = callback;
+          } else {
+            delete settings[callbackName];
+          }
+        });
+
+        // Initialize the accordion with the specified settings
+        this.$el.accordion(settings);
+      },
+
+      /**
+       * @param {HTMLElement} contentEl A content element from an item
+       * @returns {AccordionItemView} The view associated with the item
+       */
+      viewFromContentEl(contentEl) {
+        const views = Object.values(this.itemViews);
+        return views.find((view) => view.contentContainer === contentEl);
+      },
+
+      /**
+       * Creates a container for the accordion with the necessary classes for
+       * Semantic UI and renders any items belonging to the accordion. This can
+       * be used to create the root accordion or nested accordions.
+       * @param {AccordionItem[]} items - An array of AccordionItem models
+       * @returns {HTMLElement} The container element for the accordion
+       */
+      createAccordion(items) {
+        const accordionContainer = this.createContainer();
+        if (items?.length) this.addItems(items, accordionContainer);
+        return accordionContainer;
+      },
+
+      /**
+       * Creates a container element for the accordion with the necessary
+       * classes
+       * @returns {HTMLElement} The container element for the accordion
+       */
+      createContainer() {
+        const container = document.createElement("div");
+        container.classList.add(
+          Semantic.CLASS_NAMES.accordion.container,
+          Semantic.CLASS_NAMES.base,
+        );
+        container.style.marginTop = 0;
+
+        // Add optional class names based on model properties
+        const optionalClasses = ["fluid", "styled", "inverted"];
+        optionalClasses.forEach((className) => {
+          if (this.model.get(className)) {
+            container.classList.add(Semantic.CLASS_NAMES.variations[className]);
+          }
+        });
+
+        return container;
+      },
+
+      /**
+       * Adds items to the container element for the accordion
+       * @param {AccordionItem[]} models - An array of AccordionItem models
+       * @param {HTMLElement} container - The container element for the
+       * accordion
+       */
+      addItems(models, container) {
+        models.forEach((model) => {
+          this.addItem(model, container);
+        });
+      },
+
+      /**
+       * Adds an item to the container element for the accordion
+       * @param {AccordionItem} model - An AccordionItem model
+       * @param {HTMLElement} container - The container element for the
+       * accordion
+       */
+      addItem(model, container) {
+        const itemView = new AccordionItemView({ model }).render();
+
+        // Semantic UI expects the title and content to be direct children of
+        // the accordion container, important for correct application of CSS
+        container.appendChild(itemView.titleContainer);
+        container.appendChild(itemView.contentContainer);
+
+        if (!this.itemViews) this.itemViews = {};
+
+        const id = model.get("itemId");
+        this.itemViews[id] = itemView;
+        // Add children if they exist, otherwise just re-adds the content
+        this.refreshContent(id);
+      },
+
+      /**
+       * Refreshes the content of an item in the accordion. If the item has
+       * children, it will create a new accordion with the children. Otherwise,
+       * it will update the content with the item's model content attribute.
+       * @param {string} itemId - The model itemId for the item
+       */
+      refreshContent(itemId) {
+        // Check if there are children for the given item
+        const children = this.model.getChildren(itemId);
+        const itemView = this.itemViews?.[itemId];
+        if (!itemView) return;
+        if (children?.length) {
+          const subAccordion = this.createAccordion(children);
+          itemView.updateContent(subAccordion);
+        } else {
+          itemView.updateContent(itemView.model.get("content"));
+        }
+      },
+
+      /**
+       * Handles adding a new item to the accordion when the items collection
+       * has new models added to it.
+       * @param {AccordionItem} model - The new AccordionItem model
+       */
+      addNewItem(model) {
+        const parent = model.get("parent");
+        if (parent) {
+          this.refreshContent(parent);
+        } else {
+          this.addItem(model, this.rootAccordion);
+        }
+      },
+
+      /**
+       * Handles removing an item from the accordion when the items collection
+       * has models removed from it.
+       * @param {AccordionItem} model - The removed AccordionItem model
+       */
+      removeItem(model) {
+        const id = model.get("itemId") || model.cid;
+        const itemView = this.itemViews[id];
+        // remove the item view from the itemViews object
+        delete this.itemViews[id];
+        itemView?.remove();
+      },
+
+      /**
+       * Removes all items from the accordion and clears the itemViews object.
+       */
+      clearAllItems() {
+        Object.entries(this.itemViews).forEach(([id, view]) => {
+          view.remove();
+          delete this.itemViews[id];
+        });
+      },
+    },
+  );
+
+  return AccordionView;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_citations_CitationModalView.js.html b/docs/docs/src_js_views_citations_CitationModalView.js.html index 68268a7ee..dd3831796 100644 --- a/docs/docs/src_js_views_citations_CitationModalView.js.html +++ b/docs/docs/src_js_views_citations_CitationModalView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_filters_BooleanFilterView.js.html b/docs/docs/src_js_views_filters_BooleanFilterView.js.html index 171c2b0b5..9cbf7e67b 100644 --- a/docs/docs/src_js_views_filters_BooleanFilterView.js.html +++ b/docs/docs/src_js_views_filters_BooleanFilterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_filters_ChoiceFilterView.js.html b/docs/docs/src_js_views_filters_ChoiceFilterView.js.html index 40fdf9536..a6c823f36 100644 --- a/docs/docs/src_js_views_filters_ChoiceFilterView.js.html +++ b/docs/docs/src_js_views_filters_ChoiceFilterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_filters_DateFilterView.js.html b/docs/docs/src_js_views_filters_DateFilterView.js.html index 647632d11..bd84f2b58 100644 --- a/docs/docs/src_js_views_filters_DateFilterView.js.html +++ b/docs/docs/src_js_views_filters_DateFilterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_filters_FilterEditorView.js.html b/docs/docs/src_js_views_filters_FilterEditorView.js.html index 690633353..3898fb51b 100644 --- a/docs/docs/src_js_views_filters_FilterEditorView.js.html +++ b/docs/docs/src_js_views_filters_FilterEditorView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -747,19 +747,21 @@

Source: src/js/views/filters/FilterEditorView.js

inputLabel: "Select one or more metadata fields", excludeFields: view.excludeFields, addFields: view.specialFields, - separatorText: view.model.get("fieldsOperator"), + separator: view.model.get("fieldsOperator"), }); view.modalEl .find("." + view.classes.fieldsContainer) .append(view.fieldInput.el); view.fieldInput.render(); - // When the field input is changed, limit UI options to options that match - // this field type - view.fieldInput.off("changeSelection"); - view.fieldInput.on("changeSelection", function (selectedFields) { - view.handleFieldChange.call(view, selectedFields); - }); + this.stopListening(view.fieldInput.model, "change:selected"); + this.listenTo( + view.fieldInput.model, + "change:selected", + function (_model, newSelectedFields) { + view.handleFieldChange.call(view, newSelectedFields); + }, + ); } catch (error) { console.log( "There was an error rendering a fields input in a FilterEditorView" + @@ -968,9 +970,9 @@

Source: src/js/views/filters/FilterEditorView.js

newModelAttrs = selectedUI.draftModel.toJSON(); // Set the new fields - newModelAttrs.fields = _.clone(this.fieldInput.selected); + newModelAttrs.fields = _.clone(this.fieldInput.model.get("selected")); // set the new fieldsOperator - newModelAttrs.fieldsOperator = this.fieldInput.separatorText; + newModelAttrs.fieldsOperator = this.fieldInput.model.get("separator"); delete newModelAttrs.objectDOM; delete newModelAttrs.cid; diff --git a/docs/docs/src_js_views_filters_FilterGroupView.js.html b/docs/docs/src_js_views_filters_FilterGroupView.js.html index e02fe8a0e..f4343d24b 100644 --- a/docs/docs/src_js_views_filters_FilterGroupView.js.html +++ b/docs/docs/src_js_views_filters_FilterGroupView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -55,8 +55,6 @@

Source: src/js/views/filters/FilterGroupView.js

"views/filters/DateFilterView", "views/filters/NumericFilterView", "views/filters/ToggleFilterView", - "views/searchSelect/AnnotationFilterView", - "views/searchSelect/SearchableSelectView", "views/filters/SemanticFilterView", ], function ( $, @@ -69,8 +67,6 @@

Source: src/js/views/filters/FilterGroupView.js

DateFilterView, NumericFilterView, ToggleFilterView, - AnnotationFilterView, - SearchableSelectView, SemanticFilterView, ) { "use strict"; diff --git a/docs/docs/src_js_views_filters_FilterGroupsView.js.html b/docs/docs/src_js_views_filters_FilterGroupsView.js.html index 856b04a1b..93d83033a 100644 --- a/docs/docs/src_js_views_filters_FilterGroupsView.js.html +++ b/docs/docs/src_js_views_filters_FilterGroupsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_filters_FilterView.js.html b/docs/docs/src_js_views_filters_FilterView.js.html index 752689b9b..e9d1f78d0 100644 --- a/docs/docs/src_js_views_filters_FilterView.js.html +++ b/docs/docs/src_js_views_filters_FilterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -248,6 +248,7 @@

Source: src/js/views/filters/FilterView.js

if (!templateVars) { var templateVars = this.model.toJSON(); + templateVars.id = this.model.cid; } // Pass the mode (e.g. "edit", "uiBuilder") to the template, as well diff --git a/docs/docs/src_js_views_filters_NumericFilterView.js.html b/docs/docs/src_js_views_filters_NumericFilterView.js.html index 6d77dff48..c91b181b5 100644 --- a/docs/docs/src_js_views_filters_NumericFilterView.js.html +++ b/docs/docs/src_js_views_filters_NumericFilterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_filters_SemanticFilterView.js.html b/docs/docs/src_js_views_filters_SemanticFilterView.js.html index fc061f554..c012222bd 100644 --- a/docs/docs/src_js_views_filters_SemanticFilterView.js.html +++ b/docs/docs/src_js_views_filters_SemanticFilterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -44,144 +44,116 @@

Source: src/js/views/filters/SemanticFilterView.js

-
define([
-  "jquery",
-  "underscore",
-  "backbone",
-  "models/filters/Filter",
-  "views/filters/FilterView",
-  "views/searchSelect/AnnotationFilterView",
-], function ($, _, Backbone, Filter, FilterView, AnnotationFilterView) {
-  "use strict";
+            
"use strict";
 
+define([
+  "views/filters/FilterView",
+  "views/searchSelect/BioontologySelectView",
+], (FilterView, BioontologySelectView) => {
   /**
    * @class SemanticFilterView
    * @classdesc Render a specialized view of a single Filter model using the
-   *   AnnotationFilterView.
+   * BioontologySelectView. Essentially acts as a connector between the Filter
+   * model and the Bioontology model. Uses logic from both the FilterView and
+   * the BioontologySelectView.
    * @classcategory Views/Filters
-   * @extends FilterView
+   * @augments FilterView
    * @screenshot views/filters/SemanticFilterView.png
    * @since 2.22.0
    */
-  var SemanticFilterView = FilterView.extend(
+  const SemanticFilterView = FilterView.extend(
     /** @lends SemanticFilterView.prototype */ {
-      /**
-       * @inheritdoc
-       */
-      model: null,
+      /** @inheritdoc */
+      className: "filter semantic",
 
       /**
-       * @inheritdoc
+       * The ontologies to search for terms in.
+       * @type {Array.<{label: string, ontology: string, subTree: string}>}
+       * @since 2.31.0
        */
-      modelClass: Filter,
+      ontologies: MetacatUI.appModel.get("bioportalOntologies"),
 
-      className: "filter semantic",
+      /** override the template function and use subView instead */
+      template() {},
 
-      // Template is an empty function because this view delegates to the
-      // AnnotationFilterView. See render() method.
-      template: function () {},
+      /**
+       * Initialize the SemanticFilterView
+       * @param {object} [options] - The options to initialize the view with
+       * @param {Array.<{label: string, ontology: string, subTree: string}>} [options.ontologies]
+       *  - The ontologies to search for terms in
+       * @since 2.31.0
+       */
+      initialize(options = {}) {
+        if (options?.ontologies) this.ontologies = options.ontologies;
+        FilterView.prototype.initialize.call(this, options);
+      },
 
       /**
-       * Render an instance of a Semantic Filter View.
-       *
-       * Note that this View doesn't have a template and instead delegates to
-       * the AnnotationFilterView which renders a SearchableSelectView which
-       * renders an NCBOTree.
+       * Render an instance of a Semantic Filter View. Note that this View
+       * doesn't have a template and instead delegates to the
+       * BioontologySelectView which renders a SearchSelectView which renders
+       * the BioontologySelectView.
+       * @returns {SemanticFilterView} This instance
        * @since 2.22.0
        */
-      render: function () {
-        try {
-          var templateVars = this.model.toJSON();
-          templateVars.id = this.model.cid;
-
-          // Renders the template and inserts the FilterEditorView if the mode is uiBuilder
-          FilterView.prototype.render.call(this, templateVars);
-
-          var viewOpts = {
-            useSearchableSelect: true,
-            placeholderText: templateVars.placeholder,
-            inputLabel: null, // Hides label and uses FilterView label
-            ontology: this.model.get("ontology"),
-            startingRoot: this.model.get("startingRoot"),
-          };
-
-          var subView = new AnnotationFilterView(viewOpts);
-
-          this.$el.append(subView.el);
-          subView.render();
-
-          var view = this;
-          subView.on("annotationSelected", function (event, item) {
-            // Get the value of the associated input
-            var term = !item || !item.value ? input.val() : item.value;
-            var label = !item || !item.filterLabel ? null : item.filterLabel;
-
-            // Set up a label mapping for the term so we can display a
-            // human-readable label for it in the UI
-            view.setLabelMapping(term, label);
-
-            // Set the value, supports multiple values
-            var currentValue = view.model.get("values");
-            var newValuesArray = _.flatten(new Array(currentValue, term));
-            view.model.set("values", newValuesArray);
-
-            view.defocus();
-          });
-        } catch (error) {
-          console.log(
-            "There was an error rendering a SemanticFilterView." +
-              " Error details: " +
-              error,
-          );
-        }
+      render() {
+        // Inserts the FilterEditorView if the mode is uiBuilder
+        FilterView.prototype.render.call(this);
+
+        this.subView = new BioontologySelectView({
+          placeholderText: this.model.get("placeholder"),
+          inputLabel: null,
+          ontologies: this.ontologies,
+          compact: true,
+        }).render();
+        this.el.appendChild(this.subView.el);
+        this.listenTo(
+          this.subView.model,
+          "change:selected",
+          this.onSubViewSelection,
+        );
+        return this;
       },
 
       /**
-       * Helper function which defocuses the dropdown portion of the
-       * SearchableSelectView used by this View's AnnotationFilterView. When the
-       * user clicks an item in the NCBOTree widget, we want the
-       * SearchableSelectView's dropdown to go away and I couldn't find any API
-       * to do that so we have this code. See the render() method to see how it's
-       * called.
-       *
-       * Note: This isn't really a stable API and is really something we might
-       * remove in the future if we refactor the NCBOTree widget.
-       * @since 2.22.0
+       * Update the filter model when a class is selected in the
+       * BioontologySelectView. Clear the selection/search input from the
+       * SelectView and collapse the menu.
+       * @since 2.31.0
        */
-      defocus: function () {
-        this.$el.find("div.menu").removeClass("visible").addClass("hidden");
-        this.$el
-          .find("div.fluid.ui.dropdown")
-          .removeClass("active")
-          .removeClass("visible");
-        this.$el.find("input").blur();
+      onSubViewSelection() {
+        const view = this;
+        requestAnimationFrame(() => {
+          const selected = view.subView.model.getSelectedModels()?.[0];
+          if (!selected) return;
+
+          const value = selected.get("value");
+          const label = selected.get("label") || value;
+          const description = selected.get("description") || "";
+
+          view.setLabelMapping(value, label);
+          view.model.set("description", description);
+          const newValuesArray = [...view.model.get("values"), value];
+          view.model.set("values", newValuesArray);
+          view.subView.reset(true);
+        });
       },
 
       /**
        * Set the human-readable label for a term URI.
-       *
        * For most uses of the Filter model, the value(s) set on the model can
        * be shown directly in the UI. But for Semantic searches, we need to
        * be able to display a human-readable label for the value because the
        * value is likely an opaque URI.
-       *
        * Rather than fetch and/or store all the possible labels for all
        * possible URIs, we store a label for whichever terms the user chooses
        * and keep that around until we need it in the UI.
-       *
        * @param {string} term The term URI to set a label for
        * @param {string} label The label to set
        * @since 2.22.0
        */
-      setLabelMapping: function (term, label) {
-        var newMappings;
-
-        if (this.model.get("valueLabels")) {
-          newMappings = _.clone(this.model.get("valueLabels"));
-        } else {
-          newMappings = new Object();
-        }
-
+      setLabelMapping(term, label) {
+        const newMappings = { ...(this.model.get("valueLabels") || {}) };
         newMappings[term] = label;
         this.model.set("valueLabels", newMappings);
       },
diff --git a/docs/docs/src_js_views_filters_ToggleFilterView.js.html b/docs/docs/src_js_views_filters_ToggleFilterView.js.html
index d92cc9e1b..097f24c5c 100644
--- a/docs/docs/src_js_views_filters_ToggleFilterView.js.html
+++ b/docs/docs/src_js_views_filters_ToggleFilterView.js.html
@@ -30,7 +30,7 @@
 
 
     
-    

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_CesiumWidgetView.js.html b/docs/docs/src_js_views_maps_CesiumWidgetView.js.html index 3a6d58f13..2be8c89ad 100644 --- a/docs/docs/src_js_views_maps_CesiumWidgetView.js.html +++ b/docs/docs/src_js_views_maps_CesiumWidgetView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_DrawToolView.js.html b/docs/docs/src_js_views_maps_DrawToolView.js.html index cc311c86c..73dae9392 100644 --- a/docs/docs/src_js_views_maps_DrawToolView.js.html +++ b/docs/docs/src_js_views_maps_DrawToolView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_ExpansionPanelView.js.html b/docs/docs/src_js_views_maps_ExpansionPanelView.js.html index a40b7074b..4050f17b2 100644 --- a/docs/docs/src_js_views_maps_ExpansionPanelView.js.html +++ b/docs/docs/src_js_views_maps_ExpansionPanelView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_FeatureInfoView.js.html b/docs/docs/src_js_views_maps_FeatureInfoView.js.html index 1c78ed07a..95a66b91d 100644 --- a/docs/docs/src_js_views_maps_FeatureInfoView.js.html +++ b/docs/docs/src_js_views_maps_FeatureInfoView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_HelpPanelView.js.html b/docs/docs/src_js_views_maps_HelpPanelView.js.html index 1f5df976b..d152e5655 100644 --- a/docs/docs/src_js_views_maps_HelpPanelView.js.html +++ b/docs/docs/src_js_views_maps_HelpPanelView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerCategoryListView.js.html b/docs/docs/src_js_views_maps_LayerCategoryListView.js.html index c2d04ef3f..ec3883fa0 100644 --- a/docs/docs/src_js_views_maps_LayerCategoryListView.js.html +++ b/docs/docs/src_js_views_maps_LayerCategoryListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerDetailView.js.html b/docs/docs/src_js_views_maps_LayerDetailView.js.html index 4f16283f0..a9c81dac6 100644 --- a/docs/docs/src_js_views_maps_LayerDetailView.js.html +++ b/docs/docs/src_js_views_maps_LayerDetailView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerDetailsView.js.html b/docs/docs/src_js_views_maps_LayerDetailsView.js.html index 310b0d173..d4a622bc0 100644 --- a/docs/docs/src_js_views_maps_LayerDetailsView.js.html +++ b/docs/docs/src_js_views_maps_LayerDetailsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -58,7 +58,7 @@

Source: src/js/views/maps/LayerDetailsView.js

"views/maps/LayerInfoView", "views/maps/LayerNavigationView", "views/maps/LegendView", -], function ( +], ( $, _, Backbone, @@ -70,7 +70,7 @@

Source: src/js/views/maps/LayerDetailsView.js

LayerInfoView, LayerNavigationView, LegendView, -) { +) => { /** * @class LayerDetailsView * @classdesc A panel with additional information about a Layer (a Map Asset like @@ -78,12 +78,12 @@

Source: src/js/views/maps/LayerDetailsView.js

* the map, such as the opacity. * @classcategory Views/Maps * @name LayerDetailsView - * @extends Backbone.View + * @augments Backbone.View * @screenshot views/maps/LayerDetailsView.png * @since 2.18.0 * @constructs */ - var LayerDetailsView = Backbone.View.extend( + const LayerDetailsView = Backbone.View.extend( /** @lends LayerDetailsView.prototype */ { /** * The type of View this is @@ -111,7 +111,7 @@

Source: src/js/views/maps/LayerDetailsView.js

/** * Classes that are used to identify the HTML elements that comprise this view. - * @type {Object} + * @type {object} * @property {string} open The class to add to the outermost HTML element for this * view when the layer details view is open/expanded (not hidden) * @property {string} toggle The element in the template that acts as a toggle to @@ -136,7 +136,7 @@

Source: src/js/views/maps/LayerDetailsView.js

/** * Configuration for a Layer Detail section to show within this Layer Details * view. - * @typedef {Object} DetailSectionOption + * @typedef {object} DetailSectionOption * @property {string} label The name to display for this section * @property {Backbone.View} view Any view that will render content for the Layer * Detail section. This view will be passed the MapAsset model. The view should @@ -193,50 +193,48 @@

Source: src/js/views/maps/LayerDetailsView.js

* Creates an object that gives the events this view will listen to and the * associated function to call. Each entry in the object has the format 'event * selector': 'function'. - * @returns {Object} + * @returns {object} */ - events: function () { - var events = {}; + events() { + const events = {}; // Close the layer details panel when the toggle button is clicked. Get the // class of the toggle button from the classes property set in this view. - events["click ." + this.classes.toggle] = "close"; + events[`click .${this.classes.toggle}`] = "close"; return events; }, /** * Whether or not the layer details view is open - * @type {Boolean} + * @type {boolean} */ isOpen: false, /** * Executed when a new LayerDetailsView is created - * @param {Object} [options] - A literal object with options to pass to the view + * @param {object} [options] - A literal object with options to pass to the view */ - initialize: function (options) { + initialize(options) { try { // Get all the options and apply them to this view - if (typeof options == "object") { - for (const [key, value] of Object.entries(options)) { - this[key] = value; - } + if (typeof options === "object") { + Object.keys(options).forEach((key) => { + this[key] = options[key]; + }); } } catch (e) { console.log( - "A LayerDetailsView failed to initialize. Error message: " + e, + `A LayerDetailsView failed to initialize. Error message: ${e}`, ); } }, /** * Renders this view - * @return {LayerDetailsView} Returns the rendered view element + * @returns {LayerDetailsView | null} Returns the rendered view element */ - render: function () { + render() { try { - // Save a reference to this view - var view = this; - var model = this.model; + const { model } = this; // Show the layer details box as open if the view is set to have it open // already @@ -256,18 +254,25 @@

Source: src/js/views/maps/LayerDetailsView.js

// Select elements in the template that we will need to manipulate const sectionsContainer = this.el.querySelector( - "." + this.classes.sections, + `.${this.classes.sections}`, ); - const labelEl = this.el.querySelector("." + this.classes.label); + const labelEl = this.el.querySelector(`.${this.classes.label}`); // Render each section in the Details panel this.renderedSections = _.clone(this.sections); - this.renderedSections.forEach(function (section) { - var detailSection = new LayerDetailView({ + // Remove and do not render opacity section if showOpacitySlider is false + if (model?.get("showOpacitySlider") === false) { + this.renderedSections = this.renderedSections.filter( + (item) => item.label !== "Opacity", + ); + } + + this.renderedSections.forEach((section) => { + const detailSection = new LayerDetailView({ label: section.label, contentView: section.view, - model: model, + model, collapsible: section.collapsible, showTitle: section.showTitle, }); @@ -286,19 +291,18 @@

Source: src/js/views/maps/LayerDetailsView.js

// Hide/show sections with the 'hideIfError' property when the status of the // MapAsset changes this.stopListening(model, "change:status"); - this.listenTo(model, "change:status", function (model, status) { + this.listenTo(model, "change:status", (_model, status) => { const hideIfErrorSections = _.filter( this.renderedSections, - function (section) { - return section.hideIfError; - }, + (section) => section.hideIfError, ); let displayProperty = ""; if (status === "error") { displayProperty = "none"; } - hideIfErrorSections.forEach(function (section) { - section.renderedView.el.style.display = displayProperty; + hideIfErrorSections.forEach((section) => { + const renderedViewEl = section.renderedView.el; + renderedViewEl.style.display = displayProperty; }); }); @@ -312,8 +316,7 @@

Source: src/js/views/maps/LayerDetailsView.js

noticeEl.classList.add(this.classes.notification); noticeEl.innerText = notice.message; if (notice.style) { - const badgeClass = - this.classes.notification + "--" + notice.style; + const badgeClass = `${this.classes.notification}--${notice.style}`; noticeEl.classList.add(badgeClass); } sectionsContainer.prepend(noticeEl); @@ -324,7 +327,7 @@

Source: src/js/views/maps/LayerDetailsView.js

badge.classList.add(this.classes.badge); badge.innerText = notice.badge; if (notice.style) { - const badgeClass = this.classes.badge + "--" + notice.style; + const badgeClass = `${this.classes.badge}--${notice.style}`; badge.classList.add(badgeClass); } labelEl.append(badge); @@ -334,10 +337,10 @@

Source: src/js/views/maps/LayerDetailsView.js

return this; } catch (error) { console.log( - "There was an error rendering a LayerDetailsView" + - ". Error details: " + - error, + `There was an error rendering a LayerDetailsView` + + `. Error details: ${error}`, ); + return null; } }, @@ -345,7 +348,7 @@

Source: src/js/views/maps/LayerDetailsView.js

* Show/expand the Layer Details panel. Opening the panel also changes the * MapAsset model's 'selected attribute' to true. */ - open: function () { + open() { try { this.el.classList.add(this.classes.open); this.isOpen = true; @@ -355,9 +358,8 @@

Source: src/js/views/maps/LayerDetailsView.js

} } catch (error) { console.log( - "There was an error opening the LayerDetailsView" + - ". Error details: " + - error, + `There was an error opening the LayerDetailsView` + + `. Error details: ${error}`, ); } }, @@ -366,7 +368,7 @@

Source: src/js/views/maps/LayerDetailsView.js

* Hide/collapse the Layer Details panel. Closing the panel also changes the * MapAsset model's 'selected attribute' to false. */ - close: function () { + close() { try { this.el.classList.remove(this.classes.open); this.isOpen = false; @@ -376,9 +378,8 @@

Source: src/js/views/maps/LayerDetailsView.js

} } catch (error) { console.log( - "There was an error closing the LayerDetailsView" + - ". Error details: " + - error, + `There was an error closing the LayerDetailsView` + + `. Error details: ${error}`, ); } }, @@ -390,10 +391,10 @@

Source: src/js/views/maps/LayerDetailsView.js

* view. If set to null, then the view will be rendered without any layer * information. */ - updateModel: function (newModel) { + updateModel(newModel) { try { // Remove listeners from sub-views - this.renderedSections.forEach(function (section) { + this.renderedSections.forEach((section) => { if ( section.renderedView && typeof section.renderedView.onClose === "function" @@ -405,9 +406,8 @@

Source: src/js/views/maps/LayerDetailsView.js

this.render(); } catch (error) { console.log( - "There was an error updating the MapAsset model in a LayerDetailsView" + - ". Error details: " + - error, + `There was an error updating the MapAsset model in a LayerDetailsView` + + `. Error details: ${error}`, ); } }, diff --git a/docs/docs/src_js_views_maps_LayerInfoView.js.html b/docs/docs/src_js_views_maps_LayerInfoView.js.html index 4b27ebe30..09743a3ac 100644 --- a/docs/docs/src_js_views_maps_LayerInfoView.js.html +++ b/docs/docs/src_js_views_maps_LayerInfoView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerItemView.js.html b/docs/docs/src_js_views_maps_LayerItemView.js.html index 533044a75..1f9d3ff1b 100644 --- a/docs/docs/src_js_views_maps_LayerItemView.js.html +++ b/docs/docs/src_js_views_maps_LayerItemView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerListView.js.html b/docs/docs/src_js_views_maps_LayerListView.js.html index 2c698b9f2..5b5571ca0 100644 --- a/docs/docs/src_js_views_maps_LayerListView.js.html +++ b/docs/docs/src_js_views_maps_LayerListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerNavigationView.js.html b/docs/docs/src_js_views_maps_LayerNavigationView.js.html index 66fbbc8c8..7557ea690 100644 --- a/docs/docs/src_js_views_maps_LayerNavigationView.js.html +++ b/docs/docs/src_js_views_maps_LayerNavigationView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayerOpacityView.js.html b/docs/docs/src_js_views_maps_LayerOpacityView.js.html index fb92ea243..22e3d6564 100644 --- a/docs/docs/src_js_views_maps_LayerOpacityView.js.html +++ b/docs/docs/src_js_views_maps_LayerOpacityView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LayersPanelView.js.html b/docs/docs/src_js_views_maps_LayersPanelView.js.html index 05499187e..4b7d4f3fa 100644 --- a/docs/docs/src_js_views_maps_LayersPanelView.js.html +++ b/docs/docs/src_js_views_maps_LayersPanelView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_LegendView.js.html b/docs/docs/src_js_views_maps_LegendView.js.html index 930ffc202..f5dfeac36 100644 --- a/docs/docs/src_js_views_maps_LegendView.js.html +++ b/docs/docs/src_js_views_maps_LegendView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_MapView.js.html b/docs/docs/src_js_views_maps_MapView.js.html index 2452d5e1f..bb1727272 100644 --- a/docs/docs/src_js_views_maps_MapView.js.html +++ b/docs/docs/src_js_views_maps_MapView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -175,10 +175,7 @@

Source: src/js/views/maps/MapView.js

this.renderToolbar(); this.renderLayerDetails(); } - if ( - this.model.get("showFeatureInfo") && - this.model.get("clickFeatureAction") === "showDetails" - ) { + if (this.model.get("showFeatureInfo")) { this.renderFeatureInfo(); } return this; diff --git a/docs/docs/src_js_views_maps_MapWidgetContainerView.js.html b/docs/docs/src_js_views_maps_MapWidgetContainerView.js.html index ac88b62bd..649da7fbd 100644 --- a/docs/docs/src_js_views_maps_MapWidgetContainerView.js.html +++ b/docs/docs/src_js_views_maps_MapWidgetContainerView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_ScaleBarView.js.html b/docs/docs/src_js_views_maps_ScaleBarView.js.html index ece105e88..e8181093d 100644 --- a/docs/docs/src_js_views_maps_ScaleBarView.js.html +++ b/docs/docs/src_js_views_maps_ScaleBarView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_SearchInputView.js.html b/docs/docs/src_js_views_maps_SearchInputView.js.html index dd22cbfa6..27cded8fe 100644 --- a/docs/docs/src_js_views_maps_SearchInputView.js.html +++ b/docs/docs/src_js_views_maps_SearchInputView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_ShareUrlView.js.html b/docs/docs/src_js_views_maps_ShareUrlView.js.html index 3a4c778b3..913093d54 100644 --- a/docs/docs/src_js_views_maps_ShareUrlView.js.html +++ b/docs/docs/src_js_views_maps_ShareUrlView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_ToolbarView.js.html b/docs/docs/src_js_views_maps_ToolbarView.js.html index 3943f2750..2fd6b6581 100644 --- a/docs/docs/src_js_views_maps_ToolbarView.js.html +++ b/docs/docs/src_js_views_maps_ToolbarView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_legend_CategoricalSwatchView.js.html b/docs/docs/src_js_views_maps_legend_CategoricalSwatchView.js.html index 3f254e139..aeb0a8a0b 100644 --- a/docs/docs/src_js_views_maps_legend_CategoricalSwatchView.js.html +++ b/docs/docs/src_js_views_maps_legend_CategoricalSwatchView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_legend_ContinuousSwatchView.js.html b/docs/docs/src_js_views_maps_legend_ContinuousSwatchView.js.html index 2b67fd785..49999e01d 100644 --- a/docs/docs/src_js_views_maps_legend_ContinuousSwatchView.js.html +++ b/docs/docs/src_js_views_maps_legend_ContinuousSwatchView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_legend_LayerLegendView.js.html b/docs/docs/src_js_views_maps_legend_LayerLegendView.js.html index 6a5c22ae6..a6dcf5385 100644 --- a/docs/docs/src_js_views_maps_legend_LayerLegendView.js.html +++ b/docs/docs/src_js_views_maps_legend_LayerLegendView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_legend_LegendContainerView.js.html b/docs/docs/src_js_views_maps_legend_LegendContainerView.js.html index 346acb914..7f86474f3 100644 --- a/docs/docs/src_js_views_maps_legend_LegendContainerView.js.html +++ b/docs/docs/src_js_views_maps_legend_LegendContainerView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_viewfinder_PredictionView.js.html b/docs/docs/src_js_views_maps_viewfinder_PredictionView.js.html index 1d4514e9a..2509eadec 100644 --- a/docs/docs/src_js_views_maps_viewfinder_PredictionView.js.html +++ b/docs/docs/src_js_views_maps_viewfinder_PredictionView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_viewfinder_PredictionsListView.js.html b/docs/docs/src_js_views_maps_viewfinder_PredictionsListView.js.html index a54bc5d05..b083f4dcf 100644 --- a/docs/docs/src_js_views_maps_viewfinder_PredictionsListView.js.html +++ b/docs/docs/src_js_views_maps_viewfinder_PredictionsListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_viewfinder_SearchView.js.html b/docs/docs/src_js_views_maps_viewfinder_SearchView.js.html index 88d9205db..7ad72d5d6 100644 --- a/docs/docs/src_js_views_maps_viewfinder_SearchView.js.html +++ b/docs/docs/src_js_views_maps_viewfinder_SearchView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_viewfinder_ViewfinderView.js.html b/docs/docs/src_js_views_maps_viewfinder_ViewfinderView.js.html index 8eea79a07..01c888113 100644 --- a/docs/docs/src_js_views_maps_viewfinder_ViewfinderView.js.html +++ b/docs/docs/src_js_views_maps_viewfinder_ViewfinderView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_viewfinder_ZoomPresetView.js.html b/docs/docs/src_js_views_maps_viewfinder_ZoomPresetView.js.html index 41b7b246f..dbd894617 100644 --- a/docs/docs/src_js_views_maps_viewfinder_ZoomPresetView.js.html +++ b/docs/docs/src_js_views_maps_viewfinder_ZoomPresetView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_maps_viewfinder_ZoomPresetsListView.js.html b/docs/docs/src_js_views_maps_viewfinder_ZoomPresetsListView.js.html index daa0efb52..abcd10125 100644 --- a/docs/docs/src_js_views_maps_viewfinder_ZoomPresetsListView.js.html +++ b/docs/docs/src_js_views_maps_viewfinder_ZoomPresetsListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EML211EditorView.js.html b/docs/docs/src_js_views_metadata_EML211EditorView.js.html index 777f6a8b0..760360972 100644 --- a/docs/docs/src_js_views_metadata_EML211EditorView.js.html +++ b/docs/docs/src_js_views_metadata_EML211EditorView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EML211MissingValueCodeView.js.html b/docs/docs/src_js_views_metadata_EML211MissingValueCodeView.js.html index 137306c78..91817cf59 100644 --- a/docs/docs/src_js_views_metadata_EML211MissingValueCodeView.js.html +++ b/docs/docs/src_js_views_metadata_EML211MissingValueCodeView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EML211MissingValueCodesView.js.html b/docs/docs/src_js_views_metadata_EML211MissingValueCodesView.js.html index 1822ad2ba..1a3b03c75 100644 --- a/docs/docs/src_js_views_metadata_EML211MissingValueCodesView.js.html +++ b/docs/docs/src_js_views_metadata_EML211MissingValueCodesView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EML211View.js.html b/docs/docs/src_js_views_metadata_EML211View.js.html index e8fff2212..92fe5f028 100644 --- a/docs/docs/src_js_views_metadata_EML211View.js.html +++ b/docs/docs/src_js_views_metadata_EML211View.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -2581,7 +2581,7 @@

Source: src/js/views/metadata/EML211View.js

const taxonSelects = view.taxonSelects; if (!taxonSelects || !taxonSelects.length) return; const selectedItems = taxonSelects - .map((select) => select.selected) + .map((select) => select.model.get("selected")) .flat(); if (!selectedItems || !selectedItems.length) return; const selectedItemObjs = selectedItems.map((item) => { @@ -2597,14 +2597,16 @@

Source: src/js/views/metadata/EML211View.js

} }); view.addTaxa(selectedItemObjs); - taxonSelects.forEach((select) => select.changeSelection([], true)); + taxonSelects.forEach((select) => + select.model.setSelected([], { silent: true }), + ); }; button.removeEventListener("click", onButtonClick); button.addEventListener("click", onButtonClick); // Create the search selects view.taxonSelects = []; - const componentPath = "views/searchSelect/SearchableSelectView"; + const componentPath = "views/searchSelect/SearchSelectView"; require([componentPath], function (SearchSelect) { quickAddTaxa.forEach((taxaList, i) => { try { diff --git a/docs/docs/src_js_views_metadata_EMLAttributeView.js.html b/docs/docs/src_js_views_metadata_EMLAttributeView.js.html index f72be23fe..41a319287 100644 --- a/docs/docs/src_js_views_metadata_EMLAttributeView.js.html +++ b/docs/docs/src_js_views_metadata_EMLAttributeView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLEntityView.js.html b/docs/docs/src_js_views_metadata_EMLEntityView.js.html index 45a5054ae..cedd255c4 100644 --- a/docs/docs/src_js_views_metadata_EMLEntityView.js.html +++ b/docs/docs/src_js_views_metadata_EMLEntityView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLGeoCoverageView.js.html b/docs/docs/src_js_views_metadata_EMLGeoCoverageView.js.html index 761071226..ac256aabb 100644 --- a/docs/docs/src_js_views_metadata_EMLGeoCoverageView.js.html +++ b/docs/docs/src_js_views_metadata_EMLGeoCoverageView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLMeasurementScaleView.js.html b/docs/docs/src_js_views_metadata_EMLMeasurementScaleView.js.html index f1639f338..9ccf295e8 100644 --- a/docs/docs/src_js_views_metadata_EMLMeasurementScaleView.js.html +++ b/docs/docs/src_js_views_metadata_EMLMeasurementScaleView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLMeasurementTypeView.js.html b/docs/docs/src_js_views_metadata_EMLMeasurementTypeView.js.html index d7d5aa95f..c1fdee668 100644 --- a/docs/docs/src_js_views_metadata_EMLMeasurementTypeView.js.html +++ b/docs/docs/src_js_views_metadata_EMLMeasurementTypeView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLMethodsView.js.html b/docs/docs/src_js_views_metadata_EMLMethodsView.js.html index 21687705d..218086567 100644 --- a/docs/docs/src_js_views_metadata_EMLMethodsView.js.html +++ b/docs/docs/src_js_views_metadata_EMLMethodsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLOtherEntityView.js.html b/docs/docs/src_js_views_metadata_EMLOtherEntityView.js.html index 2ce3fdbf6..8db353685 100644 --- a/docs/docs/src_js_views_metadata_EMLOtherEntityView.js.html +++ b/docs/docs/src_js_views_metadata_EMLOtherEntityView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLPartyView.js.html b/docs/docs/src_js_views_metadata_EMLPartyView.js.html index 83303bd65..c2fc4acc4 100644 --- a/docs/docs/src_js_views_metadata_EMLPartyView.js.html +++ b/docs/docs/src_js_views_metadata_EMLPartyView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_EMLTempCoverageView.js.html b/docs/docs/src_js_views_metadata_EMLTempCoverageView.js.html index 990aa043e..a6218697a 100644 --- a/docs/docs/src_js_views_metadata_EMLTempCoverageView.js.html +++ b/docs/docs/src_js_views_metadata_EMLTempCoverageView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_metadata_ScienceMetadataView.js.html b/docs/docs/src_js_views_metadata_ScienceMetadataView.js.html index 1043d26bd..615ab3e4b 100644 --- a/docs/docs/src_js_views_metadata_ScienceMetadataView.js.html +++ b/docs/docs/src_js_views_metadata_ScienceMetadataView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_ontologies_BioontologyBrowserView.js.html b/docs/docs/src_js_views_ontologies_BioontologyBrowserView.js.html new file mode 100644 index 000000000..597720a03 --- /dev/null +++ b/docs/docs/src_js_views_ontologies_BioontologyBrowserView.js.html @@ -0,0 +1,294 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/ontologies/BioontologyBrowserView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/ontologies/BioontologyBrowserView.js

+ + + + + + +
+
+
define([
+  "backbone",
+  "semantic",
+  "models/connectors/Bioontology-Accordion-SearchSelect",
+  "views/accordion/AccordionView",
+  "views/searchSelect/SearchSelectView",
+], (Backbone, Semantic, Connector, AccordionView, SearchSelectView) => {
+  const BASE_CLASS = "bioontology-browser";
+  const CLASS_NAMES = {
+    accordion: AccordionView.prototype.className,
+    searchSelect: SearchSelectView.prototype.className,
+    classInfo: "class-info",
+    message: [
+      Semantic.CLASS_NAMES.base,
+      Semantic.CLASS_NAMES.variations.floating,
+      Semantic.CLASS_NAMES.message.base,
+      Semantic.CLASS_NAMES.variations.info,
+    ],
+    metacatui: {
+      loader: "icon-spinner icon-spin icon-on-left",
+      icon: "icon",
+      iconLeft: "icon-on-left",
+      floatRight: "pull-right",
+      externalLinkIcon: "icon-external-link",
+      addIcon: "icon-plus",
+      tagIcon: "icon-tag",
+    },
+  };
+  const BOOTSTRAP_CLASSES = {
+    floatRight: "pull-right",
+  };
+  const BUTTON_ID = "bioontology-select-button";
+
+  /**
+   * @class BioontologyBrowser
+   * @classdesc An interface to browser BioPortal ontologies and classes
+   * @classcategory Views/Ontologies
+   * @augments Backbone.View
+   * @since 2.31.0
+   * @screenshot views/ontologies/BioontologyBrowserView.png
+   */
+  const BioontologyBrowser = Backbone.View.extend(
+    /** @lends BioontologyBrowser.prototype */
+    {
+      /** @inheritdoc */
+      type: "BioontologyBrowser",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /**
+       * The HTML string to display when no term is selected
+       */
+      noTermHTML: `
+        <div class="${CLASS_NAMES.message.join(" ")}">
+          <div class="${Semantic.CLASS_NAMES.message.header}">
+            No term selected
+          </div>
+          <p>
+            Select a term from the ontology to view details.
+          </p>
+        </div>`,
+
+      events: {
+        [`click #${BUTTON_ID}`]: "handleSelectButtonClick",
+      },
+
+      /**
+       * Given variables, returns the HTML string the panel that shows details
+       * about a class
+       * @param {object} vars - The variables to use in the template
+       * @param {string} vars.label - The label of the class
+       * @param {string} vars.description - The description of the class
+       * @param {string} vars.id - The ID of the class
+       * @param {string} vars.uiLink - The link to the class on BioPortal
+       * @returns {string} The HTML string for the class info panel
+       */
+      classInfoTemplate(vars) {
+        return `<div class="${Semantic.CLASS_NAMES.base} ${Semantic.CLASS_NAMES.variations.raised} ${Semantic.CLASS_NAMES.card.base}" style="width:100%">
+          <div class="content">
+            
+            <div class="header">
+              <i class="${CLASS_NAMES.metacatui.icon} ${CLASS_NAMES.metacatui.iconLeft} ${CLASS_NAMES.metacatui.tagIcon} ${BOOTSTRAP_CLASSES.floatRight}"></i>
+              ${vars.label}
+            </div>
+            <div class="${Semantic.CLASS_NAMES.card.meta}">
+              ${vars.id}
+            </div>
+            <div class="${Semantic.CLASS_NAMES.card.description}">
+              ${vars.description}
+              <a href="${vars.uiLink}" target="_blank">
+              More details on BioPortal <i class="${CLASS_NAMES.metacatui.icon} ${CLASS_NAMES.metacatui.externalLinkIcon}"></i>
+            </a>
+            </div>
+          </div>
+          <div class="${Semantic.CLASS_NAMES.base} ${Semantic.CLASS_NAMES.variations.attached} ${Semantic.CLASS_NAMES.colors.blue} ${Semantic.CLASS_NAMES.button.base}" id="${BUTTON_ID}">
+            <i class="${CLASS_NAMES.metacatui.icon} ${CLASS_NAMES.metacatui.addIcon}" style="color:inherit";></i>
+            Select term
+          </div>
+        </div>`;
+      },
+
+      /**
+       * Extra CSS styles for this view.
+       */
+      styles: `
+        .${BASE_CLASS} {
+          border-radius: 5px;
+          box-sizing: border-box;
+          height: 100%;
+          display: flex;
+          flex-direction: column;
+          max-height: 70vh;
+          overflow: hidden;
+        }
+
+        .${BASE_CLASS} .${CLASS_NAMES.accordion} {
+          overflow: auto;
+          padding: 0rem 0.2rem;
+        }
+
+        .${BASE_CLASS} .${CLASS_NAMES.searchSelect} {
+          box-shadow: 0 0.0.8rem 0.6rem 0 rgba(0, 0, 0, 0.3);
+          border-bottom: 1px solid #d4d4d5;
+          border-radius: 5px;
+          z-index: 1;
+        }
+
+        .${BASE_CLASS} .${Semantic.CLASS_NAMES.card.base}, .${BASE_CLASS} .${Semantic.CLASS_NAMES.message.base} {
+          transition: 0.3s ease-in-out;
+          box-shadow: 0 -0.08rem 0.6rem 0 rgba(0, 0, 0, 0.3);
+        }
+      `,
+
+      /**
+       * Initialize the BioontologyBrowser view
+       * @param {object} options - Options for the view
+       * @param {object} options.ontologyOptions - The ontologies (or classes) that
+       * a user can select terms from. Each ontology should have a label and an
+       * ontology acronym, and an optional subtree root.
+       * @example
+       * const browser = new BioontologyBrowser({
+       *  ontologyOptions: [
+       *   {
+       *     label: "Measurement Types (ECSO)",
+       *     ontology: "ECSO",
+       *     subTree: "http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#MeasurementType"
+       *    }, { ... } ]
+       * });
+       */
+      initialize(options) {
+        MetacatUI.appModel.addCSS(this.styles, "BioontologyBrowserStyles");
+        const ontologyOptions = options?.ontologyOptions;
+        const modelOptions = ontologyOptions ? { ontologyOptions } : {};
+        this.model = new Connector(modelOptions);
+        this.listenTo(
+          this.model,
+          "change:selectedClass",
+          this.updateClassInfoEl,
+        );
+      },
+
+      /** @inheritdoc */
+      render() {
+        this.el.innerHTML = "";
+
+        // Ontology dropdown
+        this.ontologySwitcher = new SearchSelectView({
+          model: this.model.get("searchSelect"),
+        });
+        this.el.appendChild(this.ontologySwitcher.render().el);
+
+        // Accordion with browseable ontology classes
+        this.accordionView = new AccordionView({
+          model: this.model.get("accordion"),
+        });
+        this.el.appendChild(this.accordionView.render().el);
+        this.model.get("bioontology").fetch({ replaceCollection: true });
+
+        // Panel with class details
+        this.classInfoEl = document.createElement("div");
+        this.el.appendChild(this.classInfoEl);
+        this.updateClassInfoEl();
+      },
+
+      /**
+       * Update the class info panel with the currently selected class
+       * @param {number} transitionTime - The time in milliseconds for the fade
+       * transition between changing info in the panel
+       */
+      updateClassInfoEl(transitionTime = 300) {
+        let newHtml = this.noTermHTML;
+
+        const ontClass = this.model.get("selectedClass");
+        if (ontClass) {
+          newHtml = this.classInfoTemplate({
+            label: ontClass.get("prefLabel"),
+            description: ontClass.get("definition"),
+            id: ontClass.get("@id"),
+            uiLink: ontClass.get("links")?.ui,
+          });
+        }
+
+        // Change the content with a fade transition
+        this.classInfoEl.style.transition = `opacity ${transitionTime}ms ease-in-out`;
+        this.classInfoEl.style.opacity = "0.6";
+        setTimeout(() => {
+          this.classInfoEl.innerHTML = newHtml;
+          setTimeout(() => {
+            this.classInfoEl.style.opacity = "1";
+          }, 1);
+        }, transitionTime);
+      },
+
+      /**
+       * Called when the select button is clicked and triggers the selected
+       * event with the selected class model as the argument
+       * @fires BioontologyBrowser#selected
+       */
+      handleSelectButtonClick() {
+        const selectedClass = this.model.get("selectedClass");
+        if (selectedClass) {
+          this.trigger("selected", selectedClass);
+        } else {
+          // Show a message that no class is selected
+          this.updateClassInfoEl();
+        }
+      },
+    },
+  );
+
+  return BioontologyBrowser;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_portals_PortalDataView.js.html b/docs/docs/src_js_views_portals_PortalDataView.js.html index 1ee876838..1520ee7d3 100644 --- a/docs/docs/src_js_views_portals_PortalDataView.js.html +++ b/docs/docs/src_js_views_portals_PortalDataView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalHeaderView.js.html b/docs/docs/src_js_views_portals_PortalHeaderView.js.html index 8155362cf..21776ce16 100644 --- a/docs/docs/src_js_views_portals_PortalHeaderView.js.html +++ b/docs/docs/src_js_views_portals_PortalHeaderView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalListView.js.html b/docs/docs/src_js_views_portals_PortalListView.js.html index ed8e50115..97bf2df4b 100644 --- a/docs/docs/src_js_views_portals_PortalListView.js.html +++ b/docs/docs/src_js_views_portals_PortalListView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalLogosView.js.html b/docs/docs/src_js_views_portals_PortalLogosView.js.html index cf116a448..aae1bc783 100644 --- a/docs/docs/src_js_views_portals_PortalLogosView.js.html +++ b/docs/docs/src_js_views_portals_PortalLogosView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalMembersView.js.html b/docs/docs/src_js_views_portals_PortalMembersView.js.html index 7e8dde7f9..404a3358c 100644 --- a/docs/docs/src_js_views_portals_PortalMembersView.js.html +++ b/docs/docs/src_js_views_portals_PortalMembersView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalMetricsView.js.html b/docs/docs/src_js_views_portals_PortalMetricsView.js.html index 727336ba8..48e1ee515 100644 --- a/docs/docs/src_js_views_portals_PortalMetricsView.js.html +++ b/docs/docs/src_js_views_portals_PortalMetricsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalSectionView.js.html b/docs/docs/src_js_views_portals_PortalSectionView.js.html index ac57bbed2..3af8abc81 100644 --- a/docs/docs/src_js_views_portals_PortalSectionView.js.html +++ b/docs/docs/src_js_views_portals_PortalSectionView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalUsagesView.js.html b/docs/docs/src_js_views_portals_PortalUsagesView.js.html index cb70661a7..92c202424 100644 --- a/docs/docs/src_js_views_portals_PortalUsagesView.js.html +++ b/docs/docs/src_js_views_portals_PortalUsagesView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalView.js.html b/docs/docs/src_js_views_portals_PortalView.js.html index 6c905f69a..4e28a9f80 100644 --- a/docs/docs/src_js_views_portals_PortalView.js.html +++ b/docs/docs/src_js_views_portals_PortalView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalVisualizationsView.js.html b/docs/docs/src_js_views_portals_PortalVisualizationsView.js.html index 84bb9d42e..00538c52d 100644 --- a/docs/docs/src_js_views_portals_PortalVisualizationsView.js.html +++ b/docs/docs/src_js_views_portals_PortalVisualizationsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_PortalsSearchView.js.html b/docs/docs/src_js_views_portals_PortalsSearchView.js.html index 17cec2033..aba0d4ad5 100644 --- a/docs/docs/src_js_views_portals_PortalsSearchView.js.html +++ b/docs/docs/src_js_views_portals_PortalsSearchView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorDataView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorDataView.js.html index efcb096a9..40eacd2c9 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorDataView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorDataView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorImageView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorImageView.js.html index c5ac862d5..e4346e37e 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorImageView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorImageView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorLogosView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorLogosView.js.html index 632c9cd9d..01ec65239 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorLogosView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorLogosView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorMdSectionView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorMdSectionView.js.html index 2a3250a86..13708c7aa 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorMdSectionView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorMdSectionView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorSectionView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorSectionView.js.html index 3276ca06f..061ab08b6 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorSectionView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorSectionView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorSectionsView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorSectionsView.js.html index fa77752c3..944691004 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorSectionsView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorSectionsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortEditorSettingsView.js.html b/docs/docs/src_js_views_portals_editor_PortEditorSettingsView.js.html index 79a985e82..d4b7a8ef4 100644 --- a/docs/docs/src_js_views_portals_editor_PortEditorSettingsView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortEditorSettingsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_portals_editor_PortalEditorView.js.html b/docs/docs/src_js_views_portals_editor_PortalEditorView.js.html index 7de610001..d387344cc 100644 --- a/docs/docs/src_js_views_portals_editor_PortalEditorView.js.html +++ b/docs/docs/src_js_views_portals_editor_PortalEditorView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_projects_ProjectView.js.html b/docs/docs/src_js_views_projects_ProjectView.js.html index c0550316e..4b79f5133 100644 --- a/docs/docs/src_js_views_projects_ProjectView.js.html +++ b/docs/docs/src_js_views_projects_ProjectView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_queryBuilder_QueryBuilderView.js.html b/docs/docs/src_js_views_queryBuilder_QueryBuilderView.js.html index cfd3dd815..e90086a0a 100644 --- a/docs/docs/src_js_views_queryBuilder_QueryBuilderView.js.html +++ b/docs/docs/src_js_views_queryBuilder_QueryBuilderView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -50,7 +50,7 @@

Source: src/js/views/queryBuilder/QueryBuilderView.js

Source: src/js/views/queryBuilder/QueryBuilderView.jsSource: src/js/views/queryBuilder/QueryBuilderView.js -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -48,46 +48,38 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

"jquery", "underscore", "backbone", - "views/searchSelect/SearchableSelectView", + "views/searchSelect/SearchSelectView", "views/searchSelect/QueryFieldSelectView", "views/searchSelect/NodeSelectView", "views/searchSelect/AccountSelectView", "views/filters/NumericFilterView", "views/filters/DateFilterView", "views/searchSelect/ObjectFormatSelectView", - "views/searchSelect/AnnotationFilterView", - "models/filters/Filter", - "models/filters/BooleanFilter", - "models/filters/NumericFilter", - "models/filters/DateFilter", -], function ( + "views/searchSelect/BioontologySelectView", +], ( $, _, Backbone, - SearchableSelect, + SearchSelect, QueryFieldSelect, NodeSelect, AccountSelect, NumericFilterView, DateFilterView, ObjectFormatSelect, - AnnotationFilter, - Filter, - BooleanFilter, - NumericFilter, - DateFilter, -) { + BioontologySelect, +) => /** * @class QueryRuleView * @classdesc A view that provides an UI for a user to construct a single filter that * is part of a complex query * @classcategory Views/QueryBuilder * @screenshot views/QueryRuleView.png - * @extends Backbone.View - * @constructor + * @augments Backbone.View + * @class * @since 2.14.0 */ - return Backbone.View.extend( + Backbone.View.extend( /** @lends QueryRuleView.prototype */ { /** @@ -192,14 +184,14 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

/** * A function that creates and returns the Backbone events object. - * @return {Object} Returns a Backbone events object + * @returns {object} Returns a Backbone events object */ - events: function () { - var events = {}; - var removeID = "#" + this.removeRuleID + this.cid; - events["click " + removeID] = "removeSelf"; - events["mouseover " + removeID] = "previewRemove"; - events["mouseout " + removeID] = "previewRemove"; + events() { + const events = {}; + const removeID = `#${this.removeRuleID}${this.cid}`; + events[`click ${removeID}`] = "removeSelf"; + events[`mouseover ${removeID}`] = "previewRemove"; + events[`mouseout ${removeID}`] = "previewRemove"; return events; }, @@ -209,9 +201,7 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* abstracted fields which are a combination of multiple query fields, or to add a * duplicate field that has a different label. These special fields are passed on * to {@link QueryFieldSelectView#addFields}. - * * @type {SpecialField[]} - * * @since 2.15.0 */ specialFields: [ @@ -244,8 +234,7 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* when a user selects a new operator. Operators can set the exclude and * matchSubstring properties of the model, and sometimes the values as well. * Either the types property OR the fields property must be set, not both. - * - * @typedef {Object} OperatorOption + * @typedef {object} OperatorOption * @property {string} label - The label to display to the user * @property {string} icon - An icon that represents the operator * @property {boolean} matchSubstring - Whether the matchSubstring attribute is @@ -271,7 +260,6 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

/** * The list of operators that will be available in the dropdown list that connects * the query fields to the values. Each operator must be unique. - * * @type {OperatorOption[]} */ operatorOptions: [ @@ -436,8 +424,7 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* different solr query fields, and so we display different interfaces depending * on the type and category of the selected query fields. A Value Input Option * object defines a of interface to show for a given type and category. - * - * @typedef {Object} ValueInputOption + * @typedef {object} ValueInputOption * @property {string[]} filterTypes - An array of one or more filter types that * are allowed for this interface. If none are provided then any filter type is * allowed. Filter types are one of the four keys defined in @@ -453,7 +440,7 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* the special field, not the actual query fields that it represents. * @property {string} label - If the interface does not include a label (e.g. * number filter), include a string to display here. - * @property {function} uiFunction - A function that returns the UI view to use + * @property {Function} uiFunction - A function that returns the UI view to use * with all appropriate options set. The function will be called with this view as * the context. */ @@ -470,8 +457,8 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

// serviceCoupling field { queryFields: ["serviceCoupling"], - uiFunction: function () { - return new SearchableSelect({ + uiFunction() { + return new SearchSelect({ options: [ { label: "tight", @@ -495,36 +482,36 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

allowAdditions: false, inputLabel: "Select a coupling", selected: this.model.get("values"), - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, // Metadata format IDs { queryFields: ["formatId"], - uiFunction: function () { + uiFunction() { return new ObjectFormatSelect({ selected: this.model.get("values"), - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, // Semantic annotation picker { queryFields: ["sem_annotation"], - uiFunction: function () { + uiFunction() { // A bioportalAPIKey is required for the Annotation Filter UI if (MetacatUI.appModel.get("bioportalAPIKey")) { - return new AnnotationFilter({ - selected: this.model.get("values").slice(), - separatorText: this.model.get("operator"), - multiselect: true, - inputLabel: "Type a value", + return new BioontologySelect({ + selected: this.model.get("values"), + separator: this.model.get("operator"), + allowMulti: true, + allowAdditions: true, + inputLabel: "Search for a term", }); // If there's no API key, render the default UI (the last in this list) - } else { - return this.valueSelectUImap.slice(-1)[0].uiFunction.call(this); } + return this.valueSelectUImap.slice(-1)[0].uiFunction.call(this); }, }, // User/Organization account ID lookup @@ -536,10 +523,10 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

"rightsHolder", "submitter", ], - uiFunction: function () { + uiFunction() { return new AccountSelect({ selected: this.model.get("values"), - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, @@ -553,10 +540,10 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

"authoritativeMN", "datasource", ], - uiFunction: function () { + uiFunction() { return new NodeSelect({ selected: this.model.get("values"), - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, @@ -564,11 +551,11 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

{ filterTypes: ["numericFilter"], label: "Choose a value", - uiFunction: function () { + uiFunction() { return new NumericFilterView({ model: this.model, showButton: false, - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, @@ -576,23 +563,23 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

{ filterTypes: ["dateFilter"], label: "Choose a year", - uiFunction: function () { + uiFunction() { return new DateFilterView({ model: this.model, - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, // The last is the default value selection UI { - uiFunction: function () { - return new SearchableSelect({ + uiFunction() { + return new SearchSelect({ options: [], allowMulti: true, allowAdditions: true, inputLabel: "Type a value", selected: this.model.get("values"), - separatorText: this.model.get("operator"), + separator: this.model.get("operator"), }); }, }, @@ -600,191 +587,153 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

/** * Creates a new QueryRuleView - * @param {Object} options - A literal object with options to pass to the view + * @param {object} options - A literal object with options to pass to the view */ - initialize: function (options) { - try { - // Get all the options and apply them to this view - if (typeof options == "object") { - var optionKeys = Object.keys(options); - _.each( - optionKeys, - function (key, i) { - this[key] = options[key]; - }, - this, - ); - } - - // If no model is provided in the options, we cannot render this view. A - // filter model cannot be created, because it must be part of a collection. - if (!this.model || !this.model.collection) { - console.error( - "error: A Filter model that's part of a Filters collection" + - " is required to initialize a Query Rule view.", - ); - return; - } + initialize(options) { + // Apply all the options to this view + if (typeof options === "object") { + Object.assign(this, options); + } - // The model may be removed during the save process if it's empty. Remove this - // Rule Group view when that happens. - this.stopListening(this.model, "remove"); - this.listenTo(this.model, "remove", function () { - this.removeSelf(); - }); - } catch (e) { - console.log( - "Failed to initialize a Query Builder View, error message:", - e, + // If no model is provided in the options, we cannot render this view. A + // filter model cannot be created, because it must be part of a collection. + if (!this.model || !this.model.collection) { + throw new Error( + "A Filter model that's part of a Filters collection is required to initialize a Query Rule view.", ); } + + // The model may be removed during the save process if it's empty. Remove this + // Rule Group view when that happens. + this.stopListening(this.model, "remove"); + this.listenTo(this.model, "remove", () => { + this.removeSelf(); + }); }, /** * render - Render the view - * - * @return {QueryRule} Returns the view + * @returns {QueryRule} Returns the view */ - render: function () { - try { - // Add the Rule number. - // TODO: Also add the number of datasets related to rule - this.addRuleInfo(); - this.stopListening(this.model.collection, "remove"); - this.listenTo(this.model.collection, "remove", this.updateRuleInfo); - // Nested rules should also listen for changes in Filters of their parent Rule - if (this.parentRule) { - this.stopListening(this.parentRule.model.collection, "remove"); - this.listenTo( - this.parentRule.model.collection, - "remove", - this.updateRuleInfo, - ); - } - - // The remove button is needed for both FilterGroups and other Filter models - this.addRemoveButton(); - - // Render nested filter group views as another Query Builder. - if (this.model.type == "FilterGroup") { - this.$el.addClass("rule-group"); - - // We must initialize a QueryBuilderView using the inline require syntax to - // avoid the problem of circular dependencies. QueryRuleView requires - // QueryBuilderView, and QueryBuilderView requires QueryRuleView. For more - // info, see https://requirejs.org/docs/api.html#circular - var QueryBuilderView = require("views/queryBuilder/QueryBuilderView"); - - // The default - nestedLevelsAllowed = 1; - // If we are adding a query builer, then it is a nested level. Subtract one - // from the total levels allowed. - if (typeof this.nestedLevelsAllowed == "number") { - nestedLevelsAllowed = this.nestedLevelsAllowed - 1; - } + render() { + // Add the Rule number. + // TODO: Also add the number of datasets related to rule + this.addRuleInfo(); + this.stopListening(this.model.collection, "remove"); + this.listenTo(this.model.collection, "remove", this.updateRuleInfo); + // Nested rules should also listen for changes in Filters of their parent Rule + if (this.parentRule) { + this.stopListening(this.parentRule.model.collection, "remove"); + this.listenTo( + this.parentRule.model.collection, + "remove", + this.updateRuleInfo, + ); + } - // If there is a special list of fields to exclude in nested Query Builders - // (i.e. in nested FilterGroup models), then pass this list on as the - // excludeFields list in the child QueryBuilder - var excludeFields = this.excludeFields; - if ( - this.nestedExcludeFields && - Array.isArray(this.nestedExcludeFields) - ) { - excludeFields = this.nestedExcludeFields; - } + // The remove button is needed for both FilterGroups and other Filter models + this.addRemoveButton(); + + // Render nested filter group views as another Query Builder. + if (this.model.type === "FilterGroup") { + this.$el.addClass("rule-group"); + + // We must initialize a QueryBuilderView using the inline require syntax to + // avoid the problem of circular dependencies. QueryRuleView requires + // QueryBuilderView, and QueryBuilderView requires QueryRuleView. For more + // info, see https://requirejs.org/docs/api.html#circular + const QueryBuilderView = require("views/queryBuilder/QueryBuilderView"); + + // The default + let nestedLevelsAllowed = 1; + // If we are adding a query builer, then it is a nested level. Subtract one + // from the total levels allowed. + if (typeof this.nestedLevelsAllowed === "number") { + nestedLevelsAllowed = this.nestedLevelsAllowed - 1; + } - // Insert QueryRuleView - var ruleGroup = new QueryBuilderView({ - filterGroup: this.model, - // Nested Query Rules have the same color as their parent rule - ruleColorPalette: "inherit", - excludeFields: excludeFields, - specialFields: this.specialFields, - parentRule: this, - nestedLevelsAllowed: nestedLevelsAllowed, - }); - this.el.append(ruleGroup.el); - ruleGroup.render(); - } else { - // For any other filter type... Add a metadata selector field whether the - // rule is new or has already been created - this.addFieldSelect(); - - // Operator field and value field Add an operator input only for already - // existing filters (For new filters, a metadata field needs to be selected - // first) - if (this.model.get("fields") && this.model.get("fields").length) { - this.addOperatorSelect(); - this.addValueSelect(); - } + // If there is a special list of fields to exclude in nested Query Builders + // (i.e. in nested FilterGroup models), then pass this list on as the + // excludeFields list in the child QueryBuilder + let { excludeFields } = this; + if ( + this.nestedExcludeFields && + Array.isArray(this.nestedExcludeFields) + ) { + excludeFields = this.nestedExcludeFields; } - return this; - } catch (e) { - console.error( - "Error rendering the query Rule View, error message: ", - e, - ); + // Insert QueryRuleView + const ruleGroup = new QueryBuilderView({ + filterGroup: this.model, + // Nested Query Rules have the same color as their parent rule + ruleColorPalette: "inherit", + excludeFields, + specialFields: this.specialFields, + parentRule: this, + nestedLevelsAllowed, + }); + this.el.append(ruleGroup.el); + ruleGroup.render(); + } else { + // For any other filter type... Add a metadata selector field whether the + // rule is new or has already been created + this.addFieldSelect(); + + // Operator field and value field Add an operator input only for already + // existing filters (For new filters, a metadata field needs to be selected + // first) + if (this.model.get("fields") && this.model.get("fields").length) { + this.addOperatorSelect(); + this.addValueSelect(); + } } + + return this; }, /** * Insert container for the color-coded rule numbering. */ - addRuleInfo: function () { - try { - this.$indexEl = $(document.createElement("span")); - this.$ruleInfoEl = $(document.createElement("div")).addClass( - this.ruleInfoClass, - ); - this.$ruleInfoEl.append(this.$indexEl); + addRuleInfo() { + this.$indexEl = $(document.createElement("span")); + this.$ruleInfoEl = $(document.createElement("div")).addClass( + this.ruleInfoClass, + ); + this.$ruleInfoEl.append(this.$indexEl); - this.$el.append(this.$ruleInfoEl); - this.updateRuleInfo(); - } catch (error) { - console.log( - "Error adding rule info container for a Query Rule, details: " + - error, - ); - } + this.$el.append(this.$ruleInfoEl); + this.updateRuleInfo(); }, /** - * Selects a color from the - * {@link QueryRuleView#ruleColorPalette rule colour palette array}, given an + * Selects a color from the {@link QueryRuleView#ruleColorPalette}, given an * index. If the index is greater than the length of the palette, then the palette * is effectively repeated until long enough (i.e. colours will be recycled). If * no index in provided, the first colour in the palette will be selected. - * - * @param {number} [index=0] - The position of the rule within the Filters + * @param {number} [index] - The position of the rule within the Filters * collection. - * @param {string} [defaultColor="#57b39c"] - A default colour to use in case + * @param {string} [defaultColor] - A default colour to use in case * there is problem with this function (hex color code beginning with '#'). - * @return {string} - Returns a hex color code string + * @returns {string} - Returns a hex color code string */ - getPaletteColor: function (index = 0, defaultColor = "#57b39c") { + getPaletteColor(index = 0, defaultColor = "#57b39c") { try { - // Allow the rule to inherit it's color from the parent rule within which it's + // Allow the rule to inherit its color from the parent rule within which it's // nested - if (this.ruleColorPalette == "inherit") { + if (this.ruleColorPalette === "inherit") { return null; } + if (!this.ruleColorPalette || !this.ruleColorPalette.length) { return defaultColor; } - var numCols = this.ruleColorPalette.length; - if (index + 1 > numCols) { - var n = Math.floor(index / numCols); - index = index - numCols * n; - } - return this.ruleColorPalette[index]; - } catch (error) { - console.log( - "Error getting a color for a Query Rule, using the default colour" + - " instead. Error details: " + - error, - ); + + const numCols = this.ruleColorPalette.length; + const adjustedIndex = index % numCols; + + return this.ruleColorPalette[adjustedIndex]; + } catch { return defaultColor; } }, @@ -795,74 +744,55 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* the rule number, but may one day also display information such as the number of * results that there are for this individual rule. */ - updateRuleInfo: function () { - try { - // Rules are numbered in the order in which they appear in the Filters - // collection, excluding any invisible filter models. Rules nested in Rule - // Groups (within Filter Models) get numbered 3A, 3B, etc. - var letter = ""; - var index = ""; - // If this is a filter model nested in a filter group - if (this.parentRule) { - index = this.parentRule.ruleNumber; - var letterIndex = this.model.collection.visibleIndexOf(this.model); - if (typeof letterIndex === "number") { - letter = String.fromCharCode(94 + letterIndex + 3).toUpperCase(); - } - // For top-level filter models - } else { - index = this.model.collection.visibleIndexOf(this.model); + updateRuleInfo() { + // Rules are numbered in the order in which they appear in the Filters + // collection, excluding any invisible filter models. Rules nested in Rule + // Groups (within Filter Models) get numbered 3A, 3B, etc. + let letter = ""; + let index = ""; + // If this is a filter model nested in a filter group + if (this.parentRule) { + index = this.parentRule.ruleNumber; + const letterIndex = this.model.collection.visibleIndexOf(this.model); + if (typeof letterIndex === "number") { + letter = String.fromCharCode(94 + letterIndex + 3).toUpperCase(); } + // For top-level filter models + } else { + index = this.model.collection.visibleIndexOf(this.model); + } - if (typeof index == "number") { - index = index + 1; - } + if (typeof index === "number") { + index += 1; + } - var ruleNumber = index + letter; + const ruleNumber = index + letter; - // Set the rule number of the parent view to be accessed by any nested child - // rules - this.ruleNumber = ruleNumber; + // Set the rule number of the parent view to be accessed by any nested child + // rules + this.ruleNumber = ruleNumber; - // if(this.model.type == "FilterGroup") - if (ruleNumber && ruleNumber.length) { - this.$indexEl.text("Rule " + ruleNumber); - } else { - this.$indexEl.text(""); - return; - } - var color = this.getPaletteColor(index); - if (color) { - this.el.style.setProperty("--rule-color", color); - } - } catch (error) { - console.log( - "Error updating the rule numbering for a Query Rule. Details: " + - error, - ); + // if(this.model.type == "FilterGroup") + if (ruleNumber && ruleNumber.length) { + this.$indexEl.text(`Rule ${ruleNumber}`); + } else { + this.$indexEl.text(""); + return; + } + const color = this.getPaletteColor(index); + if (color) { + this.el.style.setProperty("--rule-color", color); } }, /** * addRemoveButton - Create and insert the button to remove the Query Rule */ - addRemoveButton: function () { - try { - var removeButton = $( - "<i id='" + - this.removeRuleID + - this.cid + - "' class='" + - this.removeClass + - " icon icon-remove' title='Remove this Query Rule'></i>", - ); - this.el.append(removeButton[0]); - } catch (e) { - console.error( - "Failed to create a remove button for a Query Rule, error details: " + - e, - ); - } + addRemoveButton() { + const removeButton = $( + `<i id='${this.removeRuleID}${this.cid}' class='${this.removeClass} icon icon-remove' title='Remove this Query Rule'></i>`, + ); + this.el.append(removeButton[0]); }, /** @@ -873,36 +803,34 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* in the special field's "fields" property. If the special field has an array set * for "values", then the model's values must also exactly match the special * field's values. - * * @param {string[]} [fields] - Optionally set a list of query fields to search * with. If not set, then the fields that are set on the view's filter model are * used. * @returns {SpecialField|null} - The matching special field, or null if no match * was found. - * * @since 2.15.0 */ - getSpecialField: function (fields) { + getSpecialField(fields) { // Get information about the filter model (or used the fields passed to this // function) - var selectedFields = fields || this.model.get("fields"); - var selectedFields = _.clone(selectedFields); - var selectedValues = this.model.get("values"); + const originalSelectedFields = fields || this.model.get("fields"); + const selectedFields = _.clone(originalSelectedFields); + const selectedValues = this.model.get("values"); if (!this.specialFields || !Array.isArray(this.specialFields)) { return null; } - var matchingSpecialField = _.find( + const matchingSpecialField = _.find( this.specialFields, - function (specialField) { - var fieldsMatch = false, - mustMatchValues = false, - valuesMatch = false; + (specialField) => { + let fieldsMatch = false; + let mustMatchValues = false; + let valuesMatch = false; // If *all* the fields in the fields array are present in the list // of fields that the special field represents, then count this as a match. - var commonFields = _.intersection( + const commonFields = _.intersection( specialField.fields, selectedFields, ); @@ -928,73 +856,50 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

// If this model matches one of the special fields, render it differently return matchingSpecialField || null; }, - /** - * Takes a list of query field names, checks if the model matches any of the - * special fields, and if it does, returns the list of fields with the actual - * field names replaced with the - * {@link QueryRuleView#specialFields special field name}. This function is the - * opposite of {@link QueryRuleView#convertFromSpecialFields} - * @param {string[]} fields - The list of field names to convert - * @returns {string[]} - The converted list of field names. If there were no - * special fields detected, or if there's an error, then then the field names are - * returned unchanged. - * - * @param {string[]} fields - The list of fields to convert to special fields, if - * the model matches any of the special field objects - * @returns {string[]} - Returns the list of fields with actual query field names - * replaced with special field names, if any match - * - * @since 2.15.0 + * Converts a list of query field names to special field names based on matches + * from the special fields defined. If a field matches a special field's subfields, + * it is replaced by the special field name. + * @param {string[]} fields - The list of field names to convert + * @returns {string[]} - The converted list of field names. If no special fields are + * detected, then the field names are returned unchanged. */ - convertToSpecialFields: function (fields) { - try { - var fields = _.clone(fields); - - // Insert the special field name at the same position as the associated - // query fields that we will remove - var replaceWithSpecialField = function (fields, specialField) { - if (specialField) { - position = _.findIndex( - fields, - function (selectedField) { - return specialField.fields.includes(selectedField); - }, - this, - ); - fields.splice(position, 0, specialField.name); - fields = _.difference(fields, specialField.fields); - } - return fields; - }; + convertToSpecialFields(fields) { + let fieldsCopy = [...fields]; - // If the user selected a special field, make sure we convert those first - if (this.selectedSpecialFields && this.selectedSpecialFields.length) { - this.selectedSpecialFields.forEach(function (specialFiend) { - fields = replaceWithSpecialField(fields, specialFiend); - }, this); + // Helper function to replace fields with a special field name + const replaceWithSpecialField = (originalFields, specialField) => { + const position = originalFields.findIndex((field) => + specialField.fields.includes(field), + ); + if (position !== -1) { + originalFields.splice( + position, + specialField.fields.length, + specialField.name, + ); } + return originalFields; + }; - // Search for remaining special fields given the fields and model values - var matchingSpecialField = this.getSpecialField(fields); - - // There may be more than one special field in the list of fields... - while (matchingSpecialField !== null) { - fields = replaceWithSpecialField(fields, matchingSpecialField); - // Check if there are more special fields remaining - matchingSpecialField = this.getSpecialField(fields); - } + // Iterate over each selected special field to transform the fields array + if (this.selectedSpecialFields && this.selectedSpecialFields.length) { + this.selectedSpecialFields.forEach((specialField) => { + fieldsCopy = replaceWithSpecialField(fieldsCopy, specialField); + }); + } - return fields; - } catch (error) { - console.log( - "Error converting query field names to special field names in" + - " a Query Rule View. Returning the list of fields unchanged." + - " Error details : " + - error, + // Replace any remaining matches + let matchingSpecialField = this.getSpecialField(fieldsCopy); + while (matchingSpecialField) { + fieldsCopy = replaceWithSpecialField( + fieldsCopy, + matchingSpecialField, ); - return fields; + matchingSpecialField = this.getSpecialField(fieldsCopy); } + + return fieldsCopy; }, /** @@ -1005,43 +910,30 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* array set on the view's selectedSpecialFields property. selectedSpecialFields * is cleared each time this function runs. This function is the opposite of * {@link QueryRuleView#convertToSpecialFields} - * @param {string[]} fields] - The list of field names to convert - * @returns {string[]} - The converted list of field names. If there were no - * special fields detected, or if there's an error, then then the field names are - * returned unchanged. - * * @param {string[]} fields - The list of fields to convert to actual query * service index fields * @returns {string[]} - Returns the list of fields with any special field - * replaced with real fields from the query service index - * + * replaced with real fields from the query service index. If there were no + * special fields detected, or if there's an error, then then the field names are + * returned unchanged. * @since 2.15.0 */ - convertFromSpecialFields: function (fields) { + convertFromSpecialFields(fields) { try { this.selectedSpecialFields = []; if (this.specialFields) { - this.specialFields.forEach(function (specialField) { - var index = fields.indexOf(specialField.name); + this.specialFields.forEach((specialField) => { + const index = fields.indexOf(specialField.name); if (index >= 0) { // Keep a record that the user selected a special field (useful in the // case that the special field is just a duplicate of another field) this.selectedSpecialFields.push(specialField); - fields.splice.apply( - fields, - [index, 1].concat(specialField.fields), - ); + fields.splice(index, 1, ...specialField.fields); } }, this); } return fields; } catch (error) { - console.log( - "Error converting special query fields to query fields that" + - " exist in the index in a Query Rule View. Returning the fields" + - " unchanged. Error details: " + - error, - ); return fields; } }, @@ -1050,793 +942,645 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* Create and insert an input that allows the user to select a metadata field to * query */ - addFieldSelect: function () { - try { - // Check whether the filter model set on this view contains query fields - // and values that match one of the special rules. If it does, - // convert the list of field names to special field to pass on to the - // Query Field Select View. - var selectedFields = _.clone(this.model.get("fields")); - var selectedFields = this.convertToSpecialFields(selectedFields); - - this.fieldSelect = new QueryFieldSelect({ - selected: selectedFields, - excludeFields: this.excludeFields, - addFields: this.specialFields, - separatorText: this.model.get("fieldsOperator"), - }); - this.fieldSelect.$el.addClass(this.fieldsClass); - this.el.append(this.fieldSelect.el); - this.fieldSelect.render(); - - // Update the model when the fieldsOperator changes - this.stopListening(this.fieldSelect, "separatorChanged"); - this.listenTo( - this.fieldSelect, - "separatorChanged", - function (newOperator) { - this.model.set("fieldsOperator", newOperator); - }, - ); - // Update model when the selected fields change - this.stopListening(this.fieldSelect, "changeSelection"); - this.listenTo( - this.fieldSelect, - "changeSelection", - this.handleFieldChange, - ); - } catch (e) { - console.error( - "Error adding a metadata selector input in the Query Rule" + - " View, error message:", - e, - ); - } + addFieldSelect() { + // Check whether the filter model set on this view contains query fields + // and values that match one of the special rules. If it does, + // convert the list of field names to special field to pass on to the + // Query Field Select View. + let selectedFields = _.clone(this.model.get("fields")); + selectedFields = this.convertToSpecialFields(selectedFields); + + this.fieldSelect = new QueryFieldSelect({ + selected: selectedFields, + excludeFields: this.excludeFields, + addFields: this.specialFields, + separator: this.model.get("fieldsOperator"), + }); + this.fieldSelect.$el.addClass(this.fieldsClass); + this.el.append(this.fieldSelect.el); + this.fieldSelect.render(); + + // Update the model when the fieldsOperator changes + this.stopListening(this.fieldSelect.model, "change:separator"); + this.listenTo( + this.fieldSelect.model, + "change:separator", + (_model, newOperator) => { + this.model.set("fieldsOperator", newOperator); + }, + ); + // Update model when the selected fields change + this.stopListening(this.fieldSelect.model, "change:selected"); + this.listenTo( + this.fieldSelect.model, + "change:selected", + (_model, fields) => { + this.handleFieldChange(fields); + }, + ); }, /** - * handleFieldChange - Called when the Query Field Select View triggers a change + * Called when the Query Field Select View triggers a change * event. Updates the model with the new fields, and if required, * 1) converts the filter model to a different type based on the types of fields - * selected, 2) updates the operator select and the value select - * - * @param {string[]} newFields The list of new query fields that were selected + * selected, 2) updates the operator select and the value select + * @param {string[]} fields The list of new query fields that were selected */ - handleFieldChange: function (newFields) { - try { - // Uncomment the following chunk to clear operator & values when the field - // input is cleared. - // if(!newFields || newFields.length === 0 || newFields[0] === ""){ - // if(this.operatorSelect){ - // this.operatorSelect.changeSelection([""]); - // } - // this.model.set("fields", this.model.defaults().fields); - // return - // } - - // Get the selected operator before the field changed - var opBefore = this.getSelectedOperator(); - - // If any of the new fields are special fields, replace them with the - // actual query fields before setting them in the model... - newFields = this.convertFromSpecialFields(newFields); - - // Get the current type of filter and required type given the newly selected - // fields - var typeBefore = this.model.get("nodeName"), - typeAfter = MetacatUI.queryFields.getRequiredFilterType(newFields); - - // If the type has changed, then replace the model with one of the correct - // type, update the value and operator inputs, and do nothing else - if (typeBefore != typeAfter) { - this.model = this.model.collection.replaceModel(this.model, { - filterType: typeAfter, - fields: newFields, - }); - this.removeInput("value"); - this.removeInput("operator"); - this.addOperatorSelect(""); - return; - } + handleFieldChange(fields) { + // Get the selected operator before the field changed + const opBefore = this.getSelectedOperator(); + + // If any of the new fields are special fields, replace them with the + // actual query fields before setting them in the model... + const newFields = this.convertFromSpecialFields(fields); + + // Get the current type of filter and required type given the newly selected + // fields + const typeBefore = this.model.get("nodeName"); + const typeAfter = + MetacatUI.queryFields.getRequiredFilterType(newFields); + + // If the type has changed, then replace the model with one of the correct + // type, update the value and operator inputs, and do nothing else + if (typeBefore !== typeAfter) { + this.model = this.model.collection.replaceModel(this.model, { + filterType: typeAfter, + fields: newFields, + }); + this.removeInput("value"); + this.removeInput("operator"); + this.addOperatorSelect(""); + return; + } - // If the filter model type is the same, and the operator options are the same - // for the selected fields, then update the model - this.model.set("fields", newFields); - - // Get the selected operator now that we've updated the model with new fields - var opAfter = this.getSelectedOperator(); - - // Add an empty operator input field, if there isn't one - if (!this.operatorSelect) { - this.addOperatorSelect(""); - // If the operator options have changed, refresh the operator input - } else if (opAfter !== opBefore) { - this.removeInput("operator"); - // Make sure that we overwrite any values that don't apply to the new options. - this.handleOperatorChange([""]); - this.addOperatorSelect(""); - return; - } + // If the filter model type is the same, and the operator options are the same + // for the selected fields, then update the model + this.model.set("fields", newFields); + + // Get the selected operator now that we've updated the model with new fields + const opAfter = this.getSelectedOperator(); + + // Add an empty operator input field, if there isn't one + if (!this.operatorSelect) { + this.addOperatorSelect(""); + // If the operator options have changed, refresh the operator input + } else if (opAfter !== opBefore) { + this.removeInput("operator"); + // Make sure that we overwrite any values that don't apply to the new options. + this.handleOperatorChange([""]); + this.addOperatorSelect(""); + return; + } - // Refresh the value select in case a different value input is required for - // the new fields - if (this.valueSelect) { - this.removeInput("value"); - this.addValueSelect(); - } - } catch (e) { - console.error( - "Failed to handle query field change in the Query Rule View," + - " error message: " + - e, - ); + // Refresh the value select in case a different value input is required for + // the new fields + if (this.valueSelect) { + this.removeInput("value"); + this.addValueSelect(); } }, /** * Create and insert an input field where the user can select an operator for the * given rule. Operators will vary depending on filter model type. - * - * @param {string} selectedOperator - optional. The label of an operator to + * @param {string} operator - optional. The label of an operator to * pre-select. Set to an empty string to render an empty operator selector. */ - addOperatorSelect: function (selectedOperator) { - try { - var view = this; - var operatorError = false; - - var options = this.getOperatorOptions(); - - // Identify the selected operator for existing models - if (typeof selectedOperator !== "string") { - selectedOperator = this.getSelectedOperator(); - // If there was no operator found, then this is probably an unsupported - // combination of exclude + matchSubstring + filterType - if (selectedOperator === "") { - operatorError = true; - } - } - + addOperatorSelect(operator) { + const view = this; + const options = this.getOperatorOptions(); + let operatorError = false; + let selectedOperator = operator; + + // Identify the selected operator for existing models + if (typeof selectedOperator !== "string") { + selectedOperator = this.getSelectedOperator(); + // If there was no operator found, then this is probably an unsupported + // combination of exclude + matchSubstring + filterType if (selectedOperator === "") { - selectedOperator = []; - } else { - selectedOperator = [selectedOperator]; - } - - this.operatorSelect = new SearchableSelect({ - options: options, - allowMulti: false, - inputLabel: "Select an operator", - clearable: false, - placeholderText: "Select an operator", - selected: selectedOperator, - }); - this.operatorSelect.$el.addClass(this.operatorClass); - this.el.append(this.operatorSelect.el); - - if (operatorError) { - view.listenToOnce(view.operatorSelect, "postRender", function () { - view.operatorSelect.showMessage( - "Please select a valid operator", - "error", - true, - ); - }); + operatorError = true; } + } - this.operatorSelect.render(); + if (selectedOperator === "") { + selectedOperator = []; + } else { + selectedOperator = [selectedOperator]; + } - // Update model when the values change - this.stopListening(this.operatorSelect, "changeSelection"); - this.listenTo( - this.operatorSelect, - "changeSelection", - this.handleOperatorChange, - ); - } catch (e) { - console.error( - "Error adding an operator selector input in the Query Rule " + - "View, error message:", - e, - ); + this.operatorSelect = new SearchSelect({ + options, + allowMulti: false, + inputLabel: "Select an operator", + clearable: false, + placeholderText: "Select an operator", + selected: selectedOperator, + }); + this.operatorSelect.$el.addClass(this.operatorClass); + this.el.append(this.operatorSelect.el); + + this.operatorSelect.render(); + + if (operatorError) { + view.operatorSelect.showInvalidSelectionError(); } + + // Update model when the values change + this.stopListening(this.operatorSelect.model, "change:selected"); + this.listenTo( + this.operatorSelect.model, + "change:selected", + (_model, newOperator) => { + this.handleOperatorChange(newOperator); + }, + ); }, /** * handleOperatorChange - When the operator selection is changed, update the model * and re-set the value UI when required - * * @param {string[]} newOperatorLabel The new operator label within an array, * e.g. ["is greater than"] */ - handleOperatorChange: function (newOperatorLabel) { - try { - var view = this; - - if (!newOperatorLabel || newOperatorLabel[0] == "") { - var modelDefaults = this.model.defaults(); - this.model.set({ - min: modelDefaults.min, - max: modelDefaults.max, - values: modelDefaults.values, - }); - this.removeInput("value"); - return; - } - - // Get the properties of the newly selected operator. The newOperatorLabel - // will be an array with one value. Select only from the available options, - // since there may be multiple options with the same label in - // this.operatorOptions. - var options = this.getOperatorOptions(); - var operator = _.findWhere(options, { label: newOperatorLabel[0] }); - - // Gather information about which values are currently set on the model, and - // which are required - var // Type - type = view.model.get("nodeName"), - isNumeric = ["dateFilter", "numericFilter"].includes(type), - isRange = operator.hasMin && operator.hasMax, - // Values - modelValues = this.model.get("values"), - modelHasValues = modelValues - ? modelValues && modelValues.length - : false, - modelFirstValue = modelHasValues ? modelValues[0] : null, - modelValueInt = parseInt(modelFirstValue) - ? parseInt(modelFirstValue) - : null, - needsValue = - isNumeric && - !modelValueInt && - !operator.hasMin && - !operator.hasMax, - // Min - modelMin = this.model.get("min"), - modelHasMin = modelMin === 0 || modelMin, - needsMin = operator.hasMin && !modelHasMin, - // Max - modelMax = this.model.get("max"), - modelHasMax = modelMax === 0 || modelMax, - needsMax = operator.hasMax && !modelHasMax; - - // Some operator options include a specific value to be set on the model. For - // example, "is not empty", should set the model value to the "*" wildcard. - // For operators with these specific value requirements, update the filter - // model value and remove the value select input. - if (operator.values && operator.values.length) { - this.removeInput("value"); - this.model.set("values", operator.values); - // If the operator does not have a default value, then ensure that there is - // a value select available. - } else { - if (!this.valueSelect) { - this.model.set("values", view.model.defaults().values); - this.addValueSelect(); - } - } - - // Update the model with true or false for matchSubstring and exclude - ["matchSubstring", "exclude"].forEach((prop, i) => { - if (typeof operator[prop] !== "undefined") { - view.model.set(prop, operator[prop]); - } else { - view.model.set(prop, view.model.defaults()[prop]); - } + handleOperatorChange(newOperatorLabel) { + const view = this; + + if (!newOperatorLabel || newOperatorLabel[0] === "") { + const modelDefaults = this.model.defaults(); + this.model.set({ + min: modelDefaults.min, + max: modelDefaults.max, + values: modelDefaults.values, }); + this.removeInput("value"); + return; + } - // Set min & max values as required by the operator - // TODO - test this strategy with dates... - - // Add a minimum value if one is needed - if (needsMin) { - // Search for the min in the values, then in the max - if (modelValueInt || modelValueInt === 0) { - this.model.set("min", modelValueInt); - } else if (modelHasMax) { - this.model.set("min", modelMax); - } else { - this.model.set("min", 0); - } - } + // Get the properties of the newly selected operator. The newOperatorLabel + // will be an array with one value. Select only from the available options, + // since there may be multiple options with the same label in + // this.operatorOptions. + const options = this.getOperatorOptions(); + const operator = _.findWhere(options, { label: newOperatorLabel[0] }); + + // Gather information about which values are currently set on the model, and + // which are required + const // Type + type = view.model.get("nodeName"); + const isNumeric = ["dateFilter", "numericFilter"].includes(type); + const isRange = operator.hasMin && operator.hasMax; + // Values + const modelValues = this.model.get("values"); + const modelHasValues = modelValues + ? modelValues && modelValues.length + : false; + const modelFirstValue = modelHasValues ? modelValues[0] : null; + const modelValueInt = parseInt(modelFirstValue, 10) + ? parseInt(modelFirstValue, 10) + : null; + const needsValue = + isNumeric && !modelValueInt && !operator.hasMin && !operator.hasMax; + // Min + const modelMin = this.model.get("min"); + const modelHasMin = modelMin === 0 || modelMin; + const needsMin = operator.hasMin && !modelHasMin; + // Max + const modelMax = this.model.get("max"); + const modelHasMax = modelMax === 0 || modelMax; + const needsMax = operator.hasMax && !modelHasMax; + + // Some operator options include a specific value to be set on the model. For + // example, "is not empty", should set the model value to the "*" wildcard. + // For operators with these specific value requirements, update the filter + // model value and remove the value select input. + if (operator.values && operator.values.length) { + this.removeInput("value"); + this.model.set("values", operator.values); + // If the operator does not have a default value, then ensure that there is + // a value select available. + } else if (!this.valueSelect) { + this.model.set("values", view.model.defaults().values); + this.addValueSelect(); + } - // Add a maximum value if one is needed - if (needsMax) { - // Search for the min in the values, then in the max - if (modelValueInt || modelValueInt === 0) { - this.model.set("max", modelValueInt); - } else if (modelHasMin) { - this.model.set("max", modelMin); - } else { - this.model.set("max", 0); - } + // Update the model with true or false for matchSubstring and exclude + ["matchSubstring", "exclude"].forEach((prop) => { + if (typeof operator[prop] !== "undefined") { + view.model.set(prop, operator[prop]); + } else { + view.model.set(prop, view.model.defaults()[prop]); } - - // Add a value if one is needed - if (needsValue) { - if (modelHasMin) { - this.model.set("values", [modelMin]); - } else if (modelHasMax) { - this.model.set("values", [modelMax]); - } else { - this.model.set("values", [0]); - } + }); + + // Set min & max values as required by the operator + // TODO - test this strategy with dates... + + // Add a minimum value if one is needed + if (needsMin) { + // Search for the min in the values, then in the max + if (modelValueInt || modelValueInt === 0) { + this.model.set("min", modelValueInt); + } else if (modelHasMax) { + this.model.set("min", modelMax); + } else { + this.model.set("min", 0); } + } - // Remove the minimum and max if they should not be included in the filter - if (modelHasMax && !operator.hasMax) { - this.model.set("max", this.model.defaults().max); - } - if (modelHasMin && !operator.hasMin) { - this.model.set("min", this.model.defaults().min); + // Add a maximum value if one is needed + if (needsMax) { + // Search for the min in the values, then in the max + if (modelValueInt || modelValueInt === 0) { + this.model.set("max", modelValueInt); + } else if (modelHasMin) { + this.model.set("max", modelMin); + } else { + this.model.set("max", 0); } + } - if (isRange) { - this.model.set("range", true); + // Add a value if one is needed + if (needsValue) { + if (modelHasMin) { + this.model.set("values", [modelMin]); + } else if (modelHasMax) { + this.model.set("values", [modelMax]); } else { - if (isNumeric) { - this.model.set("range", false); - } else { - this.model.unset("range"); - } + this.model.set("values", [0]); } + } - // If the operator changed for a numeric or date field, reset the value - // select. This way it can change from a range to a single value input if - // needed. - if (isNumeric) { - this.removeInput("value"); - this.addValueSelect(); - } - } catch (e) { - console.error( - "Failed to handle the operator selection in a Query Rule " + - "view, error message: " + - e, - ); + // Remove the minimum and max if they should not be included in the filter + if (modelHasMax && !operator.hasMax) { + this.model.set("max", this.model.defaults().max); + } + if (modelHasMin && !operator.hasMin) { + this.model.set("min", this.model.defaults().min); + } + + if (isRange) { + this.model.set("range", true); + } else if (isNumeric) { + this.model.set("range", false); + } else { + this.model.unset("range"); + } + + // If the operator changed for a numeric or date field, reset the value + // select. This way it can change from a range to a single value input if + // needed. + if (isNumeric) { + this.removeInput("value"); + this.addValueSelect(); } }, /** * Get a list of {@link QueryRuleView#operatorOptions operatorOptions} that are * allowed for this view's filter model - * - * @param {string[]} [fields] - Optional list of fields to use instead of the + * @param {string[]} [inputFields] - Optional list of fields to use instead of the * fields set on this view's Filter model - * + * @returns {object[]} - Returns an array of operator options that are allowed for + * this view's filter model * @since 2.15.0 */ - getOperatorOptions: function (fields) { - try { - // Check which type of rule this is (boolean, numeric, text, date) - var type = this.model.get("nodeName"); - - // If this rule contains a special field, replace the real query field names - // with the special field names for the purpose of selecting operator options - var fields = fields || this.model.get("fields"); - var fields = _.clone(fields); - var fields = this.convertToSpecialFields(fields); - - // Get the list of options for a user to select from based on field name. - // All of the rule's fields must be contained within the operator option's - // list of allowed fields for it to be a match. - var options = _.filter(this.operatorOptions, function (option) { - if (option.fields) { - return _.every(fields, function (fieldName) { - return option.fields.includes(fieldName); - }); - } - }); - - // Get the list of options for a user to select from based on type, if there - // were none that matched based on field names - if (!options || !options.length) { - options = _.filter( - this.operatorOptions, - function (option) { - if (option.types) { - return option.types.includes(type); - } - }, - this, + getOperatorOptions(inputFields) { + // Check which type of rule this is (boolean, numeric, text, date) + const type = this.model.get("nodeName"); + + // If this rule contains a special field, replace the real query field names + // with the special field names for the purpose of selecting operator options + let fields = inputFields || this.model.get("fields"); + fields = _.clone(fields); + fields = this.convertToSpecialFields(fields); + + // Get the list of options for a user to select from based on field name. + // All of the rule's fields must be contained within the operator option's + // list of allowed fields for it to be a match. + let options = _.filter(this.operatorOptions, (option) => { + if (option.fields) { + return _.every(fields, (fieldName) => + option.fields.includes(fieldName), ); } + return false; + }); - return options; - } catch (error) { - console.log( - "Error getting operator options in a Query Rule View, " + - "Error details: " + - error, - ); + // Function to check if option types include the specified type + const includesType = (option) => + option.types && option.types.includes(type); + + // Get the list of options for a user to select from based on type, if there + // were none that matched based on field names + if (!options || !options.length) { + options = this.operatorOptions.filter(includesType); } + + return options; }, /** * getSelectedOperator - Based on values set on the model, get the label to show * in the "operator" filed of the Query Rule - * - * @return {string} The operator label + * @returns {string} The operator label */ - getSelectedOperator: function () { - try { - // This view - var view = this, - // The options that we will filter down - options = this.operatorOptions, - // The user-facing operator label that we will return - selectedOperator = ""; - - // --- Filter 1 - Filter options by type --- // - - // Reduce list of options to only those that apply to the current filter type - var type = view.model.get("nodeName"); - var options = this.getOperatorOptions(); - - // --- Filter 2 - filter by 'matchSubstring', 'exclude', 'min', 'max' --- // - - // Create the conditions based on the model - var conditions = _.pick( - this.model.attributes, - "matchSubstring", - "exclude", - "min", - "max", - ); + getSelectedOperator() { + // This view + const view = this; + // The user-facing operator label that we will return + let selectedOperator = ""; + + // --- Filter 1 - Filter options by type --- // + + // Reduce list of options to only those that apply to the current filter type + const type = view.model.get("nodeName"); + let operatorOptions = this.getOperatorOptions(); + + // --- Filter 2 - filter by 'matchSubstring', 'exclude', 'min', 'max' --- // + + // Create the conditions based on the model + const conditions = _.pick( + this.model.attributes, + "matchSubstring", + "exclude", + "min", + "max", + ); - var isNumeric = ["dateFilter", "numericFilter"].includes(type); + const isNumeric = ["dateFilter", "numericFilter"].includes(type); - if (!conditions.min && conditions.min !== 0) { - if (isNumeric) { - conditions.hasMin = false; - } - } else if (isNumeric) { - conditions.hasMin = true; + if (!conditions.min && conditions.min !== 0) { + if (isNumeric) { + conditions.hasMin = false; } - if (!conditions.max && conditions.max !== 0) { - if (isNumeric) { - conditions.hasMax = false; - } - } else if (isNumeric) { - conditions.hasMax = true; + } else if (isNumeric) { + conditions.hasMin = true; + } + if (!conditions.max && conditions.max !== 0) { + if (isNumeric) { + conditions.hasMax = false; } + } else if (isNumeric) { + conditions.hasMax = true; + } - delete conditions.min; - delete conditions.max; + delete conditions.min; + delete conditions.max; - var options = _.where(options, conditions); + operatorOptions = _.where(operatorOptions, conditions); - // --- Filter 3 - filter based on the value, if there's > 1 option --- // + // --- Filter 3 - filter based on the value, if there's > 1 option --- // - if (options.length > 1) { - // Model values that determine the user-facing operator eg ["*"], [true], - // [false] - var specialValues = _.compact( - _.pluck(this.operatorOptions, "values"), - ), - specialValues = specialValues.map((val) => JSON.stringify(val)), - specialValues = _.uniq(specialValues); + if (operatorOptions.length > 1) { + // Model values that determine the user-facing operator eg ["*"], [true], + // [false] + let specialValues = _.compact( + _.pluck(this.operatorOptions, "values"), + ); + specialValues = specialValues.map((val) => JSON.stringify(val)); + specialValues = _.uniq(specialValues); - options = options.filter(function (option) { - var modelValsStringified = JSON.stringify( - view.model.get("values"), - ); - if (specialValues.includes(modelValsStringified)) { - if (JSON.stringify(option.values) === modelValsStringified) { - return true; - } - } else { - if (!option.values) { - return true; - } - } - }); - } - // --- Return value --- // + const modelValues = view.model.get("values"); + const modelValuesString = JSON.stringify(modelValues); - if (options.length === 1) { - selectedOperator = options[0].label; - } + operatorOptions = operatorOptions.filter((option) => { + if (!option.values) return true; // Filter in options without values + if (!specialValues.includes(modelValuesString)) return false; // If model values not special, filter out + return JSON.stringify(option.values) === modelValuesString; // Check exact match for special values + }); + } + // --- Return value --- // - return selectedOperator; - } catch (e) { - console.error( - "Failed to select an operator in the Query Rule View, error" + - " message: " + - e, - ); + if (operatorOptions.length === 1) { + selectedOperator = operatorOptions[0].label; } + + return selectedOperator; }, /** * getCategory - Given an array of query fields, get the user-facing category that * these fields belong to. If there are fields from multiple categories, then a * default "Text" category is returned. - * * @param {string[]} fields An array of query (Solr) fields - * @return {string} The label for the category that the given fields belong to + * @returns {string} The label for the category that the given fields belong to */ - getCategory: function (fields) { - try { - var categories = [], - // When fields is empty or are different types - defaultCategory = "Text"; + getCategory(fields) { + const categories = []; + // When fields is empty or are different types + const defaultCategory = "Text"; - if (!fields || fields.length === 0 || fields[0] === "") { - return defaultCategory; - } + if (!fields || fields.length === 0 || fields[0] === "") { + return defaultCategory; + } - fields.forEach((field, i) => { - // Get the category of the field from the matching filter model in the Query - // Fields Collection - var fieldModel = MetacatUI.queryFields.findWhere({ name: field }); - categories.push(fieldModel.get("category")); - }); + fields.forEach((field) => { + // Get the category of the field from the matching filter model in the Query + // Fields Collection + const fieldModel = MetacatUI.queryFields.findWhere({ name: field }); + categories.push(fieldModel.get("category")); + }); - // Test of all the fields are of the same type - var allEqual = categories.every((val, i, arr) => val === arr[0]); + // Test of all the fields are of the same type + const allEqual = categories.every((val, i, arr) => val === arr[0]); - if (allEqual) { - return categories[0]; - } else { - return defaultCategory; - } - } catch (e) { - console.log( - "Failed to detect the category for a group of filters in the" + - " Query Rule View, error message: " + - e, - ); + if (allEqual) { + return categories[0]; } + return defaultCategory; }, /** * Create and insert an input field where the user can provide a search value */ - addValueSelect: function () { - try { - var view = this; - (fields = this.model.get("fields")), - (filterType = MetacatUI.queryFields.getRequiredFilterType(fields)), - (category = this.getCategory(fields)), - (interfaces = this.valueSelectUImap), - (label = ""); - - // To help guide users to create valid queries, the type of value field will - // vary based on the type of field (i.e. filter nodeName), and the operator - // selected. - - // Some user-facing operators (e.g. "is true") don't require a value to be set - var selectedOperator = _.findWhere(this.operatorOptions, { - label: this.getSelectedOperator(), - }); - if (selectedOperator) { - if (selectedOperator.values && selectedOperator.values.length) { - return; - } + addValueSelect() { + const view = this; + const fields = this.model.get("fields"); + const filterType = MetacatUI.queryFields.getRequiredFilterType(fields); + const category = this.getCategory(fields); + const interfaces = this.valueSelectUImap; + let label = ""; + + // To help guide users to create valid queries, the type of value field will + // vary based on the type of field (i.e. filter nodeName), and the operator + // selected. + + // Some user-facing operators (e.g. "is true") don't require a value to be set + const selectedOperator = _.findWhere(this.operatorOptions, { + label: this.getSelectedOperator(), + }); + if (selectedOperator) { + if (selectedOperator.values && selectedOperator.values.length) { + return; } + } - // Find the appropriate UI to use the the value select field. Find the first - // match in the valueSelectUImap according to the filter type and the - // categories associated with the metadata field. - var interfaceProperties = _.find( - interfaces, - function (thisInterface) { - var typesMatch = true, - categoriesMatch = true, - namesMatch = true; - if ( - thisInterface.queryFields && - thisInterface.queryFields.length - ) { - fields.forEach((field, i) => { - if (thisInterface.queryFields.includes(field) === false) { - namesMatch = false; - } - }); + // Find the appropriate UI to use the the value select field. Find the first + // match in the valueSelectUImap according to the filter type and the + // categories associated with the metadata field. + const interfaceProperties = _.find(interfaces, (thisInterface) => { + let typesMatch = true; + let categoriesMatch = true; + let namesMatch = true; + if (thisInterface.queryFields && thisInterface.queryFields.length) { + fields.forEach((field) => { + if (thisInterface.queryFields.includes(field) === false) { + namesMatch = false; } - if ( - thisInterface.filterTypes && - thisInterface.filterTypes.length - ) { - typesMatch = thisInterface.filterTypes.includes(filterType); - } - if (thisInterface.categories && thisInterface.categories.length) { - categoriesMatch = thisInterface.categories.includes(category); - } - return typesMatch && categoriesMatch && namesMatch; - }, - ); - - this.valueSelect = interfaceProperties.uiFunction.call(this); - if (interfaceProperties.label && interfaceProperties.label.length) { - label = $( - "<p class='subtle searchable-select-label'>" + - interfaceProperties.label + - "</p>", - ); + }); } - - // Append and render the chosen value selector - this.el.append(view.valueSelect.el); - this.valueSelect.$el.addClass(this.valuesClass); - view.valueSelect.render(); - if (label) { - view.valueSelect.$el.prepend(label); + if (thisInterface.filterTypes && thisInterface.filterTypes.length) { + typesMatch = thisInterface.filterTypes.includes(filterType); + } + if (thisInterface.categories && thisInterface.categories.length) { + categoriesMatch = thisInterface.categories.includes(category); } + return typesMatch && categoriesMatch && namesMatch; + }); - // Make sure the listeners set below are not set multiple times - this.stopListening( - view.valueSelect, - "changeSelection inputFocus separatorChanged", + this.valueSelect = interfaceProperties.uiFunction.call(this); + if (interfaceProperties.label && interfaceProperties.label.length) { + label = $( + `<p class='subtle search-select-label'>${interfaceProperties.label}</p>`, ); + } - // Update model when the values change - note that the date & numeric filter - // views do not trigger a 'changeSelection' event, (because they are not based - // on a SearchSelect View) but update the models directly - this.listenTo( - view.valueSelect, - "changeSelection", - this.handleValueChange, - ); + // Append and render the chosen value selector + this.el.append(view.valueSelect.el); + this.valueSelect.$el.addClass(this.valuesClass); + view.valueSelect.render(); + if (label) { + view.valueSelect.$el.prepend(label); + } - // Update the model when the operator changes - this.listenTo( - view.valueSelect, - "separatorChanged", - function (newOperator) { - this.model.set("operator", newOperator); - }, - ); + // Make sure the listeners set below are not set multiple times + this.stopListening( + view.valueSelect.model, + "change:selected change:separator", + ); + this.stopListening(view.valueSelect.model, "change:lastInteraction"); + + // Update model when the values change - note that the date & numeric filter + // views do not trigger a 'change:selected' event, (because they are not based + // on a SearchSelect View) but update the models directly + this.listenTo( + view.valueSelect.model, + "change:selected", + (_model, newValues) => { + this.handleValueChange(newValues); + }, + ); + + // Update the model when the operator changes + this.listenTo( + view.valueSelect.model, + "change:separator", + (_model, newOperator) => { + this.model.set("operator", newOperator); + }, + ); - // Show a message that reminds the user that capitalization matters when they - // are typing a value for a field that is case-sensitive. - this.listenTo(view.valueSelect, "inputFocus", function (event) { - var fields = this.model.get("fields"); - var isCaseSensitive = _.some(fields, function (field) { - return MetacatUI.queryFields.findWhere({ + // Show a message that reminds the user that capitalization matters when they + // are typing a value for a field that is case-sensitive. + this.listenTo( + view.valueSelect.model, + "change:lastInteraction", + (model, interaction) => { + if (interaction !== "focus") return; + const currentFields = view.model.get("fields"); + const isCaseSensitive = _.some(currentFields, (field) => + MetacatUI.queryFields.findWhere({ name: field, caseSensitive: true, - }); - }); + }), + ); + if (isCaseSensitive) { - var fieldsText = "The field"; - if (fields.length > 1) { + let fieldsText = "The field"; + if (currentFields.length > 1) { fieldsText = "At least one of the fields"; } - var message = - "<i class='icon-lightbulb icon-on-left'></i> <b>Hint:</b> " + - fieldsText + - " you selected is case-sensitive. Capitalization matters here."; - view.valueSelect.showMessage( - message, - (type = "info"), - (removeOnChange = false), - ); + + const message = `<i class='icon-lightbulb icon-on-left'></i> <b>Hint:</b> ${fieldsText} you selected is case-sensitive. Capitalization matters here.`; + view.valueSelect.showMessage(message, "info", false); } else { view.valueSelect.removeMessages(); } - }); - - // Set the value to the value provided if there was one. Then validateValue() - } catch (e) { - console.error( - "Error adding a search value input in the Query Rule View," + - " error message:", - e, - ); - } + }, + ); }, /** * handleValueChange - Called when the select values for rule are changed. Updates * the model. - * * @param {string[]} newValues The new values that were selected */ - handleValueChange: function (newValues) { - try { - // TODO: validate values - - // Don't add empty values to the model - newValues = _.reject(newValues, function (val) { - return val === ""; - }); - this.model.set("values", newValues); - } catch (e) { - console.error( - "Failed to handle a change in select values in the Query Ryle" + - " View, error message: " + - e, - ); - } + handleValueChange(newValues) { + // TODO: validate values + // Don't add empty values to the model + const filteredValues = _.reject(newValues, (val) => val === ""); + this.model.set("values", filteredValues); }, - // /** - // * Ensure the value entered is valid, given the metadata field selected. - // * If it's not, show an error. If it is, remove the error if there was one. - // * - // * @return {type} description - // */ - // validateValue: function() {// TODO - // }, - /** * Remove one of the three input fields from the rule - * * @param {string} inputType Which of the inputs to remove? "field", "operator", * or "value" */ - removeInput: function (inputType) { - try { - // TODO - what, if any, model updates should happen here? - switch (inputType) { - case "value": - if (this.valueSelect) { - this.stopListening( - this.valueSelect, - "changeSelection inputFocus", - ); - this.valueSelect.remove(); - this.valueSelect = null; - } - break; - case "operator": - if (this.operatorSelect) { - this.stopListening(this.operatorSelect, "changeSelection"); - this.operatorSelect.remove(); - this.operatorSelect = null; - } - break; - case "field": - if (this.fieldSelect) { - this.stopListening(this.fieldSelect, "changeSelection"); - this.fieldSelect.remove(); - this.fieldSelect = null; - } - break; - default: - console.error( - "Must specify either value, operator, or field in the" + - " removeInput function in the Query Rule View", + removeInput(inputType) { + // TODO - what, if any, model updates should happen here? + switch (inputType) { + case "value": + if (this.valueSelect) { + this.stopListening(this.valueSelect.model, "change:selected"); + this.stopListening( + this.valueSelect.model, + "change:lastInteraction", ); - } - } catch (e) { - console.error( - "Error removing an input from the Query Rule View, error" + - " message:", - e, - ); + this.valueSelect.remove(); + this.valueSelect = null; + } + break; + case "operator": + if (this.operatorSelect) { + this.stopListening(this.operatorSelect.model, "change:selected"); + this.operatorSelect.remove(); + this.operatorSelect = null; + } + break; + case "field": + if (this.fieldSelect) { + this.stopListening(this.fieldSelect.model, "change:selected"); + this.fieldSelect.remove(); + this.fieldSelect = null; + } + break; + default: + break; } }, /** * Indicate to the user that the rule will be removed when they hover over the * remove button. + * @param {Event} e The mouseover or mouseout event */ - previewRemove: function (e) { - try { - var normalOpacity = 1.0, - previewOpacity = 0.2, - speed = 175; + previewRemove(e) { + const normalOpacity = 1.0; + const previewOpacity = 0.2; + const speed = 175; - var removeEl = e.target; - var subElements = this.$el.children().not(removeEl); + const removeEl = e.target; + const subElements = this.$el.children().not(removeEl); - if (e.type === "mouseover") { - subElements.fadeTo(speed, previewOpacity); - $(removeEl).fadeTo(speed, normalOpacity); - } - if (e.type === "mouseout") { - subElements.fadeTo(speed, normalOpacity); - $(removeEl).fadeTo(speed, previewOpacity); - } - } catch (error) { - console.log( - "Error showing a preview of the removal of a Query Rule View," + - " details: " + - error, - ); + if (e.type === "mouseover") { + subElements.fadeTo(speed, previewOpacity); + $(removeEl).fadeTo(speed, normalOpacity); + } + if (e.type === "mouseout") { + subElements.fadeTo(speed, normalOpacity); + $(removeEl).fadeTo(speed, previewOpacity); } }, @@ -1844,21 +1588,16 @@

Source: src/js/views/queryBuilder/QueryRuleView.js

* removeSelf - When the delete button is clicked, remove this entire View and * associated model */ - removeSelf: function () { - try { - $("body .popover").remove(); - $("body .tooltip").remove(); - if (this.model && this.model.collection) { - this.model.collection.remove(this.model); - } - this.remove(); - } catch (error) { - console.log("Error removing a Query Rule View, details: " + error); + removeSelf() { + $("body .popover").remove(); + $("body .tooltip").remove(); + if (this.model && this.model.collection) { + this.model.collection.remove(this.model); } + this.remove(); }, }, - ); -}); + ));
diff --git a/docs/docs/src_js_views_searchSelect_AccountSelectView.js.html b/docs/docs/src_js_views_searchSelect_AccountSelectView.js.html index 82a975664..f683b0c46 100644 --- a/docs/docs/src_js_views_searchSelect_AccountSelectView.js.html +++ b/docs/docs/src_js_views_searchSelect_AccountSelectView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -45,338 +45,34 @@

Source: src/js/views/searchSelect/AccountSelectView.js
define([
-  "jquery",
-  "underscore",
-  "backbone",
-  "views/searchSelect/SearchableSelectView",
-  "models/LookupModel",
-], function ($, _, Backbone, SearchableSelect, LookupModel) {
+  "views/searchSelect/SearchSelectView",
+  "models/searchSelect/AccountSearchSelect",
+], (SearchSelect, AccountSearchSelect) => {
   /**
    * @class AccountSelectView
    * @classdesc A select interface that allows the user to search for and select one or
    * more accountIDs
    * @classcategory Views/SearchSelect
-   * @extends SearchableSelect
-   * @constructor
+   * @augments SearchSelect
+   * @class
    * @since 2.15.0
    * @screenshot views/searchSelect/AccountSelectViewView.png
    */
-  var AccountSelectView = SearchableSelect.extend(
+  const AccountSelectView = SearchSelect.extend(
     /** @lends AccountSelectViewView.prototype */
     {
-      /**
-       * The type of View this is
-       * @type {string}
-       * @since 2.15.0
-       */
+      /** @inheritdoc */
       type: "AccountSelect",
 
-      /**
-       * The HTML class names for this view element
-       * @type {string}
-       * @since 2.15.0
-       */
-      className: SearchableSelect.prototype.className + " account-select",
+      /** @inheritdoc */
+      ModelType: AccountSearchSelect,
 
-      /**
-       * Text to show in the input field before any value has been entered
-       * @type {string}
-       * @default "Start typing a name"
-       * @since 2.15.0
-       */
-      placeholderText: "Start typing a name",
-
-      /**
-       * Label for the input element
-       * @type {string}
-       * @default "Search for a person or group"
-       * @since 2.15.0
-       */
-      inputLabel: "Search for a person or group",
-
-      /**
-       * Whether to allow users to select more than one value
-       * @type {boolean}
-       * @default true
-       * @since 2.15.0
-       */
-      allowMulti: true,
-
-      /**
-       * Setting to true gives users the ability to add their own options that
-       * are not listed in this.options. This can work with either single
-       * or multiple search select dropdowns
-       * @type {boolean}
-       * @default true
-       */
-      allowAdditions: true,
-
-      /**
-       * Can be set to an object to specify API settings for retrieving remote selection
-       * menu content from an API endpoint. Details of what can be set here are
-       * specified by the Semantic-UI / Fomantic-UI package. Set to false if not
-       * retrieving remote content.
-       * @type {Object|booealn}
-       * @since 2.15.0
-       * @see {@link https://fomantic-ui.com/modules/dropdown.html#remote-settings}
-       * @see {@link https://fomantic-ui.com/behaviors/api.html#/settings}
-       */
-      apiSettings: {
-        // Use the Accounts lookup to search for a person or group when the user types
-        // something into the input
-        responseAsync: function (settings, callback) {
-          var view = $(this).data("view");
-
-          // The search term that the user has typed into the input
-          var searchTerm = settings.urlData.query;
-
-          // Only use the account lookup service is the user has typed at least two
-          // characters. Otherwise, the callback function is never called.
-          if (searchTerm.length < 2) {
-            callback({
-              success: false,
-            });
-            return;
-          }
-
-          // For search terms at least 2 characters long, use the Lookup Model
-          MetacatUI.appLookupModel.getAccountsAutocomplete(
-            { term: searchTerm },
-            function (results) {
-              // If no match was found to the search term
-              if (results && results.length < 1) {
-                callback({
-                  success: false,
-                });
-                return;
-              }
-
-              // If there were results, format for the semantic UI dropdown function
-              results = view.formatResults(results);
-
-              callback({
-                success: true,
-                results: results,
-              });
-            },
-          );
-        },
-      },
-
-      /**
-       * Creates a new SearchableSelectView
-       * @param {Object} options - A literal object with options to pass to the view
-       * @since 2.15.0
-       */
-      initialize: function (options) {
-        try {
-          var view = this;
-
-          // Ensure there is a lookup model ready for this view to use.
-          if (MetacatUI.appLookupModel === "undefined") {
-            MetacatUI.appLookupModel = new LookupModel();
-          }
-
-          SearchableSelect.prototype.initialize.call(view, options);
-        } catch (e) {
-          console.log(
-            "Failed to initialize an Account Select view, error message:",
-            e,
-          );
-        }
-      },
-
-      /**
-       * Takes the results returned from from
-       * {@link LookupModel#getAccountsAutocomplete} and re-formats them for other
-       * functions. When the forTemplate argument is false, the results are formatted as
-       * a list mapping dropdown content specifically for the FomanticUI API. When
-       * forTemplate is true, then the results are formatted for use in the
-       * SearchableSelectView template: {@link SearchableSelectView#template}.
-       *
-       * @param  {Object[]} results The response from
-       * {@link LookupModel#getAccountsAutocomplete}
-       * @param  {boolean} forTemplate=false Whether or not to format the results for
-       * the {@link SearchableSelectView#template}
-       * @return {Object[]} The re-formatted results
-       *
-       * @see {@link https://fomantic-ui.com/modules/dropdown.html#remote-settings}
-       * @since 2.15.0
-       */
-      formatResults: function (results, forTemplate = false) {
-        results = _.map(results, function (result) {
-          if (forTemplate) {
-            // Get the ID which is saved in the parentheses
-            var regExp = /\(([^)]+)\)$/;
-            var matches = regExp.exec(result.label);
-            //matches[1] contains the value between the parentheses
-            result.description = "Account ID: " + matches[1];
-            result.label = result.label.replace(regExp, "");
-            result.label = result.label.trim();
-          } else {
-            result.label = result.label.replace(
-              "(",
-              '<span class="description">',
-            );
-            result.label = result.label.replace(")", "</span>");
-          }
-
-          var icon = "";
-
-          if (result.type === "person") {
-            icon = "user";
-          }
-          if (result.type === "group") {
-            icon = "group";
-          }
-
-          if (icon) {
-            if (forTemplate) {
-              result.icon = icon;
-            } else {
-              result.label =
-                '<i class="icon icon-on-left icon-' +
-                icon +
-                '"></i>' +
-                result.label;
-            }
-          }
-
-          if (!forTemplate) {
-            result = {
-              name: result.label,
-              value: result.value,
-            };
-          }
-          return result;
-        });
-
-        return results;
-      },
-
-      /**
-       * Render the view
-       *
-       * @return {AccountSelectView}  Returns the view
-       * @since 2.15.0
-       */
-      render: function () {
-        var view = this;
-
-        // Use the account lookup service to match the pre-selected values to
-        // the account holder's name to use as a label.
-
-        // If we haven't started looking up user/organization names yet...
-        if (typeof view.labelsToFetch === "undefined") {
-          // Keep a count of the number of accounts we need to lookup
-          view.labelsToFetch = this.selected ? this.selected.length : 0;
-
-          if (view.labelsToFetch > 0) {
-            view.options = [];
-
-            view.selected.forEach(function (accountId) {
-              MetacatUI.appLookupModel.getAccountsAutocomplete(
-                { term: accountId },
-                function (results) {
-                  // The value should match only one account (since the value is an
-                  // account ID). If we found the match, format it for the
-                  // SearchableSelectView, and the icon and tooltip will automatically be
-                  // added to the pre-selected labels.
-                  if (results && results.length === 1) {
-                    results = view.formatResults(results, true);
-                    view.options.push(results[0]);
-                  }
-                  // Whether or not we found a match, count this lookup as complete
-                  --view.labelsToFetch;
-
-                  // Once we've looked up all of the accounts, call this render function
-                  // again
-                  if (view.labelsToFetch === 0) {
-                    view.render();
-                  }
-                },
-              );
-            });
-
-            return;
-          }
-        }
-
-        // Once we've fetched the labels for any pre-selected account IDs,
-        // render as usual
-        SearchableSelect.prototype.render.call(view);
-      },
-
-      /**
-       * addTooltip - Add a tooltip to a given element using the description in the
-       * options object that's set on the view.
-       *
-       * @param  {HTMLElement} element The HTML element a tooltip should be added
-       * @param  {string} position how to position the tooltip - top | bottom | left |
-       * right
-       * @return {jQuery} The element with a tooltip wrapped by jQuery
-       * @since 2.15.0
-       */
-      addTooltip: function (element, position = "bottom") {
-        try {
-          if (!element) {
-            return;
-          }
-
-          // The account ID is saved in a <span> element in the label with the
-          // description class when the label is added from the list of search results
-          var descEl = $(element).find(".description");
-          var id = descEl.text();
-          descEl.remove();
-
-          // Otherwise, the ID is always saved as a data attribute
-          if (!id) {
-            id = $(element).attr("data-value");
-          }
-
-          // Show the account ID as a tooltip rather than in the label. Otherwise
-          // the input gets too crowded.
-          $(element)
-            .tooltip({
-              title: id ? "Account ID: " + id : "",
-              placement: position,
-              container: "body",
-              delay: {
-                show: 900,
-                hide: 50,
-              },
-            })
-            .on("show.bs.popover", function () {
-              var $el = $(this);
-              // Allow time for the popup to be added to the DOM
-              setTimeout(function () {
-                // Then add a special class to identify
-                // these popups if they need to be removed.
-                $el.data("tooltip").$tip.addClass("search-select-tooltip");
-              }, 10);
-            });
-
-          return $(element);
-        } catch (e) {
-          console.log(
-            "Failed to add tooltips in a searchable select view, error message: " +
-              e,
-          );
-        }
-      },
+      /** @inheritdoc */
+      className: `${SearchSelect.prototype.className} account-select`,
 
       // TODO: We may want to add a custom is valid option to warn the user when
       // a value entered cannot be found in the accounts lookup service.
-
-      // /**
-      //  * isValidOption - Checks if a value is one of the values given in view.options
-      //  *
-      //  * @param  {string} value The value to check
-      //  * @return {boolean}      returns true if the value is one of the values given in
-      //  * view.options
-      //  */
-      // isValidOption: function(value){
-      // },
+      // isValidOption (value) {...}
     },
   );
 
diff --git a/docs/docs/src_js_views_searchSelect_AnnotationFilterView.js.html b/docs/docs/src_js_views_searchSelect_AnnotationFilterView.js.html
index beadc2c2e..e59548e59 100644
--- a/docs/docs/src_js_views_searchSelect_AnnotationFilterView.js.html
+++ b/docs/docs/src_js_views_searchSelect_AnnotationFilterView.js.html
@@ -30,7 +30,7 @@
 
 
     
-    

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -59,6 +59,7 @@

Source: src/js/views/searchSelect/AnnotationFilterView.js * @constructor * @since 2.14.0 * @screenshot views/searchSelect/AnnotationFilterView.png + * @deprecated since 2.30.0 */ return Backbone.View.extend( /** @lends AnnotationFilterView.prototype */ @@ -105,7 +106,7 @@

Source: src/js/views/searchSelect/AnnotationFilterView.js * @type {boolean} * @since 2.22.0 */ - useSearchableSelect: false, + useSearchSelect: false, /** * The acronym of the ontology or ontologies to render a tree from. @@ -178,7 +179,7 @@

Source: src/js/views/searchSelect/AnnotationFilterView.js var view = this; - if (view.multiselect || view.useSearchableSelect) { + if (view.multiselect || view.useSearchSelect) { view.createMultiselect(); } else { view.setUpTree(); @@ -244,10 +245,10 @@

Source: src/js/views/searchSelect/AnnotationFilterView.js try { var view = this; - require(["views/searchSelect/SearchableSelectView"], function ( - SearchableSelect, + require(["views/searchSelect/SearchSelectView"], function ( + SearchSelect, ) { - view.multiSelectView = new SearchableSelect({ + view.multiSelectView = new SearchSelect({ placeholderText: view.placeholderText ? view.placeholderText : "Search for or select a value", @@ -266,7 +267,7 @@

Source: src/js/views/searchSelect/AnnotationFilterView.js view.updateMultiselect.call(view); } - //Forward the separatorChanged event from the SearchableSelectView to this AnnotationFilterView + //Forward the separatorChanged event from the SearchSelectView to this AnnotationFilterView //(perhaps this view should have been a subclass?) view.multiSelectView.on("separatorChanged", (separatorText) => { view.trigger("separatorChanged", separatorText); @@ -281,7 +282,7 @@

Source: src/js/views/searchSelect/AnnotationFilterView.js }, /** - * updateMultiselect - Functions to run once a SearchableSelect view has + * updateMultiselect - Functions to run once a SearchSelect view has * been rendered and inserted into this view, and the labels for any * pre-selected annotation values have been fetched. Updates the * hidden menu of items and the selected items. diff --git a/docs/docs/src_js_views_searchSelect_BioontologySelectView.js.html b/docs/docs/src_js_views_searchSelect_BioontologySelectView.js.html new file mode 100644 index 000000000..cd033f013 --- /dev/null +++ b/docs/docs/src_js_views_searchSelect_BioontologySelectView.js.html @@ -0,0 +1,323 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/searchSelect/BioontologySelectView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/searchSelect/BioontologySelectView.js

+ + + + + + +
+
+
"use strict";
+
+define([
+  "backbone",
+  "jquery",
+  "semantic",
+  "models/ontologies/BioontologyBatch",
+  "views/searchSelect/SolrAutocompleteView",
+  "views/ontologies/BioontologyBrowserView",
+], (
+  Backbone,
+  $,
+  Semantic,
+  BioontologyBatch,
+  SolrAutocompleteView,
+  BioontologyBrowserView,
+) => {
+  // The base class for the view
+  const BASE_CLASS = "bioontology-select";
+
+  // The class names used in the view
+  const CLASS_NAMES = {
+    button: [
+      Semantic.CLASS_NAMES.base,
+      Semantic.CLASS_NAMES.button.base,
+      Semantic.CLASS_NAMES.variations.attached,
+      Semantic.CLASS_NAMES.colors.blue,
+      "right",
+    ],
+    buttonIcon: ["icon", "icon-external-link-sign"],
+    // Bootstrap classes
+    modalCloseButton: "close",
+    modal: ["modal", "hide", `${BASE_CLASS}-modal`],
+    modalContent: "modal-body",
+  };
+
+  /**
+   * @class BioontologySelectView
+   * @classdesc A search select view that allows users to search for ontology
+   * classes that are indexed in Solr and to browse BioPortal ontologies. The
+   * view can be configured to show class labels from multiple ontologies.
+   * @classcategory Views/SearchSelect
+   * @augments SearchSelect
+   * @since 2.31.0
+   * @screenshot views/searchSelect/BioontologySelectView.png
+   */
+  return SolrAutocompleteView.extend(
+    /** @lends BioontologySelectView.prototype */
+    {
+      /** @inheritdoc */
+      type: "OntologySelect",
+
+      /** @inheritdoc */
+      className: `${BASE_CLASS} ${SolrAutocompleteView.prototype.className}`,
+
+      /**
+       * The name of the field in the Solr schema that the user is searching.
+       * @type {string}
+       */
+      queryField: "sem_annotation",
+
+      /**
+       * Set this to false to avoid fetching class labels from BioPortal. The
+       * labels will be displayed as the values that are returned from the Solr
+       * query.
+       * @type {boolean}
+       */
+      showClassLabels: true,
+
+      /**
+       * The ontologies that can be searched or browsed. Each ontology needs a
+       * "label" and a "ontology" (acronym) property. Optionally, a "subTree"
+       * property can be provided to search a specific sub-tree of the ontology.
+       * @type {Array.<{label: string, ontology: string, subTree: string}>}
+       * @since 2.31.0
+       */
+      ontologies: MetacatUI.appModel.get("bioportalOntologies"),
+
+      /**
+       * Initialize the view
+       * @param {object} [opts] - The options to initialize the view with
+       * @param {boolean} [opts.showClassLabels] - Set to false to avoid
+       * fetching class labels from BioPortal
+       * @param {string} [opts.queryField] - The name of the field in the Solr
+       * schema that the user is searching
+       * @param {object[]} [opts.ontologies] - The ontoloties (& sub-trees) to
+       * allow users to search for.
+       */
+      initialize(opts = {}) {
+        if (opts?.showClassLabels === false) this.showClassLabels = false;
+        const attrs = opts || {};
+        attrs.queryField = opts?.queryField || this.queryField;
+        attrs.fluid = false;
+        if (attrs.ontologies) {
+          this.ontologies = attrs.ontologies;
+        }
+        attrs.submenuStyle = "accordion";
+        attrs.allowAdditions = false;
+        SolrAutocompleteView.prototype.initialize.call(this, attrs);
+        if (this.showClassLabels) this.fetchClassLabels();
+      },
+
+      /** @inheritdoc */
+      render() {
+        SolrAutocompleteView.prototype.render.call(this);
+        this.renderButton();
+        this.renderOntologyModal();
+        this.addListeners();
+        return this;
+      },
+
+      /** Create the button to open the ontology browser */
+      renderButton() {
+        const button = document.createElement("button");
+        button.classList.add(...CLASS_NAMES.button);
+
+        const icon = document.createElement("i");
+        icon.classList.add(...CLASS_NAMES.buttonIcon);
+        icon.style.color = "inherit";
+
+        button.appendChild(icon);
+        this.el.appendChild(button);
+        this.button = button;
+      },
+
+      /**  Render the ontology browser modal */
+      renderOntologyModal() {
+        this.browser = new BioontologyBrowserView({
+          ontologyOptions: this.ontologies,
+        });
+        // Bootstrap modal close button
+        const closeButton = document.createElement("button");
+        closeButton.classList.add(CLASS_NAMES.modalCloseButton);
+        closeButton.setAttribute("data-dismiss", "modal");
+        closeButton.setAttribute("aria-hidden", "true");
+        closeButton.innerHTML = "&times;";
+
+        const contentDiv = document.createElement("div");
+        contentDiv.classList.add(CLASS_NAMES.modalContent);
+
+        const modal = document.createElement("div");
+        modal.classList.add(...CLASS_NAMES.modal);
+
+        modal.append(contentDiv, closeButton);
+        contentDiv.appendChild(this.browser.el);
+        document.body.appendChild(modal);
+
+        this.modal = $(modal).modal({ show: false });
+
+        this.hideOntologyBrowser();
+      },
+
+      /**
+       * Listen to when a class is selected in the browser & when the button is
+       * clicked to open the browser
+       */
+      addListeners() {
+        this.listenTo(this.browser, "selected", (cls) => {
+          this.modal.modal("hide");
+          this.selectClass(cls);
+        });
+        this.button.addEventListener("click", () => {
+          this.showOntologyBrowser();
+        });
+      },
+
+      /** Show the ontology browser modal */
+      showOntologyBrowser() {
+        // Don't render until the first time the modal is shown
+        if (!this.browserRendered) {
+          this.browser.render();
+          this.browserRendered = true;
+        }
+        this.modal.modal("show");
+      },
+
+      /** Hide the ontology browser modal */
+      hideOntologyBrowser() {
+        this.modal.modal("hide");
+      },
+
+      /**
+       * Set the value of the select element to the given ontology class
+       * @param {OntologyClass} ontologyClass - The class model to select
+       */
+      selectClass(ontologyClass) {
+        const option = ontologyClass.toSearchSelectOption();
+        const selectedValue = option.value;
+        this.model.addSelected(selectedValue);
+        this.model.get("options").add(option);
+      },
+
+      /** Fetch the labels select element from BioPortal */
+      async fetchClassLabels() {
+        const options = this.model.get("options");
+
+        if (!options.length) {
+          this.listenToOnce(options, "add reset", this.fetchClassLabels);
+          return;
+        }
+
+        const values = options.pluck("value");
+        const preSelected = this.model.get("selected");
+        const classesToFetch = [...values, ...preSelected];
+
+        if (!MetacatUI.bioontologySearch) {
+          MetacatUI.bioontologySearch = new BioontologyBatch();
+        }
+        this.bioBatchModel = MetacatUI.bioontologySearch;
+        const ontologies = this.ontologies?.map(
+          (ontology) => ontology.ontology,
+        );
+        this.bioBatchModel.set("ontologies", ontologies);
+
+        this.listenTo(
+          this.bioBatchModel.get("collection"),
+          "update",
+          (collection) => {
+            this.addOptionDetails(collection);
+          },
+        );
+        const allClasses = await this.bioBatchModel.getClasses(classesToFetch);
+        this.addOptionDetails(allClasses);
+      },
+
+      /**
+       * Add the details of the ontology classes to the options in the select
+       * element
+       * @param {Backbone.Collection|Array} classes - The collection of classes to add
+       * to the options
+       */
+      addOptionDetails(classes) {
+        if (!classes?.length) return;
+        // if collection is an array, make it a collection
+        let collection = classes;
+        if (!classes.get) collection = new Backbone.Collection(collection);
+        const options = this.model.get("options");
+        // Get only the options that don't already at least have a label
+        const toUpdate = options.filter((option) => {
+          const label = option.get("label");
+          const value = option.get("value");
+          return !label || value === label;
+        });
+        toUpdate.forEach((option) => {
+          const classId = option.get("value");
+          const cls = collection.get(classId);
+          if (cls) {
+            const newAttrs = cls.toSearchSelectOption();
+            const existingDescription = option.get("description");
+            if (existingDescription) {
+              newAttrs.description = `${newAttrs.description} (${existingDescription})`;
+            }
+            option.set(newAttrs);
+          }
+        });
+        options.renameCategory("", "Unknown Ontology");
+        options.sortByProp("category");
+        options.trigger("update");
+      },
+    },
+  );
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_searchSelect_NodeSelectView.js.html b/docs/docs/src_js_views_searchSelect_NodeSelectView.js.html index b93b455c3..31b598785 100644 --- a/docs/docs/src_js_views_searchSelect_NodeSelectView.js.html +++ b/docs/docs/src_js_views_searchSelect_NodeSelectView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -44,104 +44,71 @@

Source: src/js/views/searchSelect/NodeSelectView.js

-
define([
-  "jquery",
-  "underscore",
-  "backbone",
-  "views/searchSelect/SearchableSelectView",
-  "models/NodeModel",
-], function ($, _, Backbone, SearchableSelect, NodeModel) {
+            
define(["views/searchSelect/SearchSelectView", "models/NodeModel"], (
+  SearchSelect,
+  NodeModel,
+) => {
   /**
    * @class NodeSelect
    * @classdesc A select interface that allows the user to search for and
    * select a member node
    * @classcategory Views/SearchSelect
-   * @extends SearchableSelect
-   * @constructor
+   * @augments SearchSelect
+   * @class
    * @since 2.14.0
    * @screenshot views/searchSelect/NodeSelectView.png
    */
-  var NodeSelect = SearchableSelect.extend(
+  const NodeSelect = SearchSelect.extend(
     /** @lends NodeSelectView.prototype */
     {
-      /**
-       * The type of View this is
-       * @type {string}
-       */
+      /** @inheritdoc */
       type: "NodeSelect",
 
-      /**
-       * className - Returns the class names for this view element
-       *
-       * @return {string}  class names
-       */
-      className: SearchableSelect.prototype.className + " node-select",
+      /** @inheritdoc */
+      className: `${SearchSelect.prototype.className} node-select`,
 
-      /**
-       * Text to show in the input field before any value has been entered
-       * @type {string}
-       */
-      placeholderText: "Select a DataONE repository",
+      /** @inheritdoc */
+      initialize(options = {}) {
+        this.getNodeOptions();
 
-      /**
-       * Label for the input element
-       * @type {string}
-       */
-      inputLabel: "Select a DataONE repository",
+        const opts = {
+          placeholderText: "Select a DataONE repository",
+          inputLabel: "Select a DataONE repository",
+          allowMulti: true,
+          allowAdditions: true,
+          options: this.getNodeOptions(),
+          ...options,
+        };
 
-      /**
-       * Whether to allow users to select more than one value
-       * @type {boolean}
-       */
-      allowMulti: true,
-
-      /**
-       * Setting to true gives users the ability to add their own options that
-       * are not listed in this.options. This can work with either single
-       * or multiple search select dropxdowns
-       * @type {boolean}
-       * @default true
-       */
-      allowAdditions: true,
+        SearchSelect.prototype.initialize.call(this, opts);
+      },
 
       /**
-       * Creates a new NodeSelectView
-       * @param {Object} options - A literal object with options to pass to the view
+       * Fetch the member nodes from the NodeModel and convert them to options
+       * for the searchSelect component.
+       * @returns {object[]} An array of objects representing the member nodes
+       * @since 2.31.0
        */
-      initialize: function (options) {
-        try {
-          // Ensure the query fields are cached
-          if (typeof MetacatUI.nodeModel === "undefined") {
-            MetacatUI.nodeModel = new NodeModel();
-          }
-
-          var members = MetacatUI.nodeModel.get("members");
-
-          // Maps the nodeModel member attributes (keys) to the searchSelect
-          // dropdown options properties (values)
-          var map = Object.entries({
-            logo: "image",
-            name: "label",
-            description: "description",
-            identifier: "value",
-          });
-
-          this.options = [];
-
-          // Convert nodeModel members to options of searchSelect
-          members.forEach((member, i) => {
-            this.options[i] = {};
-            for (const [oldName, newName] of map) {
-              this.options[i][newName] = member[oldName];
-            }
+      getNodeOptions() {
+        if (!MetacatUI.nodeModel) MetacatUI.nodeModel = new NodeModel();
+        const members = MetacatUI.nodeModel.get("members") || [];
+
+        const attributeMap = {
+          logo: "image",
+          name: "label",
+          description: "description",
+          identifier: "value",
+        };
+        // Convert nodeModel members to options of searchSelect using map
+        const options = members.map((member) => {
+          const option = {};
+          Object.entries(attributeMap).forEach(([oldName, newName]) => {
+            option[newName] = member[oldName];
           });
+          return option;
+        });
 
-          SearchableSelect.prototype.initialize.call(this, options);
-        } catch (e) {
-          console.log(
-            "Failed to initialize a Node Select View, error message: " + e,
-          );
-        }
+        return options;
       },
     },
   );
diff --git a/docs/docs/src_js_views_searchSelect_ObjectFormatSelectView.js.html b/docs/docs/src_js_views_searchSelect_ObjectFormatSelectView.js.html
index dc558d4e2..4027f09ea 100644
--- a/docs/docs/src_js_views_searchSelect_ObjectFormatSelectView.js.html
+++ b/docs/docs/src_js_views_searchSelect_ObjectFormatSelectView.js.html
@@ -30,7 +30,7 @@
 
 
     
-    

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -44,123 +44,81 @@

Source: src/js/views/searchSelect/ObjectFormatSelectView.
-
define([
-  "jquery",
-  "underscore",
-  "backbone",
-  "views/searchSelect/SearchableSelectView",
-  "collections/ObjectFormats",
-], function ($, _, Backbone, SearchableSelect, ObjectFormats) {
+            
define(["views/searchSelect/SearchSelectView", "collections/ObjectFormats"], (
+  SearchSelect,
+  ObjectFormats,
+) => {
   /**
    * @class ObjectFormatSelect
    * @classdesc A select interface that allows the user to search for and
    * select a DataONE object format
    * @classcategory Views/SearchSelect
-   * @extends SearchableSelect
-   * @constructor
+   * @augments SearchSelect
+   * @class
    * @since 2.15.0
    * @screenshot views/searchSelect/ObjectFormatSelectView.png
    */
-  var ObjectFormatSelect = SearchableSelect.extend(
+  const ObjectFormatSelect = SearchSelect.extend(
     /** @lends ObjectFormatSelectView.prototype */
     {
-      /**
-       * The type of View this is
-       * @type {string}
-       */
+      /** @inheritdoc */
       type: "ObjectFormatSelect",
 
-      /**
-       * className - Returns the class names for this view element
-       *
-       * @return {string}  class names
-       */
-      className: SearchableSelect.prototype.className + " object-format-select",
-
-      /**
-       * Label for the input element
-       * @type {string}
-       * @since 2.15.0
-       */
-      inputLabel: "Select one or more metadata types",
+      /** @inheritdoc */
+      className: `${SearchSelect.prototype.className} object-format-select`,
+
+      /** @inheritdoc */
+      initialize(options = {}) {
+        const opts = {
+          inputLabel: "Select one or more metadata types",
+          placeholderText: "Type in a metadata type",
+          allowMulti: true,
+          allowAdditions: true,
+          ...options,
+        };
+
+        SearchSelect.prototype.initialize.call(this, opts);
+        this.getObjectFormats();
+      },
 
       /**
-       * Text to show in the input field before any value has been entered
-       * @type {string}
-       * @since 2.15.0
+       * Fetch the object formats from the DataONE API and update the
+       * select options on the model
+       * @since 2.31.0
        */
-      placeholderText: "Type in a metadata type",
+      getObjectFormats() {
+        const view = this;
+        // Ensure the object formats are cached
+        if (!MetacatUI.objectFormats)
+          MetacatUI.objectFormats = new ObjectFormats();
+
+        // eslint-disable-next-line no-underscore-dangle
+        const events = MetacatUI.objectFormats._events;
+
+        if (!MetacatUI.objectFormats.length && !(events && events.sync)) {
+          view.listenToOnce(
+            MetacatUI.objectFormats,
+            "sync error",
+            view.getObjectFormats,
+          );
+          MetacatUI.objectFormats.fetch();
+          return;
+        }
 
-      /**
-       * Whether to allow users to select more than one value
-       * @type {boolean}
-       * @since 2.15.0
-       */
-      allowMulti: true,
+        const formatIds = MetacatUI.objectFormats.toJSON();
 
-      /**
-       * Setting to true gives users the ability to add their own options that
-       * are not listed in this.options. This can work with either single
-       * or multiple search select dropdowns
-       * @type {boolean}
-       * @default true
-       * @since 2.15.0
-       */
-      allowAdditions: true,
+        const options = formatIds
+          // Query Rules automatically include a rule for formatType="METADATA"
+          // so subset to only METADATA formats
+          .filter((format) => format.formatType === "METADATA")
+          // Reformat for a SearchSelect
+          .map((format) => ({
+            label: format.formatName,
+            value: format.formatId,
+            description: format.formatId,
+          }));
 
-      /**
-       * Render the view
-       *
-       * @return {ObjectFormatSelect}  Returns the view
-       * @since 2.15.0
-       */
-      render: function () {
-        try {
-          var view = this;
-
-          // Ensure the object formats are cached
-          if (typeof MetacatUI.objectFormats === "undefined") {
-            MetacatUI.objectFormats = new ObjectFormats();
-          }
-
-          // If not already synced, then get the object formats
-          if (
-            MetacatUI.objectFormats.length === 0 &&
-            !(
-              MetacatUI.objectFormats._events &&
-              MetacatUI.objectFormats._events.sync
-            )
-          ) {
-            this.listenToOnce(
-              MetacatUI.objectFormats,
-              "sync error",
-              view.render,
-            );
-            MetacatUI.objectFormats.fetch();
-            return;
-          }
-
-          var formatIds = MetacatUI.objectFormats.toJSON();
-          var options = _.chain(formatIds)
-            // Since the Query Rules automatically include a rule for formatType =
-            // "METADATA", only allow filtering datasets by specific metadata type.
-            .where({ formatType: "METADATA" })
-            .map(function (format) {
-              return {
-                label: format.formatName,
-                value: format.formatId,
-                description: format.formatId,
-              };
-            })
-            .value();
-
-          this.options = options;
-
-          SearchableSelect.prototype.render.call(view);
-        } catch (error) {
-          console.log("Error rendering an Object Format Select View.");
-          console.log(error);
-        }
+        view.updateOptions(options);
       },
     },
   );
diff --git a/docs/docs/src_js_views_searchSelect_QueryFieldSelectView.js.html b/docs/docs/src_js_views_searchSelect_QueryFieldSelectView.js.html
index cfa7acff4..7131eee7a 100644
--- a/docs/docs/src_js_views_searchSelect_QueryFieldSelectView.js.html
+++ b/docs/docs/src_js_views_searchSelect_QueryFieldSelectView.js.html
@@ -30,7 +30,7 @@
 
 
     
-    

Namespaces

Classes

Global

+

Namespaces

Classes

Global

@@ -45,465 +45,66 @@

Source: src/js/views/searchSelect/QueryFieldSelectView.js
define([
-  "jquery",
   "underscore",
-  "backbone",
-  "views/searchSelect/SearchableSelectView",
-  "collections/queryFields/QueryFields",
-], function ($, _, Backbone, SearchableSelect, QueryFields) {
+  "semantic",
+  "views/searchSelect/SearchSelectView",
+  "models/searchSelect/QueryFieldSearchSelect",
+], (_, Semantic, SearchSelect, QueryFieldSearchSelect) => {
   /**
    * @class QueryFieldSelectView
-   * @classdesc A select interface that allows the user to search for and
-   * select metadata field(s).
+   * @classdesc A select interface that allows the user to search for and select
+   * metadata field(s).
    * @classcategory Views/SearchSelect
-   * @extends SearchableSelect
-   * @constructor
+   * @augments SearchSelect
+   * @class
    * @since 2.14.0
    * @screenshot views/searchSelect/QueryFieldSelectView.png
    */
-  var QueryFieldSelectView = SearchableSelect.extend(
+  const QueryFieldSelectView = SearchSelect.extend(
     /** @lends QueryFieldSelectView.prototype */
     {
-      /**
-       * The type of View this is
-       * @type {string}
-       */
+      /** @inheritdoc */
       type: "QueryFieldSelect",
 
-      /**
-       * className - the class names for this view element
-       *
-       * @type {string}
-       */
-      className: SearchableSelect.prototype.className + " query-field-select",
+      /** @inheritdoc */
+      className: `${SearchSelect.prototype.className} query-field-select`,
 
-      /**
-       * Text to show in the input field before any value has been entered
-       * @type {string}
-       */
-      placeholderText: "Search for or select a field",
+      /** @inheritdoc */
+      ModelType: QueryFieldSearchSelect,
 
-      /**
-       * Label for the input element
-       * @type {string}
-       */
-      inputLabel: "Select one or more metadata fields to query",
-
-      /**
-       * @see SearchableSelectView#submenuStyle
-       * @default "accordion"
-       */
-      submenuStyle: "accordion",
-
-      /**
-       * A list of query fields names to exclude from the list of options
-       * @type {string[]}
-       */
-      excludeFields: [],
-
-      /**
-       * An additional field object contains the properties an additional query field to
-       * add that are required to render it correctly. An additional query field is one
-       * that does not actually exist in the query service index.
-       *
-       * @typedef {Object} AdditionalField
-       *
-       * @property {string} name - A unique ID to represent this field. It must not
-       * match the name of any other query fields.
-       * @property {string[]} fields - The list of real query fields that this
-       * abstracted field will represent. It must exactly match the names of the query
-       * fields that actually exist.
-       * @property {string} label - A user-facing label to display.
-       * @property {string} description - A description for this field.
-       * @property {string} category - The name of the category under which to place
-       * this field. It must match one of the category names for an existing query
-       * field.
-       *
-       * @since 2.15.0
-       */
-
-      /**
-       * A list of additional fields which are not retrieved from the query service
-       * index, but which should be added to the list of options. This can be used to
-       * add abstracted fields which are a combination of multiple query fields, or to
-       * add a duplicate field that has a different label.
-       *
-       * @type {AdditionalField[]}
-       * @since 2.15.0
-       */
-      addFields: [],
-
-      /**
-       * A list of query fields names to display at the top of the menu, above
-       * all other category headers
-       * @type {string[]}
-       */
-      commonFields: ["text", "documents-special-field"],
-
-      /**
-       * The names of categories that should have items sorted alphabetically. Names
-       * must exactly match those in the
-       * {@link QueryField#categoriesMap Query Field model}
-       * @type {string[]}
-       * @since 2.15.0
-       */
-      categoriesToAlphabetize: ["General"],
-
-      /**
-       * Whether or not to exclude fields which are not searchable. Set to
-       * false to keep query fields that are not searchable in the returned list
-       * @type {boolean}
-       */
-      excludeNonSearchable: true,
-
-      /**
-       * Creates a new QueryFieldSelectView
-       * @param {Object} options - A literal object with options to pass to the view
-       */
-      initialize: function (options) {
-        try {
-          // Ensure the query fields are cached
-          if (typeof MetacatUI.queryFields === "undefined") {
-            MetacatUI.queryFields = new QueryFields();
-            MetacatUI.queryFields.fetch();
-          }
-          SearchableSelect.prototype.initialize.call(this, options);
-        } catch (e) {
-          console.log(
-            "Failed to initialize a Query Field Select View, error message: " +
-              e,
-          );
-        }
-      },
-
-      /**
-       * postRender - Updates the view once the dropdown UI has loaded. Processes the
-       * QueryFields given the options passed to this view, then updates the menu and
-       * selection. Processing the fields takes some time, which is why we allow the
-       * view to render before starting that process. This prevents slowing down the
-       * rendering of parent views.
-       */
-      postRender: function () {
-        try {
-          var view = this;
-          _.defer(function () {
-            view.processFields();
-            view.updateMenu();
-            // With the new menu in place, show the pre-selected values. Silent is set
-            // to true so that it doesn't trigger an update of the model. Defer to make
-            // sure the menu elements are attached.
-            _.defer(function () {
-              view.changeSelection(view.selected, true);
-            });
-            SearchableSelect.prototype.postRender.call(view);
-          });
-        } catch (error) {
-          console.log(
-            "Post-render failed in a QueryFieldSelectView." +
-              " Error details: " +
-              error,
-          );
-        }
-      },
-
-      /**
-       * Retrieves the queryFields collection if not already fetched, then organizes the
-       * fields based on the options passed to this view.
-       * @since 2.17.0
-       */
-      processFields: function () {
-        try {
-          var view = this;
-
-          // Ensure the query fields are cached for the Query Field Select
-          // View and the Query Rule View
-          if (
-            typeof MetacatUI.queryFields === "undefined" ||
-            MetacatUI.queryFields.length === 0
-          ) {
-            if (typeof MetacatUI.queryFields === "undefined") {
-              MetacatUI.queryFields = new QueryFields();
-            }
-            this.listenToOnce(
-              MetacatUI.queryFields,
-              "sync",
-              this.processFields,
-            );
-            MetacatUI.queryFields.fetch();
-            return;
-          }
-
-          // Convert the queryFields collection to an object formatted for the
-          // SearchableSelect view.
-          var fieldsJSON = MetacatUI.queryFields.toJSON();
-
-          // Process & add additional fields set on this view (these are fields not
-          // retrieved from the query service API)
-          if (this.addFields && Array.isArray(this.addFields)) {
-            // For each added field, find the icon and category order from the already
-            // existing fields with the same category.
-            this.addFields = _.map(
-              this.addFields,
-              function (field) {
-                if (field.category) {
-                  var categoryInfo = _.findWhere(fieldsJSON, {
-                    category: field.category,
-                  });
-                  ["icon", "categoryOrder"].forEach(function (prop) {
-                    if (!field[prop]) {
-                      field[prop] = categoryInfo[prop];
-                    }
-                  });
-                }
-                return field;
-              },
-              this,
-            );
-            // Add the additional fields to the array of fields fetched from the
-            // query service API
-            fieldsJSON = fieldsJSON.concat(this.addFields);
-          }
-
-          // Move common fields to the top of the menu, outside of any
-          // category headers, so that they are easy to find
-          if (this.commonFields && Array.isArray(this.commonFields)) {
-            this.commonFields.forEach(function (commonFieldName) {
-              var i = _.findIndex(fieldsJSON, { name: commonFieldName });
-              if (i > 0) {
-                // If the category name is an empty string, no header will
-                // be created in the menu
-                fieldsJSON[i].category = "";
-                // The min categoryOrder in the QueryFields collection is 1
-                fieldsJSON[i].categoryOrder = 0;
-                fieldsJSON[i].icon = "star";
-              }
-            });
-          }
-
-          // Filter out non-searchable fields (if option is true),
-          // and fields that should be excluded
-          var processedFields = _(fieldsJSON)
-            .chain()
-            .sortBy("categoryOrder")
-            .filter(function (filter) {
-              if (this.excludeNonSearchable) {
-                if (["false", false].includes(filter.searchable)) {
-                  return false;
-                }
-              }
-              if (this.excludeFields && this.excludeFields.length) {
-                if (this.excludeFields.includes(filter.name)) {
-                  return false;
-                }
-              }
-              return true;
-            }, this)
-            .map(view.fieldToOption)
-            .groupBy("categoryOrder")
-            .value();
-
-          // Rename the grouped categories
-          for (const [key, value] of Object.entries(processedFields)) {
-            processedFields[value[0].category] = value;
-            delete processedFields[key];
-          }
-
-          // Sort items alphabetically for the specified categories
-          if (
-            this.categoriesToAlphabetize &&
-            this.categoriesToAlphabetize.length
-          ) {
-            this.categoriesToAlphabetize.forEach(function (categoryName) {
-              // Sort by category label
-              processedFields[categoryName].sort(function (a, b) {
-                // Ignore upper and lowercase
-                var nameA = a.label.toUpperCase();
-                var nameB = b.label.toUpperCase();
-                if (nameA < nameB) return -1;
-                if (nameA > nameB) return 1;
-                return 0;
-              });
-            });
-          }
-
-          // Set the formatted fields on the view
-          this.options = processedFields;
-        } catch (error) {
-          console.log(
-            "There was an error organizing the Fields in a QueryFieldSelectView" +
-              " Error details: " +
-              error,
-          );
-        }
-      },
-
-      /**
-       * fieldToOption - Converts an object that represents a QueryField model in the
-       * format specified by the SearchableSelectView.options
-       *
-       * @param  {object} field An object with properties corresponding to a QueryField
-       * model
-       * @return {object}       An object in the format specified by
-       * SearchableSelectView.options
-       */
-      fieldToOption: function (field) {
-        return {
-          label: field.label ? field.label : field.name,
-          value: field.name,
-          description: field.friendlyDescription
-            ? field.friendlyDescription
-            : field.description,
-          icon: field.icon,
-          category: field.category,
-          categoryOrder: field.categoryOrder,
-          type: field.type,
-        };
-      },
-
-      /**
-       * addTooltip - Add a tooltip to a given element using the description in the
-       * options object that's set on the view. This overwrites the prototype addTooltip
-       * function so that we can use popovers with more details for query select fields.
-       *
-       * @param  {HTMLElement} element The HTML element a tooltip should be added
-       * @param  {string} position how to position the tooltip - top | bottom | left |
-       * right
-       * @return {jQuery} The element with a tooltip wrapped by jQuery
-       */
-      addTooltip: function (element, position = "bottom") {
-        if (!element) {
-          return;
-        }
-
-        // Find the description in the options object, using the data-value
-        // attribute set in the template. The data-value attribute is either
-        // the label, or the value, depending on if a value is provided.
-        var valueOrLabel = $(element).data("value"),
-          opt = _.chain(this.options)
-            .values()
-            .flatten()
-            .find(function (option) {
-              return (
-                option.label == valueOrLabel || option.value == valueOrLabel
-              );
-            })
-            .value();
-
-        var label = opt.label,
-          value = opt.value,
-          type = opt.type,
-          description = opt.description ? opt.description : "";
-
-        // For added fields, the value set on the options.value element is just a
-        // unique identifier. The values that should be used to build a query are saved
-        // in the addFields array set on this view.
-        if (this.addFields && Array.isArray(this.addFields)) {
-          var specialField = _.findWhere(this.addFields, {
-            name: valueOrLabel,
-          });
-          if (specialField) {
-            value = specialField.fields;
-            type = [];
-            specialField.fields.forEach(function (fieldName) {
-              var realField = MetacatUI.queryFields.findWhere({
-                name: fieldName,
-              });
-              if (realField) {
-                type.push(realField.get("type"));
-              } else {
-                type.push("special field");
-              }
-            }, this);
-            type = type.join(", ");
-          }
-        }
-
-        var contentEl = $(document.createElement("div")),
-          titleEl = $("<div>" + label + "</div>"),
-          valueEl = $("<code class='pull-right'>" + value + "</code>"),
-          typeEl = $(
-            "<span class='muted pull-right'><b>Type: " + type + "</b></span>",
-          ),
-          descriptionEl = $("<p>" + description + "</p>");
-
-        titleEl.append(valueEl);
-        contentEl.append(descriptionEl, typeEl);
-
-        $(element)
-          .popover({
-            title: titleEl,
-            content: contentEl,
-            html: true,
-            trigger: "hover",
-            placement: position,
-            container: "body",
-            delay: {
-              show: 1100,
-              hide: 50,
-            },
-          })
-          .on("show.bs.popover", function () {
-            var $el = $(this);
-            // Allow time for the popup to be added to the DOM
-            setTimeout(function () {
-              // Then add some css rules, and a special class to identify
-              // these popups if they need to be removed.
-              $el
-                .data("popover")
-                .$tip.css({
-                  maxWidth: "400px",
-                  pointerEvents: "none",
-                })
-                .addClass("search-select-tooltip");
-            }, 10);
-          });
-
-        return $(element);
+      /** @inheritdoc */
+      tooltipSettings: {
+        ...SearchSelect.prototype.tooltipSettings,
+        variation: "mini",
+        // the semantic "card" we use for inner content has sufficient padding
+        onCreate() {
+          this.css({ padding: 0 });
+        },
       },
 
-      /**
-       * isValidOption - Checks if a value is one of the values given in view.options
-       *
-       * @param  {string} value The value to check
-       * @return {boolean}      returns true if the value is one of the values given in view.options
-       */
-      isValidOption: function (value) {
-        try {
-          var view = this;
-
-          // First check if the value is one of the fields that's excluded.
-          if (view.excludeFields.includes(value)) {
-            // If it is, then add it to the list of options
-            var newField = MetacatUI.queryFields.findWhere({
-              name: value,
-            });
-            if (newField) {
-              newField = view.fieldToOption(newField.toJSON());
-            }
-            view.options[newField.category].push(newField);
-            view.updateMenu();
-            // Make sure the new menu is attached before updating the selections
-            setTimeout(function () {
-              // If the selected value has been removed, re-add it.
-              if (!view.selected.includes(value)) {
-                view.selected.push(value);
-              }
-              view.changeSelection(view.selected, (silent = true));
-            }, 25);
-            return true;
-          } else {
-            var isValid = SearchableSelect.prototype.isValidOption.call(
-              view,
-              value,
-            );
-            return isValid;
-          }
-        } catch (e) {
-          console.log(
-            "Failed to check if option is valid in a Query Field Select View, error message: " +
-              e,
-          );
-        }
+      /** @inheritdoc */
+      tooltipHTML(option) {
+        // If this option is one of the addedFields (an abstracted field), then
+        // we need to check the QueryFields model for the actual fields and
+        // field types this option represents.
+        this.model.setAddedFieldDetails(option);
+
+        const label = option.get("label") || "";
+        const value = option.get("fields") || option.get("value") || "";
+        const type = option.get("types") || option.get("type") || "";
+        const description = option.get("description") || "";
+
+        const htmlStr = `
+        <div class="${Semantic.CLASS_NAMES.base} ${Semantic.CLASS_NAMES.variations.mini} ${Semantic.CLASS_NAMES.card.base}">
+          <div class="${Semantic.CLASS_NAMES.card.content}">
+            <div class="${Semantic.CLASS_NAMES.card.header}">${label}</div>
+            <div class="${Semantic.CLASS_NAMES.card.meta}"><span class="category">${value}</span></div>
+            <div class="${Semantic.CLASS_NAMES.card.description}">${description}</div>
+          </div>
+          <div class="${Semantic.CLASS_NAMES.card.extra} ${Semantic.CLASS_NAMES.card.content} ${Semantic.CLASS_NAMES.grid.floated} ${Semantic.CLASS_NAMES.grid.right}">Type: <code>${type}</code></div>
+        </div>`;
+
+        return htmlStr;
       },
     },
   );
diff --git a/docs/docs/src_js_views_searchSelect_SearchSelectHeaderView.js.html b/docs/docs/src_js_views_searchSelect_SearchSelectHeaderView.js.html
new file mode 100644
index 000000000..d2ffc78c2
--- /dev/null
+++ b/docs/docs/src_js_views_searchSelect_SearchSelectHeaderView.js.html
@@ -0,0 +1,266 @@
+
+
+
+    
+    MetacatUI Dev Docs: Source: src/js/views/searchSelect/SearchSelectHeaderView.js
+
+    
+    
+    
+    
+    
+    
+    
+
+
+
+
+
+
+
+ +

Source: src/js/views/searchSelect/SearchSelectHeaderView.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "semantic"], (Backbone, Semantic) => {
+  // The class for the outermost element of the header.
+  const BASE_CLASS = Semantic.CLASS_NAMES.dropdown.header;
+
+  // The class names for the various icons in the header.
+  const CLASS_NAMES = {
+    icon: "icon",
+    chevronDown: "icon-chevron-down",
+    chevronRight: "icon-chevron-right",
+    accordionIcon: "accordion-mode-icon",
+    popoutIcon: "popout-mode-icon",
+    categoryIcon: "category-icon",
+  };
+
+  // The layout modes for the header.
+  const MODES = ["list", "popout", "accordion"];
+
+  /**
+   * @class
+   * @classdesc A category header in a SearchSelectMenuView.
+   * @classcategory Views/SearchSelect
+   * @augments SearchSelect
+   * @class
+   * @since 2.31.0
+   * @screenshot views/searchSelect/SearchSelectHeaderView.png
+   */
+  return Backbone.View.extend(
+    /** @lends SearchSelectHeaderView.prototype */
+    {
+      /** @inheritdoc */
+      type: "SearchSelectHeaderView",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /** @inheritdoc */
+      tagName: "h6",
+
+      /**
+       * The label of the category to display.
+       * @type {string}
+       */
+      category: "",
+
+      /**
+       * The fontawesome icon associated with the category.
+       * @type {string}
+       */
+      categoryIcon: "",
+
+      /**
+       * The layout for the menu - can be "popout", "accordion", or "list".
+       * @type {string}
+       */
+      mode: "list",
+
+      /** @inheritdoc */
+      initialize(opts = {}) {
+        this.category = opts?.category || "";
+        this.categoryIcon = opts?.categoryIcon || "";
+        if (opts?.mode && this.isValidMode(opts.mode)) {
+          this.mode = opts.mode;
+        }
+      },
+
+      /** @inheritdoc */
+      render() {
+        this.icons = {};
+
+        this.icons.category = null;
+        if (this.categoryIcon) {
+          this.icons.category = this.createIconEl([
+            CLASS_NAMES.icon,
+            `${CLASS_NAMES.icon}-${this.categoryIcon}`,
+            CLASS_NAMES.categoryIcon,
+          ]);
+        }
+        this.icons.accordion = this.createIconEl([
+          CLASS_NAMES.chevronDown,
+          CLASS_NAMES.accordionIcon,
+        ]);
+        this.icons.popout = this.createIconEl([
+          CLASS_NAMES.chevronRight,
+          CLASS_NAMES.popoutIcon,
+        ]);
+
+        this.el.textContent = this.category;
+        if (this.icons.category) {
+          this.el.prepend(this.icons.category);
+        }
+        this.el.append(this.icons.accordion, this.icons.popout);
+
+        this.updateMode(this.mode, true);
+
+        return this;
+      },
+
+      /**
+       * Create an icon element.
+       * @param {string[]} classes - The classes to add to the icon element.
+       * @returns {HTMLElement} The icon element.
+       */
+      createIconEl(classes) {
+        const el = document.createElement("i");
+        el.classList.add(...classes);
+        return el;
+      },
+
+      /** Hide the accordion, popout, and category icons. */
+      hideAllIcons() {
+        Object.values(this.icons).forEach((icon) => this.hideIcon(icon));
+      },
+
+      /** Show the category icon. */
+      showCategoryIcon() {
+        this.showIcon(this.icons.category);
+      },
+
+      /** Show the accordion icon. */
+      showAccordionIcon() {
+        this.showIcon(this.icons.accordion);
+      },
+
+      /** Show the popout icon. */
+      showPopoutIcon() {
+        this.showIcon(this.icons.popout);
+      },
+
+      /**
+       * Show a given icon element.
+       * @param {HTMLElement} iconEl - The icon element to show.
+       */
+      showIcon(iconEl) {
+        if (!iconEl) return;
+        const styles = iconEl.style;
+        styles.display = "inline";
+      },
+
+      /**
+       * Hide a given icon element.
+       * @param {HTMLElement} iconEl - The icon element to hide.
+       */
+      hideIcon(iconEl) {
+        if (!iconEl) return;
+        const styles = iconEl.style;
+        styles.display = "none";
+      },
+
+      /** Hide the header. */
+      hide() {
+        this.el.style.display = "none";
+      },
+
+      /** Show the header. */
+      show() {
+        this.el.style.display = "block";
+      },
+
+      /**
+       * Update the layout mode of the header.
+       * @param {string} mode - The new layout mode.
+       */
+      updateMode(mode) {
+        if (!this.isValidMode(mode)) return;
+        const modeMap = {
+          list: this.toList,
+          popout: this.toPopout,
+          accordion: this.toAccordion,
+        };
+        modeMap[mode].call(this);
+      },
+
+      /** Set the layout mode to "popout". */
+      toPopout() {
+        this.mode = "popout";
+        this.showCategoryIcon();
+        this.showPopoutIcon();
+      },
+
+      /** Set the layout mode to "accordion". */
+      toAccordion() {
+        this.mode = "accordion";
+        this.showCategoryIcon();
+        this.showAccordionIcon();
+      },
+
+      /** Set the layout mode to "list". */
+      toList() {
+        this.mode = "list";
+        this.hideAllIcons();
+      },
+
+      /**
+       * Check if a given mode is a valid layout mode.
+       * @param {string} mode - The mode to check.
+       * @returns {boolean} Whether the mode is valid.
+       */
+      isValidMode(mode) {
+        return MODES.includes(mode);
+      },
+    },
+  );
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_searchSelect_SearchSelectOptionView.js.html b/docs/docs/src_js_views_searchSelect_SearchSelectOptionView.js.html new file mode 100644 index 000000000..9f81434bb --- /dev/null +++ b/docs/docs/src_js_views_searchSelect_SearchSelectOptionView.js.html @@ -0,0 +1,229 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/searchSelect/SearchSelectOptionView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/searchSelect/SearchSelectOptionView.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "semantic", "models/searchSelect/SearchSelectOption"], (
+  Backbone,
+  Semantic,
+  OptionModel,
+) => {
+  const CLASS_NAMES = {
+    icon: "icon",
+    iconOnLeft: "icon-on-left",
+    iconOnRight: "icon-on-right",
+  };
+
+  /**
+   * @class
+   * @classdesc One option (item) in a SearchSelectView dropdown menu.
+   * @classcategory Views/SearchSelect
+   * @augments SearchSelect
+   * @class
+   * @since 2.31.0
+   * @screenshot views/searchSelect/SearchSelectOptionView.png
+   */
+  return Backbone.View.extend(
+    /** @lends SearchSelectOptionView.prototype */
+    {
+      /** @inheritdoc */
+      type: "SearchSelectOptionView",
+
+      /** @inheritdoc */
+      className: Semantic.CLASS_NAMES.dropdown.item,
+
+      /**
+       * The height and width in pixels of the image to display in the option.
+       * Format: [width, height]
+       * @type {number[]}
+       */
+      imageSize: [32, 32],
+
+      /** @inheritdoc */
+      events: {
+        mouseenter: "addTooltip",
+      },
+
+      /**
+       * Options for the Formantic UI popup module to configure the tooltip
+       * that is shown on hover. Set to false to disable.
+       * @see https://fomantic-ui.com/modules/popup.html#/settings
+       * @type {object|boolean}
+       */
+      tooltipSettings: {
+        position: "top left",
+        variation: `${Semantic.CLASS_NAMES.variations.inverted} ${Semantic.CLASS_NAMES.variations.mini}`,
+        delay: {
+          show: 300,
+          hide: 10,
+        },
+        exclusive: true,
+      },
+
+      /** @inheritdoc */
+      initialize(opts = {}) {
+        this.model = opts?.model || new OptionModel();
+        this.listenTo(this.model, "change", this.render);
+      },
+
+      /** @inheritdoc */
+      render() {
+        this.el.innerHTML = "";
+        this.removeTooltip();
+
+        const label = this.model.get("label");
+        const value = this.model.get("value") || label;
+        this.el.setAttribute("data-value", value);
+
+        const decorEl = this.createIconEl() || this.createImageEl() || "";
+        const labelEl = document.createTextNode(label);
+
+        this.el.append(decorEl, labelEl);
+        return this;
+      },
+
+      /**
+       * Creates an icon element for the option.
+       * @returns {HTMLElement|null} The icon element, or null if no icon is
+       * specified.
+       */
+      createIconEl() {
+        const iconName = this.model.get("icon");
+        if (!iconName) return null;
+        const iconEl = document.createElement("i");
+        iconEl.classList.add(
+          CLASS_NAMES.icon,
+          CLASS_NAMES.iconOnLeft,
+          `icon-${iconName}`,
+        );
+        return iconEl;
+      },
+
+      /**
+       * Creates an image element for the option.
+       * @returns {HTMLElement|null} The image element, or null if no image is
+       * specified.
+       */
+      createImageEl() {
+        const image = this.model.get("image");
+        if (!image) return null;
+
+        const imageWidth = this.imageSize?.[0] || 32;
+        const imageHeight = this.imageSize?.[1] || 32;
+        const imgEl = document.createElement("img");
+        imgEl.src = image;
+        imgEl.style.cssText = `
+          width: 100%;
+          height: 100%;
+          max-width: ${imageWidth}px;
+          max-height:${imageHeight}px;
+        `;
+        return imgEl;
+      },
+
+      /**
+       * Adds a tooltip to the option element. The tooltip is created when the
+       * user first hovers over the option.
+       */
+      addTooltip() {
+        const view = this;
+        if (this.tooltipCreated || !this.tooltipSettings) return;
+        const html = this.tooltipHTML();
+        if (!html) return;
+        this.$el.popup({
+          html,
+          ...this.tooltipSettings,
+        });
+        if (!this.tooltipCreated) {
+          view.$el.popup("show");
+        }
+        this.tooltipCreated = true;
+      },
+
+      /** Removes the tooltip from the option element */
+      removeTooltip() {
+        if (!this.tooltipCreated) return;
+        this.$el.popup("destroy");
+        this.tooltipCreated = false;
+      },
+
+      /**
+       * Create HTML for a tooltip for a given option.
+       * @returns {string|null} An HTML string to use for the content of the
+       * tooltip.
+       */
+      tooltipHTML() {
+        // TODO: Should inherit tooltip from parent view
+        return this.model.get("description") || null;
+      },
+
+      /**
+       * Returns true if the option is currently filtered out (hidden) by
+       * Semantic UI in the menu.
+       * @returns {boolean} True if the option is filtered, false otherwise.
+       */
+      isFiltered() {
+        const filteredClass = Semantic.CLASS_NAMES.dropdown.filtered;
+        return this.el.classList.contains(filteredClass);
+      },
+    },
+  );
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_searchSelect_SearchSelectOptionsView.js.html b/docs/docs/src_js_views_searchSelect_SearchSelectOptionsView.js.html new file mode 100644 index 000000000..d66830a64 --- /dev/null +++ b/docs/docs/src_js_views_searchSelect_SearchSelectOptionsView.js.html @@ -0,0 +1,379 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/searchSelect/SearchSelectOptionsView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/searchSelect/SearchSelectOptionsView.js

+ + + + + + +
+
+
"use strict";
+
+define([
+  "backbone",
+  "semantic",
+  "collections/searchSelect/SearchSelectOptions",
+  "views/searchSelect/SearchSelectOptionView",
+  "views/searchSelect/SearchSelectHeaderView",
+], (
+  Backbone,
+  Semantic,
+  SearchSelectOptions,
+  SearchSelectOptionView,
+  SearchSelectHeaderView,
+) => {
+  // Base class for the dropdown menu
+  const BASE_CLASS = Semantic.CLASS_NAMES.dropdown.menu;
+
+  // Classes that we use from the semantic module
+  const CLASS_NAMES = {
+    popout: "popout-mode",
+    accordion: "accordion-mode",
+  };
+
+  // Classes that we use from the bootstrap module
+  const BOOTSTRAP_CLASS_NAMES = {
+    collapse: "collapse",
+    collapsed: "collapsed",
+  };
+
+  // Allowaable modes for the menu
+  const MODES = ["list", "popout", "accordion"];
+
+  /**
+   * @class
+   * @classdesc The menu in a SearchSelectView. Handles the connection between
+   * the SearchSelectOptions collection and the dropdown menu.
+   * @classcategory Views/SearchSelect
+   * @augments SearchSelect
+   * @class
+   * @since 2.31.0
+   * @screenshot views/searchSelect/SearchSelectOptionsView.png
+   */
+  return Backbone.View.extend(
+    /** @lends SearchSelectMenuView.prototype */
+    {
+      /** @inheritdoc */
+      type: "SearchSelectMenuView",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /** The current layout mode for the menu */
+      mode: "list",
+
+      /**
+       * @inheritdoc
+       * @param {object} opts - The options for the view
+       * @param {SearchSelectOptions} opts.collection - The collection of options
+       * @param {string} opts.mode - The initial layout mode for the menu
+       */
+      initialize(opts = {}) {
+        this.collection = opts?.collection || new SearchSelectOptions();
+        this.listenTo(this.collection, "add", (option) =>
+          this.addOption(option, true),
+        );
+        this.listenTo(this.collection, "remove", this.removeOption);
+        this.listenTo(this.collection, "reset", this.render);
+        this.listenTo(this.collection, "update", this.render);
+        if (opts?.mode && this.isValidMode(opts.mode)) {
+          this.mode = opts.mode;
+        }
+      },
+
+      /** @inheritdoc */
+      render() {
+        this.el.innerHTML = "";
+        this.headers = {};
+        this.optionViews = [];
+        this.collection.each((option) => this.addOption(option));
+        this.updateMode(this.mode, true);
+        return this;
+      },
+
+      /**
+       * Add an option to the menu
+       * @param {SearchSelectOption} option The model to add
+       * @param {boolean} appendInOrder Whether to add the option in order
+       * according to the collection
+       */
+      addOption(option, appendInOrder = false) {
+        const category = option.get("category") || "";
+        const categoryIcon = option.get("icon") || "";
+
+        if (!this.getHeader(category) && category) {
+          this.addHeader(category, categoryIcon);
+        }
+        const optionView = new SearchSelectOptionView({
+          model: option,
+        }).render();
+
+        // Add the option to the view in the correct order
+        let appendBeforeView = null;
+        if (appendInOrder && this.collection.length > 1 && this.optionViews) {
+          const modelIndex = this.collection.indexOf(option);
+          const prevOption = this.collection.at(modelIndex - 1);
+          appendBeforeView = this.getOptionView(prevOption);
+        }
+        if (appendBeforeView) {
+          appendBeforeView.el.before(optionView.el);
+        } else {
+          this.el.append(optionView.el);
+        }
+
+        if (!this.optionViews) this.optionViews = {};
+        if (!this.optionViews[category]) this.optionViews[category] = [];
+        this.optionViews[category].push(optionView);
+      },
+
+      /**
+       * Add a header element to the menu
+       * @param {string} category The category label
+       * @param {string} categoryIcon The icon for the category
+       */
+      addHeader(category, categoryIcon) {
+        const { mode } = this;
+        const headerView = new SearchSelectHeaderView({
+          category,
+          categoryIcon,
+          mode,
+        }).render();
+        if (!this.headers) this.headers = {};
+        this.headers[category] = headerView;
+        this.el.append(headerView.el);
+      },
+
+      /**
+       * Get the header view for a category
+       * @param {string} category The category label
+       * @returns {SearchSelectHeaderView|null} The header view, or null if not
+       */
+      getHeader(category) {
+        return this.headers?.[category];
+      },
+
+      /**
+       * Given an option model, find the corresponding option view
+       * @param {SearchSelectOption} option - The option model
+       * @returns {SearchSelectOptionView|null} The option view, or null if not
+       * found
+       */
+      getOptionView(option) {
+        if (!this.optionViews?.length || !option) return null;
+        const category = option.get("category") || "";
+        return this.optionViews?.[category]?.find(
+          (view) => view.model === option,
+        );
+      },
+
+      /** Hide category headers for which all options are filtered */
+      hideEmptyCategories() {
+        if (!this.optionViews) return;
+        Object.entries(this.optionViews).forEach(([category, views]) => {
+          const allItemsFiltered = views.every((view) => view.isFiltered);
+          if (allItemsFiltered) {
+            this.headers?.[category]?.hide();
+          } else {
+            this.headers?.[category]?.show();
+          }
+        });
+      },
+
+      /** Show all category headers */
+      showAllCategories() {
+        if (!this.headers) return;
+        Object.values(this.headers).forEach((header) => header.show());
+      },
+
+      /**
+       * Remove an option from the menu
+       * @param {SearchSelectOption} option - The option model to remove
+       */
+      removeOption(option) {
+        const optionView = this.optionViews.find(
+          (view) => view.model === option,
+        );
+        optionView.remove();
+        this.optionViews = this.optionViews.filter(
+          (view) => view !== optionView,
+        );
+      },
+
+      /**
+       * Wrap a set of elements in a new container element
+       * @param {HTMLElement[]} items - The elements to wrap
+       * @param {string} tagName - The tag name for the wrapper element
+       * @param {string[]} classes - The classes to add to the wrapper element
+       * @returns {HTMLElement} The wrapper element
+       */
+      wrapAll(items, tagName = "div", classes = []) {
+        // Items can be views or HTML elements
+        const els = items.map((item) => item.el || item);
+        const wrapperEl = document.createElement(tagName);
+        const parent = els[0].parentNode;
+        wrapperEl.className = classes.join(" ");
+        parent.insertBefore(wrapperEl, els[0]);
+        wrapperEl.append(...els);
+        return wrapperEl;
+      },
+
+      /** Unwrap all elements that have been wrapped in the menu */
+      unwrapAll() {
+        this.wrapperEls?.forEach((el) => {
+          el.replaceWith(...el.childNodes);
+        });
+        this.wrapperEls = [];
+      },
+
+      /**
+       * Update the layout mode for the menu
+       * @param {string} mode - The new mode
+       * @param {boolean} force - Whether to force the update
+       */
+      updateMode(mode, force = false) {
+        if (!this.isValidMode(mode)) return;
+        if (force) this.mode = null;
+        if (this.mode === mode) return;
+        const methodMap = {
+          list: this.toList,
+          popout: this.toPopout,
+          accordion: this.toAccordion,
+        };
+        methodMap[mode].call(this, force);
+      },
+
+      /** Change the menu to list mode */
+      toList() {
+        if (this.mode === "list") return;
+        this.mode = "list";
+        this.el.classList.remove(CLASS_NAMES.popout, CLASS_NAMES.accordion);
+        this.unwrapAll();
+        if (this.headers) {
+          Object.values(this.headers)?.forEach((header) => header.toList());
+        }
+      },
+
+      /** Change the menu to popout mode */
+      toPopout() {
+        if (this.mode === "popout") return;
+        this.toList();
+        this.mode = "popout";
+        if (!this.optionViews) return;
+
+        if (!this.wrapperEls) this.wrapperEls = [];
+        this.$el.addClass(CLASS_NAMES.popout);
+
+        Object.entries(this.optionViews).forEach(([category, optionViews]) => {
+          const header = this.getHeader(category);
+          const headerAndItems = [header, ...optionViews];
+          header.toPopout();
+          const groupWrapper = this.wrapAll(headerAndItems, "div");
+          const itemsWrapper = this.wrapAll(optionViews, "div", [
+            Semantic.CLASS_NAMES.dropdown.menu,
+            CLASS_NAMES.popout,
+          ]);
+          this.wrapperEls.push(groupWrapper, itemsWrapper);
+        });
+      },
+
+      /** Change the menu to accordion mode */
+      toAccordion() {
+        if (this.mode === "accordion") return;
+
+        this.toList();
+        this.mode = "accordion";
+        if (!this.optionViews) return;
+
+        if (!this.wrapperEls) this.wrapperEls = [];
+
+        this.$el.addClass(CLASS_NAMES.accordion);
+
+        Object.entries(this.optionViews).forEach(([category, optionViews]) => {
+          const header = this.getHeader(category);
+          if (!header) return;
+          header.toAccordion();
+          // Create a unique ID for each header
+          const groupId = Math.floor(Math.random() * 100000 + 1);
+          const headerWrapper = this.wrapAll([header], "a", [
+            CLASS_NAMES.accordion,
+            BOOTSTRAP_CLASS_NAMES.collapsed,
+          ]);
+          headerWrapper.setAttribute(
+            "data-toggle",
+            BOOTSTRAP_CLASS_NAMES.collapse,
+          );
+          headerWrapper.setAttribute("data-target", `#${groupId}`);
+
+          const itemsWrapper = this.wrapAll(optionViews, "div", [
+            CLASS_NAMES.accordion,
+            BOOTSTRAP_CLASS_NAMES.collapse,
+          ]);
+          itemsWrapper.setAttribute("id", groupId);
+
+          this.wrapperEls.push(headerWrapper, itemsWrapper);
+        });
+      },
+
+      /**
+       * Check if a mode is valid
+       * @param {string} mode - The mode to check
+       * @returns {boolean} Whether the mode is valid
+       */
+      isValidMode(mode) {
+        return MODES.includes(mode);
+      },
+    },
+  );
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_searchSelect_SearchSelectView.js.html b/docs/docs/src_js_views_searchSelect_SearchSelectView.js.html new file mode 100644 index 000000000..d03636aa1 --- /dev/null +++ b/docs/docs/src_js_views_searchSelect_SearchSelectView.js.html @@ -0,0 +1,758 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/searchSelect/SearchSelectView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/searchSelect/SearchSelectView.js

+ + + + + + +
+
+
"use strict";
+
+define([
+  "jquery",
+  "underscore",
+  "backbone",
+  "semantic",
+  "views/searchSelect/SeparatorView",
+  "views/searchSelect/SearchSelectOptionsView",
+  "models/searchSelect/SearchSelect",
+], ($, _, Backbone, Semantic, SeparatorView, OptionsView, SearchSelect) => {
+  // The base class for the search select view
+  const BASE_CLASS = "search-select";
+
+  // Class names that we use in the view, including those from the dropdown
+  // module
+  const CLASS_NAMES = {
+    inputLabel: [`${BASE_CLASS}-label`, "subtle"],
+    popout: "popout-mode",
+    accordion: "accordion-mode",
+    chevronDown: "icon-chevron-down",
+    chevronRight: "icon-chevron-right",
+    dropdownIconRight: [
+      Semantic.CLASS_NAMES.dropdown.base,
+      "icon",
+      "icon-on-right",
+    ],
+    accordionIcon: "accordion-mode-icon",
+    popoutIcon: "popout-mode-icon",
+    buttonStyle: Semantic.CLASS_NAMES.button.base,
+    labeled: Semantic.CLASS_NAMES.button.labeled,
+    compact: "compact",
+  };
+
+  // The placeholder element needs both to work properly
+  CLASS_NAMES.placeholder = [
+    Semantic.CLASS_NAMES.dropdown.placeholder,
+    Semantic.CLASS_NAMES.dropdown.text,
+  ];
+
+  // Classes to use for different types of messages
+  const MESSAGE_TYPES = {
+    error: {
+      messageClass: "text-error",
+      selectUIClass: "error",
+    },
+    warning: {
+      messageClass: "text-warning",
+      selectUIClass: "warning",
+    },
+    info: {
+      messageClass: "text-info",
+      selectUIClass: "",
+    },
+  };
+
+  // The delimiter used to separate values in the dropdown
+  const DELIMITER = ";";
+
+  /**
+   * @class SearchSelectView
+   * @classdesc A select interface that allows the user to search from within
+   * the options, and optionally select multiple items. Also allows the items to
+   * be grouped, and to display an icon or image for each item.
+   * @classcategory Views/SearchSelect
+   * @augments Backbone.View
+   * @class
+   * @since 2.14.0
+   * @screenshot views/searchSelect/SearchSelectView.png
+   */
+  const SearchSelectView = Backbone.View.extend(
+    /** @lends SearchSelectView.prototype */
+    {
+      /** @inheritdoc */
+      type: "SearchSelect",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /**
+       * The constructor function for the model that this view uses. Must be a
+       * SearchSelect or an extension of it.
+       * @type {Backbone.Model}
+       * @since 2.31.0
+       */
+      ModelType: SearchSelect,
+
+      /**
+       * Options and selected values for the search select interface show a
+       * tooltip with the description of the option when the user hovers over
+       * the option. This object is passed to the Formantic UI popup module to
+       * configure the tooltip. Set to false to disable tooltips.
+       * @see https://fomantic-ui.com/modules/popup.html#/settings
+       * @type {object|boolean}
+       * @since 2.31.0
+       */
+      tooltipSettings: {
+        position: "top left",
+        variation: `${Semantic.CLASS_NAMES.variations.inverted} ${Semantic.CLASS_NAMES.variations.mini}`,
+        delay: {
+          show: 450,
+          hide: 10,
+        },
+        exclusive: true,
+      },
+
+      /** @inheritdoc */
+      initialize(opts) {
+        const options = opts || {};
+        // Set options on the view and create the model
+        const { modelAttrs, viewAttrs } = this.splitModelViewOptions(options);
+        if (!options.model) this.createModel(modelAttrs);
+        Object.assign(this, viewAttrs);
+      },
+
+      /**
+       * Split the options passed to the view into model and view attributes.
+       * @param {object} options The options passed to the view
+       * @returns {object} An object with two keys: modelAttrs and viewAttrs
+       * @since 2.31.0
+       */
+      splitModelViewOptions(options) {
+        const modelAttrNames = Object.keys(this.ModelType.prototype.defaults());
+        const modelAttrs = _.pick(options, modelAttrNames);
+        const viewAttrs = _.omit(options, modelAttrNames);
+        return { modelAttrs, viewAttrs };
+      },
+
+      /**
+       * Create a new SearchSelect model and set it on the view. If a model
+       * already exists, it will be destroyed.
+       * @param {object} options The options to pass to the model
+       * @since 2.31.0
+       */
+      createModel(options) {
+        const modelAttrs = options || {};
+
+        if (this.model) {
+          this.stopListening(this.model);
+          this.model.destroy();
+        }
+
+        // Selected values can be part of other models
+        if (modelAttrs.selected) {
+          modelAttrs.selected = [...modelAttrs.selected];
+        }
+        this.model = new this.ModelType(modelAttrs);
+      },
+
+      /** @inheritdoc */
+      render() {
+        this.el.innerHTML = "";
+
+        this.labelEl = this.createLabel();
+        this.selectContainerEl = this.createSelectContainer();
+        this.inputEl = this.createInput();
+        this.iconEl = this.createIcon();
+        this.placeholderEl = this.createPlaceholder();
+        this.menu = this.createMenu();
+        this.menuEl = this.menu.el;
+
+        this.el.append(this.labelEl || "", this.selectContainerEl || "");
+        this.selectContainerEl.append(
+          this.inputEl || "",
+          this.iconEl || "",
+          this.placeholderEl || "",
+          this.menuEl || "",
+        );
+
+        this.$selectUI = $(this.selectContainerEl);
+        this.inactivate();
+        this.showLoading();
+        this.renderSelectUI();
+        this.showSelected(true);
+        this.listenToModel();
+        this.listenToSelectUI();
+        this.checkForInvalidSelections();
+        this.enable();
+        this.hideLoading();
+
+        return this;
+      },
+
+      /** Initialize the dropdown interface */
+      renderSelectUI() {
+        const view = this;
+
+        // Destroy any previous dropdowns
+        if (typeof this.$selectUI.dropdown === "function") {
+          this.$selectUI.dropdown("destroy");
+        }
+
+        // Initialize the dropdown interface For explanations of settings, see:
+        // https://semantic-ui.com/modules/dropdown.html#/settings
+        this.$selectUI = this.$selectUI.dropdown({
+          delimiter: DELIMITER,
+          apiSettings: this.model.get("apiSettings"),
+          fullTextSearch: true,
+          duration: 90,
+          forceSelection: false,
+          ignoreDiacritics: true,
+          clearable: view.model.get("clearable"),
+          allowAdditions: view.model.get("allowAdditions"),
+          hideAdditions: false,
+          allowReselection: true,
+          onChange() {
+            if (view.enabled) {
+              // Update the model with the selected values
+              const selected = view.$selectUI.dropdown("get values");
+              view.model.setSelected(selected);
+            }
+            // ensure the DOM is updated before modifying the elements
+            requestAnimationFrame(() => {
+              view.addTooltipsToSelectionEls();
+              view.addSeparators();
+              view.addClickToTexts();
+            });
+          },
+        });
+        view.$selectUI.data("view", view);
+      },
+
+      /**
+       * Because we've modified the text elements to be hoverable to show the
+       * tooltip, we needed to move them to a higher z-index which blocks the
+       * click action on the dropdown input element. This function ensures that
+       * the dropdown is shown when any part of the input is clicked, including
+       * the selected text elements in a single-select dropdown.
+       * @since 2.31.0
+       */
+      addClickToTexts() {
+        const showMenu = () => {
+          this.$selectUI.dropdown("show");
+        };
+        const texts = this.getTexts();
+        if (!texts?.length) return;
+        texts.forEach((text) => text.removeEventListener("click", showMenu));
+        const text = this.getTexts()?.[0];
+        if (!text) return;
+        text.addEventListener("click", showMenu);
+      },
+
+      /**
+       * Update the dropdown interface with the selected values from the model
+       * @param {boolean} [silent] Set to true to prevent the dropdown from
+       * triggering a change event (an infinite loop can occur if this is not set,
+       * as the dropdown will trigger a change event, which will update the model).
+       * @since 2.31.0
+       */
+      showSelected(silent = false) {
+        const enabledBefore = this.enabled;
+        this.inactivate();
+
+        const selected = this.model.get("selected");
+        // Add one at a time so that labels appear in the correct order
+        selected.forEach((s) => {
+          this.$selectUI.dropdown("set selected", s);
+        });
+
+        if (!silent) {
+          // trigger once to ensure the model is updated
+          this.$selectUI.dropdown("set selected", selected);
+        }
+
+        if (enabledBefore) {
+          this.enable();
+        }
+      },
+
+      /** @returns {HTMLElement[]} The selected label elements in a multi-select dropdown */
+      getLabels() {
+        return this.$selectUI.find(Semantic.DROPDOWN_SELECTORS.label).toArray();
+      },
+
+      /** @returns {HTMLElement[]} The selected text element in a single-select dropdown */
+      getTexts() {
+        // default text is the placeholder
+        return this.$selectUI
+          .find(
+            `${Semantic.DROPDOWN_SELECTORS.text}:not(.${Semantic.CLASS_NAMES.dropdown.placeholder})`,
+          )
+          .toArray();
+      },
+
+      /** Add tooltips to the selected labels or text elements */
+      addTooltipsToSelectionEls() {
+        const els = this.getLabels().concat(this.getTexts());
+        els.forEach((el) => this.addTooltip(el));
+      },
+
+      /** Remove all messages from the view */
+      removeAllSeparators() {
+        this.separators?.forEach((sep) => sep.remove());
+      },
+
+      /** Add separators between labels in the dropdown if required */
+      addSeparators() {
+        this.removeAllSeparators();
+        const labels = this.getLabels();
+
+        labels.forEach((label) => {
+          const value = $(label).data("value");
+          if (this.model.separatorRequired(value)) {
+            this.addSeparator(label);
+          }
+        });
+      },
+
+      /**
+       * Add a separator before the given label element
+       * @param {HTMLElement} el The label element to add a separator before
+       */
+      addSeparator(el) {
+        if (!this.separators) this.separators = [];
+        const separator = this.createSeparator();
+        if (separator) {
+          // Attach the separator to the label so that we can easily remove it
+          // when the label is removed.
+          $(el).data("separator", separator);
+          // Add it before the label element.
+          separator.$el.insertBefore($(el));
+          this.separators.push(separator);
+        }
+      },
+
+      /**
+       * Update the view when certain model attributes change
+       * @since 2.31.0
+       */
+      listenToModel() {
+        this.stopListening(this.model);
+        const view = this;
+        this.listenTo(this.model.get("options"), "add remove reset", () => {
+          // If pre-selected values were not in the options previously, then
+          // they would have been removed and/or shown as invalid selections.
+          // Re-add & check selections, after a timeout to ensure the DOM is
+          // updated.
+          requestAnimationFrame(() => {
+            view.showSelected(true);
+            view.checkForInvalidSelections();
+            // save defaults
+            view.$selectUI.dropdown("save defaults");
+            view.$selectUI.dropdown("refresh");
+          });
+        });
+        this.listenTo(this.model, "change:submenuStyle", this.updateMenuMode);
+        if (this.model.get("hideEmptyCategoriesOnSearch")) {
+          this.listenTo(
+            this.model,
+            "change:searchTerm",
+            (_model, searchTerm) => {
+              if (searchTerm) {
+                view.menu.hideEmptyCategories();
+              } else {
+                view.menu.showAllCategories();
+              }
+            },
+          );
+        }
+      },
+
+      /**
+       * Listen to events from the select UI interface and update the model
+       * @since 2.31.0
+       */
+      listenToSelectUI() {
+        // Save the active search term in the model
+        this.$selectUI.find("input").off("keyup blur focus");
+        this.$selectUI.find("input").on("keyup blur focus", (e) => {
+          this.model.set("lastInteraction", e.type);
+          this.model.set("searchTerm", e.target.value);
+        });
+      },
+
+      /**
+       * Change the options available in the dropdown menu and re-render.
+       * @param {SearchSelectOptions} options The new options
+       * @since 2.24.0
+       */
+      updateOptions(options) {
+        this.model.updateOptions(options);
+      },
+
+      /**
+       * Create the HTML for a separator element to insert between two labels.
+       * The view.separatorClass is added to the separator element.
+       * @returns {JQuery} Returns the separator as a jQuery element
+       * @since 2.15.0
+       */
+      createSeparator() {
+        const separator = new SeparatorView({
+          model: this.model,
+          // hovering over one separator should highlight them all
+          mouseEnterCallback: () =>
+            this.separators.forEach((sep) => sep.highlight()),
+          mouseOutCallback: () =>
+            this.separators.forEach((sep) => sep.unhighlight()),
+        });
+        separator.render();
+        this.separators = this.separators || [];
+        this.separators.push(separator);
+        return separator;
+      },
+
+      /**
+       * Show an error message if the user has selected an invalid value
+       * @since 2.31.0
+       */
+      checkForInvalidSelections() {
+        const view = this;
+        const invalidSelections = view.model.hasInvalidSelections();
+        if (invalidSelections) {
+          view.showInvalidSelectionError(invalidSelections);
+        } else {
+          view.removeMessages();
+        }
+      },
+
+      /**
+       * Create the label for the search select interface
+       * @returns {HTMLElement|null} The label element, or null if no label is
+       * specified.
+       * @since 2.31.0
+       */
+      createLabel() {
+        const inputLabel = this.model.get("inputLabel");
+        if (!inputLabel) return null;
+        const inputEl = document.createElement("label");
+        inputEl.classList.add(...CLASS_NAMES.inputLabel);
+        inputEl.textContent = inputLabel;
+        return inputEl;
+      },
+
+      /**
+       * Create the container for the select interface
+       * @returns {HTMLElement} The select container element
+       * @since 2.31.0
+       */
+      createSelectContainer() {
+        const dropdownEl = document.createElement("div");
+        let classesToAdd = [
+          Semantic.CLASS_NAMES.base,
+          Semantic.CLASS_NAMES.dropdown.dropdown,
+          Semantic.CLASS_NAMES.dropdown.search,
+          this.model.get("allowMulti")
+            ? Semantic.CLASS_NAMES.dropdown.multiple
+            : null,
+          this.model.get("fluid")
+            ? Semantic.CLASS_NAMES.variations.fluid
+            : null,
+          this.model.get("buttonStyle") ? CLASS_NAMES.buttonStyle : null,
+          this.model.get("icon") ? Semantic.CLASS_NAMES.dropdown.icon : null,
+          this.model.get("icon") ? CLASS_NAMES.labeled : null,
+          this.model.get("icon")
+            ? null
+            : Semantic.CLASS_NAMES.dropdown.selection,
+        ];
+
+        classesToAdd = classesToAdd.filter(Boolean);
+        classesToAdd = classesToAdd.map((c) => c.split(" ")).flat();
+
+        dropdownEl.classList.add(...classesToAdd);
+
+        if (this.model.get("compact")) {
+          this.el.classList.add(CLASS_NAMES.compact);
+        }
+
+        return dropdownEl;
+      },
+
+      /**
+       * Create the hidden input element that will store the selected values
+       * @returns {HTMLElement} The input element
+       * @since 2.31.0
+       */
+      createInput() {
+        const inputEl = document.createElement("input");
+        inputEl.name = `search-select-${this.cid}`;
+        inputEl.type = "hidden";
+        return inputEl;
+      },
+
+      /**
+       * Create the icon element for the select interface
+       * @returns {HTMLElement} The icon element
+       * @since 2.31.0
+       */
+      createIcon() {
+        let icon = this.model.get("icon");
+        icon = icon ? `icon-${icon}` : "dropdown";
+        const iconEl = document.createElement("i");
+        iconEl.classList.add("icon", icon);
+        return iconEl;
+      },
+
+      /**
+       * Create the placeholder element for the select interface
+       * @returns {HTMLElement} The placeholder element
+       * @since 2.31.0
+       */
+      createPlaceholder() {
+        const placeholder = this.model.get("placeholderText");
+        const placeholderEl = document.createElement("span");
+        placeholderEl.classList.add(...CLASS_NAMES.placeholder);
+        placeholderEl.textContent = placeholder;
+        return placeholderEl;
+      },
+
+      /**
+       * Create the dropdown menu for the select interface
+       * @returns {OptionsView} The dropdown menu
+       * @since 2.31.0
+       */
+      createMenu() {
+        const menu = new OptionsView({
+          collection: this.model.get("options"),
+          tooltipOptions: this.tooltipSettings,
+          mode: this.model.get("submenuStyle"),
+        });
+        menu.render();
+        return menu;
+      },
+
+      /**
+       * Convert the submenu style to the style set in the model
+       * @param {boolean} [force] Set to true to force the view to update
+       * @since 2.31.0
+       */
+      updateMenuMode(force = false) {
+        const mode = this.model.get("submenuStyle");
+        this.menu.updateMode(mode, force);
+      },
+
+      /**
+       * Show a message indicated that some of the selected values are not valid
+       * choices.
+       * @param {string[]} opts The values that are not valid choices
+       */
+      showInvalidSelectionError(opts) {
+        let msg = "";
+        if (opts?.length) {
+          msg += opts.join(", ");
+          if (opts.length > 1) {
+            msg += " are not valid options. ";
+          } else {
+            msg += " is not a valid option. ";
+          }
+        }
+
+        msg += "Please select from the available options.";
+
+        this.showMessage(msg, "error", true);
+      },
+
+      /**
+       * Get the option model given a dropdown text or label element. Label
+       * elements are used for multi-select dropdowns, the value is a data
+       * attribute. Text elements are for single-select dropdowns, so the value
+       * is the current selection.
+       * @param {HTMLElement} el The text or label element
+       * @returns {SearchSelectOption|null} The option model or null if not
+       * found
+       * @since 2.31.0
+       */
+      optionFromSelectionEl(el) {
+        if (!el) return null;
+        const value =
+          $(el).data("value") || this.$selectUI.dropdown("get value");
+        if (!value && value !== 0) return null;
+        return this.model.get("options").getOptionByLabelOrValue(value);
+      },
+
+      /**
+       * Create HTML for a tooltip for a given option. By default this method
+       * returns the description of the option, but can be overridden in
+       * extended SearchSelectViews to return a custom HTML string based on
+       * the option.
+       * @param {SearchSelectOption} option The option to create a tooltip for
+       * @param {JQuery} _$element The element to attach the tooltip to
+       * @returns {string|null} An HTML string to use for the content of the
+       * tooltip.
+       * @since 2.31.0
+       */
+      tooltipHTML(option, _$element) {
+        return option?.get("description") || null;
+      },
+
+      /**
+       * Add a tooltip to a given element using the description in the options
+       * object that's set on the view.
+       * @param  {HTMLElement} element The HTML element a tooltip should be
+       * added
+       * @param  {object} settings Additional settings to override those set in
+       * view.tooltipSettings.
+       */
+      addTooltip(element, settings) {
+        // Tooltips are disabled when tooltipSettings is false
+        const viewSettings = this.tooltipSettings;
+        if (!viewSettings) return;
+
+        const $element = $(element);
+        const opt = this.optionFromSelectionEl(element);
+        const html = this.tooltipHTML(opt, $element);
+        if (!html) return;
+
+        $element.popup({
+          html,
+          ...viewSettings,
+          ...settings,
+        });
+      },
+
+      /** Visually indicate that the select interface is enabled */
+      enable() {
+        this.enabled = true;
+        this.$selectUI.removeClass(Semantic.CLASS_NAMES.dropdown.disabled);
+      },
+
+      /** Visually indicate that the select interface is inactive */
+      inactivate() {
+        this.enabled = false;
+        this.$selectUI.addClass(Semantic.CLASS_NAMES.dropdown.disabled);
+      },
+
+      /**
+       * Show an error, warning, or informational message, and highlight the
+       * select interface in an appropriate colour.
+       * @param  {string} message The message to display. Use an empty string to
+       * only highlight the select interface without showing any message text.
+       * @param  {string} type one of "error", "warning", or "info"
+       * @param  {boolean} removeOnChange set to true to remove the message as
+       * soon as the user changes the selection
+       */
+      showMessage(message, type = "info", removeOnChange = true) {
+        if (!this.$selectUI) return;
+
+        let level = typeof type === "string" ? type.toLowerCase() : "info";
+        if (!Object.keys(MESSAGE_TYPES).includes(level)) {
+          level = "info";
+        }
+
+        this.removeMessages();
+        this.$selectUI.addClass(MESSAGE_TYPES[level].selectUIClass);
+
+        if (message && message.length && typeof message === "string") {
+          this.message = $(
+            `<p style='margin:0.2rem' class='${MESSAGE_TYPES[level].messageClass}'><small>${message}</small></p>`,
+          );
+        }
+
+        this.$el.append(this.message);
+
+        if (removeOnChange) {
+          this.listenToOnce(this.model, "change:selected", this.removeMessages);
+        }
+      },
+
+      /** Remove all messages and classes set by the showMessage function */
+      removeMessages() {
+        if (!this.$selectUI) {
+          return;
+        }
+        const classes = Object.values(MESSAGE_TYPES).map(
+          (type) => type.selectUIClass,
+        );
+        this.$selectUI.removeClass(classes.join(" "));
+        if (this.message) this.message.remove();
+      },
+
+      /** Visually indicate that dropdown options are loading */
+      showLoading() {
+        this.$selectUI.addClass(Semantic.CLASS_NAMES.dropdown.loading);
+      },
+
+      /** Remove the loading spinner set by the showLoading */
+      hideLoading() {
+        this.$selectUI.removeClass(Semantic.CLASS_NAMES.dropdown.loading);
+      },
+
+      /**
+       * Remove the selected values from the dropdown interface
+       * and from the model.
+       * @param {boolean} [silent] Set to true to prevent the dropdown and the
+       * model from triggering change events
+       * @param {boolean} [closeMenu] Set to true to close the dropdown menu
+       * @since 2.31.0
+       */
+      reset(silent = false, closeMenu = true) {
+        this.$selectUI.dropdown("clear", silent);
+        this.model.set("selected", [], { silent });
+        if (closeMenu) this.$selectUI.dropdown("hide");
+      },
+    },
+  );
+
+  return SearchSelectView;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_searchSelect_SeparatorView.js.html b/docs/docs/src_js_views_searchSelect_SeparatorView.js.html new file mode 100644 index 000000000..c422cff41 --- /dev/null +++ b/docs/docs/src_js_views_searchSelect_SeparatorView.js.html @@ -0,0 +1,237 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/searchSelect/SeparatorView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/searchSelect/SeparatorView.js

+ + + + + + +
+
+
"use strict";
+
+define(["backbone", "semantic"], (Backbone, _Semantic) => {
+  // Default class names for the separator element
+  const BASE_CLASS = "separator";
+  const CLASS_NAMES = {
+    highlighted: `${BASE_CLASS}--hover`,
+  };
+
+  /**
+   * @class SeparatorView
+   * @classdesc Text that separates selected terms in a search select dropdown,
+   * such as "AND" or "OR". These may be used to represent boolean operators in
+   * a search query. The separator can be clicked to toggle between possible
+   * values set in the SearchSelect model.
+   * @classcategory Views/SearchSelect
+   * @augments Backbone.View
+   * @class
+   * @since 2.31.0
+   * @screenshot views/searchSelect/SeparatorView.png
+   */
+  const SeparatorView = Backbone.View.extend(
+    /** @lends SeparatorView.prototype */
+    {
+      /** @inheritdoc */
+      type: "SeparatorView",
+
+      /** @inheritdoc */
+      className: BASE_CLASS,
+
+      /** @inheritdoc */
+      tagName: "span",
+
+      /**
+       * Settings is passed to the Formantic UI popup module to configure a
+       * tooltip shown when the user hovers over the separator. Set to `false`
+       * to disable tooltips.
+       * @see https://fomantic-ui.com/modules/popup.html#/settings
+       * @type {object|boolean}
+       */
+      tooltipSettings: {
+        content: "Click to switch the operator",
+        variation: "mini inverted",
+        delay: {
+          show: 400,
+          hide: 40,
+        },
+      },
+
+      /**
+       * Callback function to run when the user hovers. If not set, the default
+       * behavior is to highlight the separator.
+       * @type {Function}
+       */
+      mouseEnterCallback: null,
+
+      /**
+       * Callback function to run when the user stops hovering. If not set, the
+       * default behavior is to unhighlight the separator.
+       * @type {Function}
+       */
+      mouseOutCallback: null,
+
+      /** @inheritdoc */
+      initialize(opts) {
+        // Set all the options on the view
+        Object.keys(opts).forEach((key) => {
+          this[key] = opts[key];
+        });
+        // Default to highlighting the separator on hover
+        if (!this.mouseEnterCallback && !this.mouseOutCallback) {
+          this.mouseEnterCallback = this.highlight;
+          this.mouseOutCallback = this.unhighlight;
+        }
+      },
+
+      /** @inheritdoc */
+      render() {
+        const view = this;
+        view.setText();
+
+        if (view.model.canChangeSeparator()) {
+          view.activate();
+        }
+
+        return this;
+      },
+
+      /** Update the text of the separator element to match the model */
+      setText() {
+        this.$el.text(this.model.get("separator"));
+      },
+
+      /**
+       * Add event listeners to the element to allow the user to change the
+       * separator text by clicking on it. Add visual indicators to show that
+       * the separator is clickable.
+       */
+      activate() {
+        const view = this;
+        const { $el } = this;
+
+        view.deactivate();
+
+        view.addTooltip();
+        $el.css("cursor", "pointer");
+
+        // Update the model when the separator is clicked, and update the text
+        // in the view when the model changes (the model may be changed by other
+        // views)
+        view.listenTo(view.model, "change:separator", view.updateText);
+        $el.on("click", () => {
+          view.model.setNextSeparator();
+        });
+
+        $el.on("mouseenter", () => {
+          if (view.mouseEnterCallback) {
+            view.mouseEnterCallback.call(view);
+          }
+        });
+        $el.on("mouseout", () => {
+          if (view.mouseOutCallback) {
+            view.mouseOutCallback.call(view);
+          }
+        });
+      },
+
+      /** Remove event listeners and visual indicators */
+      deactivate() {
+        this.$el.css("cursor", "default");
+        this.$el.off("click mouseenter mouseout");
+        this.stopListening(this.model);
+      },
+
+      /** Create and attach a tooltip */
+      addTooltip() {
+        const settings = this.tooltipSettings;
+        if (!settings) return;
+        this.$el.popup(settings);
+      },
+
+      /** Visually emphasize the separator */
+      highlight() {
+        this.$el.addClass(CLASS_NAMES.highlighted);
+      },
+
+      /** Visually de-emphasize the separator */
+      unhighlight() {
+        this.$el.removeClass(CLASS_NAMES.highlighted);
+      },
+
+      /** Update the text shown in the separator element */
+      updateText() {
+        const view = this;
+        const text = this.model.get("separator");
+        if (!text) return;
+        this.$el.transition({
+          animation: "pulse",
+          displayType: "inline-block",
+          duration: "250ms",
+          onComplete: () => {
+            view.setText();
+          },
+        });
+      },
+
+      /** @inheritdoc */
+      remove() {
+        this.deactivate();
+        Backbone.View.prototype.remove.call(this);
+      },
+    },
+  );
+
+  return SeparatorView;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_searchSelect_SolrAutocompleteView.js.html b/docs/docs/src_js_views_searchSelect_SolrAutocompleteView.js.html new file mode 100644 index 000000000..ca0cf3156 --- /dev/null +++ b/docs/docs/src_js_views_searchSelect_SolrAutocompleteView.js.html @@ -0,0 +1,96 @@ + + + + + MetacatUI Dev Docs: Source: src/js/views/searchSelect/SolrAutocompleteView.js + + + + + + + + + + + + + + +
+ +

Source: src/js/views/searchSelect/SolrAutocompleteView.js

+ + + + + + +
+
+
define([
+  "underscore",
+  "views/searchSelect/SearchSelectView",
+  "models/searchSelect/SolrAutocomplete",
+], (_, SearchSelect, SolrAutocomplete) => {
+  /**
+   * @class
+   * @classdesc
+   * @classcategory Views/SearchSelect
+   * @augments SearchSelect
+   * @class
+   * @since 2.31.0
+   * @screenshot views/searchSelect/SolrAutocompleteView.png
+   */
+  const SolrAutocompleteView = SearchSelect.extend(
+    /** @lends SolrAutocompleteView.prototype */
+    {
+      /** @inheritdoc */
+      type: "SolrAutocomplete",
+
+      /** @inheritdoc */
+      className: `${SearchSelect.prototype.className} solr-autocomplete`,
+
+      /** @inheritdoc */
+      ModelType: SolrAutocomplete,
+
+      /**
+       * The name of the field in the Solr schema that the user is searching.
+       * @type {string}
+       */
+      queryField: "",
+    },
+  );
+  return SolrAutocompleteView;
+});
+
+
+
+ + + + +
+ +
+ + + + + diff --git a/docs/docs/src_js_views_search_CatalogSearchView.js.html b/docs/docs/src_js_views_search_CatalogSearchView.js.html index 25740a041..cba3bbed4 100644 --- a/docs/docs/src_js_views_search_CatalogSearchView.js.html +++ b/docs/docs/src_js_views_search_CatalogSearchView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_search_SearchResultView.js.html b/docs/docs/src_js_views_search_SearchResultView.js.html index 42124059e..557a5a380 100644 --- a/docs/docs/src_js_views_search_SearchResultView.js.html +++ b/docs/docs/src_js_views_search_SearchResultView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_search_SearchResultsPagerView.js.html b/docs/docs/src_js_views_search_SearchResultsPagerView.js.html index 11678c9f7..2d8fa3eb8 100644 --- a/docs/docs/src_js_views_search_SearchResultsPagerView.js.html +++ b/docs/docs/src_js_views_search_SearchResultsPagerView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_search_SearchResultsView.js.html b/docs/docs/src_js_views_search_SearchResultsView.js.html index 9a9d5020d..d90c2f918 100644 --- a/docs/docs/src_js_views_search_SearchResultsView.js.html +++ b/docs/docs/src_js_views_search_SearchResultsView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_js_views_search_SorterView.js.html b/docs/docs/src_js_views_search_SorterView.js.html index 5e4c5c819..34c37d810 100644 --- a/docs/docs/src_js_views_search_SorterView.js.html +++ b/docs/docs/src_js_views_search_SorterView.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/docs/src_loader.js.html b/docs/docs/src_loader.js.html index 44847cd1f..985e80be7 100644 --- a/docs/docs/src_loader.js.html +++ b/docs/docs/src_loader.js.html @@ -30,7 +30,7 @@ -

Namespaces

Classes

Global

+

Namespaces

Classes

Global

diff --git a/docs/index.md b/docs/index.md index 7847e30e3..5d4cd0f33 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,7 +24,7 @@ MetacatUI is an open source, community project. We [welcome contributions](https Cite this software as: -> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.30.0). Arctic Data Center. [doi:10.18739/A2SJ19S83](https://doi.org/10.18739/A2SJ19S83) +> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.31.0). Arctic Data Center. [doi:10.18739/A2SJ19S83](https://doi.org/10.18739/A2SJ19S83) ## Related Projects diff --git a/package.json b/package.json index ac36ca790..bf1653711 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metacatui", - "version": "2.30.0", + "version": "2.31.0", "description": "MetacatUI: A client-side web interface for DataONE data repositories", "main": "server.js", "dependencies": { diff --git a/src/index.html b/src/index.html index e6e240de8..3f5513cfc 100644 --- a/src/index.html +++ b/src/index.html @@ -44,7 +44,7 @@ //Create the MetacatUI object var MetacatUI = {}; - MetacatUI.metacatUIVersion = "2.30.0"; + MetacatUI.metacatUIVersion = "2.31.0"; //Catch errors when the config or loader file fails to load. // These are mainly helpful for developers/operators installing MetacatUI diff --git a/src/js/collections/ontologies/BioontologyResults.js b/src/js/collections/ontologies/BioontologyResults.js index 482828f1a..76588167a 100644 --- a/src/js/collections/ontologies/BioontologyResults.js +++ b/src/js/collections/ontologies/BioontologyResults.js @@ -20,7 +20,7 @@ define([ * @class BioontologyResults * @classcategory Collections/Ontologies * @augments Backbone.Collection - * @since 0.0.0 + * @since 2.31.0 * @class */ const BioontologyResults = Backbone.Collection.extend( diff --git a/src/js/collections/searchSelect/SearchSelectOptions.js b/src/js/collections/searchSelect/SearchSelectOptions.js index c03de7c7b..f89a47856 100644 --- a/src/js/collections/searchSelect/SearchSelectOptions.js +++ b/src/js/collections/searchSelect/SearchSelectOptions.js @@ -9,7 +9,7 @@ define(["backbone", "models/searchSelect/SearchSelectOption"], ( * @classdesc A collection for managing dropdown options in a search * select view. * @classcategory Collections/SearchSelect - * @since 0.0.0 + * @since 2.31.0 */ const SearchSelectOptions = Backbone.Collection.extend({ /** @lends SearchSelectOptions.prototype */ diff --git a/src/js/common/Semantic.js b/src/js/common/Semantic.js index 51a1787e9..3e81e067d 100644 --- a/src/js/common/Semantic.js +++ b/src/js/common/Semantic.js @@ -5,7 +5,7 @@ * imported, the Semantic UI library is available globally and the CSS is added to * the page. e.g. you can use `$('.ui.dropdown').dropdown()` in your code. * See usage docs at https://semantic-ui.com/introduction/getting-started.html - * @since 0.0.0 + * @since 2.31.0 */ define([ `jquery`, diff --git a/src/js/common/Utilities.js b/src/js/common/Utilities.js index c1ac81aaa..49d935719 100644 --- a/src/js/common/Utilities.js +++ b/src/js/common/Utilities.js @@ -167,7 +167,7 @@ define([], () => { * @param {object} a - The first object to compare * @param {object} b - The second object to compare * @returns {boolean} True if the objects are deeply equal - * @since 0.0.0 + * @since 2.31.0 */ deepEqual(a, b) { if (a === b) return true; @@ -203,7 +203,7 @@ define([], () => { * @param {Backbone.Model} model - The model to remove defaults from * @param {string[]} [removeProps] - An array of additional properties to remove from the model * @returns {object} The JSON representation of the model with defaults removed - * @since 0.0.0 + * @since 2.31.0 */ toJSONWithoutDefaults(model, removeProps = []) { const json = model.toJSON(); diff --git a/src/js/models/AppModel.js b/src/js/models/AppModel.js index b2f8ff95f..d5af3c6c3 100644 --- a/src/js/models/AppModel.js +++ b/src/js/models/AppModel.js @@ -2101,7 +2101,7 @@ define(["jquery", "underscore", "backbone"], function ($, _, Backbone) { /** * The Bioportal REST API URL, which is set dynamically only if a bioportalAPIKey is configured * @type {string} - * @deprecated since 0.0.0 + * @deprecated since 2.31.0 */ bioportalSearchUrl: "https://data.bioontology.org/search", /** @@ -2109,7 +2109,7 @@ define(["jquery", "underscore", "backbone"], function ($, _, Backbone) { * @see {@link https://data.bioontology.org/documentation} * @type {string} * @default "https://data.bioontology.org" - * @since 0.0.0 + * @since 2.31.0 */ bioportalApiBaseUrl: "https://data.bioontology.org", /** @@ -2132,7 +2132,7 @@ define(["jquery", "underscore", "backbone"], function ($, _, Backbone) { * class. For the full list of possible ontologies, see the Bioportal * website: https://bioportal.bioontology.org/ontologies * @type {Array.<{label: string, ontology: string, subTree: string, icon: string}>} - * @since 0.0.0 + * @since 2.31.0 */ bioportalOntologies: [ { diff --git a/src/js/models/accordion/Accordion.js b/src/js/models/accordion/Accordion.js index 33b7eb534..04cc84820 100644 --- a/src/js/models/accordion/Accordion.js +++ b/src/js/models/accordion/Accordion.js @@ -9,7 +9,7 @@ define(["backbone", "models/accordion/AccordionItem"], ( * @augments Backbone.Model * @constructs * @augments Backbone.Model - * @since 0.0.0 + * @since 2.31.0 */ const Accordion = Backbone.Model.extend( /** @lends Accordion.prototype */ diff --git a/src/js/models/accordion/AccordionItem.js b/src/js/models/accordion/AccordionItem.js index d3040cb3f..80db8a593 100644 --- a/src/js/models/accordion/AccordionItem.js +++ b/src/js/models/accordion/AccordionItem.js @@ -6,7 +6,7 @@ define(["backbone"], (Backbone) => { * @classcategory Models/Accordion * @augments Backbone.Model * @constructs - * @since 0.0.0 + * @since 2.31.0 */ const AccordionItem = Backbone.Model.extend( /** @lends AccordionItem.prototype */ diff --git a/src/js/models/connectors/Bioontology-Accordion-SearchSelect.js b/src/js/models/connectors/Bioontology-Accordion-SearchSelect.js index 3dbd483bd..9f4245126 100644 --- a/src/js/models/connectors/Bioontology-Accordion-SearchSelect.js +++ b/src/js/models/connectors/Bioontology-Accordion-SearchSelect.js @@ -18,7 +18,7 @@ define([ * @augments Backbone.Model * @class * @classcategory Models/Connectors - * @since 0.0.0 + * @since 2.31.0 */ Backbone.Model.extend( /** @lends BioontologyAccordionSearchSelect.prototype */ { diff --git a/src/js/models/ontologies/Bioontology.js b/src/js/models/ontologies/Bioontology.js index d14d3d414..263a665da 100644 --- a/src/js/models/ontologies/Bioontology.js +++ b/src/js/models/ontologies/Bioontology.js @@ -9,7 +9,7 @@ define(["backbone", "collections/ontologies/BioontologyResults"], ( * @classdesc A model that fetches data from the BioPortal API for a given * ontology. * @classcategory Models/Ontologies - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const Bioontology = Backbone.Model.extend({ diff --git a/src/js/models/ontologies/BioontologyBatch.js b/src/js/models/ontologies/BioontologyBatch.js index 917d6bd8c..767c1b2d3 100644 --- a/src/js/models/ontologies/BioontologyBatch.js +++ b/src/js/models/ontologies/BioontologyBatch.js @@ -10,7 +10,7 @@ define(["backbone", "collections/ontologies/BioontologyResults"], ( * endpoint. This can be used to store data about classes that have been * fetched from BioPortal, and to fetch additional classes as needed. * @classcategory Models/Ontologies - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const BioontologyBatch = Backbone.Model.extend({ diff --git a/src/js/models/ontologies/BioontologyClass.js b/src/js/models/ontologies/BioontologyClass.js index 15f13540d..9a425e6a0 100644 --- a/src/js/models/ontologies/BioontologyClass.js +++ b/src/js/models/ontologies/BioontologyClass.js @@ -7,7 +7,7 @@ define(["backbone"], (Backbone) => { * BioPortal API. All attributes not documented here are detailed on the * BioPortal API docs: https://data.bioontology.org/documentation. * @classcategory Models/Ontologies - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const BioontologyClass = Backbone.Model.extend({ diff --git a/src/js/models/ontologies/BioontologyOntology.js b/src/js/models/ontologies/BioontologyOntology.js index 4396c1063..d03013f88 100644 --- a/src/js/models/ontologies/BioontologyOntology.js +++ b/src/js/models/ontologies/BioontologyOntology.js @@ -6,7 +6,7 @@ define(["backbone"], (Backbone) => { * @classdesc This model represents an ontology from the BioPortal API, see * https://data.bioontology.org/documentation#Ontology * @classcategory Models/Ontologies - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const BioOntology = Backbone.Model.extend({ diff --git a/src/js/models/searchSelect/AccountSearchSelect.js b/src/js/models/searchSelect/AccountSearchSelect.js index 97dbcf95b..eecbf4a8e 100644 --- a/src/js/models/searchSelect/AccountSearchSelect.js +++ b/src/js/models/searchSelect/AccountSearchSelect.js @@ -9,7 +9,7 @@ define(["models/searchSelect/SearchSelect", "models/LookupModel"], ( * @classdesc An extension of SearchSelect that sets the options to the query * fields (e.g. Solr fields) available for searching. * @classcategory Models/SearchSelect - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const AccountSearchSelect = SearchSelect.extend({ diff --git a/src/js/models/searchSelect/QueryFieldSearchSelect.js b/src/js/models/searchSelect/QueryFieldSearchSelect.js index 92ec8475c..f8eca18cc 100644 --- a/src/js/models/searchSelect/QueryFieldSearchSelect.js +++ b/src/js/models/searchSelect/QueryFieldSearchSelect.js @@ -9,7 +9,7 @@ define([ * @classdesc An extension of SearchSelect that sets the options to the query * fields (e.g. Solr fields) available for searching. * @classcategory Models/SearchSelect - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const QueryFieldSearchSelect = SearchSelect.extend({ diff --git a/src/js/models/searchSelect/SearchSelect.js b/src/js/models/searchSelect/SearchSelect.js index 6d2155f58..8feae0a68 100644 --- a/src/js/models/searchSelect/SearchSelect.js +++ b/src/js/models/searchSelect/SearchSelect.js @@ -9,7 +9,7 @@ define(["backbone", "collections/searchSelect/SearchSelectOptions"], ( * @classdesc A model for managing dropdown options and state for a search * select component. * @classcategory Models/SearchSelect - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const SearchSelect = Backbone.Model.extend({ diff --git a/src/js/models/searchSelect/SearchSelectOption.js b/src/js/models/searchSelect/SearchSelectOption.js index dbff87f32..62d94b14e 100644 --- a/src/js/models/searchSelect/SearchSelectOption.js +++ b/src/js/models/searchSelect/SearchSelectOption.js @@ -5,7 +5,7 @@ define(["backbone"], (Backbone) => { * @class SelectOptionModel * @classdesc A model for representing an option in a search select dropdown. * @classcategory Models/SearchSelect - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const SearchSelectOption = Backbone.Model.extend({ diff --git a/src/js/models/searchSelect/SolrAutocomplete.js b/src/js/models/searchSelect/SolrAutocomplete.js index 30de88518..4062e402e 100644 --- a/src/js/models/searchSelect/SolrAutocomplete.js +++ b/src/js/models/searchSelect/SolrAutocomplete.js @@ -9,7 +9,7 @@ define(["models/searchSelect/SearchSelect", "collections/SolrResults"], ( * @classdesc An extension of SearchSelect that limits the options to the * available values within a given Solr field. * @classcategory Models/SearchSelect - * @since 0.0.0 + * @since 2.31.0 * @augments Backbone.Model */ const SolrAutocomplete = SearchSelect.extend({ diff --git a/src/js/views/MdqRunView.js b/src/js/views/MdqRunView.js index 63a9708c8..08436cf17 100644 --- a/src/js/views/MdqRunView.js +++ b/src/js/views/MdqRunView.js @@ -246,7 +246,7 @@ define([ /** * Add the check result item els to the view * @param {object} groupedResults - The results grouped by status - * @since 0.0.0 + * @since 2.31.0 */ async addCheckItems(groupedResults) { const viewRef = this; @@ -299,7 +299,7 @@ define([ * @param {string} className - The class name for the check item * @param {string} iconClass - The class * @returns {string} The HTML for the check item - * @since 0.0.0 + * @since 2.31.0 */ async createCheckItem(result, className, iconClass) { const outputs = await this.getOutputHTML(result.get("output")); diff --git a/src/js/views/accordion/AccordionItemView.js b/src/js/views/accordion/AccordionItemView.js index 9d09f75f9..1c5f42fb7 100644 --- a/src/js/views/accordion/AccordionItemView.js +++ b/src/js/views/accordion/AccordionItemView.js @@ -13,7 +13,7 @@ define(["jquery", "backbone", "semantic", "models/accordion/AccordionItem"], ( * @classcategory Views/Accordion * @augments Backbone.View * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/accordion/AccordionItemViewView.png */ const AccordionItemView = Backbone.View.extend( diff --git a/src/js/views/accordion/AccordionView.js b/src/js/views/accordion/AccordionView.js index df159e87e..56d4c2159 100644 --- a/src/js/views/accordion/AccordionView.js +++ b/src/js/views/accordion/AccordionView.js @@ -16,7 +16,7 @@ define([ * @classcategory Views/Accordion * @augments Backbone.View * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/accordion/AccordionView.png */ const AccordionView = Backbone.View.extend( diff --git a/src/js/views/filters/SemanticFilterView.js b/src/js/views/filters/SemanticFilterView.js index be5725c9e..dcc8d9ee7 100644 --- a/src/js/views/filters/SemanticFilterView.js +++ b/src/js/views/filters/SemanticFilterView.js @@ -23,7 +23,7 @@ define([ /** * The ontologies to search for terms in. * @type {Array.<{label: string, ontology: string, subTree: string}>} - * @since 0.0.0 + * @since 2.31.0 */ ontologies: MetacatUI.appModel.get("bioportalOntologies"), @@ -35,7 +35,7 @@ define([ * @param {object} [options] - The options to initialize the view with * @param {Array.<{label: string, ontology: string, subTree: string}>} [options.ontologies] * - The ontologies to search for terms in - * @since 0.0.0 + * @since 2.31.0 */ initialize(options = {}) { if (options?.ontologies) this.ontologies = options.ontologies; @@ -73,7 +73,7 @@ define([ * Update the filter model when a class is selected in the * BioontologySelectView. Clear the selection/search input from the * SelectView and collapse the menu. - * @since 0.0.0 + * @since 2.31.0 */ onSubViewSelection() { const view = this; diff --git a/src/js/views/ontologies/BioontologyBrowserView.js b/src/js/views/ontologies/BioontologyBrowserView.js index d105f2dc3..31f84c280 100644 --- a/src/js/views/ontologies/BioontologyBrowserView.js +++ b/src/js/views/ontologies/BioontologyBrowserView.js @@ -36,7 +36,7 @@ define([ * @classdesc An interface to browser BioPortal ontologies and classes * @classcategory Views/Ontologies * @augments Backbone.View - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/ontologies/BioontologyBrowserView.png */ const BioontologyBrowser = Backbone.View.extend( diff --git a/src/js/views/searchSelect/AnnotationFilterView.js b/src/js/views/searchSelect/AnnotationFilterView.js index 16e2b988b..83199f12d 100644 --- a/src/js/views/searchSelect/AnnotationFilterView.js +++ b/src/js/views/searchSelect/AnnotationFilterView.js @@ -13,7 +13,7 @@ define(["jquery", "underscore", "backbone", "bioportal"], function ( * @constructor * @since 2.14.0 * @screenshot views/searchSelect/AnnotationFilterView.png - * @deprecated since 0.0.0 + * @deprecated since 2.30.0 */ return Backbone.View.extend( /** @lends AnnotationFilterView.prototype */ diff --git a/src/js/views/searchSelect/BioontologySelectView.js b/src/js/views/searchSelect/BioontologySelectView.js index 0f0888348..cdaa56aea 100644 --- a/src/js/views/searchSelect/BioontologySelectView.js +++ b/src/js/views/searchSelect/BioontologySelectView.js @@ -41,7 +41,7 @@ define([ * view can be configured to show class labels from multiple ontologies. * @classcategory Views/SearchSelect * @augments SearchSelect - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/searchSelect/BioontologySelectView.png */ return SolrAutocompleteView.extend( @@ -72,7 +72,7 @@ define([ * "label" and a "ontology" (acronym) property. Optionally, a "subTree" * property can be provided to search a specific sub-tree of the ontology. * @type {Array.<{label: string, ontology: string, subTree: string}>} - * @since 0.0.0 + * @since 2.31.0 */ ontologies: MetacatUI.appModel.get("bioportalOntologies"), diff --git a/src/js/views/searchSelect/NodeSelectView.js b/src/js/views/searchSelect/NodeSelectView.js index 31a89d52a..4facc66b0 100644 --- a/src/js/views/searchSelect/NodeSelectView.js +++ b/src/js/views/searchSelect/NodeSelectView.js @@ -41,7 +41,7 @@ define(["views/searchSelect/SearchSelectView", "models/NodeModel"], ( * Fetch the member nodes from the NodeModel and convert them to options * for the searchSelect component. * @returns {object[]} An array of objects representing the member nodes - * @since 0.0.0 + * @since 2.31.0 */ getNodeOptions() { if (!MetacatUI.nodeModel) MetacatUI.nodeModel = new NodeModel(); diff --git a/src/js/views/searchSelect/ObjectFormatSelectView.js b/src/js/views/searchSelect/ObjectFormatSelectView.js index 2815ee3c4..60e127c45 100644 --- a/src/js/views/searchSelect/ObjectFormatSelectView.js +++ b/src/js/views/searchSelect/ObjectFormatSelectView.js @@ -38,7 +38,7 @@ define(["views/searchSelect/SearchSelectView", "collections/ObjectFormats"], ( /** * Fetch the object formats from the DataONE API and update the * select options on the model - * @since 0.0.0 + * @since 2.31.0 */ getObjectFormats() { const view = this; diff --git a/src/js/views/searchSelect/SearchSelectHeaderView.js b/src/js/views/searchSelect/SearchSelectHeaderView.js index 3317f9880..0d9d3e44b 100644 --- a/src/js/views/searchSelect/SearchSelectHeaderView.js +++ b/src/js/views/searchSelect/SearchSelectHeaderView.js @@ -23,7 +23,7 @@ define(["backbone", "semantic"], (Backbone, Semantic) => { * @classcategory Views/SearchSelect * @augments SearchSelect * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/searchSelect/SearchSelectHeaderView.png */ return Backbone.View.extend( diff --git a/src/js/views/searchSelect/SearchSelectOptionView.js b/src/js/views/searchSelect/SearchSelectOptionView.js index 79427fec0..589fc37bc 100644 --- a/src/js/views/searchSelect/SearchSelectOptionView.js +++ b/src/js/views/searchSelect/SearchSelectOptionView.js @@ -17,7 +17,7 @@ define(["backbone", "semantic", "models/searchSelect/SearchSelectOption"], ( * @classcategory Views/SearchSelect * @augments SearchSelect * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/searchSelect/SearchSelectOptionView.png */ return Backbone.View.extend( diff --git a/src/js/views/searchSelect/SearchSelectOptionsView.js b/src/js/views/searchSelect/SearchSelectOptionsView.js index db6cebc44..f11240096 100644 --- a/src/js/views/searchSelect/SearchSelectOptionsView.js +++ b/src/js/views/searchSelect/SearchSelectOptionsView.js @@ -38,7 +38,7 @@ define([ * @classcategory Views/SearchSelect * @augments SearchSelect * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/searchSelect/SearchSelectOptionsView.png */ return Backbone.View.extend( diff --git a/src/js/views/searchSelect/SearchSelectView.js b/src/js/views/searchSelect/SearchSelectView.js index 5ff4792f2..88ef87fc9 100644 --- a/src/js/views/searchSelect/SearchSelectView.js +++ b/src/js/views/searchSelect/SearchSelectView.js @@ -81,7 +81,7 @@ define([ * The constructor function for the model that this view uses. Must be a * SearchSelect or an extension of it. * @type {Backbone.Model} - * @since 0.0.0 + * @since 2.31.0 */ ModelType: SearchSelect, @@ -92,7 +92,7 @@ define([ * configure the tooltip. Set to false to disable tooltips. * @see https://fomantic-ui.com/modules/popup.html#/settings * @type {object|boolean} - * @since 0.0.0 + * @since 2.31.0 */ tooltipSettings: { position: "top left", @@ -117,7 +117,7 @@ define([ * Split the options passed to the view into model and view attributes. * @param {object} options The options passed to the view * @returns {object} An object with two keys: modelAttrs and viewAttrs - * @since 0.0.0 + * @since 2.31.0 */ splitModelViewOptions(options) { const modelAttrNames = Object.keys(this.ModelType.prototype.defaults()); @@ -130,7 +130,7 @@ define([ * Create a new SearchSelect model and set it on the view. If a model * already exists, it will be destroyed. * @param {object} options The options to pass to the model - * @since 0.0.0 + * @since 2.31.0 */ createModel(options) { const modelAttrs = options || {}; @@ -226,7 +226,7 @@ define([ * click action on the dropdown input element. This function ensures that * the dropdown is shown when any part of the input is clicked, including * the selected text elements in a single-select dropdown. - * @since 0.0.0 + * @since 2.31.0 */ addClickToTexts() { const showMenu = () => { @@ -245,7 +245,7 @@ define([ * @param {boolean} [silent] Set to true to prevent the dropdown from * triggering a change event (an infinite loop can occur if this is not set, * as the dropdown will trigger a change event, which will update the model). - * @since 0.0.0 + * @since 2.31.0 */ showSelected(silent = false) { const enabledBefore = this.enabled; @@ -325,7 +325,7 @@ define([ /** * Update the view when certain model attributes change - * @since 0.0.0 + * @since 2.31.0 */ listenToModel() { this.stopListening(this.model); @@ -361,7 +361,7 @@ define([ /** * Listen to events from the select UI interface and update the model - * @since 0.0.0 + * @since 2.31.0 */ listenToSelectUI() { // Save the active search term in the model @@ -404,7 +404,7 @@ define([ /** * Show an error message if the user has selected an invalid value - * @since 0.0.0 + * @since 2.31.0 */ checkForInvalidSelections() { const view = this; @@ -420,7 +420,7 @@ define([ * Create the label for the search select interface * @returns {HTMLElement|null} The label element, or null if no label is * specified. - * @since 0.0.0 + * @since 2.31.0 */ createLabel() { const inputLabel = this.model.get("inputLabel"); @@ -434,7 +434,7 @@ define([ /** * Create the container for the select interface * @returns {HTMLElement} The select container element - * @since 0.0.0 + * @since 2.31.0 */ createSelectContainer() { const dropdownEl = document.createElement("div"); @@ -471,7 +471,7 @@ define([ /** * Create the hidden input element that will store the selected values * @returns {HTMLElement} The input element - * @since 0.0.0 + * @since 2.31.0 */ createInput() { const inputEl = document.createElement("input"); @@ -483,7 +483,7 @@ define([ /** * Create the icon element for the select interface * @returns {HTMLElement} The icon element - * @since 0.0.0 + * @since 2.31.0 */ createIcon() { let icon = this.model.get("icon"); @@ -496,7 +496,7 @@ define([ /** * Create the placeholder element for the select interface * @returns {HTMLElement} The placeholder element - * @since 0.0.0 + * @since 2.31.0 */ createPlaceholder() { const placeholder = this.model.get("placeholderText"); @@ -509,7 +509,7 @@ define([ /** * Create the dropdown menu for the select interface * @returns {OptionsView} The dropdown menu - * @since 0.0.0 + * @since 2.31.0 */ createMenu() { const menu = new OptionsView({ @@ -524,7 +524,7 @@ define([ /** * Convert the submenu style to the style set in the model * @param {boolean} [force] Set to true to force the view to update - * @since 0.0.0 + * @since 2.31.0 */ updateMenuMode(force = false) { const mode = this.model.get("submenuStyle"); @@ -560,7 +560,7 @@ define([ * @param {HTMLElement} el The text or label element * @returns {SearchSelectOption|null} The option model or null if not * found - * @since 0.0.0 + * @since 2.31.0 */ optionFromSelectionEl(el) { if (!el) return null; @@ -579,7 +579,7 @@ define([ * @param {JQuery} _$element The element to attach the tooltip to * @returns {string|null} An HTML string to use for the content of the * tooltip. - * @since 0.0.0 + * @since 2.31.0 */ tooltipHTML(option, _$element) { return option?.get("description") || null; @@ -683,7 +683,7 @@ define([ * @param {boolean} [silent] Set to true to prevent the dropdown and the * model from triggering change events * @param {boolean} [closeMenu] Set to true to close the dropdown menu - * @since 0.0.0 + * @since 2.31.0 */ reset(silent = false, closeMenu = true) { this.$selectUI.dropdown("clear", silent); diff --git a/src/js/views/searchSelect/SeparatorView.js b/src/js/views/searchSelect/SeparatorView.js index fc148c56c..aad59951c 100644 --- a/src/js/views/searchSelect/SeparatorView.js +++ b/src/js/views/searchSelect/SeparatorView.js @@ -16,7 +16,7 @@ define(["backbone", "semantic"], (Backbone, _Semantic) => { * @classcategory Views/SearchSelect * @augments Backbone.View * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/searchSelect/SeparatorView.png */ const SeparatorView = Backbone.View.extend( diff --git a/src/js/views/searchSelect/SolrAutocompleteView.js b/src/js/views/searchSelect/SolrAutocompleteView.js index 7d244600c..49a0644ce 100644 --- a/src/js/views/searchSelect/SolrAutocompleteView.js +++ b/src/js/views/searchSelect/SolrAutocompleteView.js @@ -9,7 +9,7 @@ define([ * @classcategory Views/SearchSelect * @augments SearchSelect * @class - * @since 0.0.0 + * @since 2.31.0 * @screenshot views/searchSelect/SolrAutocompleteView.png */ const SolrAutocompleteView = SearchSelect.extend(