import { Component , OnInit , Input , Output , EventEmitter } from '@angular/core' ; import { getIndicesOf } from '../../utils' ; interface property property property interface StringIndexedChunks { index : number ; str : string ; type : ShardType ; } enum ShardTypes const enum ShardType { plain , link , hashtag , mention } property property property property property class Shard { constructor ( public type = ShardType . plain , public text = '' , public linkTo = null , public queryParams = null ) { } } @ Component ( { selector : 'feed-linker' , templateUrl : './feed-linker.component.html' , styleUrls : [ './feed-linker.component.scss' ] } ) export class FeedLinkerComponent implements OnInit { @ Input ( ) text : string ; @ Input ( ) hashtags : string [ ] = new Array < string > ( ) ; @ Input ( ) mentions : string [ ] = new Array < string > ( ) ; @ Input ( ) links : string [ ] = new Array < string > ( ) ; @ Input ( ) unshorten : Object = { } ; @ Input ( ) useAll = false ; @ Output ( ) showed = new EventEmitter < boolean > ( ) ; public shardArray : Array < Shard > = new Array < Shard > ( ) ; constructor ( ) { } ngOnInit ( ) { if ( this . useAll ) { this . generateAllShards ( ) ; } else { this . generateShards ( ) ; } } showHideLightbox ( shard ) { if ( shard . type === 1 ) { window . open ( shard . linkTo , '_blank' ) ; } this . showed . emit ( true ) ; } private generateShards ( ) { const indexedChunks = [ ] ; this . hashtags . forEach ( hashtag => { const indices = getIndicesOf ( this . text , `#${ hashtag }` , false ) ; indices . forEach ( idx => { indexedChunks . push ( { index : idx , str : `#${ hashtag }` , type : ShardType . hashtag } ) ; } ) ; } ) ; this . mentions . forEach ( mention => { const indices = getIndicesOf ( this . text , `@${ mention }` , false ) ; indices . forEach ( idx => { indexedChunks . push ( { index : idx , str : `@${ mention }` , type : ShardType . mention } ) ; } ) ; } ) ; let allLinks = [ ] ; const unshortenKeys = Object . keys ( this . unshorten ) ; const unshortenValues = [ ] ; unshortenKeys . forEach ( key => unshortenValues . push ( this . unshorten [ key ] ) ) ; for ( const link of this . links ) { let insert = true ; for ( let shortened of unshortenValues ) { shortened = shortened . substring ( 0 , shortened . length - 3 ) ; if ( link . startsWith ( shortened ) ) { insert = false ; break ; } } if ( insert ) { allLinks . push ( link ) ; } } allLinks = [ ... unshortenKeys , ... allLinks ] ; allLinks . forEach ( link => { const indices = getIndicesOf ( this . text , link , false ) ; indices . forEach ( idx => { indexedChunks . push ( { index : idx , str : link , type : ShardType . link } ) ; } ) ; } ) ; indexedChunks . sort ( ( a , b ) => ( a . index > b . index ) ? 1 : ( a . index < b . index ) ? - 1 : 0 ) ; let startIndex = 0 ; const endIndex = this . text . length ; let prevInd = - 1 ; indexedChunks . forEach ( element => { if ( element . index !== prevInd ) { if ( startIndex !== element . index ) { const shard = new Shard ( ShardType . plain , this . text . substring ( startIndex , element . index ) ) ; this . shardArray . push ( shard ) ; startIndex = element . index ; } if ( startIndex === element . index ) { const str = this . text . substring ( startIndex , element . index + element . str . length ) ; const shard = new Shard ( element . type , str ) ; switch ( element . type ) { case ShardType . link : { if ( this . unshorten [ element . str ] ) { shard . linkTo = str ; shard . text = this . unshorten [ element . str ] ; } else { shard . linkTo = str ; } break ; } case ShardType . hashtag : { shard . linkTo = [ '/search' ] ; shard . queryParams = { query : str } ; break ; } case ShardType . mention : { shard . linkTo = [ '/search' ] ; shard . queryParams = { query : `from:${ str . substring ( 1 ) }` } ; break ; } } this . shardArray . push ( shard ) ; startIndex += element . str . length ; } prevInd = element . index ; } } ) ; if ( startIndex !== endIndex ) { const shard = new Shard ( ShardType . plain , this . text . substring ( startIndex ) ) ; this . shardArray . push ( shard ) ; } } private generateAllShards ( ) { const splitTextArray = this . text . split ( ' ' ) ; for ( const shardText of splitTextArray ) { if ( shardText [ 0 ] === '@' && shardText . length > 1 ) { const mentionShard = new Shard ( ShardType . mention , shardText ) ; mentionShard . linkTo = [ '/search' ] ; mentionShard . queryParams = { query : `from:${ shardText . substring ( 1 ) }` } ; this . shardArray . push ( mentionShard ) ; } else if ( shardText [ 0 ] === '#' && shardText . length > 1 ) { const hashtagShard = new Shard ( ShardType . hashtag , shardText ) ; hashtagShard . linkTo = [ '/search' ] ; hashtagShard . queryParams = { query : `#${ shardText . substring ( 1 ) }` } ; this . shardArray . push ( hashtagShard ) ; } else if ( this . stringIsURL ( shardText ) ) { const linkShard = new Shard ( ShardType . link , shardText ) ; linkShard . linkTo = shardText ; linkShard . text = shardText ; if ( this . unshorten . hasOwnProperty ( shardText ) ) { linkShard . text = this . unshorten [ shardText ] ; } this . shardArray . push ( linkShard ) ; } else { this . shardArray . push ( new Shard ( ShardType . plain , shardText ) ) ; } } } private stringIsURL ( str ) { const regexpPattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ ; const regexp = new RegExp ( regexpPattern , 'ig' ) ; const searchRes = str . search ( regexp ) ; return ( searchRes === 0 ) ? true : false ; } }