]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - client/src/app/helpers/utils.ts
Fix button icon in admin plugins
[github/Chocobozzz/PeerTube.git] / client / src / app / helpers / utils.ts
... / ...
CommitLineData
1import { map } from 'rxjs/operators'
2import { SelectChannelItem } from 'src/types/select-options-item.model'
3import { DatePipe } from '@angular/common'
4import { HttpErrorResponse } from '@angular/common/http'
5import { Notifier } from '@app/core'
6import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
7import { environment } from '../../environments/environment'
8import { AuthService } from '../core/auth'
9
10// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
11function getParameterByName (name: string, url: string) {
12 if (!url) url = window.location.href
13 name = name.replace(/[\[\]]/g, '\\$&')
14
15 const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
16 const results = regex.exec(url)
17
18 if (!results) return null
19 if (!results[2]) return ''
20
21 return decodeURIComponent(results[2].replace(/\+/g, ' '))
22}
23
24function listUserChannels (authService: AuthService) {
25 return authService.userInformationLoaded
26 .pipe(map(() => {
27 const user = authService.getUser()
28 if (!user) return undefined
29
30 const videoChannels = user.videoChannels
31 if (Array.isArray(videoChannels) === false) return undefined
32
33 return videoChannels
34 .sort((a, b) => {
35 if (a.updatedAt < b.updatedAt) return 1
36 if (a.updatedAt > b.updatedAt) return -1
37 return 0
38 })
39 .map(c => ({
40 id: c.id,
41 label: c.displayName,
42 support: c.support,
43 avatarPath: c.avatar?.path
44 }) as SelectChannelItem)
45 }))
46}
47
48function getAbsoluteAPIUrl () {
49 let absoluteAPIUrl = environment.hmr === true
50 ? 'http://localhost:9000'
51 : environment.apiUrl
52
53 if (!absoluteAPIUrl) {
54 // The API is on the same domain
55 absoluteAPIUrl = window.location.origin
56 }
57
58 return absoluteAPIUrl
59}
60
61function getAbsoluteEmbedUrl () {
62 let absoluteEmbedUrl = environment.originServerUrl
63 if (!absoluteEmbedUrl) {
64 // The Embed is on the same domain
65 absoluteEmbedUrl = window.location.origin
66 }
67
68 return absoluteEmbedUrl
69}
70
71const datePipe = new DatePipe('en')
72function dateToHuman (date: string) {
73 return datePipe.transform(date, 'medium')
74}
75
76function durationToString (duration: number) {
77 const hours = Math.floor(duration / 3600)
78 const minutes = Math.floor((duration % 3600) / 60)
79 const seconds = duration % 60
80
81 const minutesPadding = minutes >= 10 ? '' : '0'
82 const secondsPadding = seconds >= 10 ? '' : '0'
83 const displayedHours = hours > 0 ? hours.toString() + ':' : ''
84
85 return (
86 displayedHours + minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString()
87 ).replace(/^0/, '')
88}
89
90function immutableAssign <A, B> (target: A, source: B) {
91 return Object.assign({}, target, source)
92}
93
94// Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34
95function objectToFormData (obj: any, form?: FormData, namespace?: string) {
96 const fd = form || new FormData()
97 let formKey
98
99 for (const key of Object.keys(obj)) {
100 if (namespace) formKey = `${namespace}[${key}]`
101 else formKey = key
102
103 if (obj[key] === undefined) continue
104
105 if (Array.isArray(obj[key]) && obj[key].length === 0) {
106 fd.append(key, null)
107 continue
108 }
109
110 if (obj[key] !== null && typeof obj[ key ] === 'object' && !(obj[ key ] instanceof File)) {
111 objectToFormData(obj[ key ], fd, formKey)
112 } else {
113 fd.append(formKey, obj[ key ])
114 }
115 }
116
117 return fd
118}
119
120function objectLineFeedToHtml (obj: any, keyToNormalize: string) {
121 return immutableAssign(obj, {
122 [keyToNormalize]: lineFeedToHtml(obj[keyToNormalize])
123 })
124}
125
126function lineFeedToHtml (text: string) {
127 if (!text) return text
128
129 return text.replace(/\r?\n|\r/g, '<br />')
130}
131
132function removeElementFromArray <T> (arr: T[], elem: T) {
133 const index = arr.indexOf(elem)
134 if (index !== -1) arr.splice(index, 1)
135}
136
137function sortBy (obj: any[], key1: string, key2?: string) {
138 return obj.sort((a, b) => {
139 const elem1 = key2 ? a[key1][key2] : a[key1]
140 const elem2 = key2 ? b[key1][key2] : b[key1]
141
142 if (elem1 < elem2) return -1
143 if (elem1 === elem2) return 0
144 return 1
145 })
146}
147
148function scrollToTop (behavior: 'auto' | 'smooth' = 'auto') {
149 window.scrollTo({
150 left: 0,
151 top: 0,
152 behavior
153 })
154}
155
156function isInViewport (el: HTMLElement) {
157 const bounding = el.getBoundingClientRect()
158 return (
159 bounding.top >= 0 &&
160 bounding.left >= 0 &&
161 bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
162 bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
163 )
164}
165
166function isXPercentInViewport (el: HTMLElement, percentVisible: number) {
167 const rect = el.getBoundingClientRect()
168 const windowHeight = (window.innerHeight || document.documentElement.clientHeight)
169
170 return !(
171 Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100)) < percentVisible ||
172 Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
173 )
174}
175
176function genericUploadErrorHandler (parameters: {
177 err: Pick<HttpErrorResponse, 'message' | 'status' | 'headers'>
178 name: string
179 notifier: Notifier
180 sticky?: boolean
181}) {
182 const { err, name, notifier, sticky } = { sticky: false, ...parameters }
183 const title = $localize`The upload failed`
184 let message = err.message
185
186 if (err instanceof ErrorEvent) { // network error
187 message = $localize`The connection was interrupted`
188 notifier.error(message, title, null, sticky)
189 } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) {
190 message = $localize`The server encountered an error`
191 notifier.error(message, title, null, sticky)
192 } else if (err.status === HttpStatusCode.REQUEST_TIMEOUT_408) {
193 message = $localize`Your ${name} file couldn't be transferred before the set timeout (usually 10min)`
194 notifier.error(message, title, null, sticky)
195 } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) {
196 const maxFileSize = err.headers?.get('X-File-Maximum-Size') || '8G'
197 message = $localize`Your ${name} file was too large (max. size: ${maxFileSize})`
198 notifier.error(message, title, null, sticky)
199 } else {
200 notifier.error(err.message, title)
201 }
202
203 return message
204}
205
206export {
207 sortBy,
208 durationToString,
209 lineFeedToHtml,
210 getParameterByName,
211 getAbsoluteAPIUrl,
212 dateToHuman,
213 immutableAssign,
214 objectToFormData,
215 getAbsoluteEmbedUrl,
216 objectLineFeedToHtml,
217 removeElementFromArray,
218 scrollToTop,
219 isInViewport,
220 isXPercentInViewport,
221 listUserChannels,
222 genericUploadErrorHandler
223}