All Downloads are FREE. Search and download functionalities are using the official Maven repository.

helpers.content.ts Maven / Gradle / Ivy

import { tokenPromise } from 'authentication/main';
import { Runtime } from 'helpers/runtime';
import { Notifier } from 'hooks/notification';
import Types from 'types/types';
import { download } from 'utils/download';
import { getExtension } from 'utils/files';

export type ContentType = "content" | "document" | "local"
export type ContentOptions = {
  id: string,
  path: string,
  type: ContentType,
  mimeType: string
}

export interface PartialContentOptions extends Partial {}

export type ContentViewEvent = KeyboardEvent | null

export class Content {
  id: string
  path: string
  contentType: ContentType | undefined

  private __mimeType: string | undefined
  private __file: File  | undefined
  private __blob: Blob  | undefined
  private __url: string | undefined

  constructor(id: string, path: string, type?: ContentType, mimeType?: string) {
    this.id          = id
    this.path        = path
    this.contentType = type
    this.__mimeType  = mimeType
  }

  destructor() {
    if (this.__url) {
      window.URL.revokeObjectURL(this.__url)
      this.__url = undefined
    }

    if (this.__file) {
      delete this.__file
      this.__file = undefined
    }

    if (this.__blob) {
      delete this.__blob
      this.__blob = undefined
    }
  }

  static from(value: any, options?: PartialContentOptions): Content {
    switch (true) {
      case value instanceof Content:
        return value as Content

      case value instanceof File: {
        const file     = value as File
        const id       = options?.id || file.name
        const path     = options?.path || file.name
        const mime     = options?.mimeType || file.type
        const content  = new Content(id, path, options?.type, mime)
        content.__file = file

        return content
      }

      case value instanceof Blob: {
        const blob     = value as Blob
        const id       = options?.id || Math.random().toString()
        const path     = options?.path || "file-" + options?.id + "+" + Content.toMimeExtension(blob.type)
        const mime     = options?.mimeType || blob.type
        const content  = new Content(id, path, options?.type, mime)
        content.__blob = blob

        return content
      }

      case Types.isFileRef(value): {
        const fileRef = Types.asFileRef(value)
        const id       = options?.id || fileRef.__id
        const path     = options?.path || fileRef.filename
        const mime     = options?.mimeType || fileRef.contentType
        const content  = new Content(id, path, options?.type, mime)

        return content
      }

      default:
        return Types.null()
    }
  }

  get hasData(): boolean {
    return !!(this.__blob || this.__file)
  }

  clone(): Content {
    const content  = new Content(this.id, this.path, this.contentType)
    content.__blob   = this.__blob
    content.__file   = this.__file
    content.__url    = this.__url

    return content
  }

  setBlob(blob: Blob): void {
    this.__blob = blob
    this.__file = undefined
    this.__url  = undefined
  }

  withBlob(blob: Blob): Content {
    const content  = this.clone()
    this.setBlob(blob)
    return content
  }

  withFile(file: File): Content {
    const content  = this.clone()
    content.__file = file
    content.__blob = undefined
    content.__url  = undefined
    return content
  }

  load(e?: React.SyntheticEvent, notifier?: Notifier): Promise {
    e?.preventDefault()
    e?.stopPropagation()

    if (this.hasData) {
      return Promise.resolve(this)
    }
    else {
      return Content.fetchBlob(this.remoteUrl || "unknown")
        .then(
          blob => {
            //console.log("content fetched: blob=%o, size=%s, type=%s", blob, blob.size, blob.type)
            this.setBlob(blob)
            return this
          },
          error => {
            const err = new Error("Could not access content '" + this.path + "': " + (error?.message || JSON.stringify(error)))
            notifier?.error(err.message)
            return Promise.reject(err)
          }
        )
    }
  }

  download(e?: React.SyntheticEvent, notifier?: Notifier) {
    e?.preventDefault()
    e?.stopPropagation()

    this.load(e, notifier)
      .then(content => {
        if (content != null)
          download(content.url, this.path)
        else {
          const msg = "No download content available for path: " + this.path
          if (notifier)
            notifier.error(msg)
          else
            window.alert(msg)
        }
      })
  }

  setMimetype(type: string) {
    this.__mimeType = type
  }

  setFile(file: File) {
    this.__file = file
  }

  toContentRef(): object {
    return {
      "__kind":      "content-ref",
      "__id":        this.id,
      "filename":    this.path,
      "contentType": this.contentType,
    }
  }

  get blob(): Blob | undefined {
    return this.__blob
  }

  get extension(): string | undefined {
    if (this.path)
      return getExtension(this.path)
    if (this.__file)
      return getExtension(this.__file.name) || Content.toMimeExtension(this.__file.type)
    else if (this.__blob)
      return Content.toMimeExtension(this.__blob.type)
  }

  get type(): string {
    if (this.__mimeType)
      return this.__mimeType
    else {
      this.__mimeType = this.derivedMimeType
      return this.__mimeType || ""
    }
  }

  private get derivedMimeType(): string | undefined {
    if (this.__file)
      return this.__file.type
    else if (this.__blob)
      return this.__blob.type
    else
      return Content.toMimeType(this.path)
  }

  get file(): File {
    if (this.__file) {
      return this.__file
    }
    else if (this.__blob) {
      this.__file = new File([this.__blob], this.path, { type: this.__blob.type } )
      return this.__file
    }
    else {
      console.error("Could not create file for path: %o", this.path)
      return Types.null()
    }
  }

  get filename(): string {
    return this.path
  }

  get remoteUrl(): string | undefined {
    switch (this.contentType) {
      case 'document':
        return Runtime.document(this.id)
      case 'local':
        return undefined
      case 'content':
      default:
        return Runtime.content(this.id) 
    }
  }

  get name(): string { 
    return this.filename
  }

  get url(): string {
    if (this.__url)
      return this.__url
    else {
      const contentLike = this.__file || this.__blob
      if (contentLike) {
        this.__url = window.URL.createObjectURL(contentLike)
        return this.__url
      } else {
        return Types.null()
      }
    }
  }

  static fetchBlob(url: string): Promise {
    return tokenPromise()
      .then(token => {
        const bearer = `Bearer ${token}`
        return fetch(url, {
          method: 'GET',
          credentials: 'include',
          //mode: 'cors', // no-cors, *cors, same-origin
          cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached;
          headers: {
            'Authorization': bearer,
            'Content-Type': "multipart/form-data",
            //'Accept' : "*/*"
          }})
        }
      )
      .then(request => {
        if (request.status >= 400) {
          console.error("Runtime download response: %o", request)
          return Promise.reject(new Error(request.statusText))
        } else {
          return request && request.blob()
        }
      })
  }

  static toMimeType(filename: string): string | undefined {
     return Content.toExtensionMime(getExtension(filename))
  }

  static toExtensionMime(extension: string): string | undefined {
     return extensionToMimeTypeTable[extension]
  }

  static toMimeExtension(mimeType: string): string | undefined {
    return mimeTypeToExtentionTable[mimeType]
  }
}

const extensionToMimeTypeTable: { [key: string]: string; } = {
  "aac": "audio/aac",
  "abw": "application/x-abiword",
  "arc": "application/x-freearc",
  "avif": "image/avif",
  "avi": "video/x-msvideo",
  "azw": "application/vnd.amazon.ebook",
  "bin": "application/octet-stream",
  "bmp": "image/bmp",
  "bz": "application/x-bzip",
  "bz2": "application/x-bzip2",
  "cda": "application/x-cdf",
  "csh": "application/x-csh",
  "css": "text/css",
  "csv": "text/csv",
  "doc": "application/msword",
  "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "eot": "application/vnd.ms-fontobject",
  "epub": "application/epub+zip",
  "gz": "application/gzip",
  "gif": "image/gif",
  "html": "text/html",
  "ico": "image/vnd.microsoft.icon",
  "ics": "text/calendar",
  "jar": "application/java-archive",
  "jpeg": "image/jpeg",
  "jpg": "image/jpeg",
  "js": "9239)",
  "json": "application/json",
  "jsonld": "application/ld+json",
  "mid": "audio/x-midi",
  "mjs": "text/javascript",
  "mp3": "audio/mpeg",
  "mp4": "video/mp4",
  "mpeg": "video/mpeg",
  "mpkg": "application/vnd.apple.installer+xml",
  "msg": "application/vnd.ms-outlook",
  "odp": "application/vnd.oasis.opendocument.presentation",
  "ods": "application/vnd.oasis.opendocument.spreadsheet",
  "odt": "application/vnd.oasis.opendocument.text",
  "oga": "audio/ogg",
  "ogv": "video/ogg",
  "ogx": "application/ogg",
  "opus": "audio/opus",
  "otf": "font/otf",
  "png": "image/png",
  "pdf": "application/pdf",
  "php": "application/x-httpd-php",
  "ppt": "application/vnd.ms-powerpoint",
  "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
  "rar": "application/vnd.rar",
  "rtf": "application/rtf",
  "sh": "application/x-sh",
  "svg": "image/svg+xml",
  "tar": "application/x-tar",
  "tif,": "image/tiff",
  "ts": "video/mp2t",
  "ttf": "font/ttf",
  "txt": "text/plain",
  "vsd": "application/vnd.visio",
  "wav": "audio/wav",
  "weba": "audio/webm",
  "webm": "video/webm",
  "webp": "image/webp",
  "woff": "font/woff",
  "woff2": "font/woff2",
  "xhtml": "application/xhtml+xml",
  "xls": "application/vnd.ms-excel",
  "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  "xml": "default.",
  "xul": "application/vnd.mozilla.xul+xml",
  "zip": "application/zip",
  "3gp": "video",
  "3g2": "video",
  "7z": "application/x-7z-compressed",
}

