Fullscreen Map
View a fullscreen map with a side panel where the listing results can be filtered, searched and clicked on.
Dataset in use: fr-esr-principaux-etablissements-enseignement-superieur
(See it on mesr domain)
Fields in use:
type_d_etablissement | secteur_d_etablissement | dep_nom | uo_lib | adresse_uai | dep_nom | numero_telephone_uai | url |
---|---|---|---|---|---|---|---|
Grand établissement | Public | Paris | Conservatoire national des arts et métiers | 292 RUE SAINT MARTIN | Paris | 0140272000 | http://www.cnam.fr/ |
École | Public | Bouches-du-Rhône | Centrale Marseille | 38 rue Frédéric-Joliot-Curie | Bouches-du-Rhône | 0491282898 | https://www.centrale-marseille.fr/ |
École | Privé | Paris | École centrale d’électronique | 37 quai de Grenelle | Paris | 0144390600 | https://www.ece.fr/ecole-ingenieur/ |
École | Privé | Haute-Garonne | École d’ingénieurs de Purpan | 75 VOIE DU TOEC | Haute-Garonne | http://www.purpan.fr/ |
<!-- V2.1 :
- Add ods-select and multiple choice option for filters
- Add clear all filter button when one filter is applied
- Add documentation
-->
<!-- IMPORTANT ******** MUST READ !
In the following settings declaration :
A common error is forget to escape (protect) apostrophe with a leading backslash
As apostrophes are used to declare values of variable it will break the settings
Ex:
wrongVariable = 'I'll be freed from apostrophes'
correctVariable = 'I\'ll be freed from apostrophes'
-->
<!-- SETTINGS START HERE -->
<div ng-init="domain = 'mesr.opendatasoft.com';
datasetid = 'fr-esr-principaux-etablissements-enseignement-superieur';
title = 'Établissements près de chez vous';
filters = [
{'id':'type_d_etablissement','multiple':true},
{'id':'secteur_d_etablissement','multiple':true},
{'id':'dep_nom','multiple':true}
];
resetFiltersButton = true;
resetFiltersButtonLabel = 'Supprimer tous les filtres';
resultTitle = 'uo_lib';
fieldsList = ['adresse_uai', 'dep_nom', 'numero_telephone_uai'];
fieldLink = 'url';
fieldLinkLabel = 'Visiter le site web';
mapLinkLabel = 'Voir sur la carte';
viewListButtonText = 'Voir la liste';
viewDetailsButtonText = 'Voir les détails';
backToResultsButtonText = 'Retour aux résultats';
mapNoRefit = false;
DO_NOT_MODIFY_BELOW;
ctxfields = {};
isVisible = false;
activeFilters = {};
">
<!-- ### GENERAL SETTINGS ### -->
<!-- domain : (Domain URL) : Must contain the ID of the domain where the dataset is published.
ex: 'discovery.opendatasoft.com'
-->
<!-- datasetid (Dataset ID) : Must contain the ID of the dataset
ex: 'oeuvres-de-johannes-vermeer'
-->
<!-- title (Title of the page) :
ex: 'List of interest around you'
-->
<!-- ### FILTERS SETTINGS ### -->
<!-- filters (Filters) : List of object that contains the IDs to generate the filters pannel.
and multiple true or false to allow the user to select multiple values in the filter.
NB: the field must be a facet in the dataset
NB: alphanumerical sort is applied in the filter view
ex: [
{'id':'filterid','multiple':true},
{'id':'filterid2','multiple':false}
]
-->
<!-- resetFiltersButton (boolean) : add a reset filters button after filters block -->
<!-- resetFiltersButtonLabel (Label of the button) : test to display when a filter is selected
ex: 'Clear all filters'
-->
<!-- ### LIST VIEW SETTINGS ### -->
<!-- resultTitle (Title of the item) : Set the item title from a field ID
ex: 'title';
-->
<!-- fieldsList (List configuration) : Set the list of field IDs
ex: ['category','genre','date']
-->
<!-- fieldLink (Link to an external resource) : If available, the field ID of some external resource as a web URL
ex: 'link'
-->
<!-- fieldLinkLabel (The label of that link) : Label of the link button
ex: 'Read more here'
-->
<!-- mapLinkLabel (The label of the item button) : used to select the item and see it on the map
ex: 'See on the map'
-->
<!-- ### MOBILE VIEW SETTINGS ### -->
<!-- viewListButtonText : when displaying the map, the bottom button to open the list view
ex: 'See the list'
-->
<!-- viewDetailsButtonText : when an item is selected on the map, the bottom button to open the list view with the selected item
ex: 'See the item details'
-->
<!-- backToResultsButtonText : when the list view is opened, to close button to go back to the map
ex: "Back to the list'
-->
<!-- ### MAP SETTINGS ### -->
<!-- mapNoRefit : true / false refit the map when filtering -->
<!-- DO NOT MODIFY -->
<!-- Technical fields, do not modify please -->
<ods-dataset-context context="ctx"
ctx-domain="{{ domain }}"
ctx-dataset="{{ datasetid }}">
<span ng-repeat="field in ctx.dataset.fields">
{{ ctxfields[field.name] = field.label; '' }}
</span>
<span ng-repeat="filter in filters">
{{ ctx.parameters['refine.' + filter.id] = activeFilters[filter.id] ; '' }}
</span>
<aside class="cl-modal"
ng-class="{ 'is-visible' : modal.isVisible}">
<div class="cl-modal-header">
<button class="cl-modal-close-mobile"
title="Close modal"
ng-click="modal.isVisible = false">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-x">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
<h1 class="cl-modal-title">
{{ title }}
</h1>
<div class="search-module">
<i class="fa fa-search search-module-icon" aria-hidden="true"></i>
<input placeholder="Search"
ng-model="ctx.parameters['q']"
ng-model-options="{ updateOn: 'keyup', debounce: { 'default': 300, 'blur': 0 }}"
class="search-module-input"
type="text"/>
<button class="search-module-clear"
ng-if="ctx.parameters['q']"
ng-click="ctx.parameters['q'] = undefined">
<i class="fa fa-times-circle" aria-hidden="true"></i>
</button>
</div>
<!-- FILTERS -->
<div class="filter-list"
ng-init="dropdown.open = '';
select = {}">
<div ng-repeat="filter in filters">
{{ ctx.parameters['disjunctive.' + filter.id] = true; '' }}
<div ods-facet-results="categories"
ods-facet-results-facet-name="{{ filter.id }}"
ods-facet-results-context="ctx"
ods-facet-results-sort="alphanum">
<ods-select ng-if="ctxfields[filter.id]"
selected-values="activeFilters[filter.id]"
multiple="filter.multiple"
options="categories"
label-modifier="name"
value-modifier="name"
placeholder="{{ ctxfields[filter.id] }}"></ods-select>
</div>
</div>
<div class="clear-filters"
ng-show="(activeFilters | values).join('')">
<div class="clear-filters-button"
role="button"
ng-click="activeFilters = {}">
{{ resetFiltersButtonLabel }}
<i class="fa fa-times-circle" aria-hidden="true"></i>
</div>
</div>
</div>
</div>
<div class="cl-modal-content">
<ul class="result-list">
<li class="result"
ng-repeat="item in items"
ods-results="items"
ods-results-context="ctx"
ods-results-max="1000">
<h2 class="result-title">
{{ item.fields[resultTitle] }}
</h2>
<dl class="result-info">
<dt ng-repeat-start="field in fieldsList">
{{ ctxfields[field] }}
</dt>
<dd ng-repeat-end>{{ item.fields[field] }}</dd>
</dl>
<div class="result-footer">
<a href="{{ item.fields[fieldLink] }}"
ng-if="fieldLink && item.fields[fieldLink]"
target="_blank">
{{ fieldLinkLabel }}
</a>
<button class="result-button"
ng-if="!ctx.parameters['refine.' + resultTitle]"
ng-click="modal.isVisible = false;
ctx.parameters['refine.' + resultTitle] = item.fields[resultTitle];">
{{ mapLinkLabel }}
</button>
<button class="result-button"
ng-if="ctx.parameters['refine.' + resultTitle]"
ng-click="ctx.parameters['refine.' + resultTitle] = undefined">
{{ backToResultsButtonText }}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-x">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</li>
</ul>
</div>
</aside>
<ods-map no-refit="{{ mapNoRefit }}"
scroll-wheel-zoom="true"
display-control="false"
display-control-single-layer="false"
toolbar-fullscreen="false"
toolbar-drawing="false">
<ods-map-layer-group>
<ods-map-layer context="ctx"
refine-on-click-context="ctx"
refine-on-click-map-field="{{ resultTitle }}"
refine-on-click-context-field="{{ resultTitle }}"
color="#0098c3"
picto="college"
show-marker="true"
display="auto"
shape-opacity="0.5"
point-opacity="1"
border-color="#FFFFFF"
border-opacity="1"
border-size="1"
border-pattern="solid"
size="4"
size-min="3"
size-max="5"
size-function="linear"></ods-map-layer>
</ods-map-layer-group>
</ods-map>
<div class="cl-modal-open-mobile"
ng-click="modal.isVisible = true">
<svg xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-chevron-up">
<polyline points="18 15 12 9 6 15"></polyline>
</svg>
<h3 class="cl-modal-open-mobile-title"
ng-if="!ctx.parameters['refine.' + resultTitle]">
{{ viewListButtonText }}
</h3>
<h3 class="cl-modal-open-mobile-title"
ng-if="ctx.parameters['refine.' + resultTitle]">
{{ viewDetailsButtonText }}
</h3>
</div>
</ods-dataset-context>
</div>
/* General Layout
========================================================================== */
body, .main--page {
padding: 0;
margin: 0;
}
.ods-front-header, .ods-front-footer, .ods-content:after, footer {
display: none;
}
ods-dataset-context {
display: block;
position: relative;
}
.odswidget.odswidget-map {
width: 100%;
height: 100vh;
}
/* Modal
========================================================================== */
.cl-modal {
display: none;
flex-direction: column;
background-color: #FFFFFF;
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
width: 100vw;
height: 100vh;
position: absolute;
top: 35%;
left: 0;
border-radius: 6px 6px 0 0;
z-index: 30;
overflow: hidden; /* Disable horizontal scroll */
}
@media screen and (min-width: 768px) {
.cl-modal {
display: flex;
width: 400px;
height: calc(100vh - 55px);
top: 10px;
left: 47px;
border-radius: 6px;
}
}
.cl-modal.is-visible {
display: flex;
}
.cl-modal-open-mobile {
position: absolute;
bottom: 0;
text-align: center;
width: 100vw;
background-color: #FFFFFF;
padding: 13px;
z-index: 20;
border-radius: 6px 6px 0 0;
box-shadow: 0 0 5px rgba(0,0,0,0.65);
transition: all .2s;
}
.cl-modal-open-mobile:hover {
background-color: #f2f2f2;
}
@media screen and (min-width: 768px) {
.cl-modal-open-mobile {
display: none;
}
}
.cl-modal-open-mobile-title {
margin: 0;
font-weight: bold;
}
.cl-modal-close-mobile {
position: absolute;
top: 5px;
right: 5px;
background-color: transparent;
border-radius: 10000px;
border: none;
font-size: 2.5rem;
opacity: .6;
transition: all .2s;
}
.cl-modal-close-mobile:hover {
background-color: #f2f2f2;
opacity: 1;
}
@media screen and (min-width: 768px) {
.cl-modal-close-mobile {
display: none;
}
}
.cl-modal-header {
padding: 26px 26px 0 26px;
box-shadow: 0 1px 2px rgba(0,0,0,.13);
}
.cl-modal-title {
margin-top: 0;
margin-bottom: 13px;
text-align: center;
font-weight: 400;
font-size: 1.5rem;
}
.cl-modal-content {
height: 100%;
overflow-y: auto;
}
/* Search Module
========================================================================== */
.search-module {
display: flex;
align-items: stretch;
border-bottom: 1px solid #dee5ef;
transition: all .2s;
}
.search-module:hover,
.search-module:focus-within {
border-bottom-color: var(--links);
}
.search-module-icon {
color: #898d92;
margin-right: 8px;
align-self: center;
}
.search-module-input {
background-color: transparent;
width: 100%;
outline: none;
border: none;
padding: 12px 0;
transition: all .2s;
color: var(--text);
}
.search-module-input::placeholder {
transition: all .2s;
}
.search-module-clear {
color: #898d92;
font-size: 1rem;
background: transparent;
border: none;
margin: 0;
outline: none;
padding: 0 0 0 12px;
transition: all .2s;
}
.search-module-clear:hover {
opacity: .65;
}
.search-module:hover .search-module-icon,
.search-module:focus-within .search-module-icon,
.search-module:hover .search-module-input::placeholder,
.search-module:focus-within .search-module-input::placeholder {
color: var(--links)
}
/* Dropdown menu with pill styling
========================================================================== */
.filter-list {
display: flex;
flex-wrap: wrap;
margin-bottom: 20px;
}
.filter-list > div {
width: 100%;
margin-top: 13px;
}
.clear-filters {
display: flex;
align-items: center;
justify-content: center;
}
.clear-filters-button:hover {
opacity: 0.65;
}
/* Results
========================================================================== */
.result-list {
list-style: none;
padding-left: 0;
margin-top: 0;
overflow-y: auto;
}
.result {
padding: 1rem 26px;
border-top: 1px solid #DEE5EF;
}
.result:hover {
background-color: #f5f7fa;
}
.result-title {
color: var(--titles);
font-size: 1rem;
font-weight: bold;
margin-top: 0;
margin-bottom: 5px;
}
.result-info {
list-style: none;
padding-left: 0;
margin-top: 0;
margin-bottom: 10px;
overflow-wrap: break-word;
}
.result-info dt {
font-size: .9rem;
opacity: .9;
}
.result-info dd {
margin-left: 0;
margin-bottom: 5px;
}
.result-footer {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
.result-button {
display: inline-flex;
align-items: center;
background-color: transparent;
border: 1px solid var(--links);
color: var(--links);
line-height: 1.5;
border-radius: 20px;
padding: .1rem .8rem;
margin-right: 4px;
margin-bottom: 2px;
transition: all .2s;
}
.result-button .feather-x {
height: 15px;
width: 15px;
margin-left: 4px;
}
.result-button:hover {
opacity: .65;
text-decoration: none;
}