aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZaran <zaran.krleza@gmail.com>2012-04-24 01:22:27 -0700
committerZaran <zaran.krleza@gmail.com>2012-04-24 01:22:27 -0700
commit3fdb17a79de4507e8a4f3fbe47f6c078bdedda46 (patch)
treed3ef09b18bad72c2d42f4ade3bc6569dd90ccc64
parent58bd41bf1d15e9a8d70c9c9d88ccb39b81fdf8cb (diff)
downloadalias-3fdb17a79de4507e8a4f3fbe47f6c078bdedda46.tar.gz
User availibility status improvements
* store the status of users as received in the presence stanzas * new filter to convert a status as defined in rfc3921 to something readable (could be used to display contacts' status in a tooltip) * encapsulate bootsrap's dropdown plugin in the dropdown-toggle directive (adding the dropdown-toggle directive to a tag calls Bootstrap's dropdown initializer on this tag at compile time * allow the user to change his status via a dropdown button. This works, but angular complains that $apply is already in progress when you try to change your status
-rw-r--r--alias-angular/app/css/app.less73
-rw-r--r--alias-angular/app/index.html19
-rw-r--r--alias-angular/app/js/controllers.js31
-rw-r--r--alias-angular/app/js/directives.js8
-rw-r--r--alias-angular/app/js/filters.js15
-rw-r--r--alias-angular/app/lib/bootstrap-dropdown.js92
6 files changed, 197 insertions, 41 deletions
diff --git a/alias-angular/app/css/app.less b/alias-angular/app/css/app.less
index e78e124..c79c56a 100644
--- a/alias-angular/app/css/app.less
+++ b/alias-angular/app/css/app.less
@@ -7,6 +7,23 @@ html, body{
height: 100%;
}
+.chat{
+ color: #3D9940;
+}
+
+.away{
+ color: #D9B232;
+}
+
+.dnd{
+ color: #D9B232;
+}
+
+.xa{
+ color: #D9B232;
+}
+
+
#roster{
min-height: 100%;
float: left;
@@ -14,39 +31,31 @@ html, body{
background-color: @background-gray;
border: 1px solid @border-gray;
- ul{
+ ul.contact-list{
list-style: none;
padding: 0;
margin: 0;
- }
-
- li{
- background-color: white;
- border-bottom: 1px solid @border-gray;
- padding: 0;
- margin: 0;
- padding: 1em 1em;
- color: #363636;
- .transition(0.3s);
-
- &:hover{
- background-color: @background-gray;
- }
-
- &:first-child{
- border-top: 1px solid @border-gray;
- }
-
- i{
- font-size:120%;
- }
-
- .online{
- color: #3D9940;
- }
- .away{
- color: #D9B232;
+ li{
+ background-color: white;
+ border-bottom: 1px solid @border-gray;
+ padding: 0;
+ margin: 0;
+ padding: 1em 1em;
+ color: #363636;
+ .transition(0.3s);
+
+ &:hover{
+ background-color: @background-gray;
+ }
+
+ &:first-child{
+ border-top: 1px solid @border-gray;
+ }
+
+ i{
+ font-size:120%;
+ }
}
}
}
@@ -65,4 +74,8 @@ html, body{
#main{
float: left;
margin-left: 20px;
-} \ No newline at end of file
+}
+
+ul.nav-tabs li a{
+ outline: 0;
+}
diff --git a/alias-angular/app/index.html b/alias-angular/app/index.html
index fba5335..466a02a 100644
--- a/alias-angular/app/index.html
+++ b/alias-angular/app/index.html
@@ -23,6 +23,22 @@
<div id="roster" ng-controller="RosterCtl">
<form id="rostersearch" class="form-horizontal">
+ <div class="btn-toolbar">
+ <div class="btn-group">
+ <a class="btn">
+ <i class='{{self["status"]}} icon-user'></i> {{self["jid"]}}
+ </a>
+ <a class="btn dropdown-toggle" data-toggle="dropdown" dropdown-toggle="toto" href="#">
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu">
+ <li><a ng-click='status("chat")'><i class="chat icon-user"></i> Online</a></li>
+ <li><a ng-click='status("away")'><i class="away icon-user"></i> Away</a></li>
+ <li><a ng-click='status("dnd")'><i class="dnd icon-user"></i> Do Not Disturb</a></li>
+ <li><a ng-click='status("xa")'><i class="xa icon-user"></i> Extended Away</a></li>
+ </ul>
+ </div>
+ </div>
<div class="input-prepend">
<span class="add-on"><i class="icon-search"></i></span><!--
--><input class="span2" type="text" placeholder="Search" ng-model="query"/>
@@ -31,7 +47,7 @@
<input type="checkbox" ng-model="checkoffline" id="show"/> Show offline contacts
</label>
</form>
- <ul>
+ <ul class="contact-list">
<li ng-repeat="contact in get_contacts() | showoffline:checkoffline | rosterFilter:query|orderBy:'status'" ng-click="chatWith(contact)">
<i ng-class="contact.status" class="icon-user"></i> {{contact.name||contact.jid}}</li>
</ul>
@@ -48,6 +64,7 @@
</div>
</div>
<script src="lib/jquery-1.7.2.min.js"></script>
+ <script src="lib/bootstrap-dropdown.js"></script>
<script src="lib/angular/angular.js"></script>
<script src="lib/underscore-min.js"></script>
<script src="lib/config.js"></script>
diff --git a/alias-angular/app/js/controllers.js b/alias-angular/app/js/controllers.js
index 909754e..33feb0d 100644
--- a/alias-angular/app/js/controllers.js
+++ b/alias-angular/app/js/controllers.js
@@ -2,7 +2,9 @@
/* App Controllers */
function ConnectCtl($scope, StropheSrv, $log, $rootScope) {
- $rootScope.username = $scope.username;
+ $rootScope.self = {jid: "",
+ status: 'offline'
+ };
$rootScope.is_connected = function () {
return $rootScope.status == Strophe.Status.CONNECTED;
};
@@ -28,6 +30,7 @@ function ConnectCtl($scope, StropheSrv, $log, $rootScope) {
};
$scope.login = function () {
StropheSrv.login($scope.username, $scope.password, connect_callback);
+ $rootScope.self["jid"] = $scope.username;
};
$scope.disconnect = function() {
StropheSrv.disconnect();
@@ -41,6 +44,7 @@ function RosterCtl($scope, StropheSrv, $log, $rootScope) {
$scope.get_contacts = function() {
return _.toArray($scope.contacts);
};
+
function onRoster(iq) {
var elems = iq.getElementsByTagName('query');
var query = elems[0];
@@ -52,6 +56,7 @@ function RosterCtl($scope, StropheSrv, $log, $rootScope) {
});
//make sure the roster is populated before sending presence request
StropheSrv.send($pres());
+ $rootScope.self["status"] = "chat";
};
function onPresence(presence) {
@@ -60,17 +65,16 @@ function RosterCtl($scope, StropheSrv, $log, $rootScope) {
var type = $(presence).attr('type');
// if (jid in $scope.contacts) {
if(_.has($scope.contacts, jid)){
+ var contact = $scope.contacts[jid];
if (type !== 'error') {
if (type === 'unavailable') {
- $log.log(jid +' is offline');
- $scope.contacts[jid]['status'] = 'offline';
- }else{
- var show = $(presence).find('show').text();
- if (show === '') {
- $scope.contacts[jid]['status'] = 'online';
- }else{
- $log.log(jid +' is away');
- $scope.contacts[jid]['status'] = 'away';
+ contact['status'] = 'offline';
+ } else {
+ var show = $(presence).find('show');
+ if (show.length) {
+ contact['status'] = show.text();
+ } else {
+ contact['status'] = 'chat';
}
}
}
@@ -90,6 +94,13 @@ function RosterCtl($scope, StropheSrv, $log, $rootScope) {
$scope.chatWith = function(contact) {
$rootScope.$broadcast('msgrequest', contact.name||contact.jid);
};
+
+ $scope.status = function(status) {
+ var pres = $pres().c("show",{},status);
+ StropheSrv.send(pres);
+ $rootScope.self["status"] = status;
+ };
+
}
RosterCtl.$inject = ['$scope','StropheSrv','$log', '$rootScope'];
diff --git a/alias-angular/app/js/directives.js b/alias-angular/app/js/directives.js
index 3b9b652..cb7e70d 100644
--- a/alias-angular/app/js/directives.js
+++ b/alias-angular/app/js/directives.js
@@ -28,4 +28,12 @@ angular.module('Alias.directives', []).
}
};
return directiveDefinition;
+ }).directive('dropdownToggle', function($log) {
+ var directiveDefinition = {
+ restrict: 'A',
+ link: function(scope, elm, attrs) {
+ elm.dropdown();
+ }
+ };
+ return directiveDefinition;
});
diff --git a/alias-angular/app/js/filters.js b/alias-angular/app/js/filters.js
index 772e523..70bd074 100644
--- a/alias-angular/app/js/filters.js
+++ b/alias-angular/app/js/filters.js
@@ -25,4 +25,19 @@ angular.module('Alias.filters', []).
});
};
};
+ }).filter('formatStatus',function() {
+ return function(status) {
+ switch(status) {
+ case "chat":
+ return "Online";
+ case "away":
+ return "Away";
+ case "xa":
+ return "Extended Away";
+ case "dnd":
+ return "Do Not Disturb";
+ case "offline":
+ return "Offline";
+ }
+ };
}); \ No newline at end of file
diff --git a/alias-angular/app/lib/bootstrap-dropdown.js b/alias-angular/app/lib/bootstrap-dropdown.js
new file mode 100644
index 0000000..54b61c5
--- /dev/null
+++ b/alias-angular/app/lib/bootstrap-dropdown.js
@@ -0,0 +1,92 @@
+/* ============================================================
+ * bootstrap-dropdown.js v2.0.2
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* DROPDOWN CLASS DEFINITION
+ * ========================= */
+
+ var toggle = '[data-toggle="dropdown"]'
+ , Dropdown = function ( element ) {
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
+ $('html').on('click.dropdown.data-api', function () {
+ $el.parent().removeClass('open')
+ })
+ }
+
+ Dropdown.prototype = {
+
+ constructor: Dropdown
+
+ , toggle: function ( e ) {
+ var $this = $(this)
+ , selector = $this.attr('data-target')
+ , $parent
+ , isActive
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+ $parent.length || ($parent = $this.parent())
+
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+ !isActive && $parent.toggleClass('open')
+
+ return false
+ }
+
+ }
+
+ function clearMenus() {
+ $(toggle).parent().removeClass('open')
+ }
+
+
+ /* DROPDOWN PLUGIN DEFINITION
+ * ========================== */
+
+ $.fn.dropdown = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('dropdown')
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
+ * =================================== */
+
+ $(function () {
+ $('html').on('click.dropdown.data-api', clearMenus)
+ $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ })
+
+}( window.jQuery ); \ No newline at end of file