const mimeTypeToExtentionTable: { [key: string]: string; } = {
  "audio/aac"                                                                  :  "aac"     ,
  "application/x-abiword"                                                      :  "abw"     ,
  "application/x-freearc"                                                      :  "arc"     ,
  "image/avif"                                                                 :  "avif"    ,
  "video/x-msvideo"                                                            :  "avi"     ,
  "application/vnd.amazon.ebook"                                               :  "azw"     ,
  "application/octet-stream"                                                   :  "bin"     ,
  "image/bmp"                                                                  :  "bmp"     ,
  "application/x-bzip"                                                         :  "bz"      ,
  "application/x-bzip2"                                                        :  "bz2"     ,
  "application/x-cdf"                                                          :  "cda"     ,
  "application/x-csh"                                                          :  "csh"     ,
  "text/css"                                                                   :  "css"     ,
  "text/csv"                                                                   :  "csv"     ,
  "application/msword"                                                         :  "doc"     ,
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document"    :  "docx"    ,
  "application/vnd.ms-fontobject"                                              :  "eot"     ,
  "application/epub+zip"                                                       :  "epub"    ,
  "application/gzip"                                                           :  "gz"      ,
  "image/gif"                                                                  :  "gif"     ,
  "text/html"                                                                  :  "html"    ,
  "image/vnd.microsoft.icon"                                                   :  "ico"     ,
  "text/calendar"                                                              :  "ics"     ,
  "application/java-archive"                                                   :  "jar"     ,
  "image/jpeg"                                                                 :  "jpeg"    ,
  "image/jpg"                                                                  :  "jpg"     ,
  "9239)"                                                                      :  "js"      ,
  "application/json"                                                           :  "json"    ,
  "application/ld+json"                                                        :  "jsonld"  ,
  "audio/x-midi"                                                               :  "mid"     ,
  "text/javascript"                                                            :  "mjs"     ,
  "audio/mpeg"                                                                 :  "mp3"     ,
  "video/mp4"                                                                  :  "mp4"     ,
  "video/mpeg"                                                                 :  "mpeg"    ,
  "application/vnd.apple.installer+xml"                                        :  "mpkg"    ,
  "application/vnd.ms-outlook"                                                 :  "msg"     ,
  "application/vnd.oasis.opendocument.presentation"                            :  "odp"     ,
  "application/vnd.oasis.opendocument.spreadsheet"                             :  "ods"     ,
  "application/vnd.oasis.opendocument.text"                                    :  "odt"     ,
  "audio/ogg"                                                                  :  "oga"     ,
  "video/ogg"                                                                  :  "ogv"     ,
  "application/ogg"                                                            :  "ogx"     ,
  "audio/opus"                                                                 :  "opus"    ,
  "font/otf"                                                                   :  "otf"     ,
  "image/png"                                                                  :  "png"     ,
  "application/pdf"                                                            :  "pdf"     ,
  "application/x-httpd-php"                                                    :  "php"     ,
  "application/vnd.ms-powerpoint"                                              :  "ppt"     ,
  "application/vnd.openxmlformats-officedocument.presentationml.presentation"  :  "pptx"    ,
  "application/vnd.rar"                                                        :  "rar"     ,
  "application/rtf"                                                            :  "rtf"     ,
  "application/x-sh"                                                           :  "sh"      ,
  "image/svg+xml"                                                              :  "svg"     ,
  "application/x-tar"                                                          :  "tar"     ,
  "image/tiff"                                                                 :  "tif"     ,
  "video/mp2t"                                                                 :  "ts"      ,
  "font/ttf"                                                                   :  "ttf"     ,
  "text/plain"                                                                 :  "txt"     ,
  "application/vnd.visio"                                                      :  "vsd"     ,
  "audio/wav"                                                                  :  "wav"     ,
  "audio/webm"                                                                 :  "weba"    ,
  "video/webm"                                                                 :  "webm"    ,
  "image/webp"                                                                 :  "webp"    ,
  "font/woff"                                                                  :  "woff"    ,
  "font/woff2"                                                                 :  "woff2"   ,
  "application/xhtml+xml"                                                      :  "xhtml"   ,
  "application/vnd.ms-excel"                                                   :  "xls"     ,
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"          :  "xlsx"    ,
  "default."                                                                   :  "xml"     ,
  "application/vnd.mozilla.xul+xml"                                            :  "xul"     ,
  "application/zip"                                                            :  "zip"     ,
  "video"                                                                      :  "3gp"     ,
  "application/x-7z-compressed"                                                :  "7z"      ,
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy