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