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