diff --git a/app/css/app.css b/app/css/app.css
index a65e8e92..b7a22ed3 100644
--- a/app/css/app.css
+++ b/app/css/app.css
@@ -771,7 +771,7 @@ a.tg_radio_on:hover i.icon-radio {
display: inline-block;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -5px -10px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
margin-right: 18px;
}
.icon-tg-title {
@@ -809,7 +809,7 @@ a.tg_radio_on:hover i.icon-radio {
display: inline-block;
vertical-align: middle;
background: url(../img/icons/General.png) no-repeat -18px -50px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
margin-left: 12px;
margin-top: -1px;
}
@@ -1453,7 +1453,7 @@ div.im_message_video_thumb {
display: inline-block;
line-height: 0;
background: url(../img/icons/General.png) no-repeat -14px -509px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
width: 12px;
height: 18px;
margin: 12px 15px;
@@ -1476,7 +1476,7 @@ div.im_message_video_thumb {
width: 14px;
height: 16px;
background: url(../img/icons/General.png) no-repeat -13px -611px;
- background-size: 40px 678px;;
+ background-size: 40px 778px;;
margin: 13px 16px;
}
.is_1x .im_message_file_button_dl_audio .im_message_file_button_icon {
@@ -1775,42 +1775,6 @@ a.im_message_fwd_photo {
line-height: 150%;
}
-span.emoji {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- *vertical-align: auto;
- *zoom: 1;
- *display: inline;
- height: 18px;
- width: 18px;
- background-repeat: no-repeat;
- text-indent: -9999px;
-}
-
-/* widths and heights calculated according to spritesheet dimensions and icon size */
-.emoji-spritesheet-0 {
- background-size: 486px 126px;
- background-image: url('../img/emojisprite_0.png');
-}
-.emoji-spritesheet-1 {
- background-size: 522px 72px;
- background-image: url('../img/emojisprite_1.png');
-}
-.emoji-spritesheet-2 {
- background-size: 594px 126px;
- background-image: url('../img/emojisprite_2.png');
-}
-.emoji-spritesheet-3 {
- background-size: 612px 54px;
- background-image: url('../img/emojisprite_3.png');
-}
-.emoji-spritesheet-4 {
- background-size: 612px 126px;
- background-image: url('../img/emojisprite_4.png');
-}
-
.im_history_not_selected,
.im_history_empty {
visibility: hidden;
@@ -1995,116 +1959,189 @@ img.img_fullsize {
vertical-align: middle;
margin: -3px 0 0 0;
}
-.emoji-menu {
+
+
+
+.composer_emoji_insert_btn {
+ display: block;
+ position: absolute;
+ right: 3px;
+ top: 2px;
+ cursor: pointer;
+ padding: 0;
+
+ width: 22px;
+ height: 22px;
+ margin-top: 1px;
+}
+.icon-emoji {
+ display: inline-block;
+ width: 22px;
+ height: 22px;
+ vertical-align: top;
+ background: url(../img/icons/General.png) no-repeat -9px -335px;
+ background-size: 40px 778px;
+ opacity: 0.8;
+}
+.composer_emoji_tooltip {
+ display: none;
position: absolute;
z-index: 999;
width: 220px;
- margin-left: -107px;
- margin-top: -252px;
- overflow: hidden;
+ margin-left: -100px;
+ margin-top: -248px;
border: 1px #dfdfdf solid;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
- overflow: hidden;
-webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
-}
-.emoji-items-wrap1 {
background: #FFF;
padding: 5px 2px 5px 5px;
}
-.emoji-items-wrap1 .emoji-menu-tabs {
+.icon-tooltip-tail {
+ background: #FFF;
+ width: 18px;
+ height: 18px;
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+ display: inline-block;
+ -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
+ box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
+ border: 1px #dfdfdf solid;
+ border-width: 0 1px 1px 0;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ position: absolute;
+ bottom: -10px;
+ left: 50%;
+ margin-left: -9px;
+}
+
+.composer_emoji_tooltip_tabs {
width: 100%;
margin-bottom: 8px;
margin-top: 3px;
}
-.emoji-items-wrap1 .emoji-menu-tabs td {
- text-align: center;
- color: white;
+.composer_emoji_tooltip_tab {
line-height: 0;
-}
-.emoji-menu-tabs .emoji-menu-tab {
+ color: white;
display: inline-block;
width: 24px;
height: 29px;
background: url(../img/icons/IconsetSmiles.png) no-repeat;
- background-size: 42px 350px;
+ background-size: 42px 470px;
+ cursor: pointer;
+ opacity: 0.7;
+ margin: 0 3px;
}
-.is_1x .emoji-menu-tabs .emoji-menu-tab {
+.is_1x .composer_emoji_tooltip_tab {
background-image: url(../img/icons/IconsetSmiles_1x.png);
}
+.composer_emoji_tooltip_tab.active {
+ opacity: 1;
+}
-.emoji-menu-tabs .icon-recent {background-position: -9px -306px; }
-.emoji-menu-tabs .icon-recent-selected {background-position: -9px -277px; }
+.composer_emoji_tooltip_tab_recent {background-position: -9px -306px; }
+.composer_emoji_tooltip_tab_recent.active {background-position: -9px -277px; }
-.emoji-menu-tabs .icon-smile {background-position: -9px -34px; }
-.emoji-menu-tabs .icon-smile-selected {background-position: -9px -5px; }
+.composer_emoji_tooltip_tab_smile {background-position: -9px -34px; }
+.composer_emoji_tooltip_tab_smile.active {background-position: -9px -5px; }
-.emoji-menu-tabs .icon-flower {background-position: -9px -145px; }
-.emoji-menu-tabs .icon-flower-selected {background-position: -9px -118px; }
+.composer_emoji_tooltip_tab_flower {background-position: -9px -145px; }
+.composer_emoji_tooltip_tab_flower.active {background-position: -9px -118px; }
-.emoji-menu-tabs .icon-bell {background-position: -9px -89px; }
-.emoji-menu-tabs .icon-bell-selected {background-position: -9px -61px; }
+.composer_emoji_tooltip_tab_bell {background-position: -9px -89px; }
+.composer_emoji_tooltip_tab_bell.active {background-position: -9px -61px; }
-.emoji-menu-tabs .icon-car {background-position: -9px -196px; }
-.emoji-menu-tabs .icon-car-selected {background-position: -9px -170px; }
+.composer_emoji_tooltip_tab_car {background-position: -9px -196px; }
+.composer_emoji_tooltip_tab_car.active {background-position: -9px -170px; }
-.emoji-menu-tabs .icon-grid {background-position: -9px -248px; }
-.emoji-menu-tabs .icon-grid-selected {background-position: -9px -222px; }
-
-.emoji-menu-tabs .icon-recent,
-.emoji-menu-tabs .icon-smile,
-.emoji-menu-tabs .icon-flower,
-.emoji-menu-tabs .icon-bell,
-.emoji-menu-tabs .icon-car,
-.emoji-menu-tabs .icon-grid {
- opacity: 0.7;
-}
-.emoji-menu-tabs .icon-recent:hover,
-.emoji-menu-tabs .icon-smile:hover,
-.emoji-menu-tabs .icon-flower:hover,
-.emoji-menu-tabs .icon-bell:hover,
-.emoji-menu-tabs .icon-car:hover,
-.emoji-menu-tabs .icon-grid:hover {
- opacity: 1;
-}
+.composer_emoji_tooltip_tab_grid {background-position: -9px -248px; }
+.composer_emoji_tooltip_tab_grid.active {background-position: -9px -222px; }
+.composer_emoji_tooltip_tab_stickers {background-position: -9px -361px; }
+.composer_emoji_tooltip_tab_stickers.active {background-position: -9px -333px; }
-.emoji-menu .emoji-items-wrap {
+.composer_emoji_tooltip_content {
position: relative;
height: 174px;
+ overflow: hidden;
+ overflow-y: auto;
}
-.emoji-menu .emoji-items {
- padding-right: 8px;
- outline: 0 !important;
-}
-.emoji-menu img {
- width: 20px;
- height: 20px;
- vertical-align: middle;
- border: 0 none;
-}
-.emoji-menu .emoji-items a {
+
+
+a.composer_emoji_btn {
margin: -1px 0 0 -1px;
padding: 5px;
display: block;
float: left;
border-radius: 2px;
}
-.emoji-menu .emoji-items a:hover {
+a.composer_emoji_btn:hover {
background-color: #edf2f5;
}
-.emoji-menu:after {
- content: ' ';
- display: block;
- clear: left;
+
+
+
+.emoji {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ *vertical-align: auto;
+ *zoom: 1;
+ *display: inline;
+ height: 18px;
+ width: 18px;
+ background-repeat: no-repeat;
+ text-indent: -9999px;
}
-.emoji-menu a .label {
- display: none;
+
+/* widths and heights calculated according to spritesheet dimensions and icon size */
+.emoji-spritesheet-0 {
+ background-size: 486px 126px;
+ background-image: url('../img/emojisprite_0.png');
+}
+.emoji-spritesheet-1 {
+ background-size: 522px 72px;
+ background-image: url('../img/emojisprite_1.png');
+}
+.emoji-spritesheet-2 {
+ background-size: 594px 126px;
+ background-image: url('../img/emojisprite_2.png');
+}
+.emoji-spritesheet-3 {
+ background-size: 612px 54px;
+ background-image: url('../img/emojisprite_3.png');
}
+.emoji-spritesheet-4 {
+ background-size: 612px 126px;
+ background-image: url('../img/emojisprite_4.png');
+}
+
+
+.composer_emoji_btn .emoji {
+ width: 20px;
+ height: 20px;
+ vertical-align: middle;
+ border: 0 none;
+ display: inline-block;
+}
+.composer_emoji_btn .emoji-spritesheet-0 {background-size: 540px 140px;}
+.composer_emoji_btn .emoji-spritesheet-1 {background-size: 580px 80px;}
+.composer_emoji_btn .emoji-spritesheet-2 {background-size: 660px 140px;}
+.composer_emoji_btn .emoji-spritesheet-3 {background-size: 680px 60px;}
+.composer_emoji_btn .emoji-spritesheet-4 {background-size: 680px 140px;}
+
+
.error_modal_window .modal-dialog {
diff --git a/app/css/desktop.css b/app/css/desktop.css
index aa88269e..5bbb607f 100644
--- a/app/css/desktop.css
+++ b/app/css/desktop.css
@@ -171,7 +171,7 @@
margin-right: 38px;
display: inline-block;
background: url(../img/icons/General.png) no-repeat -10px -111px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
vertical-align: top;
margin-top: 3px;
}
@@ -183,7 +183,7 @@
display: inline-block;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -11px -135px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
}
.icon-settings {
width: 20px;
@@ -193,7 +193,7 @@
display: inline-block;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -10px -163px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
}
.icon-faq {
width: 20px;
@@ -203,7 +203,7 @@
display: inline-block;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -10px -637px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
}
.icon-about {
width: 21px;
@@ -212,7 +212,7 @@
display: inline-block;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -10px -193px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
}
.is_1x .icon-new-group,
.is_1x .icon-contacts,
@@ -315,7 +315,7 @@
.icon-filter-audio {
display: inline-block;
background: url(../img/icons/General.png) no-repeat 0 0;
- background-size: 40px 678px;
+ background-size: 40px 778px;
margin-right: 12px;
vertical-align: top;
}
@@ -722,26 +722,21 @@ a.footer_link.active:active {
background: inherit;
}
-.im_emoji_quick_select_area {
+.composer_emoji_panel {
display: block;
height: 30px;
overflow: hidden;
max-width: 210px;
}
-
-.im_emoji_quick_select_area a {
+.composer_emoji_panel a {
display: inline-block;
padding: 5px;
outline: 0;
border-radius: 2px;
}
-
-.im_emoji_quick_select_area a:hover {
+/*.composer_emoji_panel a:hover {
background-color: #edf2f5;
-}
-.im_emoji_quick_select_area a .label {
- display: none;
-}
+}*/
.im_message_selected .im_message_date,
.im_message_selected .im_message_document_size,
@@ -940,7 +935,8 @@ a.im_panel_peer_photo .peer_initials {
margin-left: 36px;
}
-.im_emoji_btn {
+/*.composer_emoji_insert_btn {
+ display: block;
position: absolute;
right: 3px;
top: 2px;
@@ -950,28 +946,43 @@ a.im_panel_peer_photo .peer_initials {
width: 22px;
height: 22px;
margin-top: 1px;
-}
-.icon-emoji {
+}*/
+/*.icon-emoji {
display: inline-block;
width: 22px;
height: 22px;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -9px -335px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
opacity: 0.8;
-}
+}*/
.is_1x .icon-emoji {
background-image: url(../img/icons/General_1x.png);
}
-.im_emoji_btn:hover .icon-emoji {
+.composer_emoji_insert_btn:hover .icon-emoji {
opacity: 1;
}
-.im_emoji_btn:active .icon-emoji,
-.im_emoji_btn.on .icon-emoji {
+.composer_emoji_insert_btn:active .icon-emoji,
+.composer_emoji_insert_btn.on .icon-emoji {
background-position: -9px -367px;
opacity: 1;
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
.im_send_field_wrap {
margin-bottom: 15px;
}
@@ -1014,7 +1025,7 @@ a.im_panel_peer_photo .peer_initials {
height: 17px;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -11px -455px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
opacity: 0.8;
margin: 0;
}
@@ -1050,7 +1061,7 @@ a.im_panel_peer_photo .peer_initials {
height: 18px;
vertical-align: top;
background: url(../img/icons/General.png) no-repeat -10px -399px;
- background-size: 40px 678px;
+ background-size: 40px 778px;
opacity: 0.8;
}
.is_1x .icon-camera {
diff --git a/app/img/icons/General.png b/app/img/icons/General.png
index b6f3fdf6..aa2e7ec8 100644
Binary files a/app/img/icons/General.png and b/app/img/icons/General.png differ
diff --git a/app/img/icons/General_1x.png b/app/img/icons/General_1x.png
index 271503ca..045dccad 100644
Binary files a/app/img/icons/General_1x.png and b/app/img/icons/General_1x.png differ
diff --git a/app/img/icons/IconsetSmiles.png b/app/img/icons/IconsetSmiles.png
index 4fb10645..6618c24b 100644
Binary files a/app/img/icons/IconsetSmiles.png and b/app/img/icons/IconsetSmiles.png differ
diff --git a/app/img/icons/IconsetSmiles_1x.png b/app/img/icons/IconsetSmiles_1x.png
index 9679265d..b244cb76 100644
Binary files a/app/img/icons/IconsetSmiles_1x.png and b/app/img/icons/IconsetSmiles_1x.png differ
diff --git a/app/index.html b/app/index.html
index 78eb06a2..e98f1f7c 100644
--- a/app/index.html
+++ b/app/index.html
@@ -84,6 +84,7 @@
PRODUCTION_ONLY_END-->
+
diff --git a/app/js/app.js b/app/js/app.js
index e8ec4a78..a80ee454 100644
--- a/app/js/app.js
+++ b/app/js/app.js
@@ -27,25 +27,25 @@ angular.module('myApp', [
]).
config(['$locationProvider', '$routeProvider', '$compileProvider', 'StorageProvider', function($locationProvider, $routeProvider, $compileProvider, StorageProvider) {
- var icons = {}, reverseIcons = {}, i, j, hex, name, dataItem, row, column, totalColumns;
-
- for (j = 0; j < Config.EmojiCategories.length; j++) {
- totalColumns = Config.EmojiCategorySpritesheetDimens[j][1];
- for (i = 0; i < Config.EmojiCategories[j].length; i++) {
- dataItem = Config.Emoji[Config.EmojiCategories[j][i]];
- name = dataItem[1][0];
- row = Math.floor(i / totalColumns);
- column = (i % totalColumns);
- icons[':' + name + ':'] = [j, row, column, ':'+name+':'];
- reverseIcons[name] = dataItem[0];
- }
- }
-
- $.emojiarea.spritesheetPath = 'img/emojisprite_!.png';
- $.emojiarea.spritesheetDimens = Config.EmojiCategorySpritesheetDimens;
- $.emojiarea.iconSize = 20;
- $.emojiarea.icons = icons;
- $.emojiarea.reverseIcons = reverseIcons;
+ // var icons = {}, reverseIcons = {}, i, j, hex, name, dataItem, row, column, totalColumns;
+
+ // for (j = 0; j < Config.EmojiCategories.length; j++) {
+ // totalColumns = Config.EmojiCategorySpritesheetDimens[j][1];
+ // for (i = 0; i < Config.EmojiCategories[j].length; i++) {
+ // dataItem = Config.Emoji[Config.EmojiCategories[j][i]];
+ // name = dataItem[1][0];
+ // row = Math.floor(i / totalColumns);
+ // column = (i % totalColumns);
+ // icons[':' + name + ':'] = [j, row, column, ':'+name+':'];
+ // reverseIcons[name] = dataItem[0];
+ // }
+ // }
+
+ // $.emojiarea.spritesheetPath = 'img/emojisprite_!.png';
+ // $.emojiarea.spritesheetDimens = Config.EmojiCategorySpritesheetDimens;
+ // $.emojiarea.iconSize = 20;
+ // $.emojiarea.icons = icons;
+ // $.emojiarea.reverseIcons = reverseIcons;
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|blob|filesystem|chrome-extension|app):|data:image\//);
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|file|mailto|blob|filesystem|chrome-extension|app):|data:image\//);
diff --git a/app/js/controllers.js b/app/js/controllers.js
index 4c98edbf..cb8aeda4 100644
--- a/app/js/controllers.js
+++ b/app/js/controllers.js
@@ -2992,7 +2992,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
})
- .controller('CountrySelectModalController', function ($scope, $modalInstance, $rootScope, SearchIndexManager, _) {
+ .controller('CountrySelectModalController', function ($scope, $modalInstance, $rootScope, _) {
$scope.search = {};
$scope.slice = {limit: 20, limitDelta: 20}
@@ -3035,7 +3035,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
})
- .controller('PhonebookModalController', function ($scope, $modalInstance, $rootScope, AppUsersManager, PhonebookContactsService, SearchIndexManager, ErrorService) {
+ .controller('PhonebookModalController', function ($scope, $modalInstance, $rootScope, AppUsersManager, PhonebookContactsService, ErrorService) {
$scope.search = {};
$scope.phonebook = [];
diff --git a/app/js/directives.js b/app/js/directives.js
index 6d919047..0c6f78d9 100755
--- a/app/js/directives.js
+++ b/app/js/directives.js
@@ -1071,6 +1071,16 @@ angular.module('myApp.directives', ['myApp.filters'])
};
function link ($scope, element, attrs) {
+
+ var emojiButton = $('.composer_emoji_insert_btn', element)[0];
+ new EmojiTooltip(emojiButton);
+
+ var emojiPanel = $('.composer_emoji_panel', element)[0];
+ new EmojiPanel(emojiPanel);
+
+ return;
+
+
var messageField = $('textarea', element)[0],
fileSelects = $('input', element),
dropbox = $('.im_send_dropbox_wrap', element)[0],
@@ -2587,4 +2597,4 @@ angular.module('myApp.directives', ['myApp.filters'])
}
};
- })
+ })
\ No newline at end of file
diff --git a/app/js/lib/ng_utils.js b/app/js/lib/ng_utils.js
index c7bb80e5..f26139ac 100644
--- a/app/js/lib/ng_utils.js
+++ b/app/js/lib/ng_utils.js
@@ -734,115 +734,6 @@ angular.module('izhukov.utils', [])
};
})
-.service('SearchIndexManager', function () {
- var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g,
- trimRe = /^\s+|\s$/g,
- accentsReplace = {
- a: /[åáâäà]/g,
- e: /[éêëè]/g,
- i: /[íîïì]/g,
- o: /[óôöò]/g,
- u: /[úûüù]/g,
- c: /ç/g,
- ss: /ß/g
- }
-
- return {
- createIndex: createIndex,
- indexObject: indexObject,
- cleanSearchText: cleanSearchText,
- search: search
- };
-
- function createIndex () {
- return {
- shortIndexes: {},
- fullTexts: {}
- }
- }
-
- function cleanSearchText (text) {
- text = text.replace(badCharsRe, ' ').replace(trimRe, '').toLowerCase();
-
- for (var key in accentsReplace) {
- if (accentsReplace.hasOwnProperty(key)) {
- text = text.replace(accentsReplace[key], key);
- }
- }
-
- return text;
- }
-
- function indexObject (id, searchText, searchIndex) {
- if (searchIndex.fullTexts[id] !== undefined) {
- return false;
- }
-
- searchText = cleanSearchText(searchText);
-
- 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 = cleanSearchText(query);
-
- 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('ExternalResourcesManager', function ($q, $http) {
var urlPromises = {};
diff --git a/app/js/lib/utils.js b/app/js/lib/utils.js
index f7b2f77d..60cea630 100644
--- a/app/js/lib/utils.js
+++ b/app/js/lib/utils.js
@@ -58,9 +58,64 @@ function onCtrlEnter (textarea, cb) {
});
}
+function setFieldSelection(field, from, to) {
+ field = $(field)[0];
+ try {
+ field.focus();
+ if (from === undefined || from === false) {
+ from = field.value.length;
+ }
+ if (to === undefined || to === false) {
+ to = from;
+ }
+ if (field.createTextRange) {
+ var range = field.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', to);
+ range.moveStart('character', from);
+ range.select();
+ }
+ else if (field.setSelectionRange) {
+ field.setSelectionRange(from, to);
+ }
+ } catch(e) {}
+}
+
+function getFieldSelection (field) {
+ if (field.selectionStart) {
+ return field.selectionStart;
+ }
+ else if (!document.selection) {
+ return 0;
+ }
+
+ var c = "\001",
+ sel = document.selection.createRange(),
+ txt = sel.text,
+ dup = sel.duplicate(),
+ len = 0;
+
+ try {
+ dup.moveToElementText(field);
+ } catch(e) {
+ return 0;
+ }
+
+ sel.text = txt + c;
+ len = dup.text.indexOf(c);
+ sel.moveStart('character',-1);
+ sel.text = '';
+
+ // if (browser.msie && len == -1) {
+ // return field.value.length;
+ // }
+ return len;
+}
+
+
function onContentLoaded (cb) {
setTimeout(cb, 0);
-};
+}
function tsNow (seconds) {
var t = +new Date() + (window.tsOffset || 0);
@@ -153,27 +208,140 @@ function calcImageInBox(imageW, imageH, boxW, boxH, noZooom) {
}
function versionCompare (ver1, ver2) {
- if (typeof ver1 !== 'string') {
- ver1 = '';
+ if (typeof ver1 !== 'string') {
+ ver1 = '';
+ }
+ if (typeof ver2 !== 'string') {
+ ver2 = '';
+ }
+ ver1 = ver1.replace(/^\s+|\s+$/g, '').split('.');
+ ver2 = ver2.replace(/^\s+|\s+$/g, '').split('.');
+
+ var a = Math.max(ver1.length, ver2.length), i;
+
+ for (i = 0; i < a; i++) {
+ if (ver1[i] == ver2[i]) {
+ continue;
+ }
+ if (ver1[i] > ver2[i]) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+(function (global) {
+
+ var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g,
+ trimRe = /^\s+|\s$/g,
+ accentsReplace = {
+ a: /[åáâäà]/g,
+ e: /[éêëè]/g,
+ i: /[íîïì]/g,
+ o: /[óôöò]/g,
+ u: /[úûüù]/g,
+ c: /ç/g,
+ ss: /ß/g
+ };
+
+ function createIndex () {
+ return {
+ shortIndexes: {},
+ fullTexts: {}
+ }
+ }
+
+ function cleanSearchText (text) {
+ text = text.replace(badCharsRe, ' ').replace(trimRe, '').toLowerCase();
+
+ for (var key in accentsReplace) {
+ if (accentsReplace.hasOwnProperty(key)) {
+ text = text.replace(accentsReplace[key], key);
+ }
+ }
+
+ return text;
+ }
+
+ function indexObject (id, searchText, searchIndex) {
+ if (searchIndex.fullTexts[id] !== undefined) {
+ return false;
+ }
+
+ searchText = cleanSearchText(searchText);
+
+ if (!searchText.length) {
+ return false;
}
- if (typeof ver2 !== 'string') {
- ver2 = '';
+
+ 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 = cleanSearchText(query);
+
+ 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;
+ }
}
- ver1 = ver1.replace(/^\s+|\s+$/g, '').split('.');
- ver2 = ver2.replace(/^\s+|\s+$/g, '').split('.');
- var a = Math.max(ver1.length, ver2.length), i;
+ newFoundObjs = {};
- for (i = 0; i < a; i++) {
- if (ver1[i] == ver2[i]) {
- continue;
+ 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 (ver1[i] > ver2[i]) {
- return 1;
- } else {
- return -1;
+ if (found) {
+ newFoundObjs[foundObjs[j]] = true;
}
}
- return 0;
+ return newFoundObjs;
}
+
+ global.SearchIndexManager = {
+ createIndex: createIndex,
+ indexObject: indexObject,
+ cleanSearchText: cleanSearchText,
+ search: search
+ };
+
+})(window);
+
diff --git a/app/js/message_composer.js b/app/js/message_composer.js
new file mode 100644
index 00000000..1a5d21cd
--- /dev/null
+++ b/app/js/message_composer.js
@@ -0,0 +1,396 @@
+/*!
+ * Webogram v0.3.9 - messaging web application for MTProto
+ * https://github.com/zhukov/webogram
+ * Copyright (C) 2014 Igor Zhukov
+ * https://github.com/zhukov/webogram/blob/master/LICENSE
+ */
+
+'use strict';
+
+/* EmojiHelper */
+
+(function (global, emojis, categories, spritesheets) {
+
+
+ var emojis = {};
+ var shortcuts = {};
+ var spritesheetPositions = {};
+ var index = false;
+
+ var popular = 'joy,kissing_heart,heart,heart_eyes,blush,grin,+1,relaxed,pensive,smile,sob,kiss,unamused,flushed,stuck_out_tongue_winking_eye,see_no_evil,wink,smiley,cry,stuck_out_tongue_closed_eyes,scream,rage,smirk,disappointed,sweat_smile,kissing_closed_eyes,speak_no_evil,relieved,grinning,yum,laughing,ok_hand,neutral_face,confused'.split(',');
+
+ var i, j, code, shortcut, emoji, row, column, totalColumns;
+ var len1, len2;
+
+ for (i = 0, len1 = categories.length; i < len1; i++) {
+ totalColumns = spritesheets[i][1];
+ for (j = 0, len2 = categories[i].length; j < len2; j++) {
+ code = categories[i][j];
+ emoji = Config.Emoji[code];
+ shortcut = emoji[1][0];
+ emojis[code] = [emoji[0], shortcut];
+ shortcuts[shortcut] = code;
+ spritesheetPositions[code] = [i, j, Math.floor(j / totalColumns), j % totalColumns];
+ }
+ }
+
+ function getPopularEmoji (callback) {
+ ConfigStorage.get('emojis_popular', function (popEmojis) {
+ var result = [];
+ if (popEmojis && popEmojis.length) {
+ for (var i = 0, len = popEmojis.length; i < len; i++) {
+ result.push({code: popEmojis[i][0], rate: popEmojis[i][1]});
+ }
+ callback(result);
+ return;
+ };
+ ConfigStorage.get('emojis_recent', function (recentEmojis) {
+ recentEmojis = recentEmojis || popular || [];
+ var shortcut, code;
+ for (var i = 0, len = recentEmojis.length; i < len; i++) {
+ shortcut = recentEmojis[i];
+ if (Array.isArray(shortcut)) {
+ shortcut = shortcut[0];
+ }
+ if (shortcut.charAt(0) == ':') {
+ shortcut = shortcut.substr(1, shortcut.length - 2);
+ }
+ if (code = shortcuts[shortcut]) {
+ result.push({code: code, rate: 1});
+ }
+ }
+ callback(result);
+ });
+ });
+ }
+
+ function pushPopularEmoji (code) {
+ getPopularEmoji(function (popularEmoji) {
+ var exists = false;
+ var count = popularEmoji.length;
+ var result = [];
+ for (var i = 0; i < count; i++) {
+ if (popularEmoji[i].code == code) {
+ exists = true;
+ popularEmoji[i].rate++;
+ }
+ result.push([popularEmoji[i].code, popularEmoji[i].rate]);
+ }
+ if (exists) {
+ result.sort(function (a, b) {
+ return b[1] - a[1];
+ });
+ } else {
+ if (result.length > 41) {
+ result = result.slice(0, 41);
+ }
+ result.push([code, 1]);
+ }
+ ConfigStorage.set({emojis_popular: result});
+ });
+ }
+
+ function indexEmojis () {
+ if (index === false) {
+ index = SearchIndexManager.createIndex();
+ var shortcut;
+ for (shortcut in shortcuts) {
+ if (shortcuts.hasOwnProperty(shortcut)) {
+ SearchIndexManager.indexObject(shortcuts[shortcut], shortcut, index);
+ }
+ }
+ }
+ }
+
+ function searchEmojis (q) {
+ indexEmojis();
+ return SearchIndexManager.search(q, index);
+ }
+
+ global.EmojiHelper = {
+ emojis: emojis,
+ shortcuts: shortcuts,
+ spritesheetPositions: spritesheetPositions,
+ getPopularEmoji: getPopularEmoji,
+ pushPopularEmoji: pushPopularEmoji,
+ indexEmojis: indexEmojis,
+ searchEmojis: searchEmojis
+ };
+
+})(window, Config.Emoji, Config.EmojiCategories, Config.EmojiCategorySpritesheetDimens);
+
+
+function EmojiTooltip (btnEl, options) {
+ options = options || {};
+ var self = this;
+
+ this.btnEl = $(btnEl);
+ this.onEmojiSelected = options.onEmojiSelected;
+
+ $(this.btnEl).on('mouseenter mouseleave', function (e) {
+ self.isOverBtn = e.type == 'mouseenter';
+ self.createTooltip();
+
+ if (self.isOverBtn) {
+ self.onMouseEnter(true);
+ } else {
+ self.onMouseLeave(true);
+ }
+ });
+}
+
+EmojiTooltip.prototype.onMouseEnter = function (triggerShow) {
+ if (this.hideTimeout) {
+ clearTimeout(this.hideTimeout);
+ delete this.hideTimeout;
+ }
+ else if (triggerShow && !this.showTimeout) {
+ this.showTimeout = setTimeout(this.show.bind(this), 500);
+ }
+};
+
+EmojiTooltip.prototype.onMouseLeave = function (triggerUnshow) {
+ if (!this.hideTimeout) {
+ var self = this;
+ this.hideTimeout = setTimeout(function () {
+ self.hide();
+ }, 500);
+ }
+ else if (triggerUnshow && this.showTimeout) {
+ clearTimeout(this.showTimeout);
+ delete this.showTimeout;
+ }
+};
+
+
+
+EmojiTooltip.prototype.createTooltip = function () {
+ if (this.tooltipEl) {
+ return false;
+ }
+
+ var self = this;
+ this.tooltipEl = $('').appendTo(document.body);
+
+ this.tabsEl = $('.composer_emoji_tooltip_tabs', this.tooltip);
+ this.contentEl = $('.composer_emoji_tooltip_content', this.tooltip);
+ this.footerEl = $('.composer_emoji_tooltip_footer', this.tooltip);
+ this.settingsEl = $('.composer_emoji_tooltip_settings', this.tooltip);
+
+ angular.forEach(['recent', 'smile', 'flower', 'bell', 'car', 'grid', 'stickers'], function (tabName, tabIndex) {
+ $('')
+ .on('mousedown', function (e) {
+ self.selectTab(tabIndex);
+ return cancelEvent(e);
+ })
+ .appendTo(self.tabsEl);
+ });
+
+ this.contentEl.on('mousedown', function (e) {
+ e = e.originalEvent || e;
+ var target = $(e.target), code;
+ if (target.hasClass('emoji')) {
+ target = $(target[0].parentNode);
+ }
+ if (code = target.attr('data-code')) {
+ if (self.onEmojiSelected) {
+ self.onEmojiSelected(code);
+ }
+ EmojiHelper.pushPopularEmoji(code);
+ }
+ return cancelEvent(e);
+ });
+
+ this.tooltipEl.on('mouseenter mouseleave', function (e) {
+ console.log(dT(), e.type);
+ if (e.type == 'mouseenter') {
+ self.onMouseEnter();
+ } else {
+ self.onMouseLeave();
+ }
+ });
+
+ this.selectTab(0);
+
+ return true;
+}
+
+
+EmojiTooltip.prototype.selectTab = function (tab) {
+ if (this.tab === tab) {
+ return false;
+ }
+ $('.active', this.tabsEl).removeClass('active');
+ this.tab = tab;
+ $(this.tabsEl[0].childNodes[tab]).addClass('active');
+
+ this.updateTabContents();
+};
+
+EmojiTooltip.prototype.updateTabContents = function (tab) {
+ var html = [];
+ var self = this;
+ var iconSize = Config.Mobile ? 26 : 20;
+
+ if (this.tab > 0) {
+ var categoryIndex = this.tab - 1;
+ var emoticonCodes = Config.EmojiCategories[categoryIndex];
+ var totalColumns = Config.EmojiCategorySpritesheetDimens[categoryIndex][1];
+ var count = emoticonCodes.length;
+ var emoticonCode, emoticonData, i, x, y;
+
+ for (i = 0; i < count; i++) {
+ emoticonCode = emoticonCodes[i];
+ emoticonData = Config.Emoji[emoticonCode];
+ x = iconSize * (i % totalColumns);
+ y = iconSize * Math.floor(i / totalColumns);
+ html.push('');
+ }
+ this.contentEl.html(html.join(''));
+ }
+ else {
+ EmojiHelper.getPopularEmoji(function (popularEmoji) {
+ var emoticonCode, emoticonData, spritesheet, pos, categoryIndex;
+ var count = popularEmoji.length;
+ var i, x, y;
+
+ for (i = 0; i < count; i++) {
+ emoticonCode = popularEmoji[i].code;
+ if (emoticonData = Config.Emoji[emoticonCode]) {
+ spritesheet = EmojiHelper.spritesheetPositions[emoticonCode];
+ categoryIndex = spritesheet[0];
+ pos = spritesheet[1];
+ x = iconSize * spritesheet[3];
+ y = iconSize * spritesheet[2];
+ html.push('');
+ }
+ }
+ self.contentEl.html(html.join(''));
+ });
+ }
+};
+
+EmojiTooltip.prototype.updatePosition = function () {
+ var offset = this.btnEl.offset();
+ this.tooltipEl.css({top: offset.top, left: offset.left});
+};
+
+EmojiTooltip.prototype.show = function () {
+ this.updatePosition();
+ this.tooltipEl.show();
+ delete this.showTimeout;
+};
+
+EmojiTooltip.prototype.hide = function () {
+ this.tooltipEl.hide();
+ delete this.hideTimeout;
+};
+
+
+
+
+function EmojiPanel (containerEl, options) {
+ options = options || {};
+ // var self = this;
+
+ this.containerEl = $(containerEl);
+ this.onEmojiSelected = options.onEmojiSelected;
+
+ this.containerEl.on('mousedown', function (e) {
+ e = e.originalEvent || e;
+ var target = $(e.target), code;
+ if (target.hasClass('emoji')) {
+ target = $(target[0].parentNode);
+ }
+ if (code = target.attr('data-code')) {
+ if (self.onEmojiSelected) {
+ self.onEmojiSelected(code);
+ }
+ EmojiHelper.pushPopularEmoji(code);
+ }
+ return cancelEvent(e);
+ });
+
+ this.update();
+}
+
+EmojiPanel.prototype.update = function () {
+ var html = [];
+ var self = this;
+ var iconSize = Config.Mobile ? 26 : 20;
+
+ EmojiHelper.getPopularEmoji(function (popularEmoji) {
+ var emoticonCode, emoticonData, spritesheet, pos, categoryIndex;
+ var count = popularEmoji.length;
+ var i, x, y;
+
+ for (i = 0; i < count; i++) {
+ emoticonCode = popularEmoji[i].code;
+ if (emoticonData = Config.Emoji[emoticonCode]) {
+ spritesheet = EmojiHelper.spritesheetPositions[emoticonCode];
+ categoryIndex = spritesheet[0];
+ pos = spritesheet[1];
+ x = iconSize * spritesheet[3];
+ y = iconSize * spritesheet[2];
+ html.push('');
+ }
+ }
+ self.containerEl.html(html.join(''));
+ });
+}
+
+
+
+
+
+function MessageComposer (textarea, options) {
+ this.textareaEl = $(textarea);
+
+ this.textareaEl.on('keyup keydown', this.onKeyEvent.bind(this));
+ this.textareaEl.on('focus blur', this.onFocusBlur.bind(this));
+
+ this.isActive = false;
+}
+
+MessageComposer.prototype.onKeyEvent = function (e) {
+ var self = this;
+ if (e.type == 'keyup') {
+ this.checkAutocomplete();
+ }
+}
+
+MessageComposer.prototype.checkAutocomplete = function (e) {
+ var pos = getFieldSelection(e.target);
+ var value = this.textareaEl[0].value.substr(0, pos);
+ var matches = value.match(/:([A-Za-z_]*)$/);
+ if (matches) {
+ if (matches[1]) {
+ var found = EmojiHelper.searchEmojis(matches[1]);
+ self.showEmojiSuggestions(found);
+ } else {
+ EmojiHelper.getPopularEmoji(function (found) {
+ self.showEmojiSuggestions(found);
+ });
+ }
+ }
+ else {
+ self.hideSuggestions();
+ }
+}
+
+MessageComposer.prototype.onFocusBlur = function (e) {
+ this.isActive = e.type == 'focus';
+
+ if (!this.isActive) {
+ this.hideSuggestions();
+ }
+}
+
+
+MessageComposer.prototype.showEmojiSuggestions = function (codes) {
+ this.autocompleteShown = true;
+}
+
+MessageComposer.prototype.hideSuggestions = function () {
+ delete this.autocompleteShown;
+}
diff --git a/app/js/services.js b/app/js/services.js
index 9229ec7d..1d7aa89d 100644
--- a/app/js/services.js
+++ b/app/js/services.js
@@ -11,7 +11,7 @@
angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
-.service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, $q, qSync, MtpApiFileManager, MtpApiManager, RichTextProcessor, SearchIndexManager, ErrorService, Storage, _) {
+.service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, $q, qSync, MtpApiFileManager, MtpApiManager, RichTextProcessor, ErrorService, Storage, _) {
var users = {},
usernames = {},
cachedPhotoLocations = {},
@@ -507,7 +507,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
})
-.service('AppChatsManager', function ($rootScope, $modal, _, MtpApiFileManager, MtpApiManager, AppUsersManager, RichTextProcessor, SearchIndexManager) {
+.service('AppChatsManager', function ($rootScope, $modal, _, MtpApiFileManager, MtpApiManager, AppUsersManager, RichTextProcessor) {
var chats = {},
cachedPhotoLocations = {};
@@ -687,7 +687,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
})
-.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager, PeersSelectService, Storage, FileManager, TelegramMeWebService, StatusManager, _) {
+.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, FileManager, TelegramMeWebService, StatusManager, _) {
var messagesStorage = {};
var messagesForHistory = {};
diff --git a/app/partials/desktop/emoji_btn_tooltip.html b/app/partials/desktop/emoji_btn_tooltip.html
new file mode 100644
index 00000000..51354a1b
--- /dev/null
+++ b/app/partials/desktop/emoji_btn_tooltip.html
@@ -0,0 +1,26 @@
+
\ No newline at end of file
diff --git a/app/partials/desktop/im.html b/app/partials/desktop/im.html
index 01e3cc84..c152e5fc 100644
--- a/app/partials/desktop/im.html
+++ b/app/partials/desktop/im.html
@@ -171,14 +171,13 @@
-
diff --git a/app/webogram.appcache b/app/webogram.appcache
index a43a10bd..9802e602 100644
--- a/app/webogram.appcache
+++ b/app/webogram.appcache
@@ -1,6 +1,6 @@
CACHE MANIFEST
-# 55
+# 57
NETWORK:
*