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