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