0002-admin-make-form-slugs-editable-by-the-admin-15663.patch
tests/test_admin_pages.py | ||
---|---|---|
319 | 319 |
assert_option_display(resp, 'Geolocation', 'Disabled') |
320 | 320 |
assert FormDef.get(formdef.id).geolocations is None |
321 | 321 | |
322 |
# try changing title |
|
322 |
def test_form_title_change(pub): |
|
323 |
create_superuser(pub) |
|
324 |
create_role() |
|
325 | ||
326 |
FormDef.wipe() |
|
327 |
formdef = FormDef() |
|
328 |
formdef.name = 'form title' |
|
329 |
formdef.fields = [] |
|
330 |
formdef.store() |
|
331 | ||
332 |
app = login(get_app(pub)) |
|
333 | ||
323 | 334 |
resp = app.get('/backoffice/forms/1/') |
324 | 335 |
resp = resp.click('change title') |
325 |
assert resp.forms[0]['name'].value == 'form title' |
|
326 |
resp.forms[0]['name'] = 'new title' |
|
327 |
resp = resp.forms[0].submit() |
|
336 |
assert resp.form['name'].value == 'form title' |
|
337 |
assert 'data-slug-sync' in resp.body |
|
338 |
assert not 'change-nevertheless' in resp.body |
|
339 |
resp.form['name'] = 'new title' |
|
340 |
resp = resp.form.submit() |
|
328 | 341 |
assert resp.location == 'http://example.net/backoffice/forms/1/' |
329 | 342 |
resp = resp.follow() |
330 |
assert FormDef.get(1).name == 'new title' |
|
331 |
assert FormDef.get(1).url_name == 'form-title' |
|
332 |
assert FormDef.get(1).internal_identifier == 'new-title' |
|
343 |
formdef = FormDef.get(formdef.id) |
|
344 |
assert formdef.name == 'new title' |
|
345 |
assert formdef.url_name == 'form-title' |
|
346 |
assert formdef.internal_identifier == 'new-title' |
|
347 | ||
348 |
resp = app.get('/backoffice/forms/1/') |
|
349 |
resp = resp.click('change title') |
|
350 |
assert not 'data-slug-sync' in resp.body |
|
351 |
assert not 'change-nevertheless' in resp.body |
|
352 | ||
353 |
formdef.data_class()().store() |
|
354 |
resp = app.get('/backoffice/forms/1/') |
|
355 |
resp = resp.click('change title') |
|
356 |
assert 'change-nevertheless' in resp.body |
|
357 | ||
358 |
formdef2 = FormDef() |
|
359 |
formdef2.name = 'other title' |
|
360 |
formdef2.fields = [] |
|
361 |
formdef2.store() |
|
362 | ||
363 |
resp = app.get('/backoffice/forms/%s/' % formdef2.id) |
|
364 |
resp = resp.click('change title') |
|
365 |
assert resp.form['name'].value == 'other title' |
|
366 |
resp.form['url_name'] = formdef.url_name |
|
367 |
resp = resp.form.submit() |
|
368 |
assert 'This identifier is already used.' in resp.body |
|
369 | ||
370 |
resp.form['url_name'] = 'foobar' |
|
371 |
resp = resp.form.submit().follow() |
|
372 |
assert FormDef.get(formdef2.id).url_name == 'foobar' |
|
333 | 373 | |
334 | 374 |
def test_form_category(pub): |
335 | 375 |
create_superuser(pub) |
wcs/admin/forms.py | ||
---|---|---|
670 | 670 | |
671 | 671 |
def title(self): |
672 | 672 |
form = Form(enctype='multipart/form-data') |
673 |
kwargs = {} |
|
674 |
if self.formdef.url_name == misc.simplify(self.formdef.name): |
|
675 |
# if name and url name are in sync, keep them that way |
|
676 |
kwargs['data-slug-sync'] = 'url_name' |
|
673 | 677 |
form.add(StringWidget, 'name', title=_('Form Title'), required=True, |
674 |
size=40, value=self.formdef.name) |
|
678 |
size=40, value=self.formdef.name, **kwargs) |
|
679 | ||
680 |
disabled_url_name = bool(self.formdef.data_class().count()) |
|
681 |
kwargs = {} |
|
682 |
if disabled_url_name: |
|
683 |
kwargs['readonly'] = 'readonly' |
|
684 |
form.add(ValidatedStringWidget, 'url_name', title=_('Identifier in URLs'), |
|
685 |
size=40, required=True, value=self.formdef.url_name, |
|
686 |
regex=r'^[a-zA-Z0-9_-]+', **kwargs) |
|
675 | 687 |
form.add_submit('submit', _('Submit')) |
676 | 688 |
form.add_submit('cancel', _('Cancel')) |
677 | 689 |
if form.get_widget('cancel').parse(): |
... | ... | |
679 | 691 | |
680 | 692 |
if form.is_submitted() and not form.has_errors(): |
681 | 693 |
new_name = form.get_widget('name').parse() |
682 |
formdefs_name = [x.name for x in FormDef.select(ignore_errors=True) |
|
683 |
if x.id != self.formdef.id] |
|
684 |
if new_name in formdefs_name: |
|
685 |
form.get_widget('name').set_error(_('This name is already used')) |
|
686 |
else: |
|
694 |
new_url_name = form.get_widget('url_name').parse() |
|
695 |
formdefs = [x for x in FormDef.select(ignore_errors=True) if x.id != self.formdef.id] |
|
696 |
if new_name in [x.name for x in formdefs]: |
|
697 |
form.get_widget('name').set_error(_('This name is already used.')) |
|
698 |
if new_url_name in [x.url_name for x in formdefs]: |
|
699 |
form.get_widget('url_name').set_error(_('This identifier is already used.')) |
|
700 |
if not form.has_errors(): |
|
687 | 701 |
self.formdef.name = new_name |
702 |
self.formdef.url_name = new_url_name |
|
688 | 703 |
self.formdef.store() |
689 | 704 |
return redirect('.') |
690 | 705 | |
706 |
if disabled_url_name: |
|
707 |
form.widgets.append(HtmlWidget('<p>%s<br>' % _( |
|
708 |
'The form identifier should not be modified as there is already some data.'))) |
|
709 |
form.widgets.append(HtmlWidget('<a href="" class="change-nevertheless">%s</a></p>' % _( |
|
710 |
'I understand the danger, make it editable nevertheless.'))) |
|
711 | ||
691 | 712 |
get_response().breadcrumb.append( ('title', _('Title')) ) |
692 | 713 |
self.html_top(title=self.formdef.name) |
693 | 714 |
r = TemplateIO(html=True) |
694 | 715 |
r += htmltext('<h2>%s</h2>') % _('Title') |
695 |
r += htmltext('<p>%s</p>') % _('Choose a title for this form') |
|
696 | 716 |
r += form.render() |
697 | 717 |
return r.getvalue() |
698 | 718 |
wcs/qommon/http_response.py | ||
---|---|---|
84 | 84 |
self.add_javascript_code('var QOMMON_ROOT_URL = "%s";\n' % \ |
85 | 85 |
get_publisher().get_application_static_files_root_url()) |
86 | 86 |
if script_name == 'qommon.geolocation.js': |
87 |
self.add_javascript(['jquery.js']) |
|
87 |
self.add_javascript(['jquery.js', 'qommon.slugify.js'])
|
|
88 | 88 |
self.add_javascript_code('var WCS_ROOT_URL = "%s";\n' % \ |
89 | 89 |
get_publisher().get_frontoffice_url()) |
90 | 90 |
if script_name == 'wcs.listing.js': |
91 | 91 |
self.add_javascript(['jquery.js']) |
92 |
if script_name == 'qommon.admin.js': |
|
93 |
self.add_javascript(['jquery.js', 'qommon.slugify.js']) |
|
92 | 94 | |
93 | 95 |
def add_javascript_code(self, code): |
94 | 96 |
if not self.javascript_code_parts: |
wcs/qommon/static/css/dc2/admin.css | ||
---|---|---|
610 | 610 |
padding: 5px 8px; |
611 | 611 |
background: white; |
612 | 612 |
color: black; |
613 |
transition: background ease-out 0.3s; |
|
613 | 614 |
} |
614 | 615 | |
615 | 616 |
div.TextWidget textarea:focus, |
... | ... | |
1611 | 1612 |
a.leaflet-popup-close-button { |
1612 | 1613 |
border: 0; |
1613 | 1614 |
} |
1615 | ||
1616 |
div.widget input[type=text][readonly] { |
|
1617 |
background: #f0f0f0; |
|
1618 |
} |
wcs/qommon/static/js/qommon.admin.js | ||
---|---|---|
61 | 61 |
return false; |
62 | 62 |
}); |
63 | 63 | |
64 |
/* keep title/slug in sync */ |
|
65 |
$('body').delegate('input[data-slug-sync]', 'keyup change paste', |
|
66 |
function() { |
|
67 |
var $slug_field = $(this).parents('form').find('[name=' + $(this).data('slug-sync') + ']'); |
|
68 |
if ($slug_field.prop('readonly')) return; |
|
69 |
$slug_field.val($.slugify($(this).val())); |
|
70 |
}); |
|
71 | ||
72 |
/* remove readonly attribute from fields */ |
|
73 |
$('body').delegate('a.change-nevertheless', 'click', function(e) { |
|
74 |
var readonly_fields = $(this).parents('form').find('input[readonly]'); |
|
75 |
console.log(readonly_fields); |
|
76 |
if (readonly_fields.length) { |
|
77 |
console.log('a'); |
|
78 |
readonly_fields.prop('readonly', false); |
|
79 |
readonly_fields[0].focus(); |
|
80 |
} |
|
81 |
$(this).parent().hide(); |
|
82 |
return false; |
|
83 |
}); |
|
84 | ||
64 | 85 |
/* submission channel */ |
65 | 86 |
$('div.submit-channel-selection').show().find('select').on('change', function() { |
66 | 87 |
$('input[type=hidden][name=submission_channel]').val($(this).val()); |
wcs/qommon/static/js/qommon.geolocation.js | ||
---|---|---|
1 | 1 |
$(function() { |
2 |
/* the slugify code is adapted from the urlify code of django, |
|
3 |
* django/contrib/admin/static/admin/js/urlify.js. |
|
4 |
*/ |
|
5 | ||
6 |
var LATIN_MAP = { |
|
7 |
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç': |
|
8 |
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I', |
|
9 |
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö': |
|
10 |
'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U', |
|
11 |
'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': |
|
12 |
'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', |
|
13 |
'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': |
|
14 |
'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', |
|
15 |
'ú': 'u', 'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' |
|
16 |
}; |
|
17 |
var LATIN_SYMBOLS_MAP = { |
|
18 |
'©':'(c)' |
|
19 |
}; |
|
20 |
var GREEK_MAP = { |
|
21 |
'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8', |
|
22 |
'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p', |
|
23 |
'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w', |
|
24 |
'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s', |
|
25 |
'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i', |
|
26 |
'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8', |
|
27 |
'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P', |
|
28 |
'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W', |
|
29 |
'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I', |
|
30 |
'Ϋ':'Y' |
|
31 |
}; |
|
32 |
var TURKISH_MAP = { |
|
33 |
'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U', |
|
34 |
'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G' |
|
35 |
}; |
|
36 |
var RUSSIAN_MAP = { |
|
37 |
'а':'a', 'б':'b', 'в':'v', 'г':'g', 'д':'d', 'е':'e', 'ё':'yo', 'ж':'zh', |
|
38 |
'з':'z', 'и':'i', 'й':'j', 'к':'k', 'л':'l', 'м':'m', 'н':'n', 'о':'o', |
|
39 |
'п':'p', 'р':'r', 'с':'s', 'т':'t', 'у':'u', 'ф':'f', 'х':'h', 'ц':'c', |
|
40 |
'ч':'ch', 'ш':'sh', 'щ':'sh', 'ъ':'', 'ы':'y', 'ь':'', 'э':'e', 'ю':'yu', |
|
41 |
'я':'ya', |
|
42 |
'А':'A', 'Б':'B', 'В':'V', 'Г':'G', 'Д':'D', 'Е':'E', 'Ё':'Yo', 'Ж':'Zh', |
|
43 |
'З':'Z', 'И':'I', 'Й':'J', 'К':'K', 'Л':'L', 'М':'M', 'Н':'N', 'О':'O', |
|
44 |
'П':'P', 'Р':'R', 'С':'S', 'Т':'T', 'У':'U', 'Ф':'F', 'Х':'H', 'Ц':'C', |
|
45 |
'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu', |
|
46 |
'Я':'Ya' |
|
47 |
}; |
|
48 |
var UKRAINIAN_MAP = { |
|
49 |
'Є':'Ye', 'І':'I', 'Ї':'Yi', 'Ґ':'G', 'є':'ye', 'і':'i', 'ї':'yi', 'ґ':'g' |
|
50 |
}; |
|
51 |
var CZECH_MAP = { |
|
52 |
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u', |
|
53 |
'ž':'z', 'Č':'C', 'Ď':'D', 'Ě':'E', 'Ň': 'N', 'Ř':'R', 'Š':'S', 'Ť':'T', |
|
54 |
'Ů':'U', 'Ž':'Z' |
|
55 |
}; |
|
56 |
var POLISH_MAP = { |
|
57 |
'ą':'a', 'ć':'c', 'ę':'e', 'ł':'l', 'ń':'n', 'ó':'o', 'ś':'s', 'ź':'z', |
|
58 |
'ż':'z', 'Ą':'A', 'Ć':'C', 'Ę':'E', 'Ł':'L', 'Ń':'N', 'Ó':'O', 'Ś':'S', |
|
59 |
'Ź':'Z', 'Ż':'Z' |
|
60 |
}; |
|
61 |
var LATVIAN_MAP = { |
|
62 |
'ā':'a', 'č':'c', 'ē':'e', 'ģ':'g', 'ī':'i', 'ķ':'k', 'ļ':'l', 'ņ':'n', |
|
63 |
'š':'s', 'ū':'u', 'ž':'z', 'Ā':'A', 'Č':'C', 'Ē':'E', 'Ģ':'G', 'Ī':'I', |
|
64 |
'Ķ':'K', 'Ļ':'L', 'Ņ':'N', 'Š':'S', 'Ū':'U', 'Ž':'Z' |
|
65 |
}; |
|
66 |
var ARABIC_MAP = { |
|
67 |
'أ':'a', 'ب':'b', 'ت':'t', 'ث': 'th', 'ج':'g', 'ح':'h', 'خ':'kh', 'د':'d', |
|
68 |
'ذ':'th', 'ر':'r', 'ز':'z', 'س':'s', 'ش':'sh', 'ص':'s', 'ض':'d', 'ط':'t', |
|
69 |
'ظ':'th', 'ع':'aa', 'غ':'gh', 'ف':'f', 'ق':'k', 'ك':'k', 'ل':'l', 'م':'m', |
|
70 |
'ن':'n', 'ه':'h', 'و':'o', 'ي':'y' |
|
71 |
}; |
|
72 |
var LITHUANIAN_MAP = { |
|
73 |
'ą':'a', 'č':'c', 'ę':'e', 'ė':'e', 'į':'i', 'š':'s', 'ų':'u', 'ū':'u', |
|
74 |
'ž':'z', |
|
75 |
'Ą':'A', 'Č':'C', 'Ę':'E', 'Ė':'E', 'Į':'I', 'Š':'S', 'Ų':'U', 'Ū':'U', |
|
76 |
'Ž':'Z' |
|
77 |
}; |
|
78 |
var SERBIAN_MAP = { |
|
79 |
'ђ':'dj', 'ј':'j', 'љ':'lj', 'њ':'nj', 'ћ':'c', 'џ':'dz', 'đ':'dj', |
|
80 |
'Ђ':'Dj', 'Ј':'j', 'Љ':'Lj', 'Њ':'Nj', 'Ћ':'C', 'Џ':'Dz', 'Đ':'Dj' |
|
81 |
}; |
|
82 |
var AZERBAIJANI_MAP = { |
|
83 |
'ç':'c', 'ə':'e', 'ğ':'g', 'ı':'i', 'ö':'o', 'ş':'s', 'ü':'u', |
|
84 |
'Ç':'C', 'Ə':'E', 'Ğ':'G', 'İ':'I', 'Ö':'O', 'Ş':'S', 'Ü':'U' |
|
85 |
}; |
|
86 | ||
87 |
var ALL_DOWNCODE_MAPS = [ |
|
88 |
LATIN_MAP, |
|
89 |
LATIN_SYMBOLS_MAP, |
|
90 |
GREEK_MAP, |
|
91 |
TURKISH_MAP, |
|
92 |
RUSSIAN_MAP, |
|
93 |
UKRAINIAN_MAP, |
|
94 |
CZECH_MAP, |
|
95 |
POLISH_MAP, |
|
96 |
LATVIAN_MAP, |
|
97 |
ARABIC_MAP, |
|
98 |
LITHUANIAN_MAP, |
|
99 |
SERBIAN_MAP, |
|
100 |
AZERBAIJANI_MAP |
|
101 |
]; |
|
102 | ||
103 |
var Downcoder = { |
|
104 |
'Initialize': function() { |
|
105 |
if (Downcoder.map) { // already made |
|
106 |
return; |
|
107 |
} |
|
108 |
Downcoder.map = {}; |
|
109 |
Downcoder.chars = []; |
|
110 |
for (var i=0; i<ALL_DOWNCODE_MAPS.length; i++) { |
|
111 |
var lookup = ALL_DOWNCODE_MAPS[i]; |
|
112 |
for (var c in lookup) { |
|
113 |
if (lookup.hasOwnProperty(c)) { |
|
114 |
Downcoder.map[c] = lookup[c]; |
|
115 |
} |
|
116 |
} |
|
117 |
} |
|
118 |
for (var k in Downcoder.map) { |
|
119 |
if (Downcoder.map.hasOwnProperty(k)) { |
|
120 |
Downcoder.chars.push(k); |
|
121 |
} |
|
122 |
} |
|
123 |
Downcoder.regex = new RegExp(Downcoder.chars.join('|'), 'g'); |
|
124 |
} |
|
125 |
}; |
|
126 | ||
127 |
function slugify(value) { |
|
128 |
Downcoder.Initialize(); |
|
129 |
s = value.replace(Downcoder.regex, function(m) {return Downcoder.map[m]; }); |
|
130 |
s = s.replace("'", ' '); // keep quotes as spaces |
|
131 |
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars |
|
132 |
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces |
|
133 |
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens |
|
134 |
s = s.toLowerCase(); // convert to lowercase |
|
135 |
return s; |
|
136 |
} |
|
137 | ||
138 | 2 |
function geoloc_prefill(element_type, element_value) |
139 | 3 |
{ |
140 | 4 |
$('div[data-geolocation="' + element_type +'"] input').val(element_value); |
... | ... | |
142 | 6 |
var $options = $('div[data-geolocation="' + element_type +'"] option'); |
143 | 7 |
if ($options.length == 0) return; |
144 | 8 | |
145 |
var slugified_value = slugify(element_value); |
|
9 |
var slugified_value = $.slugify(element_value);
|
|
146 | 10 |
for (var i=0; i<$options.length; i++) { |
147 | 11 |
var $option = $($options[i]); |
148 | 12 |
if (slugify($option.val()) == slugified_value || |
wcs/qommon/static/js/qommon.slugify.js | ||
---|---|---|
1 |
$(function() { |
|
2 |
/* the slugify code is adapted from the urlify code of django, |
|
3 |
* django/contrib/admin/static/admin/js/urlify.js. |
|
4 |
*/ |
|
5 | ||
6 |
var LATIN_MAP = { |
|
7 |
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç': |
|
8 |
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I', |
|
9 |
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö': |
|
10 |
'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U', |
|
11 |
'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': |
|
12 |
'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', |
|
13 |
'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': |
|
14 |
'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', |
|
15 |
'ú': 'u', 'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' |
|
16 |
}; |
|
17 |
var LATIN_SYMBOLS_MAP = { |
|
18 |
'©':'(c)' |
|
19 |
}; |
|
20 |
var GREEK_MAP = { |
|
21 |
'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8', |
|
22 |
'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p', |
|
23 |
'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w', |
|
24 |
'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s', |
|
25 |
'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i', |
|
26 |
'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8', |
|
27 |
'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P', |
|
28 |
'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W', |
|
29 |
'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I', |
|
30 |
'Ϋ':'Y' |
|
31 |
}; |
|
32 |
var TURKISH_MAP = { |
|
33 |
'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U', |
|
34 |
'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G' |
|
35 |
}; |
|
36 |
var RUSSIAN_MAP = { |
|
37 |
'а':'a', 'б':'b', 'в':'v', 'г':'g', 'д':'d', 'е':'e', 'ё':'yo', 'ж':'zh', |
|
38 |
'з':'z', 'и':'i', 'й':'j', 'к':'k', 'л':'l', 'м':'m', 'н':'n', 'о':'o', |
|
39 |
'п':'p', 'р':'r', 'с':'s', 'т':'t', 'у':'u', 'ф':'f', 'х':'h', 'ц':'c', |
|
40 |
'ч':'ch', 'ш':'sh', 'щ':'sh', 'ъ':'', 'ы':'y', 'ь':'', 'э':'e', 'ю':'yu', |
|
41 |
'я':'ya', |
|
42 |
'А':'A', 'Б':'B', 'В':'V', 'Г':'G', 'Д':'D', 'Е':'E', 'Ё':'Yo', 'Ж':'Zh', |
|
43 |
'З':'Z', 'И':'I', 'Й':'J', 'К':'K', 'Л':'L', 'М':'M', 'Н':'N', 'О':'O', |
|
44 |
'П':'P', 'Р':'R', 'С':'S', 'Т':'T', 'У':'U', 'Ф':'F', 'Х':'H', 'Ц':'C', |
|
45 |
'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu', |
|
46 |
'Я':'Ya' |
|
47 |
}; |
|
48 |
var UKRAINIAN_MAP = { |
|
49 |
'Є':'Ye', 'І':'I', 'Ї':'Yi', 'Ґ':'G', 'є':'ye', 'і':'i', 'ї':'yi', 'ґ':'g' |
|
50 |
}; |
|
51 |
var CZECH_MAP = { |
|
52 |
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u', |
|
53 |
'ž':'z', 'Č':'C', 'Ď':'D', 'Ě':'E', 'Ň': 'N', 'Ř':'R', 'Š':'S', 'Ť':'T', |
|
54 |
'Ů':'U', 'Ž':'Z' |
|
55 |
}; |
|
56 |
var POLISH_MAP = { |
|
57 |
'ą':'a', 'ć':'c', 'ę':'e', 'ł':'l', 'ń':'n', 'ó':'o', 'ś':'s', 'ź':'z', |
|
58 |
'ż':'z', 'Ą':'A', 'Ć':'C', 'Ę':'E', 'Ł':'L', 'Ń':'N', 'Ó':'O', 'Ś':'S', |
|
59 |
'Ź':'Z', 'Ż':'Z' |
|
60 |
}; |
|
61 |
var LATVIAN_MAP = { |
|
62 |
'ā':'a', 'č':'c', 'ē':'e', 'ģ':'g', 'ī':'i', 'ķ':'k', 'ļ':'l', 'ņ':'n', |
|
63 |
'š':'s', 'ū':'u', 'ž':'z', 'Ā':'A', 'Č':'C', 'Ē':'E', 'Ģ':'G', 'Ī':'I', |
|
64 |
'Ķ':'K', 'Ļ':'L', 'Ņ':'N', 'Š':'S', 'Ū':'U', 'Ž':'Z' |
|
65 |
}; |
|
66 |
var ARABIC_MAP = { |
|
67 |
'أ':'a', 'ب':'b', 'ت':'t', 'ث': 'th', 'ج':'g', 'ح':'h', 'خ':'kh', 'د':'d', |
|
68 |
'ذ':'th', 'ر':'r', 'ز':'z', 'س':'s', 'ش':'sh', 'ص':'s', 'ض':'d', 'ط':'t', |
|
69 |
'ظ':'th', 'ع':'aa', 'غ':'gh', 'ف':'f', 'ق':'k', 'ك':'k', 'ل':'l', 'م':'m', |
|
70 |
'ن':'n', 'ه':'h', 'و':'o', 'ي':'y' |
|
71 |
}; |
|
72 |
var LITHUANIAN_MAP = { |
|
73 |
'ą':'a', 'č':'c', 'ę':'e', 'ė':'e', 'į':'i', 'š':'s', 'ų':'u', 'ū':'u', |
|
74 |
'ž':'z', |
|
75 |
'Ą':'A', 'Č':'C', 'Ę':'E', 'Ė':'E', 'Į':'I', 'Š':'S', 'Ų':'U', 'Ū':'U', |
|
76 |
'Ž':'Z' |
|
77 |
}; |
|
78 |
var SERBIAN_MAP = { |
|
79 |
'ђ':'dj', 'ј':'j', 'љ':'lj', 'њ':'nj', 'ћ':'c', 'џ':'dz', 'đ':'dj', |
|
80 |
'Ђ':'Dj', 'Ј':'j', 'Љ':'Lj', 'Њ':'Nj', 'Ћ':'C', 'Џ':'Dz', 'Đ':'Dj' |
|
81 |
}; |
|
82 |
var AZERBAIJANI_MAP = { |
|
83 |
'ç':'c', 'ə':'e', 'ğ':'g', 'ı':'i', 'ö':'o', 'ş':'s', 'ü':'u', |
|
84 |
'Ç':'C', 'Ə':'E', 'Ğ':'G', 'İ':'I', 'Ö':'O', 'Ş':'S', 'Ü':'U' |
|
85 |
}; |
|
86 | ||
87 |
var ALL_DOWNCODE_MAPS = [ |
|
88 |
LATIN_MAP, |
|
89 |
LATIN_SYMBOLS_MAP, |
|
90 |
GREEK_MAP, |
|
91 |
TURKISH_MAP, |
|
92 |
RUSSIAN_MAP, |
|
93 |
UKRAINIAN_MAP, |
|
94 |
CZECH_MAP, |
|
95 |
POLISH_MAP, |
|
96 |
LATVIAN_MAP, |
|
97 |
ARABIC_MAP, |
|
98 |
LITHUANIAN_MAP, |
|
99 |
SERBIAN_MAP, |
|
100 |
AZERBAIJANI_MAP |
|
101 |
]; |
|
102 | ||
103 |
var Downcoder = { |
|
104 |
'Initialize': function() { |
|
105 |
if (Downcoder.map) { // already made |
|
106 |
return; |
|
107 |
} |
|
108 |
Downcoder.map = {}; |
|
109 |
Downcoder.chars = []; |
|
110 |
for (var i=0; i<ALL_DOWNCODE_MAPS.length; i++) { |
|
111 |
var lookup = ALL_DOWNCODE_MAPS[i]; |
|
112 |
for (var c in lookup) { |
|
113 |
if (lookup.hasOwnProperty(c)) { |
|
114 |
Downcoder.map[c] = lookup[c]; |
|
115 |
} |
|
116 |
} |
|
117 |
} |
|
118 |
for (var k in Downcoder.map) { |
|
119 |
if (Downcoder.map.hasOwnProperty(k)) { |
|
120 |
Downcoder.chars.push(k); |
|
121 |
} |
|
122 |
} |
|
123 |
Downcoder.regex = new RegExp(Downcoder.chars.join('|'), 'g'); |
|
124 |
} |
|
125 |
}; |
|
126 | ||
127 |
$.slugify = function(value) { |
|
128 |
Downcoder.Initialize(); |
|
129 |
s = value.replace(Downcoder.regex, function(m) {return Downcoder.map[m]; }); |
|
130 |
s = s.replace("'", ' '); // keep quotes as spaces |
|
131 |
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars |
|
132 |
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces |
|
133 |
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens |
|
134 |
s = s.toLowerCase(); // convert to lowercase |
|
135 |
return s; |
|
136 |
} |
|
137 |
}); |
|
0 |
- |