Skip to content

Commit

Permalink
feat: Add transliteration #145
Browse files Browse the repository at this point in the history
  • Loading branch information
szuperaz committed Dec 1, 2021
1 parent 14e5177 commit 181ff0a
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 9 deletions.
2 changes: 1 addition & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumError": "1.5mb"
},
{
"type": "anyComponentStyle",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Message send can be triggered with the `Enter` key, new line can be added with t

The `AutocompleteTextarea` extends the funcitonalities of the [`Textarea`](./textarea.mdx) component with autocomplete features:

- users can mention other users in a message
- users can mention other users in a message (transliteration is used to support languages with non-Latin characters)

## Basic usage

Expand Down
77 changes: 77 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"@ctrl/ngx-emoji-mart": "^6.0.1",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"@stream-io/transliterate": "^1.5.2",
"angular-mentions": "^1.4.0",
"dayjs": "^1.10.7",
"dotenv": "^10.0.0",
Expand Down
1 change: 1 addition & 0 deletions projects/stream-chat-angular/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"angular-mentions",
"dayjs",
"@ctrl/ngx-emoji-mart",
"@stream-io/transliterate",
"uuidv4",
"pretty-bytes"
]
Expand Down
1 change: 1 addition & 0 deletions projects/stream-chat-angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"angular-mentions": "^1.4.0",
"@ctrl/ngx-emoji-mart": "^6.0.1",
"@stream-io/transliterate": "^1.5.2",
"dayjs": "^1.10.7",
"pretty-bytes": "^5.6.0",
"tslib": "^2.3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ describe('AutocompleteTextareaComponent', () => {
},
],
}).compileComponents();
});

beforeEach(async () => {
fixture = TestBed.createComponent(AutocompleteTextareaComponent);
component = fixture.componentInstance;
nativeElement = fixture.nativeElement as HTMLElement;
Expand Down Expand Up @@ -243,4 +240,77 @@ describe('AutocompleteTextareaComponent', () => {

expect(component.autocompleteConfig.mentions!.length).toBe(1);
});

it('should transliterate - option contains non-Latin characters', fakeAsync(() => {
spyOn(channelServiceMock, 'autocompleteMembers').and.returnValue([
{ user: { id: '12', name: 'Ádám' } },
]);
component.autcompleteSearchTermChanged('Adam');
tick(300);

expect(component.autocompleteConfig.mentions![0].items?.length).toBe(1);
}));

it('should transliterate - search term contains non-Latin characters', fakeAsync(() => {
spyOn(channelServiceMock, 'autocompleteMembers').and.returnValue([
{ user: { id: '12', name: 'Adam' } },
]);
component.autcompleteSearchTermChanged('Ádám');
tick(300);

expect(component.autocompleteConfig.mentions![0].items?.length).toBe(1);
}));

it('should display textarea, and focus it', () => {
const textarea = queryTextarea();

expect(textarea).not.toBeNull();
expect(textarea?.value).toBe('');
expect(textarea?.hasAttribute('autofocus')).toBeTrue();
});

it('should display #value in textarea', () => {
component.value = 'This is my message';
fixture.detectChanges();

expect(queryTextarea()?.value).toBe('This is my message');
});

it('should emit #valueChange if user types in textarea', () => {
const spy = jasmine.createSpy();
component.valueChange.subscribe(spy);
const textarea = queryTextarea();
textarea!.value = 'message';
const event = new InputEvent('input');
textarea?.dispatchEvent(event);
fixture.detectChanges();

expect(spy).toHaveBeenCalledWith('message');
});

it(`shouldn't emit #valueChange if enter is hit`, () => {
const spy = jasmine.createSpy();
component.valueChange.subscribe(spy);
const textarea = queryTextarea();
const message = 'This is my message';
textarea!.value = message;
const event = new KeyboardEvent('keydown', { key: 'Enter' });
spyOn(event, 'preventDefault');
fixture.detectChanges();

expect(spy).not.toHaveBeenCalled();
});

it(`shouldn't emit #send if shift+enter is hit`, () => {
const spy = jasmine.createSpy();
component.send.subscribe(spy);
const textarea = queryTextarea();
textarea!.value = 'This is my message';
textarea?.dispatchEvent(
new KeyboardEvent('keydown', { key: 'Enter', shiftKey: true })
);
fixture.detectChanges();

expect(spy).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ChannelService } from '../../channel.service';
import { TextareaInterface } from '../textarea.interface';
import { ChatClientService } from '../../chat-client.service';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { TransliterationService } from '../../transliteration.service';

@Component({
selector: 'stream-autocomplete-textarea',
Expand Down Expand Up @@ -53,14 +54,18 @@ export class AutocompleteTextareaComponent
triggerChar: this.triggerChar,
dropUp: true,
labelKey: this.labelKey,
mentionFilter: this.filter,
mentionFilter: (
searchString: string,
items: { autocompleteLabel: string }[]
) => this.filter(searchString, items),
mentionSelect: (item, triggerChar) => this.mentioned(item, triggerChar),
};
private searchTerm$ = new BehaviorSubject<string>('');

constructor(
private channelService: ChannelService,
private chatClientService: ChatClientService
private chatClientService: ChatClientService,
private transliterationService: TransliterationService
) {
this.searchTerm$
.pipe(debounceTime(300), distinctUntilChanged())
Expand Down Expand Up @@ -89,9 +94,11 @@ export class AutocompleteTextareaComponent
}
}

filter(searchString: string, items: { autocompleteLabel: string }[]): any[] {
filter(searchString: string, items: { autocompleteLabel: string }[]) {
return items.filter((item) =>
item.autocompleteLabel.toLowerCase().includes(searchString.toLowerCase())
this.transliterate(item.autocompleteLabel.toLowerCase()).includes(
this.transliterate(searchString.toLowerCase())
)
);
}

Expand Down Expand Up @@ -119,6 +126,14 @@ export class AutocompleteTextareaComponent
this.send.next();
}

private transliterate(s: string) {
if (this.transliterationService) {
return this.transliterationService.transliterate(s);
} else {
return s;
}
}

private async updateMentionOptions(searchTerm?: string) {
if (!this.areMentionsEnabled) {
return;
Expand Down
11 changes: 11 additions & 0 deletions projects/stream-chat-angular/src/lib/transliteration.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@angular/core';
import transliterate from '@stream-io/transliterate';

@Injectable({ providedIn: 'root' })
export class TransliterationService {
constructor() {}

transliterate(s: string) {
return transliterate(s);
}
}
1 change: 1 addition & 0 deletions projects/stream-chat-angular/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export * from './lib/is-image-attachment';
export * from './lib/device-width';
export * from './lib/message-preview';
export * from './lib/notification.service';
export * from './lib/transliteration.service';
export * from './lib/stream-chat.module';
export * from './lib/stream-autocomplete-textarea.module';
export * from './lib/stream-textarea.module';
Expand Down

0 comments on commit 181ff0a

Please sign in to comment.