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.
Last active
July 16, 2017 20:32
-
-
Save rfprod/f59d69ae7521c830604a706156348e6a to your computer and use it in GitHub Desktop.
Messaging App Template [Twitter Bootstrap]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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">© {{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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 '; | |
$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; | |
}); | |
}; | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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