From dd24f1bb0a4b252e5342b251ba36853364da7b8e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 19 Aug 2021 09:24:29 +0200 Subject: Add video filters to common video pages --- client/src/app/helpers/utils/channel.ts | 34 ++++++++++++++++ client/src/app/helpers/utils/date.ts | 25 ++++++++++++ client/src/app/helpers/utils/html.ts | 18 +++++++++ client/src/app/helpers/utils/index.ts | 7 ++++ client/src/app/helpers/utils/object.ts | 47 ++++++++++++++++++++++ client/src/app/helpers/utils/ui.ts | 33 +++++++++++++++ client/src/app/helpers/utils/upload.ts | 37 +++++++++++++++++ client/src/app/helpers/utils/url.ts | 71 +++++++++++++++++++++++++++++++++ 8 files changed, 272 insertions(+) create mode 100644 client/src/app/helpers/utils/channel.ts create mode 100644 client/src/app/helpers/utils/date.ts create mode 100644 client/src/app/helpers/utils/html.ts create mode 100644 client/src/app/helpers/utils/index.ts create mode 100644 client/src/app/helpers/utils/object.ts create mode 100644 client/src/app/helpers/utils/ui.ts create mode 100644 client/src/app/helpers/utils/upload.ts create mode 100644 client/src/app/helpers/utils/url.ts (limited to 'client/src/app/helpers/utils') diff --git a/client/src/app/helpers/utils/channel.ts b/client/src/app/helpers/utils/channel.ts new file mode 100644 index 000000000..93863a8af --- /dev/null +++ b/client/src/app/helpers/utils/channel.ts @@ -0,0 +1,34 @@ +import { first, map } from 'rxjs/operators' +import { SelectChannelItem } from 'src/types/select-options-item.model' +import { AuthService } from '../../core/auth' + +function listUserChannels (authService: AuthService) { + return authService.userInformationLoaded + .pipe( + first(), + map(() => { + const user = authService.getUser() + if (!user) return undefined + + const videoChannels = user.videoChannels + if (Array.isArray(videoChannels) === false) return undefined + + return videoChannels + .sort((a, b) => { + if (a.updatedAt < b.updatedAt) return 1 + if (a.updatedAt > b.updatedAt) return -1 + return 0 + }) + .map(c => ({ + id: c.id, + label: c.displayName, + support: c.support, + avatarPath: c.avatar?.path + }) as SelectChannelItem) + }) + ) +} + +export { + listUserChannels +} diff --git a/client/src/app/helpers/utils/date.ts b/client/src/app/helpers/utils/date.ts new file mode 100644 index 000000000..012b959ea --- /dev/null +++ b/client/src/app/helpers/utils/date.ts @@ -0,0 +1,25 @@ +import { DatePipe } from '@angular/common' + +const datePipe = new DatePipe('en') +function dateToHuman (date: string) { + return datePipe.transform(date, 'medium') +} + +function durationToString (duration: number) { + const hours = Math.floor(duration / 3600) + const minutes = Math.floor((duration % 3600) / 60) + const seconds = duration % 60 + + const minutesPadding = minutes >= 10 ? '' : '0' + const secondsPadding = seconds >= 10 ? '' : '0' + const displayedHours = hours > 0 ? hours.toString() + ':' : '' + + return ( + displayedHours + minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString() + ).replace(/^0/, '') +} + +export { + durationToString, + dateToHuman +} diff --git a/client/src/app/helpers/utils/html.ts b/client/src/app/helpers/utils/html.ts new file mode 100644 index 000000000..2d520aee9 --- /dev/null +++ b/client/src/app/helpers/utils/html.ts @@ -0,0 +1,18 @@ +import { immutableAssign } from './object' + +function objectLineFeedToHtml (obj: any, keyToNormalize: string) { + return immutableAssign(obj, { + [keyToNormalize]: lineFeedToHtml(obj[keyToNormalize]) + }) +} + +function lineFeedToHtml (text: string) { + if (!text) return text + + return text.replace(/\r?\n|\r/g, '
') +} + +export { + objectLineFeedToHtml, + lineFeedToHtml +} diff --git a/client/src/app/helpers/utils/index.ts b/client/src/app/helpers/utils/index.ts new file mode 100644 index 000000000..dc09c92ab --- /dev/null +++ b/client/src/app/helpers/utils/index.ts @@ -0,0 +1,7 @@ +export * from './channel' +export * from './date' +export * from './html' +export * from './object' +export * from './ui' +export * from './upload' +export * from './url' diff --git a/client/src/app/helpers/utils/object.ts b/client/src/app/helpers/utils/object.ts new file mode 100644 index 000000000..1ca4a23ac --- /dev/null +++ b/client/src/app/helpers/utils/object.ts @@ -0,0 +1,47 @@ +function immutableAssign (target: A, source: B) { + return Object.assign({}, target, source) +} + +function removeElementFromArray (arr: T[], elem: T) { + const index = arr.indexOf(elem) + if (index !== -1) arr.splice(index, 1) +} + +function sortBy (obj: any[], key1: string, key2?: string) { + return obj.sort((a, b) => { + const elem1 = key2 ? a[key1][key2] : a[key1] + const elem2 = key2 ? b[key1][key2] : b[key1] + + if (elem1 < elem2) return -1 + if (elem1 === elem2) return 0 + return 1 + }) +} + +function intoArray (value: any) { + if (!value) return undefined + if (Array.isArray(value)) return value + + if (typeof value === 'string') return value.split(',') + + return [ value ] +} + +function toBoolean (value: any) { + if (!value) return undefined + + if (typeof value === 'boolean') return value + + if (value === 'true') return true + if (value === 'false') return false + + return undefined +} + +export { + sortBy, + immutableAssign, + removeElementFromArray, + intoArray, + toBoolean +} diff --git a/client/src/app/helpers/utils/ui.ts b/client/src/app/helpers/utils/ui.ts new file mode 100644 index 000000000..ac8298926 --- /dev/null +++ b/client/src/app/helpers/utils/ui.ts @@ -0,0 +1,33 @@ +function scrollToTop (behavior: 'auto' | 'smooth' = 'auto') { + window.scrollTo({ + left: 0, + top: 0, + behavior + }) +} + +function isInViewport (el: HTMLElement) { + const bounding = el.getBoundingClientRect() + return ( + bounding.top >= 0 && + bounding.left >= 0 && + bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + bounding.right <= (window.innerWidth || document.documentElement.clientWidth) + ) +} + +function isXPercentInViewport (el: HTMLElement, percentVisible: number) { + const rect = el.getBoundingClientRect() + const windowHeight = (window.innerHeight || document.documentElement.clientHeight) + + return !( + Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100)) < percentVisible || + Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible + ) +} + +export { + scrollToTop, + isInViewport, + isXPercentInViewport +} diff --git a/client/src/app/helpers/utils/upload.ts b/client/src/app/helpers/utils/upload.ts new file mode 100644 index 000000000..a3fce7fee --- /dev/null +++ b/client/src/app/helpers/utils/upload.ts @@ -0,0 +1,37 @@ +import { HttpErrorResponse } from '@angular/common/http' +import { Notifier } from '@app/core' +import { HttpStatusCode } from '@shared/models' + +function genericUploadErrorHandler (parameters: { + err: Pick + name: string + notifier: Notifier + sticky?: boolean +}) { + const { err, name, notifier, sticky } = { sticky: false, ...parameters } + const title = $localize`The upload failed` + let message = err.message + + if (err instanceof ErrorEvent) { // network error + message = $localize`The connection was interrupted` + notifier.error(message, title, null, sticky) + } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) { + message = $localize`The server encountered an error` + notifier.error(message, title, null, sticky) + } else if (err.status === HttpStatusCode.REQUEST_TIMEOUT_408) { + message = $localize`Your ${name} file couldn't be transferred before the set timeout (usually 10min)` + notifier.error(message, title, null, sticky) + } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { + const maxFileSize = err.headers?.get('X-File-Maximum-Size') || '8G' + message = $localize`Your ${name} file was too large (max. size: ${maxFileSize})` + notifier.error(message, title, null, sticky) + } else { + notifier.error(err.message, title) + } + + return message +} + +export { + genericUploadErrorHandler +} diff --git a/client/src/app/helpers/utils/url.ts b/client/src/app/helpers/utils/url.ts new file mode 100644 index 000000000..82d9cc11b --- /dev/null +++ b/client/src/app/helpers/utils/url.ts @@ -0,0 +1,71 @@ +import { environment } from '../../../environments/environment' + +// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +function getParameterByName (name: string, url: string) { + if (!url) url = window.location.href + name = name.replace(/[[\]]/g, '\\$&') + + const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)') + const results = regex.exec(url) + + if (!results) return null + if (!results[2]) return '' + + return decodeURIComponent(results[2].replace(/\+/g, ' ')) +} + +function getAbsoluteAPIUrl () { + let absoluteAPIUrl = environment.hmr === true + ? 'http://localhost:9000' + : environment.apiUrl + + if (!absoluteAPIUrl) { + // The API is on the same domain + absoluteAPIUrl = window.location.origin + } + + return absoluteAPIUrl +} + +function getAbsoluteEmbedUrl () { + let absoluteEmbedUrl = environment.originServerUrl + if (!absoluteEmbedUrl) { + // The Embed is on the same domain + absoluteEmbedUrl = window.location.origin + } + + return absoluteEmbedUrl +} + +// Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34 +function objectToFormData (obj: any, form?: FormData, namespace?: string) { + const fd = form || new FormData() + let formKey + + for (const key of Object.keys(obj)) { + if (namespace) formKey = `${namespace}[${key}]` + else formKey = key + + if (obj[key] === undefined) continue + + if (Array.isArray(obj[key]) && obj[key].length === 0) { + fd.append(key, null) + continue + } + + if (obj[key] !== null && typeof obj[key] === 'object' && !(obj[key] instanceof File)) { + objectToFormData(obj[key], fd, formKey) + } else { + fd.append(formKey, obj[key]) + } + } + + return fd +} + +export { + getParameterByName, + objectToFormData, + getAbsoluteAPIUrl, + getAbsoluteEmbedUrl +} -- cgit v1.2.3