/**
* @file dom.js
* @module dom
*/
import document from 'global/document' ;
import window from 'global/window' ;
import fs from '../fullscreen-api' ;
import log from './log.js' ;
import {isObject} de './obj' ;
import computedStyle de './computed-style' ;
import * as browser from './browser' ;
/**
* Détecter si une valeur est une chaîne de caractères contenant des caractères autres que des espaces blancs.
*
* @private
* @param {string} str
* La chaîne à vérifier
*
* @return {boolean}
* Sera `vrai` si la chaîne n'est pas vide, `faux` sinon.
*
*/
function isNonBlankString(str) {
// nous utilisons str.trim pour éliminer les caractères d'espacement
// de l'avant ou de l'arrière des caractères qui ne sont pas des espaces blancs. aka
// Toute chaîne contenant des caractères autres que des espaces blancs sera
// les contiennent toujours après `trim` mais uniquement des chaînes de caractères avec espaces blancs
// aura une longueur de 0, échouant ainsi à cette vérification.
return typeof str === 'string' && Boolean(str.trim()) ;
}
/**
* Lance une erreur si la chaîne passée contient des espaces. Il est utilisé par
* afin d'être relativement cohérent avec l'API classList.
*
* @private
* @param {string} str
* La chaîne de caractères à vérifier pour les espaces.
*
* @throws {Error}
* Lance une erreur s'il y a des espaces dans la chaîne.
*/
function throwIfWhitespace(str) {
// str.indexOf au lieu de regex car str.indexOf est plus rapide en termes de performances.
if (str.indexOf(' ') >= 0) {
lancer une nouvelle erreur ('class has illegal whitespace characters') ;
}
}
/**
* Produire une expression régulière pour faire correspondre un className à un className d'un élément.
*
* @private
* @param {string} className
* Le nom de la classe pour laquelle le RegExp doit être généré.
*
* @return {RegExp}
* Le RegExp qui vérifiera la présence d'un `className` spécifique dans un élément
* nom de classe.
*/
function classRegExp(className) {
return new RegExp('(^|\N-)' + className + '($|\N-)') ;
}
/**
* Si l'interface DOM actuelle semble être réelle (c'est-à-dire non simulée).
*
* @return {boolean}
* Sera `true` si le DOM semble être réel, `false` sinon.
*/
export function isReal() {
// Le document et la fenêtre ne seront jamais indéfinis grâce à `global`.
return document === window.document ;
}
/**
* Détermine, via le typage des canards, si une valeur est un élément DOM ou non.
*
* @param {Mixed} value
* Valeur à vérifier.
*
* @return {boolean}
* Sera `true` si la valeur est un élément DOM, `false` sinon.
*/
export function isEl(value) {
return isObject(value) && value.nodeType === 1 ;
}
/**
* Détermine si le DOM actuel est intégré dans une iframe.
*
* @return {boolean}
* Sera `true` si le DOM est intégré dans une iframe, `false` si le DOM est intégré dans une iframe
* autrement.
*/
export function isInFrame() {
// Nous avons besoin d'un try/catch ici parce que Safari lancera des erreurs lors de la tentative de
// pour obtenir soit `parent` soit `self`
essayez {
return window.parent !== window.self ;
} catch (x) {
retourner vrai ;
}
}
/**
* Crée des fonctions pour interroger le DOM à l'aide d'une méthode donnée.
*
* @private
* @param {string} method
* La méthode de création de la requête.
*
* @return {Fonction}
* La méthode d'interrogation
*/
function createQuerier(method) {
return function(selector, context) {
if (!isNonBlankString(selector)) {
return document[method](null) ;
}
if (isNonBlankString(context)) {
context = document.querySelector(context) ;
}
const ctx = isEl(context) ? context : document ;
return ctx[method] && ctx[method](selector) ;
};
}
/**
* Crée un élément et lui applique des propriétés, des attributs et insère du contenu.
*
* @param {string} [tagName='div']
* Nom de l'étiquette à créer.
*
* @param {Objet} [properties={}]
* Propriétés de l'élément à appliquer.
*
* @param {Objet} [attributes={}]
* Attributs de l'élément à appliquer.
*
* @param {module:dom~ContentDescriptor} content
* Un objet descripteur de contenu.
*
* @return {Element}
* L'élément qui a été créé.
*/
export function createEl(tagName = 'div', properties = {}, attributes = {}, content) {
const el = document.createElement(tagName) ;
Object.getOwnPropertyNames(properties).forEach(function(propName) {
const val = properties[propName] ;
// Voir #2176
// À l'origine, nous acceptions à la fois les propriétés et les attributs dans l'élément
// même objet, mais cela ne fonctionne pas aussi bien.
if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') {
log.warn('Setting attributes in the second argument of createEl()\n' +
a été supprimée. Utiliser le troisième argument à la place
`créerEl(type, propriétés, attributs). Attempting to set ${propName} to ${val}.`) ;
el.setAttribute(propName, val) ;
// Gérer textContent puisque ce n'est pas supporté partout et que nous avons un
// méthode pour cela.
else if (propName === 'textContent') {
textContent(el, val) ;
else if (el[propName] !== val || propName === 'tabIndex') {
el[propName] = val ;
}
}) ;
Object.getOwnPropertyNames(attributes).forEach(function(attrName) {
el.setAttribute(attrName, attributes[attrName]) ;
}) ;
if (content) {
appendContent(el, content) ;
}
return el ;
}
/**
* Injecte du texte dans un élément, en remplaçant entièrement tout contenu existant.
*
* @param {Element} el
* L'élément dans lequel ajouter du contenu textuel
*
* @param {string} texte
* Le contenu du texte à ajouter.
*
* @return {Element}
* L'élément avec le contenu textuel ajouté.
*/
export function textContent(el, text) {
if (typeof el.textContent === 'undefined') {
el.innerText = text ;
} else {
el.textContent = text ;
}
return el ;
}
/**
* Insérer un élément comme premier nœud enfant d'un autre
*
* @param {Element} child
* Élément à insérer
*
* @param {Element} parent
* Élément à insérer dans l'enfant
*/
export function prependTo(child, parent) {
if (parent.firstChild) {
parent.insertBefore(child, parent.firstChild) ;
} else {
parent.appendChild(child) ;
}
}
/**
* Vérifier si un élément possède un nom de classe.
*
* @param {Element} element
* Élément à vérifier
*
* @param {string} classToCheck
* Nom de la classe à vérifier
*
* @return {boolean}
* Sera `true` si l'élément a une classe, `false` sinon.
*
* @throws {Error}
* Lance une erreur si `classToCheck` contient des espaces blancs.
*/
export function hasClass(element, classToCheck) {
throwIfWhitespace(classToCheck) ;
if (element.classList) {
return element.classList.contains(classToCheck) ;
}
return classRegExp(classToCheck).test(element.className) ;
}
/**
* Ajouter un nom de classe à un élément.
*
* @param {Element} element
* Élément auquel ajouter le nom de la classe.
*
* @param {string} classToAdd
* Nom de la classe à ajouter.
*
* @return {Element}
* L'élément DOM avec le nom de classe ajouté.
*/
export function addClass(element, classToAdd) {
if (element.classList) {
element.classList.add(classToAdd) ;
// Il n'est pas nécessaire de `throwIfWhitespace` ici car `hasElClass` le fera
// dans le cas où classList n'est pas pris en charge.
} else if (!hasClass(element, classToAdd)) {
element.className = (element.className + ' ' + classToAdd).trim() ;
}
retourner l'élément ;
}
/**
* Supprime le nom d'une classe d'un élément.
*
* @param {Element} element
* Élément dont il faut supprimer le nom de la classe.
*
* @param {string} classToRemove
* Nom de la classe à supprimer
*
* @return {Element}
* L'élément du DOM dont le nom de classe a été supprimé.
*/
export function removeClass(element, classToRemove) {
// Protéger au cas où le joueur serait éliminé
if (!element) {
log.warn("removeClass a été appelé avec un élément qui n'existe pas") ;
retourner null ;
}
if (element.classList) {
element.classList.remove(classToRemove) ;
} else {
throwIfWhitespace(classToRemove) ;
element.className = element.className.split(/\s+/).filter(function(c) {
return c !== classToRemove ;
}).join(' ') ;
}
retourner l'élément ;
}
/**
* La définition du rappel pour toggleClass.
*
* @callback module:dom~PredicateCallback
* @param {Element} element
* L'élément DOM du composant.
*
* @param {string} classToToggle
* Le `nom de la classe` que l'on veut faire basculer
*
* @return {boolean|undefined}
* Si `true` est retourné, la `classeToToggle` sera ajoutée à l'élément
* `element`. Si `false`, la `classeToToggle` sera supprimée de la base de données de
* l'"élément". Si `undefined`, le rappel sera ignoré.
*/
/**
* Ajoute ou supprime un nom de classe à un élément en fonction d'un paramètre optionnel
* ou la présence/absence du nom de la classe.
*
* @param {Element} element
* L'élément qui permet d'activer un nom de classe.
*
* @param {string} classToToggle
* La classe qui doit être activée.
*
* @param {boolean|module:dom~PredicateCallback} [predicate]
* Voir la valeur de retour pour {@link module:dom~PredicateCallback}
*
* @return {Element}
* L'élément avec une classe qui a été basculé.
*/
export function toggleClass(element, classToToggle, predicate) {
// Cela ne peut pas utiliser `classList` en interne parce que IE11 ne supporte pas l'option de la liste des classes
// deuxième paramètre de la méthode `classList.toggle()` ! Ce qui n'est pas grave car
// `classList` sera utilisé par les fonctions d'ajout/suppression.
const has = hasClass(element, classToToggle) ;
if (typeof predicate === 'function') {
predicate = predicate(element, classToToggle) ;
}
if (typeof predicate !== 'boolean') {
prédicat = !a ;
}
// Si l'opération de classe nécessaire correspond à l'état actuel de l'élément
//, aucune action n'est requise.
if (predicate === has) {
retour ;
}
if (predicate) {
addClass(element, classToToggle) ;
} else {
removeClass(élément, classToToggle) ;
}
retourner l'élément ;
}
/**
* Appliquer des attributs à un élément HTML.
*
* @param {Element} el
* Élément auquel ajouter des attributs.
*
* @param {Objet} [attributs]
* Attributs à appliquer.
*/
export function setAttributes(el, attributes) {
Object.getOwnPropertyNames(attributes).forEach(function(attrName) {
const attrValue = attributes[attrName] ;
if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
el.removeAttribute(attrName) ;
} else {
el.setAttribute(attrName, (attrValue === true ? '' : attrValue)) ;
}
}) ;
}
/**
* Obtenir les valeurs des attributs d'un élément, telles qu'elles sont définies dans la balise HTML.
*
* Les attributs ne sont pas les mêmes que les propriétés. Ils sont définis sur la balise
* ou avec setAttribute.
*
* @param {Element} tag
* Élément à partir duquel les attributs de la balise sont obtenus.
*
* @return {Object}
* Tous les attributs de l'élément. Les attributs booléens seront `vrai` ou
* `false`, les autres seront des chaînes.
*/
export function getAttributes(tag) {
const obj = {} ;
// attributs booléens connus
// nous pouvons vérifier les propriétés booléennes correspondantes, mais pas dans tous les navigateurs
// et toutes les balises ne connaissent pas ces attributs, c'est pourquoi nous voulons encore les vérifier manuellement
const knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ',' ;
if (tag && tag.attributes && tag.attributes.length > 0) {
const attrs = tag.attributes ;
for (let i = attrs.length - 1 ; i >= 0 ; i--) {
const attrName = attrs[i].name ;
let attrVal = attrs[i].value ;
// vérification des booléens connus
// la propriété de l'élément correspondant renverra une valeur pour typeof
if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
// la valeur d'un attribut booléen inclus est généralement une valeur vide
// chaîne de caractères ('') qui serait égale à false si l'on se contentait de vérifier la présence d'une valeur false.
// nous ne voulons pas non plus supporter un mauvais code comme autoplay='false'
attrVal = (attrVal !== null) ? true : false ;
}
obj[attrName] = attrVal ;
}
}
retourner obj ;
}
/**
* Obtenir la valeur de l'attribut d'un élément.
*
* @param {Element} el
* Un élément DOM.
*
* @param {string} attribut
* Attribut dont il faut obtenir la valeur.
*
* @return {string}
* La valeur de l'attribut.
*/
export function getAttribute(el, attribute) {
return el.getAttribute(attribute) ;
}
/**
* Fixe la valeur de l'attribut d'un élément.
*
* @param {Element} el
* Un élément DOM.
*
* @param {string} attribut
* Attribut à définir.
*
* @param {string} value
* Valeur à attribuer à l'attribut.
*/
export function setAttribute(el, attribute, value) {
el.setAttribute(attribut, valeur) ;
}
/**
* Supprime l'attribut d'un élément.
*
* @param {Element} el
* Un élément DOM.
*
* @param {string} attribut
* Attribut à supprimer.
*/
export function removeAttribute(el, attribute) {
el.removeAttribute(attribute) ;
}
/**
* Tentative de blocage de la possibilité de sélectionner du texte.
*/
export function blockTextSelection() {
document.body.focus() ;
document.onselectstart = function() {
retourner faux ;
};
}
/**
* Désactiver le blocage de la sélection de texte.
*/
export function unblockTextSelection() {
document.onselectstart = function() {
retourner vrai ;
};
}
/**
* Identique à la fonction native `getBoundingClientRect`, mais assure que
* la méthode est prise en charge (elle l'est dans tous les navigateurs que nous prétendons prendre en charge)
* et que l'élément se trouve dans le DOM avant de continuer.
*
* Cette fonction enveloppante permet également de compenser les propriétés qui ne sont pas fournies par certaines
* les navigateurs plus anciens (notamment IE8).
*
* En outre, certains navigateurs ne permettent pas d'ajouter des propriétés à un fichier
* `ClientRect`/`DOMRect` ; nous le copions donc de façon superficielle avec la méthode standard
* (sauf `x` et `y` qui ne sont pas largement supportés). Cela aide
* éviter les implémentations où les clés ne sont pas dénombrables.
*
* @param {Element} el
* Elément dont nous voulons calculer le `ClientRect`.
*
* @return {Objet|non défini}
* Renvoie toujours un objet simple - ou `undefined` s'il ne le peut pas.
*/
export function getBoundingClientRect(el) {
if (el && el.getBoundingClientRect && el.parentNode) {
const rect = el.getBoundingClientRect() ;
const result = {} ;
['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(k => {
if (rect[k] !== undefined) {
result[k] = rect[k] ;
}
}) ;
if (!result.height) {
result.height = parseFloat(computedStyle(el, 'height')) ;
}
if (!result.width) {
result.width = parseFloat(computedStyle(el, 'width')) ;
}
retourner le résultat ;
}
}
/**
* Représente la position d'un élément DOM sur la page.
*
* @typedef {Objet} module:dom~Position
*
* @property {number} left
* Pixels à gauche.
*
* @property {number} top
* Pixels à partir du haut.
*/
/**
* Obtenir la position d'un élément dans le DOM.
*
* Utilise la technique `getBoundingClientRect` de John Resig.
*
* voir http://ejohn.org/blog/getboundingclientrect-is-awesome/
*
* @param {Element} el
* Élément à partir duquel le décalage est obtenu.
*
* @return {module:dom~Position}
* La position de l'élément qui a été transmis.
*/
export function findPosition(el) {
if (!el || (el && !el.offsetParent)) {
retour {
gauche : 0,
supérieur : 0,
width: 0,
height: 0
};
}
const width = el.offsetWidth ;
const height = el.offsetHeight ;
let left = 0 ;
let top = 0 ;
while (el.offsetParent && el !== document[fs.fullscreenElement]) {
left += el.offsetLeft ;
top += el.offsetTop ;
el = el.offsetParent ;
}
retour {
gauche,
supérieur,
largeur,
hauteur
};
}
/**
* Représente les coordonnées x et y d'un élément DOM ou d'un pointeur de souris.
*
* @typedef {Objet} module:dom~Coordonnées
*
* @property {number} x
* coordonnée x en pixels
*
* @property {number} y
* coordonnée y en pixels
*/
/**
* Obtenir la position du pointeur à l'intérieur d'un élément.
*
* La base des coordonnées se trouve en bas à gauche de l'élément.
*
* @param {Element} el
* Élément sur lequel obtenir la position du pointeur.
*
* @param {EventTarget~Event} event
* Objet de l'événement.
*
* @return {module:dom~Coordinates}
* Un objet de coordonnées correspondant à la position de la souris.
*
*/
export function getPointerPosition(el, event) {
const translated = {
x : 0,
y : 0
};
if (browser.IS_IOS) {
let item = el ;
while (item && item.nodeName.toLowerCase() !== 'html') {
const transform = computedStyle(item, 'transform') ;
if (/^matrix/.test(transform)) {
const values = transform.slice(7, -1).split(/,\s/).map(Number) ;
translated.x += values[4] ;
translated.y += values[5] ;
else if (/^matrix3d/.test(transform)) {
const values = transform.slice(9, -1).split(/,\s/).map(Number) ;
translated.x += values[12] ;
translated.y += values[13] ;
}
item = item.parentNode ;
}
}
const position = {} ;
const boxTarget = findPosition(event.target) ;
const box = findPosition(el) ;
const boxW = box.width ;
const boxH = box.height ;
let offsetY = event.offsetY - (box.top - boxTarget.top) ;
let offsetX = event.offsetX - (box.left - boxTarget.left) ;
if (event.changedTouches) {
offsetX = event.changedTouches[0].pageX - box.left ;
offsetY = event.changedTouches[0].pageY + box.top ;
if (browser.IS_IOS) {
offsetX -= translated.x ;
offsetY -= translated.y ;
}
}
position.y = (1 - Math.max(0, Math.min(1, offsetY / boxH))) ;
position.x = Math.max(0, Math.min(1, offsetX / boxW)) ;
position de retour ;
}
/**
* Détermine, par le biais du typage de canard, si une valeur est un nœud de texte ou non.
*
* @param {Mixed} value
* Vérifier si cette valeur est un nœud de texte.
*
* @return {boolean}
* Sera `true` si la valeur est un noeud de texte, `false` sinon.
*/
export function isTextNode(value) {
return isObject(value) && value.nodeType === 3 ;
}
/**
* Vide le contenu d'un élément.
*
* @param {Element} el
* L'élément dont il faut vider les enfants
*
* @return {Element}
* L'élément sans enfant
*/
export function emptyEl(el) {
while (el.firstChild) {
el.removeChild(el.firstChild) ;
}
return el ;
}
/**
* Il s'agit d'une valeur mixte qui décrit le contenu à injecter dans le DOM
* par le biais d'une méthode. Il peut être des types suivants :
*
* Type | Description
* -----------|-------------
* `string` | La valeur sera normalisée en un nœud de texte.
* `Element` | La valeur sera acceptée telle quelle.
* `TextNode` | La valeur sera acceptée telle quelle.
* `Array` | Un tableau unidimensionnel de chaînes, d'éléments, de nœuds de texte ou de fonctions. Ces fonctions doivent renvoyer une chaîne, un élément ou un nœud de texte (toute autre valeur de retour, comme un tableau, sera ignorée).
* `Fonction` | Une fonction, qui est censée retourner une chaîne, un élément, un nœud de texte, ou un tableau - n'importe laquelle des autres valeurs possibles décrites ci-dessus. Cela signifie qu'un descripteur de contenu peut être une fonction qui renvoie un tableau de fonctions, mais ces fonctions de second niveau doivent renvoyer des chaînes, des éléments ou des nœuds de texte.
*
* @typedef {string|Element|TextNode|Array|Function} module:dom~ContentDescriptor
*/
/**
* Normalise le contenu en vue d'une éventuelle insertion dans le DOM.
*
* Cela permet d'utiliser un large éventail de méthodes de définition du contenu, tout en protégeant le contenu de l'information
* de ne pas tomber dans le piège d'écrire simplement dans `innerHTML`, ce qui pourrait
* être un problème de XSS.
*
* Le contenu d'un élément peut être transmis sous plusieurs formes et
* dont le comportement est le suivant :
*
* @param {module:dom~ContentDescriptor} content
* Une valeur de descripteur de contenu.
*
* @return {Array}
* Tout le contenu qui a été transmis, normalisé en un tableau de
* ou des nœuds de texte.
*/
export function normalizeContent(content) {
// D'abord, invoquer le contenu s'il s'agit d'une fonction. S'il produit un tableau,
// qui doit avoir lieu avant la normalisation.
if (typeof content === 'function') {
content = content() ;
}
// Ensuite, on normalise en tableau, de sorte qu'un ou plusieurs éléments puissent être normalisés,
// filtrée et renvoyée.
return (Array.isArray(content) ? content : [content]).map(value => {
// Tout d'abord, invoquez value s'il s'agit d'une fonction pour produire une nouvelle valeur,
// qui sera ensuite normalisé en un nœud quelconque.
if (typeof value === 'function') {
valeur = valeur() ;
}
if (isEl(value) || isTextNode(value)) {
valeur de retour ;
}
if (typeof value === 'string' && (/\S/).test(value)) {
return document.createTextNode(value) ;
}
}).filter(value => value) ;
}
/**
* Normalise et ajoute du contenu à un élément.
*
* @param {Element} el
* Élément auquel ajouter le contenu normalisé.
*
* @param {module:dom~ContentDescriptor} content
* Une valeur de descripteur de contenu.
*
* @return {Element}
* L'élément dont le contenu normalisé a été ajouté.
*/
export function appendContent(el, content) {
normalizeContent(content).forEach(node => el.appendChild(node)) ;
return el ;
}
/**
* Normalise et insère le contenu dans un élément ; ceci est identique à
* `appendContent()`, sauf qu'il vide d'abord l'élément.
*
* @param {Element} el
* Élément dans lequel insérer le contenu normalisé.
*
* @param {module:dom~ContentDescriptor} content
* Une valeur de descripteur de contenu.
*
* @return {Element}
* L'élément dont le contenu normalisé a été inséré.
*/
export function insertContent(el, content) {
return appendContent(emptyEl(el), content) ;
}
/**
* Vérifie si un événement correspond à un simple clic gauche.
*
* @param {EventTarget~Event} event
* Objet de l'événement.
*
* @return {boolean}
* Sera `true` s'il s'agit d'un simple clic gauche, `false` dans le cas contraire.
*/
export function isSingleLeftClick(event) {
// Note : si vous créez quelque chose qui peut être déplacé, veillez à
// l'appeler sur les événements `mousedown` et `mousemove`,
// sinon `mousedown` devrait suffire pour un bouton
if (event.button === undefined && event.buttons === undefined) {
// Pourquoi avons-nous besoin de `buttons` ?
// Parce que la souris du milieu a parfois cette particularité :
// e.button === 0 et e.buttons === 4
// De plus, nous voulons empêcher les clics combinés, quelque chose comme
// Maintenir la souris du milieu puis cliquer sur le bouton gauche, ce qui donnerait
// e.button === 0, e.buttons === 5
// un simple `button` ne fonctionnera pas
// D'accord, que fait ce bloc ?
// ceci est pour chrome `simuler les appareils mobiles`
// Je souhaite également soutenir ce projet
retourner vrai ;
}
if (event.button === 0 && event.buttons === undefined) {
// Écran tactile, parfois sur un appareil spécifique, `boutons`
// n'a rien (safari sur ios, blackberry...)
retourner vrai ;
}
// L'événement `mouseup` sur un simple clic gauche a
// `button` et `buttons` égaux à 0
if (event.type === 'mouseup' && event.button === 0 &&
event.buttons === 0) {
retourner vrai ;
}
if (event.button !== 0 || event.buttons !== 1) {
// C'est la raison pour laquelle nous avons ces blocs if else ci-dessus
// s'il existe un cas particulier, nous pouvons l'attraper et le laisser passer
// nous le faisons ci-dessus, quand nous arrivons ici, c'est définitivement
// n'est pas un clic gauche
retourner faux ;
}
retourner vrai ;
}
/**
* Trouve un seul élément DOM correspondant à `selector` dans l'espace optionnel de `selector`
* `contexte` d'un autre élément DOM (par défaut `document`).
*
* @param {string} selector
* Un sélecteur CSS valide, qui sera passé à `querySelector`.
*
* @param {Elément|Chaîne} [context=document]
* Un élément du DOM à l'intérieur duquel la requête doit être effectuée. Peut également être un sélecteur
* dans ce cas, le premier élément correspondant sera utilisé
* comme contexte. En cas d'absence (ou si aucun élément ne correspond au sélecteur), les chutes
* retour à `document`.
*
* @return {Element|null}
* L'élément qui a été trouvé ou null.
*/
export const $ = createQuerier('querySelector') ;
/**
* Trouve tous les éléments du DOM correspondant à `selector` dans l'espace optionnel de `selector`
* `contexte` d'un autre élément DOM (par défaut `document`).
*
* @param {string} selector
* Un sélecteur CSS valide, qui sera passé à `querySelectorAll`.
*
* @param {Elément|Chaîne} [context=document]
* Un élément du DOM à l'intérieur duquel la requête doit être effectuée. Peut également être un sélecteur
* dans ce cas, le premier élément correspondant sera utilisé
* comme contexte. En cas d'absence (ou si aucun élément ne correspond au sélecteur), les chutes
* retour à `document`.
*
* @return {NodeList}
* Liste des éléments trouvés. Sera vide s'il n'y en a pas
* ont été trouvés.
*
*/
export const $$ = createQuerier('querySelectorAll') ;