itsa-jsext
Version:
Extensions to native javascript-objects, all within the itsa_ namespace
282 lines (259 loc) • 11 kB
JavaScript
/**
*
* Pollyfils for often used functionality for Strings
*
* <i>Copyright (c) 2014 ITSA - https://github.com/itsa</i>
* New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
*
* @module js-ext
* @submodule lib/string.js
* @class String
*
*/
"use strict";
(function(StringPrototype) {
var SUBREGEX = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
DATEPATTERN = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z/,
WHITESPACE_CLASS = "[\\s\uFEFF\xA0]+",
TRIM_LEFT_REGEX = new RegExp("^" + WHITESPACE_CLASS),
TRIM_RIGHT_REGEX = new RegExp(WHITESPACE_CLASS + "$"),
TRIMREGEX = new RegExp(TRIM_LEFT_REGEX.source + "|" + TRIM_RIGHT_REGEX.source, "g"),
PATTERN_EMAIL = new RegExp("^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]\\.)+[a-zA-Z]{2,}$"),
PATTERN_URLEND = "([a-zA-Z0-9]+\\.)*(?:[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]\\.)+[a-zA-Z]{2,}(/[\\w-]+)*$",
PATTERN_URLHTTP = new RegExp("^http://"+PATTERN_URLEND),
PATTERN_URLHTTPS = new RegExp("^https://"+PATTERN_URLEND),
PATTERN_URL = new RegExp("^(https?://)?"+PATTERN_URLEND),
PATTERN_INTEGER = /^(([-]?[1-9][0-9]*)|0)$/,
PATTERN_FLOAT_START = "^([-]?(([1-9][0-9]*)|0))?(\\",
PATTERN_FLOAT_END = "[0-9]+)?$",
PATTERN_FLOAT_COMMA = new RegExp(PATTERN_FLOAT_START + "," + PATTERN_FLOAT_END),
PATTERN_FLOAT_DOT = new RegExp(PATTERN_FLOAT_START + "." + PATTERN_FLOAT_END),
PATTERN_HEX_COLOR_ALPHA = /^#?[0-9A-F]{4}([0-9A-F]{4})?$/,
PATTERN_HEX_COLOR = /^#?[0-9A-F]{3}([0-9A-F]{3})?$/;
/**
* Checks whether the substring is part if this String.
* Alias for (String.indexOf(substring) > -1)
*
* @method itsa_contains
* @param substring {String} the substring to test for
* @param [caseInsensitive=false] {Boolean} whether to ignore case-sensivity
* @return {Boolean} whether the substring is found
*/
StringPrototype.itsa_contains = function(substring, caseInsensitive) {
return caseInsensitive ? (this.toLowerCase().indexOf(substring.toLowerCase()) > -1) : (this.indexOf(substring) > -1);
};
/**
* Checks if the string ends with the value specified by `test`
*
* @method itsa_endsWith
* @param test {String} the string to test for
* @param [caseInsensitive=false] {Boolean} whether to ignore case-sensivity
* @return {Boolean} whether the string ends with `test`
*/
// NOTE: ES6 native `endsWith` lacks the second argument
StringPrototype.itsa_endsWith = function(test, caseInsensitive) {
return (new RegExp(test+"$", caseInsensitive ? "i": "")).test(this);
};
/**
* Checks if the string can be parsed into a number when using `parseInt()`
*
* @method itsa_isParsable
* @return {Boolean} whether the string is parsable
*/
StringPrototype.itsa_isParsable = function() {
// strange enough, NaN doen't let compare itself, so we need a strange test:
// parseInt(value, 10)===parseInt(value, 10)
// which returns `true` for a parsable value, otherwise false
return (parseInt(this)===parseInt(this));
};
/**
* Uppercases the first character
*
* @method itsa_sentence
* @return {String} The same string with its first character uppercased
*/
StringPrototype.itsa_sentence = function() {
return (this.length>0) ? this[0].toUpperCase() + this.substr(1) : "";
};
/**
* Checks if the string starts with the value specified by `test`
*
* @method itsa_startsWith
* @param test {String} the string to test for
* @param [caseInsensitive=false] {Boolean} whether to ignore case-sensivity
* @return {Boolean} whether the string starts with `test`
*/
// NOTE: ES6 native `startsWith` lacks the second argument
StringPrototype.itsa_startsWith = function(test, caseInsensitive) {
return (new RegExp("^"+test, caseInsensitive ? "i": "")).test(this);
};
/**
* Performs `{placeholder}` substitution on a string. The object passed
* provides values to replace the `{placeholder}`s.
* `{placeholder}` token names must match property names of the object.
*
* `{placeholder}` tokens that are undefined on the object map will be removed.
*
* @example
* var greeting = '{message} {who}!';
* greeting.itsa_substitute({message: 'Hello'}); // results into 'Hello !'
*
* @method itsa_substitute
* @param obj {Object} Object containing replacement values.
* @param [retainUndefined=false] {Boolean} whether to keep placeholders that are undefined in `obj`
* @return {String} the substitute result.
*/
StringPrototype.itsa_substitute = function(obj, retainUndefined) {
return this.itsa_replace(SUBREGEX, function (match, key) {
return (obj[key]===undefined) ? (retainUndefined ? "{"+key+"}" : "") : obj[key];
});
};
/**
* Returns a ISO-8601 Date-object build by the String's value.
* If the String-value doesn't match ISO-8601, `null` will be returned.
*
* ISO-8601 Date's are generated by JSON.stringify(), so it's very handy to be able to reconvert them.
*
* @example
* var birthday = '2010-02-10T14:45:30.000Z';
* birthday.itsa_toDate(); // --> Wed Feb 10 2010 15:45:30 GMT+0100 (CET)
*
* @method itsa_toDate
* @return {Date|null} the Date represented by the String's value or null when invalid
*/
StringPrototype.itsa_toDate = function() {
return DATEPATTERN.test(this) ? new Date(this) : null;
};
/**
* Generated the string without any white-spaces at the start or end.
*
* @method itsa_trim
* @return {String} new String without leading and trailing white-spaces
*/
StringPrototype.itsa_trim = function() {
return this.itsa_replace(TRIMREGEX, "");
};
/**
* Generated the string without any white-spaces at the beginning.
*
* @method itsa_trimLeft
* @return {String} new String without leading white-spaces
*/
StringPrototype.itsa_trimLeft = function() {
return this.itsa_replace(TRIM_LEFT_REGEX, "");
};
/**
* Generated the string without any white-spaces at the end.
*
* @method itsa_trimRight
* @return {String} new String without trailing white-spaces
*/
StringPrototype.itsa_trimRight = function() {
return this.itsa_replace(TRIM_RIGHT_REGEX, "");
};
/**
* Replaces search-characters by a replacement. Replaces only the firts occurence.
* Does not alter the String itself, but returns a new String with the replacement.
*
* @method itsa_replace
* @param search {String} the character(s) to be replaced
* @param replacement {String} the replacement
* @param [caseInsensitive=false] {Boolean} whether to do search case-insensitive
* @return {String} new String with the replacement
*/
StringPrototype.itsa_replace = function(search, replacement, caseInsensitive) {
return StringPrototype.replace.call(this, caseInsensitive ? new RegExp(search, "i") : search, replacement);
};
/**
* Replaces search-characters by a replacement. Replaces all occurences.
* Does not alter the String itself, but returns a new String with the replacements.
*
* @method itsa_replaceAll
* @param search {String} the character(s) to be replaced
* @param replacement {String} the replacement
* @param [caseInsensitive=false] {Boolean} whether to do search case-insensitive
* @return {String} new String with the replacements
*/
StringPrototype.itsa_replaceAll=function(search, replacement, caseInsensitive) {
return StringPrototype.replace.call(this, new RegExp(search, "g" + (caseInsensitive ? "i" : "")), replacement);
};
/**
* Validates if the String's value represents a valid emailaddress.
*
* @method itsa_isValidEmail
* @return {Boolean} whether the String's value is a valid emailaddress.
*/
StringPrototype.itsa_isValidEmail = function() {
return PATTERN_EMAIL.test(this);
};
/**
* Validates if the String's value represents a valid floated number.
*
* @method itsa_isValidFloat
* @param [comma] {Boolean} whether to use a comma as decimal separator instead of a dot
* @return {Boolean} whether the String's value is a valid floated number.
*/
StringPrototype.itsa_isValidFloat = function(comma) {
return comma ? PATTERN_FLOAT_COMMA.test(this) : PATTERN_FLOAT_DOT.test(this);
};
/**
* Validates if the String's value represents a hexadecimal color.
*
* @method itsa_isValidHexaColor
* @param [alpha=false] {Boolean} whether to accept alpha transparancy
* @return {Boolean} whether the String's value is a valid hexadecimal color.
*/
StringPrototype.itsa_isValidHexaColor = function(alpha) {
return alpha ? PATTERN_HEX_COLOR_ALPHA.test(this) : PATTERN_HEX_COLOR.test(this);
};
/**
* Validates if the String's value represents a valid integer number.
*
* @method itsa_isValidNumber
* @return {Boolean} whether the String's value is a valid integer number.
*/
StringPrototype.itsa_isValidNumber = function() {
return PATTERN_INTEGER.test(this);
};
/**
* Validates if the String's value represents a valid boolean.
*
* @method itsa_isValidBoolean
* @return {Boolean} whether the String's value is a valid boolean.
*/
StringPrototype.itsa_isValidBoolean = function() {
var length = this.length,
check;
if ((length<4) || (length>5)) {
return false;
}
check = this.toUpperCase();
return ((check==="TRUE") || (check==="FALSE"));
};
/**
* Validates if the String's value represents a valid Date.
*
* @method itsa_isValidDate
* @return {Boolean} whether the String's value is a valid Date object.
*/
StringPrototype.itsa_isValidDate = function() {
return DATEPATTERN.test(this);
};
/**
* Validates if the String's value represents a valid URL.
*
* @method itsa_isValidURL
* @param [options] {Object}
* @param [options.http] {Boolean} to force matching starting with `http://`
* @param [options.https] {Boolean} to force matching starting with `https://`
* @return {Boolean} whether the String's value is a valid URL.
*/
StringPrototype.itsa_isValidURL = function(options) {
var instance = this;
options || (options={});
if (options.http && options.https) {
return false;
}
return options.http ? PATTERN_URLHTTP.test(instance) : (options.https ? PATTERN_URLHTTPS.test(instance) : PATTERN_URL.test(instance));
};
}(String.prototype));