Source: src/util.js

/**
 * A function to style a HTML element 
 * key of object must be valid css property in js representation (eg.background-color to backgroundColor:"red")
 * @function
 * @param  {HTML element} elem HTML element in which style are applied
 * @param  {Style Object} style Object of styles that applied to HTML element
 * @example
 * styleElement(heading,{backgroundColor:"#AAA"})
 */

const styleElement = (elem, style) => {
  let styleKey = style && Object.keys(style);
  if (styleKey && styleKey.length) {
    styleKey.forEach(function (key) {
      elem.style[key] = style[key];
    })
  }
}


/**
 * A function to append attributes on the  HTML element
 * @function
 * @param  {*} elem  HTML element in which attributes are applied
 * @param  {*} attrs Object of attributes that applied HTML  element
 * @example
 * addAttributes(heading,{class:"heading-container"})
 */

const addAttributes = (elem, attrs) => {
  let attrKeys = attrs && Object.keys(attrs);
  if (attrKeys && attrKeys.length) {
    attrKeys.forEach(key => {
      elem.setAttribute(key, attrs[key]);
    })
  }
}


/**
 * A function to create HTML element and apply style as well as add the attributes
 * @function
 * @param  {*} {parentElem  HTML element in which new HTML element is appended
 * @param  {*} [elemType="div"] Type of element to create
 * @param  {*} attr attributes of the element 
 * @param  {*} [innerText] Content of element  
 * @param  {*} [innerHTML] Content of element
 * @param  {*} style} Style of the element is to be added with valid css property
 */

const createElementAndAppend = ({
  parentElem,
  elemType = "div",
  attr,
  innerText,
  innerHTML,
  style
}) => {
  let elem = document.createElement(elemType);
  style && styleElement(elem, style);
  attr && addAttributes(elem, attr);

  if (innerHTML) {
    elem.innerHTML = innerHTML;
  } else if (innerText) {
    elem.innerText = innerText;
  }
  parentElem.appendChild(elem);
  return elem;
}


/**
 * A function that helps to change the position of element by draging or resizing
 * @function 
 * @param  {HTML element} element element in which drag event should fired
 * @example
 * dragAndDropElement(slide1Element1,slideData,"drag");
 */

const updatePosition = (element, type) => {

  if (type === "drag") {

    let parentX = 0;
    let parentY = 0;

    let shiftX = 0;
    let shiftY = 0;

    let dragger = element.querySelector(".dragger");

    dragger.addEventListener("mousedown", (event) => {

      parentX = element.parentElement.getBoundingClientRect().left;
      parentY = element.parentElement.getBoundingClientRect().top;


      event.preventDefault();

      shiftX = event.clientX - element.getBoundingClientRect().left;
      shiftY = event.clientY - element.getBoundingClientRect().top;

      moveAt(event.clientX, event.clientY);

      // move the element on mousemove
      element.parentElement.addEventListener('mousemove', onMouseMove);
      // drop the element, remove unneeded handlers
      dragger.onmouseup = function () {

        let lastFcused = document.querySelector("[dataToolbarActive='true']");
        if (lastFcused) {
          lastFcused.focus();
        }
        dragger.style.cursor = "grab";
        element.parentElement.removeEventListener('mousemove', onMouseMove);
        dragger.onmouseup = null;
      };

    });
    //mouse move handler
    function onMouseMove(event) {
      moveAt(event.clientX, event.clientY);
    }

    //a function that move the element to desire place

    function moveAt(pageX, pageY) {

      let left = pageX - shiftX - parentX;
      let top = pageY - shiftY - parentY

      // convert to percentage
      let leftPercentage = (left * 100) / element.parentElement.getBoundingClientRect().width + '%'
      let topPercentage = (top * 100) / element.parentElement.getBoundingClientRect().height + '%'

      dragger.style.cursor = "grabbing";
      element.style.left = leftPercentage;
      element.style.top = topPercentage;

      // updating position of thumbnail
      let id = element.getAttribute("id");

      let thumbnailElem = document.querySelector(`.thumbnail #${id}`);

      if (thumbnailElem) {
        thumbnailElem.style.left = leftPercentage;
        thumbnailElem.style.top = topPercentage;
      }
    }

    //preventing default drag and drop
    dragger.addEventListener("dragstart", () => false);

  } else if (type === "resize") {

    // resize 
    let originalWidth = 0;
    let originalHeight = 0;
    let originalMouseX = 0;
    let originalMouseY = 0;

    const resizer = element.querySelector('.resizer');

    resizer && resizer.addEventListener('mousedown', function (e) {
      e.preventDefault();
      originalWidth = element.getBoundingClientRect().width;
      originalHeight = element.getBoundingClientRect().height;
      originalMouseX = e.pageX;
      originalMouseY = e.pageY;
      window.addEventListener('mousemove', resize);
      window.addEventListener('mouseup', stopResize);
    })

    function resize(e) {

      let width = originalWidth + (e.pageX - originalMouseX);
      let height = originalHeight + (e.pageY - originalMouseY);

      // convert to percentage
      let widthPercentage = (width * 100) / element.parentElement.getBoundingClientRect().width + '%'
      let heightPercentage = (height * 100) / element.parentElement.getBoundingClientRect().height + '%'
      element.style.width = widthPercentage;
      element.style.height = heightPercentage;

      // updating thumbnail
      let id = element.getAttribute("id");
      let thumbnailElem = document.querySelector(`.thumbnail #${id}`);

      if (thumbnailElem) {
        thumbnailElem.style.width = widthPercentage
        thumbnailElem.style.height = heightPercentage
      }
    }

    function stopResize() {
      window.removeEventListener('mousemove', resize)
    }
  }
}


