string.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. /*
  2. * Utilities: A classic collection of JavaScript utilities
  3. * Copyright 2112 Matthew Eernisse ([email protected])
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. var core = require('./core')
  19. , inflection = require('./inflection')
  20. , string;
  21. /**
  22. @name string
  23. @namespace string
  24. */
  25. string = new (function () {
  26. // Regexes for trimming, and character maps for escaping
  27. var _LTR = /^\s+/
  28. , _RTR = /\s+$/
  29. , _TR = /^\s+|\s+$/g
  30. , _NL = /\n|\r|\r\n/g
  31. , _CHARS = {
  32. '&': '&'
  33. , '<': '&lt;'
  34. , '>': '&gt;'
  35. , '"': '&quot;'
  36. , '\'': '&#39;'
  37. }
  38. , _UUID_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
  39. , _buildEscape
  40. , _buildEscapeTest;
  41. // Builds the escape/unescape methods using a
  42. // map of characters
  43. _buildEscape = function (direction) {
  44. return function (str) {
  45. var string = str;
  46. // If string is NaN, null or undefined then provide an empty default
  47. if((typeof string === 'undefined') ||
  48. string === null ||
  49. (!string && isNaN(string))) {
  50. string = '';
  51. }
  52. string = string.toString();
  53. var from, to, p;
  54. for (p in _CHARS) {
  55. from = direction == 'to' ? p : _CHARS[p];
  56. to = direction == 'to' ? _CHARS[p] : p;
  57. string = string.replace(new RegExp(from, 'gm'), to);
  58. }
  59. return string;
  60. }
  61. };
  62. // Builds a method that tests for any escapable
  63. // characters, useful for avoiding double-scaping if
  64. // you're not sure if a string has already been escaped
  65. _buildEscapeTest = function (direction) {
  66. return function (string) {
  67. var pat = ''
  68. , p;
  69. for (p in _CHARS) {
  70. pat += direction == 'to' ? p : _CHARS[p];
  71. pat += '|';
  72. }
  73. pat = pat.substr(0, pat.length - 1);
  74. pat = new RegExp(pat, "gm");
  75. return pat.test(string)
  76. }
  77. };
  78. // Escape special XMl chars
  79. this.escapeXML = _buildEscape('to');
  80. // Unescape XML chars to literal representation
  81. this.unescapeXML = _buildEscape('from');
  82. // Test if a string includes special chars
  83. // that need escaping
  84. this.needsEscape = _buildEscapeTest('to');
  85. // Test if a string includes escaped chars
  86. // that need unescaping
  87. this.needsUnescape = _buildEscapeTest('from');
  88. /**
  89. @name string#escapeRegExpChars
  90. @public
  91. @function
  92. @return {String} A string of escaped characters
  93. @description Escapes regex control-characters in strings
  94. used to build regexes dynamically
  95. @param {String} string The string of chars to escape
  96. */
  97. this.escapeRegExpChars = (function () {
  98. var specials = [ '^', '$', '/', '.', '*', '+', '?', '|', '(', ')',
  99. '[', ']', '{', '}', '\\' ];
  100. var sRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
  101. return function (string) {
  102. var str = string || '';
  103. str = String(str);
  104. return str.replace(sRE, '\\$1');
  105. };
  106. }).call(this);
  107. /**
  108. @name string#toArray
  109. @public
  110. @function
  111. @return {Array} Returns an array of characters
  112. @description Converts a string to an array
  113. @param {String} string The string to convert
  114. */
  115. this.toArray = function (string) {
  116. var str = string || ''
  117. , arr = []
  118. , i = -1;
  119. str = String(str);
  120. while (++i < str.length) {
  121. arr.push(str.substr(i, 1));
  122. }
  123. return arr;
  124. };
  125. /**
  126. @name string#reverse
  127. @public
  128. @function
  129. @return {String} Returns the `string` reversed
  130. @description Reverses a string
  131. @param {String} string The string to reverse
  132. */
  133. this.reverse = function (string) {
  134. var str = string || '';
  135. str = String(str);
  136. return this.toArray(str).reverse().join('');
  137. };
  138. /**
  139. @name string#ltrim
  140. @public
  141. @function
  142. @return {String} Returns the trimmed string
  143. @description Ltrim trims `char` from the left of a `string` and returns it
  144. if no `char` is given it will trim spaces
  145. @param {String} string The string to trim
  146. @param {String} character The character to trim
  147. */
  148. this.ltrim = function (string, character) {
  149. var str = string || ''
  150. , pat = character ? new RegExp('^' + character + '+') : _LTR;
  151. str = String(str);
  152. return str.replace(pat, '');
  153. };
  154. /**
  155. @name string#rtrim
  156. @public
  157. @function
  158. @return {String} Returns the trimmed string
  159. @description Rtrim trims `char` from the right of a `string` and returns it
  160. if no `char` is given it will trim spaces
  161. @param {String} string The string to trim
  162. @param {String} character The character to trim
  163. */
  164. this.rtrim = function (string, character) {
  165. var str = string || ''
  166. , pat = character ? new RegExp(character + '+$') : _RTR;
  167. str = String(str);
  168. return str.replace(pat, '');
  169. };
  170. // Alias
  171. this.chomp = this.rtrim;
  172. /**
  173. @name string#trim
  174. @public
  175. @function
  176. @return {String} Returns the trimmed string
  177. @description Trim trims `char` from the left and right of a `string` and returns it
  178. if no `char` is given it will trim spaces
  179. @param {String} string The string to trim
  180. @param {String} character The character to trim
  181. */
  182. this.trim = function (string, character) {
  183. var str = string || ''
  184. , pat = character ? new RegExp('^' + character + '+|' + character + '+$', 'g') : _TR;
  185. str = String(str);
  186. return str.replace(pat, '');
  187. };
  188. /**
  189. @name string#chop
  190. @public
  191. @function
  192. @description Returns a new String with the last character removed. If the
  193. string ends with \r\n, both characters are removed. Applying chop to an
  194. empty string returns an empty string.
  195. @param {String} string to return with the last character removed.
  196. */
  197. this.chop = function (string) {
  198. var index
  199. , str = string || '';
  200. str = String(str);
  201. if (str.length) {
  202. // Special-case for \r\n
  203. index = str.indexOf('\r\n');
  204. if (index == str.length - 2) {
  205. return str.substring(0, index);
  206. }
  207. return str.substring(0, str.length - 1);
  208. }
  209. else {
  210. return '';
  211. }
  212. };
  213. /**
  214. @name string#lpad
  215. @public
  216. @function
  217. @return {String} Returns the padded string
  218. @description Lpad adds `char` to the left of `string` until the length
  219. of `string` is more than `width`
  220. @param {String} string The string to pad
  221. @param {String} character The character to pad with
  222. @param {Number} width the width to pad to
  223. */
  224. this.lpad = function (string, character, width) {
  225. var str = string || ''
  226. , width;
  227. str = String(str);
  228. // Should width be string.length + 1? or the same to be safe
  229. width = parseInt(width, 10) || str.length;
  230. character = character || ' ';
  231. while (str.length < width) {
  232. str = character + str;
  233. }
  234. return str;
  235. };
  236. /**
  237. @name string#rpad
  238. @public
  239. @function
  240. @return {String} Returns the padded string
  241. @description Rpad adds `char` to the right of `string` until the length
  242. of `string` is more than `width`
  243. @param {String} string The string to pad
  244. @param {String} character The character to pad with
  245. @param {Number} width the width to pad to
  246. */
  247. this.rpad = function (string, character, width) {
  248. var str = string || ''
  249. , width;
  250. str = String(str);
  251. // Should width be string.length + 1? or the same to be safe
  252. width = parseInt(width, 10) || str.length;
  253. character = character || ' ';
  254. while (str.length < width) {
  255. str += character;
  256. }
  257. return str;
  258. };
  259. /**
  260. @name string#pad
  261. @public
  262. @function
  263. @return {String} Returns the padded string
  264. @description Pad adds `char` to the left and right of `string` until the length
  265. of `string` is more than `width`
  266. @param {String} string The string to pad
  267. @param {String} character The character to pad with
  268. @param {Number} width the width to pad to
  269. */
  270. this.pad = function (string, character, width) {
  271. var str = string || ''
  272. , width;
  273. str = String(str);
  274. // Should width be string.length + 1? or the same to be safe
  275. width = parseInt(width, 10) || str.length;
  276. character = character || ' ';
  277. while (str.length < width) {
  278. str = character + str + character;
  279. }
  280. return str;
  281. };
  282. /**
  283. @name string#truncate
  284. @public
  285. @function
  286. @return {String} Returns the truncated string
  287. @description Truncates a given `string` after a specified `length` if `string` is longer than
  288. `length`. The last characters will be replaced with an `omission` for a total length
  289. not exceeding `length`. If `callback` is given it will fire if `string` is truncated.
  290. @param {String} string The string to truncate
  291. @param {Integer/Object} options Options for truncation, If options is an Integer it will be length
  292. @param {Integer} [options.length=string.length] Length the output string will be
  293. @param {Integer} [options.len] Alias for `length`
  294. @param {String} [options.omission='...'] Replace last characters with an omission
  295. @param {String} [options.ellipsis='...'] Alias for `omission`
  296. @param {String/RegExp} [options.seperator] Break the truncated test at the nearest `seperator`
  297. @param {Function} callback Callback is called only if a truncation is done
  298. */
  299. this.truncate = function (string, options, callback) {
  300. var str = string || ''
  301. , stringLen
  302. , opts
  303. , stringLenWithOmission
  304. , last
  305. , ignoreCase
  306. , multiLine
  307. , stringToWorkWith
  308. , lastIndexOf
  309. , nextStop
  310. , result
  311. , returnString;
  312. str = String(str);
  313. stringLen = str.length
  314. // If `options` is a number, assume it's the length and
  315. // create a options object with length
  316. if (typeof options === 'number') {
  317. opts = {
  318. length: options
  319. };
  320. }
  321. else {
  322. opts = options || {};
  323. }
  324. // Set `opts` defaults
  325. opts.length = opts.length || stringLen;
  326. opts.omission = opts.omission || opts.ellipsis || '...';
  327. stringLenWithOmission = opts.length - opts.omission.length;
  328. // Set the index to stop at for `string`
  329. if (opts.seperator) {
  330. if (opts.seperator instanceof RegExp) {
  331. // If `seperator` is a regex
  332. if (opts.seperator.global) {
  333. opts.seperator = opts.seperator;
  334. } else {
  335. ignoreCase = opts.seperator.ignoreCase ? 'i' : ''
  336. multiLine = opts.seperator.multiLine ? 'm' : '';
  337. opts.seperator = new RegExp(opts.seperator.source,
  338. 'g' + ignoreCase + multiLine);
  339. }
  340. stringToWorkWith = str.substring(0, stringLenWithOmission + 1)
  341. lastIndexOf = -1
  342. nextStop = 0
  343. while ((result = opts.seperator.exec(stringToWorkWith))) {
  344. lastIndexOf = result.index;
  345. opts.seperator.lastIndex = ++nextStop;
  346. }
  347. last = lastIndexOf;
  348. }
  349. else {
  350. // Seperator is a String
  351. last = str.lastIndexOf(opts.seperator, stringLenWithOmission);
  352. }
  353. // If the above couldn't be found, they'll default to -1 so,
  354. // we need to just set it as `stringLenWithOmission`
  355. if (last === -1) {
  356. last = stringLenWithOmission;
  357. }
  358. }
  359. else {
  360. last = stringLenWithOmission;
  361. }
  362. if (stringLen < opts.length) {
  363. return str;
  364. }
  365. else {
  366. returnString = str.substring(0, last) + opts.omission;
  367. returnString += callback && typeof callback === 'function' ? callback() : '';
  368. return returnString;
  369. }
  370. };
  371. /**
  372. @name string#truncateHTML
  373. @public
  374. @function
  375. @return {String} Returns the HTML safe truncated string
  376. @description Truncates a given `string` inside HTML tags after a specified `length` if string`
  377. is longer than `length`. The last characters will be replaced with an `omission`
  378. for a total length not exceeding `length`. If `callback` is given it will fire if
  379. `string` is truncated. If `once` is true only the first string in the first HTML
  380. tags will be truncated leaving the others as they were
  381. @param {String} string The string to truncate
  382. @param {Integer/Object} options Options for truncation, If options is an Integer it will be length
  383. all Object options are the same as `truncate`
  384. @param {Boolean} [options.once=false] If true, it will only be truncated once, otherwise the
  385. truncation will loop through all text inside HTML tags
  386. @param {Function} callback Callback is called only if a truncation is done
  387. */
  388. this.truncateHTML = function (string, options, callback) {
  389. var str = string || ''
  390. , returnString = ''
  391. , opts = options;
  392. str = String(str);
  393. // If `options` is a number assume it's the length and create a options object with length
  394. if (typeof opts === 'number') {
  395. var num = opts;
  396. opts = {};
  397. opts.length = num;
  398. } else opts = opts || {};
  399. // Set `default` options for HTML specifics
  400. opts.once = opts.once || false;
  401. var pat = /(<[^>]*>)/ // Patter for matching HTML tags
  402. , arr = [] // Holds the HTML tags and content seperately
  403. , truncated = false
  404. , result = pat.exec(str)
  405. , item
  406. , firstPos
  407. , lastPos
  408. , i;
  409. // Gather the HTML tags and content into the array
  410. while (result) {
  411. firstPos = result.index;
  412. lastPos = pat.lastIndex;
  413. if (firstPos !== 0) {
  414. // Should be content not HTML tags
  415. arr.push(str.substring(0, firstPos));
  416. // Slice content from string
  417. str = str.slice(firstPos);
  418. }
  419. arr.push(result[0]); // Push HTML tags
  420. str = str.slice(result[0].length);
  421. // Re-run the pattern on the new string
  422. result = pat.exec(str);
  423. }
  424. if (str !== '') {
  425. arr.push(str);
  426. }
  427. // Loop through array items appending the tags to the string,
  428. // - and truncating the text then appending it to content
  429. i = -1;
  430. while (++i < arr.length) {
  431. item = arr[i];
  432. switch (true) {
  433. // Closing tag
  434. case item.indexOf('</') == 0:
  435. returnString += item;
  436. openTag = null;
  437. break;
  438. // Opening tag
  439. case item.indexOf('<') == 0:
  440. returnString += item;
  441. openTag = item;
  442. break;
  443. // Normal text
  444. default:
  445. if (opts.once && truncated) {
  446. returnString += item;
  447. } else {
  448. returnString += this.truncate(item, opts, callback);
  449. truncated = true;
  450. }
  451. break;
  452. }
  453. }
  454. return returnString;
  455. };
  456. /**
  457. @name string#nl2br
  458. @public
  459. @function
  460. @return {String} The string with converted newlines chars to br tags
  461. @description Nl2br returns a string where all newline chars are turned
  462. into line break HTML tags
  463. @param {String} string The string to convert
  464. */
  465. this.nl2br = function (string) {
  466. var str = string || '';
  467. str = String(str);
  468. return str.replace(_NL,'<br />');
  469. };
  470. /**
  471. @name string#snakeize
  472. @public
  473. @function
  474. @return {String} The string in a snake_case version
  475. @description Snakeize converts camelCase and CamelCase strings to snake_case strings
  476. @param {String} string The string to convert to snake_case
  477. @param {String} separ='_' The seperator to use
  478. */
  479. this.snakeize = (function () {
  480. // Only create regexes once on initial load
  481. var repl = /([A-Z]+)/g
  482. , lead = /^_/g;
  483. return function (string, separ) {
  484. var str = string || ''
  485. , sep = separ || '_'
  486. , leading = separ ? new RegExp('^' + sep, 'g') : lead;
  487. str = String(str);
  488. return str.replace(repl, sep + '$1').toLowerCase().
  489. replace(leading, '');
  490. };
  491. }).call(this);
  492. // Aliases
  493. /**
  494. @name string#underscorize
  495. @public
  496. @function
  497. @return {String} The string in a underscorized version
  498. @description Underscorize returns the given `string` converting camelCase and snakeCase to underscores
  499. @param {String} string The string to underscorize
  500. */
  501. this.underscorize = this.snakeize;
  502. this.underscoreize = this.snakeize;
  503. this.decamelize = this.snakeize;
  504. /**
  505. @name string#camelize
  506. @public
  507. @function
  508. @return {String} The string in a camelCase version
  509. @description Camelize takes a string and optional options and
  510. returns a camelCase version of the given `string`
  511. @param {String} string The string to convert to camelCase
  512. @param {Object} options
  513. @param {Boolean} [options.initialCap] If initialCap is true the returned
  514. string will have a capitalized first letter
  515. @param {Boolean} [options.leadingUnderscore] If leadingUnderscore os true then if
  516. an underscore exists at the beggining
  517. of the string, it will stay there.
  518. Otherwise it'll be removed.
  519. */
  520. this.camelize = (function () {
  521. // Only create regex once on initial load
  522. var repl = /[-_](\w)/g;
  523. return function (string, options) {
  524. var str = string || ''
  525. , ret
  526. , config = {
  527. initialCap: false
  528. , leadingUnderscore: false
  529. }
  530. , opts = options || {};
  531. str = String(str);
  532. // Backward-compat
  533. if (typeof opts == 'boolean') {
  534. config = {
  535. initialCap: true
  536. };
  537. }
  538. else {
  539. core.mixin(config, opts);
  540. }
  541. ret = str.replace(repl, function (m, m1) {
  542. return m1.toUpperCase();
  543. });
  544. if (config.leadingUnderscore & str.indexOf('_') === 0) {
  545. ret = '_' + this.decapitalize(ret);
  546. }
  547. // If initialCap is true capitalize it
  548. ret = config.initialCap ? this.capitalize(ret) : this.decapitalize(ret);
  549. return ret;
  550. };
  551. }).call(this);
  552. /**
  553. @name string#decapitalize
  554. @public
  555. @function
  556. @return {String} The string with the first letter decapitalized
  557. @description Decapitalize returns the given string with the first letter uncapitalized.
  558. @param {String} string The string to decapitalize
  559. */
  560. this.decapitalize = function (string) {
  561. var str = string || '';
  562. str = String(str);
  563. return str.substr(0, 1).toLowerCase() + str.substr(1);
  564. };
  565. /**
  566. @name string#capitalize
  567. @public
  568. @function
  569. @return {String} The string with the first letter capitalized
  570. @description capitalize returns the given string with the first letter capitalized.
  571. @param {String} string The string to capitalize
  572. */
  573. this.capitalize = function (string) {
  574. var str = string || '';
  575. str = String(str);
  576. return str.substr(0, 1).toUpperCase() + str.substr(1);
  577. };
  578. /**
  579. @name string#dasherize
  580. @public
  581. @function
  582. @return {String} The string in a dashed version
  583. @description Dasherize returns the given `string` converting camelCase and snakeCase
  584. to dashes or replace them with the `replace` character.
  585. @param {String} string The string to dasherize
  586. @param {String} replace='-' The character to replace with
  587. */
  588. this.dasherize = function (string, replace) {
  589. var repl = replace || '-'
  590. return this.snakeize(string, repl);
  591. };
  592. /**
  593. @name string#include
  594. @public
  595. @function
  596. @return {Boolean} Returns true if the string is found in the string to search
  597. @description Searches for a particular string in another string
  598. @param {String} searchIn The string to search for the other string in
  599. @param {String} searchFor The string to search for
  600. */
  601. this.include = function (searchIn, searchFor) {
  602. var str = searchFor;
  603. if (!str && typeof string != 'string') {
  604. return false;
  605. }
  606. str = String(str);
  607. return (searchIn.indexOf(str) > -1);
  608. };
  609. /*
  610. * getInflections(name<String>, initialCap<String>)
  611. *
  612. * Inflection returns an object that contains different inflections
  613. * created from the given `name`
  614. */
  615. /**
  616. @name string#getInflections
  617. @public
  618. @function
  619. @return {Object} A Object containing multiple different inflects for the given `name`
  620. @description Inflection returns an object that contains different inflections
  621. created from the given `name`
  622. @param {String} name The string to create inflections from
  623. */
  624. this.getInflections = function (name) {
  625. if (!name) {
  626. return;
  627. }
  628. var self = this
  629. // Use plural version to fix possible mistakes(e,g,. thingie instead of thingy)
  630. , normalizedName = this.snakeize(inflection.pluralize(name))
  631. , nameSingular = inflection.singularize(normalizedName)
  632. , namePlural = inflection.pluralize(normalizedName);
  633. return {
  634. // For filepaths or URLs
  635. filename: {
  636. // neil_peart
  637. singular: nameSingular
  638. // neil_pearts
  639. , plural: namePlural
  640. }
  641. // Constructor names
  642. , constructor: {
  643. // NeilPeart
  644. singular: self.camelize(nameSingular, {initialCap: true})
  645. // NeilPearts
  646. , plural: self.camelize(namePlural, {initialCap: true})
  647. }
  648. , property: {
  649. // neilPeart
  650. singular: self.camelize(nameSingular)
  651. // neilPearts
  652. , plural: self.camelize(namePlural)
  653. }
  654. };
  655. };
  656. /**
  657. @name string#getInflection
  658. @public
  659. @function
  660. @return {Object} A Object containing multiple different inflects for the given `name`
  661. @description Inflection returns an object that contains different inflections
  662. created from the given `name`
  663. @param {String} name The string to create inflections from
  664. */
  665. this.getInflection = function (name, key, pluralization) {
  666. var infl = this.getInflections(name);
  667. return infl[key][pluralization];
  668. };
  669. // From Math.uuid.js, https://github.com/broofa/node-uuid
  670. // Robert Kieffer ([email protected]), MIT license
  671. this.uuid = function (length, radix) {
  672. var chars = _UUID_CHARS
  673. , uuid = []
  674. , r
  675. , i;
  676. radix = radix || chars.length;
  677. if (length) {
  678. // Compact form
  679. i = -1;
  680. while (++i < length) {
  681. uuid[i] = chars[0 | Math.random()*radix];
  682. }
  683. } else {
  684. // rfc4122, version 4 form
  685. // rfc4122 requires these characters
  686. uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
  687. uuid[14] = '4';
  688. // Fill in random data. At i==19 set the high bits of clock sequence as
  689. // per rfc4122, sec. 4.1.5
  690. i = -1;
  691. while (++i < 36) {
  692. if (!uuid[i]) {
  693. r = 0 | Math.random()*16;
  694. uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
  695. }
  696. }
  697. }
  698. return uuid.join('');
  699. };
  700. /**
  701. @name string#stripTags
  702. @public
  703. @function
  704. @return {String} A String with HTML tags removed.
  705. @description Strips HTML tags from a string.
  706. @param {String} The string to strip HTML tags from
  707. @param {String|Array} A String or Array containing allowed tags. e.g. "<br><p>"
  708. */
  709. this.stripTags = function(string, allowed) {
  710. // taken from http://phpjs.org/functions/strip_tags/
  711. var allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
  712. var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
  713. comments = /<!--[\s\S]*?-->/gi;
  714. return string.replace(comments, '').replace(tags, function ($0, $1) {
  715. return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
  716. });
  717. }
  718. })();
  719. module.exports = string;