summaryrefslogtreecommitdiff
path: root/addons/web/static/lib/underscore.string
diff options
context:
space:
mode:
authorChristophe Simonis <chs@openerp.com>2013-11-08 14:49:31 +0100
committerChristophe Simonis <chs@openerp.com>2013-11-08 14:49:31 +0100
commit1ec11253492309eeb214926da7e87e2e1add7439 (patch)
tree3da8cfcda6da59c2d91895050ac039fd7eac0dab /addons/web/static/lib/underscore.string
parent0a42a9dec96f498da0db901db834983c8e48860d (diff)
[UPD] update underscore and underscore.string libraries to latests versions
bzr revid: chs@openerp.com-20131108134931-muit7ym8q7g3ck1u
Diffstat (limited to 'addons/web/static/lib/underscore.string')
-rw-r--r--addons/web/static/lib/underscore.string/lib/underscore.string.js476
1 files changed, 312 insertions, 164 deletions
diff --git a/addons/web/static/lib/underscore.string/lib/underscore.string.js b/addons/web/static/lib/underscore.string/lib/underscore.string.js
index b0be69bf793..87611173bac 100644
--- a/addons/web/static/lib/underscore.string/lib/underscore.string.js
+++ b/addons/web/static/lib/underscore.string/lib/underscore.string.js
@@ -1,12 +1,11 @@
-// Underscore.string
-// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
-// Underscore.strings is freely distributable under the terms of the MIT license.
-// Documentation: https://github.com/epeli/underscore.string
-// Some code is borrowed from MooTools and Alexandru Marasteanu.
-
-// Version 2.2.0rc
-
-(function(root){
+// Underscore.string
+// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
+// Underscore.string is freely distributable under the terms of the MIT license.
+// Documentation: https://github.com/epeli/underscore.string
+// Some code is borrowed from MooTools and Alexandru Marasteanu.
+// Version '2.3.2'
+
+!function(root, String){
'use strict';
// Defining helper functions.
@@ -16,36 +15,51 @@
var nativeTrimLeft = String.prototype.trimLeft;
var parseNumber = function(source) { return source * 1 || 0; };
-
- var strRepeat = function(str, qty, separator){
- // ~~var — is the fastest available way to convert anything to Integer in javascript.
- // We'll use it extensively in this lib.
- str += ''; qty = ~~qty;
- for (var repeat = []; qty > 0; repeat[--qty] = str) {}
- return repeat.join(separator == null ? '' : separator);
+
+ var strRepeat = function(str, qty){
+ if (qty < 1) return '';
+ var result = '';
+ while (qty > 0) {
+ if (qty & 1) result += str;
+ qty >>= 1, str += str;
+ }
+ return result;
};
- var slice = function(a){
- return Array.prototype.slice.call(a);
+ var slice = [].slice;
+
+ var defaultToWhiteSpace = function(characters) {
+ if (characters == null)
+ return '\\s';
+ else if (characters.source)
+ return characters.source;
+ else
+ return '[' + _s.escapeRegExp(characters) + ']';
};
- var defaultToWhiteSpace = function(characters){
- if (characters != null) {
- return '[' + _s.escapeRegExp(''+characters) + ']';
+ // Helper for toBoolean
+ function boolMatch(s, matchers) {
+ var i, matcher, down = s.toLowerCase();
+ matchers = [].concat(matchers);
+ for (i = 0; i < matchers.length; i += 1) {
+ matcher = matchers[i];
+ if (!matcher) continue;
+ if (matcher.test && matcher.test(s)) return true;
+ if (matcher.toLowerCase() === down) return true;
}
- return '\\s';
- };
-
+ }
+
var escapeChars = {
lt: '<',
gt: '>',
quot: '"',
- apos: "'",
- amp: '&'
+ amp: '&',
+ apos: "'"
};
-
+
var reversedEscapeChars = {};
- for(var key in escapeChars){ reversedEscapeChars[escapeChars[key]] = key; }
+ for(var key in escapeChars) reversedEscapeChars[escapeChars[key]] = key;
+ reversedEscapeChars["'"] = '#39';
// sprintf() for JavaScript 0.7-beta1
// http://www.diveintojavascript.com/projects/javascript-sprintf
@@ -175,28 +189,28 @@
var _s = {
- VERSION: '2.2.0rc',
+ VERSION: '2.3.0',
isBlank: function(str){
+ if (str == null) str = '';
return (/^\s*$/).test(str);
},
stripTags: function(str){
- return (''+str).replace(/<\/?[^>]+>/g, '');
+ if (str == null) return '';
+ return String(str).replace(/<\/?[^>]+>/g, '');
},
- capitalize : function(str) {
- str += '';
- return str.charAt(0).toUpperCase() + str.substring(1);
+ capitalize : function(str){
+ str = str == null ? '' : String(str);
+ return str.charAt(0).toUpperCase() + str.slice(1);
},
chop: function(str, step){
- str = str+'';
- step = ~~step || str.length;
- var arr = [];
- for (var i = 0; i < str.length; i += step)
- arr.push(str.slice(i,i + step));
- return arr;
+ if (str == null) return [];
+ str = String(str);
+ step = ~~step;
+ return step > 0 ? str.match(new RegExp('.{1,' + step + '}', 'g')) : [str];
},
clean: function(str){
@@ -204,22 +218,47 @@
},
count: function(str, substr){
- str += ''; substr += '';
- return str.split(substr).length - 1;
+ if (str == null || substr == null) return 0;
+
+ str = String(str);
+ substr = String(substr);
+
+ var count = 0,
+ pos = 0,
+ length = substr.length;
+
+ while (true) {
+ pos = str.indexOf(substr, pos);
+ if (pos === -1) break;
+ count++;
+ pos += length;
+ }
+
+ return count;
},
chars: function(str) {
- return (''+str).split('');
+ if (str == null) return [];
+ return String(str).split('');
+ },
+
+ swapCase: function(str) {
+ if (str == null) return '';
+ return String(str).replace(/\S/g, function(c){
+ return c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase();
+ });
},
escapeHTML: function(str) {
- return (''+str).replace(/[&<>"']/g, function(match){ return '&' + reversedEscapeChars[match] + ';'; });
+ if (str == null) return '';
+ return String(str).replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; });
},
unescapeHTML: function(str) {
- return (''+str).replace(/\&([^;]+);/g, function(entity, entityCode){
+ if (str == null) return '';
+ return String(str).replace(/\&([^;]+);/g, function(entity, entityCode){
var match;
-
+
if (entityCode in escapeChars) {
return escapeChars[entityCode];
} else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
@@ -233,64 +272,72 @@
},
escapeRegExp: function(str){
- // From MooTools core 1.2.4
- return str.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
+ if (str == null) return '';
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
},
- insert: function(str, i, substr){
+ splice: function(str, i, howmany, substr){
var arr = _s.chars(str);
- arr.splice(~~i, 0, ''+substr);
+ arr.splice(~~i, ~~howmany, substr);
return arr.join('');
},
+ insert: function(str, i, substr){
+ return _s.splice(str, i, 0, substr);
+ },
+
include: function(str, needle){
- return !!~(''+str).indexOf(needle);
+ if (needle === '') return true;
+ if (str == null) return false;
+ return String(str).indexOf(needle) !== -1;
},
join: function() {
- var args = slice(arguments);
- return args.join(args.shift());
+ var args = slice.call(arguments),
+ separator = args.shift();
+
+ if (separator == null) separator = '';
+
+ return args.join(separator);
},
lines: function(str) {
- return (''+str).split("\n");
+ if (str == null) return [];
+ return String(str).split("\n");
},
reverse: function(str){
return _s.chars(str).reverse().join('');
},
- splice: function(str, i, howmany, substr){
- var arr = _s.chars(str);
- arr.splice(~~i, ~~howmany, substr);
- return arr.join('');
- },
-
startsWith: function(str, starts){
- str += ''; starts += '';
- return str.length >= starts.length && str.substring(0, starts.length) === starts;
+ if (starts === '') return true;
+ if (str == null || starts == null) return false;
+ str = String(str); starts = String(starts);
+ return str.length >= starts.length && str.slice(0, starts.length) === starts;
},
endsWith: function(str, ends){
- str += ''; ends += '';
- return str.length >= ends.length && str.substring(str.length - ends.length) === ends;
+ if (ends === '') return true;
+ if (str == null || ends == null) return false;
+ str = String(str); ends = String(ends);
+ return str.length >= ends.length && str.slice(str.length - ends.length) === ends;
},
succ: function(str){
- str += '';
- var arr = _s.chars(str);
- arr.splice(str.length-1, 1, String.fromCharCode(str.charCodeAt(str.length-1) + 1));
- return arr.join('');
+ if (str == null) return '';
+ str = String(str);
+ return str.slice(0, -1) + String.fromCharCode(str.charCodeAt(str.length-1) + 1);
},
titleize: function(str){
- return (''+str).replace(/\b./g, function(ch){ return ch.toUpperCase(); });
+ if (str == null) return '';
+ str = String(str).toLowerCase();
+ return str.replace(/(?:^|\s|-)\S/g, function(c){ return c.toUpperCase(); });
},
camelize: function(str){
- return _s.trim(str).replace(/[-_\s]+(.)?/g, function(match, chr){
- return chr && chr.toUpperCase();
- });
+ return _s.trim(str).replace(/[-_\s]+(.)?/g, function(match, c){ return c ? c.toUpperCase() : ""; });
},
underscored: function(str){
@@ -298,45 +345,41 @@
},
dasherize: function(str){
- return _s.trim(str).replace(/[_\s]+/g, '-').replace(/([A-Z])/g, '-$1').replace(/-+/g, '-').toLowerCase();
+ return _s.trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
},
classify: function(str){
- str += '';
- return _s.titleize(str.replace(/_/g, ' ')).replace(/\s/g, '')
+ return _s.titleize(String(str).replace(/[\W_]/g, ' ')).replace(/\s/g, '');
},
humanize: function(str){
- return _s.capitalize(this.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
+ return _s.capitalize(_s.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
},
trim: function(str, characters){
- str += '';
- if (!characters && nativeTrim) { return nativeTrim.call(str); }
+ if (str == null) return '';
+ if (!characters && nativeTrim) return nativeTrim.call(str);
characters = defaultToWhiteSpace(characters);
- return str.replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
+ return String(str).replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
},
ltrim: function(str, characters){
- str+='';
- if (!characters && nativeTrimLeft) {
- return nativeTrimLeft.call(str);
- }
+ if (str == null) return '';
+ if (!characters && nativeTrimLeft) return nativeTrimLeft.call(str);
characters = defaultToWhiteSpace(characters);
- return str.replace(new RegExp('^' + characters + '+'), '');
+ return String(str).replace(new RegExp('^' + characters + '+'), '');
},
rtrim: function(str, characters){
- str+='';
- if (!characters && nativeTrimRight) {
- return nativeTrimRight.call(str);
- }
+ if (str == null) return '';
+ if (!characters && nativeTrimRight) return nativeTrimRight.call(str);
characters = defaultToWhiteSpace(characters);
- return str.replace(new RegExp(characters + '+$'), '');
+ return String(str).replace(new RegExp(characters + '+$'), '');
},
truncate: function(str, length, truncateStr){
- str += ''; truncateStr = truncateStr || '...';
+ if (str == null) return '';
+ str = String(str); truncateStr = truncateStr || '...';
length = ~~length;
return str.length > length ? str.slice(0, length) + truncateStr : str;
},
@@ -344,57 +387,53 @@
/**
* _s.prune: a more elegant version of truncate
* prune extra chars, never leaving a half-chopped word.
- * @author github.com/sergiokas
+ * @author github.com/rwz
*/
prune: function(str, length, pruneStr){
- str += ''; length = ~~length;
- pruneStr = pruneStr != null ? ''+pruneStr : '...';
-
- var pruned, borderChar, template = str.replace(/\W/g, function(ch){
- return (ch.toUpperCase() !== ch.toLowerCase()) ? 'A' : ' ';
- });
-
- borderChar = template.charAt(length);
-
- pruned = template.slice(0, length);
-
- // Check if we're in the middle of a word
- if (borderChar && borderChar.match(/\S/))
- pruned = pruned.replace(/\s\S+$/, '');
-
- pruned = _s.rtrim(pruned);
-
- return (pruned+pruneStr).length > str.length ? str : str.substring(0, pruned.length)+pruneStr;
+ if (str == null) return '';
+
+ str = String(str); length = ~~length;
+ pruneStr = pruneStr != null ? String(pruneStr) : '...';
+
+ if (str.length <= length) return str;
+
+ var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
+ template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
+
+ if (template.slice(template.length-2).match(/\w\w/))
+ template = template.replace(/\s*\S+$/, '');
+ else
+ template = _s.rtrim(template.slice(0, template.length-1));
+
+ return (template+pruneStr).length > str.length ? str : str.slice(0, template.length)+pruneStr;
},
words: function(str, delimiter) {
+ if (_s.isBlank(str)) return [];
return _s.trim(str, delimiter).split(delimiter || /\s+/);
},
pad: function(str, length, padStr, type) {
- str += '';
-
+ str = str == null ? '' : String(str);
+ length = ~~length;
+
var padlen = 0;
- length = ~~length;
-
- if (!padStr) {
+ if (!padStr)
padStr = ' ';
- } else if (padStr.length > 1) {
+ else if (padStr.length > 1)
padStr = padStr.charAt(0);
- }
-
+
switch(type) {
case 'right':
- padlen = (length - str.length);
+ padlen = length - str.length;
return str + strRepeat(padStr, padlen);
case 'both':
- padlen = (length - str.length);
- return strRepeat(padStr, Math.ceil(padlen/2)) +
- str +
- strRepeat(padStr, Math.floor(padlen/2));
+ padlen = length - str.length;
+ return strRepeat(padStr, Math.ceil(padlen/2)) + str
+ + strRepeat(padStr, Math.floor(padlen/2));
default: // 'left'
- padlen = (length - str.length);
+ padlen = length - str.length;
return strRepeat(padStr, padlen) + str;
}
},
@@ -419,76 +458,185 @@
},
toNumber: function(str, decimals) {
- str += '';
- var num = parseNumber(parseNumber(str).toFixed(~~decimals));
- return num === 0 && !str.match(/^0+$/) ? Number.NaN : num;
+ if (!str) return 0;
+ str = _s.trim(str);
+ if (!str.match(/^-?\d+(?:\.\d+)?$/)) return NaN;
+ return parseNumber(parseNumber(str).toFixed(~~decimals));
+ },
+
+ numberFormat : function(number, dec, dsep, tsep) {
+ if (isNaN(number) || number == null) return '';
+
+ number = number.toFixed(~~dec);
+ tsep = typeof tsep == 'string' ? tsep : ',';
+
+ var parts = number.split('.'), fnums = parts[0],
+ decimals = parts[1] ? (dsep || '.') + parts[1] : '';
+
+ return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
},
strRight: function(str, sep){
- str += ''; sep = sep != null ? ''+sep : sep;
+ if (str == null) return '';
+ str = String(str); sep = sep != null ? String(sep) : sep;
var pos = !sep ? -1 : str.indexOf(sep);
return ~pos ? str.slice(pos+sep.length, str.length) : str;
},
strRightBack: function(str, sep){
- str += ''; sep = sep != null ? ''+sep : sep;
+ if (str == null) return '';
+ str = String(str); sep = sep != null ? String(sep) : sep;
var pos = !sep ? -1 : str.lastIndexOf(sep);
return ~pos ? str.slice(pos+sep.length, str.length) : str;
},
strLeft: function(str, sep){
- str += ''; sep = sep != null ? ''+sep : sep;
+ if (str == null) return '';
+ str = String(str); sep = sep != null ? String(sep) : sep;
var pos = !sep ? -1 : str.indexOf(sep);
return ~pos ? str.slice(0, pos) : str;
},
strLeftBack: function(str, sep){
+ if (str == null) return '';
str += ''; sep = sep != null ? ''+sep : sep;
var pos = str.lastIndexOf(sep);
return ~pos ? str.slice(0, pos) : str;
},
- toSentence: function(array, separator, lastSeparator) {
- separator || (separator = ', ');
- lastSeparator || (lastSeparator = ' and ');
- var length = array.length, str = '';
+ toSentence: function(array, separator, lastSeparator, serial) {
+ separator = separator || ', ';
+ lastSeparator = lastSeparator || ' and ';
+ var a = array.slice(), lastMember = a.pop();
- for (var i = 0; i < length; i++) {
- str += array[i];
- if (i === (length - 2)) { str += lastSeparator; }
- else if (i < (length - 1)) { str += separator; }
- }
+ if (array.length > 2 && serial) lastSeparator = _s.rtrim(separator) + lastSeparator;
+
+ return a.length ? a.join(separator) + lastSeparator + lastMember : lastMember;
+ },
- return str;
+ toSentenceSerial: function() {
+ var args = slice.call(arguments);
+ args[3] = true;
+ return _s.toSentence.apply(_s, args);
},
slugify: function(str) {
- var from = "ąàáäâãćęèéëêìíïîłńòóöôõùúüûñçżź",
- to = "aaaaaaceeeeeiiiilnooooouuuunczz",
- regex = new RegExp(defaultToWhiteSpace(from), 'g');
+ if (str == null) return '';
- str = (''+str).toLowerCase();
+ var from = "ąàáäâãåæăćęèéëêìíïîłńòóöôõøśșțùúüûñçżź",
+ to = "aaaaaaaaaceeeeeiiiilnoooooosstuuuunczz",
+ regex = new RegExp(defaultToWhiteSpace(from), 'g');
- str = str.replace(regex, function(ch){
- var index = from.indexOf(ch);
+ str = String(str).toLowerCase().replace(regex, function(c){
+ var index = from.indexOf(c);
return to.charAt(index) || '-';
});
- return _s.trim(str.replace(/[^\w\s-]/g, '').replace(/[-\s]+/g, '-'), '-');
+ return _s.dasherize(str.replace(/[^\w\s-]/g, ''));
+ },
+
+ surround: function(str, wrapper) {
+ return [wrapper, str, wrapper].join('');
+ },
+
+ quote: function(str, quoteChar) {
+ return _s.surround(str, quoteChar || '"');
+ },
+
+ unquote: function(str, quoteChar) {
+ quoteChar = quoteChar || '"';
+ if (str[0] === quoteChar && str[str.length-1] === quoteChar)
+ return str.slice(1,str.length-1);
+ else return str;
},
exports: function() {
var result = {};
for (var prop in this) {
- if (!this.hasOwnProperty(prop) || ~_s.words('include contains reverse').indexOf(prop)) continue;
+ if (!this.hasOwnProperty(prop) || prop.match(/^(?:include|contains|reverse)$/)) continue;
result[prop] = this[prop];
}
return result;
},
-
- repeat: strRepeat
+
+ repeat: function(str, qty, separator){
+ if (str == null) return '';
+
+ qty = ~~qty;
+
+ // using faster implementation if separator is not needed;
+ if (separator == null) return strRepeat(String(str), qty);
+
+ // this one is about 300x slower in Google Chrome
+ for (var repeat = []; qty > 0; repeat[--qty] = str) {}
+ return repeat.join(separator);
+ },
+
+ naturalCmp: function(str1, str2){
+ if (str1 == str2) return 0;
+ if (!str1) return -1;
+ if (!str2) return 1;
+
+ var cmpRegex = /(\.\d+)|(\d+)|(\D+)/g,
+ tokens1 = String(str1).toLowerCase().match(cmpRegex),
+ tokens2 = String(str2).toLowerCase().match(cmpRegex),
+ count = Math.min(tokens1.length, tokens2.length);
+
+ for(var i = 0; i < count; i++) {
+ var a = tokens1[i], b = tokens2[i];
+
+ if (a !== b){
+ var num1 = parseInt(a, 10);
+ if (!isNaN(num1)){
+ var num2 = parseInt(b, 10);
+ if (!isNaN(num2) && num1 - num2)
+ return num1 - num2;
+ }
+ return a < b ? -1 : 1;
+ }
+ }
+
+ if (tokens1.length === tokens2.length)
+ return tokens1.length - tokens2.length;
+
+ return str1 < str2 ? -1 : 1;
+ },
+
+ levenshtein: function(str1, str2) {
+ if (str1 == null && str2 == null) return 0;
+ if (str1 == null) return String(str2).length;
+ if (str2 == null) return String(str1).length;
+
+ str1 = String(str1); str2 = String(str2);
+
+ var current = [], prev, value;
+
+ for (var i = 0; i <= str2.length; i++)
+ for (var j = 0; j <= str1.length; j++) {
+ if (i && j)
+ if (str1.charAt(j - 1) === str2.charAt(i - 1))
+ value = prev;
+ else
+ value = Math.min(current[j], current[j - 1], prev) + 1;
+ else
+ value = i + j;
+
+ prev = current[j];
+ current[j] = value;
+ }
+
+ return current.pop();
+ },
+
+ toBoolean: function(str, trueValues, falseValues) {
+ if (typeof str === "number") str = "" + str;
+ if (typeof str !== "string") return !!str;
+ str = _s.trim(str);
+ if (boolMatch(str, trueValues || ["true", "1"])) return true;
+ if (boolMatch(str, falseValues || ["false", "0"])) return false;
+ }
};
// Aliases
@@ -500,26 +648,26 @@
_s.rjust = _s.lpad;
_s.ljust = _s.rpad;
_s.contains = _s.include;
+ _s.q = _s.quote;
+ _s.toBool = _s.toBoolean;
+
+ // Exporting
// CommonJS module is defined
if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports) {
- // Export module
+ if (typeof module !== 'undefined' && module.exports)
module.exports = _s;
- }
- exports._s = _s;
- } else if (typeof define === 'function' && define.amd) {
- // Register as a named module with AMD.
- define('underscore.string', function() {
- return _s;
- });
-
- } else {
- // Integrate with Underscore.js if defined
- // or create our own underscore object.
- root._ = root._ || {};
- root._.string = root._.str = _s;
+ exports._s = _s;
}
-}(this || window));
+ // Register as a named module with AMD.
+ if (typeof define === 'function' && define.amd)
+ define('underscore.string', [], function(){ return _s; });
+
+
+ // Integrate with Underscore.js if defined
+ // or create our own underscore object.
+ root._ = root._ || {};
+ root._.string = root._.str = _s;
+}(this, String);