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