Browse Source

Added basic support for webpages

master
Igor Zhukov 10 years ago
parent
commit
22f95ec5b1
  1. 7
      app/js/directives.js
  2. 140
      app/js/services.js
  3. 34
      app/less/app.less
  4. 4
      app/partials/desktop/message.html
  5. 50
      app/partials/desktop/message_attach_webpage.html

7
app/js/directives.js

@ -457,12 +457,15 @@ angular.module('myApp.directives', ['myApp.filters'])
templateUrl: templateUrl('message_attach_contact') templateUrl: templateUrl('message_attach_contact')
}; };
}) })
.directive('myMessageWebpage', function() { .directive('myMessageWebpage', function(AppPhotosManager) {
return { return {
scope: { scope: {
'webpage': '=myMessageWebpage' 'webpage': '=myMessageWebpage'
}, },
templateUrl: templateUrl('message_attach_webpage') templateUrl: templateUrl('message_attach_webpage'),
link: function ($scope) {
$scope.openPhoto = AppPhotosManager.openPhoto;
}
}; };
}) })
.directive('myMessagePending', function() { .directive('myMessagePending', function() {

140
app/js/services.js

@ -792,7 +792,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, PeersSelectService, Storage, FileManager, TelegramMeWebService, StatusManager, _) { .service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, AppWebPagesManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, FileManager, TelegramMeWebService, StatusManager, _) {
var messagesStorage = {}; var messagesStorage = {};
var messagesForHistory = {}; var messagesForHistory = {};
@ -802,7 +802,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var pendingByRandomID = {}; var pendingByRandomID = {};
var pendingByMessageID = {}; var pendingByMessageID = {};
var pendingAfterMsgs = {}; var pendingAfterMsgs = {};
var pendingWebPages = {};
var sendFilePromise = $q.when(); var sendFilePromise = $q.when();
var tempID = -1; var tempID = -1;
@ -1399,16 +1398,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
AppAudioManager.saveAudio(apiMessage.media.audio); AppAudioManager.saveAudio(apiMessage.media.audio);
break; break;
case 'messageMediaWebPage': case 'messageMediaWebPage':
var webpage = apiMessage.media.webpage; AppWebPagesManager.saveWebPage(apiMessage.media.webpage);
if (webpage.photo && webpage.photo._ === 'photo') {
AppPhotosManager.savePhoto(webpage.photo);
} else {
delete webpage.photo;
}
if (pendingWebPages[webpage.id] === undefined) {
pendingWebPages[webpage.id] = {};
}
pendingWebPages[webpage.id][apiMessage.id] = true;
break; break;
} }
} }
@ -1978,9 +1968,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
break; break;
case 'messageMediaWebPage': case 'messageMediaWebPage':
if (message.media.webpage.photo) { message.media.webpage = AppWebPagesManager.wrapForHistory(message.media.webpage.id);
message.media.webpage.photo = AppPhotosManager.wrapForHistory(message.media.webpage.photo.id, {website: true});
}
break; break;
} }
} }
@ -2504,32 +2492,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
}); });
break; break;
case 'updateWebPage':
console.log('webpage update', update);
var webpage = update.webpage;
if (pendingWebPages[webpage.id] !== undefined) {
var message, historyMessage;
angular.forEach(pendingWebPages[webpage.id], function (t, msgID) {
if (message = messagesStorage[msgID]) {
message.media = {
_: 'messageMediaWebPage',
webpage: webpage
};
}
if (historyMessage = messagesForHistory[msgID]) {
if (webpage.photo) {
AppPhotosManager.savePhoto(webpage.photo);
webpage.photo = AppPhotosManager.wrapForHistory(webpage.photo.id, {website: true});
}
historyMessage.media = {
_: 'messageMediaWebPage',
webpage: webpage
};
}
});
}
break;
} }
}); });
@ -2795,6 +2757,66 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
}) })
.service('AppWebPagesManager', function ($modal, $window, $rootScope, MtpApiManager, AppPhotosManager, RichTextProcessor) {
var webpages = {};
var pendingWebPages = {};
function saveWebPage (apiWebPage, messageID) {
if (apiWebPage.photo && apiWebPage.photo._ === 'photo') {
AppPhotosManager.savePhoto(apiWebPage.photo);
} else {
delete apiWebPage.photo;
}
apiWebPage.rTitle = RichTextProcessor.wrapRichText(
apiWebPage.title || apiWebPage.author,
{noLinks: true, noLinebreaks: true}
);
apiWebPage.rDescription = RichTextProcessor.wrapRichText(
apiWebPage.description, {
contextSite: apiWebPage.site_name || 'external'
}
);
if (messageID) {
if (pendingWebPages[webpage.id] === undefined) {
pendingWebPages[webpage.id] = {};
}
pendingWebPages[webpage.id][messageID] = true;
webpages[apiWebPage.id] = apiWebPage;
}
if (webpages[apiWebPage.id] === undefined) {
webpages[apiWebPage.id] = apiWebPage;
} else {
safeReplaceObject(webpages[apiWebPage.id], apiWebPage);
}
};
$rootScope.$on('apiUpdate', function (e, update) {
switch (update._) {
case 'updateWebPage':
saveWebPage(update.webpage);
break;
}
});
function wrapForHistory (webPageID) {
var webPage = angular.copy(webpages[webPageID]) || {_: 'webPageEmpty'};
if (webPage.photo && webPage.photo.id) {
webPage.photo = AppPhotosManager.wrapForHistory(webPage.photo.id, {website: webPage.type != 'photo' && webPage.type != 'video'});
}
return webPage;
}
return {
saveWebPage: saveWebPage,
wrapForHistory: wrapForHistory
}
})
.service('AppVideoManager', function ($sce, $rootScope, $modal, $window, MtpApiFileManager, AppUsersManager, FileManager, qSync) { .service('AppVideoManager', function ($sce, $rootScope, $modal, $window, MtpApiFileManager, AppUsersManager, FileManager, qSync) {
var videos = {}, var videos = {},
@ -3820,6 +3842,17 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var soundcloudRegex = /^https?:\/\/(?:soundcloud\.com|snd\.sc)\/([a-zA-Z0-9%\-\_]+)\/([a-zA-Z0-9%\-\_]+)/i; var soundcloudRegex = /^https?:\/\/(?:soundcloud\.com|snd\.sc)\/([a-zA-Z0-9%\-\_]+)\/([a-zA-Z0-9%\-\_]+)/i;
var spotifyRegex = /(https?:\/\/(open\.spotify\.com|play\.spotify\.com|spoti\.fi)\/(.+)|spotify:(.+))/i; var spotifyRegex = /(https?:\/\/(open\.spotify\.com|play\.spotify\.com|spoti\.fi)\/(.+)|spotify:(.+))/i;
var siteHashtags = {
Telegram: '#/im?q=%23{1}',
Twitter: 'https://twitter.com/hashtag/{1}',
Instagram: 'https://instagram.com/explore/tags/{1}/'
};
var siteMentions = {
Telegram: '#/im?p=%40{1}',
Twitter: 'https://twitter.com/{1}',
Instagram: 'https://instagram.com/{1}/'
};
return { return {
wrapRichText: wrapRichText, wrapRichText: wrapRichText,
@ -3852,6 +3885,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
raw = text, raw = text,
html = [], html = [],
url, url,
contextSite = options.contextSite || 'Telegram',
contextExternal = contextSite != 'Telegram',
emojiFound = false, emojiFound = false,
emojiTitle, emojiTitle,
emojiCoords; emojiCoords;
@ -3862,7 +3897,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
html.push(encodeEntities(raw.substr(0, match.index))); html.push(encodeEntities(raw.substr(0, match.index)));
if (match[3]) { // telegram.me links if (match[3]) { // telegram.me links
if (!options.noLinks) { var contextUrl = !options.noLinks && siteMentions[contextSite];
if (match[2] != '@' && contextExternal) {
contextUrl = false;
}
if (contextUrl) {
var attr = ''; var attr = '';
if (options.highlightUsername && if (options.highlightUsername &&
options.highlightUsername.toLowerCase() == match[3].toLowerCase() && options.highlightUsername.toLowerCase() == match[3].toLowerCase() &&
@ -3871,8 +3910,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
html.push( html.push(
match[1], match[1],
'<a ' + attr + ' href="#/im?p=', '<a ',
encodeURIComponent('@' + match[3]), attr,
contextExternal ? ' target="_blank" ' : '',
' href="',
contextUrl.replace('{1}', encodeURIComponent(match[3])),
'">', '">',
encodeEntities(match[2] + match[3]), encodeEntities(match[2] + match[3]),
'</a>' '</a>'
@ -3970,11 +4012,15 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
} }
else if (match[10]) { else if (match[10]) {
if (!options.noLinks) { var contextUrl = !options.noLinks && siteHashtags[contextSite];
if (contextUrl) {
html.push( html.push(
encodeEntities(match[9]), encodeEntities(match[9]),
'<a href="#/im?q=', '<a ',
encodeURIComponent(match[10]), contextExternal ? ' target="_blank" ' : '',
'href="',
contextUrl.replace('{1}', encodeURIComponent(match[10].substr(1)))
,
'">', '">',
encodeEntities(match[10]), encodeEntities(match[10]),
'</a>' '</a>'

34
app/less/app.less

@ -1491,6 +1491,40 @@ div.im_message_video_thumb {
} }
} }
.im_message_webpage_wrap {
margin: 3px 0 3px;
border-left: 2px solid #7eaad1;
padding-left: 12px;
}
.im_message_webpage_site {
color: #999;
font-weight: normal;
line-height: 120%;
margin-bottom: 3px;
}
.im_message_webpage_title {
font-weight: bold;
// margin-right: 4px;
}
.icon-circle {
display: none;
// display: inline-block;
width: 0.5em;
height: 0.5em;
border-radius: 0.5em;
background: #999;
overflow: hidden;
vertical-align: middle;
margin: -2px 3px 0;
}
.im_message_webpage_description {
margin: 2px 0 2px;
}
.im_message_article_thumb {
margin: 5px 0 5px 5px;
}
.im_message_video_embed { .im_message_video_embed {
padding-bottom: 56.25%; /* 16/9 ratio */ padding-bottom: 56.25%; /* 16/9 ratio */
} }

4
app/partials/desktop/message.html

@ -51,7 +51,7 @@
</div> </div>
<div class="im_message_text" ng-if="::historyMessage.message.length || false" ng-bind-html="::historyMessage.richMessage" dir="auto"></div> <div class="im_message_text" ng-if="::historyMessage.message.length || false" ng-bind-html="::historyMessage.richMessage" dir="auto"></div>
<div class="im_message_external_embed_wrap" ng-if="::historyMessage.richUrlEmbed || false" my-external-embed="historyMessage.richUrlEmbed"></div> <!-- <div class="im_message_external_embed_wrap" ng-if="::historyMessage.richUrlEmbed || false" my-external-embed="historyMessage.richUrlEmbed"></div> -->
<div ng-if="::historyMessage.media || historyMessage.id < 0 ? true : false" class="im_message_media" ng-switch="historyMessage.media._"> <div ng-if="::historyMessage.media || historyMessage.id < 0 ? true : false" class="im_message_media" ng-switch="historyMessage.media._">
<div ng-switch-when="messageMediaPhoto" my-message-photo></div> <div ng-switch-when="messageMediaPhoto" my-message-photo></div>
@ -60,7 +60,7 @@
<div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio"></div> <div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio"></div>
<div ng-switch-when="messageMediaGeo" my-message-map></div> <div ng-switch-when="messageMediaGeo" my-message-map></div>
<div ng-switch-when="messageMediaContact" class="im_message_contact" my-message-contact></div> <div ng-switch-when="messageMediaContact" class="im_message_contact" my-message-contact></div>
<!-- <div ng-switch-when="messageMediaWebPage" class="im_message_webpage" my-message-webpage="historyMessage.media.webpage"></div> --> <div ng-switch-when="messageMediaWebPage" class="im_message_webpage" my-message-webpage="historyMessage.media.webpage"></div>
<div ng-switch-when="messageMediaPending" my-message-pending></div> <div ng-switch-when="messageMediaPending" my-message-pending></div>
<div ng-switch-when="messageMediaUnsupported"> <div ng-switch-when="messageMediaUnsupported">
<div class="im_message_text"> <div class="im_message_text">

50
app/partials/desktop/message_attach_webpage.html

@ -1,21 +1,47 @@
<div class="im_message_document clearfix" ng-class="{im_message_document_thumbed: !!webpage.photo}" ng-if="webpage._ == 'webPage'"> <div class="im_message_webpage_wrap clearfix" ng-switch="webpage.type">
<div ng-switch-when="photo" class="im_message_webpage_photo">
<a ng-if="::webpage.photo" ng-click="docOpen()"> <div class="im_message_webpage_site" ng-bind="webpage.site_name || webpage.display_url"></div>
<div class="im_message_document_thumb_wrap"> <div class="im_message_webpage_title">
<a href="{{webpage.url}}" target="_blank" ng-bind-html="webpage.rTitle"></a>
</div>
<div ng-if="webpage.description.length" class="im_message_webpage_description" ng-bind-html="webpage.rDescription"></div>
<a class="im_message_photo_thumb" ng-click="openPhoto(webpage.photo.id, {w: webpage.id})" ng-style="::{width: webpage.photo.thumb.width + 'px'}" ng-mouseover="preloadPhoto(webpage.photo.id)">
<img <img
class="im_message_document_thumb" class="im_message_photo_thumb"
my-load-thumb my-load-thumb
thumb="webpage.photo.thumb" thumb="webpage.photo.thumb"
/> />
</a>
</div>
<div ng-switch-when="video" class="im_message_webpage_video">
<div class="im_message_webpage_site" ng-bind="webpage.site_name || webpage.display_url"></div>
<div class="im_message_webpage_title">
<a href="{{webpage.url}}" target="_blank" ng-bind-html="webpage.rTitle"></a>
</div> </div>
</a> <div ng-if="webpage.description.length" class="im_message_webpage_description" ng-bind-html="webpage.rDescription"></div>
<a class="im_message_video_thumb" ng-href="{{webpage.url}}" target="_blank" ng-style="::{width: video.thumb.width + 'px'}">
<span ng-if="webpage.duration > 0" class="im_message_video_duration" ng-bind="::webpage.duration | duration"></span>
<i class="icon icon-videoplay"></i>
<img
class="im_message_video_thumb"
my-load-thumb
thumb="webpage.photo.thumb"
/>
</a>
</div>
<div class="im_message_document_info"> <div ng-switch-default class="im_message_webpage_article">
<div class="im_message_document_name_wrap"> <div ng-if="webpage.photo" class="im_message_webpage_article_photo pull-right">
<a href="" ng-click="docOpen()" class="im_message_document_name" ng-bind="webpage.title || webpage.author"></a> <img
<span class="im_message_document_size" ng-bind="webpage.display_url"></span> class="im_message_article_thumb"
my-load-thumb
thumb="webpage.photo.thumb"
/>
</div>
<div class="im_message_webpage_site" ng-bind="webpage.site_name"></div>
<div class="im_message_webpage_title">
<a href="{{webpage.url}}" target="_blank" ng-bind-html="webpage.rTitle"></a>
</div> </div>
<div class="im_message_website_description" ng-bind="webpage.description"></div> <div ng-if="webpage.description.length" class="im_message_webpage_description" ng-bind-html="webpage.rDescription"></div>
</div> </div>
</div> </div>
Loading…
Cancel
Save