damon-utils
Version:
A post-processing library for DAMON
282 lines (256 loc) • 8.96 kB
JavaScript
module.exports = function (document) {
this.document = document;
return {
// For sanity's sake
// # Nil
// I like the NOT operator's conciseness when testing for null or undefined
// I like strict type checking
// So I made a strictly typed equivalent functions with:
// - 3-letters name
// - single argument
/**
* Nil
* Neither null nor undefined
* @param { boolean } exp
* @returns { boolean }
*/
nil(exp) { // values implicitly considered functions
if (
exp === null
|| typeof exp === 'undefined'
) {
return true;
} else {
return false;
}
},
// # Hack
// .slice() uses a closed-open interval
// the *sane* convention goes closed-closed
/**
* Hack
* @param { number } start
* @param { number } end
* @returns
*/
hack(array, start, end) {
return array.slice(start, end + 1);
},
// # Prune/Pick
// Javascript inherited spreadsheet-like .filter()
// It felt confusing there
// It feels confusing here too
/**
* Pick
* @param {*} array
* @param {*} pruningFunction
* @returns
*/
pick(array, pruningFunction) {
return array.filter(pruningFunction);
},
/**
* Prune
* The inverse of filter()
* @param {*} array
* @param {*} filteringFunction
* @returns
*/
prune(array, filteringFunction) {
return array.filter(function (x) {
return !filteringFunction(x);
});
},
// # Check
// .every() just sounds weird
/**
* Check
* @param {*} array
* @param {*} checkingFunction
* @returns
*/
check(array, checkingFunction) {
return array.every(checkingFunction);
},
/**
* Escape
* @param { string } string
* @returns
*/
escape(string) {
return string
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
},
/**
* DOM-rendering template tag
* @param {*} strings
* @returns {object} a DocumentFragment
*/
html(strings) {
let output = strings[0], // assumes empty string start?
max = Math.max(strings.length, arguments.length - 1);
for (let i = 1; i < max; i++) {
output += arguments[i];
output += strings[i];
}
let fragment = document.createDocumentFragment();
fragment.innerHTML = output;
return fragment;
},
// # DATA-STATE
// Alternative CSS state management with data-attributes rather than classes
// - using data-attributes css selectors instead of classes in dynamic cases fits the MVC pattern better
// - makes it easier to match model and vue in css and html
// - using dataset instead of classlist allows to distinguish static .class from dynamic state
// - classes essentialy work as booleans types like ".walked"
// - you have to notice their abscence, amongst other potential use of .class
// - data-state work as a string type you can dedicate to store state only, and more than one state
/**
* Add
* @param { object } element
* @param { string } state
*/
addDataState(element, state) {
let stateArray = [];
if (
element.dataset.state
&& element.dataset.state.indexOf(' ') > -1
) {
stateArray = element.dataset.state.split(' ');
} else {
stateArray = [element.dataset.state];
}
if (stateArray.indexOf(state) === -1) {
stateArray.push(state);
element.dataset.state = stateArray.join(' ');
}
},
/**
* Remove
* @param { object } element
* @param { string } state
*/
removeDataState(element, state) {
let stateArray = [];
if (
element.dataset.state
&& element.dataset.state.indexOf(' ') > -1
) {
stateArray = element.dataset.state.split(' ');
} else {
stateArray = [element.dataset.state];
}
element.dataset.state =
stateArray
.filter(element => (element !== state))
.join(' ');
},
/**
* Replace
* @param { object } element
* @param { string } stateToRemove
* @param { string } stateToAdd
*/
replaceDataState(element, stateToRemove, stateToAdd) {
this.removeDataState(element, stateToRemove);
this.addDataState(element, stateToAdd);
},
/**
* Toggle
* @param { object } element
* @param { string } state
*/
toggleDataState(element, state) {
let stateArray = element.dataset.state.split(' ');
if (stateArray.indexOf(state) == -1) {
this.addDataState(element, state);
} else {
this.removeDataState(element, state);
}
},
//# AJAX Functions
/**
* AJAX GET
* @param {string} url The target url
* @param {function} callback
* @param {boolean} isJson Response contains json
* @param {object} callbackContext
*/
ajaxGet(url, callback, isJson, callbackContext) {
var req = new XMLHttpRequest();
req.open("GET", url);
req.addEventListener("load", function () {
if (req.status >= 200 && req.status < 400) {
if (isJson) {
// Transforme la donnée du format JSON vers le format texte avant le callback
var json = {};
try {
json = JSON.parse(req.responseText);
} catch (error) {
console.error("Get request returned invalid JSON.")
}
callbackContext === undefined ? callback(json) : callback.apply(callbackContext, [json]);
} else {
// Appelle la fonction callback en lui passant la réponse de la requête
callbackContext === undefined ? callback(req.responseText) : callback.apply(callbackContext, [req.responseText]);
}
} else {
console.error(req.status + " " + req.statusText + " " + url);
}
});
req.addEventListener("error", function () {
console.error("Erreur réseau avec l'URL " + url);
});
req.send(null);
},
/**
* Exécute un appel AJAX POST
* Prend en paramètres l'URL cible, la donnée à envoyer et la fonction callback appelée en cas de succès
* Le paramètre isJson permet d'indiquer si l'envoi concerne des données JSON
* @param {string} url
* @param {string} data
* @param {function} successCallback
* @param {function} failureCallback
* @param {boolean} isJson
* @param {object} successCallbackContext
* @param {object} failureCallbackContext
*/
ajaxPost(url, data, successCallback, failureCallback, isJson, successCallbackContext, failureCallbackContext) {
var req = new XMLHttpRequest();
req.open("POST", url);
req.addEventListener("load", function () {
if (req.status >= 200 && req.status < 400) {
// Appelle la fonction callback en lui passant la réponse de la requête
successCallbackContext === undefined ? successCallback(req) : successCallback.apply(successCallbackContext, [req]);
} else {
// Appelle la fonction callback en lui passant la réponse de la requête
failureCallbackContext === undefined ? failureCallback(req) : failureCallback.apply(failureCallbackContext, [req]);
console.error(req.status + " " + req.statusText + " " + url);
}
});
req.addEventListener("error", function () {
console.error("Erreur réseau avec l'URL " + url);
});
if (isJson) {
// Définit le contenu de la requête comme étant du JSON
req.setRequestHeader("Content-Type", "application/json");
// Transforme la donnée du format JSON vers le format texte avant l'envoi
data = JSON.stringify(data);
}
req.send(data);
},
/**
* Pipe
* Function piping with initial input
* @param {*} functions
* @param {*} input
* @returns {*}
*/
pipe(input, ...functions) {
return functions.reduce((res, fun) => fun(res), input);
}
};};