1 /* 2 * Copyright (C) 2012-2013 DFKI GmbH 3 * Deutsches Forschungszentrum fuer Kuenstliche Intelligenz 4 * German Research Center for Artificial Intelligence 5 * http://www.dfki.de 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28 /* 29 * JavaScript extensions for String type 30 * 31 */ 32 define (function () { 33 if( !String.prototype.startsWith ){ 34 /** 35 * Check if the String starts with token 36 * @function 37 */ 38 String.prototype.startsWith = function (token, ignoreCase) { 39 /// <summary> 40 /// Check if the String starts with token 41 /// </summary> 42 /// <param name="token" type="String"> 43 /// the token to check for 44 /// </param> 45 /// <param name="ignoreCase" type="Boolean"> 46 /// (optional) if <code>true</code> checking will ignore case of characters. 47 /// Default is <code>false</code>. 48 /// </param> 49 /// <returns type="Boolean"> 50 /// true, if the String starts with token, otherwise false. 51 /// </returns> 52 var str, isStarting = false; 53 var isIgnoreCase = typeof ignoreCase !== 'undefined' && ignoreCase == true; 54 if(isIgnoreCase){ 55 token = token.toLowerCase(); 56 str = this.toLowerCase(); 57 } 58 else { 59 str = this; 60 } 61 62 isStarting = str.lastIndexOf(token, 0) === 0; 63 64 return isStarting; 65 }; 66 }//END: if( !String.prototype.startsWith 67 else { 68 69 //if it already exists, then it is probably startsWith(str [, position]) 70 String.prototype.startsWithOrig = String.prototype.startsWith; 71 72 //"map" startsWith(str,number) to startsWith(str,boolean): 73 String.prototype.startsWith = function (token, startIndex, ignoreCase) { 74 if(typeof ignoreCase === 'undefined' && typeof startIndex === 'boolean' || startIndex === 'true'){ 75 ignoreCase = startIndex; 76 startIndex = null; 77 } 78 var isIgnoreCase = typeof ignoreCase !== 'undefined' && ignoreCase == true; 79 80 var str = this.toString(), other = token.toString(); 81 if(isIgnoreCase){ 82 str = str.toLowerCase(); 83 other = other.toLowerCase(); 84 } 85 86 if(startIndex){ 87 return str.startsWithOrig(other, startIndex); 88 } 89 else { 90 return str.startsWithOrig(other); 91 } 92 }; 93 } 94 95 96 97 if( !String.prototype.endsWith ){ 98 /** 99 * Check if the String ends with token 100 * @function 101 */ 102 String.prototype.endsWith = function (token, ignoreCase) { 103 /// <summary> 104 /// Check if the String ends with token 105 /// </summary> 106 /// <param name="token" type="String"> 107 /// the token to check for 108 /// </param> 109 /// <param name="ignoreCase" type="Boolean"> 110 /// (optional) if <code>true</code> checking will ignore case of characters. 111 /// Default is <code>false</code>. 112 /// </param> 113 /// <returns type="Boolean"> 114 /// true, if the String ends with token, otherwise false. 115 /// </returns> 116 var str, isEnding = false, pos; 117 var isIgnoreCase = typeof ignoreCase !== 'undefined' && ignoreCase == true; 118 if(isIgnoreCase){ 119 token = token.toLowerCase(); 120 str = this.toLowerCase(); 121 } 122 else { 123 str = this; 124 } 125 126 pos = str.length - token.length; 127 //sanity check if the token is smaller than the String itself -> token cannot be a sub-string! 128 if(pos < 0){ 129 return false; 130 } 131 isEnding = str.indexOf(token, pos) === pos; 132 133 return isEnding; 134 }; 135 }//END: if( !String.prototype.endsWith 136 else { 137 138 //if it already exists, then it is probably endsWith(str [, position]) 139 String.prototype.endsWithOrig = String.prototype.endsWith; 140 141 //"map" endsWith(str,number) to endsWith(str,boolean): 142 String.prototype.endsWith = function (token, startIndex, ignoreCase) { 143 if(typeof ignoreCase === 'undefined' && typeof startIndex === 'boolean' || startIndex === 'true'){ 144 ignoreCase = startIndex; 145 startIndex = null; 146 } 147 var isIgnoreCase = typeof ignoreCase !== 'undefined' && ignoreCase == true; 148 149 var str = this.toString(), other = token.toString(); 150 if(isIgnoreCase){ 151 str = str.toLowerCase(); 152 other = other.toLowerCase(); 153 } 154 155 if(startIndex){ 156 return str.endsWithOrig(other, startIndex); 157 } 158 else { 159 return str.endsWithOrig(other); 160 } 161 }; 162 } 163 164 if( !String.prototype.replaceAll ){ 165 /** 166 * ReplaceAll by Fagner Brack (MIT License) 167 * 168 * Replaces all occurrences of a substring in a string 169 * 170 * @function 171 */ 172 String.prototype.replaceAll = function (token, newToken, ignoreCase) { 173 /// <summary> 174 /// Replace all occurances of a String with a new String 175 /// </summary> 176 /// <param name="token">the String to replace (all its occurances)</param> 177 /// <param name="newToken">the new String for the replacement</param> 178 /// <param name="ignoreCase"> 179 /// if true, the String token is matched/searched for without 180 /// taking case into account 181 /// </param> 182 /// <returns type="String"> 183 /// a new String in which all occurances of token are replaced by newToken. 184 /// If token or newToken are not Strings, the unmodified String will be returned. 185 /// </returns> 186 var str, i = -1, _token; 187 if ((str = this.toString()) && typeof token === "string" && typeof newToken === "string") { 188 _token = ignoreCase === true ? token.toLowerCase() : undefined; 189 while ((i = ( 190 _token !== undefined ? 191 str.toLowerCase().indexOf( 192 _token, 193 i >= 0 ? i + newToken.length : 0 194 ) : str.indexOf( 195 token, 196 i >= 0 ? i + newToken.length : 0 197 ) 198 )) !== -1) { 199 str = str.substring(0, i) 200 .concat(newToken) 201 .concat(str.substring(i + token.length)); 202 } 203 } 204 return str; 205 }; 206 }//END: if( !String.prototype.replaceAll 207 208 /** 209 * Escape quotes, i.e. replace single quotes <code>'</code> with <code>\'</code> 210 * @function 211 */ 212 String.prototype.escapeQuotes = function () { 213 var str; 214 if (str = this.toString()) { 215 return str.replaceAll('\'', '\\\'', false); 216 } else if(str == ''){ 217 return str; 218 } 219 throw new Error('Error in String.escapeQuotes: This is not a string: '+ (typeof this)); 220 }; 221 222 /** 223 * Escape double quotes, i.e. replace quotes <code>"</code> with <code>\"</code> 224 */ 225 String.prototype.escapeDoubleQuotes = function () { 226 var str; 227 if (str = this.toString()) { 228 return str.replaceAll('"', '\\"', false); 229 } else if(str == ''){ 230 return str; 231 } 232 throw new Error('Error in String.escapeDoubleQuotes: This is not a string: '+ (typeof this)); 233 }; 234 235 /** 236 * Un-escape quotes, i.e. replace escaped single quotes <code>\'</code> with <code>'</code> 237 */ 238 String.prototype.unescapeQuotes = function () { 239 var str; 240 if (str = this.toString()) { 241 return str.replaceAll('\\\'', '\'', false); 242 } else if(str == ''){ 243 return str; 244 } 245 throw new Error('Error in String.unescapeQuotes: This is not a string: '+ (typeof this)); 246 }; 247 248 /** 249 * Un-escape double quotes, i.e. replace escaped quotes <code>\"</code> with <code>"</code> 250 */ 251 String.prototype.unescapeDoubleQuotes = function () { 252 var str; 253 if (str = this.toString()) { 254 return str.replaceAll('\\"', '"', false); 255 } else if(str == ''){ 256 return str; 257 } 258 throw new Error('Error in String.unescapeDoubleQuotes: This is not a string: '+ (typeof this)); 259 }; 260 261 //TRIM function: only define, if the platform does not provide it already 262 if (!String.prototype.trim) { 263 264 console.info('WARNING: No String.trim() function defined, extending String with custom trim() function...'); 265 266 String.prototype.trim = function(){ 267 return this 268 .replace(/^\s\s*/, '') //remove whitespace at start... 269 .replace(/\s\s*$/, '');//... and whitespaces at the end of the String 270 }; 271 } 272 273 274 if(String.prototype.htmlEncode == null){ 275 276 /*jslint white: true, onevar: true, undef: true, nomen: true, eqeqeq: true, 277 plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true */ 278 /** 279 * HTML-Encode the supplied input 280 * 281 * Parameters: 282 * 283 * this/source {string} 284 * The text to be encoded. 285 * 286 * @param display {boolean} 287 * (optional) 288 * The output is intended for display. 289 * 290 * If true (or undefined): 291 * * Tabs will be expanded to the number of spaces 292 * indicated by the 'tabs' argument. 293 * * Line breaks will be converted to <br />. 294 * 295 * If false: 296 * * Tabs and linebreaks get turned into ____; 297 * entities just like all other control characters. 298 * 299 * @param tabs {number} 300 * (optional) 301 * The number of spaces to expand tabs to. 302 * (Ignored if the 'display' parameter evaluates to false 303 * or if tabs is not >= 0.) 304 * 305 * Default: undefined (do not replace tabs with spaces) 306 * 307 * version 2010-11-08 (modified: 2012-12-20) 308 */ 309 310 String.prototype.htmlEncode = function (display, tabs) { 311 var i, s, ch, peek, line, result, 312 next, endline, push, 313 spaces, source = this; 314 315 //'parse' parameters 316 if(typeof display === 'number'){ 317 //use as tabs-parameter 318 tabs = display; 319 display = true; 320 } else if(typeof display === 'undefined'){ 321 display = true; 322 } 323 if(typeof tabs === 'string'){ 324 tabs = parseInt(tabs,10); 325 } else if(typeof tabs === 'number'){ 326 tabs = Math.floor(tabs); 327 } else { 328 tabs = -1; 329 } 330 331 // Stash the next character and advance the pointer 332 next = function () { 333 peek = source.charAt(i); 334 i += 1; 335 }; 336 337 // Start a new "line" of output, to be joined later by <br /> 338 endline = function () { 339 line = line.join(''); 340 if (display) { 341 // If a line starts or ends with a space, it evaporates in html 342 // unless it's an nbsp. 343 line = line.replace(/(^ )|( $)/g, ' '); 344 } 345 result.push(line); 346 line = []; 347 }; 348 349 // Push a character or its entity onto the current line 350 push = function () { 351 if (ch < ' ' || ch > '~') { 352 line.push('' + ch.charCodeAt(0) + ';'); 353 } else { 354 line.push(ch); 355 } 356 }; 357 358 359 result = []; 360 line = []; 361 362 i = 0; 363 next(); 364 while (i <= source.length) { // less than or equal, because i is always one ahead 365 ch = peek; 366 next(); 367 368 // HTML special chars. 369 switch (ch) { 370 case '<': 371 line.push('<'); 372 break; 373 case '>': 374 line.push('>'); 375 break; 376 case '&': 377 line.push('&'); 378 break; 379 case '"': 380 line.push('"'); 381 break; 382 case "'": 383 line.push('''); 384 break; 385 default: 386 // If the output is intended for display, 387 // then end lines on newlines, and replace tabs with spaces. 388 if (display) { 389 switch (ch) { 390 case '\r': 391 // If this \r is the beginning of a \r\n, skip over the \n part. 392 if (peek === '\n') { 393 next(); 394 } 395 endline(); 396 break; 397 case '\n': 398 endline(); 399 break; 400 case '\t': 401 // expand tabs? 402 if(tabs >= 0){ 403 spaces = tabs - (line.length % tabs); 404 for (s = 0; s < spaces; s += 1) { 405 line.push(' '); 406 } 407 } else{ 408 //otherwise: preserve tabs 409 push(' '); 410 } 411 break; 412 default: 413 // All other characters can be dealt with generically. 414 push(); 415 } 416 } else { 417 // If the output is not for display, 418 // then none of the characters need special treatment. 419 push(); 420 } 421 } 422 } 423 endline(); 424 425 // If you can't beat 'em, join 'em. 426 result = result.join('<br />'); 427 428 if (display) { 429 // Break up contiguous blocks of spaces with non-breaking spaces 430 result = result.replace(/ {2}/g, ' '); 431 } 432 433 // tada! 434 return result; 435 }; 436 437 } 438 }); 439