]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/helpers/utils.ts
Fix tags in search filters
[github/Chocobozzz/PeerTube.git] / client / src / app / helpers / utils.ts
1 import { DatePipe } from '@angular/common'
2 import { environment } from '../../environments/environment'
3 import { AuthService } from '../core/auth'
4 import { SelectChannelItem } from '@app/shared/shared-forms/select-channel.component'
5
6 // Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
7 function getParameterByName (name: string, url: string) {
8 if (!url) url = window.location.href
9 name = name.replace(/[\[\]]/g, '\\$&')
10
11 const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
12 const results = regex.exec(url)
13
14 if (!results) return null
15 if (!results[2]) return ''
16
17 return decodeURIComponent(results[2].replace(/\+/g, ' '))
18 }
19
20 function populateAsyncUserVideoChannels (
21 authService: AuthService,
22 channel: SelectChannelItem[]
23 ) {
24 return new Promise(res => {
25 authService.userInformationLoaded
26 .subscribe(
27 () => {
28 const user = authService.getUser()
29 if (!user) return
30
31 const videoChannels = user.videoChannels
32 if (Array.isArray(videoChannels) === false) return
33
34 videoChannels.forEach(c => channel.push({
35 id: c.id,
36 label: c.displayName,
37 support: c.support,
38 avatarPath: c.avatar?.path
39 }))
40
41 return res()
42 }
43 )
44 })
45 }
46
47 function getAbsoluteAPIUrl () {
48 let absoluteAPIUrl = environment.hmr === true
49 ? 'http://localhost:9000'
50 : environment.apiUrl
51
52 if (!absoluteAPIUrl) {
53 // The API is on the same domain
54 absoluteAPIUrl = window.location.origin
55 }
56
57 return absoluteAPIUrl
58 }
59
60 function getAbsoluteEmbedUrl () {
61 let absoluteEmbedUrl = environment.embedUrl
62 if (!absoluteEmbedUrl) {
63 // The Embed is on the same domain
64 absoluteEmbedUrl = window.location.origin
65 }
66
67 return absoluteEmbedUrl
68 }
69
70 const datePipe = new DatePipe('en')
71 function dateToHuman (date: string) {
72 return datePipe.transform(date, 'medium')
73 }
74
75 function durationToString (duration: number) {
76 const hours = Math.floor(duration / 3600)
77 const minutes = Math.floor((duration % 3600) / 60)
78 const seconds = duration % 60
79
80 const minutesPadding = minutes >= 10 ? '' : '0'
81 const secondsPadding = seconds >= 10 ? '' : '0'
82 const displayedHours = hours > 0 ? hours.toString() + ':' : ''
83
84 return (
85 displayedHours + minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString()
86 ).replace(/^0/, '')
87 }
88
89 function immutableAssign <A, B> (target: A, source: B) {
90 return Object.assign({}, target, source)
91 }
92
93 // Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34
94 function objectToFormData (obj: any, form?: FormData, namespace?: string) {
95 const fd = form || new FormData()
96 let formKey
97
98 for (const key of Object.keys(obj)) {
99 if (namespace) formKey = `${namespace}[${key}]`
100 else formKey = key
101
102 if (obj[key] === undefined) continue
103
104 if (Array.isArray(obj[key]) && obj[key].length === 0) {
105 fd.append(key, null)
106 continue
107 }
108
109 if (obj[key] !== null && typeof obj[ key ] === 'object' && !(obj[ key ] instanceof File)) {
110 objectToFormData(obj[ key ], fd, formKey)
111 } else {
112 fd.append(formKey, obj[ key ])
113 }
114 }
115
116 return fd
117 }
118
119 function objectLineFeedToHtml (obj: any, keyToNormalize: string) {
120 return immutableAssign(obj, {
121 [keyToNormalize]: lineFeedToHtml(obj[keyToNormalize])
122 })
123 }
124
125 function lineFeedToHtml (text: string) {
126 if (!text) return text
127
128 return text.replace(/\r?\n|\r/g, '<br />')
129 }
130
131 function removeElementFromArray <T> (arr: T[], elem: T) {
132 const index = arr.indexOf(elem)
133 if (index !== -1) arr.splice(index, 1)
134 }
135
136 function sortBy (obj: any[], key1: string, key2?: string) {
137 return obj.sort((a, b) => {
138 const elem1 = key2 ? a[key1][key2] : a[key1]
139 const elem2 = key2 ? b[key1][key2] : b[key1]
140
141 if (elem1 < elem2) return -1
142 if (elem1 === elem2) return 0
143 return 1
144 })
145 }
146
147 function scrollToTop () {
148 window.scroll(0, 0)
149 }
150
151 // Thanks: https://github.com/uupaa/dynamic-import-polyfill
152 function importModule (path: string) {
153 return new Promise((resolve, reject) => {
154 const vector = '$importModule$' + Math.random().toString(32).slice(2)
155 const script = document.createElement('script')
156
157 const destructor = () => {
158 delete window[ vector ]
159 script.onerror = null
160 script.onload = null
161 script.remove()
162 URL.revokeObjectURL(script.src)
163 script.src = ''
164 }
165
166 script.defer = true
167 script.type = 'module'
168
169 script.onerror = () => {
170 reject(new Error(`Failed to import: ${path}`))
171 destructor()
172 }
173 script.onload = () => {
174 resolve(window[ vector ])
175 destructor()
176 }
177 const absURL = (environment.apiUrl || window.location.origin) + path
178 const loader = `import * as m from "${absURL}"; window.${vector} = m;` // export Module
179 const blob = new Blob([ loader ], { type: 'text/javascript' })
180 script.src = URL.createObjectURL(blob)
181
182 document.head.appendChild(script)
183 })
184 }
185
186 function isInViewport (el: HTMLElement) {
187 const bounding = el.getBoundingClientRect()
188 return (
189 bounding.top >= 0 &&
190 bounding.left >= 0 &&
191 bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
192 bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
193 )
194 }
195
196 function isXPercentInViewport (el: HTMLElement, percentVisible: number) {
197 const rect = el.getBoundingClientRect()
198 const windowHeight = (window.innerHeight || document.documentElement.clientHeight)
199
200 return !(
201 Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100)) < percentVisible ||
202 Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
203 )
204 }
205
206 export {
207 sortBy,
208 durationToString,
209 lineFeedToHtml,
210 getParameterByName,
211 populateAsyncUserVideoChannels,
212 getAbsoluteAPIUrl,
213 dateToHuman,
214 immutableAssign,
215 objectToFormData,
216 getAbsoluteEmbedUrl,
217 objectLineFeedToHtml,
218 removeElementFromArray,
219 importModule,
220 scrollToTop,
221 isInViewport,
222 isXPercentInViewport
223 }