Browse Source

Supported dialogs scrolling

master
Igor Zhukov 10 years ago
parent
commit
cb6aaad417
  1. 100
      app/css/app.css
  2. 153
      app/css/desktop.css
  3. 23
      app/css/mobile.css
  4. 1
      app/index.html
  5. 381
      app/js/directives_mobile.js
  6. 2
      app/js/init.js
  7. 2
      app/js/lib/utils.js
  8. 109
      app/partials/mobile/im.html
  9. 55
      app/vendor/jquery.nanoscroller/nanoscroller.css
  10. 2
      app/webogram.appcache

100
app/css/app.css

@ -799,48 +799,7 @@ a.tg_radio_on:hover i.icon-radio { @@ -799,48 +799,7 @@ a.tg_radio_on:hover i.icon-radio {
.im_page_wrap {
background: #FFF;
max-width: 1000px;
min-width: 300px;
margin: 0 auto;
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 0 0 3px 3px;
overflow: hidden;
}
.im_page_footer {
font-size: 11px;
text-align: center;
color: #9cacb9;
line-height: 40px;
}
.im_page_footer_brand {
color: #9cacb9;
font-weight: bold;
}
.im_page_footer_brand:hover,
.im_page_footer_brand:active {
color: #8499aa;
text-decoration: none;
}
.im_dialogs_col_wrap {
float: left;
width: 31%;
border-right: 2px solid #E9EBED;
padding-bottom: 10px;
}
.im_history_col_wrap {
float: left;
width: 69%;
}
/* Dialogs list */
@ -861,10 +820,6 @@ a.tg_radio_on:hover i.icon-radio { @@ -861,10 +820,6 @@ a.tg_radio_on:hover i.icon-radio {
margin-top: 10px;
}
.im_dialogs_col {
margin-right: -7px;
}
.im_dialogs_col .nano > .nano-pane {
background : rgba(0,0,0,0.0);
@ -984,11 +939,7 @@ a.tg_radio_on:hover i.icon-radio { @@ -984,11 +939,7 @@ a.tg_radio_on:hover i.icon-radio {
.im_dialogs_wrap {
}
.im_dialogs_scrollable_wrap {
padding: 0 19px 0 12px;
outline: none ! important;
}
.im_dialogs_scrollable_wrap .im_dialog_wrap {
@ -1127,57 +1078,6 @@ a.im_dialog_selected .im_dialog_date { @@ -1127,57 +1078,6 @@ a.im_dialog_selected .im_dialog_date {
/* IM history */
.im_history_col {
}
.im_history_col .nano > .nano-pane,
.contacts_modal_col .nano > .nano-pane,
.im_dialogs_modal_col .nano > .nano-pane {
background : rgba(3,36,64,0.08);
width : 9px;
right: 0;
top: 0;
/*-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;*/
-moz-border-radius : 2px;
-webkit-border-radius : 2px;
border-radius : 2px;
-webkit-transition : none;
-moz-transition : none;
-o-transition : none;
transition : none;
}
.contacts_modal_col .nano > .nano-pane {
width: 6px;
right: 7px;
}
.im_dialogs_modal_col .nano > .nano-pane {
width: 6px;
right: 2px;
}
.im_dialogs_modal_col .im_dialogs_scrollable_wrap {
padding: 0 12px 0 12px;
}
.im_history_col .nano > .nano-pane {
top: 10px;
right: 8px;
}
.im_history_col .nano > .nano-pane > .nano-slider,
.contacts_modal_col .nano > .nano-pane > .nano-slider,
.im_dialogs_modal_col .nano > .nano-pane > .nano-slider {
background : rgba(3,46,79,0.22);
margin: 0;
-moz-border-radius : 2px;
-webkit-border-radius : 2px;
border-radius : 2px;
}
.im_history_panel_wrap {
margin: 0 23px 0 15px;
cursor: pointer;

153
app/css/desktop.css

@ -0,0 +1,153 @@ @@ -0,0 +1,153 @@
/** initial setup **/
.nano {
position : relative;
width : 100%;
height : 100%;
overflow : hidden;
}
.nano > .nano-content {
position : absolute;
overflow : scroll;
overflow-x : hidden;
top : 0;
right : 0;
bottom : 0;
left : 0;
}
.nano > .nano-content:focus {
outline: thin dotted;
}
.nano > .nano-content::-webkit-scrollbar {
display: none;
}
.has-scrollbar > .nano-content::-webkit-scrollbar {
display: block;
}
.nano > .nano-pane {
background : rgba(0,0,0,.25);
position : absolute;
width : 10px;
right : 0;
top : 0;
bottom : 0;
visibility : hidden\9; /* Target only IE7 and IE8 with this hack */
opacity : .01;
-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;
-moz-border-radius : 5px;
-webkit-border-radius : 5px;
border-radius : 5px;
}
.nano > .nano-pane > .nano-slider {
background: #444;
background: rgba(0,0,0,.5);
position : relative;
margin : 0 1px;
-moz-border-radius : 3px;
-webkit-border-radius : 3px;
border-radius : 3px;
}
.nano:hover > .nano-pane, .nano-pane.active, .nano-pane.flashed {
visibility : visible\9; /* Target only IE7 and IE8 with this hack */
opacity : 0.99;
}
.im_page_wrap {
background: #FFF;
max-width: 1000px;
min-width: 300px;
margin: 0 auto;
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 0 0 3px 3px;
overflow: hidden;
}
.im_page_footer {
font-size: 11px;
text-align: center;
color: #9cacb9;
line-height: 40px;
}
.im_page_footer_brand {
color: #9cacb9;
font-weight: bold;
}
.im_page_footer_brand:hover,
.im_page_footer_brand:active {
color: #8499aa;
text-decoration: none;
}
.im_dialogs_col {
margin-right: -7px;
}
.im_dialogs_col_wrap {
float: left;
width: 31%;
border-right: 2px solid #E9EBED;
padding-bottom: 10px;
}
.im_dialogs_scrollable_wrap {
padding: 0 19px 0 12px;
}
.im_history_col_wrap {
float: left;
width: 69%;
}
.im_history_col .nano > .nano-pane,
.contacts_modal_col .nano > .nano-pane,
.im_dialogs_modal_col .nano > .nano-pane {
background : rgba(3,36,64,0.08);
width : 9px;
right: 0;
top: 0;
/*-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;*/
-moz-border-radius : 2px;
-webkit-border-radius : 2px;
border-radius : 2px;
-webkit-transition : none;
-moz-transition : none;
-o-transition : none;
transition : none;
}
.contacts_modal_col .nano > .nano-pane {
width: 6px;
right: 7px;
}
.im_dialogs_modal_col .nano > .nano-pane {
width: 6px;
right: 2px;
}
.im_dialogs_modal_col .im_dialogs_scrollable_wrap {
padding: 0 12px 0 12px;
}
.im_history_col .nano > .nano-pane {
top: 10px;
right: 8px;
}
.im_history_col .nano > .nano-pane > .nano-slider,
.contacts_modal_col .nano > .nano-pane > .nano-slider,
.im_dialogs_modal_col .nano > .nano-pane > .nano-slider {
background : rgba(3,46,79,0.22);
margin: 0;
-moz-border-radius : 2px;
-webkit-border-radius : 2px;
border-radius : 2px;
}

23
app/css/mobile.css

@ -775,16 +775,11 @@ a.im_message_from_photo { @@ -775,16 +775,11 @@ a.im_message_from_photo {
display: block;
}
.im_dialogs_col {
margin-right: 0;
}
.im_page_peer_not_selected .im_dialogs_col_wrap .nano-pane {
width: 6px;
right: 3px;
}
.im_page_peer_not_selected .im_dialogs_col_wrap .nano-pane > .nano-slider {
background : rgba(3,46,79,0.22);
border-radius: 3px;
margin: 0;
.im_dialogs_scrollable_wrap {
overflow: hidden;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.im_dialogs_panel {
@ -801,14 +796,10 @@ a.im_message_from_photo { @@ -801,14 +796,10 @@ a.im_message_from_photo {
.im_page_split .im_dialogs_search {
margin-right: 0;
}
.im_dialogs_modal_col .im_dialogs_scrollable_wrap,
.im_dialogs_scrollable_wrap {
padding: 0;
}
.im_dialogs_scrollable_wrap a.im_dialog {
border-bottom: 1px solid #d4d4d4;
border-top: 1px solid #d4d4d4;
border-bottom: 1px solid #eee;
border-top: 1px solid #eee;
margin-top: -1px;
border-radius: 0 !important;
padding-right: 11px;
@ -914,7 +905,7 @@ a.im_message_fwd_author { @@ -914,7 +905,7 @@ a.im_message_fwd_author {
.im_dialogs_scrollable_wrap .active a.im_dialog:hover,
.im_dialogs_scrollable_wrap .active a.im_dialog_selected {
border-radius: 0;
background-color: #f0f0f0;
background-color: #f4f4f4;
}

1
app/index.html

@ -73,6 +73,7 @@ @@ -73,6 +73,7 @@
PRODUCTION_ONLY_END-->
<script type="text/javascript" src="js/directives.js"></script>
<script type="text/javascript" src="js/directives_mobile.js"></script>
<!-- endbuild -->
</body>

381
app/js/directives_mobile.js

@ -0,0 +1,381 @@ @@ -0,0 +1,381 @@
/*!
* Webogram v0.3.0 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
'use strict';
/* Directives */
angular.module('myApp.directives')
.directive('myDialogsListMobile', function($window, $timeout) {
return {
link: link
};
function link ($scope, element, attrs) {
var dialogsColWrap = $('.im_dialogs_col_wrap')[0],
scrollableWrap = element[0],
headWrap = $('.tg_page_head')[0],
panelWrapSelector = attrs.modal
? '.mobile_modal_body .im_dialogs_panel'
: '.im_dialogs_panel',
panelWrap = $(panelWrapSelector)[0],
hasTabs = false,
moreNotified = false;
$scope.$on('ui_dialogs_tabs', function (e, newHasTabs) {
hasTabs = newHasTabs;
updateSizes();
});
$scope.$on('ui_dialogs_search', updateSizes);
$scope.$on('ui_dialogs_update', updateSizes);
$scope.$on('ui_dialogs_append', function () {
onContentLoaded(function () {
moreNotified = false;
$timeout(function () {
$(scrollableWrap).trigger('scroll');
});
});
});
$scope.$on('ui_dialogs_change', function () {
onContentLoaded(function () {
moreNotified = false;
$timeout(function () {
$(scrollableWrap).trigger('scroll');
});
});
});
$(scrollableWrap).on('scroll', function (e) {
if (!element.is(':visible')) return;
if (!moreNotified && scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) {
$scope.$emit('dialogs_need_more');
moreNotified = true;
}
});
function updateSizes () {
if (!panelWrap || !panelWrap.offsetHeight) {
panelWrap = $(panelWrapSelector)[0];
}
if (attrs.modal) {
$(element).css({
height: $($window).height() -
(panelWrap ? panelWrap.offsetHeight : 58) - 46
});
return;
}
if (!headWrap || !headWrap.offsetHeight) {
headWrap = $('.tg_page_head')[0];
}
if (!dialogsColWrap || !dialogsColWrap.offsetHeight) {
dialogsColWrap = $('.im_dialogs_col_wrap')[0];
}
$(element).css({
height: $($window).height() -
(headWrap ? headWrap.offsetHeight : 44) -
(panelWrap ? panelWrap.offsetHeight : 58) -
parseInt($(dialogsColWrap).css('paddingBottom') || 0)
});
}
$($window).on('resize', updateSizes);
updateSizes();
setTimeout(updateSizes, 1000);
};
})
.directive('myHistoryMobile', function ($window, $timeout, $rootScope, $transition) {
return {
link: link
};
function link ($scope, element, attrs) {
var historyWrap = $('.im_history_wrap', element)[0],
historyMessagesEl = $('.im_history_messages', element)[0],
historyEl = $('.im_history', element)[0],
scrollableWrap = $('.im_history_scrollable_wrap', element)[0],
scrollable = $('.im_history_scrollable', element)[0],
panelWrap = $('.im_history_panel_wrap', element)[0],
bottomPanelWrap = $('.im_bottom_panel_wrap', element)[0],
sendFormWrap = $('.im_send_form_wrap', element)[0],
headWrap = $('.tg_page_head')[0],
sendForm = $('.im_send_form', element)[0],
moreNotified = false,
lessNotified = false;
onContentLoaded(function () {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
});
$(historyWrap).nanoScroller({preventPageScrolling: true, tabIndex: -1, iOSNativeScrolling: true});
var updateScroller = function (delay) {
// console.trace('scroller update', delay);
$timeout(function () {
if (!$(scrollableWrap).hasClass('im_history_to_bottom')) {
$(historyWrap).nanoScroller();
}
}, delay || 0);
}
var transform = false,
trs = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'],
i;
for (i = 0; i < trs.length; i++) {
if (trs[i] in historyMessagesEl.style) {
transform = trs[i];
break;
}
}
var animated = transform ? true : false,
curAnimation = false;
$scope.$on('ui_history_append_new', function (e, options) {
if (!atBottom && !options.my) {
return;
}
var curAnimated = animated &&
!$rootScope.idle.isIDLE &&
historyMessagesEl.clientHeight > 0,
wasH;
if (curAnimated) {
wasH = scrollableWrap.scrollHeight;
} else {
$(scrollable).css({bottom: 0});
$(scrollableWrap).addClass('im_history_to_bottom');
}
onContentLoaded(function () {
if (curAnimated) {
curAnimation = true;
$(historyMessagesEl).removeClass('im_history_appending');
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
$(historyMessagesEl).css(transform, 'translate(0px, ' + (scrollableWrap.scrollHeight - wasH) + 'px)');
$(historyWrap).nanoScroller();
var styles = {};
styles[transform] = 'translate(0px, 0px)';
$(historyMessagesEl).addClass('im_history_appending');
$transition($(historyMessagesEl), styles).then(function () {
curAnimation = false;
$(historyMessagesEl).removeClass('im_history_appending');
updateBottomizer();
});
} else {
$(scrollableWrap).removeClass('im_history_to_bottom');
$(scrollable).css({bottom: ''});
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
updateBottomizer();
}
});
});
function changeScroll () {
var unreadSplit, focusMessage;
if (focusMessage = $('.im_message_focus', scrollableWrap)[0]) {
scrollableWrap.scrollTop = Math.max(0, focusMessage.offsetTop - Math.floor(scrollableWrap.clientHeight / 2) + 26);
atBottom = false;
} else if (unreadSplit = $('.im_message_unread_split', scrollableWrap)[0]) {
scrollableWrap.scrollTop = Math.max(0, unreadSplit.offsetTop - 52);
atBottom = false;
} else {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
atBottom = true;
}
updateScroller();
$timeout(function () {
$(scrollableWrap).trigger('scroll');
});
};
$scope.$on('ui_history_change', function () {
$(scrollableWrap).addClass('im_history_to_bottom');
$(scrollable).css({bottom: 0});
onContentLoaded(function () {
$(scrollableWrap).removeClass('im_history_to_bottom');
$(scrollable).css({bottom: ''});
updateSizes(true);
moreNotified = false;
lessNotified = false;
changeScroll();
});
});
$scope.$on('ui_history_change_scroll', function () {
onContentLoaded(changeScroll)
});
$scope.$on('ui_history_focus', function () {
if (!atBottom) {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
updateScroller();
atBottom = true;
}
});
$scope.$on('ui_history_prepend', function () {
var sh = scrollableWrap.scrollHeight,
st = scrollableWrap.scrollTop,
pr = parseInt($(scrollableWrap).css('paddingRight')),
ch = scrollableWrap.clientHeight;
$(scrollableWrap).addClass('im_history_to_bottom');
scrollableWrap.scrollHeight; // Some strange Chrome bug workaround
$(scrollable).css({bottom: -(sh - st - ch), marginLeft: -Math.ceil(pr / 2)});
var upd = function () {
$(scrollableWrap).removeClass('im_history_to_bottom');
$(scrollable).css({bottom: '', marginLeft: ''});
scrollableWrap.scrollTop = st + scrollableWrap.scrollHeight - sh;
updateBottomizer();
moreNotified = false;
$timeout(function () {
if (scrollableWrap.scrollHeight != sh) {
$(scrollableWrap).trigger('scroll');
}
});
clearTimeout(timer);
unreg();
},
timer = setTimeout(upd, 0),
unreg = $scope.$on('$viewContentLoaded', upd);
});
$scope.$on('ui_history_append', function () {
var sh = scrollableWrap.scrollHeight;
onContentLoaded(function () {
atBottom = false;
updateBottomizer();
lessNotified = false;
$timeout(function () {
if (scrollableWrap.scrollHeight != sh) {
$(scrollableWrap).trigger('scroll');
}
});
});
});
$scope.$on('ui_panel_update', function () {
onContentLoaded(function () {
updateSizes();
$scope.$broadcast('ui_message_send');
$timeout(function () {
$(scrollableWrap).trigger('scroll');
});
});
});
$scope.$on('ui_selection_clear', function () {
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
} else if (document.selection) { // IE?
document.selection.empty();
}
});
$scope.$on('ui_editor_resize', updateSizes);
$scope.$on('ui_height', function () {
onContentLoaded(updateSizes);
// updateSizes();
});
var atBottom = true;
$(scrollableWrap).on('scroll', function (e) {
if (!element.is(':visible') ||
$(scrollableWrap).hasClass('im_history_to_bottom') ||
curAnimation) {
return;
}
atBottom = scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight;
if (!moreNotified && scrollableWrap.scrollTop <= 300) {
moreNotified = true;
$scope.$emit('history_need_more');
}
else if (!lessNotified && scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) {
lessNotified = true;
$scope.$emit('history_need_less');
}
});
function updateSizes (heightOnly) {
if (!element.is(':visible') && !$(element[0].parentNode.parentNode).is(':visible')) {
return;
}
if ($(sendFormWrap).is(':visible')) {
$(sendFormWrap).css({
height: $(sendForm).height()
});
}
if (!headWrap || !headWrap.offsetHeight) {
headWrap = $('.tg_page_head')[0];
}
var historyH = $($window).height() - panelWrap.offsetHeight - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 44);
$(historyWrap).css({
height: historyH
});
updateBottomizer();
if (heightOnly === true) return;
if (atBottom) {
onContentLoaded(function () {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
updateScroller();
});
}
updateScroller(100);
}
function updateBottomizer () {
$(historyMessagesEl).css({marginTop: 0});
var marginTop = scrollableWrap.offsetHeight
- historyMessagesEl.offsetHeight
- 20
- (Config.Mobile ? 0 : 49);
if (historyMessagesEl.offsetHeight > 0 && marginTop > 0) {
$(historyMessagesEl).css({marginTop: marginTop});
}
$(historyWrap).nanoScroller();
}
$($window).on('resize', updateSizes);
updateSizes();
onContentLoaded(updateSizes);
}
})

2
app/js/init.js

@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
switch (layout) {
case 'mobile': Config.Mobile = true; break;
case 'desktop': Config.Mobile = false; break;
default: Config.Mobile = Config.Mobile; break;
default: Config.Mobile = Config.Navigator.mobile; break;
}
$('head').append(

2
app/js/lib/utils.js

@ -136,6 +136,6 @@ if (!Function.prototype.bind) { @@ -136,6 +136,6 @@ if (!Function.prototype.bind) {
}
function templateUrl (tplName) {
return 'partials/' + (Config.Navigator.mobile ? 'mobile' : 'desktop') + '/' + tplName + '.html';
return 'partials/' + (Config.Mobile ? 'mobile' : 'desktop') + '/' + tplName + '.html';
}

109
app/partials/mobile/im.html

@ -4,21 +4,8 @@ @@ -4,21 +4,8 @@
<div class="im_page_split clearfix">
<div class="im_dialogs_col_wrap" ng-controller="AppImDialogsController" my-dialogs has-tabs="{{search.query.length > 0}}">
<div ng-controller="AppImDialogsController" my-dialogs has-tabs="{{search.query.length > 0}}" class="im_dialogs_col_wrap">
<div class="im_dialogs_panel">
<div class="dropdown im_dialogs_panel_dropdown pull-right">
<a class="dropdown-toggle">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<ul class="dropdown-menu">
<li><a ng-click="openGroup()">New Group</a></li>
<li><a ng-click="importContact()">New Contact</a></li>
<li><a ng-click="openContacts()">Contacts</a></li>
<li><a ng-click="openSettings()">Settings</a></li>
</ul>
</div>
<div class="im_dialogs_search">
<input class="form-control im_dialogs_search_field no_outline" type="search" placeholder="Search" ng-model="search.query"/>
<a class="im_dialogs_search_clear" ng-click="searchClear()" ng-show="search.query.length"></a>
@ -32,73 +19,65 @@ @@ -32,73 +19,65 @@
</div>
</div>
<div my-dialogs-list class="im_dialogs_col">
<div class="im_dialogs_wrap nano">
<div class="im_dialogs_scrollable_wrap nano-content">
<div class="im_dialogs_empty_wrap" ng-if="isEmpty.contacts">
<h3 class="im_dialogs_empty_header">No contacts yet</h3>
<p class="im_dialogs_empty_lead">Get started by adding a contact to chat with</p>
<button type="button" class="btn btn-primary btn-sm" ng-click="importContact()">Add contact</button>
<button ng-if="phonebookAvailable" type="button" class="btn btn-primary btn-sm im_dialogs_import_phonebook" ng-click="importPhonebook()">Import phonebook</button>
</div>
<div my-dialogs-list-mobile class="im_dialogs_col im_dialogs_scrollable_wrap">
<div ng-switch="search.messages">
<ul ng-switch-when="true" class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.id" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li>
</ul>
<ul ng-switch-default class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li>
</ul>
</div>
<div class="im_dialogs_empty_wrap" ng-if="isEmpty.contacts">
<h3 class="im_dialogs_empty_header">No contacts yet</h3>
<p class="im_dialogs_empty_lead">Get started by adding a contact to chat with</p>
<button type="button" class="btn btn-primary btn-sm" ng-click="importContact()">Add contact</button>
<button ng-if="phonebookAvailable" type="button" class="btn btn-primary btn-sm im_dialogs_import_phonebook" ng-click="importPhonebook()">Import phonebook</button>
</div>
<div class="im_dialogs_contacts_wrap" ng-show="!search.messages &amp;&amp; contacts.length > 0">
<h5>Contacts</h5>
<ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID" ng-class="{active: curDialog.peerID == contact.userID}">
<a class="im_dialog" ng-click="dialogSelect(contact.peerString)">
<div class="im_dialog_photo pull-left">
<img
class="im_dialog_photo"
my-load-thumb
thumb="contact.userPhoto"
/>
</div>
<div class="im_dialog_message_wrap">
<div class="im_dialog_peer">
<span class="im_dialog_user" ng-bind-html="contact.user.rFullName"></span>
</div>
<div class="im_dialog_message">
<span class="im_dialog_message_text" my-user-status="::contact.userID"></span>
</div>
</div>
</a>
</li>
</ul>
</div>
<div ng-switch="search.messages">
<ul ng-switch-when="true" class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.id" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li>
</ul>
<ul ng-switch-default class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li>
</ul>
</div>
</div>
<div class="im_dialogs_contacts_wrap" ng-show="!search.messages &amp;&amp; contacts.length > 0">
<h5>Contacts</h5>
<ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID" ng-class="{active: curDialog.peerID == contact.userID}">
<a class="im_dialog" ng-click="dialogSelect(contact.peerString)">
<div class="im_dialog_photo pull-left">
<img
class="im_dialog_photo"
my-load-thumb
thumb="contact.userPhoto"
/>
</div>
<div class="im_dialog_message_wrap">
<div class="im_dialog_peer">
<span class="im_dialog_user" ng-bind-html="contact.user.rFullName"></span>
</div>
<div class="im_dialog_message">
<span class="im_dialog_message_text" my-user-status="::contact.userID"></span>
</div>
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="im_history_col_wrap" ng-controller="AppImHistoryController">
<div ng-show="state.notSelected" ng-switch="isEmpty.contacts &amp;&amp; isEmpty.dialogs">
<div ng-switch-when="true" class="im_history_no_dialogs_wrap">
<div ng-show="state.notSelected">
<div class="im_history_no_dialogs_wrap">
<h3 class="im_dialogs_empty_header">Get started</h3>
<p class="im_dialogs_empty_lead">Welcome to Telegram Web. You can always set your profile photo and change your name in Settings.</p>
<button type="button" class="btn btn-primary btn-sm" ng-click="openSettings()">Open Settings</button>
</div>
<div ng-switch-default class="im_history_not_selected" my-vertical-position="0.35" padding="true">
Please select a chat to start messaging
</div>
</div>
<div ng-show="!state.notSelected &amp;&amp; !state.loaded" class="im_history_not_selected" my-vertical-position="0.35" padding="true">
Loading history<span my-loading-dots></span>
</div>
<div ng-show="state.loaded">
<div my-history class="im_history_col">
<div my-history-mobile class="im_history_col">
<div class="im_history_panel_wrap">
@ -271,8 +250,4 @@ @@ -271,8 +250,4 @@
</div>
<div class="im_page_footer">
<a class="im_page_footer_brand" target="_blank" href="https://github.com/zhukov/webogram">Telegram beta</a> by izhukov &amp; toberg
</div>
<div id="notify_sound"></div>

55
app/vendor/jquery.nanoscroller/nanoscroller.css vendored

@ -1,55 +0,0 @@ @@ -1,55 +0,0 @@
/** initial setup **/
.nano {
position : relative;
width : 100%;
height : 100%;
overflow : hidden;
}
.nano > .nano-content {
position : absolute;
overflow : scroll;
overflow-x : hidden;
top : 0;
right : 0;
bottom : 0;
left : 0;
}
.nano > .nano-content:focus {
outline: thin dotted;
}
.nano > .nano-content::-webkit-scrollbar {
display: none;
}
.has-scrollbar > .nano-content::-webkit-scrollbar {
display: block;
}
.nano > .nano-pane {
background : rgba(0,0,0,.25);
position : absolute;
width : 10px;
right : 0;
top : 0;
bottom : 0;
visibility : hidden\9; /* Target only IE7 and IE8 with this hack */
opacity : .01;
-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;
-moz-border-radius : 5px;
-webkit-border-radius : 5px;
border-radius : 5px;
}
.nano > .nano-pane > .nano-slider {
background: #444;
background: rgba(0,0,0,.5);
position : relative;
margin : 0 1px;
-moz-border-radius : 3px;
-webkit-border-radius : 3px;
border-radius : 3px;
}
.nano:hover > .nano-pane, .nano-pane.active, .nano-pane.flashed {
visibility : visible\9; /* Target only IE7 and IE8 with this hack */
opacity : 0.99;
}

2
app/webogram.appcache

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
CACHE MANIFEST
# 30
# 31
NETWORK:
*

Loading…
Cancel
Save