provide specific engine boundaries for nodejs and yarn
[oweals/peertube.git] / client / src / app / shared / renderer / linkifier.service.ts
1 import { Injectable } from '@angular/core'
2 import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
3 import * as linkify from 'linkifyjs'
4 import linkifyHtml from 'linkifyjs/html'
5
6 @Injectable()
7 export class LinkifierService {
8
9   static CLASSNAME = 'linkified'
10
11   private linkifyOptions = {
12     className: {
13       mention: LinkifierService.CLASSNAME + '-mention',
14       url: LinkifierService.CLASSNAME + '-url'
15     }
16   }
17
18   constructor () {
19     // Apply plugin
20     this.mentionWithDomainPlugin(linkify)
21   }
22
23   linkify (text: string) {
24     return linkifyHtml(text, this.linkifyOptions)
25   }
26
27   private mentionWithDomainPlugin (linkify: any) {
28     const TT = linkify.scanner.TOKENS // Text tokens
29     const { TOKENS: MT, State } = linkify.parser // Multi tokens, state
30     const MultiToken = MT.Base
31     const S_START = linkify.parser.start
32
33     const TT_AT = TT.AT
34     const TT_DOMAIN = TT.DOMAIN
35     const TT_LOCALHOST = TT.LOCALHOST
36     const TT_NUM = TT.NUM
37     const TT_COLON = TT.COLON
38     const TT_SLASH = TT.SLASH
39     const TT_TLD = TT.TLD
40     const TT_UNDERSCORE = TT.UNDERSCORE
41     const TT_DOT = TT.DOT
42
43     function MENTION (this: any, value: any) {
44       this.v = value
45     }
46
47     linkify.inherits(MultiToken, MENTION, {
48       type: 'mentionWithDomain',
49       isLink: true,
50       toHref () {
51         return getAbsoluteAPIUrl() + '/services/redirect/accounts/' + this.toString().substr(1)
52       }
53     })
54
55     const S_AT = S_START.jump(TT_AT) // @
56     const S_AT_SYMS = new State()
57     const S_MENTION = new State(MENTION)
58     const S_MENTION_DIVIDER = new State()
59     const S_MENTION_DIVIDER_SYMS = new State()
60
61     // @_,
62     S_AT.on(TT_UNDERSCORE, S_AT_SYMS)
63
64     //  @_*
65     S_AT_SYMS
66       .on(TT_UNDERSCORE, S_AT_SYMS)
67       .on(TT_DOT, S_AT_SYMS)
68
69     // Valid mention (not made up entirely of symbols)
70     S_AT
71       .on(TT_DOMAIN, S_MENTION)
72       .on(TT_LOCALHOST, S_MENTION)
73       .on(TT_TLD, S_MENTION)
74       .on(TT_NUM, S_MENTION)
75
76     S_AT_SYMS
77       .on(TT_DOMAIN, S_MENTION)
78       .on(TT_LOCALHOST, S_MENTION)
79       .on(TT_TLD, S_MENTION)
80       .on(TT_NUM, S_MENTION)
81
82     // More valid mentions
83     S_MENTION
84       .on(TT_DOMAIN, S_MENTION)
85       .on(TT_LOCALHOST, S_MENTION)
86       .on(TT_TLD, S_MENTION)
87       .on(TT_COLON, S_MENTION)
88       .on(TT_NUM, S_MENTION)
89       .on(TT_UNDERSCORE, S_MENTION)
90
91     // Mention with a divider
92     S_MENTION
93       .on(TT_AT, S_MENTION_DIVIDER)
94       .on(TT_SLASH, S_MENTION_DIVIDER)
95       .on(TT_DOT, S_MENTION_DIVIDER)
96
97     // Mention _ trailing stash plus syms
98     S_MENTION_DIVIDER.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS)
99     S_MENTION_DIVIDER_SYMS.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS)
100
101     // Once we get a word token, mentions can start up again
102     S_MENTION_DIVIDER
103       .on(TT_DOMAIN, S_MENTION)
104       .on(TT_LOCALHOST, S_MENTION)
105       .on(TT_TLD, S_MENTION)
106       .on(TT_NUM, S_MENTION)
107
108     S_MENTION_DIVIDER_SYMS
109       .on(TT_DOMAIN, S_MENTION)
110       .on(TT_LOCALHOST, S_MENTION)
111       .on(TT_TLD, S_MENTION)
112       .on(TT_NUM, S_MENTION)
113   }
114 }