npm package: @openmind/zero-storelocator
Description: Storelocator Zero Components
Author: openmind
Latest version: 0.0.4

# StoreLocator Zero Components
Built on top [StoreLocator library](https://stash.openmindonline.it/projects/OC/repos/storelocator) and [Zero framework](https://stash.openmindonline.it/projects/OC/repos/zero).
_StoreLocatorZeroComponents_ allows you to start using basic standard functionalities of Store Locator pages. It has been thinked to be Plug&Play and it is _html data-attribute driven_.

NOTE: in order to use this module you have to enable the `react mode` of Zero.
Do not forget to pass and object while starting Zero via:
```js
Zero.start( {} );
```
##### Components
- `ZStoreLocator`: main wrapper for all StoreLocator functionalities
- `ZMap`: wrapper for map and its events
- `ZSearch`: wrapper for Google Autocomplete Service
- `ZResults`: wrapper for result stores list
- `ZFilters`: wrapper for filters
- `ZResultsCounter`: wrapper for the counter of the in-map pins

All of these components can be extended via `extends` keyword in _ES6_

##### Start using
Structure/Order of components:
```
    HTML Page
      |
      L   ZStoreLocator
            L   ZSearch
            L   ZResults
            L   ZMap
            L   ZFilters
            L   ZResultsCounter
```

##### ZStoreLocator
Add these few lines in you HTML page:
```html
<div data-component="ZStoreLocator" data-zstorelocator-sl-markerkey="storeCode">
  ...
</div>
```
`data-zstorelocator-sl-` stores all StoreLocator initializing options. See [StoreLocator doc](https://stash.openmindonline.it/projects/OC/repos/storelocator/browse?at=refs%2Fheads%2Fbuild) for more details.

It casts these messages:
- `StoreLocator:Init` once _StoreLocator_ module has been initialized and ready to be used. It passes `StoreLocator` key in its message
- `StoreLocator:GeoJson:Loaded` each time a new _GeoJson_ has been loaded from server. It passes `geojson` key in its message

You have to extend these methods:
- `refreshGeoJsonViaAjax(data)` -> it performs a new ajax request to server for retrieving new GeoJson. `data` contains all data from page. It must return a Promise
- `filterResults(geojson, data)` -> it filters geojson result represented by `geojson` argument. `data` contains all data from page. It must return a new geojson object
- `sortResults(geojson, data)` -> it sorts the geojson resultset represented by `geojson` argument. `data` contains all data from page. It doesn't return value

##### ZSearch
Add these few lines in you HTML page:
```html
<form data-component="ZSearch">
    <input value="" type="text" name="search" />
    <button type="button" class="search">Search</button>
    <button type="button" class="geo-location">Geo Location</button>
</form>
```
ZSearch searches HTML element via `input[name=search]` `button.geo-location` and `button.search` selectors. They can be override via:
```js
class MyCustomZSearch extends ZSearch {
    get Selectors() {
      return {
        GeolocationButton: "my-custom-geo-location-selector",
        SearchButton: "my-custom-search-selector",
        SearchInput: "my-custom-input-text-selector"
      }
    }
}
```
It casts:
- `StoreLocator:Search:Place` each time user searches via _GoogleAutocompleteService_. It passes:
```
place: geolocation -> the geolocation object
address: address_text -> the searched text
```

##### ZResults
Add these few lines in your html page:
```html
<div data-component="ZResults">
    <span id="counter"></span>
    <template id="template-store">
      ...
    </template>
    <ol id="results-list-container" >
    </ol>
</div>
```
ZResults searches html element via these selectors:
- `Template`: "#template-store" -> the template element id (it will be parsed via `Handlebars`)
- `ResultsContainer`: "#results-list-container" -> container of stores list
- `StoreListElement`: 'li.store-item' -> each store details element in the container
- `ShowDetailsButton`: 'button.show-details' -> button for handle _show details_ action within each _store details element_
- `HideDetailsButton`: 'button.hide-details' -> button for handle _hide details_ action within each _store details element_
- `SpanCounter`: '#counter' -> the element which contains the label "{number} stores found"
- `HighlightedClass`: "highlighted" -> the css class which will be added while user mouseovering on item
- `SelectedClass`: 'selected' -> the css class which will be added while user clicking on item

All of these selectors can be modified as per `ZSearch` documentation.

It casts:
- `StoreLocator:List:Hover` / `StoreLocator:List:Unhover` -> each time user mouseovering/mouseleaving on an element in the list
- `StoreLocator:List:Clicked` / `StoreLocator:List:Clicked` -> each time user clicking on 'show'/'hide' details buttons


##### ZMap
Add these few lines in your html page:
```html
<div data-component="ZMap" data-zmap-usecluster="true" data-zmap-map-pan_Control="false">
    <div id="map-container" class="map"></div>
    <button id="controls_zoom_in">+</button>
    <button id="controls_zoom_out">-</button>
</div>
```

_data-attribute_ prefixed by `map` will be passed to GoogleMap while initializing the map. See GoogleMap doc for more details

ZMap searches html element via these selectors:
- `Map`: "#map-container" -> the GoogleMap container
- `ZoomIn`: "#controls_zoom_in" -> button which will handle the _zoom in_ functionality
- `ZoomOut`: "#controls_zoom_out" -> button which will handle the _zoom out_ functionality

All of these selectors can be modified as per `ZSearch` documentation.
Moreover you can extends some methods in order to customize your requirements:
- `onGeoJsonLoaded`: method fired each time a new _GeoJson_ has been loaded from server. It calls `StoreLocator#showMarker` api
- `bindMarker`: method called for each _marker_ while rendering pins on map. Here you can bind all marker's events
- `bindStoreLocator`: method called on startup once `StoreLocator` module has been initialized. Here you can bind some events on _StoreLocator_

It casts:
- `StoreLocator:Map:Navigated` each time user performs a new search via _ZSearch_ and map has moved on that location
- `StoreLocator:Map:Ready` once Map is ready to use
- `StoreLocator:Pin:Hover` / `StoreLocator:Pin:Unhover` each time user mouseovering/mouseleaving a pin on the map
- `StoreLocator:Pin:Clicked` / `StoreLocator:Pin:Unclicked` each time user toggle-click on a pin on the map


##### ZFilters
Add these few lines in your html page:
```html
  <form data-component="ZFilters">

    <span class="filters-counter"></span>

    <div>
      <button class="apply-filter-btn">Apply</button>
      <button class="clear-filter-btn" type="reset">Clear</button>
    </div>
  </form>
```
FEATURES:
- ZFilter must be a `<form>` since we're using jQuery's `.serializeArray()`
- Thus use in your form only tags allowed in `<form>` such as `inputs, selects, textareas`
- It comes out with its own filter counter


ZFilter searches html element via these selectors:
- `FiltersCounter`: ".filters-counter" -> is the counter for the applied filters. It will be filled using `text()` function via jQuery
- `ApplyFiltersBtn`: ".apply-filter-btn" -> apply filters button. It also adds 'is-filtered' css class to the form
- `ClearFiltersBtn`: ".clear-filter-btn" -> clear filters button. It also removes 'is-filtered' css class from the form

It casts:
- `Storelocator:Filter:Applied`: when filters are applied (apply-button)
- `Storelocator:Filter:Clear`: when filters are cleare (clear-button)

It uses react to set this property -> `Zero.$state.StoreLocator.Filters`

##### ZResultsCounter

Add these few lines in your html page:

```html
<span data-component="ZResultsCounter"></span>
```

ZResultsCounter only shows the current number of results (visible pins). It will be filled using `text()` function via jQuery

It grabs:
- `StoreLocator:GeoJson:Loaded`: since `msg.geojson.features` returns the number of on-map pins