diff --git a/app/css/app.css b/app/css/app.css index 8c2c7204..779290de 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -580,7 +580,7 @@ a.im_dialog:hover .im_dialog_message_text { margin-left: 5px; } .im_history_panel_info_link { - /*color: #999;*/ + color: #999; font-size: 13px; font-weight: normal; padding-top: 5px; @@ -1000,9 +1000,14 @@ textarea.im_message_field { vertical-align: text-top; background: url(../img/icons/Attach_2x.png) 0 0 no-repeat; background-size: 19px 22px; + opacity: 0.6; } .im_attach:hover .icon-paperclip { + opacity: 1; +} +.im_attach:active .icon-paperclip { background-image: url(../img/icons/Attach_pressed_2x.png); + opacity: 1; } .im_emoji_btn { @@ -1021,9 +1026,15 @@ textarea.im_message_field { vertical-align: text-top; background: url(../img/icons/Smile_2x.png) 0 0 no-repeat; background-size: 22px 22px; + opacity: 0.6; } .im_emoji_btn:hover .icon-emoji { + opacity: 1; +} +.im_emoji_btn:active .icon-emoji, +.im_emoji_btn.on .icon-emoji { background-image: url(../img/icons/Smile_pressed_2x.png); + opacity: 1; } .im_attach_input { @@ -1184,10 +1195,14 @@ img.img_fullsize { /* Emoji area */ -.emoji-wysiwyg-editor:empty:before{ - content:attr(placeholder); +.emoji-wysiwyg-editor:empty:before { + content: attr(placeholder); color: #9aa2ab; } +.emoji-wysiwyg-editor:active:before, +.emoji-wysiwyg-editor:focus:before { + content: '' !important; +} .emoji-wysiwyg-editor { font-size: 12px; @@ -1215,15 +1230,16 @@ img.img_fullsize { position: absolute; z-index: 999; width: 180px; + margin-left: -90px; + margin-top: -232px; + overflow: hidden; +} +.emoji-items-wrap1 { + background: rgba(0,0,0, 0.65); padding: 5px 2px 5px 5px; - margin-left: -88px; - margin-top: -225px; - -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; - background: rgba(0,0,0, 0.7); - overflow: hidden; } .emoji-menu .emoji-items-wrap { position: relative; @@ -1259,6 +1275,14 @@ img.img_fullsize { display: none; } +.emoji-menu-tail { + background: url(../img/icons/Arrow_2x.png) 0 0 no-repeat; + background-size: 14px 7px; + width: 14px; + height: 7px; + margin: 0 83px; +} + .emoji-menu .nano > .pane { background : rgba(255,255,255,.0); diff --git a/app/index.html b/app/index.html index f0e25997..71fb1b76 100644 --- a/app/index.html +++ b/app/index.html @@ -7,7 +7,7 @@ - + @@ -34,13 +34,13 @@ - + - + @@ -51,11 +51,11 @@ - - - + + + - + diff --git a/app/js/app.js b/app/js/app.js index ce633664..11fb238c 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -50,7 +50,7 @@ config(['$locationProvider', '$routeProvider', '$compileProvider', function($loc // $locationProvider.html5Mode(true); $routeProvider.when('/', {templateUrl: 'partials/welcome.html?1', controller: 'AppWelcomeController'}); $routeProvider.when('/login', {templateUrl: 'partials/login.html?2', controller: 'AppLoginController'}); - $routeProvider.when('/im', {templateUrl: 'partials/im.html?3', controller: 'AppIMController', reloadOnSearch: false}); + $routeProvider.when('/im', {templateUrl: 'partials/im.html?4', controller: 'AppIMController', reloadOnSearch: false}); $routeProvider.otherwise({redirectTo: '/'}); }]); diff --git a/app/js/controllers.js b/app/js/controllers.js index bb677d8e..0b685d82 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -59,7 +59,6 @@ angular.module('myApp.controllers', []) $scope.error = {}; }, function (error) { - console.log(error); $scope.progress.enabled = false; console.log('sendCode error', error); switch (error.type) { @@ -125,6 +124,15 @@ angular.module('myApp.controllers', []) $scope.$on('$routeUpdate', updateCurDialog); + $scope.$on('history_focus', function (e, peerData) { + if (peerData.peerString == $scope.curDialog.peer) { + $scope.$broadcast('ui_history_focus'); + } else { + $location.url('/im?p=' + peerData.peerString); + } + }); + + $scope.isLoggedIn = true; $scope.logOut = function () { MtpApiManager.logOut().then(function () { @@ -354,7 +362,7 @@ angular.module('myApp.controllers', []) // console.trace(); $scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID)); $scope.typing = {}; - $scope.$broadcast('ui_history_append'); + $scope.$broadcast('ui_history_append', {my: addedMessage.my}); offset++; // console.log('append check', $rootScope.idle.isIDLE, addedMessage.peerID, $scope.curDialog.peerID); @@ -382,7 +390,7 @@ angular.module('myApp.controllers', []) break; case 'updateChatUserTyping': - if (-update.chat_id == $scope.curDialog.peerID) { + if (-update.chat_id == $scope.curDialog.peerID && AppUsersManager.hasUser(update.user_id)) { $scope.typing = {user: AppUsersManager.getUser(update.user_id)}; $timeout.cancel(typingTimeouts[update.user_id]); @@ -420,6 +428,8 @@ angular.module('myApp.controllers', []) var lastTyping = false; $scope.$watch('draftMessage.text', function (newVal) { + // console.log('ctrl text changed', newVal); + // console.trace('ctrl text changed', newVal); AppMessagesManager.readHistory($scope.curDialog.inputPeer); if (newVal.length) { @@ -457,7 +467,7 @@ angular.module('myApp.controllers', []) return false; } - text = text.replace(/:\s*(.+?)\s*:/g, function (all, name) { + text = text.replace(/:([a-z0-9\-_]+?):/gi, function (all, name) { var utfChar = $.emojiarea.reverseIcons[name]; if (utfChar !== undefined) { return utfChar; @@ -485,6 +495,7 @@ angular.module('myApp.controllers', []) } else { // console.log('Reset peer'); $scope.draftMessage.text = ''; + $scope.$broadcast('ui_peer_draft'); } } @@ -509,11 +520,11 @@ angular.module('myApp.controllers', []) $scope.video = AppVideoManager.wrapForFull($scope.videoID); }) - .controller('UserModalController', function ($scope, $location, AppUsersManager) { + .controller('UserModalController', function ($scope, $location, $rootScope, $modalStack, AppUsersManager) { $scope.user = AppUsersManager.wrapForFull($scope.userID); $scope.goToHistory = function () { - $scope.$close(); - $location.url('/im?p=' + $scope.user.peerString); + $modalStack.dismissAll(); + $rootScope.$broadcast('history_focus', {peerString: $scope.user.peerString}); }; }) diff --git a/app/js/directives.js b/app/js/directives.js index 16b8b19f..49bb55e6 100644 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -16,7 +16,7 @@ angular.module('myApp.directives', ['myApp.filters']) restrict: 'AE', scope: true, translude: false, - templateUrl: 'partials/dialog.html?3' + templateUrl: 'partials/dialog.html?4' }; }) @@ -25,7 +25,7 @@ angular.module('myApp.directives', ['myApp.filters']) restrict: 'AE', scope: true, translude: false, - templateUrl: 'partials/message.html?4' + templateUrl: 'partials/message.html?5' }; }) @@ -124,8 +124,8 @@ angular.module('myApp.directives', ['myApp.filters']) var animated = true, curAnimation = false; - scope.$on('ui_history_append', function () { - if (!atBottom) { + scope.$on('ui_history_append', function (e, options) { + if (!atBottom && !options.my) { return; } if (animated) { @@ -143,8 +143,8 @@ angular.module('myApp.directives', ['myApp.filters']) }, { duration: 200, always: function () { - curAnimation = false; updateScroller(); + curAnimation = false; } }); updateScroller(); @@ -171,6 +171,13 @@ angular.module('myApp.directives', ['myApp.filters']) }); }); + 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, @@ -264,6 +271,11 @@ angular.module('myApp.directives', ['myApp.filters']) $(fileSelect).on('change', function () { scope.$apply(function () { scope.draftMessage.files = Array.prototype.slice.call(fileSelect.files); + setTimeout(function () { + try { + fileSelect.value = ''; + } catch (e) {}; + }, 1000); }); }); @@ -287,6 +299,7 @@ angular.module('myApp.directives', ['myApp.filters']) if (richTextarea) { scope.$watch('draftMessage.text', function (newVal) { + // console.log('dir text change', newVal); if (!newVal.length && !messageField.value.length) { $timeout(function () { updateField(); @@ -296,12 +309,15 @@ angular.module('myApp.directives', ['myApp.filters']) } function updateField () { - $(richTextarea).text(scope.draftMessage.text || ''); + var html = $('
').text(scope.draftMessage.text || '').html(); + html = html.replace(/\n/g, '
'); + $(richTextarea).html(html) } $('body').on('dragenter dragleave dragover drop', onDragDropEvent); scope.$on('ui_peer_change', focusField); + scope.$on('ui_history_focus', focusField); scope.$on('ui_history_change', focusField); scope.$on('ui_message_send', focusField); scope.$on('ui_peer_draft', updateField); diff --git a/app/js/services.js b/app/js/services.js index 1fd6ca42..97f6cb5e 100644 --- a/app/js/services.js +++ b/app/js/services.js @@ -46,19 +46,14 @@ angular.module('myApp.services', []) var deferred = $q.defer(); - // console.log('get', keys); chrome.storage.local.get(keys, function (resultObj) { - // console.log('got', resultObj); result = []; angular.forEach(keys, function (key) { var value = resultObj[key]; - // console.log('p1', key, value); value = value === undefined || value === null ? false : JSON.parse(value); - // console.log('p2', value); result.push(cache[key] = value); }); - // console.log('got parsed', result); deferred.resolve(single ? result[0] : result); }); @@ -711,7 +706,7 @@ angular.module('myApp.services', []) saveMessages([message]); historyStorage.pending.unshift(messageID); - $rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID}); + $rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID, my: true}); // setTimeout(function () { message.send(); @@ -805,7 +800,7 @@ angular.module('myApp.services', []) saveMessages([message]); historyStorage.pending.unshift(messageID); - $rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID}); + $rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID, my: true}); // setTimeout(function () { message.send(); @@ -1013,7 +1008,7 @@ angular.module('myApp.services', []) } notification.onclick = function () { - $location.url('/im?p=' + peerString); + $rootScope.$broadcast('history_focus', {peerString: peerString}); }; notification.message = notificationMessage; diff --git a/app/partials/dialog.html b/app/partials/dialog.html index c2714b42..fb7006ba 100644 --- a/app/partials/dialog.html +++ b/app/partials/dialog.html @@ -91,7 +91,7 @@ - +
diff --git a/app/partials/im.html b/app/partials/im.html index c1d7be1b..9511e5fc 100644 --- a/app/partials/im.html +++ b/app/partials/im.html @@ -31,8 +31,8 @@
+ Info

- Info
- + + + + +
@@ -179,7 +183,7 @@
-
+
diff --git a/app/vendor/jquery.emojiarea/jquery.emojiarea.js b/app/vendor/jquery.emojiarea/jquery.emojiarea.js index 1d4edbff..5a176bbb 100644 --- a/app/vendor/jquery.emojiarea/jquery.emojiarea.js +++ b/app/vendor/jquery.emojiarea/jquery.emojiarea.js @@ -16,7 +16,7 @@ /** * This file also contains some modifications by Igor Zhukov in order to add custom scrollbars to EmojiMenu - * See keyword `MODIFICATION: ` in source code. + * See keyword `MODIFICATION` in source code. */ (function($, window, document) { @@ -254,7 +254,7 @@ this.$editor = $('
').addClass('emoji-wysiwyg-editor'); this.$editor.text($textarea.val()); this.$editor.attr({contenteditable: 'true'}); - this.$editor.on('blur keyup paste', function() { return self.onChange.apply(self, arguments); }); + this.$editor.on('blur keyup paste', function(e) { return self.onChange.apply(self, [e]); }); this.$editor.on('mousedown focus', function() { document.execCommand('enableObjectResizing', false, false); }); this.$editor.on('blur', function() { document.execCommand('enableObjectResizing', true, true); }); @@ -278,7 +278,19 @@ }); }; - EmojiArea_WYSIWYG.prototype.onChange = function() { + EmojiArea_WYSIWYG.prototype.onChange = function(e) { + if (e && e.type == 'paste') { + var text = (e.originalEvent || e).clipboardData.getData('text/plain'), + self = this; + setTimeout(function () { + self.onChange(); + }, 0); + if (text.length) { + document.execCommand('insertText', false, text); + return cancelEvent(); + } + return true; + } this.$textarea.val(this.val()).trigger('change'); }; @@ -363,13 +375,18 @@ this.$menu.addClass('emoji-menu'); this.$menu.hide(); - /* MODIFICATION: Following 2 lines are modified by Igor Zhukov, in order to add scrollbars to EmojiMenu */ - this.$itemsWrap = $('
').appendTo(this.$menu); + /*! MODIFICATION START + Following code was modified by Igor Zhukov, in order to add scrollbars and tail to EmojiMenu + */ + this.$itemsTailWrap = $('
').appendTo(this.$menu); + this.$itemsWrap = $('
').appendTo(this.$itemsTailWrap); this.$items = $('
').appendTo(this.$itemsWrap); + $('
').appendTo(this.$menu); + /*! MODIFICATION END */ $body.append(this.$menu); - /* MODIFICATION: Following line is added by Igor Zhukov, in order to add scrollbars to EmojiMenu */ + /*! MODIFICATION: Following line is added by Igor Zhukov, in order to add scrollbars to EmojiMenu */ this.$itemsWrap.nanoScroller({preventPageScrolling: true, tabIndex: -1}); $body.on('keydown', function(e) { @@ -378,7 +395,19 @@ } }); - $body.on('mouseup', function() { + $body.on('mouseup', function(e) { + /*! MODIFICATION START + Following code was added by Igor Zhukov, in order to prevent close on click on EmojiMenu scrollbar + */ + e = e.originalEvent || e; + var target = e.originalTarget || e.target || window; + while (target && target != window) { + target = target.parentNode; + if (target == self.$menu[0]) { + return; + } + } + /*! MODIFICATION END */ self.hide(); }); @@ -394,7 +423,14 @@ this.$menu.on('click', 'a', function(e) { var emoji = $('.label', $(this)).text(); window.setTimeout(function() { - self.onItemSelected.apply(self, [emoji]); + /*! MODIFICATION START + Following code was modified by Igor Zhukov, in order to prevent close on shift-, ctrl-, alt- emoji select + */ + self.onItemSelected(emoji); + if (!e.shiftKey && !e.ctrlKey && !e.metaKey) { + self.hide(); + } + /*! MODIFICATION END */ }, 0); e.stopPropagation(); return false; @@ -405,7 +441,6 @@ EmojiMenu.prototype.onItemSelected = function(emoji) { this.emojiarea.insert(emoji); - this.hide(); }; EmojiMenu.prototype.load = function() { @@ -425,7 +460,7 @@ this.$items.html(html.join('')); - /* MODIFICATION: Following 4 lines were added by Igor Zhukov, in order to add scrollbars to EmojiMenu */ + /*! MODIFICATION: Following 4 lines were added by Igor Zhukov, in order to add scrollbars to EmojiMenu */ var self = this; setTimeout(function () { self.$itemsWrap.nanoScroller(); @@ -450,12 +485,15 @@ this.emojiarea.$button.removeClass('on'); this.emojiarea = null; } + + this.visible = false; this.$menu.hide(); }; EmojiMenu.prototype.show = function(emojiarea) { if (this.emojiarea && this.emojiarea === emojiarea) return; + emojiarea.$button.addClass('on'); this.emojiarea = emojiarea; this.emojiarea.menu = this; diff --git a/app/vendor/ui-bootstrap/ui-bootstrap-custom-0.7.0.js b/app/vendor/ui-bootstrap/ui-bootstrap-custom-0.7.0.js index 797840d6..731c18e7 100644 --- a/app/vendor/ui-bootstrap/ui-bootstrap-custom-0.7.0.js +++ b/app/vendor/ui-bootstrap/ui-bootstrap-custom-0.7.0.js @@ -71,10 +71,8 @@ angular.module('ui.bootstrap.modal', []) }); scope.close = function (evt) { - console.log('close', evt); var modal = $modalStack.getTop(); if (modal && modal.value.backdrop && modal.value.backdrop != 'static') { - console.log('backdrop click'); evt.preventDefault(); evt.stopPropagation(); $modalStack.dismiss(modal.key, 'backdrop click'); @@ -94,7 +92,6 @@ angular.module('ui.bootstrap.modal', []) transclude: true, templateUrl: 'template/modal/window.html', link: function (scope, element, attrs) { - console.log('init window'); scope.windowClass = attrs.windowClass || ''; //trigger CSS transitions @@ -170,8 +167,6 @@ angular.module('ui.bootstrap.modal', []) }); $modalStack.open = function (modalInstance, modal) { - console.log('open', 11); - openedWindows.add(modalInstance, { deferred: modal.deferred, modalScope: modal.scope, @@ -196,8 +191,6 @@ angular.module('ui.bootstrap.modal', []) }; $modalStack.close = function (modalInstance, result) { - // console.log('close'); - console.trace(); var modal = openedWindows.get(modalInstance); if (modal) { modal.value.deferred.resolve(result); @@ -218,6 +211,15 @@ angular.module('ui.bootstrap.modal', []) return openedWindows.top(); }; + $modalStack.dismissAll = function () { + var modal; + while (modal = openedWindows.top()) { + $rootScope.$apply(function () { + $modalStack.dismiss(modal.key); + }); + } + } + return $modalStack; }]) @@ -260,14 +262,12 @@ angular.module('ui.bootstrap.modal', []) result: modalResultDeferred.promise, opened: modalOpenedDeferred.promise, close: function (result) { - console.log('close'); $modalStack.close(modalInstance, result); }, dismiss: function (reason) { $modalStack.dismiss(modalInstance, reason); } }; - console.log('modal', modalInstance); //merge and clean up options modalOptions = angular.extend({}, $modalProvider.options, modalOptions); diff --git a/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.7.0.js b/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.7.0.js index 1e837cf6..6cb3d2ae 100644 --- a/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.7.0.js +++ b/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.7.0.js @@ -210,6 +210,15 @@ angular.module('ui.bootstrap.modal', []) } }; + $modalStack.dismissAll = function () { + var modal; + while (openedWindows.length()) { + if (modal = openedWindows.top()) { + $modalStack.dismiss(modal.key); + } + } + } + $modalStack.getTop = function () { return openedWindows.top(); };