121 lines
3.4 KiB
JavaScript
121 lines
3.4 KiB
JavaScript
|
|
// Minimal URL polyfill for environments (like uni-app APP service layer) that
|
||
|
|
// don't provide a native URL implementation. It only supports the pieces that
|
||
|
|
// our codebase relies on: resolving href/origin/pathname and providing
|
||
|
|
// createObjectURL/revokeObjectURL stubs.
|
||
|
|
|
||
|
|
(function ensureURLPolyfill() {
|
||
|
|
if (typeof URL !== 'undefined') {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
const globalObj = typeof globalThis !== 'undefined'
|
||
|
|
? globalThis
|
||
|
|
: (typeof global !== 'undefined'
|
||
|
|
? global
|
||
|
|
: (typeof self !== 'undefined'
|
||
|
|
? self
|
||
|
|
: (typeof window !== 'undefined' ? window : {})))
|
||
|
|
|
||
|
|
const ABSOLUTE_URL_REGEX = /^([a-zA-Z][a-zA-Z0-9+.-]*:)?\/\/([^\/?#:]+)(?::(\d+))?(\/[^?#]*)?([\?][^#]*)?(#.*)?$/
|
||
|
|
|
||
|
|
function normalizePath(path) {
|
||
|
|
if (!path) return '/'
|
||
|
|
if (!path.startsWith('/')) return '/' + path
|
||
|
|
return path
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseAbsoluteUrl(url) {
|
||
|
|
const match = url.match(ABSOLUTE_URL_REGEX)
|
||
|
|
if (!match) return null
|
||
|
|
const protocol = match[1] || ''
|
||
|
|
const hostname = match[2] || ''
|
||
|
|
const port = match[3] || ''
|
||
|
|
const pathname = normalizePath(match[4] || '/')
|
||
|
|
const search = match[5] || ''
|
||
|
|
const hash = match[6] || ''
|
||
|
|
const host = hostname + (port ? ':' + port : '')
|
||
|
|
const origin = protocol ? `${protocol}//${host}` : ''
|
||
|
|
return { protocol, hostname, port, pathname, search, hash, host, origin, href: `${origin}${pathname}${search}${hash}` }
|
||
|
|
}
|
||
|
|
|
||
|
|
function isAbsolute(url) {
|
||
|
|
return /^([a-zA-Z][a-zA-Z0-9+.-]*:)?\/\//.test(url)
|
||
|
|
}
|
||
|
|
|
||
|
|
function resolveUrl(input, base) {
|
||
|
|
if (isAbsolute(input)) {
|
||
|
|
return input
|
||
|
|
}
|
||
|
|
if (base && isAbsolute(base)) {
|
||
|
|
const baseParts = parseAbsoluteUrl(base)
|
||
|
|
if (!baseParts) return input
|
||
|
|
if (input.startsWith('/')) {
|
||
|
|
return `${baseParts.origin}${input}`
|
||
|
|
}
|
||
|
|
const dir = baseParts.pathname.endsWith('/')
|
||
|
|
? baseParts.pathname
|
||
|
|
: baseParts.pathname.replace(/[^/]+$/, '/')
|
||
|
|
return `${baseParts.origin}${dir}${input}`
|
||
|
|
}
|
||
|
|
return input
|
||
|
|
}
|
||
|
|
|
||
|
|
class URLPolyfill {
|
||
|
|
constructor(input, base) {
|
||
|
|
const resolved = resolveUrl(String(input || ''), base ? String(base) : undefined)
|
||
|
|
const parsed = parseAbsoluteUrl(resolved)
|
||
|
|
if (parsed) {
|
||
|
|
this.href = parsed.href
|
||
|
|
this.protocol = parsed.protocol
|
||
|
|
this.hostname = parsed.hostname
|
||
|
|
this.port = parsed.port
|
||
|
|
this.pathname = parsed.pathname
|
||
|
|
this.search = parsed.search
|
||
|
|
this.hash = parsed.hash
|
||
|
|
this.host = parsed.host
|
||
|
|
this.origin = parsed.origin
|
||
|
|
} else {
|
||
|
|
this.href = resolved
|
||
|
|
this.protocol = ''
|
||
|
|
this.hostname = ''
|
||
|
|
this.port = ''
|
||
|
|
this.pathname = resolved || '/'
|
||
|
|
this.search = ''
|
||
|
|
this.hash = ''
|
||
|
|
this.host = ''
|
||
|
|
this.origin = ''
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
toString() {
|
||
|
|
return this.href
|
||
|
|
}
|
||
|
|
|
||
|
|
static createObjectURL(blob) {
|
||
|
|
console.warn('[URL polyfill] createObjectURL fallback used')
|
||
|
|
if (typeof blob === 'string') {
|
||
|
|
return blob
|
||
|
|
}
|
||
|
|
if (typeof FileReader !== 'undefined' && blob) {
|
||
|
|
try {
|
||
|
|
const reader = new FileReader()
|
||
|
|
reader.readAsDataURL(blob)
|
||
|
|
return ''
|
||
|
|
} catch (e) {
|
||
|
|
console.warn('[URL polyfill] createObjectURL fallback failed:', e)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 'data:application/octet-stream;base64,'
|
||
|
|
}
|
||
|
|
|
||
|
|
static revokeObjectURL() {
|
||
|
|
// No-op in polyfill
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
globalObj.URL = URLPolyfill
|
||
|
|
})()
|
||
|
|
|
||
|
|
|
||
|
|
|