Skip to content

Instantly share code, notes, and snippets.

@Mandorlo
Last active April 1, 2020 09:44
Show Gist options
  • Save Mandorlo/dc3fe5ec1509772bb89bb6630cd83db9 to your computer and use it in GitHub Desktop.
Save Mandorlo/dc3fe5ec1509772bb89bb6630cd83db9 to your computer and use it in GitHub Desktop.
Useful functions for html
/**
* 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