0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-11-25 05:02:57 +01:00

Move urlify (Django port) & remove xregexp vendor library

- Move vendor/urlify.js into our own codebase as a port of the Djago util
- Remove the need for xregexp polyfill library
This commit is contained in:
LB Johnston 2023-11-01 19:12:12 +10:00 committed by LB (Ben Johnston)
parent f0cf73f0d3
commit be5b69078a
8 changed files with 549 additions and 232 deletions

View File

@ -229,8 +229,6 @@ describe('compare behaviour', () => {
});
describe('urlify behaviour', () => {
require('../../../wagtail/admin/static_src/wagtailadmin/js/vendor/urlify')
.default;
let application;
beforeEach(() => {

View File

@ -77,6 +77,11 @@ export class SlugController extends Controller<HTMLInputElement> {
/**
* Advanced slugify of a string, updates the controlled element's value
* or can be used to simply return the transformed value.
*
* The urlify (Django port) function performs extra processing on the string &
* is more suitable for creating a slug from the title, rather than sanitising manually.
* If the urlify util returns an empty string it will fall back to the slugify method.
*
* If a custom event with detail.value is provided, that value will be used
* instead of the field's value.
*/
@ -84,9 +89,13 @@ export class SlugController extends Controller<HTMLInputElement> {
event: CustomEvent<{ value: string }> | { detail: { value: string } },
ignoreUpdate = false,
) {
const unicodeSlugsEnabled = this.allowUnicodeValue;
const { value = this.element.value } = event?.detail || {};
const newValue = urlify(value.trim(), { unicodeSlugsEnabled });
const trimmedValue = value.trim();
const newValue =
urlify(trimmedValue) ||
this.slugify({ detail: { value: trimmedValue } }, true);
if (!ignoreUpdate) {
this.element.value = newValue;

View File

@ -0,0 +1,494 @@
[
{
"LATIN_MAP": [
["À", "A"],
["Á", "A"],
["Â", "A"],
["Ã", "A"],
["Ä", "A"],
["Å", "A"],
["Æ", "AE"],
["Ç", "C"],
["È", "E"],
["É", "E"],
["Ê", "E"],
["Ë", "E"],
["Ì", "I"],
["Í", "I"],
["Î", "I"],
["Ï", "I"],
["Ð", "D"],
["Ñ", "N"],
["Ò", "O"],
["Ó", "O"],
["Ô", "O"],
["Õ", "O"],
["Ö", "O"],
["Ő", "O"],
["Ø", "O"],
["Ù", "U"],
["Ú", "U"],
["Û", "U"],
["Ü", "U"],
["Ű", "U"],
["Ý", "Y"],
["Þ", "TH"],
["Ÿ", "Y"],
["ß", "ss"],
["à", "a"],
["á", "a"],
["â", "a"],
["ã", "a"],
["ä", "a"],
["å", "a"],
["æ", "ae"],
["ç", "c"],
["è", "e"],
["é", "e"],
["ê", "e"],
["ë", "e"],
["ì", "i"],
["í", "i"],
["î", "i"],
["ï", "i"],
["ð", "d"],
["ñ", "n"],
["ò", "o"],
["ó", "o"],
["ô", "o"],
["õ", "o"],
["ö", "o"],
["ő", "o"],
["ø", "o"],
["ù", "u"],
["ú", "u"],
["û", "u"],
["ü", "u"],
["ű", "u"],
["ý", "y"],
["þ", "th"],
["ÿ", "y"]
]
},
{ "LATIN_SYMBOLS_MAP": [["©", "(c)"]] },
{
"GREEK_MAP": [
["α", "a"],
["β", "b"],
["γ", "g"],
["δ", "d"],
["ε", "e"],
["ζ", "z"],
["η", "h"],
["θ", "8"],
["ι", "i"],
["κ", "k"],
["λ", "l"],
["μ", "m"],
["ν", "n"],
["ξ", "3"],
["ο", "o"],
["π", "p"],
["ρ", "r"],
["σ", "s"],
["τ", "t"],
["υ", "y"],
["φ", "f"],
["χ", "x"],
["ψ", "ps"],
["ω", "w"],
["ά", "a"],
["έ", "e"],
["ί", "i"],
["ό", "o"],
["ύ", "y"],
["ή", "h"],
["ώ", "w"],
["ς", "s"],
["ϊ", "i"],
["ΰ", "y"],
["ϋ", "y"],
["ΐ", "i"],
["Α", "A"],
["Β", "B"],
["Γ", "G"],
["Δ", "D"],
["Ε", "E"],
["Ζ", "Z"],
["Η", "H"],
["Θ", "8"],
["Ι", "I"],
["Κ", "K"],
["Λ", "L"],
["Μ", "M"],
["Ν", "N"],
["Ξ", "3"],
["Ο", "O"],
["Π", "P"],
["Ρ", "R"],
["Σ", "S"],
["Τ", "T"],
["Υ", "Y"],
["Φ", "F"],
["Χ", "X"],
["Ψ", "PS"],
["Ω", "W"],
["Ά", "A"],
["Έ", "E"],
["Ί", "I"],
["Ό", "O"],
["Ύ", "Y"],
["Ή", "H"],
["Ώ", "W"],
["Ϊ", "I"],
["Ϋ", "Y"]
]
},
{
"TURKISH_MAP": [
["ş", "s"],
["Ş", "S"],
["ı", "i"],
["İ", "I"],
["ç", "c"],
["Ç", "C"],
["ü", "u"],
["Ü", "U"],
["ö", "o"],
["Ö", "O"],
["ğ", "g"],
["Ğ", "G"]
]
},
{
"ROMANIAN_MAP": [
["ă", "a"],
["î", "i"],
["ș", "s"],
["ț", "t"],
["â", "a"],
["Ă", "A"],
["Î", "I"],
["Ș", "S"],
["Ț", "T"],
["Â", "A"]
]
},
{
"RUSSIAN_MAP": [
["а", "a"],
["б", "b"],
["в", "v"],
["г", "g"],
["д", "d"],
["е", "e"],
["ё", "yo"],
["ж", "zh"],
["з", "z"],
["и", "i"],
["й", "j"],
["к", "k"],
["л", "l"],
["м", "m"],
["н", "n"],
["о", "o"],
["п", "p"],
["р", "r"],
["с", "s"],
["т", "t"],
["у", "u"],
["ф", "f"],
["х", "h"],
["ц", "c"],
["ч", "ch"],
["ш", "sh"],
["щ", "sh"],
["ъ", ""],
["ы", "y"],
["ь", ""],
["э", "e"],
["ю", "yu"],
["я", "ya"],
["А", "A"],
["Б", "B"],
["В", "V"],
["Г", "G"],
["Д", "D"],
["Е", "E"],
["Ё", "Yo"],
["Ж", "Zh"],
["З", "Z"],
["И", "I"],
["Й", "J"],
["К", "K"],
["Л", "L"],
["М", "M"],
["Н", "N"],
["О", "O"],
["П", "P"],
["Р", "R"],
["С", "S"],
["Т", "T"],
["У", "U"],
["Ф", "F"],
["Х", "H"],
["Ц", "C"],
["Ч", "Ch"],
["Ш", "Sh"],
["Щ", "Sh"],
["Ъ", ""],
["Ы", "Y"],
["Ь", ""],
["Э", "E"],
["Ю", "Yu"],
["Я", "Ya"]
]
},
{
"UKRAINIAN_MAP": [
["Є", "Ye"],
["І", "I"],
["Ї", "Yi"],
["Ґ", "G"],
["є", "ye"],
["і", "i"],
["ї", "yi"],
["ґ", "g"]
]
},
{
"CZECH_MAP": [
["č", "c"],
["ď", "d"],
["ě", "e"],
["ň", "n"],
["ř", "r"],
["š", "s"],
["ť", "t"],
["ů", "u"],
["ž", "z"],
["Č", "C"],
["Ď", "D"],
["Ě", "E"],
["Ň", "N"],
["Ř", "R"],
["Š", "S"],
["Ť", "T"],
["Ů", "U"],
["Ž", "Z"]
]
},
{
"SLOVAK_MAP": [
["á", "a"],
["ä", "a"],
["č", "c"],
["ď", "d"],
["é", "e"],
["í", "i"],
["ľ", "l"],
["ĺ", "l"],
["ň", "n"],
["ó", "o"],
["ô", "o"],
["ŕ", "r"],
["š", "s"],
["ť", "t"],
["ú", "u"],
["ý", "y"],
["ž", "z"],
["Á", "a"],
["Ä", "A"],
["Č", "C"],
["Ď", "D"],
["É", "E"],
["Í", "I"],
["Ľ", "L"],
["Ĺ", "L"],
["Ň", "N"],
["Ó", "O"],
["Ô", "O"],
["Ŕ", "R"],
["Š", "S"],
["Ť", "T"],
["Ú", "U"],
["Ý", "Y"],
["Ž", "Z"]
]
},
{
"POLISH_MAP": [
["ą", "a"],
["ć", "c"],
["ę", "e"],
["ł", "l"],
["ń", "n"],
["ó", "o"],
["ś", "s"],
["ź", "z"],
["ż", "z"],
["Ą", "A"],
["Ć", "C"],
["Ę", "E"],
["Ł", "L"],
["Ń", "N"],
["Ó", "O"],
["Ś", "S"],
["Ź", "Z"],
["Ż", "Z"]
]
},
{
"LATVIAN_MAP": [
["ā", "a"],
["č", "c"],
["ē", "e"],
["ģ", "g"],
["ī", "i"],
["ķ", "k"],
["ļ", "l"],
["ņ", "n"],
["š", "s"],
["ū", "u"],
["ž", "z"],
["Ā", "A"],
["Č", "C"],
["Ē", "E"],
["Ģ", "G"],
["Ī", "I"],
["Ķ", "K"],
["Ļ", "L"],
["Ņ", "N"],
["Š", "S"],
["Ū", "U"],
["Ž", "Z"]
]
},
{
"ARABIC_MAP": [
["أ", "a"],
["ب", "b"],
["ت", "t"],
["ث", "th"],
["ج", "g"],
["ح", "h"],
["خ", "kh"],
["د", "d"],
["ذ", "th"],
["ر", "r"],
["ز", "z"],
["س", "s"],
["ش", "sh"],
["ص", "s"],
["ض", "d"],
["ط", "t"],
["ظ", "th"],
["ع", "aa"],
["غ", "gh"],
["ف", "f"],
["ق", "k"],
["ك", "k"],
["ل", "l"],
["م", "m"],
["ن", "n"],
["ه", "h"],
["و", "o"],
["ي", "y"]
]
},
{
"LITHUANIAN_MAP": [
["ą", "a"],
["č", "c"],
["ę", "e"],
["ė", "e"],
["į", "i"],
["š", "s"],
["ų", "u"],
["ū", "u"],
["ž", "z"],
["Ą", "A"],
["Č", "C"],
["Ę", "E"],
["Ė", "E"],
["Į", "I"],
["Š", "S"],
["Ų", "U"],
["Ū", "U"],
["Ž", "Z"]
]
},
{
"SERBIAN_MAP": [
["ђ", "dj"],
["ј", "j"],
["љ", "lj"],
["њ", "nj"],
["ћ", "c"],
["џ", "dz"],
["đ", "dj"],
["Ђ", "Dj"],
["Ј", "j"],
["Љ", "Lj"],
["Њ", "Nj"],
["Ћ", "C"],
["Џ", "Dz"],
["Đ", "Dj"]
]
},
{
"AZERBAIJANI_MAP": [
["ç", "c"],
["ə", "e"],
["ğ", "g"],
["ı", "i"],
["ö", "o"],
["ş", "s"],
["ü", "u"],
["Ç", "C"],
["Ə", "E"],
["Ğ", "G"],
["İ", "I"],
["Ö", "O"],
["Ş", "S"],
["Ü", "U"]
]
},
{
"GEORGIAN_MAP": [
["ა", "a"],
["ბ", "b"],
["გ", "g"],
["დ", "d"],
["ე", "e"],
["ვ", "v"],
["ზ", "z"],
["თ", "t"],
["ი", "i"],
["კ", "k"],
["ლ", "l"],
["მ", "m"],
["ნ", "n"],
["ო", "o"],
["პ", "p"],
["ჟ", "j"],
["რ", "r"],
["ს", "s"],
["ტ", "t"],
["უ", "u"],
["ფ", "f"],
["ქ", "q"],
["ღ", "g"],
["", "y"],
["შ", "sh"],
["ჩ", "ch"],
["ც", "c"],
["ძ", "dz"],
["წ", "w"],
["ჭ", "ch"],
["ხ", "x"],
["ჯ", "j"],
["ჰ", "h"]
]
}
]

View File

@ -1,16 +1,10 @@
import { urlify } from './urlify';
describe('urlify', () => {
beforeAll(() => {
// load window.URLify
require('../../../wagtail/admin/static_src/wagtailadmin/js/vendor/urlify')
.default;
});
describe('urlify with unicode slugs disabled (default)', () => {
it('should return a correct slug which is escaped by urlify', () => {
expect(urlify('This & That')).toBe('this-that');
expect(urlify('The Price is $72.00!')).toBe('the-price-is-7200');
expect(urlify('Lisboa é ótima à beira-mar')).toBe(
'lisboa-e-otima-a-beira-mar',
);
@ -18,7 +12,7 @@ describe('urlify', () => {
});
describe('urlify with unicode slugs enabled', () => {
const options = { unicodeSlugsEnabled: true };
const options = { allowUnicode: true };
it('should return a correct slug which is escaped by urlify', () => {
expect(urlify('Before', options)).toBe('before');
@ -31,9 +25,9 @@ describe('urlify', () => {
'on-this-day-in-november',
);
expect(urlify('This & That', options)).toBe('this-that');
expect(urlify('The Price is $72.00!', options)).toBe('the-price-is-7200');
expect(urlify('Lisboa é ótima à beira-mar', options)).toBe(
'lisboa-e-otima-a-beira-mar',
'lisboa-é-ótima-à-beira-mar',
);
});
});

View File

@ -1,21 +1,45 @@
import { slugify } from './slugify';
import config from './urlify.config.json';
declare global {
interface Window {
URLify: any;
}
}
const downcodeMapping = config.reduce((acc, downcodeMap) => {
Object.values(downcodeMap)
.flat()
.forEach(([char, replacedChar]) => {
acc[char] = replacedChar;
});
return acc;
}, {});
const regex = new RegExp(Object.keys(downcodeMapping).join('|'), 'g');
/**
* Returns the supplied string as a slug suitable for a URL using the vendor URLify util.
* If the vendor util returns an empty string it will fall back to the slugify method.
* IMPORTANT This util and the mapping is a direct port of Django's urlify.js util,
* without the need for a full Regex polyfill implementation.
* @see https://github.com/django/django/blob/main/django/contrib/admin/static/admin/js/urlify.js
*/
export const urlify = (value: string, options = {}) => {
// URLify performs extra processing on the string (e.g. removing stopwords) and is more suitable
// for creating a slug from the title, rather than sanitising a slug entered manually
const cleaned = window.URLify(value, 255);
// if the result is blank (e.g. because the title consisted entirely of stopwords),
// fall through to the non-URLify method
return cleaned || slugify(value, options);
export const urlify = (
originalStr: string,
{
numChars = 255,
allowUnicode = false,
}: { numChars?: number; allowUnicode?: boolean } = {},
) => {
let str = originalStr;
// changes, e.g., "Petty theft" to "petty-theft"
if (!allowUnicode) {
str = str.replace(regex, (item) => downcodeMapping[item]);
}
str = str.toLowerCase(); // convert to lowercase
// if downcode doesn't hit, the char will be stripped here
if (allowUnicode) {
// Keep Unicode letters including both lowercase and uppercase
// characters, whitespace, and dash; remove other characters.
str = str.replace(/[^-_\p{L}\p{N}\s]/gu, '');
} else {
str = str.replace(/[^-\w\s]/g, ''); // remove unneeded chars
}
str = str.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
str = str.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
str = str.substring(0, numChars); // trim to first num_chars chars
str = str.replace(/-+$/g, ''); // trim any trailing hyphens
return str;
};

View File

@ -1,182 +0,0 @@
/*global XRegExp*/
(function() {
'use strict';
var LATIN_MAP = {
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE',
'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I',
'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O',
'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U',
'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a',
'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c',
'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i',
'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o',
'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',
'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
};
var LATIN_SYMBOLS_MAP = {
'©': '(c)'
};
var GREEK_MAP = {
'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h',
'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3',
'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f',
'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o',
'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y',
'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z',
'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N',
'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y',
'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I',
'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y'
};
var TURKISH_MAP = {
'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u',
'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G'
};
var ROMANIAN_MAP = {
'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a',
'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A'
};
var RUSSIAN_MAP = {
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm',
'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '',
'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M',
'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '',
'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
};
var UKRAINIAN_MAP = {
'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i',
'ї': 'yi', 'ґ': 'g'
};
var CZECH_MAP = {
'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't',
'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R',
'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z'
};
var SLOVAK_MAP = {
'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l',
'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't',
'ú': 'u', 'ý': 'y', 'ž': 'z',
'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L',
'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T',
'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z'
};
var POLISH_MAP = {
'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's',
'ź': 'z', 'ż': 'z',
'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S',
'Ź': 'Z', 'Ż': 'Z'
};
var LATVIAN_MAP = {
'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l',
'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z',
'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L',
'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z'
};
var ARABIC_MAP = {
'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd',
'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't',
'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm',
'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y'
};
var LITHUANIAN_MAP = {
'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u',
'ū': 'u', 'ž': 'z',
'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U',
'Ū': 'U', 'Ž': 'Z'
};
var SERBIAN_MAP = {
'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz',
'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C',
'Џ': 'Dz', 'Đ': 'Dj'
};
var AZERBAIJANI_MAP = {
'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u',
'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U'
};
var GEORGIAN_MAP = {
'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z',
'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o',
'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f',
'ქ': 'q', 'ღ': 'g', '': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz',
'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h'
};
var ALL_DOWNCODE_MAPS = [
LATIN_MAP,
LATIN_SYMBOLS_MAP,
GREEK_MAP,
TURKISH_MAP,
ROMANIAN_MAP,
RUSSIAN_MAP,
UKRAINIAN_MAP,
CZECH_MAP,
SLOVAK_MAP,
POLISH_MAP,
LATVIAN_MAP,
ARABIC_MAP,
LITHUANIAN_MAP,
SERBIAN_MAP,
AZERBAIJANI_MAP,
GEORGIAN_MAP
];
var Downcoder = {
'Initialize': function() {
if (Downcoder.map) { // already made
return;
}
Downcoder.map = {};
Downcoder.chars = [];
for (var i = 0; i < ALL_DOWNCODE_MAPS.length; i++) {
var lookup = ALL_DOWNCODE_MAPS[i];
for (var c in lookup) {
if (lookup.hasOwnProperty(c)) {
Downcoder.map[c] = lookup[c];
}
}
}
for (var k in Downcoder.map) {
if (Downcoder.map.hasOwnProperty(k)) {
Downcoder.chars.push(k);
}
}
Downcoder.regex = new RegExp(Downcoder.chars.join('|'), 'g');
}
};
function downcode(slug) {
Downcoder.Initialize();
return slug.replace(Downcoder.regex, function(m) {
return Downcoder.map[m];
});
}
function URLify(s, num_chars, allowUnicode) {
// changes, e.g., "Petty theft" to "petty-theft"
if (!allowUnicode) {
s = downcode(s);
}
s = s.toLowerCase(); // convert to lowercase
// if downcode doesn't hit, the char will be stripped here
if (allowUnicode) {
// Keep Unicode letters including both lowercase and uppercase
// characters, whitespace, and dash; remove other characters.
s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), '');
} else {
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
}
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
s = s.substring(0, num_chars); // trim to first num_chars chars
s = s.replace(/-+$/g, ''); // trim any trailing hyphens
return s;
}
window.URLify = URLify;
})();

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,5 @@
<script src="{% versioned_static 'wagtailadmin/js/expanding-formset.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/preview-panel.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/privacy-switch.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/vendor/xregexp.min.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/vendor/urlify.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/workflow-action.js' %}"></script>
{% hook_output 'insert_editor_js' %}