├── plugin
├── .npmignore
├── references.d.ts
├── tsconfig.json
├── package.json
├── index.css
├── index.d.ts
├── README.md
├── index.ts
└── index.js
├── demo.gif
├── demo
├── app
│ ├── img
│ │ ├── alert.jpg
│ │ └── marcel.jpg
│ ├── app.ts
│ ├── App_Resources
│ │ ├── iOS
│ │ │ ├── icon.png
│ │ │ ├── Default.png
│ │ │ ├── icon-40.png
│ │ │ ├── icon-60.png
│ │ │ ├── icon-72.png
│ │ │ ├── icon-76.png
│ │ │ ├── icon@2x.png
│ │ │ ├── Default@2x.png
│ │ │ ├── Icon-Small.png
│ │ │ ├── icon-40@2x.png
│ │ │ ├── icon-60@2x.png
│ │ │ ├── icon-72@2x.png
│ │ │ ├── icon-76@2x.png
│ │ │ ├── Icon-Small-50.png
│ │ │ ├── Icon-Small@2x.png
│ │ │ ├── Default-568h@2x.png
│ │ │ ├── Default-667h@2x.png
│ │ │ ├── Default-736h@3x.png
│ │ │ ├── Default-Landscape.png
│ │ │ ├── Default-Portrait.png
│ │ │ ├── Icon-Small-50@2x.png
│ │ │ ├── Default-Portrait@2x.png
│ │ │ ├── Default-Landscape@2x.png
│ │ │ ├── Default-Landscape@3x.png
│ │ │ ├── Default-Landscape-568h@2x.png
│ │ │ ├── Default-Landscape-667h@2x.png
│ │ │ ├── build.xcconfig
│ │ │ └── Info.plist
│ │ └── Android
│ │ │ ├── drawable-hdpi
│ │ │ └── icon.png
│ │ │ ├── drawable-ldpi
│ │ │ └── icon.png
│ │ │ ├── drawable-mdpi
│ │ │ └── icon.png
│ │ │ ├── drawable-nodpi
│ │ │ └── splashscreen.9.png
│ │ │ ├── app.gradle
│ │ │ └── AndroidManifest.xml
│ ├── app.js
│ ├── references.d.ts
│ ├── main-view-model.ts
│ ├── main-page.xml
│ ├── main-view-model.js
│ ├── package.json
│ ├── app.css
│ ├── main-page.js
│ └── main-page.ts
├── hooks
│ ├── before-watch
│ │ └── nativescript-dev-typescript.js
│ └── before-prepare
│ │ └── nativescript-dev-typescript.js
├── references.d.ts
├── livesync.cmd
├── tsconfig.json
└── package.json
├── .gitignore
├── LICENSE
└── README.md
/plugin/.npmignore:
--------------------------------------------------------------------------------
1 | *.map
2 | index.ts
3 | tsconfig.json
4 | references.d.ts
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo.gif
--------------------------------------------------------------------------------
/demo/app/img/alert.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/img/alert.jpg
--------------------------------------------------------------------------------
/demo/app/img/marcel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/img/marcel.jpg
--------------------------------------------------------------------------------
/demo/app/app.ts:
--------------------------------------------------------------------------------
1 | import Application = require("application");
2 |
3 | Application.start({ moduleName: "main-page" });
4 |
--------------------------------------------------------------------------------
/demo/hooks/before-watch/nativescript-dev-typescript.js:
--------------------------------------------------------------------------------
1 | module.exports = require("nativescript-dev-typescript/lib/watch.js");
2 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /pushall.sh
2 | /demo/node_modules
3 | /demo/platforms
4 | /plugin/chat-view-common.js.map
5 | /demo/app/*.map
6 | /plugin/*.map
7 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-40.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-60.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-72.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-76.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon@2x.png
--------------------------------------------------------------------------------
/demo/hooks/before-prepare/nativescript-dev-typescript.js:
--------------------------------------------------------------------------------
1 | module.exports = require("nativescript-dev-typescript/lib/before-prepare.js");
2 |
--------------------------------------------------------------------------------
/demo/references.d.ts:
--------------------------------------------------------------------------------
1 | /// Needed for autocompletion and compilation.
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Icon-Small.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-40@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-60@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-72@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/icon-76@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Icon-Small-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Icon-Small-50.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Icon-Small@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-568h@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-667h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-667h@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-736h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-736h@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Landscape.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Portrait.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Icon-Small-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Icon-Small-50@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Portrait@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Portrait@2x.png
--------------------------------------------------------------------------------
/demo/app/app.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var Application = require("application");
3 | Application.start({ moduleName: "main-page" });
4 | //# sourceMappingURL=app.js.map
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/Android/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/Android/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/Android/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Landscape@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Landscape@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Landscape@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Landscape@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Landscape-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Landscape-568h@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Default-Landscape-667h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/iOS/Default-Landscape-667h@2x.png
--------------------------------------------------------------------------------
/demo/app/references.d.ts:
--------------------------------------------------------------------------------
1 | /// Enable smart suggestions and completions in Visual Studio Code JavaScript projects.
2 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-nodpi/splashscreen.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkloubert/nativescript-chatview/HEAD/demo/app/App_Resources/Android/drawable-nodpi/splashscreen.9.png
--------------------------------------------------------------------------------
/plugin/references.d.ts:
--------------------------------------------------------------------------------
1 | /// Enable smart suggestions and completions in Visual Studio Code JavaScript projects.
2 |
--------------------------------------------------------------------------------
/demo/app/main-view-model.ts:
--------------------------------------------------------------------------------
1 | import {Observable} from "data/observable";
2 |
3 | export function createViewModel() {
4 | var viewModel = new Observable();
5 |
6 | return viewModel;
7 | }
8 |
--------------------------------------------------------------------------------
/demo/app/main-page.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/app/main-view-model.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var observable_1 = require("data/observable");
3 | function createViewModel() {
4 | var viewModel = new observable_1.Observable();
5 | return viewModel;
6 | }
7 | exports.createViewModel = createViewModel;
8 | //# sourceMappingURL=main-view-model.js.map
--------------------------------------------------------------------------------
/demo/livesync.cmd:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | CLS
3 |
4 | CALL tns plugin remove nativescript-chatview
5 |
6 | CD ..
7 | CD plugin
8 | ECHO Rebuild plugin...
9 | CALL tsc
10 | ECHO Done
11 |
12 | CD ..
13 | CD demo
14 |
15 | CALL tns plugin add ..\plugin
16 |
17 | CALL tns livesync --watch
18 |
--------------------------------------------------------------------------------
/plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "sourceMap": true,
6 | "experimentalDecorators": true,
7 | "emitDecoratorMetadata": true,
8 | "noEmitHelpers": true,
9 | "noEmitOnError": true
10 | }
11 | }
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/build.xcconfig:
--------------------------------------------------------------------------------
1 | // You can add custom settings here
2 | // for example you can uncomment the following line to force distribution code signing
3 | // CODE_SIGN_IDENTITY = iPhone Distribution
4 | // ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
5 | // ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = Brand Assets;
6 |
--------------------------------------------------------------------------------
/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "sourceMap": true,
6 | "experimentalDecorators": true,
7 | "emitDecoratorMetadata": true,
8 | "noEmitHelpers": true,
9 | "noEmitOnError": true
10 | },
11 | "exclude": [
12 | "node_modules",
13 | "platforms"
14 | ]
15 | }
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/app.gradle:
--------------------------------------------------------------------------------
1 | // Add your native dependencies here:
2 |
3 | // Uncomment to add recyclerview-v7 dependency
4 | //dependencies {
5 | // compile 'com.android.support:recyclerview-v7:+'
6 | //}
7 |
8 | android {
9 | defaultConfig {
10 | generatedDensities = []
11 | }
12 | aaptOptions {
13 | additionalParameters "--no-version-vectors"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo/app/package.json:
--------------------------------------------------------------------------------
1 | {"name":"tns-template-hello-world","main":"app.js","version":"2.0.0","author":{"name":"Telerik","email":"support@telerik.com"},"description":"Nativescript hello-world project template","license":"Apache-2.0","keywords":["telerik","mobile","nativescript","{N}","tns","appbuilder","template"],"repository":{"type":"git","url":"git://github.com/NativeScript/template-hello-world.git"},"bugs":{"url":"https://github.com/NativeScript/template-hello-world/issues"},"homepage":"https://github.com/NativeScript/template-hello-world","android":{"v8Flags":"--expose_gc"},"readme":"ERROR: No README data found!","_id":"tns-template-hello-world@2.0.0","_from":"tns-template-hello-world@2.0.0"}
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "NativeScript Application",
3 | "license": "SEE LICENSE IN ",
4 | "readme": "NativeScript Application",
5 | "repository": "",
6 | "nativescript": {
7 | "id": "org.nativescript.NativeScriptChatViewDemo",
8 | "tns-android": {
9 | "version": "2.4.1"
10 | }
11 | },
12 | "dependencies": {
13 | "nativescript-chatview": "file:..\\plugin",
14 | "tns-core-modules": "^2.4.1"
15 | },
16 | "devDependencies": {
17 | "babel-traverse": "6.19.0",
18 | "babel-types": "6.19.0",
19 | "babylon": "6.14.1",
20 | "lazy": "1.0.11",
21 | "nativescript-dev-typescript": "^0.3.2",
22 | "typescript": "^1.8.10"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nativescript-chatview",
3 | "description": "NativeScript UI module for implementing WhatsApp like chat applications.",
4 | "version": "1.0.3",
5 | "nativescript": {
6 | "platforms": {
7 | "android": "1.1.0",
8 | "ios": "1.0.0"
9 | }
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/mkloubert/nativescript-chatview"
14 | },
15 | "keywords": [
16 | "NativeScript",
17 | "API",
18 | "HTTP",
19 | "REST",
20 | "JSON",
21 | "XML"
22 | ],
23 | "author": {
24 | "name": "Marcel Joachim Kloubert",
25 | "email": "marcel.kloubert@gmx.net"
26 | },
27 | "license": {
28 | "type": "MIT",
29 | "url": "https://github.com/mkloubert/nativescript-chatview/blob/master/LICENSE"
30 | },
31 | "bugs": {
32 | "url": "https://github.com/mkloubert/nativescript-chatview/issues"
33 | },
34 | "homepage": "https://github.com/mkloubert/nativescript-chatview",
35 | "readmeFilename": "README.md",
36 | "dependencies": {}
37 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Marcel Kloubert
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIconFile
12 | icon.png
13 | CFBundleIcons
14 |
15 | CFBundlePrimaryIcon
16 |
17 | CFBundleIconFiles
18 |
19 | icon-40
20 | icon-60
21 | icon-72
22 | icon-76
23 | Icon-Small
24 | Icon-Small-50
25 |
26 | UIPrerenderedIcon
27 |
28 |
29 |
30 | CFBundleInfoDictionaryVersion
31 | 6.0
32 | CFBundleName
33 | ${PRODUCT_NAME}
34 | CFBundlePackageType
35 | APPL
36 | CFBundleShortVersionString
37 | 1.0
38 | CFBundleSignature
39 | ????
40 | CFBundleVersion
41 | 1.0
42 | LSRequiresIPhoneOS
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIRequiresFullScreen
47 |
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/demo/app/app.css:
--------------------------------------------------------------------------------
1 |
2 | .nsChatView-view .nsChatView-sendMessageArea {
3 | margin: 4,0,0,0;
4 | background-color: #e8e8e8;
5 | }
6 |
7 | .nsChatView-view .nsChatView-sendMessageArea Button {
8 | background-color: transparent;
9 | margin: 0;
10 | }
11 |
12 | .nsChatView-view .nsChatView-messageList {
13 | background-color: transparent;
14 | border-color: transparent;
15 | border-width: 0;
16 | margin: 0;
17 | }
18 |
19 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-avatar,
20 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-avatar {
21 | margin: 8;
22 | border-radius: 32;
23 | width: 64;
24 | }
25 |
26 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-separator,
27 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-separator {
28 | border-color: transparent;
29 | border-width: 0;
30 | width: 32;
31 | }
32 |
33 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-message,
34 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-message {
35 | margin: 8;
36 | }
37 |
38 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea,
39 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
40 | border-radius: 8;
41 | }
42 |
43 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea {
44 | background-color: #edeef2;
45 | }
46 |
47 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
48 | background-color: #00b863;
49 | }
50 |
51 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content,
52 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content {
53 | margin: 12,16,12,16;
54 | }
55 |
56 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea Label,
57 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea Label {
58 | margin: 0;
59 | }
60 |
61 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content Label {
62 | color: black;
63 | }
64 |
65 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content Label {
66 | color: white;
67 | }
68 |
69 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content .nsChatView-date,
70 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content .nsChatView-date {
71 | font-size: 11;
72 | margin-bottom: 12;
73 | }
74 |
75 | .nsChatView-view .nsChatView-messageField {
76 | font-size: 14;
77 | }
78 |
--------------------------------------------------------------------------------
/plugin/index.css:
--------------------------------------------------------------------------------
1 |
2 | .nsChatView-view .nsChatView-sendMessageArea {
3 | margin: 4,0,0,0;
4 | background-color: #e8e8e8;
5 | }
6 |
7 | .nsChatView-view .nsChatView-sendMessageArea Button {
8 | background-color: transparent;
9 | margin: 0;
10 | }
11 |
12 | .nsChatView-view .nsChatView-messageList {
13 | background-color: transparent;
14 | border-color: transparent;
15 | border-width: 0;
16 | margin: 0;
17 | }
18 |
19 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-avatar,
20 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-avatar {
21 | margin: 8;
22 | border-radius: 32;
23 | width: 64;
24 | }
25 |
26 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-separator,
27 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-separator {
28 | border-color: transparent;
29 | border-width: 0;
30 | width: 32;
31 | }
32 |
33 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-message,
34 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-message {
35 | margin: 8;
36 | }
37 |
38 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea,
39 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
40 | border-radius: 8;
41 | }
42 |
43 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea {
44 | background-color: #edeef2;
45 | }
46 |
47 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
48 | background-color: #00b863;
49 | }
50 |
51 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content,
52 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content {
53 | margin: 12,16,12,16;
54 | }
55 |
56 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea Label,
57 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea Label {
58 | margin: 0;
59 | }
60 |
61 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content Label {
62 | color: black;
63 | }
64 |
65 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content Label {
66 | color: white;
67 | }
68 |
69 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content .nsChatView-date,
70 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content .nsChatView-date {
71 | font-size: 11;
72 | margin-bottom: 12;
73 | }
74 |
75 | .nsChatView-view .nsChatView-messageField {
76 | font-size: 14;
77 | }
78 |
--------------------------------------------------------------------------------
/plugin/index.d.ts:
--------------------------------------------------------------------------------
1 | import Button = require("ui/button");
2 | import ListView = require("ui/list-view");
3 | import GridLayout = require("ui/layouts/grid-layout");
4 | import Observable = require("data/observable");
5 | import ObservableArray = require("data/observable-array");
6 | import TextField = require("ui/text-field");
7 | /**
8 | * A view for displaying chat messages.
9 | */
10 | export declare class ChatView extends GridLayout.GridLayout {
11 | /**
12 | * The name of the event that is raised when the "SEND" button is clicked.
13 | */
14 | static sendChatMessageButtonTapEvent: string;
15 | private _messageField;
16 | private _messageList;
17 | private _messages;
18 | private _sendMessageArea;
19 | private _sendMessageButton;
20 | private _sendChatMessageButtonTapEventListeners;
21 | /** @inheritdoc */
22 | constructor(json?: any);
23 | /**
24 | * Appends a list of messages.
25 | *
26 | * @param {IChatMessage} ...msgs One or more messages to append.
27 | */
28 | appendMessages(...msgs: IChatMessage[]): void;
29 | /**
30 | * Focus the text field with the chat message to send.
31 | *
32 | * @return {Boolean} Operation was successful or not.
33 | */
34 | focusMessageField(): boolean;
35 | /**
36 | * Inserts chat messages at a specific position.
37 | *
38 | * @param {Number} index The zero based index where the messages should be inserted.
39 | * @param {IChatMessage} ...msgs One or more messages to insert.
40 | */
41 | insertMessages(index: number, ...msgs: IChatMessage[]): void;
42 | /**
43 | * Gets the input field that stores the chat message that should be send.
44 | */
45 | messageField: TextField.TextField;
46 | /**
47 | * Gets the list that displays the chat messages.
48 | */
49 | messageList: ListView.ListView;
50 | /**
51 | * Gets the array of messages.
52 | */
53 | messages: ObservableArray.ObservableArray;
54 | /**
55 | * Adds an event handler that is invoked when the "SEND" button is clicked.
56 | *
57 | * @param {Function} handler The handler to add.
58 | */
59 | notifyOnSendMessageTap(handler: (eventData: SendMessageTappedEventData) => void): void;
60 | /**
61 | * Prepends a list of messages.
62 | *
63 | * @param {IChatMessage} ...msgs One or more messages to prepend.
64 | */
65 | prependMessages(...msgs: IChatMessage[]): void;
66 | /**
67 | * Resets the value of the chat message field.
68 | */
69 | resetMessage(): void;
70 | /**
71 | * Gets the control that contains the chat message field
72 | * and the "SEND" button.
73 | */
74 | sendMessageArea: GridLayout.GridLayout;
75 | /**
76 | * Gets the button that is used to send a chat message.
77 | */
78 | sendMessageButton: Button.Button;
79 | /**
80 | * Gets and sets the caption of the "SEND" button.
81 | */
82 | sendMessageButtonCaption: string;
83 | /**
84 | * Gets and sets the hint text for the chat message field.
85 | */
86 | typeMessageHint: string;
87 | }
88 | /**
89 | * Describes an object that stores required data for a char message.
90 | */
91 | export interface IChatMessage {
92 | /**
93 | * The date.
94 | *
95 | * @property
96 | */
97 | date?: any;
98 | /**
99 | * The image source.
100 | *
101 | * @property
102 | */
103 | image?: any;
104 | /**
105 | * Defines if the displayed item is aligned on the right side or not.
106 | *
107 | * @property
108 | */
109 | isRight?: boolean;
110 | /**
111 | * The message value.
112 | *
113 | * @property
114 | */
115 | message?: any;
116 | }
117 | /**
118 | * Data for an event that is raised when the "SEND" button is clicked.
119 | */
120 | export declare class SendMessageTappedEventData implements Observable.EventData {
121 | private _message;
122 | private _object;
123 | /**
124 | * Initializes a new instance of that class.
125 | *
126 | * @param {ChatView} view The underlying view.
127 | * @param {String} msg
128 | */
129 | constructor(view: ChatView, msg: string);
130 | /** @inheritdoc */
131 | eventName: string;
132 | /**
133 | * Focuses the chat message field.
134 | *
135 | * @return {Boolean} Operation was successful or not.
136 | */
137 | focusTextField(): boolean;
138 | /**
139 | * Gets the message to send.
140 | */
141 | message: string;
142 | /** @inheritdoc */
143 | object: ChatView;
144 | /**
145 | * Resets the message value.
146 | */
147 | resetMessage(): void;
148 | /**
149 | * Scrolls to bottom.
150 | */
151 | scrollToBottom(): void;
152 | }
153 |
--------------------------------------------------------------------------------
/demo/app/main-page.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var ChatViewModule = require("nativescript-chatview");
3 | var Timer = require("timer");
4 | var TypeUtils = require("utils/types");
5 | var ViewModel = require("./main-view-model");
6 | function createAnswer(msg) {
7 | if (/(\s*)([0-9]+)(\.?)([0-9]*)(\s*)([\+|\-|\*|\/])(\s*)([0-9]+)(\.?)([0-9]*)/i.test(msg)) {
8 | var result;
9 | eval("result = " + msg + ";");
10 | return result;
11 | }
12 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "how", "are", "you")) {
13 | return "Fine!";
14 | }
15 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "what", "time", "is", "it")) {
16 | return getTime();
17 | }
18 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "hi")) {
19 | return "Hi! How are you?";
20 | }
21 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "fine")) {
22 | return "Cool!";
23 | }
24 | return 'You said: "' + msg + '"';
25 | }
26 | function getSimilarity(left, right) {
27 | if (left === right) {
28 | return 1;
29 | }
30 | if (TypeUtils.isNullOrUndefined(left) ||
31 | TypeUtils.isNullOrUndefined(right)) {
32 | return 0;
33 | }
34 | left = left.toLowerCase().trim();
35 | right = right.toLowerCase().trim();
36 | var distance = 0;
37 | if (left !== right) {
38 | var matrix = new Array(left.length + 1);
39 | for (var i = 0; i < matrix.length; i++) {
40 | matrix[i] = new Array(right.length + 1);
41 | for (var ii = 0; ii < matrix[i].length; ii++) {
42 | matrix[i][ii] = 0;
43 | }
44 | }
45 | for (var i = 0; i <= left.length; i++) {
46 | matrix[i][0] = i;
47 | }
48 | for (var j = 0; j <= right.length; j++) {
49 | matrix[0][j] = j;
50 | }
51 | for (var i = 0; i < left.length; i++) {
52 | for (var j = 0; j < right.length; j++) {
53 | if (left[i] === right[j]) {
54 | matrix[i + 1][j + 1] = matrix[i][j];
55 | }
56 | else {
57 | matrix[i + 1][j + 1] = Math.min(matrix[i][j + 1] + 1, matrix[i + 1][j] + 1);
58 | matrix[i + 1][j + 1] = Math.min(matrix[i + 1][j + 1], matrix[i][j] + 1);
59 | }
60 | }
61 | distance = matrix[left.length][right.length];
62 | }
63 | }
64 | return 1.0 - distance / Math.max(left.length, right.length);
65 | }
66 | function checkForAllTerms(str) {
67 | var terms = [];
68 | for (var _i = 1; _i < arguments.length; _i++) {
69 | terms[_i - 1] = arguments[_i];
70 | }
71 | var parts = str.split(" ");
72 | for (var i = 0; i < parts.length; i++) {
73 | var p = parts[i];
74 | if (p.trim() === "") {
75 | continue;
76 | }
77 | var found = false;
78 | for (var ii = 0; ii < terms.length; ii++) {
79 | var t = terms[ii];
80 | if (getSimilarity(p, t) >= 0.5) {
81 | found = true;
82 | break;
83 | }
84 | }
85 | if (!found) {
86 | return false;
87 | }
88 | }
89 | return true;
90 | }
91 | function getLettersAndDigitsOnly(str) {
92 | var result = "";
93 | for (var i = 0; i < str.length; i++) {
94 | if (/[a-zA-Z0-9]/i.test(str[i])) {
95 | result += str[i];
96 | }
97 | else if (/[\s]/i.test(str[i])) {
98 | result += " ";
99 | }
100 | }
101 | return result;
102 | }
103 | function getTime() {
104 | var now = new Date();
105 | var hours = now.getHours();
106 | return numberToString(hours == 12 ? 12 : (hours % 12)) + ":" + numberToString(now.getMinutes()) + " " +
107 | (hours < 13 ? "AM" : "PM");
108 | }
109 | function numberToString(n) {
110 | var str = "" + n;
111 | if (n < 10) {
112 | str = "0" + str;
113 | }
114 | return str;
115 | }
116 | function onNavigatingTo(args) {
117 | var page = args.object;
118 | page.bindingContext = ViewModel.createViewModel();
119 | var chatView = new ChatViewModule.ChatView();
120 | chatView.sendMessageButtonCaption = "Send";
121 | chatView.typeMessageHint = "Your message for Albert";
122 | chatView.notifyOnSendMessageTap(function (eventData) {
123 | eventData.object.appendMessages({
124 | date: getTime(),
125 | isRight: true,
126 | image: "~/img/marcel.jpg",
127 | message: eventData.message,
128 | });
129 | eventData.resetMessage();
130 | eventData.scrollToBottom();
131 | eventData.focusTextField();
132 | Timer.setTimeout(function () {
133 | eventData.object.appendMessages({
134 | date: getTime(),
135 | isRight: false,
136 | image: "~/img/alert.jpg",
137 | message: createAnswer(eventData.message),
138 | });
139 | }, Math.floor(Math.random() * 2000));
140 | });
141 | chatView.focusMessageField();
142 | page.content = chatView;
143 | }
144 | exports.onNavigatingTo = onNavigatingTo;
145 | //# sourceMappingURL=main-page.js.map
--------------------------------------------------------------------------------
/demo/app/main-page.ts:
--------------------------------------------------------------------------------
1 | import ChatViewModule = require("nativescript-chatview");
2 | import Frame = require("ui/frame");
3 | import PageModule = require("ui/page");
4 | import Timer = require("timer");
5 | import TypeUtils = require("utils/types");
6 | import View = require("ui/core/view");
7 | import ViewModel = require("./main-view-model");
8 |
9 | function createAnswer(msg) : string {
10 | if (/(\s*)([0-9]+)(\.?)([0-9]*)(\s*)([\+|\-|\*|\/])(\s*)([0-9]+)(\.?)([0-9]*)/i.test(msg)) {
11 | var result;
12 | eval("result = " + msg + ";");
13 |
14 | return result;
15 | }
16 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "how", "are", "you")) {
17 | return "Fine!";
18 | }
19 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "what", "time", "is", "it")) {
20 | return getTime();
21 | }
22 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "hi")) {
23 | return "Hi! How are you?";
24 | }
25 | else if (checkForAllTerms(getLettersAndDigitsOnly(msg), "fine")) {
26 | return "Cool!";
27 | }
28 |
29 | return 'You said: "' + msg + '"';
30 | }
31 |
32 | function getSimilarity(left: string, right: string) : number {
33 | if (left === right) {
34 | return 1;
35 | }
36 |
37 | if (TypeUtils.isNullOrUndefined(left) ||
38 | TypeUtils.isNullOrUndefined(right)) {
39 | return 0;
40 | }
41 |
42 | left = left.toLowerCase().trim();
43 | right = right.toLowerCase().trim();
44 |
45 | var distance = 0;
46 |
47 | if (left !== right) {
48 | var matrix = new Array(left.length + 1);
49 | for (var i = 0; i < matrix.length; i++) {
50 | matrix[i] = new Array(right.length + 1);
51 |
52 | for (var ii = 0; ii < matrix[i].length; ii++) {
53 | matrix[i][ii] = 0;
54 | }
55 | }
56 |
57 | for (var i = 0; i <= left.length; i++) {
58 | matrix[i][0] = i;
59 | }
60 |
61 | for (var j = 0; j <= right.length; j++) {
62 | matrix[0][j] = j;
63 | }
64 |
65 | for (var i = 0; i < left.length; i++) {
66 | for (var j = 0; j < right.length; j++) {
67 | if (left[i] === right[j]) {
68 | matrix[i + 1][j + 1] = matrix[i][j];
69 | }
70 | else {
71 | matrix[i + 1][j + 1] = Math.min(matrix[i][j + 1] + 1,
72 | matrix[i + 1][j] + 1);
73 |
74 | matrix[i + 1][j + 1] = Math.min(matrix[i + 1][j + 1],
75 | matrix[i][j] + 1);
76 | }
77 | }
78 |
79 | distance = matrix[left.length][right.length];
80 | }
81 | }
82 |
83 | return 1.0 - distance / Math.max(left.length,
84 | right.length);
85 | }
86 |
87 | function checkForAllTerms(str: string, ...terms: string[]) : boolean {
88 | var parts = str.split(" ");
89 | for (var i = 0; i < parts.length; i++) {
90 | var p = parts[i];
91 | if (p.trim() === "") {
92 | continue;
93 | }
94 |
95 | var found = false;
96 |
97 | for (var ii = 0; ii < terms.length; ii++) {
98 | var t = terms[ii];
99 |
100 | if (getSimilarity(p, t) >= 0.5) {
101 | found = true;
102 | break;
103 | }
104 | }
105 |
106 | if (!found) {
107 | return false;
108 | }
109 | }
110 |
111 | return true;
112 | }
113 |
114 | function getLettersAndDigitsOnly(str: string) : string {
115 | var result = "";
116 |
117 | for (var i = 0; i < str.length; i++) {
118 | if (/[a-zA-Z0-9]/i.test(str[i])) {
119 | result += str[i];
120 | }
121 | else if (/[\s]/i.test(str[i])) {
122 | result += " ";
123 | }
124 | }
125 |
126 | return result;
127 | }
128 |
129 | function getTime() : string {
130 | var now = new Date();
131 |
132 | var hours = now.getHours();
133 | return numberToString(hours == 12 ? 12 : (hours % 12)) + ":" + numberToString(now.getMinutes()) + " " +
134 | (hours < 13 ? "AM" : "PM");
135 | }
136 |
137 | function numberToString(n: number): string {
138 | var str = "" + n;
139 | if (n < 10) {
140 | str = "0" + str;
141 | }
142 |
143 | return str;
144 | }
145 |
146 | export function onNavigatingTo(args) {
147 | var page = args.object;
148 | page.bindingContext = ViewModel.createViewModel();
149 |
150 | var chatView = new ChatViewModule.ChatView();
151 | chatView.sendMessageButtonCaption = "Send";
152 | chatView.typeMessageHint = "Your message for Albert";
153 |
154 | chatView.notifyOnSendMessageTap((eventData) => {
155 | eventData.object.appendMessages({
156 | date: getTime(),
157 | isRight: true,
158 | image: "~/img/marcel.jpg",
159 | message: eventData.message,
160 | });
161 |
162 | eventData.resetMessage();
163 | eventData.scrollToBottom();
164 | eventData.focusTextField();
165 |
166 | Timer.setTimeout(() => {
167 | eventData.object.appendMessages({
168 | date: getTime(),
169 | isRight: false,
170 | image: "~/img/alert.jpg",
171 | message: createAnswer(eventData.message),
172 | });
173 | }, Math.floor(Math.random() * 2000));
174 | });
175 |
176 | chatView.focusMessageField();
177 |
178 | page.content = chatView;
179 | }
180 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/nativescript-chatview)
2 | [](https://www.npmjs.com/package/nativescript-chatview)
3 |
4 | # NativeScript ChatView
5 |
6 | A [NativeScript](https://nativescript.org/) UI module for implementing WhatsApp like chat applications.
7 |
8 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SSS259WRLTWU2)
9 |
10 | ## License
11 |
12 | [MIT license](https://raw.githubusercontent.com/mkloubert/nativescript-chatview/master/LICENSE)
13 |
14 | ## Platforms
15 |
16 | * Android
17 | * iOS
18 |
19 | ## Installation
20 |
21 | Run
22 |
23 | ```bash
24 | tns plugin add nativescript-chatview
25 | ```
26 |
27 | inside your app project to install the module.
28 |
29 | ## Demo
30 |
31 | The demo app can be found [here](https://github.com/mkloubert/nativescript-chatview/tree/master/demo).
32 |
33 | 
34 |
35 | ## Usage
36 |
37 | ### Include
38 |
39 | ```javascript
40 | import ChatView = require("nativescript-chatview");
41 | ```
42 |
43 | ### Create view
44 |
45 | ```xml
46 |
48 |
49 | ```
50 |
51 | ```typescript
52 | import ChatView = require("nativescript-chatview");
53 |
54 | function getTime() : string {
55 | var now = new Date();
56 |
57 | var hours = now.getHours();
58 | return numberToString(hours == 12 ? 12 : (hours % 12)) + ":" + numberToString(now.getMinutes()) + " " +
59 | (hours < 13 ? "AM" : "PM");
60 | }
61 |
62 | export function onNavigatingTo(args) {
63 | var page = args.object;
64 |
65 | // create view
66 | var chatView = new ChatView.ChatView();
67 |
68 | // register event when user taps
69 | // on SEND button
70 | chatView.notifyOnSendMessageTap((eventData: ChatView.SendMessageTappedEventData) => {
71 | // add a chat message
72 | eventData.object.appendMessages({
73 | date: getTime(),
74 | isRight: true,
75 | image: "~/img/avatar.jpg",
76 | message: eventData.message,
77 | });
78 | });
79 |
80 | // focus text field
81 | chatView.focusMessageField();
82 |
83 | page.content = chatView;
84 | }
85 | ```
86 |
87 | #### The XML way
88 |
89 | ```xml
90 |
93 |
94 |
95 |
96 | ```
97 |
98 | ### Styling
99 |
100 | Add the following CSS to your code:
101 |
102 | ```css
103 | .nsChatView-view .nsChatView-sendMessageArea {
104 | margin: 4,0,0,0;
105 | background-color: #e8e8e8;
106 | }
107 |
108 | .nsChatView-view .nsChatView-sendMessageArea Button {
109 | background-color: transparent;
110 | margin: 0;
111 | }
112 |
113 | .nsChatView-view .nsChatView-messageList {
114 | background-color: transparent;
115 | border-color: transparent;
116 | border-width: 0;
117 | margin: 0;
118 | }
119 |
120 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-avatar,
121 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-avatar {
122 | margin: 8;
123 | border-radius: 32;
124 | width: 64;
125 | }
126 |
127 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-separator,
128 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-separator {
129 | border-color: transparent;
130 | border-width: 0;
131 | width: 32;
132 | }
133 |
134 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-message,
135 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-message {
136 | margin: 8;
137 | }
138 |
139 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea,
140 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
141 | border-radius: 8;
142 | }
143 |
144 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea {
145 | background-color: #edeef2;
146 | }
147 |
148 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
149 | background-color: #00b863;
150 | }
151 |
152 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content,
153 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content {
154 | margin: 12,16,12,16;
155 | }
156 |
157 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea Label,
158 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea Label {
159 | margin: 0;
160 | }
161 |
162 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content Label {
163 | color: black;
164 | }
165 |
166 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content Label {
167 | color: white;
168 | }
169 |
170 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content .nsChatView-date,
171 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content .nsChatView-date {
172 | font-size: 11;
173 | margin-bottom: 12;
174 | }
175 |
176 | .nsChatView-view .nsChatView-messageField {
177 | font-size: 14;
178 | }
179 | ```
180 |
181 | To understand how a `ChatView` is defined, you can have a look at the following XML definition:
182 |
183 | ```xml
184 |
186 |
187 |
188 |
193 |
194 |
195 |
196 |
197 |
199 |
200 |
201 |
206 |
207 |
208 |
210 |
211 |
212 |
213 |
215 |
216 |
217 |
221 |
222 |
223 |
226 |
227 |
228 |
229 |
230 |
231 |
233 |
234 |
235 |
236 |
237 |
238 |
241 |
242 |
243 |
246 |
247 |
248 |
251 |
252 |
253 | ```
254 |
255 | The following properties of a `ChatView` can be used to access the controls defined in the XML:
256 |
257 | | Name | CSS class |
258 | | ---- | --------- |
259 | | messageField | nsChatView-messageField |
260 | | messageList | nsChatView-messageList |
261 | | sendMessageArea | nsChatView-sendMessageArea |
262 | | sendMessageButton | nsChatView-sendMessageButton |
263 |
264 | ### Add messages
265 |
266 | Chat messages are wrapped into an `IChatMessage` object:
267 |
268 | ```typescript
269 | export interface IChatMessage {
270 | /**
271 | * The date.
272 | */
273 | date?: any;
274 |
275 | /**
276 | * The image source.
277 | */
278 | image?: any;
279 |
280 | /**
281 | * Defines if the displayed item is aligned on the right side or not.
282 | */
283 | isRight?: boolean;
284 |
285 | /**
286 | * The message value.
287 | */
288 | message?: any;
289 | }
290 | ```
291 |
292 | #### Add
293 |
294 | Use `appendMessages()` method to add one or more chat messages:
295 |
296 | ```typescript
297 | object.appendMessages({
298 | date: getTime(),
299 | isRight: true,
300 | image: "~/img/me.jpg",
301 | message: "My message",
302 | }, {
303 | date: getTime(),
304 | isRight: false,
305 | image: "~/img/friend.jpg",
306 | message: "Friend's message",
307 | });
308 | ```
309 |
310 | #### Insert
311 |
312 | Use `insertMessages()` method to insert one or more chat messages at a specific position:
313 |
314 | ```typescript
315 | object.insertMessages(1, {
316 | date: getTime(),
317 | isRight: true,
318 | image: "~/img/me.jpg",
319 | message: "My message",
320 | }, {
321 | date: getTime(),
322 | isRight: false,
323 | image: "~/img/friend.jpg",
324 | message: "Friend's message",
325 | });
326 | ```
327 |
328 | #### Prepend
329 |
330 | Use `insertMessages()` method to prepend one or more chat messages:
331 |
332 | ```typescript
333 | object.prependMessages({
334 | date: getTime(),
335 | isRight: true,
336 | image: "~/img/me.jpg",
337 | message: "My message",
338 | }, {
339 | date: getTime(),
340 | isRight: false,
341 | image: "~/img/friend.jpg",
342 | message: "Friend's message",
343 | });
344 | ```
345 |
346 | ### SEND button
347 |
348 | Use the `notifyOnSendMessageTap()` method to register for a "click" event:
349 |
350 | ```typescript
351 | chatView.notifyOnSendMessageTap((eventData: ChatView.SendMessageTappedEventData) => {
352 | // handle the event
353 | });
354 | ```
355 |
356 | The `eventData` object has the following structure:
357 |
358 | ```typescript
359 | import Observable = require("data/observable");
360 |
361 | export class SendMessageTappedEventData implements Observable.EventData {
362 | /** @inheritdoc */
363 | public eventName: string;
364 |
365 | /**
366 | * Focuses the chat message field.
367 | *
368 | * @return {Boolean} Operation was successful or not.
369 | */
370 | public focusTextField(): boolean;
371 |
372 | /**
373 | * Gets the message to send.
374 | */
375 | public message: string;
376 |
377 | /** @inheritdoc */
378 | public object: ChatView;
379 |
380 | /**
381 | * Resets the message value.
382 | */
383 | public resetMessage();
384 |
385 | /**
386 | * Scrolls to bottom.
387 | */
388 | public scrollToBottom();
389 | }
390 | ```
391 |
--------------------------------------------------------------------------------
/plugin/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/nativescript-chatview)
2 | [](https://www.npmjs.com/package/nativescript-chatview)
3 |
4 | # NativeScript ChatView
5 |
6 | A [NativeScript](https://nativescript.org/) UI module for implementing WhatsApp like chat applications.
7 |
8 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SSS259WRLTWU2)
9 |
10 | ## License
11 |
12 | [MIT license](https://raw.githubusercontent.com/mkloubert/nativescript-chatview/master/LICENSE)
13 |
14 | ## Platforms
15 |
16 | * Android
17 | * iOS
18 |
19 | ## Installation
20 |
21 | Run
22 |
23 | ```bash
24 | tns plugin add nativescript-chatview
25 | ```
26 |
27 | inside your app project to install the module.
28 |
29 | ## Demo
30 |
31 | The demo app can be found [here](https://github.com/mkloubert/nativescript-chatview/tree/master/demo).
32 |
33 | 
34 |
35 | ## Usage
36 |
37 | ### Include
38 |
39 | ```javascript
40 | import ChatView = require("nativescript-chatview");
41 | ```
42 |
43 | ### Create view
44 |
45 | ```xml
46 |
48 |
49 | ```
50 |
51 | ```typescript
52 | import ChatView = require("nativescript-chatview");
53 |
54 | function getTime() : string {
55 | var now = new Date();
56 |
57 | var hours = now.getHours();
58 | return numberToString(hours == 12 ? 12 : (hours % 12)) + ":" + numberToString(now.getMinutes()) + " " +
59 | (hours < 13 ? "AM" : "PM");
60 | }
61 |
62 | export function onNavigatingTo(args) {
63 | var page = args.object;
64 |
65 | // create view
66 | var chatView = new ChatView.ChatView();
67 |
68 | // register event when user taps
69 | // on SEND button
70 | chatView.notifyOnSendMessageTap((eventData: ChatView.SendMessageTappedEventData) => {
71 | // add a chat message
72 | eventData.object.appendMessages({
73 | date: getTime(),
74 | isRight: true,
75 | image: "~/img/avatar.jpg",
76 | message: eventData.message,
77 | });
78 | });
79 |
80 | // focus text field
81 | chatView.focusMessageField();
82 |
83 | page.content = chatView;
84 | }
85 | ```
86 |
87 | #### The XML way
88 |
89 | ```xml
90 |
93 |
94 |
95 |
96 | ```
97 |
98 | ### Styling
99 |
100 | Add the following CSS to your code:
101 |
102 | ```css
103 | .nsChatView-view .nsChatView-sendMessageArea {
104 | margin: 4,0,0,0;
105 | background-color: #e8e8e8;
106 | }
107 |
108 | .nsChatView-view .nsChatView-sendMessageArea Button {
109 | background-color: transparent;
110 | margin: 0;
111 | }
112 |
113 | .nsChatView-view .nsChatView-messageList {
114 | background-color: transparent;
115 | border-color: transparent;
116 | border-width: 0;
117 | margin: 0;
118 | }
119 |
120 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-avatar,
121 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-avatar {
122 | margin: 8;
123 | border-radius: 32;
124 | width: 64;
125 | }
126 |
127 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-separator,
128 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-separator {
129 | border-color: transparent;
130 | border-width: 0;
131 | width: 32;
132 | }
133 |
134 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-message,
135 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-message {
136 | margin: 8;
137 | }
138 |
139 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea,
140 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
141 | border-radius: 8;
142 | }
143 |
144 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea {
145 | background-color: #edeef2;
146 | }
147 |
148 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea {
149 | background-color: #00b863;
150 | }
151 |
152 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content,
153 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content {
154 | margin: 12,16,12,16;
155 | }
156 |
157 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea Label,
158 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea Label {
159 | margin: 0;
160 | }
161 |
162 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content Label {
163 | color: black;
164 | }
165 |
166 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content Label {
167 | color: white;
168 | }
169 |
170 | .nsChatView-view .nsChatView-messageList .nsChatView-item-left .nsChatView-messageArea .nsChatView-content .nsChatView-date,
171 | .nsChatView-view .nsChatView-messageList .nsChatView-item-right .nsChatView-messageArea .nsChatView-content .nsChatView-date {
172 | font-size: 11;
173 | margin-bottom: 12;
174 | }
175 |
176 | .nsChatView-view .nsChatView-messageField {
177 | font-size: 14;
178 | }
179 | ```
180 |
181 | To understand how a `ChatView` is defined, you can have a look at the following XML definition:
182 |
183 | ```xml
184 |
186 |
187 |
188 |
193 |
194 |
195 |
196 |
197 |
199 |
200 |
201 |
206 |
207 |
208 |
210 |
211 |
212 |
213 |
215 |
216 |
217 |
221 |
222 |
223 |
226 |
227 |
228 |
229 |
230 |
231 |
233 |
234 |
235 |
236 |
237 |
238 |
241 |
242 |
243 |
246 |
247 |
248 |
251 |
252 |
253 | ```
254 |
255 | The following properties of a `ChatView` can be used to access the controls defined in the XML:
256 |
257 | | Name | CSS class |
258 | | ---- | --------- |
259 | | messageField | nsChatView-messageField |
260 | | messageList | nsChatView-messageList |
261 | | sendMessageArea | nsChatView-sendMessageArea |
262 | | sendMessageButton | nsChatView-sendMessageButton |
263 |
264 | ### Add messages
265 |
266 | Chat messages are wrapped into an `IChatMessage` object:
267 |
268 | ```typescript
269 | export interface IChatMessage {
270 | /**
271 | * The date.
272 | */
273 | date?: any;
274 |
275 | /**
276 | * The image source.
277 | */
278 | image?: any;
279 |
280 | /**
281 | * Defines if the displayed item is aligned on the right side or not.
282 | */
283 | isRight?: boolean;
284 |
285 | /**
286 | * The message value.
287 | */
288 | message?: any;
289 | }
290 | ```
291 |
292 | #### Add
293 |
294 | Use `appendMessages()` method to add one or more chat messages:
295 |
296 | ```typescript
297 | object.appendMessages({
298 | date: getTime(),
299 | isRight: true,
300 | image: "~/img/me.jpg",
301 | message: "My message",
302 | }, {
303 | date: getTime(),
304 | isRight: false,
305 | image: "~/img/friend.jpg",
306 | message: "Friend's message",
307 | });
308 | ```
309 |
310 | #### Insert
311 |
312 | Use `insertMessages()` method to insert one or more chat messages at a specific position:
313 |
314 | ```typescript
315 | object.insertMessages(1, {
316 | date: getTime(),
317 | isRight: true,
318 | image: "~/img/me.jpg",
319 | message: "My message",
320 | }, {
321 | date: getTime(),
322 | isRight: false,
323 | image: "~/img/friend.jpg",
324 | message: "Friend's message",
325 | });
326 | ```
327 |
328 | #### Prepend
329 |
330 | Use `insertMessages()` method to prepend one or more chat messages:
331 |
332 | ```typescript
333 | object.prependMessages({
334 | date: getTime(),
335 | isRight: true,
336 | image: "~/img/me.jpg",
337 | message: "My message",
338 | }, {
339 | date: getTime(),
340 | isRight: false,
341 | image: "~/img/friend.jpg",
342 | message: "Friend's message",
343 | });
344 | ```
345 |
346 | ### SEND button
347 |
348 | Use the `notifyOnSendMessageTap()` method to register for a "click" event:
349 |
350 | ```typescript
351 | chatView.notifyOnSendMessageTap((eventData: ChatView.SendMessageTappedEventData) => {
352 | // handle the event
353 | });
354 | ```
355 |
356 | The `eventData` object has the following structure:
357 |
358 | ```typescript
359 | import Observable = require("data/observable");
360 |
361 | export class SendMessageTappedEventData implements Observable.EventData {
362 | /** @inheritdoc */
363 | public eventName: string;
364 |
365 | /**
366 | * Focuses the chat message field.
367 | *
368 | * @return {Boolean} Operation was successful or not.
369 | */
370 | public focusTextField(): boolean;
371 |
372 | /**
373 | * Gets the message to send.
374 | */
375 | public message: string;
376 |
377 | /** @inheritdoc */
378 | public object: ChatView;
379 |
380 | /**
381 | * Resets the message value.
382 | */
383 | public resetMessage();
384 |
385 | /**
386 | * Scrolls to bottom.
387 | */
388 | public scrollToBottom();
389 | }
390 | ```
391 |
--------------------------------------------------------------------------------
/plugin/index.ts:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) Marcel Joachim Kloubert
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to
7 | // deal in the Software without restriction, including without limitation the
8 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 | // sell copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | // DEALINGS IN THE SOFTWARE.
22 |
23 | import Button = require("ui/button");
24 | import ListView = require("ui/list-view");
25 | import GridLayout = require("ui/layouts/grid-layout");
26 | import Observable = require("data/observable");
27 | import ObservableArray = require("data/observable-array");
28 | import TextField = require("ui/text-field");
29 | // import TextView = require("ui/text-view");
30 | import TypeUtils = require("utils/types");
31 | import UIEnums = require("ui/enums");
32 |
33 | /**
34 | * A view for displaying chat messages.
35 | */
36 | export class ChatView extends GridLayout.GridLayout {
37 | /**
38 | * The name of the event that is raised when the "SEND" button is clicked.
39 | */
40 | public static sendChatMessageButtonTapEvent: string = "sendChatMessageButtonTap";
41 |
42 | private _messageField: TextField.TextField;
43 | // private _messageField: TextView.TextView;
44 | private _messageList: ListView.ListView;
45 | private _messages: ObservableArray.ObservableArray = new ObservableArray.ObservableArray();
46 | private _sendMessageArea: GridLayout.GridLayout;
47 | private _sendMessageButton: Button.Button;
48 | private _sendChatMessageButtonTapEventListeners = [];
49 |
50 | /** @inheritdoc */
51 | constructor(json?: any) {
52 | super(json);
53 |
54 | var me = this;
55 | me.className = "nsChatView-view";
56 |
57 | this.addRow(new GridLayout.ItemSpec(1, "star"));
58 | this.addRow(new GridLayout.ItemSpec(1, "auto"));
59 |
60 | var rootRows = this.getRows();
61 | var chatListRow = rootRows[0];
62 | var sendMessageRow = rootRows[1];
63 |
64 | // chat list
65 | this._messageList = new ListView.ListView();
66 | this._messageList.className = "nsChatView-messageList";
67 | this._messageList.horizontalAlignment = "stretch";
68 | this._messageList.verticalAlignment = "stretch";
69 | this._messageList.items = this._messages;
70 | this._messageList.itemTemplate = `
71 |
76 |
77 |
79 |
80 |
81 |
83 |
84 |
88 |
89 |
92 |
93 |
94 |
95 |
96 |
98 | `;
99 | this.addChild(this._messageList);
100 | GridLayout.GridLayout.setRow(this._messageList, 0);
101 |
102 | this._sendMessageArea = new GridLayout.GridLayout();
103 | this._sendMessageArea.className = "nsChatView-sendMessageArea";
104 | this._sendMessageArea.addRow(new GridLayout.ItemSpec(1, "auto"));
105 | this._sendMessageArea.addColumn(new GridLayout.ItemSpec(1, "star"));
106 | this._sendMessageArea.addColumn(new GridLayout.ItemSpec(1, "auto"));
107 | this.addChild(this._sendMessageArea);
108 | GridLayout.GridLayout.setRow(this._sendMessageArea, 1);
109 |
110 | this._messageField = new TextField.TextField();
111 | // this._messageField = new TextView.TextView();
112 | this._messageField.className = "nsChatView-messageField";
113 | // this._messageField.returnKeyType = UIEnums.ReturnKeyType.send;
114 | this._messageField.autocorrect = false;
115 | this._messageField.autocapitalizationType = UIEnums.AutocapitalizationType.none;
116 | this._sendMessageArea.addChild(this._messageField);
117 | GridLayout.GridLayout.setRow(this._messageField, 0);
118 | GridLayout.GridLayout.setColumn(this._messageField, 0);
119 |
120 | this._messageField.on(TextField.TextField.returnPressEvent, (eventData) => {
121 | me._sendMessageButton
122 | .notify({
123 | eventName: Button.Button.tapEvent,
124 | object: me._sendMessageButton
125 | });
126 | });
127 |
128 | this._sendMessageButton = new Button.Button();
129 | this._sendMessageButton.className = "nsChatView-sendMessageButton";
130 | this._sendMessageArea.addChild(this._sendMessageButton);
131 | GridLayout.GridLayout.setRow(this._sendMessageButton, 0);
132 | GridLayout.GridLayout.setColumn(this._sendMessageButton, 1);
133 |
134 | this._sendMessageButton.on(Button.Button.tapEvent, (eventData) => {
135 | var chatMsg = me._messageField.text;
136 | if (TypeUtils.isNullOrUndefined(chatMsg) ||
137 | "" === chatMsg.trim()) {
138 |
139 | return;
140 | }
141 |
142 | me.notify(new SendMessageTappedEventData(me, chatMsg));
143 | });
144 |
145 | this.on(ChatView.sendChatMessageButtonTapEvent, function(eventData) {
146 | for (var i = 0; i < me._sendChatMessageButtonTapEventListeners.length; i++) {
147 | var el = me._sendChatMessageButtonTapEventListeners[i];
148 | el(eventData);
149 | }
150 | });
151 |
152 | this.typeMessageHint = "Type message...";
153 | this.sendMessageButtonCaption = "SEND";
154 | }
155 |
156 | /**
157 | * Appends a list of messages.
158 | *
159 | * @param {IChatMessage} ...msgs One or more messages to append.
160 | */
161 | public appendMessages(...msgs: IChatMessage[]) {
162 | for (var i = 0; i < msgs.length; i++) {
163 | this._messages.push(msgs[i]);
164 | }
165 | }
166 |
167 | /**
168 | * Focus the text field with the chat message to send.
169 | *
170 | * @return {Boolean} Operation was successful or not.
171 | */
172 | public focusMessageField() : boolean {
173 | return this._messageField.focus();
174 | }
175 |
176 | /**
177 | * Inserts chat messages at a specific position.
178 | *
179 | * @param {Number} index The zero based index where the messages should be inserted.
180 | * @param {IChatMessage} ...msgs One or more messages to insert.
181 | */
182 | public insertMessages(index: number, ...msgs: IChatMessage[]) {
183 | for (var i = 0; i < msgs.length; i++) {
184 | this._messages.splice(index + i, 0, msgs[0]);
185 | }
186 | }
187 |
188 | /**
189 | * Gets the input field that stores the chat message that should be send.
190 | */
191 | public get messageField(): TextField.TextField {
192 | // public get messageField(): TextView.TextView {
193 | return this._messageField;
194 | }
195 |
196 | /**
197 | * Gets the list that displays the chat messages.
198 | */
199 | public get messageList(): ListView.ListView {
200 | return this._messageList;
201 | }
202 |
203 | /**
204 | * Gets the array of messages.
205 | */
206 | public get messages(): ObservableArray.ObservableArray {
207 | return this._messages;
208 | }
209 |
210 | /**
211 | * Adds an event handler that is invoked when the "SEND" button is clicked.
212 | *
213 | * @param {Function} handler The handler to add.
214 | */
215 | public notifyOnSendMessageTap(handler: (eventData: SendMessageTappedEventData) => void) {
216 | this._sendChatMessageButtonTapEventListeners
217 | .push(handler);
218 | }
219 |
220 | /**
221 | * Prepends a list of messages.
222 | *
223 | * @param {IChatMessage} ...msgs One or more messages to prepend.
224 | */
225 | public prependMessages(...msgs: IChatMessage[]) {
226 | for (var i = 0; i < msgs.length; i++) {
227 | this._messages.splice(i, 0, msgs[0]);
228 | }
229 | }
230 |
231 | /**
232 | * Resets the value of the chat message field.
233 | */
234 | public resetMessage() {
235 | this._messageField.text = "";
236 | }
237 |
238 | /**
239 | * Gets the control that contains the chat message field
240 | * and the "SEND" button.
241 | */
242 | public get sendMessageArea(): GridLayout.GridLayout {
243 | return this._sendMessageArea;
244 | }
245 |
246 | /**
247 | * Gets the button that is used to send a chat message.
248 | */
249 | public get sendMessageButton(): Button.Button {
250 | return this._sendMessageButton;
251 | }
252 |
253 | /**
254 | * Gets and sets the caption of the "SEND" button.
255 | */
256 | public get sendMessageButtonCaption() : string {
257 | return this._sendMessageButton.text;
258 | }
259 | public set sendMessageButtonCaption(value: string) {
260 | this._sendMessageButton.text = value;
261 | }
262 |
263 | /**
264 | * Gets and sets the hint text for the chat message field.
265 | */
266 | public get typeMessageHint() : string {
267 | return this._messageField.hint;
268 | }
269 | public set typeMessageHint(value: string) {
270 | this._messageField.hint = value;
271 | }
272 | }
273 |
274 | /**
275 | * Describes an object that stores required data for a char message.
276 | */
277 | export interface IChatMessage {
278 | /**
279 | * The date.
280 | *
281 | * @property
282 | */
283 | date?: any;
284 |
285 | /**
286 | * The image source.
287 | *
288 | * @property
289 | */
290 | image?: any;
291 |
292 | /**
293 | * Defines if the displayed item is aligned on the right side or not.
294 | *
295 | * @property
296 | */
297 | isRight?: boolean;
298 |
299 | /**
300 | * The message value.
301 | *
302 | * @property
303 | */
304 | message?: any;
305 | }
306 |
307 | /**
308 | * Data for an event that is raised when the "SEND" button is clicked.
309 | */
310 | export class SendMessageTappedEventData implements Observable.EventData {
311 | private _message: string;
312 | private _object: ChatView;
313 |
314 | /**
315 | * Initializes a new instance of that class.
316 | *
317 | * @param {ChatView} view The underlying view.
318 | * @param {String} msg
319 | */
320 | constructor(view: ChatView, msg: string) {
321 | this._object = view;
322 | this._message = msg;
323 | }
324 |
325 | /** @inheritdoc */
326 | public get eventName(): string {
327 | return ChatView.sendChatMessageButtonTapEvent;
328 | }
329 |
330 | /**
331 | * Focuses the chat message field.
332 | *
333 | * @return {Boolean} Operation was successful or not.
334 | */
335 | public focusTextField(): boolean {
336 | return this._object.focusMessageField();
337 | }
338 |
339 | /**
340 | * Gets the message to send.
341 | */
342 | public get message(): string {
343 | return this._message;
344 | }
345 |
346 | /** @inheritdoc */
347 | public get object(): ChatView {
348 | return this._object;
349 | }
350 |
351 | /**
352 | * Resets the message value.
353 | */
354 | public resetMessage() {
355 | this._object.resetMessage();
356 | }
357 |
358 | /**
359 | * Scrolls to bottom.
360 | */
361 | public scrollToBottom() {
362 | this._object.messageList
363 | .scrollToIndex(this._object.messages.length - 1);
364 |
365 | this._object.messageList.refresh();
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/plugin/index.js:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) Marcel Joachim Kloubert
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to
7 | // deal in the Software without restriction, including without limitation the
8 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 | // sell copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | // DEALINGS IN THE SOFTWARE.
22 | "use strict";
23 | var Button = require("ui/button");
24 | var ListView = require("ui/list-view");
25 | var GridLayout = require("ui/layouts/grid-layout");
26 | var ObservableArray = require("data/observable-array");
27 | var TextField = require("ui/text-field");
28 | // import TextView = require("ui/text-view");
29 | var TypeUtils = require("utils/types");
30 | var UIEnums = require("ui/enums");
31 | /**
32 | * A view for displaying chat messages.
33 | */
34 | var ChatView = (function (_super) {
35 | __extends(ChatView, _super);
36 | /** @inheritdoc */
37 | function ChatView(json) {
38 | _super.call(this, json);
39 | this._messages = new ObservableArray.ObservableArray();
40 | this._sendChatMessageButtonTapEventListeners = [];
41 | var me = this;
42 | me.className = "nsChatView-view";
43 | this.addRow(new GridLayout.ItemSpec(1, "star"));
44 | this.addRow(new GridLayout.ItemSpec(1, "auto"));
45 | var rootRows = this.getRows();
46 | var chatListRow = rootRows[0];
47 | var sendMessageRow = rootRows[1];
48 | // chat list
49 | this._messageList = new ListView.ListView();
50 | this._messageList.className = "nsChatView-messageList";
51 | this._messageList.horizontalAlignment = "stretch";
52 | this._messageList.verticalAlignment = "stretch";
53 | this._messageList.items = this._messages;
54 | this._messageList.itemTemplate = "\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n";
55 | this.addChild(this._messageList);
56 | GridLayout.GridLayout.setRow(this._messageList, 0);
57 | this._sendMessageArea = new GridLayout.GridLayout();
58 | this._sendMessageArea.className = "nsChatView-sendMessageArea";
59 | this._sendMessageArea.addRow(new GridLayout.ItemSpec(1, "auto"));
60 | this._sendMessageArea.addColumn(new GridLayout.ItemSpec(1, "star"));
61 | this._sendMessageArea.addColumn(new GridLayout.ItemSpec(1, "auto"));
62 | this.addChild(this._sendMessageArea);
63 | GridLayout.GridLayout.setRow(this._sendMessageArea, 1);
64 | this._messageField = new TextField.TextField();
65 | // this._messageField = new TextView.TextView();
66 | this._messageField.className = "nsChatView-messageField";
67 | // this._messageField.returnKeyType = UIEnums.ReturnKeyType.send;
68 | this._messageField.autocorrect = false;
69 | this._messageField.autocapitalizationType = UIEnums.AutocapitalizationType.none;
70 | this._sendMessageArea.addChild(this._messageField);
71 | GridLayout.GridLayout.setRow(this._messageField, 0);
72 | GridLayout.GridLayout.setColumn(this._messageField, 0);
73 | this._messageField.on(TextField.TextField.returnPressEvent, function (eventData) {
74 | me._sendMessageButton
75 | .notify({
76 | eventName: Button.Button.tapEvent,
77 | object: me._sendMessageButton
78 | });
79 | });
80 | this._sendMessageButton = new Button.Button();
81 | this._sendMessageButton.className = "nsChatView-sendMessageButton";
82 | this._sendMessageArea.addChild(this._sendMessageButton);
83 | GridLayout.GridLayout.setRow(this._sendMessageButton, 0);
84 | GridLayout.GridLayout.setColumn(this._sendMessageButton, 1);
85 | this._sendMessageButton.on(Button.Button.tapEvent, function (eventData) {
86 | var chatMsg = me._messageField.text;
87 | if (TypeUtils.isNullOrUndefined(chatMsg) ||
88 | "" === chatMsg.trim()) {
89 | return;
90 | }
91 | me.notify(new SendMessageTappedEventData(me, chatMsg));
92 | });
93 | this.on(ChatView.sendChatMessageButtonTapEvent, function (eventData) {
94 | for (var i = 0; i < me._sendChatMessageButtonTapEventListeners.length; i++) {
95 | var el = me._sendChatMessageButtonTapEventListeners[i];
96 | el(eventData);
97 | }
98 | });
99 | this.typeMessageHint = "Type message...";
100 | this.sendMessageButtonCaption = "SEND";
101 | }
102 | /**
103 | * Appends a list of messages.
104 | *
105 | * @param {IChatMessage} ...msgs One or more messages to append.
106 | */
107 | ChatView.prototype.appendMessages = function () {
108 | var msgs = [];
109 | for (var _i = 0; _i < arguments.length; _i++) {
110 | msgs[_i - 0] = arguments[_i];
111 | }
112 | for (var i = 0; i < msgs.length; i++) {
113 | this._messages.push(msgs[i]);
114 | }
115 | };
116 | /**
117 | * Focus the text field with the chat message to send.
118 | *
119 | * @return {Boolean} Operation was successful or not.
120 | */
121 | ChatView.prototype.focusMessageField = function () {
122 | return this._messageField.focus();
123 | };
124 | /**
125 | * Inserts chat messages at a specific position.
126 | *
127 | * @param {Number} index The zero based index where the messages should be inserted.
128 | * @param {IChatMessage} ...msgs One or more messages to insert.
129 | */
130 | ChatView.prototype.insertMessages = function (index) {
131 | var msgs = [];
132 | for (var _i = 1; _i < arguments.length; _i++) {
133 | msgs[_i - 1] = arguments[_i];
134 | }
135 | for (var i = 0; i < msgs.length; i++) {
136 | this._messages.splice(index + i, 0, msgs[0]);
137 | }
138 | };
139 | Object.defineProperty(ChatView.prototype, "messageField", {
140 | /**
141 | * Gets the input field that stores the chat message that should be send.
142 | */
143 | get: function () {
144 | // public get messageField(): TextView.TextView {
145 | return this._messageField;
146 | },
147 | enumerable: true,
148 | configurable: true
149 | });
150 | Object.defineProperty(ChatView.prototype, "messageList", {
151 | /**
152 | * Gets the list that displays the chat messages.
153 | */
154 | get: function () {
155 | return this._messageList;
156 | },
157 | enumerable: true,
158 | configurable: true
159 | });
160 | Object.defineProperty(ChatView.prototype, "messages", {
161 | /**
162 | * Gets the array of messages.
163 | */
164 | get: function () {
165 | return this._messages;
166 | },
167 | enumerable: true,
168 | configurable: true
169 | });
170 | /**
171 | * Adds an event handler that is invoked when the "SEND" button is clicked.
172 | *
173 | * @param {Function} handler The handler to add.
174 | */
175 | ChatView.prototype.notifyOnSendMessageTap = function (handler) {
176 | this._sendChatMessageButtonTapEventListeners
177 | .push(handler);
178 | };
179 | /**
180 | * Prepends a list of messages.
181 | *
182 | * @param {IChatMessage} ...msgs One or more messages to prepend.
183 | */
184 | ChatView.prototype.prependMessages = function () {
185 | var msgs = [];
186 | for (var _i = 0; _i < arguments.length; _i++) {
187 | msgs[_i - 0] = arguments[_i];
188 | }
189 | for (var i = 0; i < msgs.length; i++) {
190 | this._messages.splice(i, 0, msgs[0]);
191 | }
192 | };
193 | /**
194 | * Resets the value of the chat message field.
195 | */
196 | ChatView.prototype.resetMessage = function () {
197 | this._messageField.text = "";
198 | };
199 | Object.defineProperty(ChatView.prototype, "sendMessageArea", {
200 | /**
201 | * Gets the control that contains the chat message field
202 | * and the "SEND" button.
203 | */
204 | get: function () {
205 | return this._sendMessageArea;
206 | },
207 | enumerable: true,
208 | configurable: true
209 | });
210 | Object.defineProperty(ChatView.prototype, "sendMessageButton", {
211 | /**
212 | * Gets the button that is used to send a chat message.
213 | */
214 | get: function () {
215 | return this._sendMessageButton;
216 | },
217 | enumerable: true,
218 | configurable: true
219 | });
220 | Object.defineProperty(ChatView.prototype, "sendMessageButtonCaption", {
221 | /**
222 | * Gets and sets the caption of the "SEND" button.
223 | */
224 | get: function () {
225 | return this._sendMessageButton.text;
226 | },
227 | set: function (value) {
228 | this._sendMessageButton.text = value;
229 | },
230 | enumerable: true,
231 | configurable: true
232 | });
233 | Object.defineProperty(ChatView.prototype, "typeMessageHint", {
234 | /**
235 | * Gets and sets the hint text for the chat message field.
236 | */
237 | get: function () {
238 | return this._messageField.hint;
239 | },
240 | set: function (value) {
241 | this._messageField.hint = value;
242 | },
243 | enumerable: true,
244 | configurable: true
245 | });
246 | /**
247 | * The name of the event that is raised when the "SEND" button is clicked.
248 | */
249 | ChatView.sendChatMessageButtonTapEvent = "sendChatMessageButtonTap";
250 | return ChatView;
251 | }(GridLayout.GridLayout));
252 | exports.ChatView = ChatView;
253 | /**
254 | * Data for an event that is raised when the "SEND" button is clicked.
255 | */
256 | var SendMessageTappedEventData = (function () {
257 | /**
258 | * Initializes a new instance of that class.
259 | *
260 | * @param {ChatView} view The underlying view.
261 | * @param {String} msg
262 | */
263 | function SendMessageTappedEventData(view, msg) {
264 | this._object = view;
265 | this._message = msg;
266 | }
267 | Object.defineProperty(SendMessageTappedEventData.prototype, "eventName", {
268 | /** @inheritdoc */
269 | get: function () {
270 | return ChatView.sendChatMessageButtonTapEvent;
271 | },
272 | enumerable: true,
273 | configurable: true
274 | });
275 | /**
276 | * Focuses the chat message field.
277 | *
278 | * @return {Boolean} Operation was successful or not.
279 | */
280 | SendMessageTappedEventData.prototype.focusTextField = function () {
281 | return this._object.focusMessageField();
282 | };
283 | Object.defineProperty(SendMessageTappedEventData.prototype, "message", {
284 | /**
285 | * Gets the message to send.
286 | */
287 | get: function () {
288 | return this._message;
289 | },
290 | enumerable: true,
291 | configurable: true
292 | });
293 | Object.defineProperty(SendMessageTappedEventData.prototype, "object", {
294 | /** @inheritdoc */
295 | get: function () {
296 | return this._object;
297 | },
298 | enumerable: true,
299 | configurable: true
300 | });
301 | /**
302 | * Resets the message value.
303 | */
304 | SendMessageTappedEventData.prototype.resetMessage = function () {
305 | this._object.resetMessage();
306 | };
307 | /**
308 | * Scrolls to bottom.
309 | */
310 | SendMessageTappedEventData.prototype.scrollToBottom = function () {
311 | this._object.messageList
312 | .scrollToIndex(this._object.messages.length - 1);
313 | this._object.messageList.refresh();
314 | };
315 | return SendMessageTappedEventData;
316 | }());
317 | exports.SendMessageTappedEventData = SendMessageTappedEventData;
318 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------