Browse Source

Improved mobile scrollers

master
Igor Zhukov 10 years ago
parent
commit
5880113b70
  1. 74
      app/css/app.css
  2. 60
      app/css/desktop.css
  3. 81
      app/css/mobile.css
  4. 192
      app/js/directives_mobile.js
  5. 104
      app/partials/desktop/head.html
  6. 30
      app/partials/mobile/contacts_modal.html
  7. 26
      app/partials/mobile/country_select_modal.html
  8. 2
      app/partials/mobile/edit_contact_modal.html
  9. 7
      app/partials/mobile/head.html
  10. 64
      app/partials/mobile/im.html
  11. 60
      app/partials/mobile/peer_select.html
  12. 54
      app/partials/mobile/phonebook_modal.html

74
app/css/app.css

@ -231,12 +231,6 @@ input[type="number"] {
line-height: 20px; line-height: 20px;
} }
.navbar-peer-wrap {
display: none;
}
.navbar-toggle-wrap {
display: none;
}
.tg_page_head .navbar-menu .navbar-nav.navbar-right { .tg_page_head .navbar-menu .navbar-nav.navbar-right {
margin-right: 0; margin-right: 0;
} }
@ -825,29 +819,7 @@ a.tg_radio_on:hover i.icon-radio {
} }
.im_dialogs_col .nano > .nano-pane {
background : rgba(0,0,0,0.0);
width : 12px;
right: 0px;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
/*-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;*/
-webkit-transition : none;
-moz-transition : none;
-o-transition : none;
transition : none;
}
.im_dialogs_col .nano > .nano-pane > .nano-slider {
background: #A5B1B9;
margin: 0 5px;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.im_dialogs_panel { .im_dialogs_panel {
padding: 12px 12px 6px; padding: 12px 12px 6px;
@ -1190,7 +1162,10 @@ a.im_dialog_selected .im_dialog_date {
-webkit-perspective: 1000; -webkit-perspective: 1000;
-webkit-backface-visibility: hidden; -webkit-backface-visibility: hidden;
} }
.im_history_to_bottom {
overflow: hidden;
position: relative;
}
.im_history_to_bottom .im_history_scrollable { .im_history_to_bottom .im_history_scrollable {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
@ -1892,10 +1867,6 @@ textarea.im_message_field {
background-position: -10px -36px; background-position: -10px -36px;
opacity: 1; opacity: 1;
} }
.im_head_attach {
display: none;
}
.im_attach_input, .im_attach_input,
.im_media_attach_input { .im_media_attach_input {
cursor: pointer; cursor: pointer;
@ -2358,16 +2329,6 @@ img.chat_modal_participant_photo {
} }
.emoji-menu .nano > .nano-pane {
background : rgba(255,255,255,0.0);
right: -2px;
}
.emoji-menu .nano > .nano-pane > .nano-slider {
background: #d1d1d1;
margin: 0 3px 0 4px;
}
.error_modal_window .modal-dialog { .error_modal_window .modal-dialog {
max-width: 350px; max-width: 350px;
} }
@ -2727,11 +2688,7 @@ a:hover .icon-twitter {
opacity: 1; opacity: 1;
} }
.contacts_modal_col {
margin-right: -17px;
}
.contacts_scrollable_wrap { .contacts_scrollable_wrap {
padding: 0 17px 0 0;
outline: none ! important; outline: none ! important;
} }
.contacts_modal_contacts_empty { .contacts_modal_contacts_empty {
@ -3206,27 +3163,6 @@ ce671b orange
padding: 14px 0; padding: 14px 0;
} }
.countries_modal_col .nano > .nano-pane {
background : rgba(3,36,64,0.08);
width : 3px;
right: 6px;
top: 0;
-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.countries_modal_col .nano > .nano-pane > .nano-slider {
background : rgba(3,46,79,0.22);
margin: 0;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.countries_scrollable_wrap a.countries_modal_country { .countries_scrollable_wrap a.countries_modal_country {
clear: both; clear: both;

60
app/css/desktop.css

@ -54,6 +54,36 @@
opacity : 0.99; opacity : 0.99;
} }
.emoji-menu .nano > .nano-pane {
background : rgba(255,255,255,0.0);
right: -2px;
}
.emoji-menu .nano > .nano-pane > .nano-slider {
background: #d1d1d1;
margin: 0 3px 0 4px;
}
.countries_modal_col .nano > .nano-pane {
background : rgba(3,36,64,0.08);
width : 3px;
right: 6px;
top: 0;
-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.countries_modal_col .nano > .nano-pane > .nano-slider {
background : rgba(3,46,79,0.22);
margin: 0;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.im_page_wrap { .im_page_wrap {
@ -99,6 +129,29 @@
.im_dialogs_scrollable_wrap { .im_dialogs_scrollable_wrap {
padding: 0 19px 0 12px; padding: 0 19px 0 12px;
} }
.im_dialogs_col .nano > .nano-pane {
background : rgba(0,0,0,0.0);
width : 12px;
right: 0px;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
/*-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;*/
-webkit-transition : none;
-moz-transition : none;
-o-transition : none;
transition : none;
}
.im_dialogs_col .nano > .nano-pane > .nano-slider {
background: #A5B1B9;
margin: 0 5px;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.im_history_col_wrap { .im_history_col_wrap {
float: left; float: left;
@ -124,7 +177,6 @@
-o-transition : none; -o-transition : none;
transition : none; transition : none;
} }
.contacts_modal_col .nano > .nano-pane { .contacts_modal_col .nano > .nano-pane {
width: 6px; width: 6px;
right: 7px; right: 7px;
@ -137,6 +189,12 @@
.im_dialogs_modal_col .im_dialogs_scrollable_wrap { .im_dialogs_modal_col .im_dialogs_scrollable_wrap {
padding: 0 12px 0 12px; padding: 0 12px 0 12px;
} }
.contacts_modal_col {
margin-right: -17px;
}
.contacts_scrollable_wrap {
padding: 0 17px 0 0;
}
.im_history_col .nano > .nano-pane { .im_history_col .nano > .nano-pane {
top: 10px; top: 10px;

81
app/css/mobile.css

@ -38,7 +38,7 @@ html {
} }
.tg_page_head .navbar-inverse .navbar-toggle:hover, .tg_page_head .navbar-inverse .navbar-toggle:hover,
.tg_page_head .navbar-inverse .navbar-toggle:active, /*.tg_page_head .navbar-inverse .navbar-toggle:active,*/
.tg_page_head .navbar-inverse .navbar-toggle:focus, .tg_page_head .navbar-inverse .navbar-toggle:focus,
.tg_page_head .navbar-inverse .open .navbar-toggle { .tg_page_head .navbar-inverse .open .navbar-toggle {
background-color: rgba(0,0,0,0.1); background-color: rgba(0,0,0,0.1);
@ -158,8 +158,8 @@ html {
font-size: 13px; font-size: 13px;
height: 46px; height: 46px;
} }
.tg_page_head .navbar-inverse .navbar-quick-nav > li > a:hover, .tg_page_head .navbar-inverse .navbar-quick-nav > li > a:hover/*,
.tg_page_head .navbar-inverse .navbar-quick-nav > li > a:active { .tg_page_head .navbar-inverse .navbar-quick-nav > li > a:active*/ {
background-color: rgba(0,0,0,0.1); background-color: rgba(0,0,0,0.1);
} }
.navbar-quick-nav .icon-back { .navbar-quick-nav .icon-back {
@ -281,6 +281,12 @@ html {
text-align: center; text-align: center;
} }
.mobile_scrollable_wrap {
overflow: hidden;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.login_form_wrap { .login_form_wrap {
border-radius: 0; border-radius: 0;
@ -506,10 +512,10 @@ img.im_message_video_thumb,
.im_send_panel_wrap { .im_send_panel_wrap {
padding: 10px 0 12px; padding: 10px 0 12px;
} }
.im_history_scrollable_wrap {
.im_history_scrollable_wrap.im_history_to_bottom {
overflow: hidden; overflow: hidden;
overflow-y: scroll; position: relative;
-webkit-overflow-scrolling: touch;
} }
.im_history { .im_history {
position: static; position: static;
@ -746,19 +752,6 @@ a.im_message_from_photo {
padding: 5px 0; padding: 5px 0;
margin: 0; margin: 0;
} }
.im_history_col .nano > .nano-pane {
top: 3px;
right: 3px;
width: 6px;
}
.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);
border-radius: 3px;
margin: 0;
}
.im_dialogs_col_wrap { .im_dialogs_col_wrap {
@ -783,9 +776,6 @@ a.im_message_from_photo {
.im_dialogs_col { .im_dialogs_col {
} }
.im_dialogs_scrollable_wrap { .im_dialogs_scrollable_wrap {
overflow: hidden;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
} }
.im_dialogs_panel { .im_dialogs_panel {
@ -1196,58 +1186,17 @@ a.mobile_modal_action .tg_checkbox_label {
padding: 5px; padding: 5px;
} }
.im_head_attach {
display: block;
float: right;
cursor: pointer;
overflow: hidden;
position: relative;
margin: 5px 0 5px 5px;
height: 34px;
border-radius: 4px;
padding: 3px 7px;
border: 1px solid #497495;
}
.navbar_peer_not_selected .im_head_attach {
display: none;
}
.im_head_attach:active {
background-color: rgba(255,255,255,0.1);
}
.im_head_attach .icon-paperclip {
display: inline-block;
width: 21px;
height: 22px;
vertical-align: text-top;
opacity: 0.8;
background: url(../img/icons/MobileIcons_2x.png) 0 -30px no-repeat;
background-size: 21px 52px;
}
.is_1x .im_head_attach .icon-paperclip {
background-image: url(../img/icons/MobileIcons_1x.png);
}
.im_head_attach:active .icon-paperclip {
opacity: 1;
}
.contacts_modal_search { .contacts_modal_search {
padding: 3px 0 12px; padding: 3px 0 12px;
} }
.contacts_modal_col { .contacts_modal_col {
margin-right: -12px; margin: 0 -9px;
}
.contacts_scrollable_wrap {
padding-right: 12px;
}
.contacts_modal_col .nano > .nano-pane {
width: 6px;
right: 5px;
} }
.contacts_modal_members_list a.contacts_modal_contact { .contacts_modal_members_list a.contacts_modal_contact {
padding: 8px 0; padding: 8px 9px;
border-radius: 0; border-radius: 0;
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid #eee;
} }
.contacts_modal_members_list li.contacts_modal_contact_wrap { .contacts_modal_members_list li.contacts_modal_contact_wrap {
margin: 0; margin: 0;

192
app/js/directives_mobile.js

@ -89,7 +89,7 @@ angular.module('myApp.directives')
} }
$(element).css({ $(element).css({
height: $($window).height() - height: $($window).height() -
(headWrap ? headWrap.offsetHeight : 44) - (headWrap ? headWrap.offsetHeight : 46) -
(panelWrap ? panelWrap.offsetHeight : 58) - (panelWrap ? panelWrap.offsetHeight : 58) -
parseInt($(dialogsColWrap).css('paddingBottom') || 0) parseInt($(dialogsColWrap).css('paddingBottom') || 0)
}); });
@ -112,10 +112,8 @@ angular.module('myApp.directives')
function link ($scope, element, attrs) { function link ($scope, element, attrs) {
var historyWrap = $('.im_history_wrap', element)[0], var historyWrap = $('.im_history_wrap', element)[0],
historyMessagesEl = $('.im_history_messages', element)[0], historyMessagesEl = $('.im_history_messages', element)[0],
historyEl = $('.im_history', element)[0],
scrollableWrap = $('.im_history_scrollable_wrap', element)[0], scrollableWrap = $('.im_history_scrollable_wrap', element)[0],
scrollable = $('.im_history_scrollable', element)[0], scrollable = $('.im_history_scrollable', element)[0],
panelWrap = $('.im_history_panel_wrap', element)[0],
bottomPanelWrap = $('.im_bottom_panel_wrap', element)[0], bottomPanelWrap = $('.im_bottom_panel_wrap', element)[0],
sendFormWrap = $('.im_send_form_wrap', element)[0], sendFormWrap = $('.im_send_form_wrap', element)[0],
headWrap = $('.tg_page_head')[0], headWrap = $('.tg_page_head')[0],
@ -127,82 +125,58 @@ angular.module('myApp.directives')
scrollableWrap.scrollTop = scrollableWrap.scrollHeight; scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
}); });
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) { $scope.$on('ui_history_append_new', function (e, options) {
if (!atBottom && !options.my) { if (!atBottom && !options.my) {
return; return;
} }
var curAnimated = animated &&
!$rootScope.idle.isIDLE &&
historyMessagesEl.clientHeight > 0,
wasH;
if (curAnimated) { var pr = parseInt($(scrollableWrap).css('paddingRight'))
wasH = scrollableWrap.scrollHeight; $(scrollableWrap).addClass('im_history_to_bottom');
} else { $(scrollable).css({bottom: 0, marginLeft: -Math.ceil(pr / 2)});
$(scrollable).css({bottom: 0});
$(scrollableWrap).addClass('im_history_to_bottom');
}
onContentLoaded(function () { onContentLoaded(function () {
if (curAnimated) { $(scrollableWrap).removeClass('im_history_to_bottom');
curAnimation = true; $(scrollable).css({bottom: '', marginLeft: ''});
$(historyMessagesEl).removeClass('im_history_appending'); scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
scrollableWrap.scrollTop = scrollableWrap.scrollHeight; updateBottomizer();
$(historyMessagesEl).css(transform, 'translate(0px, ' + (scrollableWrap.scrollHeight - wasH) + 'px)');
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 () { function changeScroll () {
var unreadSplit, focusMessage; var unreadSplit, focusMessage;
// console.trace('change scroll');
if (focusMessage = $('.im_message_focus:visible', scrollableWrap)[0]) { if (focusMessage = $('.im_message_focus:visible', scrollableWrap)[0]) {
scrollableWrap.scrollTop = Math.max(0, focusMessage.offsetTop - Math.floor(scrollableWrap.clientHeight / 2) + 26); var ch = scrollableWrap.clientHeight,
st = scrollableWrap.scrollTop,
ot = focusMessage.offsetTop,
h = focusMessage.clientHeight;
if (!st || st + ch < ot || st > ot + h) {
scrollableWrap.scrollTop = Math.max(0, ot - Math.floor(ch / 2) + 26);
}
atBottom = false; atBottom = false;
} else if (unreadSplit = $('.im_message_unread_split:visible', scrollableWrap)[0]) { } else if (unreadSplit = $('.im_message_unread_split:visible', scrollableWrap)[0]) {
// console.log('change scroll unread', unreadSplit.offsetTop);
scrollableWrap.scrollTop = Math.max(0, unreadSplit.offsetTop - 52); scrollableWrap.scrollTop = Math.max(0, unreadSplit.offsetTop - 52);
atBottom = false; atBottom = false;
} else { } else {
// console.log('change scroll bottom');
scrollableWrap.scrollTop = scrollableWrap.scrollHeight; scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
atBottom = true; atBottom = true;
} }
$timeout(function () { $timeout(function () {
$(scrollableWrap).trigger('scroll'); $(scrollableWrap).trigger('scroll');
scrollTopInitial = scrollableWrap.scrollTop;
}); });
}; };
$scope.$on('ui_history_change', function () { $scope.$on('ui_history_change', function () {
var pr = parseInt($(scrollableWrap).css('paddingRight'))
$(scrollableWrap).addClass('im_history_to_bottom'); $(scrollableWrap).addClass('im_history_to_bottom');
$(scrollable).css({bottom: 0}); $(scrollable).css({bottom: 0, marginLeft: -Math.ceil(pr / 2)});
onContentLoaded(function () { onContentLoaded(function () {
$(scrollableWrap).removeClass('im_history_to_bottom'); $(scrollableWrap).removeClass('im_history_to_bottom');
$(scrollable).css({bottom: ''}); $(scrollable).css({bottom: '', marginLeft: ''});
updateSizes(true); updateSizes(true);
moreNotified = false; moreNotified = false;
lessNotified = false; lessNotified = false;
@ -227,14 +201,18 @@ angular.module('myApp.directives')
pr = parseInt($(scrollableWrap).css('paddingRight')), pr = parseInt($(scrollableWrap).css('paddingRight')),
ch = scrollableWrap.clientHeight; ch = scrollableWrap.clientHeight;
$(scrollable).css({marginBottom: -(sh - st - ch - 4), marginLeft: -Math.ceil(pr / 2)});
$(scrollableWrap).addClass('im_history_to_bottom'); $(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 () { var upd = function () {
$(scrollableWrap).removeClass('im_history_to_bottom'); $(scrollableWrap).removeClass('im_history_to_bottom');
$(scrollable).css({bottom: '', marginLeft: ''}); $(scrollable).css({marginBottom: '', marginLeft: ''});
scrollableWrap.scrollTop = st + scrollableWrap.scrollHeight - sh; if (scrollTopInitial >= 0) {
changeScroll();
} else {
scrollableWrap.scrollTop = st + scrollableWrap.scrollHeight - sh;
}
updateBottomizer(); updateBottomizer();
moreNotified = false; moreNotified = false;
@ -259,6 +237,10 @@ angular.module('myApp.directives')
updateBottomizer(); updateBottomizer();
lessNotified = false; lessNotified = false;
if (scrollTopInitial >= 0) {
changeScroll();
}
$timeout(function () { $timeout(function () {
if (scrollableWrap.scrollHeight != sh) { if (scrollableWrap.scrollHeight != sh) {
$(scrollableWrap).trigger('scroll'); $(scrollableWrap).trigger('scroll');
@ -293,23 +275,26 @@ angular.module('myApp.directives')
$scope.$on('ui_editor_resize', updateSizes); $scope.$on('ui_editor_resize', updateSizes);
$scope.$on('ui_height', function () { $scope.$on('ui_height', function () {
onContentLoaded(updateSizes); onContentLoaded(updateSizes);
// updateSizes();
}); });
var atBottom = true; var atBottom = true,
scrollTopInitial = -1;
$(scrollableWrap).on('scroll', function (e) { $(scrollableWrap).on('scroll', function (e) {
if (!element.is(':visible') || if (!element.is(':visible') ||
$(scrollableWrap).hasClass('im_history_to_bottom') || $(scrollableWrap).hasClass('im_history_to_bottom')) {
curAnimation) {
return; return;
} }
atBottom = scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight; var st = scrollableWrap.scrollTop;
atBottom = st >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight;
if (scrollTopInitial >= 0 && scrollTopInitial != st) {
scrollTopInitial = -1;
}
if (!moreNotified && scrollableWrap.scrollTop <= 300) { if (!moreNotified && st <= 300) {
moreNotified = true; moreNotified = true;
$scope.$emit('history_need_more'); $scope.$emit('history_need_more');
} }
else if (!lessNotified && scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) { else if (!lessNotified && st >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) {
lessNotified = true; lessNotified = true;
$scope.$emit('history_need_less'); $scope.$emit('history_need_less');
} }
@ -328,7 +313,7 @@ angular.module('myApp.directives')
if (!headWrap || !headWrap.offsetHeight) { if (!headWrap || !headWrap.offsetHeight) {
headWrap = $('.tg_page_head')[0]; headWrap = $('.tg_page_head')[0];
} }
var historyH = $($window).height() - panelWrap.offsetHeight - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 44); var historyH = $($window).height() - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 46);
$(historyWrap).css({ $(historyWrap).css({
height: historyH height: historyH
}); });
@ -345,11 +330,11 @@ angular.module('myApp.directives')
} }
function updateBottomizer () { function updateBottomizer () {
return;
$(historyMessagesEl).css({marginTop: 0}); $(historyMessagesEl).css({marginTop: 0});
var marginTop = scrollableWrap.offsetHeight var marginTop = scrollableWrap.offsetHeight
- historyMessagesEl.offsetHeight - historyMessagesEl.offsetHeight
- 20 - 20;
- (Config.Mobile ? 0 : 49);
if (historyMessagesEl.offsetHeight > 0 && marginTop > 0) { if (historyMessagesEl.offsetHeight > 0 && marginTop > 0) {
$(historyMessagesEl).css({marginTop: marginTop}); $(historyMessagesEl).css({marginTop: marginTop});
@ -363,3 +348,86 @@ angular.module('myApp.directives')
} }
}) })
.directive('myContactsListMobile', function($window, $timeout) {
return {
link: link
};
function link ($scope, element, attrs) {
var searchWrap = $('.contacts_modal_search')[0],
panelWrap = $('.contacts_modal_panel')[0];
function updateSizes () {
$(element).css({
height: $($window).height() -
(panelWrap && panelWrap.offsetHeight || 0) -
(searchWrap && searchWrap.offsetHeight || 0) -
64
});
}
$($window).on('resize', updateSizes);
$scope.$on('contacts_change', function () {
onContentLoaded(updateSizes)
});
onContentLoaded(updateSizes);
};
})
.directive('myCountriesListMobile', function($window, $timeout) {
return {
link: link
};
function link ($scope, element, attrs) {
var searchWrap = $('.countries_modal_search')[0],
panelWrap = $('.countries_modal_panel')[0];
function updateSizes () {
$(element).css({
height: $($window).height()
- (panelWrap && panelWrap.offsetHeight || 0)
- (searchWrap && searchWrap.offsetHeight || 0)
- (46 + 18)
});
}
$($window).on('resize', updateSizes);
onContentLoaded(updateSizes);
};
})
.directive('myInfiniteScrollerMobile', function () {
return {
link: link,
scope: true
};
function link($scope, element, attrs) {
var scrollableWrap = element[0],
moreNotified = false;
$(scrollableWrap).on('scroll', function (e) {
if (!element.is(':visible')) return;
if (!moreNotified &&
scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) {
moreNotified = true;
$scope.$apply(function () {
$scope.slice.limit += ($scope.slice.limitDelta || 20);
});
onContentLoaded(function () {
moreNotified = false;
});
}
});
};
})

104
app/partials/desktop/head.html

@ -2,112 +2,8 @@
<div class="navbar navbar-static-top navbar-inverse" role="navigation" ng-class="{navbar_peer_not_selected: !curDialog.peer, navbar_offline: offline, navbar_history_select: historyState.selectActions}"> <div class="navbar navbar-static-top navbar-inverse" role="navigation" ng-class="{navbar_peer_not_selected: !curDialog.peer, navbar_offline: offline, navbar_history_select: historyState.selectActions}">
<div class="container"> <div class="container">
<a class="navbar-peer-wrap" ng-click="showPeerInfo()">
<img
my-load-thumb
watch="true"
thumb="historyPeer.photo"
/>
</a>
<div class="navbar-toggle-wrap dropdown">
<a class="dropdown-toggle navbar-toggle">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<ul ng-if="!curDialog.peer &amp;&amp; isLoggedIn" 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>
<li><a ng-click="logOut()">Log Out</a></li>
</ul>
<ul ng-if="curDialog.peer &amp;&amp; isLoggedIn" class="dropdown-menu">
<li><a ng-click="toggleEdit()">Edit messages</a></li>
<li ng-if="!historyFilter.mediaType" class="divider"></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('photos')">Photos</a></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('video')">Videos</a></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('documents')">Documents</a></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('audio')">Voice notes</a></li>
</ul>
<ul ng-if="!isLoggedIn" class="dropdown-menu">
<li><a href="https://github.com/zhukov/webogram" target="_blank">About</a></li>
</ul>
</div>
<a ng-if="isLoggedIn" class="navbar-search-wrap" ng-click="toggleSearch()">
<i class="icon-search"></i>
</a>
<div class="navbar-header"> <div class="navbar-header">
<a class="navbar-brand" href="{{isLoggedIn ? '#/im' : '#/'}}"><span class="tg_head_logo"></span></a> <a class="navbar-brand" href="{{isLoggedIn ? '#/im' : '#/'}}"><span class="tg_head_logo"></span></a>
<div ng-show="curDialog.peer" ng-switch="curDialog.peer &amp;&amp; historyFilter.mediaType.length > 0">
<ul ng-switch-when="true" class="nav navbar-nav navbar-quick-nav">
<li>
<a ng-click="toggleMedia()" class="navbar-quick-media-back">
<i class="icon icon-back"></i>
<div class="navbar-quick-back-title" ng-switch="historyFilter.mediaType">
<h4 ng-switch-when="photos">Photos</h4>
<h4 ng-switch-when="video">Videos</h4>
<h4 ng-switch-when="documents">Documents</h4>
<h4 ng-switch-when="audio">Voice messages</h4>
</div>
</a>
</li>
</ul>
<div ng-switch-default ng-switch="historyState.selectActions">
<ul ng-switch-when="true" class="nav navbar-navbar navbar-quick-nav navbar-history-edit">
<li class="navbar-quick-right">
<a ng-click="toggleEdit()">Cancel</a>
</li>
<li class="navbar-quick-left">
<a ng-click="selectedFlush()">Clear All</a>
</li>
<li class="navbar-quick-title">Edit</li>
</ul>
<ul ng-switch-default class="nav navbar-nav navbar-quick-nav" ng-switch="historyPeer.id > 0">
<li ng-switch-when="true">
<a href="#/im" class="navbar-quick-profile-back">
<i class="icon icon-back"></i>
<div class="navbar-quick-back-title">
<h4 ng-bind-html="historyPeer.data.rFullName"></h4>
<small ng-switch="historyState.typing.length">
<span ng-switch-when="1" class="status_online">
typing<span my-loading-dots></span>
</span>
<span ng-switch-default my-user-status="historyPeer.id"></span>
</small>
</div>
</a>
</li>
<li ng-switch-default>
<a href="#/im" class="navbar-quick-group-back">
<i class="icon icon-back"></i>
<div class="navbar-quick-back-title">
<h4 ng-bind-html="historyPeer.data.rTitle"></h4>
<small ng-switch="historyState.typing.length">
<ng-pluralize ng-switch-when="0" count="historyPeer.data.participants_count"
when="{'0': 'No members', 'one': '1 member', 'other': '{} members'}">
</ng-pluralize>
<span ng-switch-when="1" class="status_online">
<span my-user-link="historyState.typing[0]" short="true"></span> is typing<span my-loading-dots></span>
</span>
<span ng-switch-when="2" class="status_online">
<span my-user-link="historyState.typing[0]" short="true"></span>, <span my-user-link="historyState.typing[1]" short="true"></span><span my-loading-dots></span>
</span>
<span ng-switch-default class="status_online">
<span my-user-link="historyState.typing[0]" short="true"></span>+{{historyState.typing.length - 1}}<span my-loading-dots></span>
</span>
</small>
</div>
</a>
</li>
</ul>
</div>
</div>
</div> </div>
<div class="navbar-menu" ng-switch="offline"> <div class="navbar-menu" ng-switch="offline">

30
app/partials/mobile/contacts_modal.html

@ -48,30 +48,22 @@
</div> </div>
<div my-contacts-list class="contacts_modal_col"> <div class="contacts_modal_col contacts_wrap contacts_scrollable_wrap mobile_scrollable_wrap" my-contacts-list-mobile my-infinite-scroller-mobile>
<ul class="contacts_modal_members_list nav nav-pills nav-stacked">
<div class="contacts_wrap nano" my-infinite-scroller> <li class="contacts_modal_contact_wrap clearfix" ng-repeat="contact in contacts | orderBy:'user.sortName' | limitTo: slice.limit track by contact.userID" ng-class="{active: selectedContacts[contact.userID], disabled: disabledContacts[contact.userID]}">
<div class="contacts_scrollable_wrap nano-content"> <a class="contacts_modal_contact" ng-click="contactSelect(contact.userID)">
<ul class="contacts_modal_members_list nav nav-pills nav-stacked"> <i ng-if="multiSelect" class="icon icon-contact-tick"></i>
<li class="contacts_modal_contact_wrap clearfix" ng-repeat="contact in contacts | orderBy:'user.sortName' | limitTo: slice.limit track by contact.userID" ng-class="{active: selectedContacts[contact.userID], disabled: disabledContacts[contact.userID]}"> <div class="contacts_modal_contact_photo pull-left" my-user-photolink="contact.userID" status="true" img-class="contacts_modal_contact_photo"></div>
<a class="contacts_modal_contact" ng-click="contactSelect(contact.userID)"> <div class="contacts_modal_contact_name" ng-bind-html="contact.user.rFullName"></div>
<div class="contacts_modal_contact_status" my-user-status="::contact.userID"></div>
<i ng-if="multiSelect" class="icon icon-contact-tick"></i> </a>
</li>
<div class="contacts_modal_contact_photo pull-left" my-user-photolink="contact.userID" status="true" img-class="contacts_modal_contact_photo"></div>
<div class="contacts_modal_contact_name" ng-bind-html="contact.user.rFullName"></div>
<div class="contacts_modal_contact_status" my-user-status="::contact.userID"></div>
</a>
</li>
</ul>
</div>
</div>
</ul>
</div> </div>
</div> </div>

26
app/partials/mobile/country_select_modal.html

@ -30,25 +30,17 @@
<a class="countries_modal_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a> <a class="countries_modal_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div> </div>
<div class="countries_modal_col" my-countries-list> <div class="countries_modal_col countries_wrap countries_scrollable_wrap" my-countries-list-mobile my-infinite-scroller-mobile>
<ul class="countries_modal_members_list nav nav-pills nav-stacked">
<div class="countries_wrap nano" my-infinite-scroller> <li class="countries_modal_country_wrap clearfix" ng-repeat="country in countries | limitTo : slice.limit track by $index">
<div class="countries_scrollable_wrap nano-content"> <a class="countries_modal_country" ng-click="$close(country)">
<span class="countries_modal_country_code pull-right" ng-bind="country.code"></span>
<ul class="countries_modal_members_list nav nav-pills nav-stacked"> <span class="countries_modal_country_name" ng-bind="country.name"></span>
</a>
<li class="countries_modal_country_wrap clearfix" ng-repeat="country in countries | limitTo : slice.limit track by $index"> </li>
<a class="countries_modal_country" ng-click="$close(country)">
<span class="countries_modal_country_code pull-right" ng-bind="country.code"></span>
<span class="countries_modal_country_name" ng-bind="country.name"></span>
</a>
</li>
</ul>
</div>
</div>
</ul>
</div> </div>
</div> </div>

2
app/partials/mobile/edit_contact_modal.html

@ -9,7 +9,7 @@
<h4>Edit contact</h4> <h4>Edit contact</h4>
<div class="form-group"> <div class="form-group">
<span class="form-control uneditable-input disabled" disabled ng-bind="importContact.phone | phoneNumber"></span> <span class="form-control uneditable-input input-sm disabled" disabled ng-bind="importContact.phone | phoneNumber"></span>
</div> </div>
<div class="form-group"> <div class="form-group">
<input class="form-control input-sm" my-focused type="text" placeholder="First name" ng-model="importContact.first_name"/> <input class="form-control input-sm" my-focused type="text" placeholder="First name" ng-model="importContact.first_name"/>

7
app/partials/mobile/head.html

@ -118,13 +118,6 @@
<li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-loading-dots></span></span></li> <li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-loading-dots></span></span></li>
</ul> </ul>
<ul ng-switch-default class="nav navbar-nav navbar-right">
<li ng-if="isLoggedIn &amp;&amp; !isEmpty.contacts"><a href="" ng-click="openContacts()">Contacts</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="openSettings()">Settings</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="logOut()">Log Out</a></li>
<li ng-if="!isLoggedIn"><a href="https://github.com/zhukov/webogram" target="_blank">About</a></li>
</ul>
</div> </div>
</div> </div>

64
app/partials/mobile/im.html

@ -19,7 +19,7 @@
</div> </div>
</div> </div>
<div my-dialogs-list-mobile class="im_dialogs_col im_dialogs_scrollable_wrap"> <div my-dialogs-list-mobile class="im_dialogs_col im_dialogs_scrollable_wrap mobile_scrollable_wrap">
<div class="im_dialogs_empty_wrap" ng-if="isEmpty.contacts"> <div class="im_dialogs_empty_wrap" ng-if="isEmpty.contacts">
<h3 class="im_dialogs_empty_header">No contacts yet</h3> <h3 class="im_dialogs_empty_header">No contacts yet</h3>
@ -65,13 +65,6 @@
</div> </div>
<div class="im_history_col_wrap" ng-controller="AppImHistoryController"> <div class="im_history_col_wrap" ng-controller="AppImHistoryController">
<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>
<div ng-show="!state.notSelected &amp;&amp; !state.loaded" class="im_history_not_selected" my-vertical-position="0.35" padding="true"> <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> Loading history<span my-loading-dots></span>
</div> </div>
@ -79,58 +72,7 @@
<div ng-show="state.loaded"> <div ng-show="state.loaded">
<div my-history-mobile class="im_history_col"> <div my-history-mobile class="im_history_col">
<div class="im_history_panel_wrap"> <div class="im_history_wrap im_history_scrollable_wrap mobile_scrollable_wrap">
<div class="im_history_panel clearfix" ng-controller="AppImPanelController">
<div class="im_history_panel_title">
<a class="im_history_panel_info_link pull-right" ng-click="showPeerInfo()">Info</a>
<a class="im_history_panel_edit_link pull-right" ng-click="toggleEdit()">Edit</a>
<div class="dropdown im_history_panel_media_dropdown pull-right">
<a class="dropdown-toggle">Media<i class="icon icon-caret"></i></a>
<ul class="dropdown-menu">
<li><a ng-click="toggleMedia('photos')">Photos</a></li>
<li><a ng-click="toggleMedia('video')">Videos</a></li>
<li><a ng-click="toggleMedia('documents')">Documents</a></li>
<li><a ng-click="toggleMedia('audio')">Voice messages</a></li>
</ul>
</div>
<a ng-show="historyFilter.mediaType.length || skippedHistory" class="im_history_panel_return_link pull-right" ng-click="returnToRecent()" ng-switch="skippedHistory">
<span ng-switch-when="true">Show recent messages</span>
<span ng-switch-default>Show all messages</span>
<strong class="im_history_panel_return_count" ng-show="missedCount > 0" ng-bind="'+' + missedCount"></strong>
</a>
<div ng-switch="historyFilter.mediaType">
<h4 ng-switch-when="photos">Photos</h4>
<h4 ng-switch-when="video">Videos</h4>
<h4 ng-switch-when="documents">Documents</h4>
<h4 ng-switch-when="audio">Voice messages</h4>
<h4 ng-switch-default ng-switch="historyPeer.id > 0" ng-click="showPeerInfo()">
<div ng-switch-when="true">
<span ng-bind-html="historyPeer.data.rFullName"></span>
<small class="im_peer_online" my-user-status="historyPeer.id"></small>
</div>
<div ng-switch-default>
<span ng-bind-html="historyPeer.data.rTitle"></span>
<small class="im_chat_users">
<ng-pluralize count="historyPeer.data.participants_count"
when="{'0': 'No members', 'one': '1 member', 'other': '{} members'}">
</ng-pluralize>
</small>
</div>
</h4>
</div>
</div>
</div>
</div>
<div class="im_history_wrap im_history_scrollable_wrap">
<div class="im_history_scrollable"> <div class="im_history_scrollable">
<div class="im_history" ng-class="{im_history_selectable: historyState.selectActions}"> <div class="im_history" ng-class="{im_history_selectable: historyState.selectActions}">
@ -140,7 +82,7 @@
</div> </div>
<div class="im_history_messages" ng-class="{im_history_messages_group: historyPeer.id < 0}"> <div class="im_history_messages" ng-class="{im_history_messages_group: historyPeer.id < 0}">
<div ng-show="peerHistory.peerID == historyPeer.id" ng-repeat="peerHistory in peerHistories"> <div class="im_history_messages_peer" ng-show="peerHistory.peerID == historyPeer.id" ng-repeat="peerHistory in peerHistories">
<div class="im_history_message_wrap" my-message ng-repeat="historyMessage in peerHistory.messages"></div> <div class="im_history_message_wrap" my-message ng-repeat="historyMessage in peerHistory.messages"></div>
</div> </div>
</div> </div>

60
app/partials/mobile/peer_select.html

@ -32,41 +32,37 @@
<div class="im_dialogs_modal_col_wrap" ng-controller="AppImDialogsController" my-dialogs> <div class="im_dialogs_modal_col_wrap" ng-controller="AppImDialogsController" my-dialogs>
<div class="im_dialogs_panel"> <div class="im_dialogs_panel">
<div class="im_dialogs_search"> <div class="im_dialogs_search">
<input my-focused class="form-control im_dialogs_search_field" type="search" placeholder="Search" ng-model="search.query"/> <input my-focused 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="search.query = ''" ng-show="search.query.length"></a> <a class="im_dialogs_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div> </div>
</div> </div>
<div my-dialogs-list modal="true" class="im_dialogs_modal_col"> <div my-dialogs-list-mobile modal="true" class="im_dialogs_modal_col im_dialogs_scrollable_wrap mobile_scrollable_wrap">
<div class="im_dialogs_wrap nano"> <ul class="nav nav-pills nav-stacked">
<div class="im_dialogs_scrollable_wrap nano-content"> <li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID"></li>
<ul class="nav nav-pills nav-stacked"> </ul>
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID"></li> <div class="im_dialogs_contacts_wrap" ng-show="contacts.length > 0">
</ul> <h5>Contacts</h5>
<div class="im_dialogs_contacts_wrap" ng-show="contacts.length > 0"> <ul class="nav nav-pills nav-stacked">
<h5>Contacts</h5> <li class="im_dialog_wrap" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID" ng-class="{active: curDialog.peerID == contact.userID}">
<ul class="nav nav-pills nav-stacked"> <a class="im_dialog" ng-click="dialogSelect(contact.peerString)">
<li class="im_dialog_wrap" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID" ng-class="{active: curDialog.peerID == contact.userID}"> <div class="im_dialog_photo pull-left">
<a class="im_dialog" ng-click="dialogSelect(contact.peerString)"> <img
<div class="im_dialog_photo pull-left"> class="im_dialog_photo"
<img my-load-thumb
class="im_dialog_photo" thumb="contact.userPhoto"
my-load-thumb />
thumb="contact.userPhoto" </div>
/> <div class="im_dialog_message_wrap">
</div> <div class="im_dialog_peer">
<div class="im_dialog_message_wrap"> <span class="im_dialog_user" ng-bind-html="contact.user.rFullName"></span>
<div class="im_dialog_peer"> </div>
<span class="im_dialog_user" ng-bind-html="contact.user.rFullName"></span> <div class="im_dialog_message">
</div> <span class="im_dialog_message_text" my-user-status="::contact.userID"></span>
<div class="im_dialog_message"> </div>
<span class="im_dialog_message_text" my-user-status="::contact.userID"></span> </div>
</div> </a>
</div> </li>
</a> </ul>
</li>
</ul>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

54
app/partials/mobile/phonebook_modal.html

@ -37,45 +37,41 @@
</div> </div>
<div my-contacts-list class="contacts_modal_col"> <div class="contacts_modal_col contacts_wrap contacts_scrollable_wrap mobile_scrollable_wrap" my-contacts-list-mobile my-infinite-scroller-mobile>
<div ng-switch="contactsEmpty">
<div class="contacts_wrap nano" my-infinite-scroller> <div ng-switch-when="true" class="contacts_modal_contacts_empty" my-vertical-position="0.2" padding="true">
<div class="contacts_scrollable_wrap nano-content" ng-switch="contactsEmpty"> Your phonebook is empty.
</div>
<div ng-switch-when="true" class="contacts_modal_contacts_empty" my-vertical-position="0.2" padding="true">
Your phonebook is empty.
</div>
<ul ng-switch-default class="contacts_modal_members_list nav nav-pills nav-stacked"> <ul ng-switch-default class="contacts_modal_members_list nav nav-pills nav-stacked">
<li class="contacts_modal_contact_wrap clearfix" ng-repeat="contact in contacts | limitTo: slice.limit track by contact.id" ng-class="{active: selectedContacts[contact.id]}"> <li class="contacts_modal_contact_wrap clearfix" ng-repeat="contact in contacts | limitTo: slice.limit track by contact.id" ng-class="{active: selectedContacts[contact.id]}">
<a class="contacts_modal_contact" ng-click="contactSelect(contact.id)"> <a class="contacts_modal_contact" ng-click="contactSelect(contact.id)">
<i ng-if="multiSelect" class="icon icon-contact-tick"></i> <i ng-if="multiSelect" class="icon icon-contact-tick"></i>
<div class="contacts_modal_contact_photo pull-left"> <div class="contacts_modal_contact_photo pull-left">
<img <img
class="contacts_modal_contact_photo" class="contacts_modal_contact_photo"
ng-src="{{contact.photo}}" ng-src="{{contact.photo}}"
/> />
</div> </div>
<div class="contacts_modal_contact_name"> <div class="contacts_modal_contact_name">
<span ng-bind="contact.first_name"></span> <span ng-bind="contact.first_name"></span>
<span ng-bind="contact.last_name"></span> <span ng-bind="contact.last_name"></span>
</div> </div>
<div class="contacts_modal_contact_status" ng-repeat="phone in contact.phones"> <div class="contacts_modal_contact_status" ng-repeat="phone in contact.phones">
<span ng-bind="phone | phoneNumber"></span> <span ng-bind="phone | phoneNumber"></span>
</div> </div>
</a> </a>
</li> </li>
</ul> </ul>
</div>
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save