Last active
April 1, 2020 09:44
-
-
Save Mandorlo/dc3fe5ec1509772bb89bb6630cd83db9 to your computer and use it in GitHub Desktop.
Useful functions for html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* waits for fn_cond() to return truthy value and then executes fn_exec() | |
*/ | |
function retry(fn_cond, fn_exec, max_retries = -5) { | |
if (max_retries == 0) return; | |
if (fn_cond()) return fn_exec(); | |
return setTimeout(_ => retry(fn_cond, fn_exec, max_retries-1), 100); | |
} | |
/** | |
* The main function to handle loading | |
* To use this, place an element somewhere with display:none (a spinner or anything to indicate loading) | |
* the element should have the attribute loader-for="target_id" where target_id is the id of the html element that is loading | |
* when the element should start loading, call loader = loading(target) or loading('#loading_id') | |
* then when loading is finished, call loader.stop() | |
* if sthg went wrong, loader = null | |
* | |
* @param string|jqueryElement target the target element, can be a selector or a jQuery html element | |
* @param {*} opt the loading options | |
* | |
* @return null|{loading:function->bool, stop:function} object to stop loading | |
*/ | |
function loading(target, opt = {}) { | |
// init and options | |
if (typeof target == 'string') target = $(target); | |
opt = ccnObjectAssign({ | |
'hide_target_while_loading': true, | |
'delay': 200, // ms | |
'onloading': null, // function executed on loading = true | |
'onstop': null, // function executed when loading finishes | |
}, opt); | |
// get the target id | |
let target_id = target.attr('id'); | |
if (!target_id) return null; | |
// get the corresponding loader | |
let loader = $(`[loader-for*='${target_id}']`); | |
// activate loader | |
let loading = true; | |
setTimeout(_ => { | |
if (!loading) return; | |
if (opt && typeof opt.onloading == "function") return opt.onloading(); | |
if (opt && opt.hide_target_while_loading) target.hide(); | |
if (loader.length) loader.show(); | |
}, (opt) ? opt.delay : 200) | |
// return the loader object | |
return { | |
loading: () => loading, | |
stop: function() { | |
if (!loading) return; | |
loading = false; | |
if (opt && typeof opt.onstop == 'function') return opt.onstop(); | |
if (opt && opt.hide_target_while_loading) target.show(); | |
if (loader.length) loader.hide(); | |
} | |
} | |
} | |
/** | |
* selects the text inside the element | |
* (and copy it to clipboard if copy = true) | |
* | |
* @param string|HtmlElement node the target element : either a string selector or an Html element | |
* @param bool copy copy text to clipboard or not | |
*/ | |
function selectText(node, copy = true) { | |
if (typeof node == 'string') node = $(node)[0]; | |
if (document.body.createTextRange) { | |
const range = document.body.createTextRange(); | |
range.moveToElementText(node); | |
range.select(); | |
if (copy) {$(node).select(); document.execCommand('copy')}; | |
} else if (window.getSelection) { | |
const selection = window.getSelection(); | |
const range = document.createRange(); | |
range.selectNodeContents(node); | |
if (copy) {$(node).select(); document.execCommand('copy')}; | |
selection.removeAllRanges(); | |
selection.addRange(range); | |
} else { | |
console.warn("Could not select text in node: Unsupported browser."); | |
} | |
} | |
/** | |
* Sets a cookie | |
* | |
* @param string cname cookie name | |
* @param string cvalue cookie value | |
* @param int exdays number of days of validity | |
*/ | |
function setCookie(cname, cvalue, exdays) { | |
var d = new Date(); | |
d.setTime(d.getTime() + (exdays*24*60*60*1000)); | |
var expires = "expires="+ d.toUTCString(); | |
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; | |
} | |
function getCookie(cname, return_val = null) { | |
let m = (new RegExp(cname+'\s*\=([^\;]+)', 'g')).exec(document.cookie); | |
if (m && m.length > 1) return m[1]; | |
return return_val; | |
} | |
/** | |
* Adds a script to the document | |
* | |
* @param string url | |
* | |
* @return Promise<void> that resolves | |
*/ | |
async function addScript(url) { | |
if (scriptLoaded(url)) return true; | |
let sc = document.createElement('script'); | |
sc.setAttribute('src', url); | |
return new Promise((resolve, reject) => { | |
document.head.appendChild(sc); | |
sc.onload = () => resolve(true); | |
}) | |
} | |
function scriptLoaded(url) { | |
let scripts = document.getElementsByTagName('script'); | |
for (var i = scripts.length; i--;) { | |
if (scripts[i].src == url) return true; | |
} | |
return false; | |
} | |
/** | |
* Adds a css stylesheet dynamically | |
* TODO : check if css already exist | |
* | |
* @param string fileName the path to the CSS stylesheet | |
*/ | |
function addCss(fileName) { | |
var link = $("<link />",{ | |
rel: "stylesheet", | |
type: "text/css", | |
href: fileName | |
}) | |
$('head').append(link); | |
} | |
/** | |
* Removes a CSS stylesheet from the head | |
* | |
* @param string fileName the path to the CSS stylesheet | |
*/ | |
function removeCss(fileName) { | |
jQuery('link').each(function(){ | |
if (jQuery(this).attr('href').indexOf(fileName) >= 0) $(this).remove(); | |
}) | |
} | |
/** | |
* Checks if we are on smartphone/mobile based on the navigator user agent | |
* | |
* @return bool true if smartphone/mobile detected | |
*/ | |
function isMobile() {return isSmartphone();} | |
function isSmartphone() { | |
return navigator.userAgent.match(/Android/i) | |
|| navigator.userAgent.match(/webOS/i) | |
|| navigator.userAgent.match(/iPhone/i) | |
|| navigator.userAgent.match(/iPad/i) | |
|| navigator.userAgent.match(/iPod/i) | |
|| navigator.userAgent.match(/BlackBerry/i) | |
} | |
/** | |
* @return string the current season of the year | |
*/ | |
function getSeason() { | |
let curr = parseInt(moment().format('MMDD')); | |
if (curr >= 1222 || curr <= 320) return "winter"; | |
if (321 <= curr && curr <= 620) return "spring"; | |
if (621 <= curr && curr <= 922) return "summer"; | |
if (923 <= curr && curr <= 1221) return "autumn"; | |
} | |
String.prototype.hashCode = function() { | |
var hash = 0, i, chr; | |
if (this.length === 0) return hash; | |
for (i = 0; i < this.length; i++) { | |
chr = this.charCodeAt(i); | |
hash = ((hash << 5) - hash) + chr; | |
hash |= 0; // Convert to 32bit integer | |
} | |
return hash; | |
}; | |
/** | |
* runs an ajax request and returns a Promise | |
*/ | |
function request(url, opt = {}) { | |
opt = Object.assign({ | |
method: 'GET', | |
'content-type': "application/x-www-form-urlencoded", | |
type: 'html', // | 'json' | |
data: null, | |
}, opt) | |
opt.type = opt.type.toLowerCase(); | |
opt.method = opt.method.toUpperCase(); | |
if (opt.type === 'json') opt.['content-type'] = 'application/json'; | |
let xhttp = new XMLHttpRequest(); | |
return new Promise((resolve, reject) => { | |
xhttp.onreadystatechange = function() { | |
if (this.readyState == 4 && this.status == 200) { | |
if (opt.type == 'json') return resolve(JSON.parse(this.responseText)); | |
resolve(this.responseText); | |
} | |
}; | |
xhttp.open(opt.method, url, true); | |
xhttp.setRequestHeader("Content-type", opt['content-type']); | |
if (opt.data) (typeof opt.data === 'string') ? xhttp.send(opt.data) : xhttp.send(buildFormData(opt.data)); | |
else xhttp.send(); | |
}) | |
function buildFormData(d) { | |
let data = new FormData(); | |
for (let attr in d) { | |
data.append(attr, d[attr]); | |
} | |
return data; | |
} | |
} | |
/** | |
* Returns url get parameters | |
*/ | |
function getUrlVars() { | |
var vars = {}; | |
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { | |
vars[key] = value; | |
}); | |
return vars; | |
} | |
/** | |
* Generates a nice id | |
*/ | |
function generate_id(opt = {}) { | |
opt = Object.assign({ | |
"sep": "-", | |
"not_in": [], // list of forbidden ids | |
"suffix": () => Math.round(Math.random() * 1000) | |
}, opt) | |
let positive_adjectives = ['adorable', 'amazing', 'amusing', 'authentic', 'awesome', 'beautiful', 'beloved', 'blessed', 'brave', 'brilliant', 'calm', 'caring', 'charismatic', 'cheerful', 'charming', 'compassionate', 'creative', 'cute', 'diligent', 'diplomatic', 'dynamic', 'enchanted', 'enlightened', 'enthusiastic', 'fabulous', 'faithful', 'fearless', 'forgiving', 'friendly', 'funny', 'generous', 'genuine', 'graceful', 'gracious', 'happy', 'honest', 'incredible', 'inspired', 'intelligent', 'jovial', 'kind', 'lively', 'loyal', 'lucky', 'mindful', 'miraculous', 'nice', 'noble', 'original', 'peaceful', 'positive', 'precious', 'relaxed', 'sensitive', 'smart', 'splendid', 'strong', 'successful', 'tranquil', 'trusting', 'vivacious', 'wise', 'zestful']; | |
let names = ['fractal', 'narval', 'lynx', 'unicorn', 'magnolia', 'hibiscus', 'almondtree', 'lion', 'tiger', 'eagle', 'falcon', 'mustang', 'gibbon', 'koala', 'firefox', 'meerkat', 'ibex', 'whale', 'bear', 'heron', 'quetzal', 'salamander', 'ringtail', 'ocelot', 'pangolin', 'yak', 'beaver']; | |
let gen_id = function() { | |
let id = pick(positive_adjectives) + opt.sep + pick(names); | |
if (opt.suffix) id += opt.sep + (typeof opt.suffix == 'function' ? opt.suffix() : opt.suffix); | |
return id; | |
} | |
let id = gen_id(); | |
while (opt.not_in.includes(id)) {id = gen_id()} | |
return id; | |
} | |
function pick(liste, ind = 1) { | |
if (Array.isArray(liste)) return pick_list(liste, ind); | |
// TODO for object/dict | |
} | |
function pick_list(arr, ind = 1) { | |
liste = arr.slice(); | |
ind = Math.min(ind, liste.length); | |
let res = []; | |
while (ind > 0) { | |
let n = Math.floor(Math.random() * liste.length); | |
res.push(liste[n]); | |
delete liste[n]; | |
ind--; | |
} | |
if (res.length == 1) return res[0]; | |
return res; | |
} | |
/** | |
* pinger un serveur http en requêtant une image (pour contourner le mixed-content error si on requête un serveur http et non https) | |
* @return Promise(true|false) | |
*/ | |
function checkHttp(url) { | |
return new Promise(function(resolve, reject) { | |
let img = new Image(); | |
img.onload = _ => resolve(true); | |
img.onerror = _ => resolve(false); | |
img.src = url + '?random-no-cache=' + Math.floor((1 + Math.random()) * 0x10000).toString(16); | |
setTimeout(_ => resolve(false), 5000); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment