diff --git a/.travis.yml b/.travis.yml
index b18be5b..369834e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
+dist: trusty
language: node_js
node_js:
- "10"
-
before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
@@ -10,7 +10,7 @@ before_script:
- npm install
- cd src
- npm link
- - npm install -g angular-cli
+ - npm install -g @angular/cli
- npm install -g karma
- npm install
script:
diff --git a/README.md b/README.md
index 876c945..35f0cbb 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ __Required Settings__
__Additional Settings__
* [title]{string}: The title to be displayed on the friends list. Default is "Friends".
+* [isDisabled]{boolean}: Indicates if ng-chat should be hidden. This stops poll requests to the friends list. Default is false.
* [isCollapsed]{boolean}: If set to true the friends list will be rendered as collapsed by default. Default is false.
* [pollFriendsList]{boolean}: If set to true the module will do a long poll on the "adapter.listFriends" method to keep the friends list updated. Default is false.
* [pollingInterval]{number}: Configures the long poll interval in milliseconds. Default is 5000.
@@ -96,6 +97,7 @@ __Additional Settings__
* [showMessageDate]{boolean}: Shows the date in which a message was sent. Default is true.
* [messageDatePipeFormat]{string}: The format for the pipe that is used when rendering the date in which a message was sent. Default is "short".
* [groupAdapter]{IChatGroupAdapter}: A group adapter implementation to enable group chat.
+* [isViewportOnMobileEnabled]{boolean}: Allow ng-chat to render and be displayed on mobile devices. Default is false.
__Localization__
* [messagePlaceholder]{string}: The placeholder that is displayed in the text input on each chat window. Default is "Type a message".
diff --git a/angular.json b/angular.json
index 25ae5f9..4e5fa81 100644
--- a/angular.json
+++ b/angular.json
@@ -68,7 +68,7 @@
"assets": [
"demo/offline_bot/src/assets"
],
- "tsConfig": "demo/offline_bot/src/../../../tsconfig.json",
+ "tsConfig": "demo/offline_bot/src/../../../tsconfig.json"
}
},
"lint": {
diff --git a/demo/offline_bot/package.json b/demo/offline_bot/package.json
index 183e979..b7c1136 100644
--- a/demo/offline_bot/package.json
+++ b/demo/offline_bot/package.json
@@ -22,11 +22,12 @@
"@angular/platform-browser-dynamic": "^7.0.3",
"@angular/router": "^7.0.3",
"core-js": "^2.5.7",
- "rxjs": "^6.3.3",
- "zone.js": "^0.8.26",
- "ng-chat": "^2.0.4"
+ "ng-chat": "^2.0.5",
+ "rxjs": "^6.5.2",
+ "zone.js": "^0.8.26"
},
"devDependencies": {
+ "@angular-devkit/build-angular": "0.13.4",
"@angular/cli": "^7.0.4",
"@angular/compiler-cli": "^7.0.3",
"@angular/language-service": "^7.0.3",
@@ -45,6 +46,6 @@
"protractor": "~5.4.1",
"ts-node": "~7.0.1",
"tslint": "~5.11.0",
- "typescript": "~3.1.6"
+ "typescript": "~3.2.4"
}
}
diff --git a/package.json b/package.json
index 28d5086..f738224 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
},
"dependencies": {},
"devDependencies": {
- "@angular-devkit/build-angular": "~0.10.0",
+ "@angular-devkit/build-angular": "^0.13.4",
"@angular/cli": "^7.0.5",
"@angular/common": "^7.0.3",
"@angular/compiler": "^7.0.3",
@@ -82,7 +82,7 @@
"tslint": "^5.11.0",
"tslint-config-valorsoft": "^2.2.1",
"typedoc": "^0.13.0",
- "typescript": "~3.1.6",
+ "typescript": "~3.2.4",
"wallaby-webpack": "^3.9.13",
"webdriver-manager": "^12.1.0",
"zone.js": "^0.8.26"
diff --git a/src/ng-chat/assets/ng-chat.component.default.css b/src/ng-chat/assets/ng-chat.component.default.css
index 1de559b..11b8f9b 100644
--- a/src/ng-chat/assets/ng-chat.component.default.css
+++ b/src/ng-chat/assets/ng-chat.component.default.css
@@ -25,7 +25,7 @@
height:360px;
border-width: 1px;
border-style: solid;
- margin-right:20px;
+ margin-right: 20px;
box-shadow: 0 4px 8px rgba(0,0,0,.25);
border-bottom:0;
}
@@ -212,15 +212,15 @@
}
.ng-chat-window
{
- right:260px;
- height:360px;
- z-index:999;
- bottom:0;
+ right: 260px;
+ height: 360px;
+ z-index: 999;
+ bottom: 0;
+ width: 300px;
position: fixed;
- width:300px;
border-width: 1px;
border-style: solid;
- border-bottom:0;
+ border-bottom: 0;
box-shadow: 0 4px 8px rgba(0,0,0,.25);
}
.ng-chat-window-collapsed
@@ -417,3 +417,18 @@
float: right;
margin-right: 5px;
}
+
+/* Mobile viewport only */
+@media only screen and (max-width: 581px) {
+ #ng-chat-people
+ {
+ width: 300px;
+ height: 360px;
+ margin-right: 0;
+ }
+
+ .ng-chat-window
+ {
+ position: initial;
+ }
+}
diff --git a/src/ng-chat/components/ng-chat-options/ng-chat-options.component.css b/src/ng-chat/components/ng-chat-options/ng-chat-options.component.css
index 6a015e9..f2e574b 100644
--- a/src/ng-chat/components/ng-chat-options/ng-chat-options.component.css
+++ b/src/ng-chat/components/ng-chat-options/ng-chat-options.component.css
@@ -38,3 +38,9 @@
display: block;
}
+/* Mobile viewport only */
+@media only screen and (max-width: 581px) {
+ .ng-chat-options-content {
+ right: 0;
+ }
+}
diff --git a/src/ng-chat/ng-chat.component.html b/src/ng-chat/ng-chat.component.html
index ddfbef7..696b1e8 100644
--- a/src/ng-chat/ng-chat.component.html
+++ b/src/ng-chat/ng-chat.component.html
@@ -1,6 +1,6 @@
-
+
-
+
@@ -28,7 +28,7 @@
-
+
{{user.displayName}}
0" class="ng-chat-unread-messages-count unread-messages-counter-container primary-text">{{unreadMessagesTotalByParticipant(user)}}
@@ -74,7 +74,7 @@
-
+
{{window.participant | groupMessageDisplayName:message}}
diff --git a/src/ng-chat/ng-chat.component.ts b/src/ng-chat/ng-chat.component.ts
index b47e913..28724a0 100644
--- a/src/ng-chat/ng-chat.component.ts
+++ b/src/ng-chat/ng-chat.component.ts
@@ -1,6 +1,5 @@
import { Component, Input, OnInit, ViewChildren, ViewChild, HostListener, Output, EventEmitter, ElementRef, ViewEncapsulation } from '@angular/core';
import { HttpClient } from '@angular/common/http';
-import { DomSanitizer } from '@angular/platform-browser';
import { ChatAdapter } from './core/chat-adapter';
import { IChatGroupAdapter } from './core/chat-group-adapter';
@@ -40,13 +39,34 @@ import { Observable } from 'rxjs';
})
export class NgChat implements OnInit, IChatController {
- constructor(public sanitizer: DomSanitizer, private _httpClient: HttpClient) { }
+ constructor(private _httpClient: HttpClient) { }
// Exposes enums for the ng-template
public ChatParticipantType = ChatParticipantType;
public ChatParticipantStatus = ChatParticipantStatus;
public MessageType = MessageType;
+ private _isDisabled: boolean = false;
+
+ get isDisabled(): boolean {
+ return this._isDisabled;
+ }
+
+ @Input()
+ set isDisabled(value: boolean) {
+ this._isDisabled = value;
+
+ if (value)
+ {
+ // To address issue https://github.com/rpaschoal/ng-chat/issues/120
+ window.clearInterval(this.pollingIntervalWindowInstance)
+ }
+ else
+ {
+ this.activateFriendListFetch();
+ }
+ }
+
@Input()
public adapter: ChatAdapter;
@@ -133,7 +153,10 @@ export class NgChat implements OnInit, IChatController {
@Input()
public showMessageDate: boolean = true;
-
+
+ @Input()
+ public isViewportOnMobileEnabled: boolean = false;
+
@Output()
public onParticipantClicked: EventEmitter = new EventEmitter();
@@ -172,6 +195,8 @@ export class NgChat implements OnInit, IChatController {
protected selectedUsersFromFriendsList: User[] = [];
+ private pollingIntervalWindowInstance: number;
+
public defaultWindowOptions(currentWindow: Window): IChatOption[]
{
if (this.groupAdapter && currentWindow.participant.participantType == ChatParticipantType.User)
@@ -256,8 +281,8 @@ export class NgChat implements OnInit, IChatController {
this.updateWindowsState(this.windows);
- // Viewport should have space for at least one chat window.
- this.unsupportedViewport = this.hideFriendsListOnUnsupportedViewport && maxSupportedOpenedWindows < 1;
+ // Viewport should have space for at least one chat window but should show in mobile if option is enabled.
+ this.unsupportedViewport = this.isViewportOnMobileEnabled? false : this.hideFriendsListOnUnsupportedViewport && maxSupportedOpenedWindows < 1;
}
// Initializes the chat plugin and the messaging adapter
@@ -279,17 +304,7 @@ export class NgChat implements OnInit, IChatController {
this.adapter.messageReceivedHandler = (participant, msg) => this.onMessageReceived(participant, msg);
this.adapter.friendsListChangedHandler = (participantsResponse) => this.onFriendsListChanged(participantsResponse);
- // Loading current users list
- if (this.pollFriendsList){
- // Setting a long poll interval to update the friends list
- this.fetchFriendsList(true);
- setInterval(() => this.fetchFriendsList(false), this.pollingInterval);
- }
- else
- {
- // Since polling was disabled, a friends list update mechanism will have to be implemented in the ChatAdapter.
- this.fetchFriendsList(true);
- }
+ this.activateFriendListFetch();
this.bufferAudioFile();
@@ -300,6 +315,8 @@ export class NgChat implements OnInit, IChatController {
this.fileUploadAdapter = new DefaultFileUploadAdapter(this.fileUploadUrl, this._httpClient);
}
+ this.NormalizeWindows();
+
this.isBootstrapped = true;
}
catch(ex)
@@ -325,6 +342,23 @@ export class NgChat implements OnInit, IChatController {
}
}
+ private activateFriendListFetch(): void {
+ if (this.adapter)
+ {
+ // Loading current users list
+ if (this.pollFriendsList){
+ // Setting a long poll interval to update the friends list
+ this.fetchFriendsList(true);
+ this.pollingIntervalWindowInstance = window.setInterval(() => this.fetchFriendsList(false), this.pollingInterval);
+ }
+ else
+ {
+ // Since polling was disabled, a friends list update mechanism will have to be implemented in the ChatAdapter.
+ this.fetchFriendsList(true);
+ }
+ }
+ }
+
// Initializes browser notifications
private async initializeBrowserNotifications()
{
@@ -512,10 +546,11 @@ export class NgChat implements OnInit, IChatController {
this.windows.unshift(newChatWindow);
- // Is there enough space left in the view port ?
- if (this.windows.length * this.windowSizeFactor >= this.viewPortTotalArea - (!this.hideFriendsList ? this.friendsListWidth : 0))
- {
- this.windows.pop();
+ // Is there enough space left in the view port ? but should be displayed in mobile if option is enabled
+ if (!this.isViewportOnMobileEnabled) {
+ if (this.windows.length * this.windowSizeFactor >= this.viewPortTotalArea - (!this.hideFriendsList ? this.friendsListWidth : 0)) {
+ this.windows.pop();
+ }
}
this.updateWindowsState(this.windows);
diff --git a/src/ng-chat/ng-chat.module.ts b/src/ng-chat/ng-chat.module.ts
index 5c0da57..a3a422d 100644
--- a/src/ng-chat/ng-chat.module.ts
+++ b/src/ng-chat/ng-chat.module.ts
@@ -6,12 +6,13 @@ import { HttpClientModule } from '@angular/common/http';
import { NgChat } from './ng-chat.component';
import { EmojifyPipe } from './pipes/emojify.pipe';
import { LinkfyPipe } from './pipes/linkfy.pipe';
+import { SanitizePipe } from './pipes/sanitize.pipe';
import { GroupMessageDisplayNamePipe } from './pipes/group-message-display-name.pipe';
import { NgChatOptionsComponent } from './components/ng-chat-options/ng-chat-options.component';
@NgModule({
imports: [CommonModule, FormsModule, HttpClientModule],
- declarations: [NgChat, EmojifyPipe, LinkfyPipe, GroupMessageDisplayNamePipe, NgChatOptionsComponent],
+ declarations: [NgChat, EmojifyPipe, LinkfyPipe, SanitizePipe, GroupMessageDisplayNamePipe, NgChatOptionsComponent],
exports: [NgChat]
})
export class NgChatModule {
diff --git a/src/ng-chat/pipes/sanitize.pipe.ts b/src/ng-chat/pipes/sanitize.pipe.ts
new file mode 100644
index 0000000..1187193
--- /dev/null
+++ b/src/ng-chat/pipes/sanitize.pipe.ts
@@ -0,0 +1,14 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
+
+/*
+ * Sanitizes an URL resource
+*/
+@Pipe({name: 'sanitize'})
+export class SanitizePipe implements PipeTransform {
+ constructor(protected sanitizer: DomSanitizer) {}
+
+ transform(url: string): SafeResourceUrl {
+ return this.sanitizer.bypassSecurityTrustResourceUrl(url);
+ }
+}
diff --git a/src/package.json b/src/package.json
index 0a196b4..e455b11 100644
--- a/src/package.json
+++ b/src/package.json
@@ -1,6 +1,6 @@
{
"name": "ng-chat",
- "version": "2.0.4",
+ "version": "2.0.5",
"peerDependencies": {
"@angular/common": "*",
"@angular/core": "*",
@@ -13,13 +13,13 @@
"@angular/forms": "^7.0.3",
"@angular/platform-browser": "^7.0.3",
"zone.js": "^0.8.26",
- "rxjs": "^6.3.3",
+ "rxjs": "^6.5.2",
"@angular/compiler": "^7.0.3",
"@angular/compiler-cli": "^7.0.3",
"gulp": "~4.0.0",
"gulp-inline-ng2-template": "^5.0.1",
"rollup": "^0.67.0",
- "typescript": "~3.1.6",
+ "typescript": "~3.2.4",
"uglify-js": "^3.4.9",
"ng-packagr": "^4.4.0",
"tsickle": "^0.33.1"
diff --git a/src/spec/ng-chat.component.spec.ts b/src/spec/ng-chat.component.spec.ts
index d498422..d3c5bc4 100644
--- a/src/spec/ng-chat.component.spec.ts
+++ b/src/spec/ng-chat.component.spec.ts
@@ -51,7 +51,7 @@ let subject: any = null;
describe('NgChat', () => {
beforeEach(() => {
- subject = new NgChat(null, null); // HttpClient related methods are tested elsewhere
+ subject = new NgChat(null); // HttpClient related methods are tested elsewhere
subject.userId = 123;
subject.adapter = new MockableAdapter();
subject.groupAdapter = new MockableGroupAdapter();
@@ -97,7 +97,11 @@ describe('NgChat', () => {
it('Persistent windows state must be enabled by default', () => {
expect(subject.persistWindowsState).toBeTruthy();
});
-
+
+ it('Is viewport mobile case state must be disabled by default', () => {
+ expect(subject.isViewportOnMobileEnabled).toBeFalsy();
+ });
+
it('isCollapsed must be disabled by default', () => {
expect(subject.isCollapsed).toBeFalsy();
});