Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rfprod/f59d69ae7521c830604a706156348e6a to your computer and use it in GitHub Desktop.
Save rfprod/f59d69ae7521c830604a706156348e6a to your computer and use it in GitHub Desktop.
Messaging App Template [Twitter Bootstrap]
<html >
<body ng-app="msgApp">
<div ng-controller="appCtrl" class="wide" load-data>
<!-- * NAVBAR * -->
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" title="...">
<img class="logo" alt="logo" src="http://s3-us-west-2.amazonaws.com/s.cdpn.io/423527/profile/profile-80_1.jpg"/>
</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right" id="myTab">
<li class="nav-tabs active">
<a href="#index" title="Index." ng-click="activateTab($event)">
<span class="glyphicon glyphicon-comment" aria-hidden="true"></span> <span class="hidden-sm hidden-md hidden-lg">INDEX</span>
</a>
</li>
<li class="nav-tabs">
<a href="#info" title="Contact form." ng-click="activateTab($event)">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <span class="hidden-sm hidden-md hidden-lg">INFO</span>
</a>
</li>
<li class="nav-tabs">
<a href="https://gist.github.com/rfprod/f59d69ae7521c830604a706156348e6a/edit" title="Gist." target=_blank>
<span class="glyphicon glyphicon-download-alt" aria-hidden="true"></span> <span class="hidden-sm hidden-md hidden-lg">GIST</span>
</a>
</li>
<li class="util-info" title="All trademarks and copyrights are property of their respective owners.">
<a class="util-info-internals">&copy; {{currentYear()}}</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- NAVBAR END -->
<div class="tab-content">
<div class="tab-pane active" id="index">
<h1 class="container">{{title}}</h1>
<div id="messages-list" class="col-xs-4 col-sm-4 col-md-4 col-lg-4"></div>
<div id="messages-details" class="col-xs-8 col-sm-8 col-md-8 col-lg-8"></div>
<span us-spinner spinner-key="spinner-1"></span>
<hr/>
<div class="container">
<div class="msg-preview col-xs-12 col-sm-12 col-md-12 col-lg-12" ng-bind-html="markedPreview"></div>
<input id="username" class="wide" type="text" ng-readonly="loading" ng-model="name"/>
<textarea id="messagetext" class="wide" type="text" ng-readonly="loading" ng-model="message"></textarea>
<div class="btn-group-justified">
<a id="send-message" type="button" ng-hide="loading" ng-disabled="loading" class="btn btn-info" send-message>{{buttonText}}</a>
</div>
<div id="output" class="container"></div>
</div>
</div>
<div class="tab-pane" id="info">
<h1 class="container">{{title}}</h1>
<div id="info-details" class="col-xs-12 col-sm-12 col-md-12 col-lg-12" ng-bind-html="infoText"></div>
</div>
</div>
</div>
</body>
</html>

Messaging App Template

AngularJS app uses libraries: jQuery, Bootstrap, AngularJS. User stories: User can select a Conversation, and see messages inside the Conversation in a separate section to the right of Conversations list. User can post a message to the selected Conversation (this information is stored locally and is discarded on the page reload). User can use markdown for message text formatting.

A Pen by V on CodePen.

License.

