/*
* Helma License Notice
*
* The contents of this file are subject to the Helma License
* Version 2.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://adele.helma.org/download/helma/license.txt
*
* Copyright 1998-2006 Helma Software. All Rights Reserved.
*
* $RCSfile: String.js,v $
* $Author$
* $Revision$
* $Date$
*/
String.ANUMPATTERN = /[^a-zA-Z0-9]/;
String.APATTERN = /[^a-zA-Z]/;
String.NUMPATTERN = /[^0-9]/;
String.FILEPATTERN = /[^a-zA-Z0-9-_\. ]/;
String.HEXPATTERN = /[^a-fA-F0-9]/;
String.LEFT = -1
String.BALANCE = 0
String.RIGHT = 1
String.ISOFORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
String.SPACE = " ";
String.EMPTY = "";
String.NULL = String.EMPTY; // to be deprecated?
// Email and URL RegExps contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
// licensed unter MIT license - http://www.opensource.org/licenses/mit-license.php
String.EMAILPATTERN = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
String.URLPATTERN = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
/**
* @fileoverview Adds useful methods to the JavaScript String type.
*
* To use this optional module, its repository needs to be added to the
* application, for example by calling app.addRepository('modules/core/String.js')
*/
app.addRepository('modules/core/Global.js');
/**
* checks if a date format pattern is correct
* @external
* @memberof {String}
* @return Boolean true if the pattern is correct
*/
String.prototype.isDateFormat = function() {
try {
new java.text.SimpleDateFormat(this);
return true;
} catch (err) {
return false;
}
};
/**
* parse a timestamp into a date object. This is used when users
* want to set createtime explicitly when creating/editing stories.
* @external
* @memberof {String}
* @param String date format to be applied
* @param Object Java TimeZone Object (optional)
* @return Object contains the resulting date
*/
String.prototype.toDate = function(format, timezone) {
var sdf = res.data._dateformat;
if (!sdf) {
sdf = new java.text.SimpleDateFormat(format);
res.data._dateformat = sdf;
} else if (format != sdf.toPattern())
sdf.applyPattern(format);
if (timezone && timezone != sdf.getTimeZone())
sdf.setTimeZone(timezone);
try {
return new Date(sdf.parse(this).getTime());
} catch (err) {
return null;
}
};
/**
* function checks if the string passed contains any characters that
* are forbidden in URLs and tries to create a java.net.URL from it
* FIXME: probably deprecated -> helma.Url
* @external
* @memberof {String}
* @return Boolean
* @see helma.Url.PATTERN
*/
String.prototype.isUrl = function() {
return String.URLPATTERN.test(this);
};
/**
* function checks if the string passed contains any characters
* that are forbidden in image- or filenames
* @external
* @memberof {String}
* @return Boolean
*/
String.prototype.isFileName = function() {
return !String.FILEPATTERN.test(this);
};
/**
* function cleans the string passed as argument from any characters
* that are forbidden or shouldn't be used in filenames
* @external
* @memberof {String}
* @return Boolean
*/
String.prototype.toFileName = function() {
return this.replace(new RegExp(String.FILEPATTERN.source, "g"), String.NULL);
};
/**
* function checks a string for a valid color value in hexadecimal format.
* it may also contain # as first character
* @external
* @memberof {String}
* @returns Boolean false, if string length (without #) > 6 or < 6 or
* contains any character which is not a valid hex value
*/
String.prototype.isHexColor = function() {
var str = this;
if (this.indexOf("#") == 0)
str = this.substring(1);
if (str.length != 6)
return false;
return !String.HEXPATTERN.test(str);
};
/**
* converts a string into a hexadecimal color
* representation (e.g. "ffcc33"). also knows how to
* convert a color string like "rgb (255, 204, 51)".
* @external
* @memberof {String}
* @return String the resulting hex color (w/o "#")
*/
String.prototype.toHexColor = function() {
if (this.startsWith("rgb")) {
res.push();
var col = this.replace(/[^0-9,]/g, String.NULL);
var parts = col.split(",");
for (var i in parts) {
var num = parseInt(parts[i], 10);
var hex = num.toString(16);
res.write(hex.pad("0", 2, String.LEFT));
}
return res.pop();
}
var col = this.replace(new RegExp(String.HEXPATTERN.source), String.NULL);
return col.toLowerCase().pad("0", 6, String.LEFT);
};
/**
* function returns true if the string contains
* only a-z and 0-9 (case insensitive!)
* @external
* @memberof {String}
* @return Boolean true in case string is alpha, false otherwise
*/
String.prototype.isAlphanumeric = function() {
if (!this.length)
return false;
return !String.ANUMPATTERN.test(this);
};
/**
* function cleans a string by throwing away all
* non-alphanumeric characters
* @external
* @memberof {String}
* @return cleaned string
*/
String.prototype.toAlphanumeric = function() {
return this.replace(new RegExp(String.ANUMPATTERN.source, "g"), String.NULL);
};
/**
* function returns true if the string contains
* only characters a-z
* @external
* @memberof {String}
* @return Boolean true in case string is alpha, false otherwise
*/
String.prototype.isAlpha = function() {
if (!this.length)
return false;
return !String.APATTERN.test(this);
};
/**
* function returns true if the string contains
* only 0-9
* @external
* @memberof {String}
* @return Boolean true in case string is numeric, false otherwise
*/
String.prototype.isNumeric = function() {
if (!this.length)
return false;
return !String.NUMPATTERN.test(this);
};
/**
* transforms the first n characters of a string to uppercase
* @external
* @memberof {String}
* @param Number amount of characters to transform
* @return String the resulting string
*/
String.prototype.capitalize = function(limit) {
if (limit == null)
limit = 1;
var head = this.substring(0, limit);
var tail = this.substring(limit, this.length);
return head.toUpperCase() + tail.toLowerCase();
};
/**
* transforms the first n characters of each
* word in a string to uppercase
* @external
* @memberof {String}
* @return String the resulting string
*/
String.prototype.titleize = function() {
var parts = this.split(" ");
res.push();
for (var i in parts) {
res.write(parts[i].capitalize());
if (i < parts.length-1)
res.write(" ");
}
return res.pop();
};
/**
* translates all characters of a string into HTML entities
* @external
* @memberof {String}
* @return String translated result
*/
String.prototype.entitize = function() {
res.push();
for (var i=0; i/g, replacement);
return str;
};
/**
* function calculates the md5 hash of a string
* @external
* @memberof {String}
* @return String md5 hash of the string
*/
String.prototype.md5 = function() {
return Packages.helma.util.MD5Encoder.encode(this);
};
/**
* function returns true if the string starts with
* the string passed as argument
* @external
* @memberof {String}
* @param String string pattern to search for
* @return Boolean true in case it matches the beginning
* of the string, false otherwise
*/
String.prototype.startsWith = function(str, offset) {
var javaObj = new java.lang.String(this);
if (offset != null)
return javaObj.startsWith(str, offset);
return javaObj.startsWith(str);
};
/**
* function returns true if the string ends with
* the string passed as argument
* @external
* @memberof {String}
* @param String string pattern to search for
* @return Boolean true in case it matches the end of
* the string, false otherwise
*/
String.prototype.endsWith = function(str) {
var javaObj = new java.lang.String(this);
return javaObj.endsWith(str);
};
/**
* fills a string with another string up to a desired length
* @external
* @memberof {String}
* @param String the filling string
* @param Number the desired length of the resulting string
* @param Number the direction which the string will be padded in:
* -1: left 0: both (balance) 1: right
* (you can use the constants String.LEFT,
* String.BALANCE and String.RIGHT here as well.)
* @return String the resulting string
*/
String.prototype.pad = function(str, len, mode) {
if (str == null || len == null)
return this;
var diff = len - this.length;
if (diff == 0)
return this;
var left, right = 0;
if (mode == null || mode == String.RIGHT)
right = diff;
else if (mode == String.LEFT)
left = diff;
else if (mode == String.BALANCE) {
right = Math.round(diff / 2);
left = diff - right;
}
res.push();
for (var i=0; i -1)
return true;
return false;
};
/**
* function compares a string with the one passed as argument
* using diff
* @external
* @memberof {String}
* @param String String to compare against String object value
* @param String Optional regular expression string to use for
* splitting. If not defined, newlines will be used.
* @return Object Array containing one JS object for each line
* with the following properties:
* .num Line number
* .value String line if unchanged
* .deleted Obj Array containing deleted lines
* .inserted Obj Array containing added lines
*/
String.prototype.diff = function(mod, separator) {
// if no separator use line separator
var regexp = (typeof(separator) == "undefined") ?
new RegExp("\r\n|\r|\n") :
new RegExp(separator);
// split both strings into arrays
var orig = this.split(regexp);
var mod = mod.split(regexp);
// create the Diff object
var diff = new Packages.helma.util.Diff(orig, mod);
// get the diff.
var d = diff.diff();
if (!d)
return null;
var max = Math.max(orig.length, mod.length);
var result = new Array();
for (var i=0;i -1) {
count += 1;
offset += 1;
}
return count;
};
/**
* returns the string encoded using the base64 algorithm
* @external
* @memberof {String}
*/
String.prototype.enbase64 = function() {
var bytes = new java.lang.String(this) . getBytes();
return new Packages.sun.misc.BASE64Encoder().encode(bytes);
};
/**
* returns the decoded string using the base64 algorithm
* @external
* @memberof {String}
*/
String.prototype.debase64 = function() {
var bytes = new Packages.sun.misc.BASE64Decoder().decodeBuffer(this);
return String(new java.lang.String(bytes));
};
// wrapper methods for string-related
// global helma functions
String.prototype.encode = function() {
return encode(this);
};
String.prototype.encodeXml = function() {
return encodeXml(this);
};
String.prototype.encodeForm = function() {
return encodeForm(this);
};
String.prototype.format = function() {
return format(this);
};
String.prototype.stripTags = function() {
return stripTags(this);
};
/**
* factory to create functions for sorting objects in an array
* @external
* @memberof {String}
* @param String name of the field each object is compared with
* @param Number order (ascending or descending)
* @return Function ready for use in Array.prototype.sort
*/
String.Sorter = function(field, order) {
if (!order)
order = 1;
var key = field + ":" + order;
if (!String.Sorter.cache[key]) {
String.Sorter.cache[key] = function(a, b) {
var str1 = String(a[field] || String.NULL).toLowerCase();
var str2 = String(b[field] || String.NULL).toLowerCase();
if (str1 > str2)
return order * 1;
if (str1 < str2)
return order * -1;
return 0;
};
}
return String.Sorter.cache[key];
};
String.Sorter.ASC = 1;
String.Sorter.DESC = -1;
String.Sorter.cache = {};
/**
* create a string from a bunch of substrings
* @external
* @memberof {String}
* @param String one or more strings as arguments
* @return String the resulting string
*/
String.compose = function() {
res.push();
for (var i=0; i