admin: make form slugs editable by the admin (#15663)
This commit is contained in:
parent
c3be61b8d1
commit
78db869ae2
|
@ -344,17 +344,57 @@ def test_forms_edit(pub):
|
|||
assert_option_display(resp, 'Geolocation', 'Disabled')
|
||||
assert FormDef.get(formdef.id).geolocations is None
|
||||
|
||||
# try changing title
|
||||
def test_form_title_change(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.fields = []
|
||||
formdef.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/forms/1/')
|
||||
resp = resp.click('change title')
|
||||
assert resp.forms[0]['name'].value == 'form title'
|
||||
resp.forms[0]['name'] = 'new title'
|
||||
resp = resp.forms[0].submit()
|
||||
assert resp.form['name'].value == 'form title'
|
||||
assert 'data-slug-sync' in resp.body
|
||||
assert not 'change-nevertheless' in resp.body
|
||||
resp.form['name'] = 'new title'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location == 'http://example.net/backoffice/forms/1/'
|
||||
resp = resp.follow()
|
||||
assert FormDef.get(1).name == 'new title'
|
||||
assert FormDef.get(1).url_name == 'form-title'
|
||||
assert FormDef.get(1).internal_identifier == 'new-title'
|
||||
formdef = FormDef.get(formdef.id)
|
||||
assert formdef.name == 'new title'
|
||||
assert formdef.url_name == 'form-title'
|
||||
assert formdef.internal_identifier == 'new-title'
|
||||
|
||||
resp = app.get('/backoffice/forms/1/')
|
||||
resp = resp.click('change title')
|
||||
assert not 'data-slug-sync' in resp.body
|
||||
assert not 'change-nevertheless' in resp.body
|
||||
|
||||
formdef.data_class()().store()
|
||||
resp = app.get('/backoffice/forms/1/')
|
||||
resp = resp.click('change title')
|
||||
assert 'change-nevertheless' in resp.body
|
||||
|
||||
formdef2 = FormDef()
|
||||
formdef2.name = 'other title'
|
||||
formdef2.fields = []
|
||||
formdef2.store()
|
||||
|
||||
resp = app.get('/backoffice/forms/%s/' % formdef2.id)
|
||||
resp = resp.click('change title')
|
||||
assert resp.form['name'].value == 'other title'
|
||||
resp.form['url_name'] = formdef.url_name
|
||||
resp = resp.form.submit()
|
||||
assert 'This identifier is already used.' in resp.body
|
||||
|
||||
resp.form['url_name'] = 'foobar'
|
||||
resp = resp.form.submit().follow()
|
||||
assert FormDef.get(formdef2.id).url_name == 'foobar'
|
||||
|
||||
def test_form_category(pub):
|
||||
create_superuser(pub)
|
||||
|
|
|
@ -670,8 +670,20 @@ class FormDefPage(Directory):
|
|||
|
||||
def title(self):
|
||||
form = Form(enctype='multipart/form-data')
|
||||
kwargs = {}
|
||||
if self.formdef.url_name == misc.simplify(self.formdef.name):
|
||||
# if name and url name are in sync, keep them that way
|
||||
kwargs['data-slug-sync'] = 'url_name'
|
||||
form.add(StringWidget, 'name', title=_('Form Title'), required=True,
|
||||
size=40, value=self.formdef.name)
|
||||
size=40, value=self.formdef.name, **kwargs)
|
||||
|
||||
disabled_url_name = bool(self.formdef.data_class().count())
|
||||
kwargs = {}
|
||||
if disabled_url_name:
|
||||
kwargs['readonly'] = 'readonly'
|
||||
form.add(ValidatedStringWidget, 'url_name', title=_('Identifier in URLs'),
|
||||
size=40, required=True, value=self.formdef.url_name,
|
||||
regex=r'^[a-zA-Z0-9_-]+', **kwargs)
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
if form.get_widget('cancel').parse():
|
||||
|
@ -679,20 +691,28 @@ class FormDefPage(Directory):
|
|||
|
||||
if form.is_submitted() and not form.has_errors():
|
||||
new_name = form.get_widget('name').parse()
|
||||
formdefs_name = [x.name for x in FormDef.select(ignore_errors=True)
|
||||
if x.id != self.formdef.id]
|
||||
if new_name in formdefs_name:
|
||||
form.get_widget('name').set_error(_('This name is already used'))
|
||||
else:
|
||||
new_url_name = form.get_widget('url_name').parse()
|
||||
formdefs = [x for x in FormDef.select(ignore_errors=True) if x.id != self.formdef.id]
|
||||
if new_name in [x.name for x in formdefs]:
|
||||
form.get_widget('name').set_error(_('This name is already used.'))
|
||||
if new_url_name in [x.url_name for x in formdefs]:
|
||||
form.get_widget('url_name').set_error(_('This identifier is already used.'))
|
||||
if not form.has_errors():
|
||||
self.formdef.name = new_name
|
||||
self.formdef.url_name = new_url_name
|
||||
self.formdef.store()
|
||||
return redirect('.')
|
||||
|
||||
if disabled_url_name:
|
||||
form.widgets.append(HtmlWidget('<p>%s<br>' % _(
|
||||
'The form identifier should not be modified as there is already some data.')))
|
||||
form.widgets.append(HtmlWidget('<a href="" class="change-nevertheless">%s</a></p>' % _(
|
||||
'I understand the danger, make it editable nevertheless.')))
|
||||
|
||||
get_response().breadcrumb.append( ('title', _('Title')) )
|
||||
self.html_top(title=self.formdef.name)
|
||||
r = TemplateIO(html=True)
|
||||
r += htmltext('<h2>%s</h2>') % _('Title')
|
||||
r += htmltext('<p>%s</p>') % _('Choose a title for this form')
|
||||
r += form.render()
|
||||
return r.getvalue()
|
||||
|
||||
|
|
|
@ -84,11 +84,13 @@ class HTTPResponse(quixote.http_response.HTTPResponse):
|
|||
self.add_javascript_code('var QOMMON_ROOT_URL = "%s";\n' % \
|
||||
get_publisher().get_application_static_files_root_url())
|
||||
if script_name == 'qommon.geolocation.js':
|
||||
self.add_javascript(['jquery.js'])
|
||||
self.add_javascript(['jquery.js', 'qommon.slugify.js'])
|
||||
self.add_javascript_code('var WCS_ROOT_URL = "%s";\n' % \
|
||||
get_publisher().get_frontoffice_url())
|
||||
if script_name == 'wcs.listing.js':
|
||||
self.add_javascript(['jquery.js'])
|
||||
if script_name == 'qommon.admin.js':
|
||||
self.add_javascript(['jquery.js', 'qommon.slugify.js'])
|
||||
|
||||
def add_javascript_code(self, code):
|
||||
if not self.javascript_code_parts:
|
||||
|
|
|
@ -610,6 +610,7 @@ div.widget input[type="text"] {
|
|||
padding: 5px 8px;
|
||||
background: white;
|
||||
color: black;
|
||||
transition: background ease-out 0.3s;
|
||||
}
|
||||
|
||||
div.TextWidget textarea:focus,
|
||||
|
@ -1611,3 +1612,7 @@ div.leaflet-popup-content p.view-link {
|
|||
a.leaflet-popup-close-button {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.widget input[type=text][readonly] {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,27 @@ $(function() {
|
|||
return false;
|
||||
});
|
||||
|
||||
/* keep title/slug in sync */
|
||||
$('body').delegate('input[data-slug-sync]', 'keyup change paste',
|
||||
function() {
|
||||
var $slug_field = $(this).parents('form').find('[name=' + $(this).data('slug-sync') + ']');
|
||||
if ($slug_field.prop('readonly')) return;
|
||||
$slug_field.val($.slugify($(this).val()));
|
||||
});
|
||||
|
||||
/* remove readonly attribute from fields */
|
||||
$('body').delegate('a.change-nevertheless', 'click', function(e) {
|
||||
var readonly_fields = $(this).parents('form').find('input[readonly]');
|
||||
console.log(readonly_fields);
|
||||
if (readonly_fields.length) {
|
||||
console.log('a');
|
||||
readonly_fields.prop('readonly', false);
|
||||
readonly_fields[0].focus();
|
||||
}
|
||||
$(this).parent().hide();
|
||||
return false;
|
||||
});
|
||||
|
||||
/* submission channel */
|
||||
$('div.submit-channel-selection').show().find('select').on('change', function() {
|
||||
$('input[type=hidden][name=submission_channel]').val($(this).val());
|
||||
|
|
|
@ -1,140 +1,4 @@
|
|||
$(function() {
|
||||
/* the slugify code is adapted from the urlify code of django,
|
||||
* django/contrib/admin/static/admin/js/urlify.js.
|
||||
*/
|
||||
|
||||
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 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 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 ALL_DOWNCODE_MAPS = [
|
||||
LATIN_MAP,
|
||||
LATIN_SYMBOLS_MAP,
|
||||
GREEK_MAP,
|
||||
TURKISH_MAP,
|
||||
RUSSIAN_MAP,
|
||||
UKRAINIAN_MAP,
|
||||
CZECH_MAP,
|
||||
POLISH_MAP,
|
||||
LATVIAN_MAP,
|
||||
ARABIC_MAP,
|
||||
LITHUANIAN_MAP,
|
||||
SERBIAN_MAP,
|
||||
AZERBAIJANI_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 slugify(value) {
|
||||
Downcoder.Initialize();
|
||||
s = value.replace(Downcoder.regex, function(m) {return Downcoder.map[m]; });
|
||||
s = s.replace("'", ' '); // keep quotes as spaces
|
||||
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.toLowerCase(); // convert to lowercase
|
||||
return s;
|
||||
}
|
||||
|
||||
function geoloc_prefill(element_type, element_value)
|
||||
{
|
||||
$('div[data-geolocation="' + element_type +'"] input').val(element_value);
|
||||
|
@ -142,7 +6,7 @@ function geoloc_prefill(element_type, element_value)
|
|||
var $options = $('div[data-geolocation="' + element_type +'"] option');
|
||||
if ($options.length == 0) return;
|
||||
|
||||
var slugified_value = slugify(element_value);
|
||||
var slugified_value = $.slugify(element_value);
|
||||
for (var i=0; i<$options.length; i++) {
|
||||
var $option = $($options[i]);
|
||||
if (slugify($option.val()) == slugified_value ||
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
$(function() {
|
||||
/* the slugify code is adapted from the urlify code of django,
|
||||
* django/contrib/admin/static/admin/js/urlify.js.
|
||||
*/
|
||||
|
||||
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 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 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 ALL_DOWNCODE_MAPS = [
|
||||
LATIN_MAP,
|
||||
LATIN_SYMBOLS_MAP,
|
||||
GREEK_MAP,
|
||||
TURKISH_MAP,
|
||||
RUSSIAN_MAP,
|
||||
UKRAINIAN_MAP,
|
||||
CZECH_MAP,
|
||||
POLISH_MAP,
|
||||
LATVIAN_MAP,
|
||||
ARABIC_MAP,
|
||||
LITHUANIAN_MAP,
|
||||
SERBIAN_MAP,
|
||||
AZERBAIJANI_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');
|
||||
}
|
||||
};
|
||||
|
||||
$.slugify = function(value) {
|
||||
Downcoder.Initialize();
|
||||
s = value.replace(Downcoder.regex, function(m) {return Downcoder.map[m]; });
|
||||
s = s.replace("'", ' '); // keep quotes as spaces
|
||||
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.toLowerCase(); // convert to lowercase
|
||||
return s;
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue