Browse Source

Added dialogs search, improved emoji

master
Igor Zhukov 11 years ago
parent
commit
5c6a185d11
  1. 2
      app/css/app.css
  2. 10
      app/index.html
  3. 2
      app/js/app.js
  4. 58
      app/js/controllers.js
  5. 178
      app/js/services.js
  6. 6
      app/partials/im.html
  7. 2
      app/partials/photo_modal.html
  8. 2
      app/partials/video_modal.html
  9. 21
      app/vendor/jquery.emojiarea/jquery.emojiarea.js

2
app/css/app.css

@ -1314,7 +1314,7 @@ img.img_fullsize {
position: absolute; position: absolute;
z-index: 999; z-index: 999;
width: 180px; width: 180px;
margin-left: -90px; margin-left: -91px;
margin-top: -232px; margin-top: -232px;
overflow: hidden; overflow: hidden;
} }

10
app/index.html

@ -7,7 +7,7 @@
<link rel="stylesheet" href="vendor/angular/angular-csp.css"/> <link rel="stylesheet" href="vendor/angular/angular-csp.css"/>
<link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.css"/> <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="vendor/jquery.nanoscroller/nanoscroller.css"/> <link rel="stylesheet" href="vendor/jquery.nanoscroller/nanoscroller.css"/>
<link rel="stylesheet" href="css/app.css?18"/> <link rel="stylesheet" href="css/app.css?19"/>
<link rel="icon" href="favicon.ico" type="image/x-icon" /> <link rel="icon" href="favicon.ico" type="image/x-icon" />
<meta property="og:title" content="Webogram"> <meta property="og:title" content="Webogram">
@ -34,7 +34,7 @@
<script type="text/javascript" src="vendor/console-polyfill/console-polyfill.js?1"></script> <script type="text/javascript" src="vendor/console-polyfill/console-polyfill.js?1"></script>
<script type="text/javascript" src="vendor/jquery/jquery.min.js"></script> <script type="text/javascript" src="vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="vendor/jquery.nanoscroller/nanoscroller.js"></script> <script type="text/javascript" src="vendor/jquery.nanoscroller/nanoscroller.js"></script>
<script type="text/javascript" src="vendor/jquery.emojiarea/jquery.emojiarea.js?4"></script> <script type="text/javascript" src="vendor/jquery.emojiarea/jquery.emojiarea.js?5"></script>
<script type="text/javascript" src="vendor/angular/angular.js?1"></script> <script type="text/javascript" src="vendor/angular/angular.js?1"></script>
<script type="text/javascript" src="vendor/angular/angular-route.js?1"></script> <script type="text/javascript" src="vendor/angular/angular-route.js?1"></script>
@ -51,9 +51,9 @@
<script type="text/javascript" src="js/lib/mtproto.js?17"></script> <script type="text/javascript" src="js/lib/mtproto.js?17"></script>
<script type="text/javascript" src="js/util.js"></script> <script type="text/javascript" src="js/util.js"></script>
<script type="text/javascript" src="js/app.js?13"></script> <script type="text/javascript" src="js/app.js?14"></script>
<script type="text/javascript" src="js/services.js?14"></script> <script type="text/javascript" src="js/services.js?16"></script>
<script type="text/javascript" src="js/controllers.js?22"></script> <script type="text/javascript" src="js/controllers.js?23"></script>
<script type="text/javascript" src="js/filters.js?3"></script> <script type="text/javascript" src="js/filters.js?3"></script>
<script type="text/javascript" src="js/directives.js?15"></script> <script type="text/javascript" src="js/directives.js?15"></script>

2
app/js/app.js

@ -57,7 +57,7 @@ config(['$locationProvider', '$routeProvider', '$compileProvider', function($loc
// $locationProvider.html5Mode(true); // $locationProvider.html5Mode(true);
$routeProvider.when('/', {templateUrl: 'partials/welcome.html?3', controller: 'AppWelcomeController'}); $routeProvider.when('/', {templateUrl: 'partials/welcome.html?3', controller: 'AppWelcomeController'});
$routeProvider.when('/login', {templateUrl: 'partials/login.html?4', controller: 'AppLoginController'}); $routeProvider.when('/login', {templateUrl: 'partials/login.html?4', controller: 'AppLoginController'});
$routeProvider.when('/im', {templateUrl: 'partials/im.html?10', controller: 'AppIMController', reloadOnSearch: false}); $routeProvider.when('/im', {templateUrl: 'partials/im.html?11', controller: 'AppIMController', reloadOnSearch: false});
$routeProvider.otherwise({redirectTo: '/'}); $routeProvider.otherwise({redirectTo: '/'});
}]); }]);

58
app/js/controllers.js

@ -145,11 +145,12 @@ angular.module('myApp.controllers', [])
}; };
}) })
.controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, MtpApiManager) { .controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager) {
$scope.$on('$routeUpdate', updateCurDialog); $scope.$on('$routeUpdate', updateCurDialog);
$scope.$on('history_focus', function (e, peerData) { $scope.$on('history_focus', function (e, peerData) {
$modalStack.dismissAll();
if (peerData.peerString == $scope.curDialog.peer) { if (peerData.peerString == $scope.curDialog.peer) {
$scope.$broadcast('ui_history_focus'); $scope.$broadcast('ui_history_focus');
} else { } else {
@ -182,12 +183,13 @@ angular.module('myApp.controllers', [])
// console.log('init controller'); // console.log('init controller');
$scope.dialogs = []; $scope.dialogs = [];
$scope.search = {};
var offset = 0, var offset = 0,
maxID = 0, maxID = 0,
hasMore = false, hasMore = false,
limit = 20; startLimit = 20,
limit = 100;
MtpApiManager.invokeApi('account.updateStatus', {offline: false}); MtpApiManager.invokeApi('account.updateStatus', {offline: false});
$scope.$on('dialogs_need_more', function () { $scope.$on('dialogs_need_more', function () {
@ -204,6 +206,10 @@ angular.module('myApp.controllers', [])
}); });
$scope.$on('dialogs_update', function (e, dialog) { $scope.$on('dialogs_update', function (e, dialog) {
if ($scope.search.query !== undefined && $scope.search.query.length) {
return false;
}
var pos = false; var pos = false;
angular.forEach($scope.dialogs, function(curDialog, curPos) { angular.forEach($scope.dialogs, function(curDialog, curPos) {
if (curDialog.peerID == dialog.peerID) { if (curDialog.peerID == dialog.peerID) {
@ -220,27 +226,33 @@ angular.module('myApp.controllers', [])
$scope.dialogs.unshift(wrappedDialog); $scope.dialogs.unshift(wrappedDialog);
}); });
loadDialogs(); $scope.$watch('search.query', loadDialogs);
function loadDialogs (startLimit) { function loadDialogs () {
offset = 0; offset = 0;
maxID = 0; maxID = 0;
hasMore = false; hasMore = false;
startLimit = startLimit || limit;
AppMessagesManager.getDialogs(maxID, startLimit).then(function (dialogsResult) {
offset += startLimit;
maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message;
hasMore = offset < dialogsResult.count;
AppMessagesManager.getDialogs($scope.search.query, maxID, startLimit).then(function (dialogsResult) {
$scope.dialogs = []; $scope.dialogs = [];
angular.forEach(dialogsResult.dialogs, function (dialog) {
$scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count)); if (dialogsResult.dialogs.length) {
}); offset += startLimit;
maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message;
hasMore = offset < dialogsResult.count;
angular.forEach(dialogsResult.dialogs, function (dialog) {
$scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count));
});
}
$scope.$broadcast('ui_dialogs_change'); $scope.$broadcast('ui_dialogs_change');
if (!$scope.search.query) {
AppMessagesManager.getDialogs('', maxID, limit);
}
}, function (error) { }, function (error) {
if (error.code == 401) { if (error.code == 401) {
$location.url('/login'); $location.url('/login');
@ -253,7 +265,7 @@ angular.module('myApp.controllers', [])
return; return;
} }
AppMessagesManager.getDialogs(maxID, limit).then(function (dialogsResult) { AppMessagesManager.getDialogs($scope.search.query, maxID, limit).then(function (dialogsResult) {
offset += limit; offset += limit;
maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message; maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message;
hasMore = offset < dialogsResult.count; hasMore = offset < dialogsResult.count;
@ -280,7 +292,12 @@ angular.module('myApp.controllers', [])
$scope.history = []; $scope.history = [];
$scope.typing = {}; $scope.typing = {};
var peerID, offset, hasMore, maxID, limit = 20; var peerID,
offset = 0,
hasMore = false,
maxID = 0,
startLimit = 20,
limit = 50;
function applyDialogSelect (newPeer) { function applyDialogSelect (newPeer) {
newPeer = newPeer || $scope.curDialog.peer || ''; newPeer = newPeer || $scope.curDialog.peer || '';
@ -351,8 +368,8 @@ angular.module('myApp.controllers', [])
offset = 0; offset = 0;
maxID = 0; maxID = 0;
AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit).then(function (historyResult) { AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, startLimit).then(function (historyResult) {
offset += limit; offset += startLimit;
hasMore = offset < historyResult.count; hasMore = offset < historyResult.count;
maxID = historyResult.history[historyResult.history.length - 1]; maxID = historyResult.history[historyResult.history.length - 1];
@ -553,7 +570,6 @@ angular.module('myApp.controllers', [])
.controller('UserModalController', function ($scope, $location, $rootScope, $modalStack, AppUsersManager) { .controller('UserModalController', function ($scope, $location, $rootScope, $modalStack, AppUsersManager) {
$scope.user = AppUsersManager.wrapForFull($scope.userID); $scope.user = AppUsersManager.wrapForFull($scope.userID);
$scope.goToHistory = function () { $scope.goToHistory = function () {
$modalStack.dismissAll();
$rootScope.$broadcast('history_focus', {peerString: $scope.user.peerString}); $rootScope.$broadcast('history_focus', {peerString: $scope.user.peerString});
}; };
}) })

178
app/js/services.js

@ -376,6 +376,17 @@ angular.module('myApp.services', [])
}; };
} }
}, },
getPeerSearchText: function (peerID) {
var text;
if (peerID > 0) {
var user = AppUsersManager.getUser(peerID);
text = (user.first_name || '') + ' ' + (user.last_name || '') + ' ' + (user.phone || '');
} else if (peerID < 0) {
var chat = AppChatsManager.getChat(-peerID);
text = chat.title || '';
}
return text;
},
getOutputPeer: function (peerID) { getOutputPeer: function (peerID) {
return peerID > 0 return peerID > 0
? {_: 'peerUser', user_id: peerID} ? {_: 'peerUser', user_id: peerID}
@ -405,7 +416,94 @@ angular.module('myApp.services', [])
} }
}) })
.service('AppMessagesManager', function ($q, $rootScope, $filter, $sanitize, $location, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager) { .service('SearchIndexManager', function () {
var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g,
trimRe = /^\s+|\s$/g;
return {
createIndex: createIndex,
indexObject: indexObject,
search: search
};
function createIndex () {
return {
shortIndexes: {},
fullTexts: {}
}
}
function indexObject (id, searchText, searchIndex) {
if (searchIndex.fullTexts[id] !== undefined) {
return false;
}
searchText = searchText.replace(badCharsRe, ' ').replace(trimRe, '').toLowerCase();
if (!searchText.length) {
return false;
}
var shortIndexes = searchIndex.shortIndexes;
searchIndex.fullTexts[id] = searchText;
angular.forEach(searchText.split(' '), function(searchWord) {
var len = Math.min(searchWord.length, 3),
wordPart, i;
for (i = 1; i <= len; i++) {
wordPart = searchWord.substr(0, i);
if (shortIndexes[wordPart] === undefined) {
shortIndexes[wordPart] = [id];
} else {
shortIndexes[wordPart].push(id);
}
}
});
}
function search (query, searchIndex) {
var shortIndexes = searchIndex.shortIndexes,
fullTexts = searchIndex.fullTexts;
query = query.replace(badCharsRe, ' ').replace(trimRe, '').toLowerCase();
var queryWords = query.split(' '),
foundObjs = false,
newFoundObjs, i, j, searchText, found;
for (i = 0; i < queryWords.length; i++) {
newFoundObjs = shortIndexes[queryWords[i].substr(0, 3)];
if (!newFoundObjs) {
foundObjs = [];
break;
}
if (foundObjs === false || foundObjs.length > newFoundObjs.length) {
foundObjs = newFoundObjs;
}
}
newFoundObjs = {};
for (j = 0; j < foundObjs.length; j++) {
found = true;
searchText = fullTexts[foundObjs[j]];
for (i = 0; i < queryWords.length; i++) {
if (searchText.indexOf(queryWords[i]) == -1) {
found = false;
break;
}
}
if (found) {
newFoundObjs[foundObjs[j]] = true;
}
}
return newFoundObjs;
}
})
.service('AppMessagesManager', function ($q, $rootScope, $filter, $sanitize, $location, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager) {
var messagesStorage = {}; var messagesStorage = {};
var messagesForHistory = {}; var messagesForHistory = {};
@ -415,25 +513,51 @@ angular.module('myApp.services', [])
var pendingByMessageID = {}; var pendingByMessageID = {};
var tempID = -1; var tempID = -1;
var dialogsIndex = SearchIndexManager.createIndex(),
cachedResults = {query: false};
NotificationsManager.start(); NotificationsManager.start();
function getDialogs (maxID, limit) { function getDialogs (query, maxID, limit) {
var curDialogStorage = dialogsStorage;
if (angular.isString(query) && query.length) {
if (!limit || cachedResults.query !== query) {
cachedResults.query = query;
var results = SearchIndexManager.search(query, dialogsIndex);
cachedResults.dialogs = [];
angular.forEach(dialogsStorage.dialogs, function (dialog) {
if (results[dialog.peerID]) {
cachedResults.dialogs.push(dialog);
}
});
cachedResults.count = cachedResults.dialogs.length;
}
curDialogStorage = cachedResults;
} else {
cachedResults.query = false;
}
var offset = 0; var offset = 0;
if (maxID > 0) { if (maxID > 0) {
for (offset = 0; offset < dialogsStorage.dialogs.length; offset++) { for (offset = 0; offset < curDialogStorage.dialogs.length; offset++) {
if (maxID > dialogsStorage.dialogs[offset].top_message) { if (maxID > curDialogStorage.dialogs[offset].top_message) {
break; break;
} }
} }
} }
if (dialogsStorage.count !== null && ( if (curDialogStorage.count !== null && (
dialogsStorage.dialogs.length >= offset + limit || curDialogStorage.dialogs.length >= offset + limit ||
dialogsStorage.dialogs.length == dialogsStorage.count curDialogStorage.dialogs.length == curDialogStorage.count
)) { )) {
return $q.when({ return $q.when({
count: dialogsStorage.count, count: curDialogStorage.count,
dialogs: dialogsStorage.dialogs.slice(offset, offset + limit) dialogs: curDialogStorage.dialogs.slice(offset, offset + limit)
}); });
} }
@ -449,29 +573,34 @@ angular.module('myApp.services', [])
saveMessages(dialogsResult.messages); saveMessages(dialogsResult.messages);
if (maxID > 0) { if (maxID > 0) {
for (offset = 0; offset < dialogsStorage.dialogs.length; offset++) { for (offset = 0; offset < curDialogStorage.dialogs.length; offset++) {
if (maxID > dialogsStorage.dialogs[offset].top_message) { if (maxID > curDialogStorage.dialogs[offset].top_message) {
break; break;
} }
} }
} }
dialogsStorage.count = dialogsResult._ == 'messages.dialogsSlice' curDialogStorage.count = dialogsResult._ == 'messages.dialogsSlice'
? dialogsResult.count ? dialogsResult.count
: dialogsResult.dialogs.length; : dialogsResult.dialogs.length;
dialogsStorage.dialogs.splice(offset, dialogsStorage.dialogs.length - offset); curDialogStorage.dialogs.splice(offset, curDialogStorage.dialogs.length - offset);
angular.forEach(dialogsResult.dialogs, function (dialog) { angular.forEach(dialogsResult.dialogs, function (dialog) {
dialogsStorage.dialogs.push({ var peerID = AppPeersManager.getPeerID(dialog.peer),
peerID: AppPeersManager.getPeerID(dialog.peer), peerText = AppPeersManager.getPeerSearchText(peerID);
SearchIndexManager.indexObject(peerID, peerText, dialogsIndex);
curDialogStorage.dialogs.push({
peerID: peerID,
top_message: dialog.top_message, top_message: dialog.top_message,
unread_count: dialog.unread_count unread_count: dialog.unread_count
}); });
}); });
deferred.resolve({ deferred.resolve({
count: dialogsStorage.count, count: curDialogStorage.count,
dialogs: dialogsStorage.dialogs.slice(offset, offset + limit) dialogs: curDialogStorage.dialogs.slice(offset, offset + limit)
}); });
}, function (error) { }, function (error) {
deferred.reject(error); deferred.reject(error);
@ -1104,6 +1233,9 @@ angular.module('myApp.services', [])
dialog.unread_count++; dialog.unread_count++;
} }
dialog.top_message = message.id; dialog.top_message = message.id;
SearchIndexManager.indexObject(peerID, AppPeersManager.getPeerSearchText(peerID), dialogsIndex);
dialogsStorage.dialogs.unshift(dialog); dialogsStorage.dialogs.unshift(dialog);
$rootScope.$broadcast('dialogs_update', dialog); $rootScope.$broadcast('dialogs_update', dialog);
@ -1193,7 +1325,7 @@ angular.module('myApp.services', [])
} }
}); });
console.log('choosing', photo, width, height, bestPhotoSize); // console.log('choosing', photo, width, height, bestPhotoSize);
return bestPhotoSize; return bestPhotoSize;
} }
@ -1266,7 +1398,7 @@ angular.module('myApp.services', [])
scope.photoID = photoID; scope.photoID = photoID;
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: 'partials/photo_modal.html', templateUrl: 'partials/photo_modal.html?1',
controller: 'PhotoModalController', controller: 'PhotoModalController',
scope: scope, scope: scope,
backdrop: 'static' backdrop: 'static'
@ -1360,12 +1492,9 @@ angular.module('myApp.services', [])
scope.videoID = videoID; scope.videoID = videoID;
scope.progress = {enabled: false}; scope.progress = {enabled: false};
scope.player = {}; scope.player = {};
// scope.close = function () {
// modalInstance.close();
// }
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: 'partials/video_modal.html', templateUrl: 'partials/video_modal.html?1',
controller: 'VideoModalController', controller: 'VideoModalController',
scope: scope scope: scope
}); });
@ -1740,9 +1869,6 @@ angular.module('myApp.services', [])
var regExp = new RegExp('((?:(ftp|https?)://|(?:mailto:)?([A-Za-z0-9._%+-]+@))(\\S*\\.\\S*[^\\s.;,(){}<>"\']))|(\\n)|(' + emojiUtf.join('|') + ')', 'i'); var regExp = new RegExp('((?:(ftp|https?)://|(?:mailto:)?([A-Za-z0-9._%+-]+@))(\\S*\\.\\S*[^\\s.;,(){}<>"\']))|(\\n)|(' + emojiUtf.join('|') + ')', 'i');
// console.log(regExp);
return { return {
wrapRichText: wrapRichText wrapRichText: wrapRichText
}; };

6
app/partials/im.html

@ -6,14 +6,14 @@
<div class="im_dialogs_col_wrap" ng-controller="AppImDialogsController"> <div class="im_dialogs_col_wrap" ng-controller="AppImDialogsController">
<div class="im_dialogs_search"> <div class="im_dialogs_search">
<input class="form-control im_dialogs_search_field" type="search" placeholder="Search" ng-model="searchQuery"/> <input class="form-control im_dialogs_search_field" type="search" placeholder="Search" ng-model="search.query"/>
<a class="im_dialogs_search_clear" ng-click="searchQuery = ''" ng-show="searchQuery.length"></a> <a class="im_dialogs_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div> </div>
<div my-dialogs-list class="im_dialogs_col"> <div my-dialogs-list class="im_dialogs_col">
<div class="im_dialogs_wrap nano"> <div class="im_dialogs_wrap nano">
<div class="im_dialogs_scrollable_wrap content"> <div class="im_dialogs_scrollable_wrap content">
<ul class="nav nav-pills nav-stacked"> <ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs | filter:searchQuery" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li> <li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li>
</ul> </ul>
</div> </div>
</div> </div>

2
app/partials/photo_modal.html

@ -4,7 +4,7 @@
<div class="photo_modal_image_wrap" my-load-full-photo full-photo="photo.full" thumb-location="photo.thumb.location" ng-click="$close()"> </div> <div class="photo_modal_image_wrap" my-load-full-photo full-photo="photo.full" thumb-location="photo.thumb.location" ng-click="$close()"> </div>
<p class="media_modal_info">From: <span class="media_modal_author">{{photo.fromUser | userName}}</span>, {{photo.date | dateOrTime}}</p> <p class="media_modal_info">From: <span class="media_modal_author" ng-bind-html="photo.fromUser.rFullName" ></span>, {{photo.date | dateOrTime}}</p>
</div> </div>

2
app/partials/video_modal.html

@ -4,7 +4,7 @@
<div class="video_modal_image_wrap" my-load-video video="video"></div> <div class="video_modal_image_wrap" my-load-video video="video"></div>
<p class="media_modal_info">From: <span class="media_modal_author">{{video.fromUser | userName}}</span>, {{video.date | dateOrTime}}</p> <p class="media_modal_info">From: <span class="media_modal_author" ng-bind-html="video.fromUser.rFullName"></span>, {{video.date | dateOrTime}}</p>
</div> </div>

21
app/vendor/jquery.emojiarea/jquery.emojiarea.js vendored

@ -321,6 +321,16 @@
util.restoreSelection(this.selection); util.restoreSelection(this.selection);
} }
try { util.replaceSelection($img[0]); } catch (e) {} try { util.replaceSelection($img[0]); } catch (e) {}
/*! MODIFICATION START
Following code was modified by Igor Zhukov, in order to improve selection handling
*/
var self = this;
setTimeout(function () {
self.selection = util.saveSelection();
}, 100);
/*! MODIFICATION END */
this.onChange(); this.onChange();
}; };
@ -418,7 +428,7 @@
var target = e.originalTarget || e.target || window; var target = e.originalTarget || e.target || window;
while (target && target != window) { while (target && target != window) {
target = target.parentNode; target = target.parentNode;
if (target == self.$menu[0]) { if (target == self.$menu[0] || self.emojiarea && target == self.emojiarea.$button[0]) {
return; return;
} }
} }
@ -438,11 +448,11 @@
this.$menu.on('click', 'a', function(e) { this.$menu.on('click', 'a', function(e) {
var emoji = $('.label', $(this)).text(); var emoji = $('.label', $(this)).text();
window.setTimeout(function() { window.setTimeout(function() {
self.onItemSelected(emoji);
/*! MODIFICATION START /*! MODIFICATION START
Following code was modified by Igor Zhukov, in order to prevent close on shift-, ctrl-, alt- emoji select Following code was modified by Igor Zhukov, in order to close only on ctrl-, alt- emoji select
*/ */
self.onItemSelected(emoji); if (e.ctrlKey || e.metaKey) {
if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
self.hide(); self.hide();
} }
/*! MODIFICATION END */ /*! MODIFICATION END */
@ -507,7 +517,8 @@
}; };
EmojiMenu.prototype.show = function(emojiarea) { EmojiMenu.prototype.show = function(emojiarea) {
if (this.emojiarea && this.emojiarea === emojiarea) return; /* MODIFICATION: Following line was modified by Igor Zhukov, in order to improve EmojiMenu behaviour */
if (this.emojiarea && this.emojiarea === emojiarea) return this.hide();
emojiarea.$button.addClass('on'); emojiarea.$button.addClass('on');
this.emojiarea = emojiarea; this.emojiarea = emojiarea;
this.emojiarea.menu = this; this.emojiarea.menu = this;

Loading…
Cancel
Save