urlify.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*global XRegExp*/
  2. (function() {
  3. 'use strict';
  4. var LATIN_MAP = {
  5. 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE',
  6. 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I',
  7. 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O',
  8. 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U',
  9. 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a',
  10. 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c',
  11. 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i',
  12. 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o',
  13. 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',
  14. 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
  15. };
  16. var LATIN_SYMBOLS_MAP = {
  17. '©': '(c)'
  18. };
  19. var GREEK_MAP = {
  20. 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h',
  21. 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3',
  22. 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f',
  23. 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o',
  24. 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y',
  25. 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z',
  26. 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N',
  27. 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y',
  28. 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I',
  29. 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y'
  30. };
  31. var TURKISH_MAP = {
  32. 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u',
  33. 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G'
  34. };
  35. var ROMANIAN_MAP = {
  36. 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a',
  37. 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A'
  38. };
  39. var RUSSIAN_MAP = {
  40. 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
  41. 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm',
  42. 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
  43. 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '',
  44. 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
  45. 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
  46. 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M',
  47. 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
  48. 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '',
  49. 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
  50. };
  51. var UKRAINIAN_MAP = {
  52. 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i',
  53. 'ї': 'yi', 'ґ': 'g'
  54. };
  55. var CZECH_MAP = {
  56. 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't',
  57. 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R',
  58. 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z'
  59. };
  60. var POLISH_MAP = {
  61. 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's',
  62. 'ź': 'z', 'ż': 'z',
  63. 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S',
  64. 'Ź': 'Z', 'Ż': 'Z'
  65. };
  66. var LATVIAN_MAP = {
  67. 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l',
  68. 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z',
  69. 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L',
  70. 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z'
  71. };
  72. var ARABIC_MAP = {
  73. 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd',
  74. 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't',
  75. 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm',
  76. 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y'
  77. };
  78. var LITHUANIAN_MAP = {
  79. 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u',
  80. 'ū': 'u', 'ž': 'z',
  81. 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U',
  82. 'Ū': 'U', 'Ž': 'Z'
  83. };
  84. var SERBIAN_MAP = {
  85. 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz',
  86. 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C',
  87. 'Џ': 'Dz', 'Đ': 'Dj'
  88. };
  89. var AZERBAIJANI_MAP = {
  90. 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u',
  91. 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U'
  92. };
  93. var GEORGIAN_MAP = {
  94. 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z',
  95. 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o',
  96. 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f',
  97. 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz',
  98. 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h'
  99. };
  100. var ALL_DOWNCODE_MAPS = [
  101. LATIN_MAP,
  102. LATIN_SYMBOLS_MAP,
  103. GREEK_MAP,
  104. TURKISH_MAP,
  105. ROMANIAN_MAP,
  106. RUSSIAN_MAP,
  107. UKRAINIAN_MAP,
  108. CZECH_MAP,
  109. POLISH_MAP,
  110. LATVIAN_MAP,
  111. ARABIC_MAP,
  112. LITHUANIAN_MAP,
  113. SERBIAN_MAP,
  114. AZERBAIJANI_MAP,
  115. GEORGIAN_MAP
  116. ];
  117. var Downcoder = {
  118. 'Initialize': function() {
  119. if (Downcoder.map) { // already made
  120. return;
  121. }
  122. Downcoder.map = {};
  123. Downcoder.chars = [];
  124. for (var i = 0; i < ALL_DOWNCODE_MAPS.length; i++) {
  125. var lookup = ALL_DOWNCODE_MAPS[i];
  126. for (var c in lookup) {
  127. if (lookup.hasOwnProperty(c)) {
  128. Downcoder.map[c] = lookup[c];
  129. }
  130. }
  131. }
  132. for (var k in Downcoder.map) {
  133. if (Downcoder.map.hasOwnProperty(k)) {
  134. Downcoder.chars.push(k);
  135. }
  136. }
  137. Downcoder.regex = new RegExp(Downcoder.chars.join('|'), 'g');
  138. }
  139. };
  140. function downcode(slug) {
  141. Downcoder.Initialize();
  142. return slug.replace(Downcoder.regex, function(m) {
  143. return Downcoder.map[m];
  144. });
  145. }
  146. function URLify(s, num_chars, allowUnicode) {
  147. // changes, e.g., "Petty theft" to "petty-theft"
  148. // remove all these words from the string before urlifying
  149. if (!allowUnicode) {
  150. s = downcode(s);
  151. }
  152. var removelist = [
  153. "a", "an", "as", "at", "before", "but", "by", "for", "from", "is",
  154. "in", "into", "like", "of", "off", "on", "onto", "per", "since",
  155. "than", "the", "this", "that", "to", "up", "via", "with"
  156. ];
  157. var r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
  158. s = s.replace(r, '');
  159. // if downcode doesn't hit, the char will be stripped here
  160. if (allowUnicode) {
  161. // Keep Unicode letters including both lowercase and uppercase
  162. // characters, whitespace, and dash; remove other characters.
  163. s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), '');
  164. } else {
  165. s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
  166. }
  167. s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
  168. s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
  169. s = s.toLowerCase(); // convert to lowercase
  170. return s.substring(0, num_chars); // trim to first num_chars chars
  171. }
  172. window.URLify = URLify;
  173. })();