/ * !
* Webogram v0 . 1 - messaging web application for MTProto
* https : //github.com/zhukov/webogram
* Copyright ( C ) 2014 Igor Zhukov < igor . beatle @ gmail . com >
* https : //github.com/zhukov/webogram/blob/master/LICENSE
* /
'use strict' ;
/* Directives */
angular . module ( 'myApp.directives' , [ 'myApp.filters' ] )
. directive ( 'myDialog' , function ( ) {
return {
restrict : 'AE' ,
scope : true ,
translude : false ,
templateUrl : 'partials/dialog.html?4'
} ;
} )
. directive ( 'myMessage' , function ( ) {
return {
restrict : 'AE' ,
scope : true ,
translude : false ,
templateUrl : 'partials/message.html?6'
} ;
} )
. directive ( 'myDialogsList' , function ( $window , $timeout ) {
return {
link : link
} ;
function link ( scope , element , attrs ) {
// console.log('init directive', element);
var dialogsWrap = $ ( '.im_dialogs_wrap' , element ) [ 0 ] ,
scrollableWrap = $ ( '.im_dialogs_scrollable_wrap' , element ) [ 0 ] ,
// dialogsSearch = $('im_dialogs_search', element)[0],
moreNotified = false ;
onContentLoaded ( function ( ) {
$ ( dialogsWrap ) . nanoScroller ( { preventPageScrolling : true , tabIndex : - 1 } ) ;
} ) ;
var updateScroller = function ( ) {
onContentLoaded ( function ( ) {
$ ( dialogsWrap ) . nanoScroller ( ) ;
} ) ;
}
scope . $on ( 'ui_dialogs_prepend' , updateScroller ) ;
scope . $on ( 'ui_dialogs_append' , function ( ) {
onContentLoaded ( function ( ) {
updateScroller ( ) ;
moreNotified = false ;
} ) ;
} ) ;
scope . $on ( 'ui_dialogs_change' , function ( ) {
onContentLoaded ( function ( ) {
updateScroller ( ) ;
moreNotified = false ;
} ) ;
} ) ;
$ ( scrollableWrap ) . on ( 'scroll' , function ( e ) {
// console.log('scroll', moreNotified);
if ( ! moreNotified && scrollableWrap . scrollTop >= scrollableWrap . scrollHeight - scrollableWrap . clientHeight - 300 ) {
// console.log('emit need more');
scope . $emit ( 'dialogs_need_more' ) ;
moreNotified = true ;
}
} ) ;
function updateSizes ( ) {
$ ( element ) . css ( {
height : $ ( $window ) . height ( ) - 162
} ) ;
}
$ ( $window ) . on ( 'resize' , updateSizes ) ;
updateSizes ( ) ;
} ;
} )
. directive ( 'myHistory' , function ( $window , $timeout ) {
return {
link : link
} ;
function link ( scope , element , attrs ) {
var historyWrap = $ ( '.im_history_wrap' , element ) [ 0 ] ,
historyEl = $ ( '.im_history' , element ) [ 0 ] ,
scrollableWrap = $ ( '.im_history_scrollable_wrap' , element ) [ 0 ] ,
scrollable = $ ( '.im_history_scrollable' , element ) [ 0 ] ,
panelWrap = $ ( '.im_history_panel_wrap' , element ) [ 0 ] ,
sendPanelWrap = $ ( '.im_send_panel_wrap' , element ) [ 0 ] ,
sendFormWrap1 = $ ( '.im_send_form_wrap1' , element ) [ 0 ] ,
sendFormWrap = $ ( '.im_send_form_wrap' , element ) [ 0 ] ,
moreNotified = false ;
onContentLoaded ( function ( ) {
scrollableWrap . scrollTop = scrollableWrap . scrollHeight ;
$ ( historyWrap ) . nanoScroller ( { preventPageScrolling : true , tabIndex : - 1 } ) ;
} ) ;
var updateScroller = function ( delay ) {
$timeout ( function ( ) {
if ( ! $ ( scrollableWrap ) . hasClass ( 'im_history_to_bottom' ) ) {
$ ( historyWrap ) . nanoScroller ( ) ;
}
} , delay || 0 ) ;
}
var animated = true ,
curAnimation = false ;
scope . $on ( 'ui_history_append' , function ( e , options ) {
if ( ! atBottom && ! options . my ) {
return ;
}
if ( animated ) {
$ ( scrollableWrap ) . stop ( ) ;
} else {
$ ( scrollable ) . css ( { bottom : 0 } ) ;
$ ( scrollableWrap ) . addClass ( 'im_history_to_bottom' ) ;
}
onContentLoaded ( function ( ) {
if ( animated ) {
curAnimation = true ;
$ ( scrollableWrap ) . stop ( ) . animate ( {
scrollTop : scrollableWrap . scrollHeight - scrollableWrap . clientHeight
} , {
duration : 200 ,
always : function ( ) {
updateScroller ( ) ;
curAnimation = false ;
}
} ) ;
updateScroller ( ) ;
} else {
$ ( scrollableWrap ) . removeClass ( 'im_history_to_bottom' ) ;
$ ( scrollable ) . css ( { bottom : '' } ) ;
scrollableWrap . scrollTop = scrollableWrap . scrollHeight ;
$ ( historyWrap ) . nanoScroller ( ) ;
}
} ) ;
} ) ;
scope . $on ( 'ui_history_change' , function ( ) {
$ ( scrollableWrap ) . addClass ( 'im_history_to_bottom' ) ;
$ ( scrollable ) . css ( { bottom : 0 } ) ;
onContentLoaded ( function ( ) {
$ ( scrollableWrap ) . removeClass ( 'im_history_to_bottom' ) ;
$ ( scrollable ) . css ( { bottom : '' } ) ;
updateSizes ( ) ;
scrollableWrap . scrollTop = scrollableWrap . scrollHeight ;
updateScroller ( ) ;
moreNotified = false ;
} ) ;
} ) ;
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 ,
st = scrollableWrap . scrollTop ,
ch = scrollableWrap . clientHeight ;
$ ( scrollableWrap ) . addClass ( 'im_history_to_bottom' ) ;
$ ( scrollable ) . css ( { bottom : - ( sh - st - ch ) } ) ;
onContentLoaded ( function ( ) {
$ ( scrollableWrap ) . removeClass ( 'im_history_to_bottom' ) ;
$ ( scrollable ) . css ( { bottom : '' } ) ;
scrollableWrap . scrollTop = st + scrollableWrap . scrollHeight - sh ;
updateScroller ( ) ;
moreNotified = false ;
} ) ;
} ) ;
scope . $on ( 'ui_editor_change' , function ( e , data ) {
if ( data . start ) {
if ( ! $ ( sendPanelWrap ) . hasClass ( 'im_panel_fixed_bottom' ) ) {
sendFormWrap1 . style . height = sendFormWrap . offsetHeight + 'px' ;
$ ( sendPanelWrap ) . addClass ( 'im_panel_fixed_bottom' ) ;
}
} else {
sendFormWrap1 . style . height = 'auto' ;
$ ( sendPanelWrap ) . removeClass ( 'im_panel_fixed_bottom' ) ;
}
} ) ;
scope . $on ( 'ui_editor_resize' , updateSizes ) ;
var atBottom = true ;
$ ( scrollableWrap ) . on ( 'scroll' , function ( e ) {
if ( $ ( scrollableWrap ) . hasClass ( 'im_history_to_bottom' ) ) {
return cancelEvent ( e ) ;
}
if ( curAnimation ) {
return ;
}
atBottom = scrollableWrap . scrollTop >= scrollableWrap . scrollHeight - scrollableWrap . clientHeight ;
if ( ! moreNotified && scrollableWrap . scrollTop <= 300 ) {
moreNotified = true ;
scope . $emit ( 'history_need_more' ) ;
}
} ) ;
function updateSizes ( heightOnly ) {
$ ( historyWrap ) . css ( {
height : $ ( $window ) . height ( ) - panelWrap . offsetHeight - sendPanelWrap . offsetHeight - 90
} ) ;
$ ( historyEl ) . css ( {
minHeight : $ ( $window ) . height ( ) - panelWrap . offsetHeight - sendPanelWrap . offsetHeight - 90 - 44
} ) ;
if ( heightOnly == true ) return ;
if ( atBottom ) {
onContentLoaded ( function ( ) {
scrollableWrap . scrollTop = scrollableWrap . scrollHeight ;
updateScroller ( ) ;
// $(historyWrap).nanoScroller({scroll: 'bottom'});
} ) ;
}
updateScroller ( 100 ) ;
}
$ ( $window ) . on ( 'resize' , updateSizes ) ;
onContentLoaded ( updateSizes ) ;
}
} )
. directive ( 'mySendForm' , function ( $timeout ) {
return {
link : link ,
scope : {
draftMessage : '='
}
} ;
function link ( scope , element , attrs ) {
var messageField = $ ( 'textarea' , element ) [ 0 ] ,
fileSelects = $ ( 'input' , element ) ,
dropbox = $ ( '.im_send_dropbox_wrap' , element ) [ 0 ] ,
emojiButton = $ ( '.im_emoji_btn' , element ) [ 0 ] ,
editorElement = messageField ,
dragStarted , dragTimeout ,
emojiArea = $ ( messageField ) . emojiarea ( { button : emojiButton , norealTime : true } ) ,
emojiMenu = $ ( '.emoji-menu' , element ) [ 0 ] ,
richTextarea = $ ( '.emoji-wysiwyg-editor' , element ) [ 0 ] ;
if ( richTextarea ) {
editorElement = richTextarea ;
$ ( richTextarea ) . addClass ( 'form-control' ) ;
$ ( richTextarea ) . attr ( 'placeholder' , $ ( messageField ) . attr ( 'placeholder' ) ) ;
var updatePromise ;
$ ( richTextarea ) . on ( 'keyup' , function ( e ) {
scope . $emit ( 'ui_editor_change' , { start : false } ) ;
updateHeight ( ) ;
scope . draftMessage . text = richTextarea . innerText ;
$timeout . cancel ( updatePromise ) ;
updatePromise = $timeout ( updateValue , 1000 ) ;
} ) ;
}
fileSelects . on ( 'change' , function ( ) {
var self = this ;
scope . $apply ( function ( ) {
scope . draftMessage . files = Array . prototype . slice . call ( self . files ) ;
scope . draftMessage . isMedia = $ ( self ) . hasClass ( 'im_media_attach_input' ) ;
setTimeout ( function ( ) {
try {
self . value = '' ;
} catch ( e ) { } ;
} , 1000 ) ;
} ) ;
} ) ;
var sendOnEnter = true ;
$ ( editorElement ) . on ( 'keydown' , function ( e ) {
if ( e . keyCode == 13 ) {
var submit = false ;
if ( sendOnEnter && ! e . shiftKey ) {
submit = true ;
} else if ( ! sendOnEnter && ( e . ctrlKey || e . metaKey ) ) {
submit = true ;
}
if ( submit ) {
scope . $emit ( 'ui_editor_change' , { start : false } ) ;
updateHeight ( ) ;
$ ( element ) . trigger ( 'submit' ) ;
return cancelEvent ( e ) ;
}
}
if ( richTextarea ) {
scope . $emit ( 'ui_editor_change' , { start : true } ) ;
updateHeight ( ) ;
}
} ) ;
var lastTyping = 0 ;
$ ( editorElement ) . on ( 'keyup' , function ( e ) {
var now = + new Date ( ) ;
if ( now - lastTyping < 5000 ) {
return ;
}
lastTyping = now ;
scope . $emit ( 'ui_typing' ) ;
} ) ;
function updateField ( ) {
if ( richTextarea ) {
$timeout . cancel ( updatePromise ) ;
var html = $ ( '<div>' ) . text ( scope . draftMessage . text || '' ) . html ( ) ;
html = html . replace ( /\n/g , '<br/>' ) ;
$ ( richTextarea ) . html ( html ) ;
updateHeight ( ) ;
}
}
function updateValue ( ) {
if ( richTextarea ) {
$ ( richTextarea ) . trigger ( 'change' ) ;
updateHeight ( ) ;
}
}
var height = richTextarea . offsetHeight ;
function updateHeight ( ) {
var newHeight = richTextarea . offsetHeight ;
if ( height != newHeight ) {
height = newHeight ;
scope . $emit ( 'ui_editor_change' , { start : false } ) ;
scope . $emit ( 'ui_editor_resize' ) ;
}
} ;
$ ( '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 ) ;
scope . $on ( 'ui_message_before_send' , updateValue ) ;
scope . $on ( '$destroy' , function cleanup ( ) {
$ ( 'body' ) . off ( 'dragenter dragleave dragover drop' , onDragDropEvent ) ;
} ) ;
focusField ( ) ;
function focusField ( ) {
onContentLoaded ( function ( ) {
editorElement . focus ( ) ;
} ) ;
}
function onDragDropEvent ( e ) {
var dragStateChanged = false ;
if ( ! dragStarted || dragStarted == 1 ) {
dragStarted = checkDragEvent ( e ) ? 2 : 1 ;
dragStateChanged = true ;
}
if ( dragStarted == 2 ) {
if ( dragTimeout ) {
setTimeout ( function ( ) {
clearTimeout ( dragTimeout ) ;
dragTimeout = false ;
} , 0 ) ;
}
if ( e . type == 'dragenter' || e . type == 'dragover' ) {
if ( dragStateChanged ) {
$ ( dropbox )
. css ( { height : $ ( editorElement ) . height ( ) + 12 , width : $ ( editorElement ) . width ( ) + 12 } )
. show ( ) ;
}
} else {
if ( e . type == 'drop' ) {
scope . $apply ( function ( ) {
scope . draftMessage . files = Array . prototype . slice . call ( e . originalEvent . dataTransfer . files ) ;
scope . draftMessage . isMedia = false ;
} ) ;
}
dragTimeout = setTimeout ( function ( ) {
$ ( dropbox ) . hide ( ) ;
dragStarted = false ;
dragTimeout = false ;
} , 300 ) ;
}
}
return cancelEvent ( e ) ;
} ;
}
} )
. directive ( 'myLoadThumb' , function ( MtpApiFileManager ) {
return {
link : link ,
scope : {
thumb : '='
}
} ;
function link ( scope , element , attrs ) {
var counter = 0 ;
var cachedSrc = MtpApiFileManager . getCachedFile ( scope . thumb && scope . thumb . location ) ;
if ( cachedSrc ) {
element . attr ( 'src' , cachedSrc ) ;
}
scope . $watch ( 'thumb.location' , function ( newLocation ) {
var counterSaved = ++ counter ;
if ( ! newLocation ) {
element . attr ( 'src' , scope . thumb && scope . thumb . placeholder || 'img/blank.gif' ) ;
return ;
}
var cachedSrc = MtpApiFileManager . getCachedFile ( newLocation ) ;
if ( cachedSrc ) {
element . attr ( 'src' , cachedSrc ) ;
return ;
}
element . attr ( 'src' , scope . thumb . placeholder || 'img/blank.gif' ) ;
MtpApiFileManager . downloadSmallFile ( scope . thumb . location , scope . thumb . size ) . then ( function ( url ) {
if ( counterSaved == counter ) {
element . attr ( 'src' , url ) ;
}
} , function ( e ) {
console . log ( 'Download image failed' , e , scope . thumb . location ) ;
if ( counterSaved == counter ) {
element . attr ( 'src' , scope . thumb . placeholder || 'img/blank.gif' ) ;
}
} ) ;
} )
}
} )
. directive ( 'myLoadFullPhoto' , function ( MtpApiFileManager ) {
return {
link : link ,
transclude : true ,
template :
'<div class="img_fullsize_with_progress_wrap" ng-style="{width: fullPhoto.width + \'px\', height: fullPhoto.height + \'px\' } " > \
< div class = "img_fullsize_progress_overlay" ng - show = "progress.enabled" > \
< div class = "img_fullsize_progress_wrap" ng - style = "{width: fullPhoto.width + \'px\', height: fullPhoto.height + \'px\'}" > \
< div class = "img_fullsize_progress progress tg_progress" > \
< div class = "progress-bar progress-bar-success" role = "progressbar" aria - valuenow = "{{progress.percent}}" aria - valuemin = "0" aria - valuemax = "100" style = "width: {{progress.percent}}%" > \
< span class = "sr-only" > { { progress . percent } } % Complete ( success ) < / s p a n > \
< / d i v > \
< / d i v > \
< / d i v > \
< / d i v > \
< div class = "photo_full_wrap" > \
< a class = "photo_modal_image" > \
< img class = "photo_modal_image" width = "{{fullPhoto.width}}" height = "{{fullPhoto.height}}" / > \
< / a > \
< / d i v > \
< div class = "photo_modal_error_wrap" ng - if = "error" > \
< div class = "photo_modal_error" ng - if = "error.html" ng - bind - html = "error.html" > < / d i v > \
< div class = "photo_modal_error" ng - if = "error.text" > { { error . text } } < / d i v > \
< / d i v > \
< / d i v > ' ,
scope : {
fullPhoto : '=' ,
thumbLocation : '='
}
} ;
function link ( scope , element , attrs ) {
var imgElement = $ ( 'img' , element ) ;
imgElement
. attr ( 'src' , MtpApiFileManager . getCachedFile ( scope . thumbLocation ) || 'img/blank.gif' )
. addClass ( 'thumb_blurred' )
. addClass ( 'thumb_blur_animation' ) ;
if ( ! scope . fullPhoto . location ) {
return ;
}
var apiPromise ;
if ( scope . fullPhoto . size ) {
var inputLocation = {
_ : 'inputFileLocation' ,
volume _id : scope . fullPhoto . location . volume _id ,
local _id : scope . fullPhoto . location . local _id ,
secret : scope . fullPhoto . location . secret
} ;
apiPromise = MtpApiFileManager . downloadFile ( scope . fullPhoto . location . dc _id , inputLocation , scope . fullPhoto . size ) ;
} else {
apiPromise = MtpApiFileManager . downloadSmallFile ( scope . fullPhoto . location ) ;
}
scope . progress = { enabled : true , percent : 1 } ;
apiPromise . then ( function ( url ) {
scope . progress . enabled = false ;
imgElement
. attr ( 'src' , url )
. removeClass ( 'thumb_blurred' ) ;
} , function ( e ) {
console . log ( 'Download image failed' , e , scope . fullPhoto . location ) ;
scope . progress . enabled = false ;
if ( e && e . type == 'FS_BROWSER_UNSUPPORTED' ) {
scope . error = { html : 'Your browser doesn\'t support <a href="https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem" target="_blank">LocalFileSystem</a> feature which is needed to display this image.<br/>Please, install <a href="http://google.com/chrome" target="_blank">Google Chrome</a> or use <a href="https://telegram.org/" target="_blank">mobile app</a> instead.' } ;
} else {
scope . error = { text : 'Download failed' , error : e } ;
}
} , function ( progress ) {
scope . progress . percent = Math . max ( 1 , Math . floor ( 100 * progress . done / progress . total ) ) ;
} ) ;
}
} )
. directive ( 'myLoadVideo' , function ( $sce , MtpApiFileManager ) {
return {
link : link ,
transclude : true ,
template :
'<div class="img_fullsize_with_progress_wrap" ng-style="{width: video.full.width + \'px\', height: video.full.height + \'px\' } " > \
< div class = "img_fullsize_progress_overlay" ng - show = "progress.enabled" > \
< div class = "img_fullsize_progress_wrap" ng - style = "{width: video.full.width + \'px\', height: video.full.height + \'px\'}" > \
< div class = "img_fullsize_progress progress tg_progress" > \
< div class = "progress-bar progress-bar-success" role = "progressbar" aria - valuenow = "{{progress.percent}}" aria - valuemin = "0" aria - valuemax = "100" style = "width: {{progress.percent}}%" > \
< span class = "sr-only" > { { progress . percent } } % Complete ( success ) < / s p a n > \
< / d i v > \
< / d i v > \
< / d i v > \
< / d i v > \
< div class = "img_fullsize_wrap" ng - if = "!player.src" > \
< img \
class = "img_fullsize" \
my - load - thumb \
thumb = "video.thumb" \
width = "{{video.full.width}}" \
height = "{{video.full.height}}" \
/ > \
< / d i v > \
< div class = "video_full_player" ng - if = "player.src" > \
< embed ng - src = "{{player.src}}" width = "{{video.full.width}}" height = "{{video.full.height}}" autoplay = "true" CONTROLLER = "TRUE" loop = "false" pluginspace = "http://www.apple.com/quicktime/" ng - if = "player.quicktime" / > \
< video width = "{{video.full.width}}" height = "{{video.full.height}}" controls autoplay ng - if = "!player.quicktime" > \
< source ng - src = "{{player.src}}" type = "video/mp4" > \
< / v i d e o > \
< / d i v > \
< div class = "video_full_error_wrap" ng - if = "error" > \
< div class = "video_full_error" ng - if = "error.html" ng - bind - html = "error.html" > < / d i v > \
< div class = "video_full_error" ng - if = "error.text" > { { error . text } } < / d i v > \
< / d i v > \
< / d i v > ' ,
scope : {
video : '='
}
} ;
function link ( scope , element , attrs ) {
scope . progress = { enabled : true , percent : 1 } ;
scope . player = { } ;
var inputLocation = {
_ : 'inputVideoFileLocation' ,
id : scope . video . id ,
access _hash : scope . video . access _hash
} ;
var hasQt = false , i ;
// if (navigator.plugins) {
// for (i = 0; i < navigator.plugins.length; i++) {
// if (navigator.plugins[i].name.indexOf('QuickTime') >= 0) {
// hasQt = true;
// }
// }
// }
MtpApiFileManager . downloadFile ( scope . video . dc _id , inputLocation , scope . video . size ) . then ( function ( url ) {
scope . progress . enabled = false ;
// scope.progress = {enabled: true, percent: 50};
scope . player . quicktime = hasQt ;
scope . player . src = $sce . trustAsResourceUrl ( url ) ;
} , function ( e ) {
console . log ( 'Download video failed' , e , scope . video ) ;
scope . progress . enabled = false ;
scope . player . src = '' ;
if ( e && e . type == 'FS_BROWSER_UNSUPPORTED' ) {
scope . error = { html : 'Your browser doesn\'t support <a href="https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem" target="_blank">LocalFileSystem</a> feature which is needed to play this video.<br/>Please, install <a href="http://google.com/chrome" target="_blank">Google Chrome</a> or use <a href="https://telegram.org/" target="_blank">mobile app</a> instead.' } ;
} else {
scope . error = { text : 'Video download failed' , error : e } ;
}
} , function ( progress ) {
scope . progress . percent = Math . max ( 1 , Math . floor ( 100 * progress . done / progress . total ) ) ;
} ) ;
}
} )
. directive ( 'myMapPoint' , function ( ExternalResourcesManager ) {
return {
link : link ,
scope : {
point : '='
}
} ;
function link ( scope , element , attrs ) {
var apiKey = 'AIzaSyC32ij28dCa0YzEV_HqbWfIwTZQql-RNS0' ;
var src = 'https://maps.googleapis.com/maps/api/staticmap?sensor=false¢er=' + scope . point [ 'lat' ] + ',' + scope . point [ 'long' ] + '&zoom=13&size=200x100&scale=2&key=' + apiKey ;
ExternalResourcesManager . downloadImage ( src ) . then ( function ( url ) {
element . append ( '<img src="' + url + '" width="200" height="100"/>' ) ;
} ) ;
element . attr ( 'href' , 'https://maps.google.com/?q=' + scope . point [ 'lat' ] + ',' + scope . point [ 'long' ] ) ;
element . attr ( 'target' , '_blank' ) ;
}
} )
. directive ( 'myTypingDots' , function ( $interval ) {
return {
link : link ,
} ;
var interval ;
function link ( scope , element , attrs ) {
var promise = $interval ( function ( ) {
var time = + new Date ( ) ,
cnt = 3 ;
if ( time % 1000 <= 200 ) {
cnt = 0 ;
} else if ( time % 1000 <= 400 ) {
cnt = 1 ;
} else if ( time % 1000 <= 600 ) {
cnt = 2 ;
}
element . html ( ( new Array ( cnt + 1 ) ) . join ( '.' ) ) ;
} , 200 ) ;
scope . $on ( '$destroy' , function cleanup ( ) {
$interval . cancel ( promise ) ;
} ) ;
}
} )