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);
  }
}