@fto-consult/common
Version:
Un ensemble de bibliothèques et d'utilistaires communs pour le développement d'applications javascript
353 lines (316 loc) • 14.1 kB
JavaScript
// Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import isDElement from "./isDOMElement";
import isNonNullString from "../isNonNullString";
export const isDOMElement = isDElement;
var global = typeof window == "object" && window ? window : typeof global == 'object' && global ? global : {}
/*** get max z-index value */
export function getMaxZindex()
{
let highestZIndex = 0;
// later, potentially repeatedly
highestZIndex = Math.max(
highestZIndex,
...Array.from(document.querySelectorAll("body *:not([data-highest]):not(.yetHigher)"), (elem) => parseFloat(getComputedStyle(elem).zIndex))
.filter((zIndex) => !isNaN(zIndex))
);
return highestZIndex;
}
/*** retrieve viewport elements of window
* retourne les dimensions visibles de l'élement window passé en paramète :
* @return : {w : la largeur de la fenêtre,h : la hauteur de la fenêtre}
*/
export function getViewportSize(w) {
// Use the specified window or the current window if no argument
w = w || window;
// This works for all browsers except IE8 and before
if (w.innerWidth != null) return { w: w.innerWidth, h: w.innerHeight };
// For IE (or any browser) in Standards mode
var d = w.document;
if (document.compatMode == "CSS1Compat")
return { w: d.documentElement.clientWidth,
h: d.documentElement.clientHeight };
// For browsers in Quirks mode
return { w: d.body.clientWidth, h: d.body.clientHeight };
}
/*** get absolute position of an elemnet */
export function getAbsolutePosition(el) {
var
found,
left = 0,
top = 0,
width = 0,
height = 0,
offsetBase = getAbsolutePosition.offsetBase;
if (!offsetBase && document.body) {
offsetBase = getAbsolutePosition.offsetBase = document.createElement('div');
offsetBase.style.cssText = 'position:absolute;left:0;top:0';
document.body.appendChild(offsetBase);
}
if (el && el.ownerDocument === document && 'getBoundingClientRect' in el && offsetBase) {
var boundingRect = el.getBoundingClientRect();
var baseRect = offsetBase.getBoundingClientRect();
found = true;
left = boundingRect.left - baseRect.left;
top = boundingRect.top - baseRect.top;
width = boundingRect.right - boundingRect.left;
height = boundingRect.bottom - boundingRect.top;
}
return {
found: found,
left: left,
top: top,
width: width,
height: height,
right: left + width,
bottom: top + height
};
}
export function getViewportOffset(element){
var offset = {"left":0,"top":0}; //keep initial values number so you won't get NaN on first math. operation (on undefined).
for( ; null !== element ; ){
var style = undefined
,position = undefined
;
offset.left = offset.left + element.offsetLeft;
offset.top = offset.top + element.offsetTop;
try{
style = self.getComputedStyle(element);
}catch(err){}
if("undefined" === typeof style) return offset; //sometimes we can go up to the document (not document.documentElement a.k.a HTML-tag but the actual document-object - then getComputedStyle will fail.
if(null === element.parentNode) return offset; //element is-not contained.
element = element.parentNode; //element is contained. also - that's our "loop++".
offset.left = offset.left - (element.scrollLeft || 0); //sometimes scrollLeft is undefined (that will prevent NaN in the offset.left).
offset.top = offset.top - (element.scrollTop || 0); //sometimes scrollLeft is undefined (that will prevent NaN in the offset.top).
position = style.getPropertyValue("position");
if(true === /relative|absolute|fixed/i.test(position)){
offset.left = offset.left + (Number.parseInt(style.getPropertyValue("border-left-width"), 0) || 0);
offset.top = offset.top + (Number.parseInt(style.getPropertyValue("border-top-width"), 0) || 0);
}
element = (true === /fixed/i.test(position)) ? null : element.parentNode; //skip going-up more, in-case the element has a fixed position, in-that-case we're done (the loop stop-condition will be activated).
}
return offset;
}
let isDomFullScreen = false;
/*** put element to fullScreen */
export function fullscreen(element) {
try {
if(!isDOMElement(element)) {
element = document.body;
};
if(element.requestFullscreen)
element.requestFullscreen();
else if(element.mozRequestFullScreen)
element.mozRequestFullScreen();
else if(element.webkitRequestFullscreen)
element.webkitRequestFullscreen();
else if(element.msRequestFullscreen)
element.msRequestFullscreen();
isDomFullScreen = true;
} catch(e){console.log(e," requesting fullscreen")}
}
export function exitFullscreen() {
if(!document.activeElement || !isDomFullScreen) return;
try {
if(document.exitFullscreen)
document.exitFullscreen();
else if(document.mozCancelFullScreen)
document.mozCancelFullScreen();
else if(document.webkitExitFullscreen)
document.webkitExitFullscreen();
else if(document.msExitFullscreen)
document.msExitFullscreen();
isDomFullScreen = false;
} catch(e){console.log(e," exiting fullscreen")}
}
// Returns the DOM Node of the element which is in full-screen
// Returns null if no element in full-screen
function getCurrentFullScreenElement() {
return (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null);
}
export function IsFullScreenCurrently() {
var full_screen_element = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null;
// If no element is in full-screen
if(full_screen_element === null)
return false;
else
return true;
}
export function hasClassName(elem, className) {
if(!isDOMElement(elem)) return false;
return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
}
/***
* addClassName(elem,c1,c2,c3)
*/
export function addClassName() {
let args = Array.prototype.slice.call(arguments,0);
let elem = args[0];
if(!isDOMElement(elem)) return;
for(let i = 1; i< args.length;i++){
let className = args[i];
if(isNonNullString(className) && !hasClassName(elem, className)){
elem.className += ' ' + className;
}
}
}
export function removeClassName() {
let args = Array.prototype.slice.call(arguments,0);
let elem = args[0];
if(!elem || !isDOMElement(elem)) return;
for(let i = 1; i< args.length;i++){
let className = args[i];
if(isNonNullString(className) && isNonNullString(elem.className)){
var reg = new RegExp('(\\s|^)'+className+'(\\s|$)');
elem.className = elem.className.replace(reg,' ');
elem.className = elem.className.replace(className,"")
}
}
}
Object.defineProperties(global,{
getMaxZindex : {value:getMaxZindex},
addClassNameName : {value : addClassName},
hasClassNameName : {value : hasClassName},
removeClassNameName : {value : removeClassName},
fullscreen : {value:fullscreen},
getViewportSize : {value:getViewportSize},
getAbsolutePosition:{value:getAbsolutePosition},
getViewportOffset : {value:getViewportOffset},
exitFullscreen : {value : exitFullscreen},
isFullScreenCurrently : {value : IsFullScreenCurrently},
getCurrentFullScreenElement : {value : getCurrentFullScreenElement}
})
/**** retourne les enfants direct du dom element, dont le selector sel est passé en paramètre
* @param : elem : l'élément dom dont les enfants seront recherchés
* @param : queryDomSelector : le selecteur dom dont les éléments devront match
* @param : cb : la fonction de rappel à appeler à chaque élément dom trouvé : cette fonction prend en paramètre l'élément et son index dans la liste
* @return : tableau contenant la liste des différents enfants direct de l'élément passé en paramètre
*/
function getDirectChildren(elem, queryDomSelector,cb){
if(!isDOMElement(elem) || !isNonNullString(queryDomSelector)) return [];
if(!(elem.childNodes)) return [];
let ret = [], i = 0, l = elem.childNodes.length;
let nodes = elem.childNodes;
let counterIdx = 0;
cb = defaultFunc(cb);
for (i; i < l; ++i){
if(!isDOMElement(nodes[i])) continue;
if (nodes[i].matches(queryDomSelector)){
if(cb.call(nodes[i],nodes[i],counterIdx,i) === false) continue;
counterIdx++;
ret.push(nodes[i]);
}
}
return ret;
}
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
if(!isNonNullString(s)) return false;
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
Element.prototype.getDirectChildren = function(queryDomSelector,cb){
return getDirectChildren.call(this,queryDomSelector,cb);
}
Element.prototype.setMaxZindex = function(){
let elem = this;
if(!isDOMElement(elem)) return;
let zIndex = getMaxZindex();
elem.style.zIndex = zIndex+"";
}
}
if(typeof Element !== 'undefined' && Element){
/*** si le dom element a une scroll bar */
Element.prototype.hasScrollbar = function(type){
return domElementHasScrollbar(this,type);
}
}
/*** vérifie les scroll bar qu'on un élément dom
* @param element {dom} l'élément à vérifier
* @param type {string} le type de barre à vérifier
*
*/
export const domElementHasScrollbar = (elem,type)=>{
if(!isDOMElement(elem)) return null;
let sc = {
horizontal : elem.scrollWidth > elem.clientWidth,
vertical : elem.scrollHeight > elem.clientHeight
}
type = defaultStr(type).toLowerCase().trim();
if(type in sc){
return sc[type];
}
return sc;
}
global.getDomDirectChildren = getDirectChildren;
export const getScrollParent = global.getScrollParent = global.getParentScroll = (node,includeHidden) => {
const regex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/; ///(auto|scroll)/;
if(!isDOMElement(node)) return document.body;
const parents = (_node, ps) => {
if (_node.parentNode === null) { return ps; }
return parents(_node.parentNode, ps.concat([_node]));
};
const style = (_node, prop) => getComputedStyle(_node, null).getPropertyValue(prop);
const overflow = _node => style(_node, 'overflow') + style(_node, 'overflow-y') + style(_node, 'overflow-x');
const scroll = _node => regex.test(overflow(_node));
/* eslint-disable consistent-return */
const scrollParent = (_node) => {
if (!(_node instanceof HTMLElement || _node instanceof SVGElement)) {
return;
}
const ps = parents(_node.parentNode, []);
for (let i = 0; i < ps.length; i += 1) {
if (scroll(ps[i])) {
return ps[i];
}
}
return document.scrollingElement || document.documentElement;
};
return scrollParent(node);
/* eslint-enable consistent-return */
};
export const getParentScroll = getScrollParent;
export const isNodeList = global.isNodeList = function isNodeList(nodes) {
var stringRepr = Object.prototype.toString.call(nodes);
return typeof nodes === 'object' &&
/^\[object (HTMLCollection|NodeList|Object)\]$/.test(stringRepr) &&
(typeof nodes.length === 'number') &&
(nodes.length === 0 || (typeof nodes[0] === "object" && nodes[0].nodeType > 0));
}
export const findParentFromNodeList = global.findParentFromNodeList = function(nodeList){
if(!isNodeList(nodeList)) return null;
for(let i in nodeList){
if(isDOMElement(nodeList[i]) && isDOMElement(nodeList[i].parentElement)) return nodeList[i].parentElement;
}
return null;
}
export const moveDomInputCursorToEnd = global.moveDomInputCursorToEnd = function (inputElt,focus,title) {
if(!isDOMElement(inputElt)) return;
setTimeout(function () {
if (typeof inputElt.selectionStart == "number") {
inputElt.selectionStart = inputElt.selectionEnd = inputElt.value.length;
} else if (typeof inputElt.createTextRange != "undefined") {
var range = inputElt.createTextRange();
range.collapse(false);
range.select();
}
if(isNonNullString(focus)){
title = defaultStr(title,focus)
}
if(typeof title =="string"){
inputElt.title = title;
}
if(defaultBool(focus,true)){
inputElt.focus();
}
}, 1);
}