editGraphe/fonctionsUtiles.js

import { addElement } from 'sesajs/dom'

/** @module editGraphe/fonctionsUtiles */

/**
 * Retourne la position absolue d’un élément html
 * @param {Element} el
 * @returns {{x: number, y: number}}
 */
export function findPosDiv (el) {
  let x = 0
  let y = 0
  if (el.offsetParent) {
    x = el.offsetLeft
    y = el.offsetTop
    while (el === el.offsetParent) {
      x += el.offsetLeft
      y += el.offsetTop
    }
  }
  return { x, y }
}

/**
 * Alias de getElementById
 * @param {string} id
 * @returns {Element}
 */
export function gettag (id) {
  return document.getElementById(id)
}

export function clone (srcInstance) {
  /* Si l’instance source n’est pas un objet ou qu’elle ne vaut rien c’est une feuille donc on la retourne */
  if (typeof srcInstance !== 'object' || srcInstance == null) {
    return srcInstance
  }
  /* On appelle le constructeur de l’instance source pour crée une nouvelle instance de la même classe */
  const newInstance = srcInstance.constructor()
  /* On parcourt les propriétés de l’objet et on les recopies dans la nouvelle instance */
  for (const i in srcInstance) {
    newInstance[i] = clone(srcInstance[i])
  }
  /* On retourne la nouvelle instance */
  return newInstance
}

/**
 * Configuration d’un élément html à créer
 * @typedef EltConfig
 * @property {string} [id] id html de l’élément à créer
 * @property {HTMLElement} [papa] Le parent dans lequel ajouter l’élément créé (en dernier)
 */
/**
 * Ajoute l’élément défini par config à config.papa
 * @param {EltConfig} config
 * @return {HTMLElement}
 */
export function addElt (config) {
  if (!config.papa) {
    console.error('config sans papa', config)
    throw Error('impossible d’ajouter un élément sur un objet sans parent')
  }
  const elt = getElt(config)
  if (!elt) throw Error('Pas trouvé l’élément à ajouter')
  config.papa.appendChild(elt)
  return elt
}
export function getElt (config) {
  if (typeof config !== 'object' || typeof config.tag !== 'string') throw Error('paramètres invalides')
  const elt = document.createElement(config.tag)
  if (config.id) elt.id = config.id
  if (config.fontSize) elt.style.fontSize = config.fontSize
  if (config.color) elt.style.color = config.color
  return elt
}

/**
 * Retourne un élément du dom, le crée s’il n’existait pas
 * @param {HTMLElement} parent
 * @param {string} tag
 * @param {object} options
 * @param {string} [options.id]
 * @param {string} [options.className] Si pas d’id fourni il faut fournir une classe css, ce sera le premier élément (avec le bon tag) de parent ayant cette classe qui sera retourné
 * @param {string} [childText]
 * @return {HTMLElement}
 */
export const findOrCreateElement = (parent, tag, { id, className }, childText) => {
  if (id) {
    return document.getElementById(id) || addElement(parent, tag, { id, content: childText })
  }
  if (className) {
    let elt
    const elts = parent.getElementsByClassName(className)
    if (elts && elts.length) {
      // on prend le premier avec le bon tag
      elts.some(_elt => {
        if (_elt.tagName === tag) {
          elt = _elt
          return true // pour arrêter la boucle
        }
        return false
      })
    }
    if (elt) return elt
    return addElement(parent, tag, { class: className, content: childText })
  }
  throw Error('Paramètres incorrect (il faut fournir id ou className en option')
}

/**
 * Ajoute un <div> dans config.papa
 * @param {EltConfig} config
 * @param {string} [config.value='']
 * @return {HTMLInputElement}
 */
export function creediv (config) {
  return addElt({ ...config, tag: 'div' })
}
/**
 * Ajoute un <input> dans config.papa
 * @param {EltConfig} config
 * @param {string} [config.value='']
 * @return {HTMLInputElement}
 */
export function creeinput (config) {
  const input = getElt({ ...config, tag: 'input' })
  if (config.value !== undefined) input.value = config.value
  if (config.type) input.type = config.type
  config.papa.appendChild(input)
  return input
}
/**
 * Ajoute un <span> dans config.papa
 * @param {EltConfig} config
 * @param {string} [config.value='']
 * @return {HTMLSpanElement}
 */
export function creespan (config) {
  const span = getElt({ ...config, tag: 'span' })
  if (config.innerHTML) span.innerHTML = config.innerHTML
  if (config.textContent) span.textContent = config.textContent
  config.papa.appendChild(span)
  return span
}
/**
 * Ajoute des input radio (et leur label) dans un <span>, ajouté dans config.papa
 * @param {EltConfig} config
 * @param {string[]} config.value Les valeurs (utilisées aussi comme label)
 * @param {string[]} config.id_radios_btn Les id des boutons radio
 * @param {string} config.check La valeur du bouton radio à sélectionner
 * @return {HTMLSpanElement}
 */
export function creebtnsradios (config) {
  if (!Array.isArray(config.value)) throw Error('Paramètres incorrects')
  const span = getElt({ ...config, tag: 'span' })
  span.style.textAlign = 'center'
  config.value.forEach((val, index) => {
    const radiosBtn = document.createElement('input')
    radiosBtn.type = 'radio'
    radiosBtn.name = config.id
    radiosBtn.value = val
    radiosBtn.id = config.id_radios_btn[index]
    if (config.check === config.value[index]) {
      radiosBtn.checked = true
    }
    const label = document.createElement('label')
    label.htmlFor = 'label' + radiosBtn.id
    label.appendChild(document.createTextNode(val + '   '))
    span.appendChild(radiosBtn)
    span.appendChild(label)
  })
  config.papa.appendChild(span)
  return span
}

/**
 * Ajoute un tag <select>, wrappé dans un span, dans config.papa
 * @param {EltConfig} config
 * @param {string[]} config.value Les valeurs (utilisées aussi comme label)
 * @param {string} config.prefixe Préfixe d’id sur le select (suivi de 'select' puis de nom_param)
 * @param {string} config.nom_param Suffixe de l’id du select
 * @return {HTMLSpanElement}
 */
export function creelisteDeroulante (config) {
  const span = getElt({ ...config, tag: 'span' })
  const selectElt = document.createElement('select')
  selectElt.id = config.prefixe + 'select' + config.nom_param
  if (Array.isArray(config.value)) {
    for (const [index, val] of config.value.entries()) {
      const optionElt = document.createElement('option')
      if (config.selected === config.value[index]) {
        optionElt.selected = true
      }
      optionElt.id = config.nom_param + encodeURIComponent(val)
      optionElt.innerHTML = val
      selectElt.appendChild(optionElt)
    }
  } else {
    console.warn('Pas de propriété value (array) dans', config)
  }
  span.appendChild(selectElt)
  config.papa.appendChild(span)
  return span
}

/**
 * Retourne le nombre X (pas forcément entier) si cssString vaut "Xpx" (undefined sinon)
 * @param {string} cssString
 * @return {number|undefined}
 */
export function extractNumberFromCss (cssString) {
  if (/^[0-9]+px$/.test(cssString)) return Number(cssString.substr(0, cssString.length - 2))
}