core-geonetwork
core-geonetwork copied to clipboard
GeoNetwork app as web components.
Add support to embed GeoNetwork app in other website using webcomponents and evaluate what are the limitation of using webcomponents with current libraries.
The web component can be added using an iframe or as shadow DOM mode. Custom configuration can be defined to customize the app. Webcomponent can only show a full text box with some facets
or the search app only
or the full app. Use the UI configuration to configure your component.
Webcomponent can facilitate embedding of GeoNetwork in another website. In theory, it will help avoiding JS and CSS conflicts compared to trying to embed the JS app directly in the page by providing some isolation (as it is done in Sextant https://sextant.ifremer.fr/Donnees/Catalogue). This PR evaluates what are the limitation and difficulties and demonstrate what is operational.
Examples
Examples are available http://localhost:8080/geonetwork/catalog/webcomponents/index.html
The UI configuration is used to customize the component. Examples demonstrate how to add a simple search box which can point to your catalogue, display numbers using facets, show a simple list of results corresponding to a particular search, embed the map viewer...
Shadow DOM mode
To embed GeoNetwork in a page use:
<gn-app url="http://localhost:8080/geonetwork"
portal="srv"
config='{"mods": {
"home": {"enabled": false},
"footer": {"enabled": false},
"header": {"enabled": false}
}}'></gn-app>
<script src="webcomponents.js"></script>
When using shadow DOM mode, fonts used in the application needs to be loaded in the main HTML page. This is done by adding gn_web_components.css
in the parent page.
Angularjs does not allow to be loaded more than once, so adding 2 webcomponents using shadow DOM mode will trigger WARNING: Tried to load AngularJS more than once
. Use iframe mode instead.
Iframe mode
To embed GeoNetwork in a page use:
<gn-app-frame
url="http://localhost:8080/geonetwork"
portal="srv"
config='{"mods": {
"home": {"enabled": false},
"footer": {"enabled": false},
"header": {"enabled": false}
}}'
></gn-app-frame>
<script src="webcomponents.js"></script>
Iframe mode is less responsive in height compared to the shadow DOM mode which automatically extend itself.
Other example with third party HTML page layout
Changes:
- [x] Home page / Add configuration to customize information tabs
- [x] Home page / Add support to link to the catalogue if only the home page is in a webcomponent
- [x] Hotkeys / Add configuration to disable keyword shortcuts
- [x] Library / jQuery / Listen events on shadow root https://github.com/jquery/jquery/issues/4317 - changes backported in this PR
- [x] Library / Bootstrap / Interaction with document.body not accessible from the webcomponent (eg. popover, dropdown) - Add the possibility to set a context root node (which is not document - https://github.com/geonetwork/core-geonetwork/blob/0b89278c1b05042ed3ffbbb85d1dffa63ce3901e/web-ui/src/main/resources/catalog/lib/bootstrap.js#L28-L29).
Known limitations
- 2 webcomponent using Shadow DOM mode can't be included in the same page due to angularjs limitation. For better webcomponent support migration to more modern UI framework would be required.
- All bootstrap JS components may not work properly when embedded using Shadow DOM mode (but the default home and search apps work fine)
Funded by Ifremer
Nice! this looks a little bit like the approach we experimented in Sextant. One of the big limitations I found is that jQuery is global to the document, so you might have conflicts and other unexpected issues. For instance the bootstrap dropdowns and modals do not work in that configuration.
Fonts are always a bit annoying in web components since (at least in current browsers) they are not used if they are not defined in the host document as well, but that can be worked around with a bit of code (like you did for icons).
Also I think this part here is risky: https://github.com/geonetwork/core-geonetwork/blob/c2ee8381a9ff5544d8db48f3ac60c48be9e67818/web-ui/src/main/resources/catalog/webcomponents/webcomponents.js#L30
IMO this needs some sanitizing to make sure that baseUrl
does not contain malicious code (same with portal
).
Do you have options to solve "the big limitations"? It looks like the main point is that the $ fn is contextualized to document and in web component case, it would be needed to contextualize it to the root of the shadowDOM. Not sure if we can override this.
Do you have options to solve "the big limitations"? It looks like the main point is that the $ fn is contextualized to document and in web component case, it would be needed to contextualize it to the root of the shadowDOM. Not sure if we can override this.
Last time I checked, the option to "hack" jQuery to work with the component root instead of the document was tempting but not really feasible in practice (that would mean changing many different parts of the jquery code and create a maintenance nightmare).
Another option would be to rewrite all the components and directives relying on bootstrap/jquery with custom ones. This would be a lot of work but theoretically doable.
I think it's worthwhile to put that in perspective with the actual benefits from using web components instead of an iframe:
- an iframe provide an even higher level of encapsulation at the cost of some security limitations (which we solved in Sextant I think)
- the main downside of the iframe is that nothing can go "out" (e.g. modals), and it cannot determine its own size
- it is still possible to provide a similar API for including GeoNetwork as you did in that PR, but instead of
you would do something like<gn-app url="http://localhost:8080/geonetwork" portal="srv" config='{"mods": {"map": {"enabled": false}}}'> </gn-app> <script src="webcomponents.js"></script>
and this script would be responsible for creating the iframe for example (or including the angularjs application right in the page like in Sextant).<script src="webcomponents.js" url="http://localhost:8080/geonetwork" portal="srv" config='{"mods": {"map": {"enabled": false}}}'> </script>
or other options, upgrade bootstrap maybe ?
or other options, upgrade bootstrap maybe ?
Boostrap 5 does not use jquery any more, so it might work better in a shadow DOM (to be confirmed). Upgrading Bootstrap would be quite the undertaking though, probably comparable to rewriting the modals/dropdowns/datepicker/etc. directives.
Sorry for not having better alternatives. As a matter of fact this situation was one of the big motivations for starting the gn-ui project.
Kudos, SonarCloud Quality Gate passed!
0 Bugs
0 Vulnerabilities
0 Security Hotspots
0 Code Smells
No Coverage information
0.0% Duplication
Impressive work, did you manage to avoid having conflicts if jquery is also included in the host page? This was very common in Sextant, two versions (sometimes more) of jquery with different versions would end up being in conflict.
Quality Gate passed
Issues
0 New issues
Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code
@fxprunayre maybe you missed my last question, I'd be keen to hear whether you managed to avoid conflicts when jquery is already in the page, as this isn't listed in the limitations. Thanks!
did you manage to avoid having conflicts if jquery is also included in the host page? This was very common in Sextant, two versions (sometimes more) of jquery with different versions would end up being in conflict.
So far, we did not observed issue related to that. Adding a JQuery version in the webcomponent test pages does not look to introduce issues.
Quality Gate passed
Issues
0 New issues
0 Accepted issues
Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code