├── .gitignore ├── bower.json ├── config.rb ├── gulp ├── server.js ├── styles.js ├── templates.js └── watch.js ├── gulpfile.js ├── icon.png ├── package.json ├── readme.md ├── sample ├── app.js ├── chatTemplate.html ├── chatTemplate.js ├── custom-template.css ├── custom-template.html ├── index.html ├── popup.html └── style.css └── src ├── css ├── components │ ├── chat-bottom-bar.css │ ├── chat-msg-container.css │ ├── chat-msg.css │ ├── chat-top-bar.css │ └── chat-window.css ├── config.css ├── style.css └── themes.css ├── sass ├── components │ ├── chat-bottom-bar.scss │ ├── chat-msg-container.scss │ ├── chat-msg.scss │ ├── chat-top-bar.scss │ └── chat-window.scss ├── config.scss ├── style.scss └── themes.scss ├── scripts ├── index.js └── templates.js └── templates └── chatTemplate.html /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | bower_components 3 | .atomignore 4 | .idea 5 | node_modules -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bootstrap-simple-chat", 3 | "version": "0.4.0", 4 | "authors": [ 5 | "Irontec SL", 6 | "Aitor Llamas Jimenez ", 7 | "Austin Floyd " 8 | ], 9 | "description": "Simple Chat Directive for AngularJS with Bootstrap with infinite scroll", 10 | "moduleType": [ 11 | "globals" 12 | ], 13 | "keywords": [ 14 | "angularjs", 15 | "bootstrap", 16 | "directive", 17 | "chat" 18 | ], 19 | "license": "MIT", 20 | "ignore": [ 21 | "**/.*", 22 | "node_modules", 23 | "bower_components", 24 | "test", 25 | "tests" 26 | ], 27 | "main": [ 28 | "src/scripts/index.js", 29 | "src/css/style.css" 30 | ], 31 | "dependencies": { 32 | "angular": "~1.3.x", 33 | "bootstrap": "~3.3.1", 34 | "lodash": "2.4.x" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | require 'compass/import-once/activate' 2 | # Require any additional compass plugins here. 3 | 4 | # Set this to the root of your project when deployed: 5 | http_path = "/" 6 | css_dir = "src/css" 7 | sass_dir = "src/sass" 8 | images_dir = "src/images" 9 | javascripts_dir = "src/scripts" 10 | 11 | # You can select your preferred output style here (can be overridden via the command line): 12 | # output_style = :expanded or :nested or :compact or :compressed 13 | 14 | # To enable relative paths to assets via compass helper functions. Uncomment: 15 | # relative_assets = true 16 | 17 | # To disable debugging comments that display the original location of your selectors. Uncomment: 18 | # line_comments = false 19 | 20 | 21 | # If you prefer the indented syntax, you might want to regenerate this 22 | # project again passing --syntax sass, or you can uncomment this: 23 | # preferred_syntax = :sass 24 | # and then run: 25 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 26 | -------------------------------------------------------------------------------- /gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var browserSync = require('browser-sync'); 5 | 6 | gulp.task('templates-reload', ['templates'], function() { 7 | browserSync.reload(); 8 | }); 9 | 10 | gulp.task('sass-reload', ['styles'], function() { 11 | browserSync.reload(); 12 | }); 13 | 14 | gulp.task('serve-reload', function() { 15 | browserSync.reload(); 16 | }); 17 | 18 | gulp.task('serve', ['watch'], function () { 19 | browserSync.init({ 20 | startPath: '/index.html', 21 | server: { 22 | baseDir: './sample', 23 | routes: { 24 | '/bower_components': 'bower_components', 25 | '/src': 'src' 26 | } 27 | } 28 | }); 29 | }); -------------------------------------------------------------------------------- /gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var gulpSass = require('gulp-sass'); 5 | var gulpAutoprefixer = require('gulp-autoprefixer'); 6 | 7 | gulp.task('styles', function () { 8 | return gulp.src('./src/sass/**/*.scss') 9 | .pipe(gulpSass({outputStyle: 'expanded'}).on('error', gulpSass.logError)) 10 | .pipe(gulpAutoprefixer({ 11 | browsers: ['last 2 versions'], 12 | cascade: false 13 | })) 14 | .pipe(gulp.dest('./src/css')); 15 | }); -------------------------------------------------------------------------------- /gulp/templates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var gulpTemplateCache = require('gulp-angular-templatecache'); 6 | 7 | gulp.task('templates', function () { 8 | return gulp.src('./src/templates/**/*.html') 9 | .pipe(gulpTemplateCache({ 10 | module: 'irontec.simpleChat' 11 | })) 12 | .pipe(gulp.dest('./src/scripts')); 13 | }); 14 | 15 | gulp.task('custom-template', function () { 16 | return gulp.src('./sample/chatTemplate.html') 17 | .pipe(gulpTemplateCache('chatTemplate.js', { 18 | module: 'irontec.simpleChat' 19 | })) 20 | .pipe(gulp.dest('./sample')); 21 | }); -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | gulp.task('watch', ['styles', 'templates'], function () { 6 | gulp.watch(['./sample/**/*.html'], ['serve-reload']); 7 | gulp.watch(['./src/**/*.js', './sample/**/*.js'], ['serve-reload']); 8 | gulp.watch(['./src/**/*.css', './sample/**/*.css'], ['serve-reload']); 9 | 10 | gulp.watch(['./src/**/*.html'], ['templates-reload']); 11 | gulp.watch(['./src/**/*.scss'], ['sass-reload']); 12 | }); 13 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your gulpfile! 3 | * The gulp tasks are splitted in several files in the gulp directory 4 | * because putting all here was really too long 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var gulp = require('gulp'); 10 | var requireDir = require('require-dir'); 11 | var tasks = requireDir('./gulp'); 12 | 13 | /** 14 | * Default task clean temporaries directories and launch the 15 | * main optimization build task 16 | */ 17 | gulp.task('default', function () { 18 | gulp.start('serve'); 19 | }); 20 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/irontec/angular-bootstrap-simple-chat/0d9500e16b0c205542cb4b69d632f84b44ce590f/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bootstrap-simple-chat", 3 | "version": "0.4.0", 4 | "description": "Simple Chat Directive for AngularJS with Bootstrap with infinite scroll", 5 | "main": "gulpfile.js", 6 | "dependencies": { 7 | }, 8 | "devDependencies": { 9 | "browser-sync": "~2.9.11", 10 | "gulp": "~3.9.0", 11 | "gulp-angular-templatecache": "^1.8.0", 12 | "gulp-autoprefixer": "~3.0.2", 13 | "gulp-sass": "^2.1.1", 14 | "require-dir": "^0.3.0" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/irontec/angular-bootstrap-simple-chat" 19 | }, 20 | "license": "MIT", 21 | "homepage": "https://github.com/irontec/angular-bootstrap-simple-chat" 22 | } 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ```` 2 | 3 | An AngularJS+Bootstrap Simple Chat Directive 4 | 5 | ![AngularJS Chat](https://raw.githubusercontent.com/irontec/angular-bootstrap-simple-chat/master/icon.png "AngularJS Chat") 6 | 7 | # Usage 8 | ## Requirements 9 | 10 | ```json 11 | "dependencies": { 12 | "angularjs": "~1.3.8", 13 | "bootstrap": "~3.3.1", 14 | "angularjs-scroll-glue": "~0.0.1" 15 | } 16 | ``` 17 | ## Installation 18 | ### Install with Bower 19 | ```bash 20 | bower install --save angular-bootstrap-simple-chat 21 | ``` 22 | ### Add the dependencies to your index.html 23 | ```html 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ``` 33 | 34 | ### Load the module in your app 35 | ```javascript 36 | angular.module('app', ['irontec.simpleChat']); 37 | ``` 38 | 39 | ## Using 40 | ```html 41 | /** VIEW **/ 42 | 52 | 53 | ``` 54 | 55 | ```javascript 56 | /** CONTROLLER **/ 57 | angular.module('app').controller('Shell', Shell); 58 | 59 | function Shell() { 60 | 61 | var vm = this; 62 | 63 | vm.messages = [ 64 | { 65 | 'username': 'username1', 66 | 'content': 'Hi!' 67 | }, 68 | { 69 | 'username': 'username2', 70 | 'content': 'Hello!' 71 | }, 72 | { 73 | 'username': 'username2', 74 | 'content': 'Hello!' 75 | }, 76 | { 77 | 'username': 'username2', 78 | 'content': 'Hello!' 79 | }, 80 | { 81 | 'username': 'username2', 82 | 'content': 'Hello!' 83 | }, 84 | { 85 | 'username': 'username2', 86 | 'content': 'Hello!' 87 | } 88 | ]; 89 | 90 | vm.username = 'username1'; 91 | 92 | vm.sendMessage = function(message, username) { 93 | if(message && message !== '' && username) { 94 | vm.messages.push({ 95 | 'username': username, 96 | 'content': message 97 | }); 98 | } 99 | }; 100 | vm.visible = true; 101 | vm.expandOnNew = true; 102 | } 103 | ``` 104 | 105 | ## Documentation 106 | ### Params 107 | * messages: array of messages to show. 108 | Message Format: {username: 'username', content: 'My message'} 109 | * username: username of the user using the app 110 | * input-placeholder-text: String, text in the input placeholder 111 | * title: String, text in the chat top title 112 | * theme: String, theme used for the chat 113 | * submit-function: Function in the controller to be launched on the new message submit. It receives two params: *message & username* 114 | * visible: Boolean, controls visibility on the page (required) 115 | 116 | ## Using themes 117 | * First, add the themes stylesheet to your index.html 118 | 119 | ```html 120 | 121 | ``` 122 | * Define the theme you will use with the theme property 123 | * List of themes: 124 | * irontec 125 | * material 126 | -------------------------------------------------------------------------------- /sample/app.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app', ['irontec.simpleChat']); 5 | 6 | angular.module('app').controller('Shell', Shell); 7 | 8 | function Shell() { 9 | 10 | var vm = this; 11 | 12 | vm.messages = [ 13 | { 14 | 'username': 'Matt', 15 | 'content': 'Hi!' 16 | }, 17 | { 18 | 'username': 'Elisa', 19 | 'content': 'Whats up?' 20 | }, 21 | { 22 | 'username': 'Matt', 23 | 'content': 'I found this nice AngularJS Directive' 24 | }, 25 | { 26 | 'username': 'Elisa', 27 | 'content': 'Looks Great!' 28 | } 29 | ]; 30 | 31 | vm.username = 'Matt'; 32 | 33 | vm.sendMessage = function(message, username) { 34 | if(message && message !== '' && username) { 35 | vm.messages.push({ 36 | 'username': username, 37 | 'content': message 38 | }); 39 | } 40 | }; 41 | 42 | } 43 | 44 | })(); 45 | -------------------------------------------------------------------------------- /sample/chatTemplate.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

{{vm.title}}

7 |
8 |
9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | myUserId:{{vm.myUserId}} 18 | 19 |

{{message.content}}

20 |
21 | {{message.username}}  22 | {{message.date|date:hh:mm:a}} 23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 32 | 33 | 34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | -------------------------------------------------------------------------------- /sample/chatTemplate.js: -------------------------------------------------------------------------------- 1 | angular.module("irontec.simpleChat").run(["$templateCache", function($templateCache) {$templateCache.put("chatTemplate.html","
\r\n
\r\n
\r\n
\r\n
\r\n

{{vm.title}}

\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n myUserId:{{vm.myUserId}}\r\n \r\n

{{message.content}}

\r\n
\r\n {{message.username}} \r\n {{message.date|date:hh:mm:a}}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n");}]); -------------------------------------------------------------------------------- /sample/custom-template.css: -------------------------------------------------------------------------------- 1 | .chat-window { 2 | position: fixed; 3 | right: 0; 4 | bottom: 0; 5 | max-height: 600px; 6 | height: auto; 7 | width: 320px; 8 | } 9 | 10 | 11 | .chat-window.minimized { 12 | height: 40px; 13 | } 14 | 15 | .chat-top-bar { 16 | height: 40px; 17 | } 18 | 19 | .chat-bottom-bar { 20 | height: 60px; 21 | } 22 | 23 | .msg-container-base { 24 | height: auto; 25 | max-height: 500px; 26 | } 27 | 28 | .panel-body { 29 | padding: 0; 30 | } 31 | -------------------------------------------------------------------------------- /sample/custom-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AngularJS+Bootstrap Simple Chat Directive Sample 7 | 8 | 9 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 27 | 28 | 29 | 30 |
31 | 40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AngularJS+Bootstrap Simple Chat Directive Sample 7 | 8 | 9 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 25 | 26 |
27 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /sample/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AngularJS+Bootstrap Simple Chat Directive Sample 7 | 8 | 9 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 30 | 33 | 34 | 35 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /sample/style.css: -------------------------------------------------------------------------------- 1 | html, body{ 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | /* 7 | .my-custom-chat-theme > .chat-window{ 8 | float: right; 9 | } 10 | */ 11 | 12 | .chat-container { 13 | width: 400px; 14 | height: 100%; 15 | margin: 0 auto; 16 | } 17 | -------------------------------------------------------------------------------- /src/css/components/chat-bottom-bar.css: -------------------------------------------------------------------------------- 1 | /* line 3, ../../sass/components/chat-bottom-bar.scss */ 2 | .chat-bottom-bar { 3 | overflow: hidden; 4 | padding: 10px; 5 | position: relative; 6 | height: 70px; 7 | max-height: 70px; 8 | } 9 | /* line 10, ../../sass/components/chat-bottom-bar.scss */ 10 | .chat-bottom-bar .icon-minim { 11 | padding: 2px 10px; 12 | } 13 | /* line 14, ../../sass/components/chat-bottom-bar.scss */ 14 | .chat-bottom-bar input { 15 | height: calc(70px - 30px); 16 | } 17 | -------------------------------------------------------------------------------- /src/css/components/chat-msg-container.css: -------------------------------------------------------------------------------- 1 | /* line 4, ../../sass/components/chat-msg-container.scss */ 2 | .msg-container-base { 3 | background: #e5e5e5; 4 | margin: 0; 5 | height: calc(100% - 140px); 6 | overflow-x: hidden; 7 | padding: 0 10px 10px; 8 | } 9 | /* line 11, ../../sass/components/chat-msg-container.scss */ 10 | .msg-container-base::-webkit-scrollbar-track { 11 | background-color: #f5f5f5; 12 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 13 | } 14 | /* line 16, ../../sass/components/chat-msg-container.scss */ 15 | .msg-container-base::-webkit-scrollbar { 16 | background-color: #f5f5f5; 17 | width: 12px; 18 | } 19 | /* line 21, ../../sass/components/chat-msg-container.scss */ 20 | .msg-container-base::-webkit-scrollbar-thumb { 21 | background-color: #555; 22 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 23 | } 24 | /* line 26, ../../sass/components/chat-msg-container.scss */ 25 | .msg-container-base .msg-container { 26 | display: flex; 27 | overflow: hidden; 28 | padding: 10px; 29 | } 30 | -------------------------------------------------------------------------------- /src/css/components/chat-msg.css: -------------------------------------------------------------------------------- 1 | /* line 2, ../../sass/components/chat-msg.scss */ 2 | .chat-msg { 3 | background: #fff; 4 | border-radius: 2px; 5 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 6 | max-width: 100%; 7 | padding: 10px; 8 | } 9 | /* line 9, ../../sass/components/chat-msg.scss */ 10 | .chat-msg p { 11 | font-size: 13px; 12 | margin: 0 0 .2rem; 13 | } 14 | /* line 14, ../../sass/components/chat-msg.scss */ 15 | .chat-msg time { 16 | color: #ccc; 17 | font-size: 11px; 18 | } 19 | /* line 19, ../../sass/components/chat-msg.scss */ 20 | .chat-msg .chat-msg-author { 21 | display: block; 22 | } 23 | /* line 23, ../../sass/components/chat-msg.scss */ 24 | .chat-msg.chat-msg-receive { 25 | margin-right: 0; 26 | padding-bottom: 20px; 27 | } 28 | /* line 28, ../../sass/components/chat-msg.scss */ 29 | .chat-msg.chat-msg-sent { 30 | margin-right: 0; 31 | padding-bottom: 20px; 32 | } 33 | /* line 32, ../../sass/components/chat-msg.scss */ 34 | .chat-msg.chat-msg-sent .chat-msg-author { 35 | text-align: right; 36 | } 37 | /* line 36, ../../sass/components/chat-msg.scss */ 38 | .chat-msg.chat-msg-sent time { 39 | float: right; 40 | } 41 | -------------------------------------------------------------------------------- /src/css/components/chat-top-bar.css: -------------------------------------------------------------------------------- 1 | /* line 3, ../../sass/components/chat-top-bar.scss */ 2 | .chat-top-bar { 3 | background: #666; 4 | color: #fff; 5 | overflow: hidden; 6 | padding: 10px; 7 | position: relative; 8 | height: 70px; 9 | max-height: 70px; 10 | border-radius: 0; 11 | } 12 | /* line 13, ../../sass/components/chat-top-bar.scss */ 13 | .chat-top-bar .icon-minim { 14 | padding: 2px 10px; 15 | } 16 | -------------------------------------------------------------------------------- /src/css/components/chat-window.css: -------------------------------------------------------------------------------- 1 | /* line 3, ../../sass/components/chat-window.scss */ 2 | .chat-window { 3 | margin: 0; 4 | padding: 0; 5 | width: 100%; 6 | height: 100%; 7 | } 8 | /* line 9, ../../sass/components/chat-window.scss */ 9 | .chat-window .col-xs-12.col-md-12 { 10 | padding: 0; 11 | height: 100%; 12 | } 13 | /* line 13, ../../sass/components/chat-window.scss */ 14 | .chat-window .panel { 15 | border: 0; 16 | border-radius: 5px 5px 0 0; 17 | margin-bottom: 0; 18 | height: 100%; 19 | } 20 | -------------------------------------------------------------------------------- /src/css/config.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/irontec/angular-bootstrap-simple-chat/0d9500e16b0c205542cb4b69d632f84b44ce590f/src/css/config.css -------------------------------------------------------------------------------- /src/css/style.css: -------------------------------------------------------------------------------- 1 | /* line 3, ../sass/components/chat-window.scss */ 2 | .chat-window { 3 | margin: 0; 4 | padding: 0; 5 | width: 100%; 6 | height: 100%; 7 | } 8 | /* line 9, ../sass/components/chat-window.scss */ 9 | .chat-window .col-xs-12.col-md-12 { 10 | padding: 0; 11 | height: 100%; 12 | } 13 | /* line 13, ../sass/components/chat-window.scss */ 14 | .chat-window .panel { 15 | border: 0; 16 | border-radius: 5px 5px 0 0; 17 | margin-bottom: 0; 18 | height: 100%; 19 | } 20 | 21 | /* line 3, ../sass/components/chat-top-bar.scss */ 22 | .chat-top-bar { 23 | background: #666; 24 | color: #fff; 25 | overflow: hidden; 26 | padding: 10px; 27 | position: relative; 28 | height: 70px; 29 | max-height: 70px; 30 | border-radius: 0; 31 | } 32 | /* line 13, ../sass/components/chat-top-bar.scss */ 33 | .chat-top-bar .icon-minim { 34 | padding: 2px 10px; 35 | } 36 | 37 | /* line 3, ../sass/components/chat-bottom-bar.scss */ 38 | .chat-bottom-bar { 39 | overflow: hidden; 40 | padding: 10px; 41 | position: relative; 42 | height: 70px; 43 | max-height: 70px; 44 | } 45 | /* line 10, ../sass/components/chat-bottom-bar.scss */ 46 | .chat-bottom-bar .icon-minim { 47 | padding: 2px 10px; 48 | } 49 | /* line 14, ../sass/components/chat-bottom-bar.scss */ 50 | .chat-bottom-bar input { 51 | height: calc(70px - 30px); 52 | } 53 | 54 | /* line 4, ../sass/components/chat-msg-container.scss */ 55 | .msg-container-base { 56 | background: #e5e5e5; 57 | margin: 0; 58 | height: calc(100% - 140px); 59 | overflow-x: hidden; 60 | padding: 0 10px 10px; 61 | } 62 | /* line 11, ../sass/components/chat-msg-container.scss */ 63 | .msg-container-base::-webkit-scrollbar-track { 64 | background-color: #f5f5f5; 65 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 66 | } 67 | /* line 16, ../sass/components/chat-msg-container.scss */ 68 | .msg-container-base::-webkit-scrollbar { 69 | background-color: #f5f5f5; 70 | width: 12px; 71 | } 72 | /* line 21, ../sass/components/chat-msg-container.scss */ 73 | .msg-container-base::-webkit-scrollbar-thumb { 74 | background-color: #555; 75 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 76 | } 77 | /* line 26, ../sass/components/chat-msg-container.scss */ 78 | .msg-container-base .msg-container { 79 | display: flex; 80 | overflow: hidden; 81 | padding: 10px; 82 | } 83 | 84 | /* line 2, ../sass/components/chat-msg.scss */ 85 | .chat-msg { 86 | background: #fff; 87 | border-radius: 2px; 88 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 89 | max-width: 100%; 90 | padding: 10px; 91 | } 92 | /* line 9, ../sass/components/chat-msg.scss */ 93 | .chat-msg p { 94 | font-size: 13px; 95 | margin: 0 0 .2rem; 96 | } 97 | /* line 14, ../sass/components/chat-msg.scss */ 98 | .chat-msg time { 99 | color: #ccc; 100 | font-size: 11px; 101 | } 102 | /* line 19, ../sass/components/chat-msg.scss */ 103 | .chat-msg .chat-msg-author { 104 | display: block; 105 | } 106 | /* line 23, ../sass/components/chat-msg.scss */ 107 | .chat-msg.chat-msg-receive { 108 | margin-right: 0; 109 | padding-bottom: 20px; 110 | } 111 | /* line 28, ../sass/components/chat-msg.scss */ 112 | .chat-msg.chat-msg-sent { 113 | margin-right: 0; 114 | padding-bottom: 20px; 115 | } 116 | /* line 32, ../sass/components/chat-msg.scss */ 117 | .chat-msg.chat-msg-sent .chat-msg-author { 118 | text-align: right; 119 | } 120 | /* line 36, ../sass/components/chat-msg.scss */ 121 | .chat-msg.chat-msg-sent time { 122 | float: right; 123 | } 124 | -------------------------------------------------------------------------------- /src/css/themes.css: -------------------------------------------------------------------------------- 1 | /* line 11, ../sass/themes.scss */ 2 | .chat-th-irontec .chat-top-bar { 3 | background: #c33; 4 | color: #fff; 5 | } 6 | /* line 17, ../sass/themes.scss */ 7 | .chat-th-irontec .chat-msg-receive .chat-msg-author { 8 | color: #c33; 9 | } 10 | /* line 23, ../sass/themes.scss */ 11 | .chat-th-irontec .chat-input:focus { 12 | border-color: #c33; 13 | box-shadow: 0 1px 1px #fff inset, 0 0 8px #c33; 14 | outline: 0 none; 15 | } 16 | /* line 30, ../sass/themes.scss */ 17 | .chat-th-irontec .chat-submit-button { 18 | background: #c33; 19 | color: #fff; 20 | } 21 | /* line 34, ../sass/themes.scss */ 22 | .chat-th-irontec .chat-submit-button:focus { 23 | border-color: #c33; 24 | outline: 0 none; 25 | } 26 | 27 | /* line 11, ../sass/themes.scss */ 28 | .chat-th-material .chat-top-bar { 29 | background: #009688; 30 | color: #fff; 31 | } 32 | /* line 17, ../sass/themes.scss */ 33 | .chat-th-material .chat-msg-receive .chat-msg-author { 34 | color: #009688; 35 | } 36 | /* line 23, ../sass/themes.scss */ 37 | .chat-th-material .chat-input:focus { 38 | border-color: #009688; 39 | box-shadow: 0 1px 1px #fff inset, 0 0 8px #009688; 40 | outline: 0 none; 41 | } 42 | /* line 30, ../sass/themes.scss */ 43 | .chat-th-material .chat-submit-button { 44 | background: #009688; 45 | color: #fff; 46 | } 47 | /* line 34, ../sass/themes.scss */ 48 | .chat-th-material .chat-submit-button:focus { 49 | border-color: #009688; 50 | outline: 0 none; 51 | } 52 | -------------------------------------------------------------------------------- /src/sass/components/chat-bottom-bar.scss: -------------------------------------------------------------------------------- 1 | @import '../config'; 2 | // Chat Top Bar Class 3 | .chat-bottom-bar { 4 | overflow: hidden; 5 | padding: 10px; 6 | position: relative; 7 | height: $bottom-bar-height; 8 | max-height: $bottom-bar-height; 9 | 10 | .icon-minim { 11 | padding: 2px 10px; 12 | } 13 | 14 | input { 15 | height: calc(#{$bottom-bar-height} - 30px); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/sass/components/chat-msg-container.scss: -------------------------------------------------------------------------------- 1 | @import '../config'; 2 | // Chat Container Class 3 | $chat-container-ignorespace: ($top-bar-height + $bottom-bar-height); 4 | .msg-container-base { 5 | background: #e5e5e5; 6 | margin: 0; 7 | height: calc(100% - #{$chat-container-ignorespace}); 8 | overflow-x: hidden; 9 | padding: 0 10px 10px; 10 | 11 | &::-webkit-scrollbar-track { 12 | background-color: #f5f5f5; 13 | box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 14 | } 15 | 16 | &::-webkit-scrollbar { 17 | background-color: #f5f5f5; 18 | width: 12px; 19 | } 20 | 21 | &::-webkit-scrollbar-thumb { 22 | background-color: #555; 23 | box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 24 | } 25 | 26 | .msg-container { 27 | display: flex; 28 | overflow: hidden; 29 | padding: 10px; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/sass/components/chat-msg.scss: -------------------------------------------------------------------------------- 1 | // Chat Message Class 2 | .chat-msg { 3 | background: #fff; 4 | border-radius: 2px; 5 | box-shadow: 0 1px 2px rgba(0, 0, 0, .2); 6 | max-width: 100%; 7 | padding: 10px; 8 | 9 | p { 10 | font-size: 13px; 11 | margin: 0 0 .2rem; 12 | } 13 | 14 | time { 15 | color: #ccc; 16 | font-size: 11px; 17 | } 18 | 19 | .chat-msg-author { 20 | display: block; 21 | } 22 | 23 | &.chat-msg-receive { 24 | margin-right: 0; 25 | padding-bottom: 20px; 26 | } 27 | 28 | &.chat-msg-sent { 29 | margin-right: 0; 30 | padding-bottom: 20px; 31 | 32 | .chat-msg-author { 33 | text-align: right; 34 | } 35 | 36 | time { 37 | float: right; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/sass/components/chat-top-bar.scss: -------------------------------------------------------------------------------- 1 | @import '../config'; 2 | // Chat Top Bar Class 3 | .chat-top-bar { 4 | background: #666; 5 | color: #fff; 6 | overflow: hidden; 7 | padding: 10px; 8 | position: relative; 9 | height: $top-bar-height; 10 | max-height: $top-bar-height; 11 | border-radius: 0; 12 | 13 | .icon-minim { 14 | padding: 2px 10px; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/sass/components/chat-window.scss: -------------------------------------------------------------------------------- 1 | 2 | // Chat Window Class 3 | .chat-window { 4 | margin: 0; 5 | padding: 0; 6 | width: 100%; 7 | height: 100%; 8 | 9 | .col-xs-12.col-md-12 { 10 | padding: 0; 11 | height: 100%; 12 | } 13 | .panel { 14 | border: 0; 15 | border-radius: 5px 5px 0 0; 16 | margin-bottom: 0; 17 | height: 100%; 18 | } 19 | 20 | &.minimized { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/sass/config.scss: -------------------------------------------------------------------------------- 1 | // Some variables 2 | $top-bar-height: 70px; 3 | $bottom-bar-height: 70px; 4 | -------------------------------------------------------------------------------- /src/sass/style.scss: -------------------------------------------------------------------------------- 1 | 2 | @import 'config'; 3 | 4 | // Main Style File, only imports 5 | @import 'components/chat-window'; 6 | @import 'components/chat-top-bar'; 7 | @import 'components/chat-bottom-bar'; 8 | @import 'components/chat-msg-container'; 9 | @import 'components/chat-msg'; 10 | -------------------------------------------------------------------------------- /src/sass/themes.scss: -------------------------------------------------------------------------------- 1 | $themes: 2 | 'irontec' #c33 #fff, 3 | 'material' #009688 #fff; 4 | 5 | @each $theme in $themes { 6 | $name: nth($theme, 1); 7 | $color: nth($theme, 2); 8 | $forecolor: nth($theme, 3); 9 | 10 | .chat-th-#{$name} { 11 | .chat-top-bar { 12 | background: $color; 13 | color: $forecolor; 14 | } 15 | 16 | .chat-msg-receive { 17 | .chat-msg-author { 18 | color: $color; 19 | } 20 | } 21 | 22 | .chat-input { 23 | &:focus { 24 | border-color: $color; 25 | box-shadow: 0 1px 1px $forecolor inset, 0 0 8px $color; 26 | outline: 0 none; 27 | } 28 | } 29 | 30 | .chat-submit-button { 31 | background: $color; 32 | color: $forecolor; 33 | 34 | &:focus { 35 | border-color: $color; 36 | outline: 0 none; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/scripts/index.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('irontec.simpleChat', []); 5 | angular.module('irontec.simpleChat').directive('irontecSimpleChat', ['$timeout', SimpleChat]); 6 | 7 | function SimpleChat($timeout) { 8 | var directive = { 9 | restrict: 'EA', 10 | templateUrl: 'chatTemplate.html', 11 | replace: true, 12 | scope: { 13 | messages: '=', 14 | username: '=', 15 | myUserId: '=', 16 | inputPlaceholderText: '@', 17 | submitButtonText: '@', 18 | title: '@', 19 | theme: '@', 20 | submitFunction: '&', 21 | visible: '=', 22 | infiniteScroll: '&', 23 | expandOnNew: '=' 24 | }, 25 | link: link, 26 | controller: ChatCtrl, 27 | controllerAs: 'vm' 28 | }; 29 | 30 | function link(scope, element) { 31 | if (!scope.inputPlaceholderText) { 32 | scope.inputPlaceholderText = 'Write your message here...'; 33 | 34 | } 35 | 36 | if (!scope.submitButtonText || scope.submitButtonText === '') { 37 | scope.submitButtonText = 'Send'; 38 | } 39 | 40 | if (!scope.title) { 41 | scope.title = 'Chat'; 42 | } 43 | 44 | scope.$msgContainer = $('.msg-container-base'); // BS angular $el jQuery lite won't work for scrolling 45 | scope.$chatInput = $(element).find('.chat-input'); 46 | 47 | var elWindow = scope.$msgContainer[0]; 48 | scope.$msgContainer.bind('scroll', _.throttle(function() { 49 | var scrollHeight = elWindow.scrollHeight; 50 | if (elWindow.scrollTop <= 10) { 51 | scope.historyLoading = true; // disable jump to bottom 52 | scope.$apply(scope.infiniteScroll); 53 | $timeout(function() { 54 | scope.historyLoading = false; 55 | if (scrollHeight !== elWindow.scrollHeight) // don't scroll down if nothing new added 56 | scope.$msgContainer.scrollTop(360); // scroll down for loading 4 messages 57 | }, 150); 58 | } 59 | }, 300)); 60 | } 61 | 62 | return directive; 63 | } 64 | 65 | ChatCtrl.$inject = ['$scope', '$timeout']; 66 | 67 | function ChatCtrl($scope, $timeout) { 68 | var vm = this; 69 | 70 | vm.isHidden = false; 71 | vm.messages = $scope.messages; 72 | vm.username = $scope.username; 73 | vm.myUserId = $scope.myUserId; 74 | vm.inputPlaceholderText = $scope.inputPlaceholderText; 75 | vm.submitButtonText = $scope.submitButtonText; 76 | vm.title = $scope.title; 77 | vm.theme = 'chat-th-' + $scope.theme; 78 | vm.writingMessage = ''; 79 | vm.panelStyle = {'display': 'block'}; 80 | vm.chatButtonClass= 'fa-angle-double-down icon_minim'; 81 | 82 | vm.toggle = toggle; 83 | vm.close = close; 84 | vm.submitFunction = submitFunction; 85 | 86 | function submitFunction() { 87 | $scope.submitFunction()(vm.writingMessage, vm.username); 88 | vm.writingMessage = ''; 89 | scrollToBottom(); 90 | } 91 | 92 | $scope.$watch('visible', function() { // make sure scroll to bottom on visibility change w/ history items 93 | scrollToBottom(); 94 | $timeout(function() { 95 | $scope.$chatInput.focus(); 96 | }, 250); 97 | }); 98 | $scope.$watch('messages.length', function() { 99 | if (!$scope.historyLoading) scrollToBottom(); // don't scrollToBottom if just loading history 100 | if ($scope.expandOnNew && vm.isHidden) { 101 | toggle(); 102 | } 103 | }); 104 | 105 | function scrollToBottom() { 106 | $timeout(function() { // use $timeout so it runs after digest so new height will be included 107 | $scope.$msgContainer.scrollTop($scope.$msgContainer[0].scrollHeight); 108 | }, 200, false); 109 | } 110 | 111 | function close() { 112 | $scope.visible = false; 113 | } 114 | 115 | function toggle() { 116 | if(vm.isHidden) { 117 | vm.chatButtonClass = 'fa-angle-double-down icon_minim'; 118 | vm.panelStyle = {'display': 'block'}; 119 | vm.isHidden = false; 120 | scrollToBottom(); 121 | } else { 122 | vm.chatButtonClass = 'fa-expand icon_minim'; 123 | vm.panelStyle = {'display': 'none'}; 124 | vm.isHidden = true; 125 | } 126 | } 127 | } 128 | })(); 129 | -------------------------------------------------------------------------------- /src/scripts/templates.js: -------------------------------------------------------------------------------- 1 | angular.module("irontec.simpleChat").run(["$templateCache", function($templateCache) {$templateCache.put("chatTemplate.html","
\r\n
\r\n
\r\n
\r\n
\r\n

{{vm.title}}

\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n myUserId:{{vm.myUserId}}\r\n \r\n

{{message.content}}

\r\n
\r\n {{message.username}} \r\n {{message.date|date:hh:mm:a}}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
");}]); -------------------------------------------------------------------------------- /src/templates/chatTemplate.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

{{vm.title}}

7 |
8 |
9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 | myUserId:{{vm.myUserId}} 18 | 19 |

{{message.content}}

20 |
21 | {{message.username}}  22 | {{message.date|date:hh:mm:a}} 23 |
24 |
25 |
26 |
27 |
28 | 38 |
39 |
40 |
--------------------------------------------------------------------------------