(function (global, Str) {
"use strict";
// region [ Private Functions ]
/**
* Test if the specified object is an array.
* @param obj {Array|object}
* @returns {boolean}
* @private
*/
function _isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
/**
* Convert json string into js object.
* @param s
* @private
*/
function _parseJson(s) {
var _parser;
if (typeof global.JSON !== 'undefined') {
_parser = global.JSON.parse;
}
else if (typeof window.jQuery !== 'undefined') {
_parser = window.jQuery.parseJSON;
}
if (typeof _parser === 'undefined') {
throw 'Undefined JSON method';
}
return _parser(s);
}
// endregion
/**
* Check for undefined, null, zero length, blanks or s is false.
* @param s {string|object} - string, array or object to test.
* @returns {boolean}
* Unit Test: http://jsfiddle.net/wao20/TGP3N/
*/
Str.empty = function (s) {
// s == undefined <= double equals is deliberate, check for null and undefined
return !!(s == undefined
|| s.length === 0
|| Str.trim(s).length === 0
|| !s);
};
/**
* Compare two strings
* @param s1 {?string}
* @param s2 {?string}
* @param caseSensitive {boolean=}
* @returns {boolean}
*/
Str.equals = function (s1, s2, caseSensitive) {
if (s1 == undefined || s2 == undefined) {
return false;
}
if (caseSensitive) {
return s1 == s2;
}
return s1.toLowerCase() == s2.toLowerCase();
};
/**
* empty(), '0', '0.0', 'false' => false. Otherwise return !!s.
*
* @param s {?string}
* @returns {boolean}
*/
Str.boolVal = function (s) {
if (Str.empty(s)) {
return false;
}
s = Str.trim(s).toLowerCase();
if (s == '0' || s == '0.0' || s == 'false') {
return false;
}
return !!s;
};
/**
* Escape the string to be use as a literal in regex expression.
*
* @param s {string|Array}
* @returns {string|Array}
*/
Str.regexEscape = function (s) {
if (!s) {
return '';
}
if (typeof s === 'string') {
return s.replace(/([.?*+\^$\[\]\\(){}|\-])/g, '\\$1');
}
else if (_isArray(s)) {
var result = [], i;
for (i = 0; i < s.length; i++) {
result.push(Str.regexEscape(s[i]));
}
return result;
}
return s;
};
/**
* Tests whether the beginning of a string matches pattern.
*
* @param s {string}
* @param pattern {string} - to find
* @param caseSensitive {boolean=}
* @return {boolean}
*/
Str.startsWith = function (s, pattern, caseSensitive) {
if (caseSensitive) {
return s.indexOf(pattern) === 0;
}
return s.toLowerCase().indexOf(pattern.toLowerCase()) === 0;
};
/**
* Test if string ends with specified pattern
* @param s {string}
* @param pattern {string}
* @param caseSensitive {boolean=}
* @returns {boolean}
*/
Str.endsWith = function (s, pattern, caseSensitive) {
var d = s.length - pattern.length;
if (caseSensitive) {
return d >= 0 && s.lastIndexOf(pattern) === d;
}
return d >= 0 && s.toLowerCase().lastIndexOf(pattern.toLowerCase()) === d;
};
/**
* Check if the string contains a substring.
* @param s {string}
* @param needle {string}
* @param caseSensitive {boolean=}
* @return {boolean}
*/
Str.contains = function (s, needle, caseSensitive) {
if (Str.empty(s) || Str.empty(needle)) {
return false;
}
if (caseSensitive) {
return s.indexOf(needle) > -1;
}
return s.toLowerCase().indexOf(needle.toLowerCase()) > -1;
};
/**
* Must contains all the element in the array.
* @param s {string}
* @param needles {Array|string}
* @param caseSensitive {boolean=}
* @return {boolean}
*/
Str.containsAll = function (s, needles, caseSensitive) {
var i = 0;
if (_isArray(needles)) {
for (i = 0; i < needles.length; i++) {
if (!Str.contains(s, needles[i], caseSensitive)) {
return false;
}
}
return true;
}
return Str.contains(s, needles, caseSensitive);
};
/**
* Must contains ANY the element in the array.
* @param s {string}
* @param needles {Array|string}
* @param caseSensitive {boolean=}
* @return {boolean}
*/
Str.containsAny = function (s, needles, caseSensitive) {
var i;
if (_isArray(needles)) {
for (i = 0; i < needles.length; i++) {
if (Str.contains(s, needles[i], caseSensitive)) {
return true;
}
}
return false;
}
return Str.contains(s, needles, caseSensitive);
};
/**
* Determine if the specified variable is a string
* @param o
* @returns {boolean}
*/
Str.isString = function (o) {
return typeof o === 'string';
};
/**
* Trims white space from the beginning and end of a string.
* @param s {string}
* @param c {string=}
* @return {string}
*/
Str.trim = function (s, c) {
if (!Str.isString(s)) {
return s;
}
if (c == undefined || c == ' ') {
if (String.prototype.trim) {
return String.prototype.trim.call(s);
}
return s.replace(/^\s+/, '').replace(/\s+$/, '');
}
return Str.trimStart(Str.trimEnd(s, c), c);
};
/**
* Remove chars/Str from the start of the string
* @param s
* @param c {string|Array=} - supports Str.trimStart(s, ['0x0', '0', 'x']);
*/
Str.trimStart = function (s, c) {
if (c == undefined || c == '') {
return s.replace(/^\s+/, '');
}
var trims = c, regex, result;
if (!_isArray(c)) {
trims = [c];
}
trims = Str.regexEscape(trims).join('|');
regex = '^(' + trims + '|\s)+';
regex = new RegExp(regex, 'g');
result = s.replace(regex, '');
return result;
};
/**
* Remove chars/Str(s) from the end of the string
* @param s {string}
* @param c {string|Array=} - supports Str.trimEnd(s, ['0x0', '0', 'x']);
*/
Str.trimEnd = function (s, c) {
if (c == undefined) {
return s.replace(/\s+$/, '');
}
var trims = c, regex, result;
if (!_isArray(c)) {
trims = [c];
}
trims = Str.regexEscape(trims).join('|');
regex = '(' + trims + '|\s)+$';
regex = new RegExp(regex, 'g');
result = s.replace(regex, '');
return result;
};
/**
* Extended substring, support negative index (ordinal js substr(startIndex, endIndex))
*
* @param s {string}
* @param index {number} - if negative take string from the right similar to php substr()
* @param len {number=} - number of char to take starting from the index to the right (even when index is negative)
* @return {string}
*/
Str.subStr = function (s, index, len) {
if (s == undefined) {
return '';
}
len = len || 0;
if (Math.abs(index) > s.length) {
return s;
}
// regular substring
if (index > -1) {
if (len > 0 && (index + len) < s.length) {
return s.substring(index, index + len);
}
return s.substring(index);
}
// Negative index, take string from the right
// Index is negative => subStr ('hello', -3) => 'llo'
var start = s.length + index;
if (len > 0 && (start + len) < s.length) {
return s.substring(start, start + len);
}
return s.substring(start);
};
/**
* Count number of occurrences of an substring.
* @param s {string} - the big string
* @param sub {string} - the little string you want to find.
* @param caseSensitive {boolean=}
* @returns {number}
*/
Str.subCount = function (s, sub, caseSensitive) {
sub = Str.regexEscape(sub);
if (caseSensitive) {
return s.split(sub).length - 1;
}
return s.toLowerCase().split(sub.toLowerCase()).length - 1;
};
/**
* Concatenate count number of copies of s together and return result.
* @param s {string}
* @param count {number} - Number of times to repeat s
* @return {string}
*/
Str.repeat = function (s, count) {
var result = '', i;
for (i = 0; i < count; i++) {
result += s;
}
return result;
};
/**
* Pad left
*
* @param s {!string}
* @param padStr {!string} - the padding
* @param totalLength {!number} - the final length after padding
* @return {string}
*/
Str.padLeft = function (s, padStr, totalLength) {
return s.length >= totalLength ? s : Str.repeat(padStr, (totalLength - s.length) / padStr.length) + s;
};
/**
* Pad right
*
* @param s {string}
* @param padStr {string} - the padding
* @param totalLength {number} - the final length after padding
* @return {string}
*/
Str.padRight = function (s, padStr, totalLength) {
return s.length >= totalLength ? s : s + Str.repeat(padStr, (totalLength - s.length) / padStr.length);
};
/**
* Pad string based on the boolean value.
*
* @param s {string}
* @param padStr {string} - the padding
* @param totalLength {number} - the final length after padding
* @param padRight {boolean} - pad right if true, pad left otherwise
* @return {string}
*/
Str.pad = function (s, padStr, totalLength, padRight) {
if (padRight) {
return Str.padRight(s, padStr, totalLength);
}
return Str.padLeft(s, padStr, totalLength);
};
/**
* Strips any HTML tags from the specified string.
* @param s {string}
* @return {string}
*/
Str.stripTags = function (s) {
return s.replace(/<\/?[^>]+>/gi, '');
};
/**
* escapeHTML from Prototype-1.6.0.2 -- If it's good enough for Webkit and IE, it's good enough for Gecko!
* Converts HTML special characters to their entity equivalents.
*
* @param s {string}
* @return {string}
*/
Str.escapeHTML = function (s) {
s = s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return s;
};
/**
* unescapeHTML from Prototype-1.6.0.2 -- If it's good enough for Webkit and IE, it's good enough for Gecko!
* Strips tags and converts the entity forms of special HTML characters to their normal form.
*
* @param s {string}
* @return {string}
*/
Str.unescapeHTML = function (s) {
return Str.stripTags(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
};
/**
* Remove all Viet's accents and replace it with the latin based alphabet
* @param s {string}
* @return {string}
*/
Str.stripViet = function (s) {
/*
data = data.replace(/[àáâãăạảấầẩẫậắằẳẵặ]/g, 'a');
data = data.replace(/[òóôõơọỏốồổỗộớờởỡợ]/g, 'o');
data = data.replace(/[èéêẹẻẽếềểễệ]/g, 'e');
data = data.replace(/[ùúũưụủứừửữự]/g, 'u');
data = data.replace(/[ìíĩỉị]/g, 'i');
data = data.replace(/[ýỳỵỷỹ]/g, 'y');
data = data.replace(/[đðĐ]/g, 'd');
*/
if (Str.empty(s)) {
return s;
}
s = s.replace(/[\u00E0\u00E1\u00E2\u00E3\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7]/g, 'a');
s = s.replace(/[\u00F2\u00F3\u00F4\u00F5\u01A1\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3]/g, 'o');
s = s.replace(/[\u00E8\u00E9\u00EA\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7]/g, 'e');
s = s.replace(/[\u00F9\u00FA\u0169\u01B0\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1]/g, 'u');
s = s.replace(/[\u00EC\u00ED\u0129\u1EC9\u1ECB]/g, 'i');
s = s.replace(/[\u00FD\u1EF3\u1EF5\u1EF7\u1EF9]/g, 'y');
s = s.replace(/[\u0111\u00F0\u0110]/g, 'd');
return s;
};
/**
* Use this to constructs multi lines string
*
* eg. Str.multiLines(true,
* 'hello',
* 'world'
* );
* returns: "hello\nworld"
*
* @param glue {string} - the separator between each line (eg. '\n', ', ' or ' ')
* @param args {...string} - each line
*/
Str.multiLines = function (glue, args) {
args = Array.prototype.splice.call(arguments, 1);
return args.join(glue);
};
/**
* Try to parse the json, if valid return the object else return defaultValue
*
* @param s {string} - json string
* @param defaultValue {boolean|object=} - if not specified defaultValue=false
* @returns {boolean|object}
*/
Str.parseJson = function (s, defaultValue) {
defaultValue = defaultValue === undefined ? false : defaultValue;
if (Str.empty(s)) {
return defaultValue;
}
try {
if (typeof s === 'string') {
return _parseJson(s);
}
// it already an object
return s;
}
catch (err) {
return defaultValue;
}
};
/**
* Escape the attribute, make sure it doesn't break the attribute select or to be use a an attribute.
* @param s {string} - the string
*/
Str.escapeAttribute = function (s) {
return s.replace(/"/g, '\\"');
};
/**
* Reverse the string.
*
* @param s
* @returns {*}
*/
Str.reverse = function (s) {
if (s) {
return s.split('').reverse().join('');
}
return s;
};
/**
* Get all the matched based on the specified group.
*
* @param s {string}
* @param regex {RegExp}
* @param index {Number} - the index of the match.
* @returns {Array}
*/
Str.matchAll = function (s, regex, index) {
var m, result = [];
index = index || 0;
if (!s) {
return [];
}
while (m = regex.exec(s)) {
result.push(m[index]);
}
return result;
};
/**
* Split the string into multiple smaller chunks.
*
* @param s
* @param chunkSize
* @returns {Array}
*/
Str.chop = function (s, chunkSize) {
var regex;
if (!s) {
return [];
}
regex = new RegExp('.{1,' + chunkSize + '}', 'g');
return s.match(regex);
};
function _getWords(s) {
s = s.replace(/(\w)([A-Z][a-z])/, '$1-$2');
s = s.replace(' ', '-');
s = s.replace('_', '-');
s = s.replace(/-+/g, '-');
return s.split('-')
}
/**
* Convert any string to camel case.
*
* @param s
*/
Str.toCamelCase = function (s) {
var words = _getWords(s), result = '', i, word;
for (i = 0; i < words.length; i++) {
word = words[i];
if (i == 0) {
result += word.toLowerCase();
}
else {
result += word.charAt(0).toUpperCase() + word.substr(1).toLowerCase();
}
}
return result;
};
/**
* Convert any string to title case.
*
* @param s
*/
Str.toTitleCase = function (s) {
var words = _getWords(s), result = '', i, word;
for (i = 0; i < words.length; i++) {
word = words[i];
result += word.charAt(0).toUpperCase() + word.substr(1).toLowerCase() + ' ';
}
return Str.trimEnd(result);
};
/**
* Convert any string to snake case.
*
* @param s
*/
Str.toSnakeCase = function (s) {
var words = _getWords(s), result = '', i, word;
for (i = 0; i < words.length; i++) {
word = words[i];
result += word.toLowerCase() + '_';
}
return Str.trimEnd(result, '_');
};
/**
* Convert any string to-kebab-case.
*
* @param s
*/
Str.toKebabCase = function (s) {
var words = _getWords(s), result = '', i, word;
for (i = 0; i < words.length; i++) {
word = words[i];
result += word.toLowerCase() + '-';
}
return Str.trimEnd(result, '-');
};
}(window, window._Str = {}));