diff --git a/demo/assets/location-list-metadata.json b/demo/assets/location-list-metadata.json new file mode 100644 index 00000000..9cbe665a --- /dev/null +++ b/demo/assets/location-list-metadata.json @@ -0,0 +1,12 @@ +[ + { + "id": "default-location-list", + "name": "Default Location List", + "path": "./assets/location-list.json" + }, + { + "id": "hospitals", + "name": "Hospitals", + "path": "./assets/locations/hospitals.json" + } +] diff --git a/demo/assets/locations/hospitals.json b/demo/assets/locations/hospitals.json new file mode 100755 index 00000000..18e85190 --- /dev/null +++ b/demo/assets/locations/hospitals.json @@ -0,0 +1,43 @@ +{ + "locationsLevels": ["ward", "clinic"], + "locations": { + "ward1": { + "id": "ward1", + "label": "ward 1", + "children": { + "clinic1": { + "id": "clinic1", + "label": "clinic 1", + "latitude": 44.46567, + "longitude": -73.21911 + }, + "clinic2": { + "id": "clinic2", + "label": "clinic 2", + "latitude": 44.45308, + "longitude": -73.19576 + } + } + }, + "ward2": { + "id": "ward2", + "label": "ward 2", + "children": { + "clinic3": { + "id": "clinic3", + "label": "clinic 3", + "latitude": 44.46567, + "longitude": -73.21911 + + }, + "clinic4": { + "id": "clinic4", + "label": "clinic 4", + "latitude": 44.46567, + "longitude": -73.21911 + + } + } + } + } +} diff --git a/demo/index.html b/demo/index.html index 79b309d1..c5091853 100644 --- a/demo/index.html +++ b/demo/index.html @@ -37,13 +37,17 @@ + - + + diff --git a/tangy-base-widget.js b/tangy-base-widget.js index b6239044..62935c0a 100644 --- a/tangy-base-widget.js +++ b/tangy-base-widget.js @@ -602,7 +602,7 @@ class TangyBaseWidget extends PolymerElement { return false; } - // ?? So we can do event listeners on dynamic items?? Could also make form components for things like . + // Use to add dynamic event listeners or make form components for things like . afterRenderEdit() {} /* @@ -917,6 +917,9 @@ class TangyBaseWidget extends PolymerElement { .querySelector("#container") .querySelector("tangy-form") .addEventListener("submit", (event) => this._onSubmit()); + + this.afterRenderEdit(); + } else if (this.mode === MODE_INFO) { this.shadowRoot.querySelector("#container").innerHTML = this.renderInfo( this._config diff --git a/tangy-form-condensed-editor.js b/tangy-form-condensed-editor.js index 8f9b5192..d9602975 100644 --- a/tangy-form-condensed-editor.js +++ b/tangy-form-condensed-editor.js @@ -75,6 +75,10 @@ class TangyFormCondensedEditor extends PolymerElement { type: String, value: "", }, + locationListMetadata: { + type: Object, + value: '' + } }; } @@ -112,6 +116,9 @@ class TangyFormCondensedEditor extends PolymerElement { this.print ? "MODE_PRINT" : "MODE_INFO" ); widgetEl.setAttribute("files-endpoint", this.filesEndpoint); + if (foundWidget.widgetName == 'tangy-location-widget') { + widgetEl.setAttribute("location-list-metadata", `${JSON.stringify(this.locationListMetadata)}`); + } if (this.hideSkipIf) widgetEl.setAttribute("hide-skip-if", ""); if (this.hideShowIf) widgetEl.setAttribute("hide-show-if", ""); wrap(childNode, widgetEl); @@ -264,6 +271,7 @@ class TangyFormCondensedEditor extends PolymerElement { } const addInputEl = document.createElement("tangy-form-editor-add-input"); addInputEl.setAttribute("files-endpoint", this.filesEndpoint); + addInputEl.setAttribute("location-list-metadata", `${JSON.stringify(this.locationListMetadata)}`); if (this.hasAttribute('hide-skip-if')) addInputEl.setAttribute('hide-skip-if', '') if (this.hasAttribute('hide-show-if')) addInputEl.setAttribute('hide-show-if', '') if (insertAfterEl) { diff --git a/tangy-form-editor-add-input.js b/tangy-form-editor-add-input.js index 33fcbd36..8ed6805e 100644 --- a/tangy-form-editor-add-input.js +++ b/tangy-form-editor-add-input.js @@ -127,6 +127,14 @@ class TangyFormEditorAddInput extends PolymerElement { const wrapperEl = document.createElement(event.target.id) wrapperEl.setAttribute('mode', 'MODE_EDIT') wrapperEl.setAttribute('files-endpoint', this.getAttribute('files-endpoint')) + + if (event.target.id == 'tangy-location-widget') { + const locationListMetadata = this.getAttribute('location-list-metadata') + if (locationListMetadata) { + wrapperEl.setAttribute("location-list-metadata", locationListMetadata); + } + } + if (this.hasAttribute('hide-skip-if')) wrapperEl.setAttribute('hide-skip-if', '') if (this.hasAttribute('hide-show-if')) wrapperEl.setAttribute('hide-show-if', '') this.after(wrapperEl) diff --git a/tangy-form-editor.js b/tangy-form-editor.js index 1f7a5b4d..ae8ca308 100644 --- a/tangy-form-editor.js +++ b/tangy-form-editor.js @@ -161,6 +161,10 @@ class TangyFormEditor extends PolymerElement { filesEndpoint: { type: String, value: '' + }, + locationListMetadata: { + type: Object, + value: '' } }; } @@ -562,7 +566,8 @@ class TangyFormEditor extends PolymerElement { this.$.container.innerHTML = '' this.innerHTML = ` diff --git a/tangy-form-item-editor.js b/tangy-form-item-editor.js index e81a98ef..4b935319 100644 --- a/tangy-form-item-editor.js +++ b/tangy-form-item-editor.js @@ -108,6 +108,10 @@ class TangyFormItemEditor extends PolymerElement { type: String, value: "", }, + locationListMetadata: { + type: Object, + value: '' + } }; } @@ -220,10 +224,12 @@ class TangyFormItemEditor extends PolymerElement { - + diff --git a/widget/tangy-location-widget.js b/widget/tangy-location-widget.js index 7b7ddd17..61c426cb 100644 --- a/widget/tangy-location-widget.js +++ b/widget/tangy-location-widget.js @@ -5,6 +5,7 @@ import "tangy-form/input/tangy-checkbox.js"; import { TangyBaseWidget } from "../tangy-base-widget.js"; class TangyLocationWidget extends TangyBaseWidget { + get claimElement() { return "tangy-location"; } @@ -21,6 +22,7 @@ class TangyLocationWidget extends TangyBaseWidget { metaDataTemplate: "", filterByGlobal: false, showLevels: "", + locationSrc: "" }; } @@ -35,6 +37,7 @@ class TangyLocationWidget extends TangyBaseWidget { ...this.upcastAdvancedAttributes(config, element), ...this.upcastUnimplementedAttributes(config, element), metaDataTemplate: element.innerHTML, + locationListMetadata: element.locationListMetadata }; } @@ -50,6 +53,7 @@ class TangyLocationWidget extends TangyBaseWidget { show-levels="${config.showLevels}" ${config.filterByGlobal ? "filter-by-global" : ""} ${config.showMetaData ? "show-meta-data" : ""} + location-src=${config.locationSrc} > ${config.metaDataTemplate} @@ -98,18 +102,33 @@ class TangyLocationWidget extends TangyBaseWidget {
${this.renderEditCoreAttributes(config)} ${this.renderEditQuestionAttributes(config)} - Filter by locations in the user profile? - - show meta-data - +
+

Select the location list to use for this input

+
The Default Location List will be used if none is selected
+
Changing the list will clear the entry for Filter by Location
+ + ${this.renderLocationListMetadataSelect()} + +
+
+

Select the checkboxes below to limit the levels that will appear in the list

+
If none are selected, all levels will appear in the list
+ + ${this.renderShowLevelsCheckboxes()} + +
+
+

Choose which metadata labels will appear in the list

+
The metadata labels are useful to provide context to the user
+ show meta-data + +
+
+

Check the box to filter the list by the user profile

+ Filter by locations in the user profile? +
${this.renderEditConditionalAttributes(config)} @@ -127,6 +146,91 @@ class TangyLocationWidget extends TangyBaseWidget { `; } + afterRenderEdit() { + this.shadowRoot + .querySelector("#container") + .querySelector("tangy-form") + .querySelector("tangy-form-item") + .querySelector("iron-pages") + .querySelector("tangy-select.location-src-select") + .addEventListener('change', this.onLocationSrcChange.bind(this)); + } + + renderLocationListMetadataSelect() { + let options = '' + let locationListMetadata = JSON.parse(this.getAttribute('location-list-metadata')) + if (locationListMetadata) { + for (let location of locationListMetadata) { + options = `${options} + ` + } + } + return options; + } + + renderShowLevelsCheckboxes() { + let options = '' + let locationListMetadata = JSON.parse(this.getAttribute('location-list-metadata')) + if (locationListMetadata) { + const locationList = Object.values(locationListMetadata).find(l => l.path == this._config.locationSrc) + for (let level of locationList.locationsLevels) { + options = `${options} + ` + } + } + return options; + } + + onLocationSrcChange(event) { + // If showLevels is set, we need to clear it when the locationSrc changes + // since the levels are probably not in the new locationSrc + if (event.target.value != this._config.locationSrc) { + this._config.locationSrc = event.target.value + this._config.showLevels = '' + + // Should this be done another way? + this._render(); + } + } + + // converts a comma separated string of values into a tangy-checkboxes value + getShowLevelTangyCheckboxesValue() { + let values = [] + + if (this._config.showLevels) { + let selectedLevels = this._config.showLevels.split(',') + let locationListMetadata = JSON.parse(this.getAttribute('location-list-metadata')) + if (locationListMetadata) { + const locationList = Object.values(locationListMetadata).find(l => l.path == this._config.locationSrc) + for (let level of locationList.levels) { + values.push( + { + "name": level, + "value": selectedLevels.includes(level) ? "on" : "" + } + ) + } + } + } + + return JSON.stringify(values) + } + + // converts a tangy-checkboxes value into a comma separated string of values + getShowLevelValueString(formEl) { + let values = [] + let input = formEl.response.items[0].inputs.find( + (input) => input.name === "showLevels") + if (input) { + for (let v of input.value) { + if (v.value == 'on') { + values.push(v.name) + } + } + } + return values.join(',') + } + onSubmit(config, formEl) { return { ...config, @@ -136,15 +240,17 @@ class TangyLocationWidget extends TangyBaseWidget { ...this.onSubmitValidationAttributes(config, formEl), ...this.onSubmitAdvancedAttributes(config, formEl), ...this.onSubmitUnimplementedAttributes(config, formEl), + locationSrc: + formEl.response.items[0].inputs.find( + (input) => input.name === "location-src" + ).value, filterByGlobal: formEl.response.items[0].inputs.find( (input) => input.name === "filterByGlobal" ).value === "on" ? true : false, - showLevels: formEl.response.items[0].inputs.find( - (input) => input.name === "showLevels" - ).value, + showLevels: this.getShowLevelValueString(formEl), showMetaData: formEl.response.items[0].inputs.find( (input) => input.name === "show-meta-data"