diff options
| author | Zaran <zaran.krleza@gmail.com> | 2012-04-24 01:22:27 -0700 |
|---|---|---|
| committer | Zaran <zaran.krleza@gmail.com> | 2012-04-24 01:22:27 -0700 |
| commit | 3fdb17a79de4507e8a4f3fbe47f6c078bdedda46 (patch) | |
| tree | d3ef09b18bad72c2d42f4ade3bc6569dd90ccc64 /alias-angular/app | |
| parent | 58bd41bf1d15e9a8d70c9c9d88ccb39b81fdf8cb (diff) | |
| download | alias-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
Diffstat (limited to 'alias-angular/app')
| -rw-r--r-- | alias-angular/app/css/app.less | 73 | ||||
| -rw-r--r-- | alias-angular/app/index.html | 19 | ||||
| -rw-r--r-- | alias-angular/app/js/controllers.js | 31 | ||||
| -rw-r--r-- | alias-angular/app/js/directives.js | 8 | ||||
| -rw-r--r-- | alias-angular/app/js/filters.js | 15 | ||||
| -rw-r--r-- | alias-angular/app/lib/bootstrap-dropdown.js | 92 |
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 |