var app = angular.module('msgApp',['angularSpinner','ngSanitize']);
app.controller('appCtrl', ($scope, $window, usSpinnerService) => {
$scope.title = 'App template';
$scope.name = 'Your **name**';
$scope.message = '*Your* **message**\n####You can use [markdown](https://guides.github.com/features/mastering-markdown/)\nto create rich messages ![image](http://s3-us-west-2.amazonaws.com/s.cdpn.io/423527/profile/profile-80_1.jpg)';
$scope.infoText = marked('This application uses libraries: **jQuery**, **Bootstrap**, **Angular**.\n\n#### User stories:\n* User can select a *Conversation*, and see messages inside the *Conversation* in a separate section to the right of *Conversations* list.\n* User can post a message to the selected *Conversation* (this information is stored locally and is discarded on the page reload).\n* User can use [markdown](https://guides.github.com/features/mastering-markdown/) for message text formatting.');
$scope.$watch('name', () => {
$scope.markedPreview = marked($scope.name+':<br/>'+$scope.message);
});
$scope.$watch('message', () => {
$scope.markedPreview = marked($scope.name+':<br/>'+$scope.message);
});
$scope.markedPreview = marked($scope.name+':<br/>'+$scope.message);
$scope.buttonText = 'Send Message';
$scope.currentYear = () => {
var curYear = (new Date()).getFullYear();
return curYear;
};
$scope.data = [
{id: 1, subject: 'Conversation 1', created: 'xxxx-xx-xx xx:xx',
parts: [
{id: 1, author: 'usr1', text: 'usr1 message1'},
{id: 2, author: 'usr2', text: 'usr2 message1'}
]
},
{id: 2, subject: 'Conversation 2', created: 'xxxx-xx-xx xx:xx',
parts: [
{id: 1, author: 'usr1', text: 'usr1 message1'},
{id: 2, author: 'usr2', text: 'usr2 message1'}
]
}
];
$scope.activateTab = ($event) => {
console.log('activate tab');
console.log($event.currentTarget);
var clickedButton = $event.currentTarget;
var tabButtons = $('#myTab').find('li');
for (var i=0;i<tabButtons.length;i++) tabButtons[i].setAttribute('class','nav-tabs');
clickedButton.parentNode.setAttribute('class','nav-tabs active');
if ($event.currentTarget.getAttribute('href') == '#index') {
$('#index').addClass('active');
$('#info').removeClass('active');
}else{
$('#index').removeClass('active');
$('#info').addClass('active');
}
$('.navbar-toggle').removeClass('collapsed');
$('.navbar-collapse').removeClass('in');
};
$scope.loading = false;
$scope.startSpin = () => {
$scope.$apply(() => {
$scope.loading = true;
});
usSpinnerService.spin('spinner-1');
}
$scope.stopSpin = () => {
$scope.$apply(() => {
$scope.loading = false;
});
usSpinnerService.stop('spinner-1');
}
});
app.directive("loadData", ($compile) => {
return (scope, element, attrs) => {
scope.data.forEach((val,i,arr) => {
if (i==0) {
$('#messages-list').html($compile('<div id="msg-list-item" class="well well-sm" itm="'+i+'" msg-details>'+val.subject+'<br>'+val.created+'</div>')(scope));
}else{
$('#messages-list').append($compile('<div id="msg-list-item" class="well well-sm" itm="'+i+'" msg-details>'+val.subject+'<br>'+val.created+'</div>')(scope));
}
});
}
});
app.directive("msgDetails", ($compile) => {
return (scope, element, attrs) => {
element.bind("click", () => {
scope.startSpin();
var allElements = $('#messages-list').find('div#msg-list-item');
for (var z=0;z<allElements.length;z++){
var elClass = allElements[z].getAttribute('class');
if (elClass.indexOf('selected') != -1) {
allElements[z].setAttribute('class',elClass.substring(0,elClass.length-9));
}
}
element.addClass('selected');
console.log(scope.data[attrs["itm"]]);
var dataobj = scope.data[attrs["itm"]];
var output = '';
dataobj.parts.forEach((val,i,arr) => {
output += '<div id="msg-details" class="well well-sm"><span class="bold">'+marked(val.author)+'</span><hr/>'+marked(val.text)+'</div>';
});
setTimeout(() => {
scope.stopSpin();
$('#messages-details').html($compile(output)(scope));
var msgObj = document.getElementById('messages-details');
msgObj.scrollTop = msgObj.scrollHeight;
},2500);
});
}
});
app.directive("sendMessage", ($compile) => {
return (scope, element, attrs) => {
element.bind("click", () => {
scope.startSpin();
var allElements = $('#messages-list').find('div#msg-list-item');
var counter = 0;
for (var z=0;z<allElements.length;z++){
var elClass = allElements[z].getAttribute('class');
if (elClass.indexOf('selected') != -1) {
console.log(allElements[z].getAttribute('itm'));
var selectedId = parseInt(allElements[z].getAttribute('itm'),10);
var author = $('#username').val();
var text = $('#messagetext').val();
console.log(author+': '+text);
var selectedIdParts = scope.data[selectedId].parts;
var newObj = {id: (selectedIdParts.length+1), author: author, text: text};
selectedIdParts.push(newObj);
console.log(scope.data[selectedId].parts);
var output = '<div id="msg-details" class="well well-sm"><span class="bold">'+marked(author)+'</span><br/>'+marked(text)+'</div>';
setTimeout(() => {
scope.stopSpin();
$('#messages-details').append($compile(output)(scope));
var msgObj = document.getElementById('messages-details');
msgObj.scrollTop = msgObj.scrollHeight;
},1500);
}else counter++;
}
if (counter == allElements.length) {
scope.stopSpin();
alert('You should select a conversation to send a message.');
}
counter = 0;
});
};
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-spinner/0.8.1/angular-spinner.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular-sanitize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
$white: #ffffff
body
.logo
height: 1em
.logo:hover
border-radius: 50%
border: 1px $white dashed
.wide
width: 100%
a:hover
text-decoration: none
.tab-content
padding-top: 50px
#messages-list
max-height: 50vh
overflow-y: hidden
#msg-list-item
font-size: 0.85em
#msg-list-item:hover
background-color: #5bffff
cursor: pointer
.selected
background-color: #5beffe
#messages-details
max-height: 50vh
overflow-y: scroll
#indicator
top: 10vh
left: 50%
bottom: 10vh
.bold
font-weight: bold
#msg-preview
display: block
width: 100%
textarea
resize: vertical
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment