hooks.mjs

/**
## /hooks

The mapp.hooks{} module parses, updates, and stores URL parameter.

```js
{
  current: {
    layers: [],
    locations: [],
  },
  set,
  parse,
  remove,
  removeAll,
  push,
  filter,
}
```

@module /hooks
*/

const hooks = {
  current: {
    layers: [],
    locations: [],
  },
  set,
  parse,
  remove,
  removeAll,
  push,
  filter,
}

export default hooks;

/**
@function parse

@description
The method parses key/value pairs of URL searchParams from the document window.location.href.
*/
function parse() {
  
  const url = new URL(window.location.href);

  // Iterate over the search parameters
  for (const [key, value] of url.searchParams.entries()) {
    // string 'false' should be boolean false
    if (value === 'false') {
      hooks.current[key] = false;
      continue;
    }
    // string 'true' should be boolean true
    if (value === 'true') {
      hooks.current[key] = true;
      continue;
    }
    // layers and locations should always be arrays
    if (key === 'locations' || key === 'layers') {
      hooks.current[key] = decodeURIComponent(value).split(',');
      continue;
    }

    hooks.current[key] = value.includes(',') ? decodeURIComponent(value).split(',') : value;
  }

  // Strip token from url
  if (hooks.current.token) {
    url.searchParams.delete('token');
    window.history.replaceState({}, document.title, url.toString());
    delete hooks.current.token;
  }
}

/**
@function set
 
@description
The set method will assign a URL params object to the hooks.current{} before calling the pushState() method.

@param {Object} _hooks A params object to be assigned to the hooks.current.
*/
function set(_hooks) {

  Object.assign(hooks.current, _hooks)

  pushState()
}

/**
@function remove
 
@description
Remove key from mapp.hooks.current and URI. Array properties will be emptied. Other properties will be deleted.

@param {string} key hooks.current{} property key.
*/
function remove(key) {

  if (Array.isArray(hooks.current[key])) {

    // Empty array.
    hooks.current[key].length = 0

  } else {

    delete hooks.current[key]
  }

  pushState()
}

/**
@function removeAll
 
@description
Iterate through all hooks.current property keys and call the remove method with the key argument.
*/
function removeAll() {

  Object.keys(hooks.current).forEach(key => remove(key))

  pushState()
}

/**
@function push
 
@description
Assigns the val param to the hooks.current[key] property.

@param {string} key hooks.current{} property key.
@param {*} val hooks.current[key] property val.
*/
function push(key, val) {

  if (hooks.current[key]) {

    if (hooks.current[key].indexOf(val) < 0) hooks.current[key].push(val)

  } else {

    hooks.current[key] = [val]
  }

  pushState()
}

/**
@function filter
 
@description
Filter [remove] a value from an hooks.current array property.

This is requiired to strip a location.hook from the [selected] locations.

@param {string} key hooks.current{} array property key.
@param {*} val hooks.current[key] array property val.
*/
function filter(key, val) {

  if (!Array.isArray(hooks.current[key])) return;

  hooks.current[key] = hooks.current[key].filter(el => el !== val)

  pushState()
}

/**
@function pushState
 
@description
Pushes changes in the hooks.current to the window URL.
*/
function pushState() {

  try {
    window.history.pushState({},
      document.title,
      `?${mapp.utils.paramString(hooks.current)}`)

  } catch (me) {
    console.log(me)
  }
}