/**
 * A funtion that takes inline style and convert to js Object style
 * @function
 * @param  {Object} style style of element (eg. slide1.style)
 * @returns Object that contains js formated style of element
 * @example
 * formatStyleToStore(slide1.style);
 */

const formatStyleToStore = (style) => {
  let styleSheet = {}
  let i = 0;
  while (i >= 0) {
    if (style[i]) {
      let key = camalize(style[i]);
      styleSheet[key] = style[key]
      // console.log('key:', key, style[key]);
      i++;
    } else {
      i = -1; //exiting from loop
    }
  }
  return styleSheet;
}


/** A function to make camel case to any string
 * @function
 * @param  {String} str String to be camalize
 * @returns {String} camal case string
 */

const camalize = (str) => {
  return str.replace(/[-,\W]+(.)/g, function (match, chr) {
    return chr.toUpperCase();
  });
}


/**
 * A function that helps to  export All Collected/prepated data 
 * @function 
 * @param  {Object} jsonData Data is to be exported
 * @param  {String} fileName [n="data.json"] name of the download file 
 */

const exportToJsonFile = (jsonData, fileName) => {
  let dataStr = JSON.stringify(jsonData);
  let dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);

  let exportFileDefaultName = fileName || 'data.json';

  let linkElement = document.createElement('a');
  linkElement.setAttribute('href', dataUri);
  linkElement.setAttribute('download', exportFileDefaultName);
  linkElement.click();
}


/**
 * A function that generate random number between passed range
 * @function
 * @param  {Number} min Lower value of the range
 * @param  {Number} max Upper value of the range
 * @returns {Number} random number between given number
 */
const randomNumber = (min, max) => {
  return Math.floor(Math.random() * (max - min + 1) + min)
}


/**
 * A function that remove the un
 * @function
 * @param {*} elem 
 */

const removeUnnecessaryAttr = (elem) => {
  let dragger = elem.querySelector(".dragger");
  dragger.parentElement.removeChild(dragger)

  let resizer = elem.querySelector(".resizer");
  resizer.parentElement.removeChild(resizer)
  // removing contenteditable attribute on slide list
  let allContentEditAble = elem.querySelectorAll("[contenteditable='true']");
  allContentEditAble.forEach(el => {
    el.removeAttribute("contenteditable");
  });
}


/**
 * A function that returen user name
 * @function
 * @param  {*} email custom email made for this app
 */
const getUsernameFromEmail = email => email.split("-")[0];