@ -22,62 +22,75 @@ import PopupStickers from '../../popups/stickers';
@@ -22,62 +22,75 @@ import PopupStickers from '../../popups/stickers';
import Scrollable , { ScrollableX } from '../../scrollable' ;
import StickyIntersector from '../../stickyIntersector' ;
import { wrapSticker , wrapStickerSetThumb } from '../../wrappers' ;
import findAndSplice from '../../../helpers/array/findAndSplice' ;
import { attachClickEvent } from '../../../helpers/dom/clickEvent' ;
import positionElementByIndex from '../../../helpers/dom/positionElementByIndex' ;
import noop from '../../../helpers/noop' ;
import ButtonIcon from '../../buttonIcon' ;
import confirmationPopup from '../../confirmationPopup' ;
import VisibilityIntersector , { OnVisibilityChange } from '../../visibilityIntersector' ;
export class SuperStickerRenderer {
public lazyLoadQueue : LazyLoadQueueRepeat ;
private animatedDivs : Set < HTMLDivElement > = new Set ( ) ;
private animated : Set < HTMLElement > = new Set ( ) ;
constructor (
private regularLazyLoadQueue : LazyLoadQueue ,
private group : string ,
private managers : AppManagers
private managers : AppManagers ,
private options? : IntersectionObserverInit
) {
this . lazyLoadQueue = new LazyLoadQueueRepeat ( undefined , ( target , visible ) = > {
this . lazyLoadQueue = new LazyLoadQueueRepeat ( undefined , ( { target , visible } ) = > {
if ( ! visible ) {
this . processInvisibleDiv ( target as HTMLDivElemen t ) ;
this . processInvisible ( target ) ;
}
} ) ;
} , options ) ;
}
public clear() {
this . lazyLoadQueue . clear ( ) ;
}
public renderSticker ( doc : MyDocument , div? : HTMLDivElement , loadPromises? : Promise < any > [ ] ) {
if ( ! div ) {
div = document . createElement ( 'div' ) ;
div . classList . add ( 'grid-item' , 'super-sticker' ) ;
public renderSticker ( doc : MyDocument , element? : HTMLElement , loadPromises? : Promise < any > [ ] ) {
if ( ! element ) {
element = document . createElement ( 'div' ) ;
element . classList . add ( 'grid-item' , 'super-sticker' ) ;
element . dataset . docId = '' + doc . id ;
if ( doc . animated ) {
this . observeAnimatedDiv ( div ) ;
this . observeAnimated ( element ) ;
}
}
// * This will wrap only a thumb
wrapSticker ( {
/* !doc.animated && */ wrapSticker ( {
doc ,
div ,
div : element ,
lazyLoadQueue : this.regularLazyLoadQueue ,
group : this.group ,
onlyThumb : doc.animated ,
loadPromises
} ) ;
return div ;
return element ;
}
public observeAnimatedDiv ( div : HTMLDivElement ) {
this . animatedDivs . add ( div ) ;
public observeAnimated ( element : HTMLElement ) {
this . animated . add ( element ) ;
this . lazyLoadQueue . observe ( {
div ,
load : this.processVisibleDiv
div : element ,
load : this.processVisible
} ) ;
}
private checkAnimationContainer = ( div : HTMLElement , visible : boolean ) = > {
public unobserveAnimated ( element : HTMLElement ) {
this . animated . delete ( element ) ;
this . lazyLoadQueue . unobserve ( element ) ;
}
private checkAnimationContainer = ( element : HTMLElement , visible : boolean ) = > {
// console.error('checkAnimationContainer', div, visible);
const players = animationIntersector . getAnimations ( div ) ;
const players = animationIntersector . getAnimations ( element ) ;
players . forEach ( ( player ) = > {
if ( ! visible ) {
animationIntersector . checkAnimation ( player , true , true ) ;
@ -87,8 +100,8 @@ export class SuperStickerRenderer {
@@ -87,8 +100,8 @@ export class SuperStickerRenderer {
} ) ;
} ;
private processVisibleDiv = async ( div : HTMLElement ) = > {
const docId = div . dataset . docId ;
private processVisible = async ( element : HTMLElement ) = > {
const docId = element . dataset . docId ;
const doc = await this . managers . appDocsManager . getDoc ( docId ) ;
const size = mediaSizes . active . esgSticker . width ;
@ -97,7 +110,7 @@ export class SuperStickerRenderer {
@@ -97,7 +110,7 @@ export class SuperStickerRenderer {
const promise = wrapSticker ( {
doc ,
div : div as HTMLDivE lement,
div : e lement,
width : size ,
height : size ,
lazyLoadQueue : null ,
@ -109,7 +122,7 @@ export class SuperStickerRenderer {
@@ -109,7 +122,7 @@ export class SuperStickerRenderer {
promise . then ( ( ) = > {
// clearTimeout(timeout);
this . checkAnimationContainer ( div , this . lazyLoadQueue . intersector . isVisible ( div ) ) ;
this . checkAnimationContainer ( element , this . lazyLoadQueue . intersector . isVisible ( element ) ) ;
} ) ;
/ * l e t t i m e o u t = w i n d o w . s e t T i m e o u t ( ( ) = > {
@ -119,123 +132,152 @@ export class SuperStickerRenderer {
@@ -119,123 +132,152 @@ export class SuperStickerRenderer {
return promise ;
} ;
public processInvisibleDiv = async ( div : HTMLElement ) = > {
const docId = div . dataset . docId ;
public processInvisible = async ( element : HTMLElement ) = > {
const docId = element . dataset . docId ;
const doc = await this . managers . appDocsManager . getDoc ( docId ) ;
// console.log('STICKER INvisible:', /* div, */docId);
this . checkAnimationContainer ( div , false ) ;
this . checkAnimationContainer ( element , false ) ;
div . innerHTML = '' ;
this . renderSticker ( doc , div as HTMLDivElement ) ;
element . textContent = '' ;
this . renderSticker ( doc , element as HTMLDivElement ) ;
} ;
}
type StickersTabCategory = {
elements : {
container : HTMLElement ,
title : HTMLElement ,
items : HTMLElement ,
menuTab : HTMLElement ,
menuTabPadding : HTMLElement
} ,
set : StickerSet . stickerSet ,
items : {
document : MyDocument ,
element : HTMLElement
} [ ]
} ;
const RECENT_STICKERS_COUNT = 20 ;
export default class StickersTab implements EmoticonsTab {
private content : HTMLElement ;
private stickersDiv : HTMLElement ;
private stickerSets : { [ id : string ] : {
stickers : HTMLElement ,
tab : HTMLElement
} } = { } ;
private recentDiv : HTMLElement ;
private recentStickers : MyDocument [ ] = [ ] ;
private categories : { [ id : string ] : StickersTabCategory } ;
private categoriesMap : Map < HTMLElement , StickersTabCategory > ;
private categoriesIntersector : VisibilityIntersector ;
private scroll : Scrollable ;
private menu : HTMLElement ;
private mounted = false ;
private queueCategoryPush : { element : HTMLElement , prepend : boolean } [ ] = [ ] ;
private stickyIntersector : StickyIntersector ;
private superStickerRenderer : SuperStickerRenderer ;
constructor ( private managers : AppManagers ) {
this . categories = { } ;
this . categoriesMap = new Map ( ) ;
}
categoryPush ( categoryDiv : HTMLElement , categoryTitle : DocumentFragment | string = '' , promise : Promise < MyDocument [ ] > , prepend? : boolean ) {
// if((docs.length % 5) !== 0) categoryDiv.classList.add('not-full');
private createCategory ( stickerSet : StickerSet.stickerSet , _title : HTMLElement | DocumentFragment ) {
const container = document . createElement ( 'div' ) ;
container . classList . add ( 'emoji-category' , 'hide' ) ;
const itemsDiv = document . createElement ( 'div' ) ;
itemsDiv . classList . add ( 'category-items' , 'super-stickers' ) ;
const items = document . createElement ( 'div' ) ;
items . classList . add ( 'category-items' , 'super-stickers' ) ;
const titleDiv = document . createElement ( 'div' ) ;
titleDiv . classList . add ( 'category-title' ) ;
const title = document . createElement ( 'div' ) ;
title . classList . add ( 'category-title' ) ;
title . append ( _title ) ;
if ( categoryTitle ) {
if ( typeof ( categoryTitle ) === 'string' ) titleDiv . innerHTML = categoryTitle ;
else titleDiv . append ( categoryTitle ) ;
}
const menuTab = ButtonIcon ( undefined , { noRipple : true } ) ;
menuTab . classList . add ( 'menu-horizontal-div-item' ) ;
const menuTabPadding = document . createElement ( 'div' ) ;
menuTabPadding . classList . add ( 'menu-horizontal-div-item-padding' ) ;
menuTab . append ( menuTabPadding ) ;
const category : StickersTabCategory = {
elements : {
container ,
title ,
items ,
menuTab ,
menuTabPadding
} ,
set : stickerSet ,
items : [ ]
} ;
container . append ( title , items ) ;
categoryDiv . append ( titleDiv , itemsDiv ) ;
this . categories [ stickerSet . id ] = category ;
this . categoriesMap . set ( container , category ) ;
this . stickyIntersector . observeStickyHeaderChanges ( categoryDiv ) ;
this . categoriesIntersector . observe ( container ) ;
this . stickyIntersector . observeStickyHeaderChanges ( container ) ;
this . queueCategoryPush . push ( { element : categoryDiv , prepend } ) ;
return category ;
}
private categoryAppendStickers (
category : StickersTabCategory ,
promise : Promise < MyDocument [ ] >
) {
const { container } = category . elements ;
promise . then ( ( documents ) = > {
documents . forEach ( ( doc ) = > {
// if(doc._ === 'documentEmpty') return;
itemsDiv . append ( this . superStickerRenderer . renderSticker ( doc ) ) ;
const isVisible = this . isCategoryVisible ( category ) ;
documents . forEach ( ( document ) = > {
const element = this . superStickerRenderer . renderSticker ( document ) ;
category . items . push ( { document , element } ) ;
if ( isVisible ) {
category . elements . items . append ( element ) ;
}
} ) ;
if ( this . queueCategoryPush . length ) {
this . queueCategoryPush . forEach ( ( { element , prepend } ) = > {
if ( prepend ) {
if ( this . recentDiv . parentElement ) {
this . stickersDiv . prepend ( element ) ;
this . stickersDiv . prepend ( this . recentDiv ) ;
} else {
this . stickersDiv . prepend ( element ) ;
}
} else this . stickersDiv . append ( element ) ;
} ) ;
this . queueCategoryPush . length = 0 ;
}
this . setCategoryItemsHeight ( category ) ;
container . classList . remove ( 'hide' ) ;
} ) ;
}
return { titleDiv } ;
private isCategoryVisible ( category : StickersTabCategory ) {
return this . categoriesIntersector . getVisible ( ) . includes ( category . elements . container ) ;
}
async renderStickerSet ( set : StickerSet . stickerSet , prepend = false ) {
const categoryDiv = document . createElement ( 'div' ) ;
categoryDiv . classList . add ( 'sticker-category' ) ;
categoryDiv . dataset . id = '' + set . id ;
categoryDiv . dataset . access_hash = '' + set . access_hash ;
private setCategoryItemsHeight ( category : StickersTabCategory ) {
const containerWidth = this . content . getBoundingClientRect ( ) . width - 10 ;
const stickerSize = mediaSizes . active . esgSticker . width ;
const button = document . createElement ( 'button' ) ;
button . classList . add ( 'btn-icon' , 'menu-horizontal-div-item' ) ;
const itemsPerRow = Math . floor ( containerWidth / stickerSize ) ;
const rows = Math . ceil ( category . items . length / itemsPerRow ) ;
const height = rows * stickerSize ;
this . stickerSets [ set . id ] = {
stickers : categoryDiv ,
tab : button
} ;
category . elements . items . style . minHeight = height + 'px' ;
}
if ( prepend ) {
this . menu . insertBefore ( button , this . menu . firstElementChild . nextSibling ) ;
} else {
this . menu . append ( button ) ;
}
private async renderStickerSet ( set : StickerSet . stickerSet , prepend = false ) {
const category = this . createCategory ( set , wrapEmojiText ( set . title ) ) ;
const { menuTab , menuTabPadding , container } = category . elements ;
// stickersScroll.append(categoryDiv);
positionElementByIndex ( menuTab , this . menu , prepend ? 1 : 0xFFFF ) ;
const promise = this . managers . appStickersManager . getStickerSet ( set ) ;
this . categoryPush ( categoryDiv , wrapEmojiText ( set . title ) , promise . then ( ( stickerSet ) = > stickerSet . documents as MyDocument [ ] ) , prepend ) ;
const stickerSet = await promise ;
this . categoryAppendStickers (
category ,
promise . then ( ( stickerSet ) = > stickerSet . documents as MyDocument [ ] )
) ;
// const stickerSet = await promise;
// console.log('got stickerSet', stickerSet, li);
positionElementByIndex ( container , this . scroll . container , prepend ? 1 : 0xFFFF , - 1 ) ;
wrapStickerSetThumb ( {
set ,
container : button ,
container : menuTabPadding ,
group : EMOTICONSSTICKERGROUP ,
lazyLoadQueue : EmoticonsDropdown.lazyLoadQueue ,
width : 32 ,
@ -244,21 +286,17 @@ export default class StickersTab implements EmoticonsTab {
@@ -244,21 +286,17 @@ export default class StickersTab implements EmoticonsTab {
} ) ;
}
init() {
public init() {
this . content = document . getElementById ( 'content-stickers' ) ;
// let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
this . recentDiv = document . createElement ( 'div' ) ;
this . recentDiv . classList . add ( 'sticker-category' , 'stickers-recent' ) ;
const menuWrapper = this . content . previousElementSibling as HTMLDivElement ;
this . menu = menuWrapper . firstElementChild as HTMLUListElement ;
const menuScroll = new ScrollableX ( menuWrapper ) ;
this . stickersDiv = document . createElement ( 'div' ) ;
this . stickersDiv . classList . add ( 'stickers-categories' ) ;
this . content . append ( this . stickersDiv ) ;
this . scroll = new Scrollable ( this . content , 'STICKERS' ) ;
this . scroll . onAdditionalScroll = ( ) = > {
setTyping ( ) ;
} ;
/ * s t i c k e r s D i v . a d d E v e n t L i s t e n e r ( ' m o u s e o v e r ' , ( e ) = > {
let target = e . target as HTMLElement ;
@ -277,30 +315,35 @@ export default class StickersTab implements EmoticonsTab {
@@ -277,30 +315,35 @@ export default class StickersTab implements EmoticonsTab {
}
} ) ; * /
rootScope . addEventListener ( 'stickers_installed' , ( e ) = > {
const set : StickerSet . stickerSet = e ;
if ( ! this . stickerSets [ set . id ] && this . mounted ) {
this . renderStickerSet ( set , true ) ;
const onCategoryVisibility : OnVisibilityChange = ( { target , visible , entry } ) = > {
const category = this . categoriesMap . get ( target ) ;
// console.log('roll the windows up', category, target, visible, entry);
if ( ! visible ) {
category . elements . items . textContent = '' ;
} else {
category . elements . items . append ( . . . category . items . map ( ( { element } ) = > element ) ) ;
}
} ) ;
} ;
rootScope . addEventListener ( 'stickers_deleted' , ( e ) = > {
const set : StickerSet . stickerSet = e ;
const intersectionOptions : IntersectionObserverInit = { root : emoticonsDropdown.getElement ( ) } ;
this . categoriesIntersector = new VisibilityIntersector ( onCategoryVisibility , intersectionOptions ) ;
if ( this . stickerSets [ set . id ] && this . mounted ) {
const elements = this . stickerSets [ set . id ] ;
elements . stickers . remove ( ) ;
elements . tab . remove ( ) ;
delete this . stickerSets [ set . id ] ;
}
} ) ;
const clearCategoryItems = ( category : StickersTabCategory ) = > {
category . elements . items . textContent = '' ;
category . items . forEach ( ( { element } ) = > this . superStickerRenderer . unobserveAnimated ( element ) ) ;
category . items . length = 0 ;
} ;
this . stickersDiv . addEventListener ( 'click' , ( e ) = > {
this . scroll . container . addEventListener ( 'click' , ( e ) = > {
const target = e . target as HTMLElement ;
if ( findUpClassName ( target , 'category-title' ) ) {
const el = findUpAttribute ( target , 'data-id' ) ;
new PopupStickers ( { id : el.dataset.id , access_hash : el.dataset.access_hash } ) . show ( ) ;
const container = findUpClassName ( target , 'emoji-category' ) ;
const category = this . categoriesMap . get ( container ) ;
if ( category . set . id === 'recent' ) {
return ;
}
new PopupStickers ( { id : category.set.id , access_hash : category.set.access_hash } ) . show ( ) ;
return ;
}
@ -311,12 +354,6 @@ export default class StickersTab implements EmoticonsTab {
@@ -311,12 +354,6 @@ export default class StickersTab implements EmoticonsTab {
rootScope . dispatchEvent ( 'choosing_sticker' , ! cancel ) ;
} ;
this . scroll = new Scrollable ( this . content , 'STICKERS' ) ;
this . scroll . setVirtualContainer ( this . stickersDiv ) ;
this . scroll . onAdditionalScroll = ( ) = > {
setTyping ( ) ;
} ;
emoticonsDropdown . addEventListener ( 'closed' , ( ) = > {
setTyping ( true ) ;
} ) ;
@ -325,24 +362,43 @@ export default class StickersTab implements EmoticonsTab {
@@ -325,24 +362,43 @@ export default class StickersTab implements EmoticonsTab {
setTyping ( ) ;
} ) ;
this . stickyIntersector = EmoticonsDropdown . menuOnClick ( this . menu , this . scroll , menuScroll ) . stickyIntersector ;
const { stickyIntersector , setActive } = EmoticonsDropdown . menuOnClick ( this . menu , this . scroll , menuScroll ) ;
this . stickyIntersector = stickyIntersector ;
const preloader = putPreloader ( this . content , true ) ;
Promise . all ( [
this . managers . appStickersManager . getRecentStickers ( ) . then ( ( stickers ) = > {
this . recentStickers = stickers . stickers . slice ( 0 , 20 ) as MyDocument [ ] ;
const recentCategory = this . createCategory ( { id : 'recent' } as any , i18n ( 'Stickers.Recent' ) ) ;
recentCategory . elements . title . classList . add ( 'disable-hover' ) ;
recentCategory . elements . menuTab . classList . add ( 'tgico-recent' , 'active' ) ;
recentCategory . elements . menuTabPadding . remove ( ) ;
this . toggleRecentCategory ( recentCategory , false ) ;
const clearButton = ButtonIcon ( 'close' , { noRipple : true } ) ;
recentCategory . elements . title . append ( clearButton ) ;
attachClickEvent ( clearButton , ( ) = > {
confirmationPopup ( {
titleLangKey : 'ClearRecentStickersAlertTitle' ,
descriptionLangKey : 'ClearRecentStickersAlertMessage' ,
button : {
langKey : 'Clear'
}
} ) . then ( ( ) = > {
this . managers . appStickersManager . clearRecentStickers ( ) ;
} , noop ) ;
} ) ;
// stickersScroll.prepend(categoryDiv);
const onRecentStickers = ( stickers : MyDocument [ ] ) = > {
const sliced = stickers . slice ( 0 , RECENT_STICKERS_COUNT ) as MyDocument [ ] ;
this . stickerSets [ 'recent' ] = {
stickers : this.recentDiv ,
tab : this.menu.firstElementChild as HTMLElement
} ;
clearCategoryItems ( recentCategory ) ;
this . toggleRecentCategory ( recentCategory , ! ! sliced . length ) ;
this . categoryAppendStickers ( recentCategory , Promise . resolve ( sliced ) ) ;
} ;
Promise . all ( [
this . managers . appStickersManager . getRecentStickers ( ) . then ( ( stickers ) = > {
preloader . remove ( ) ;
const { titleDiv } = this . categoryPush ( this . recentDiv , '' , Promise . resolve ( this . recentStickers ) , true ) ;
titleDiv . append ( i18n ( 'Stickers.Recent' ) ) ;
onRecentStickers ( stickers . stickers as MyDocument [ ] ) ;
} ) ,
this . managers . appStickersManager . getAllStickers ( ) . then ( ( res ) = > {
@ -355,41 +411,114 @@ export default class StickersTab implements EmoticonsTab {
@@ -355,41 +411,114 @@ export default class StickersTab implements EmoticonsTab {
] ) . finally ( ( ) = > {
this . mounted = true ;
setTyping ( ) ;
setActive ( 0 ) ;
} ) ;
this . superStickerRenderer = new SuperStickerRenderer ( EmoticonsDropdown . lazyLoadQueue , EMOTICONSSTICKERGROUP , this . managers ) ;
this . superStickerRenderer = new SuperStickerRenderer ( EmoticonsDropdown . lazyLoadQueue , EMOTICONSSTICKERGROUP , this . managers , intersectionOptions ) ;
const rendererLazyLoadQueue = this . superStickerRenderer . lazyLoadQueue ;
emoticonsDropdown . addLazyLoadQueueRepeat ( rendererLazyLoadQueue , this . superStickerRenderer . processInvisible ) ;
// emoticonsDropdown.addEventListener('close', () => {
// this.categoriesIntersector.lock();
// });
emoticonsDropdown . addLazyLoadQueueRepeat ( this . superStickerRenderer . lazyLoadQueue , this . superStickerRenderer . processInvisibleDiv ) ;
// emoticonsDropdown.addEventListener('closed', () => {
// for(const [container] of this.categoriesMap) {
// onCategoryVisibility(container, false);
// }
// });
/ * s e t I n t e r v a l ( ( ) = > {
// @ts-ignore
const players = Object . values ( lottieLoader . players ) . filter ( ( p ) = > p . width === 80 ) ;
// emoticonsDropdown.addEventListener('opened', () => {
// this.categoriesIntersector.unlockAndRefresh();
// });
console . log ( 'STICKERS RENDERED IN PANEL:' , players . length , players . filter ( ( p ) = > ! p . paused ) . length , this . superStickerRenderer . lazyLoadQueue . intersector . getVisible ( ) . length ) ;
} , . 25 e3 ) ; * /
// setInterval(() => {
// // @ts-ignore
// const players = Object.values(lottieLoader.players).filter((p) => p.width >= 80);
// console.log(
// 'STICKERS RENDERED IN PANEL:',
// players.length,
// players.filter((p) => !p.paused).length,
// rendererLazyLoadQueue.intersector.getVisible().length
// );
// }, .25e3);
rootScope . addEventListener ( 'stickers_installed' , ( set ) = > {
if ( ! this . categories [ set . id ] && this . mounted ) {
this . renderStickerSet ( set , true ) ;
}
} ) ;
rootScope . addEventListener ( 'stickers_deleted' , ( { id } ) = > {
const category = this . categories [ id ] ;
if ( category && this . mounted ) {
category . elements . container . remove ( ) ;
category . elements . menuTab . remove ( ) ;
this . categoriesIntersector . unobserve ( category . elements . container ) ;
clearCategoryItems ( category ) ;
delete this . categories [ id ] ;
this . categoriesMap . delete ( category . elements . container ) ;
}
} ) ;
rootScope . addEventListener ( 'stickers_recent' , ( stickers ) = > {
if ( this . mounted ) {
onRecentStickers ( stickers ) ;
}
} ) ;
const resizeCategories = ( ) = > {
for ( const [ container , category ] of this . categoriesMap ) {
this . setCategoryItemsHeight ( category ) ;
}
} ;
mediaSizes . addEventListener ( 'resize' , resizeCategories ) ;
emoticonsDropdown . addEventListener ( 'opened' , resizeCategories ) ;
this . init = null ;
}
pushRecentSticker ( doc : MyDocument ) {
this . managers . appStickersManager . pushRecentSticker ( doc ) ;
private toggleRecentCategory ( category : StickersTabCategory , visible : boolean ) {
if ( ! visible ) {
category . elements . menuTab . remove ( ) ;
category . elements . container . remove ( ) ;
} else {
positionElementByIndex ( category . elements . menuTab , this . menu , 0 ) ;
positionElementByIndex ( category . elements . container , this . scroll . container , 0 ) ;
}
// category.elements.container.classList.toggle('hide', !visible);
}
public pushRecentSticker ( doc : MyDocument ) {
this . managers . appStickersManager . pushRecentSticker ( doc . id ) ;
if ( ! this . recentDiv ? . parentElement ) {
const category = this . categories [ 'recent' ] ;
if ( ! category ) {
return ;
}
let div = this . recentDiv . querySelector ( ` [data-doc-id=" ${ doc . id } "] ` ) ;
if ( ! div ) {
div = this . superStickerRenderer . renderSticker ( doc ) ;
const items = category . elements . items ;
let item = findAndSplice ( category . items , ( item ) = > item . document . id === doc . id ) ;
if ( ! item ) {
item = {
element : this.superStickerRenderer.renderSticker ( doc ) ,
document : doc
} ;
}
const items = this . recentDiv . querySelector ( '.category-items' ) ;
items . prepend ( div ) ;
if ( items . childElementCount > 20 ) {
( Array . from ( items . children ) as HTMLElement [ ] ) . slice ( 20 ) . forEach ( ( el ) = > el . remove ( ) ) ;
category . items . unshift ( item ) ;
if ( items . childElementCount ) items . prepend ( item . element ) ;
if ( items . childElementCount > RECENT_STICKERS_COUNT ) {
( Array . from ( items . children ) as HTMLElement [ ] ) . slice ( RECENT_STICKERS_COUNT ) . forEach ( ( el ) = > el . remove ( ) ) ;
}
this . setCategoryItemsHeight ( category ) ;
this . toggleRecentCategory ( category , true ) ;
}
onClose() {