JavaScript

Memo

Traitement des chaînes de caractères

Remplacement des caractères spéciaux

function removeAccents (text) {
    return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}

kebab-case to camelCase

const capitalizeFirstLetter = (text: string) => text.charAt(0).toUpperCase() + text.slice(1)
const kebab2camelCase = (text: string) => text.split('-').map(capitalizeFirstLetter).join('')

Echapement d'une expression régulière

Voir la librairie regexp.escape : https://www.npmjs.com/package/regexp.escape

Traitement des tableaux

Tri multicritères

myArray.sort((a, b) => a.firstname.localeCompare(b.firstname) || a.lastname.localeCompare(b.lastname) || a.age - b.age)

Variante

myArray.sort((a, b) => {
    const compFirstname = a.firstname.localeCompare(b.firstname)
    const compLastname = a.lastname.localeCompare(b.lastname)
    const compAge = a.age - b.age
    return compFirstname || compLastname || compAge
})

Traitement des objets

Tri des clés

Object.keys(myObject).sort().reduce(
    (obj, key) => {
        obj[key] = myObject[key]
        return obj
    }, {}
)

Traitement des dates

Formatage

En javascript pur :

function formatDate (date) {
  return `${date.getDate()}/${('0' + (date.getMonth() + 1)).slice(-2)}/${date.getFullYear()} ${date.getHours()}:${('0' + date.getMinutes()).slice(-2)}:${('0' + date.getSeconds()).slice(-2)}`
}

Gestion des appels successifs

Debounce

Appeler qu'une seule fois une fonction au début ou à la fin d'une succession de déclenchements d'un événement.

function debounce (delay, callback) {
  var timeout = null
  return function () {
    if (timeout) {
      clearTimeout(timeout)
    }
    var args = arguments
    timeout = setTimeout(function () {
      callback.apply(null, args)
      timeout = null
    }, delay)
  }
}

window.onresize = debounce(250, function () {
  console.log('e')
})

throttle

Exécuter une fonction de manière périodique durant la séquence de déclenchements.

function throttle(delay, callback) {
  var previousCall = new Date().getTime()
  return function () {
    var time = new Date().getTime()
    if ((time - previousCall) >= delay) {
      previousCall = time
      callback.apply(null, arguments)
    }
  }
}

window.onresize = throttle(250, function () {
  console.log('e')
})

Génération de nombres et chaînes aléatoires

Série de chiffres de longueur donnée

genNumbers (length) {
  return Math.floor(Math.pow(10, length - 1) + Math.random() * 9 * Math.pow(10, length - 1))
}

Gestion des clics et double-clics sur un même élément

let clickCounter = 0
let timer: NodeJS.Timeout
domElement.addEventListener('click', () => {
  clickCounter++
  if (clickCounter === 1) {
    timer = setTimeout(() => {
      clickCounter = 0
      // Simple click
      onSvgNodeClick(node)
    }, 300)
    return
  } else {
    clearTimeout(timer)
    clickCounter = 0
    // Double click
    onSvgNodeDblclick(node)
  }
})

Gestion des erreurs

Etendre la classe Error

class DownloadError extends Error {
  response: Response
  constructor(message: string, response: Response) {
    super(message);
    this.response = response;
    Object.setPrototypeOf(this, DownloadError.prototype);
  }
};

new DownloadError('Erreur au téléchargement du fichier', response);

Manipulation du DOM

Attendre le chargement complet du DOM

window.readyHandlers = [];
window.ready = function ready(handler) {
  window.readyHandlers.push(handler);
  handleState();
};

window.handleState = function handleState () {
  if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
    while(window.readyHandlers.length > 0) {
      (window.readyHandlers.shift())();
    }
  }
};

document.onreadystatechange = window.handleState;

ready(function () {
  // your code here
});

Attendre la présence d'un élément

function waitForElement (selector, callback) {
    const wait = setInterval(function () {
        const element = document.querySelector(selector);
        if (element !== null) {
            callback(element);
            clearInterval(wait);
        }
    }, 100);
}

Divers

Mise en surbrillance de text HTML

Avec mark.js

highlight (text, search) {
  if (typeof text !== 'undefined' && text !== null && !!search) {
    const el = document.createElement('div')
    el.innerHTML = text
    const mark = new Mark(el)
    mark.mark(search, {
      'acrossElements': true
    })
    return el.innerHTML
  }
  return text
}

Fixer plusieurs lignes et/ou plusieurs colonnes d'un tableau

HTML

<table class="software-table" data-sticky-rows="2" data-sticky-cols="3">
    ...
</table>

CSS

table[data-sticky-rows] th,
table[data-sticky-rows] td,
table[data-sticky-cols] th,
table[data-sticky-cols] td {
    position: relative;
    z-index: -2;
}
table[data-sticky-rows] tr.sticky th,
table[data-sticky-rows] tr.sticky td,
table[data-sticky-cols] tr th.sticky,
table[data-sticky-rows] tr td.sticky {
    position: sticky;
    z-index: -1;
}
table[data-sticky-rows] tr.sticky th.sticky,
table[data-sticky-rows] tr.sticky td.sticky {
    z-index: 0;
}

Javascript

document.querySelectorAll('table[data-sticky-rows],table[data-sticky-cols]').forEach(table => {
    const options = {
        rows: parseInt(table.getAttribute('data-sticky-rows')) || 0,
        cols: parseInt(table.getAttribute('data-sticky-cols')) || 0
    };
    const tableStyle = getComputedStyle(table);
    let deltaV = deltaH = 0;
    // Si le style border-collapse est "separate", il faut en tenir compte
    if (tableStyle.borderCollapse === 'separate') {
        const borderSpacing = tableStyle.borderSpacing.split(' ');
        deltaV += parseFloat(borderSpacing[0]) * 2;
        deltaH += parseFloat(borderSpacing[1]) * 2;
    }
    let top = 0;
    // Pour chaque ligne du tableau
    table.querySelectorAll('tr').forEach((row, rowI) => {
        let left = 0;
        let totalColspan = 0;
        // Pour chaque cellule de la ligne
        [...row.querySelectorAll('th,td')].some((cell, cellI) => {
            const colspan = cell.getAttribute('colspan');
            colspan && (totalColspan += parseInt(colspan) - 1);
            if (rowI < options.rows) {
                cell.style.top = `${top}px`
            }
            if (cellI < options.cols - totalColspan) {
                cell.classList.add('sticky');
                cell.style.left = `${left}px`;
            }
            if (rowI >= options.rows && cellI >= options.cols - totalColspan) {
                return true;
            }
            left += cell.offsetWidth + deltaH;
        });
        if (rowI < options.rows) {
            row.classList.add('sticky');
            top += row.offsetHeight + deltaV;
        }
    });
});

Télécharger des données en provenance d'une variable

function download (data, type = 'text') {
  const a = document.createElement('a')
  a.setAttribute('download', 'data')
  a.href = window.URL.createObjectURL(new Blob([data], { type: type }))
  document.body.appendChild(a)
  a.click()
  a.remove()
}

const data = Array.from({ length: 256 }, (_, i) => -128 + i)
  .sort(() => Math.random() - 0.5)
  .join("\n")

download(data)