Skip to content

Instantly share code, notes, and snippets.

@Error601
Last active August 29, 2015 14:21
Show Gist options
  • Save Error601/68cb013bdf41485b2126 to your computer and use it in GitHub Desktop.
Save Error601/68cb013bdf41485b2126 to your computer and use it in GitHub Desktop.
Useful helper functions inspired by (or lifted from) other libraries.
/*!
* Global general-purpose JavaScript convenience
* utlity helper functions, because the world
* needs yet ANOTHER JavaScript library for
* things that should just be native JavaScript
* methods in the first place!
*
* Some of these functions are taken straight from
* other libraries and transplanted here - thus
* the name 'locash' - a nod to lodash/underscore
* and jQuery.
*
* Methods available under global '_$' and
* 'locash' objects. You may want to set
* _$ = locash in the scope of your functions
* to avoid possible conflicts if you use a library
* that uses _$ as the top-level object/funtion.
*
* Latest source available here:
* https://gist.github.com/Error601/68cb013bdf41485b2126
*/
(function(){
var root = this,
window = root,
_$, locash,
undefined;
root._$ = root.locash = locash = _$ =
firstDefined(root._$, root.locash, {});
function firstDefined(){
var undefined, i = -1;
while (++i < arguments.length) {
if (arguments[i] !== undefined) {
return arguments[i];
}
}
return undefined;
}
_$.firstDefined = firstDefined;
function isDefined(x){
return typeof x != 'undefined'
}
_$.isDefined = isDefined;
function isUndefined(x){
return typeof x == 'undefined'
}
_$.isUndefined = isUndefined;
function isString(str){
return typeof str === 'string';
}
_$.isString = isString;
function stringLower(str){
return str.toString().toLowerCase();
}
_$.stringLower = stringLower;
function stringUpper(str){
return str.toString().toUpperCase();
}
_$.stringUpper = stringUpper;
// split string into array of words using spaces, underscores,
// hyphens, periods, commas, or 'delim' (RegExp) as word delimeters
function splitWords(str, delim){
str = str+'';
delim = delim || /(\s|,|_|\-|\.)+/g;
// insert spaces between words and remove multiple spaces
str = str.replace(delim,' ');
// split on whitespace char.
return str.split(/\s/);
}
_$.splitWords = splitWords;
// convert from camelCase 'textString',
// or underscored 'text_string',
// or space-separated 'text string'
// or period-separated text.string
// or array of separate strings
// to hyphenated 'text-string'
// optionally preserving original case where
// possible and allowing 'other' characters
// 'delim' is optional custom word delimiter
function toDashed(str, other, preserve, delim){
if (isArray(str)){
str = str.join(' ');
// force delim to space if 'str' is array
delim = /\s+/;
}
else {
str = str+'';
}
return splitWords(str, delim).map(function(word){
// add hyphens before capital letters
word = word.replace(/[A-Z]/g, function(c){
return '-' + c;
});
// remove hyphens after capital letters
word = word.replace(/([A-Z]\-)/g, function(c){
return c.replace(/\-$/, '');
});
if (!preserve){
word = word.toLowerCase();
}
if (!other){
word = word.replace(/[^A-Za-z0-9\-]/g, '-');
}
return word;
}).join('-').replace(/\-+/g, '-').replace(/^\-+|\-+$/g, '');
}
_$.toDashed = _$.dashify = _$.dasherize = _$.hyphenize = toDashed;
// convert from hyphenated 'text-string',
// or underscored 'text_string',
// or space-separated 'text string'
// or period-separated text.string
// or array or separate strings
// to camelCase 'textString'
// optionally preserving original case where
// possible and allowing 'other' characters
function toCamelCase(str, other, preserve, delim){
if (isArray(str)){
str = str.join(' ');
// force delim to space if 'str' is array
delim = /\s+/;
}
else {
str = str+'';
}
return splitWords(str, delim).map(function(word, i){
if (!preserve){
word = word.toLowerCase();
}
if (i > 0){
word = word.charAt(0).toUpperCase() + word.substr(1);
}
if (!other){
word = word.replace(/[^A-Za-z0-9]/g, '');
}
return word;
}).join('');
}
_$.toCamelCase = _$.camelCase = _$.camelify = _$.camelize = toCamelCase;
// force only characters after a dash to be
// capitalized when converting to camelCase
// 'Foo-BAR-blah' -> 'fooBarBlah'
function forceCamelCase(str, other){
return toCamelCase(str, other, false);
}
_$.forceCamelCase = _$.forceCamel = _$.toCamelLower = _$.camelLower = forceCamelCase;
function sentenceCase(str){
return str.charAt(0).toUpperCase() + str.slice(1);
}
_$.sentenceCase = _$.capitalize = sentenceCase;
function titleCase(str, force){
var words = (str+'').split(/\s+|_+|\-+/); // allow spaces, underscores, or dashes as word delimiters
return words.map(function(word){
if (isTrue(force)){
word = word.toLowerCase();
}
return word.charAt(0).toUpperCase() + word.slice(1);
}).join(' ');
}
_$.titleCase = titleCase;
function truncateString(str, len, suffix){
str = str+'';
len = len || 30; // default length is 30 chars
if (str.length <= len) {
return str;
}
else {
return str.substring(0, len) + (suffix||'...');
}
}
_$.truncate = _$.truncateString = truncateString;
function isTrue(val){
return stringLower(val || '') === 'true';
}
_$.isTrue = isTrue;
function isFalse(val){
return stringLower(val || '') === 'false';
}
_$.isFalse = isFalse;
// heavy-handed comparison of 2 values as strings
function isEqual(a, b){
if (arguments.length === 2 && typeof a != 'undefined') {
return (a.toString() === b.toString());
}
else {
return undefined;
}
}
_$.isEqual = isEqual;
function isEqualLower(a, b){
return isEqual(stringLower(a || ''), stringLower(b || ''));
}
_$.isEqualLower = isEqualLower;
// returns true for objects, arrays, and null
function isObject( obj ){
return typeof obj == 'object';
}
_$.isObject = isObject;
function isPlainObject(obj){
return Object.prototype.toString.call(obj) === '[object Object]';
}
_$.isPlainObject = isPlainObject;
// return something to attach properties and methods to
function getObject(obj){
if (isFunction(obj) || isPlainObject(obj)) {
return obj;
}
else {
return {};
}
}
_$.getObject = getObject;
function getPlainObject(obj){
return isPlainObject(obj) ? obj : {};
}
_$.getPlainObject = getPlainObject;
function isArray(arr){
if (Array.isArray) {
return Array.isArray(arr);
}
else {
return Object.prototype.toString.call(arr) === '[object Array]';
}
}
_$.isArray = isArray;
function isFunction(func){
return typeof func == 'function';
}
_$.isFunction = isFunction;
function isNumber(num){
return (typeof num == 'number' && !isNaN(num));
}
_$.isNumber = isNumber;
// copy of jQuery's $.isNumeric() method
function isNumeric(num){
// parseFloat NaNs numeric-cast false positives (null|true|false|"")
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
// subtraction forces infinities to NaN
// adding 1 corrects loss of precision from parseFloat (jQuery issue #15100)
return !isArray(num) && (num - parseFloat(num) + 1) >= 0;
}
_$.isNumeric = isNumeric;
function isEmptyArray(arr){
return isArray(arr) && arr.length === 0;
}
_$.isEmptyArray = isEmptyArray;
function isEmptyObject(obj){
var name;
for ( name in obj ) {
return false;
}
return true;
}
_$.isEmptyObject = isEmptyObject;
function isEmpty(x){
if (isPlainObject(x)) {
return isEmptyObject(x);
}
if (isArray(x)) {
return isEmptyArray(x);
}
return (x === '' || x === null || isUndefined(x) || !isFunction(x));
}
_$.isEmpty = isEmpty;
// copy of jQuery's $.extend() method
function extend(){
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if (typeof target === "boolean") {
deep = target;
// skip the boolean and the target
target = arguments[i] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if (typeof target !== "object" && !isFunction(target)) {
target = {};
}
// extend parent object if only one argument is passed
if (i === length) {
target = this;
i--;
}
for (; i < length; i++) {
// Only deal with non-null/undefined values
if ((options = arguments[i]) != null) {
// Extend the base object
for (name in options) {
// don't check for this - extend everything
//if ( !options.hasOwnProperty(name) ) {
// continue;
//}
src = target[name];
copy = options[name];
// Prevent never-ending loop
if (target === copy) {
continue;
}
// Recurse if we're merging plain objects or arrays
if (deep && copy && ( isPlainObject(copy) || (copyIsArray = isArray(copy)) )) {
if (copyIsArray) {
copyIsArray = false;
clone = src && isArray(src) ? src : [];
}
else {
clone = src && isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[name] = extend(deep, clone, copy);
// Don't bring in undefined values
}
else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
// Return the modified object
return target;
}
_$.extend = extend;
// default deep extend
function extendDeep(){
var args = toArray(arguments);
return extend.apply(null, [true].concat(args));
}
_$.extendDeep = extendDeep;
// clone and extend
function extendCopy(){
var args = toArray(arguments);
return extend.apply(null, [{}].concat(args));
}
_$.extendCopy = extendCopy;
// clone and deep extend
function extendCopyDeep(){
var args = toArray(arguments);
return extend.apply(null, [true, {}].concat(args));
}
_$.extendCopyDeep = extendCopyDeep;
// return a deep cloned copy of a single 'obj'
function cloneObject(obj){
return extend(true, {}, obj);
}
_$.cloneObject = cloneObject;
function clone(obj){
if (isPlainObject(obj)){
return extend(true, {}, obj);
}
if (isArray(obj)){
return toArray(obj);
}
if (isFunction(obj)){
return function(){
obj.apply(null, arguments);
}
}
else {
return obj;
}
}
_$.clone = clone;
// return the last item in an array-like object
function getLast(arr){
var undefined;
if (isEmpty(arr)) { return undefined }
if (!arr.length) { return arr }
return arr[arr.length - 1];
}
_$.getLast = getLast;
// make sure we only run a function one time
function once(func, args){
func = func || function(){};
if (func.called) { return }
func.apply(null, args);
func.called = true;
}
_$.once = once;
// execute a function on each item in an
// array(-like) object with a length property
// works like native Array.forEach();
function forEach(arr, fn){
var i = -1, len;
if (!arr || !arr.length) { return }
len = arr.length;
if (isFunction(fn)) {
while (++i < len) {
fn(arr[i], i);
}
}
}
_$.forEach = forEach;
// execute a function on each
// of an object's own properties
// works like jQuery's $.each()
// but only for objects
function forOwn(obj, fn){
var _key;
if (!isObject(obj)) { return }
if (isFunction(fn)) {
for (_key in obj) {
if (obj.hasOwnProperty(_key)) {
fn(_key, obj[_key]);
}
}
}
}
_$.forOwn = forOwn;
// convert array-like object or arguments to a real array
// (twice as fast as Array.prototype.slice.call(arguments))
function toArray(arr){
var i = -1,
len = arr.length,
_args = new Array(len);
while (++i < len) {
_args[i] = arr[i];
}
return _args;
}
_$.toArray = toArray;
// check if 'item' is in an 'arr' array
function inArray(item, arr){
var i = -1,
len = arr.length;
if (!len) {
return false;
}
while (++i < len){
if (arr[i] === item){
return true;
}
}
return false;
}
_$.inArray = inArray;
// remove duplicate values from an array
function dedupeArray(arr){
var out = [],
i = -1,
len = arr.length,
item;
while (++i < len) {
item = arr[i];
if (!inArray(item, out)){
out.push(item);
}
}
return out;
}
_$.dedupeArray = _$.dedupe = dedupeArray;
// set default values for object
function setDefaults(obj, props){
//obj = getObject(obj);
//forOwn(props, function(name, val){
// obj[name] = val;
//});
//return obj;
return extendCopyDeep(obj, props)
}
_$.setDefaults = setDefaults;
// pass an array of values to make sure ALL of them are numbers
// 'numeric' argument indicates allowing numeric *string*: '1'
function allNumbers(arr, numeric){
var len = arr.length,
i = -1,
checkNumber = (numeric) ? isNumeric : isNumber;
if (!isArray(arr)) { return false }
while (++i < len) {
if (!checkNumber(arr[i])) {
return false;
}
}
return true;
}
_$.allNumbers = allNumbers;
// pass an array of values to make sure they're ALL numeric
function allNumeric(arr){
return allNumbers(arr, true);
}
_$.allNumeric = allNumeric;
// pass an array of values to check for at least one number
// 'numeric' argument indicates allowing numeric string
function hasNumber(arr, numeric){
var numbers = 0,
len = arr.length,
i = -1,
checkNumber = (numeric) ? isNumeric : isNumber;
if (!isArray(arr)) { return false }
while (++i < len) {
if (checkNumber(arr[i])) {
numbers += 1;
}
}
return numbers > 0;
}
_$.hasNumber = hasNumber;
// returns number as a string with leading zeros (or other character)
// thanks to - http://stackoverflow.com/a/10073788
// revised here - http://jsfiddle.net/rj0rf5hg/2/
// padNumber( 5 ) //=> '05'
// padNumber( 55, 4 ) //=> '0055'
// padNumber( 555, 6, 'X' ) //=> 'XXX555'
function padNumber(num, size, fill){
// only whole numbers
if (parseInt(num, 10) !== +num) { return num + '' }
num = num + ''; // make sure 'num' is a string
// make sure 'size' is a whole number
// defaults to 2 digits
size = (typeof size != 'undefined') ? parseInt(size, 10) : 2;
fill = fill || '0'; // default fill character is '0'
return (num.length >= size) ? num : new Array(size - num.length + 1).join(fill) + num;
}
_$.padNumber = padNumber;
function zeroPad(num, size, fill){
return padNumber(num, size, fill || '0');
}
_$.zeroPad = zeroPad;
// add commas to numbers
function addCommas(nStr){
nStr += '';
var
x = nStr.split('.'),
x1 = x[0],
x2 = x.length > 1 ? '.' + x[1] : ''
;
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
_$.addCommas = _$.formatNumber = addCommas;
function roundNumber(num, dec){
return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}
_$.roundNumber = roundNumber;
// convert number to file size in KB, MB, GB
// rounded to 'round' decimal places
function sizeFormat(size, round){
var KB = 1024,
MB = KB * KB,
GB = MB * KB,
TB = GB * KB;
// round to 2 decimal places by default
round = round || 2;
if (size >= TB) {
return roundNumber(size / TB, round) + ' TB';
}
if (size >= GB) {
return roundNumber(size / GB, round) + ' GB';
}
if (size >= MB) {
return roundNumber(size / MB, round) + ' MB';
}
if (size >= KB) {
return roundNumber(size / KB, round) + ' KB';
}
return size + ' B';
}
_$.sizeFormat = _$.dataSize = sizeFormat;
function randomID(prefix, seq){
window.autoIDcount = window.autoIDcount || 0;
window.autoIDs = window.autoIDs || [];
var pre = (isDefined(prefix)) ? prefix : 'i';
var i = (isUndefined(seq) || isTrue(seq)) ? padNumber(++window.autoIDcount, 4) : '';
var newID = pre + i + '-' + (Math.random() + 1).toString(36).substr(2, 8);
window.autoIDs.push(newID);
window.randomIDcount = window.autoIDcount;
window.randomIDs = window.autoIDs;
return newID;
}
window.autoID = window.randomID = randomID;
_$.randomID = _$.randomId = _$.autoID = _$.autoId = randomID;
// enhanced encodeURIComponent() that
// replaces more non-word characters
function encodeURIComponentAll(str){
return encodeURIComponent(str).replace(/[!'()*]/g, function(c){
return '%' + c.charCodeAt(0).toString(16);
});
}
_$.encodeURIComponentAll = _$.encodeURIComponent = _$.betterEncodeURIComponent = encodeURIComponentAll;
var supportsDataset = !!(document.head && document.head.dataset);
function setElementData(element, name, val){
if (supportsDataset) {
element.dataset[toCamelCase(name)] = val;
}
else {
element.setAttribute('data-' + toDashed(name), val);
}
}
_$.setElementData = setElementData;
function getElementData(element, name){
if (supportsDataset) {
return element.dataset[toCamelCase(name)];
}
else {
return element.getAttribute('data-' + toDashed(name));
}
}
_$.getElementData = getElementData;
function elementData(element, name, val){
if (isDefined(val)){
return setElementData(element, name, val);
}
return getElementData(element, name);
}
_$.elementData = _$.elData = _$._data = elementData;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment