diff --git a/README.md b/README.md index ebdf5e5..6fefed9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![npm](https://img.shields.io/npm/v/ng-chat.svg)](https://www.npmjs.com/package/ng-chat) [![npm downloads](https://img.shields.io/npm/dm/ng-chat.svg)](https://npmjs.org/ng-chat) -[![Build Status](https://travis-ci.org/rpaschoal/ng-chat.svg?branch=master)](https://travis-ci.org/rpaschoal/ng-chat) +[![Build Status](https://travis-ci.org/rpaschoal/ng-chat.svg?branch=development)](https://travis-ci.org/rpaschoal/ng-chat) [![codecov](https://codecov.io/gh/rpaschoal/ng-chat/branch/master/graph/badge.svg)](https://codecov.io/gh/rpaschoal/ng-chat) A simple facebook/linkedin lookalike chat module for Angular applications. @@ -76,6 +76,7 @@ __Additional Settings__ * [pollingInterval]{number}: Configures the long poll interval in milliseconds. Default is 5000. * [historyEnabled]{boolean}: Defines whether the component should call the "getMessageHistory" from the chat-adapter. Default is true. * [emojisEnabled]{boolean}: Enables emoji parsing on the messages. Default is true. +* [linkfyEnabled]{boolean}: Transforms links within the messages to valid HTML links. Default is true. #### Implement your ChatAdapter: diff --git a/demo/aspnetcore_signalr/package.json b/demo/aspnetcore_signalr/package.json index 832145f..242ee5a 100644 --- a/demo/aspnetcore_signalr/package.json +++ b/demo/aspnetcore_signalr/package.json @@ -29,7 +29,7 @@ "bootstrap": "^3.3.7", "core-js": "^2.4.1", "jquery": "3.2.1", - "ng-chat": "1.0.0", + "ng-chat": "1.0.1", "ng2-loading-bar": "0.0.6", "reflect-metadata": "^0.1.10", "rxjs": "5.4.2", diff --git a/demo/offline_bot/package.json b/demo/offline_bot/package.json index 099b267..4e940c5 100644 --- a/demo/offline_bot/package.json +++ b/demo/offline_bot/package.json @@ -24,7 +24,7 @@ "core-js": "^2.4.1", "rxjs": "^5.4.2", "zone.js": "^0.8.14", - "ng-chat": "1.0.0" + "ng-chat": "1.0.1" }, "devDependencies": { "@angular/cli": "1.3.2", diff --git a/src/ng-chat/ng-chat.component.html b/src/ng-chat/ng-chat.component.html index 286cfc5..ba20119 100644 --- a/src/ng-chat/ng-chat.component.html +++ b/src/ng-chat/ng-chat.component.html @@ -45,12 +45,10 @@ - - {{emojisEnabled ? (message.message | emojify) : message.message}} - + - + diff --git a/src/ng-chat/ng-chat.component.ts b/src/ng-chat/ng-chat.component.ts index 17a64f0..887a137 100644 --- a/src/ng-chat/ng-chat.component.ts +++ b/src/ng-chat/ng-chat.component.ts @@ -49,6 +49,9 @@ export class NgChat implements OnInit { @Input() public emojisEnabled: boolean = true; + @Input() + public linkfyEnabled: boolean = true; + public searchInput: string = ""; private users: User[]; diff --git a/src/ng-chat/ng-chat.module.ts b/src/ng-chat/ng-chat.module.ts index e727e80..40574ba 100644 --- a/src/ng-chat/ng-chat.module.ts +++ b/src/ng-chat/ng-chat.module.ts @@ -4,10 +4,11 @@ import { FormsModule } from '@angular/forms'; import { NgChat } from './ng-chat.component'; import { EmojifyPipe } from './pipes/emojify.pipe'; +import { LinkfyPipe } from './pipes/linkfy.pipe'; @NgModule({ imports: [CommonModule, FormsModule], - declarations: [NgChat, EmojifyPipe], + declarations: [NgChat, EmojifyPipe, LinkfyPipe], exports: [NgChat] }) export class NgChatModule { diff --git a/src/ng-chat/pipes/emojify.pipe.ts b/src/ng-chat/pipes/emojify.pipe.ts index f1d0409..9b1105d 100644 --- a/src/ng-chat/pipes/emojify.pipe.ts +++ b/src/ng-chat/pipes/emojify.pipe.ts @@ -23,14 +23,14 @@ let emojiDictionary = [ */ @Pipe({name: 'emojify'}) export class EmojifyPipe implements PipeTransform { - transform(message: string): string { - if (message && message.length > 1) { - emojiDictionary.forEach(emoji => { - emoji.patterns.forEach(pattern => { - message = message.replace(pattern, emoji.unicode); - }) - }); - } + transform(message: string, pipeEnabled: boolean): string { + if (pipeEnabled && message && message.length > 1) { + emojiDictionary.forEach(emoji => { + emoji.patterns.forEach(pattern => { + message = message.replace(pattern, emoji.unicode); + }) + }); + } return message; } diff --git a/src/ng-chat/pipes/linkfy.pipe.ts b/src/ng-chat/pipes/linkfy.pipe.ts new file mode 100644 index 0000000..5fabc06 --- /dev/null +++ b/src/ng-chat/pipes/linkfy.pipe.ts @@ -0,0 +1,33 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +/* + * Transforms text containing URLs or E-mails to valid links/mailtos +*/ +@Pipe({name: 'linkfy'}) +export class LinkfyPipe implements PipeTransform { + transform(message: string, pipeEnabled: boolean): string { + if (pipeEnabled && message && message.length > 1) + { + let replacedText; + let replacePatternProtocol; + let replacePatternWWW; + let replacePatternMailTo; + + // URLs starting with http://, https://, or ftp:// + replacePatternProtocol = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim; + replacedText = message.replace(replacePatternProtocol, '$1'); + + // URLs starting with "www." (ignoring // before it). + replacePatternWWW = /(^|[^\/])(www\.[\S]+(\b|$))/gim; + replacedText = replacedText.replace(replacePatternWWW, '$1$2'); + + // Change email addresses to mailto:: links. + replacePatternMailTo = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim; + replacedText = replacedText.replace(replacePatternMailTo, '$1'); + + return replacedText; + } + else + return message; + } +} diff --git a/src/package.json b/src/package.json index c0567df..cf92f97 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "ng-chat", - "version": "1.0.0", + "version": "1.0.1", "peerDependencies": { "@angular/common": "*", "@angular/core": "*", diff --git a/src/spec/emojify.pipe.spec.ts b/src/spec/emojify.pipe.spec.ts index 33bd9f6..03193d8 100644 --- a/src/spec/emojify.pipe.spec.ts +++ b/src/spec/emojify.pipe.spec.ts @@ -6,27 +6,33 @@ describe('EmojifyPipe', () => { }); it('Must work on empty messages', () => { - let result = this.subject.transform(''); + let result = this.subject.transform('', true); expect(result).toBe(''); }); + it('Must not replace with emoji when piple is disabled', () => { + let result = this.subject.transform(':)', false); + + expect(result).toBe(':)'); + }); + it('Must not replace the message text when no emoji is found', () => { let message = 'Test message'; - let result = this.subject.transform(message); + let result = this.subject.transform(message, true); expect(result).toBe(message); }); it('Must replace message text with emoji unicode 😃', () => { - let result = this.subject.transform(':)'); + let result = this.subject.transform(':)', true); expect(result).toBe('😃'); }); it('Must replace message text with emoji unicode 👍', () => { - let result = this.subject.transform(':+1'); + let result = this.subject.transform(':+1', true); expect(result).toBe('👍'); }); diff --git a/src/spec/linkfy.pipe.spec.ts b/src/spec/linkfy.pipe.spec.ts new file mode 100644 index 0000000..1e517c7 --- /dev/null +++ b/src/spec/linkfy.pipe.spec.ts @@ -0,0 +1,73 @@ +import { LinkfyPipe } from '../ng-chat/pipes/linkfy.pipe'; + +describe('LinkfyPipe', () => { + beforeEach(() => { + this.subject = new LinkfyPipe(); + }); + + it('Must work on empty messages', () => { + let result = this.subject.transform('', true); + + expect(result).toBe(''); + }); + + it('Must not replace with link when piple is disabled', () => { + let result = this.subject.transform('www.github.com/rpaschoal/ng-chat', false); + + expect(result).toBe('www.github.com/rpaschoal/ng-chat'); + }); + + it('Must not replace with HTTP link when piple is disabled', () => { + let result = this.subject.transform('http://github.com/rpaschoal/ng-chat', false); + + expect(result).toBe('http://github.com/rpaschoal/ng-chat'); + }); + + it('Must not replace with HTTPs link when piple is disabled', () => { + let result = this.subject.transform('https://github.com/rpaschoal/ng-chat', false); + + expect(result).toBe('https://github.com/rpaschoal/ng-chat'); + }); + + it('Must not replace with FTP link when piple is disabled', () => { + let result = this.subject.transform('ftp://127.0.0.1', false); + + expect(result).toBe('ftp://127.0.0.1'); + }); + + it('Must not replace e-mail with mailto link when piple is disabled', () => { + let result = this.subject.transform('test@email.com', false); + + expect(result).toBe('test@email.com'); + }); + + it('Must replace www.{0} text with link', () => { + let result = this.subject.transform('www.github.com/rpaschoal/ng-chat', true); + + expect(result).toBe('www.github.com/rpaschoal/ng-chat'); + }); + + it('Must replace http://{0} text with link', () => { + let result = this.subject.transform('http://github.com/rpaschoal/ng-chat', true); + + expect(result).toBe('http://github.com/rpaschoal/ng-chat'); + }); + + it('Must replace https://{0} text with link', () => { + let result = this.subject.transform('https://github.com/rpaschoal/ng-chat', true); + + expect(result).toBe('https://github.com/rpaschoal/ng-chat'); + }); + + it('Must replace ftp://{0} text with link', () => { + let result = this.subject.transform('ftp://127.0.0.1', true); + + expect(result).toBe('ftp://127.0.0.1'); + }); + + it('Must replace e-mail with mailto link', () => { + let result = this.subject.transform('test@email.com', true); + + expect(result).toBe('test@email.com'); + }); +});