Merge pull request #850 from sharetribe/fix-slug-generation

Fix / improve slug generation
This commit is contained in:
Vesa Luusua 2018-06-21 14:40:52 +03:00 committed by GitHub
commit 2d9eacfc7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 7 deletions

View file

@ -12,6 +12,10 @@ way to update this template, but currently, we follow a pattern:
---
## Upcoming version
* [fix] Improve slug creation (slashes were breaking rendering in some environments)
[#850](https://github.com/sharetribe/flex-template-web/pull/850)
## v1.0.0
* [change] Migrate remaining Redux Forms to Final Form. Also now all the form components can be

View file

@ -1,6 +1,6 @@
{
"name": "app",
"version": "0.3.1",
"version": "1.0.0",
"private": true,
"license": "Apache-2.0",
"dependencies": {

View file

@ -5,13 +5,55 @@ const { LatLng, LatLngBounds } = sdkTypes;
export const LISTING_PAGE_PENDING_APPROVAL_VARIANT = 'pending-approval';
export const createSlug = str =>
encodeURIComponent(
str
.toLowerCase()
.split(' ')
.join('-')
// Create slug from random texts
// From Gist thread: https://gist.github.com/mathewbyrne/1280286
export const createSlug = str => {
let text = str
.toString()
.toLowerCase()
.trim();
const sets = [
{ to: 'a', from: 'ÀÁÂÃÄÅÆĀĂĄẠẢẤẦẨẪẬẮẰẲẴẶ' },
{ to: 'c', from: 'ÇĆĈČ' },
{ to: 'd', from: 'ÐĎĐÞ' },
{ to: 'e', from: 'ÈÉÊËĒĔĖĘĚẸẺẼẾỀỂỄỆ' },
{ to: 'g', from: 'ĜĞĢǴ' },
{ to: 'h', from: 'ĤḦ' },
{ to: 'i', from: 'ÌÍÎÏĨĪĮİỈỊ' },
{ to: 'j', from: 'Ĵ' },
{ to: 'ij', from: 'IJ' },
{ to: 'k', from: 'Ķ' },
{ to: 'l', from: 'ĹĻĽŁ' },
{ to: 'm', from: 'Ḿ' },
{ to: 'n', from: 'ÑŃŅŇ' },
{ to: 'o', from: 'ÒÓÔÕÖØŌŎŐỌỎỐỒỔỖỘỚỜỞỠỢǪǬƠ' },
{ to: 'oe', from: 'Œ' },
{ to: 'p', from: 'ṕ' },
{ to: 'r', from: 'ŔŖŘ' },
{ to: 's', from: 'ߌŜŞŠ' },
{ to: 't', from: 'ŢŤ' },
{ to: 'u', from: 'ÙÚÛÜŨŪŬŮŰŲỤỦỨỪỬỮỰƯ' },
{ to: 'w', from: 'ẂŴẀẄ' },
{ to: 'x', from: 'ẍ' },
{ to: 'y', from: 'ÝŶŸỲỴỶỸ' },
{ to: 'z', from: 'ŹŻŽ' },
{ to: '-', from: "·/_,:;'" },
];
sets.forEach(set => {
text = text.replace(new RegExp(`[${set.from}]`, 'gi'), set.to);
});
return encodeURIComponent(
text
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/[^\w-]+/g, '') // Remove all non-word chars
.replace(/--+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, '') // Trim - from end of text
);
};
/**
* Parse float from a string

View file

@ -1,5 +1,6 @@
import { types as sdkTypes } from './sdkLoader';
import {
createSlug,
parseFloatNum,
encodeLatLng,
decodeLatLng,
@ -15,6 +16,32 @@ const SPACE = encodeURIComponent(' ');
const COMMA = encodeURIComponent(',');
describe('urlHelpers', () => {
describe('parseFloatNum()', () => {
it('handles empty string (returns "")', () => {
expect(createSlug('')).toEqual('');
});
it('handles space characters', () => {
expect(createSlug('ice hockey tournament')).toEqual('ice-hockey-tournament');
});
it('handles special characters', () => {
expect(createSlug('ice hockey!%/@$€ for the win')).toEqual('ice-hockey-for-the-win');
});
it('handles multiple "-"', () => {
expect(createSlug('testing ---- dashes')).toEqual('testing-dashes');
});
it('handles umlauts', () => {
expect(createSlug('jääkiekko / pesäpallo')).toEqual('jaakiekko-pesapallo');
});
it('handles Emojis', () => {
expect(createSlug('smiling 💩 emoji')).toEqual('smiling-emoji');
});
});
describe('parseFloatNum()', () => {
it('handles empty value', () => {
expect(parseFloatNum('')).toBeNull();