]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/helpers/utils.ts
Sort channels by -updatedAt
[github/Chocobozzz/PeerTube.git] / client / src / app / helpers / utils.ts
1 import { map } from 'rxjs/operators'
2 import { SelectChannelItem } from 'src/types/select-options-item.model'
3 import { DatePipe } from '@angular/common'
4 import { HttpErrorResponse } from '@angular/common/http'
5 import { Notifier } from '@app/core'
6 import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
7 import { environment } from '../../environments/environment'
8 import { AuthService } from '../core/auth'
9
10 // Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
11 function 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
24 function 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
48 function 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
61 function 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
71 const datePipe = new DatePipe('en')
72 function dateToHuman (date: string) {
73 return datePipe.transform(date, 'medium')
74 }
75
76 function 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
90 function immutableAssign <A, B> (target: A, source: B) {
91 return Object.assign({}, target, source)
92 }
93
94 // Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34
95 function 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
120 function objectLineFeedToHtml (obj: any, keyToNormalize: string) {
121 return immutableAssign(obj, {
122 [keyToNormalize]: lineFeedToHtml(obj[keyToNormalize])
123 })
124 }
125
126 function lineFeedToHtml (text: string) {
127 if (!text) return text
128
129 return text.replace(/\r?\n|\r/g, '<br />')
130 }
131
132 function removeElementFromArray <T> (arr: T[], elem: T) {
133 const index = arr.indexOf(elem)
134 if (index !== -1) arr.splice(index, 1)
135 }
136
137 function 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
148 function scrollToTop (behavior: 'auto' | 'smooth' = 'auto') {
149 window.scrollTo({
150 left: 0,
151 top: 0,
152 behavior
153 })
154 }
155
156 function 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
166 function 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
176 function uploadErrorHandler (parameters: {
177 err: HttpErrorResponse
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.REQUEST_TIMEOUT_408) {
190 message = $localize`Your ${name} file couldn't be transferred before the set timeout (usually 10min)`
191 notifier.error(message, title, null, sticky)
192 } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) {
193 const maxFileSize = err.headers?.get('X-File-Maximum-Size') || '8G'
194 message = $localize`Your ${name} file was too large (max. size: ${maxFileSize})`
195 notifier.error(message, title, null, sticky)
196 } else {
197 notifier.error(err.message, title)
198 }
199
200 return message
201 }
202
203 export {
204 sortBy,
205 durationToString,
206 lineFeedToHtml,
207 getParameterByName,
208 getAbsoluteAPIUrl,
209 dateToHuman,
210 immutableAssign,
211 objectToFormData,
212 getAbsoluteEmbedUrl,
213 objectLineFeedToHtml,
214 removeElementFromArray,
215 scrollToTop,
216 isInViewport,
217 isXPercentInViewport,
218 listUserChannels,
219 uploadErrorHandler
220 }