-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for q:base
#93
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,24 +26,26 @@ | |
*/ | ||
export const qrlResolver = ( | ||
doc: Document, | ||
eventUrl: string | null | undefined, | ||
linkElm?: HTMLLinkElement, | ||
href?: string, | ||
url?: URL | ||
element: Element | null, | ||
eventUrl?: string | null, | ||
_url?: string, | ||
_base?: string | URL | ||
): URL | undefined => { | ||
if (eventUrl) { | ||
url = new URL( | ||
eventUrl.replace(/^(\w+):(\/)?/, (str, protocol, slash) => { | ||
linkElm = doc.querySelector(`[rel="q.protocol.${protocol}"]`) as HTMLLinkElement; | ||
href = linkElm && linkElm.href; | ||
if (!href) error(protocol + ' not defined'); | ||
return href + (href!.endsWith('/') ? '' : slash || ''); | ||
}), | ||
doc.baseURI | ||
); | ||
url.pathname += '.js'; | ||
if (eventUrl === undefined) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NO, it specifically is looking for |
||
// recursive call | ||
if (element) { | ||
_url = element.getAttribute('q:base')!; | ||
_base = qrlResolver( | ||
doc, | ||
element.parentNode && (element.parentNode as HTMLElement).closest('[q\\:base]') | ||
); | ||
} else { | ||
_url = doc.baseURI; | ||
} | ||
} else if (eventUrl) { | ||
(_url = eventUrl + '.js'), (_base = qrlResolver(doc, element!.closest('[q\\:base]'))); | ||
} | ||
return url; | ||
return _url ? new URL(_url, _base) : undefined; | ||
}; | ||
|
||
const error = (msg: string) => { | ||
|
@@ -67,7 +69,7 @@ export const qwikLoader = (doc: Document, hasInitialized?: boolean | number) => | |
}; | ||
|
||
const dispatch = async (element: Element, eventName: string, ev: Event, url?: URL) => { | ||
url = qrlResolver(doc, element.getAttribute('on:' + eventName)); | ||
url = qrlResolver(doc, element, element.getAttribute('on:' + eventName)); | ||
if (url) { | ||
const handler = getModuleExport( | ||
url, | ||
|
@@ -172,13 +174,14 @@ export const setupPrefetching = ( | |
const intersectionObserverCallback = (items: IntersectionObserverEntry[]) => { | ||
items.forEach((item) => { | ||
if (item.intersectionRatio > 0) { | ||
const attrs = item.target.attributes; | ||
const element = item.target; | ||
const attrs = element.attributes; | ||
for (let i = 0; i < attrs.length; i++) { | ||
const attr = attrs[i]; | ||
const name = attr.name; | ||
const value = attr.value; | ||
if (name.startsWith('on:') && value) { | ||
const url = qrlResolver(doc, value)!; | ||
const url = qrlResolver(doc, element, value)!; | ||
url.hash = url.search = ''; | ||
const key = url.toString(); | ||
if (!qrlCache[key]) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,14 +16,12 @@ import { assertDefined } from '../assert/assert'; | |
/** | ||
* Lazy load a `QRL` symbol and returns the resulting value. | ||
* | ||
* @param base -`QRL`s are relative, and therefore they need a base for resolution. | ||
* - `Element` use `base.ownerDocument.baseURI` | ||
* - `Document` use `base.baseURI` | ||
* @param element - Location of the URL to resolve against. | ||
* @param url - A relative URL (as `string` or `QRL`) or fully qualified `URL` | ||
* @returns A cached value synchronously or promise of imported value. | ||
* @public | ||
*/ | ||
export function qImport<T>(node: Node | Document, url: string | QRL<T> | URL): T | Promise<T> { | ||
export function qImport<T>(element: Element, url: string | QRL<T> | URL): T | Promise<T> { | ||
if (isParsedQRL(url)) { | ||
assertDefined(url._serialized); | ||
url = Array.isArray(url._serialized) ? url._serialized[0] : url._serialized!; | ||
|
@@ -35,9 +33,9 @@ export function qImport<T>(node: Node | Document, url: string | QRL<T> | URL): T | |
return Promise.resolve<T>(testSymbol); | ||
} | ||
} | ||
const doc: QDocument = node.ownerDocument || (node as Document); | ||
const doc: QDocument = element.ownerDocument!; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not possible for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not any more. |
||
const corePlatform = getPlatform(doc); | ||
const normalizedUrl = toUrl(doc, url); | ||
const normalizedUrl = toUrl(doc, element, url); | ||
const importPath = corePlatform.toPath(normalizedUrl); | ||
const exportName = qExport(normalizedUrl); | ||
const cacheKey = importPath + '#' + exportName; | ||
|
@@ -82,43 +80,27 @@ export function qImportSet(doc: QDocument, cacheKey: string, value: any): void { | |
* @param url - relative URL | ||
* @returns fully qualified URL. | ||
*/ | ||
export function toUrl(doc: Document, url: string | QRL | URL): URL { | ||
if (typeof url === 'string') { | ||
const baseURI = getConfig(doc, `baseURI`) || doc.baseURI; | ||
return new URL(adjustProtocol(doc, url), baseURI); | ||
} else { | ||
return url as URL; | ||
} | ||
} | ||
export function toUrl(doc: Document, element: Element | null, url?: string | QRL | URL): URL { | ||
let _url: string | QRL | URL; | ||
let _base: string | URL | undefined = undefined; | ||
|
||
/** | ||
* Convert custom protocol to path by looking it up in `QConfig` | ||
* | ||
* Paths such as | ||
* ``` | ||
* QRL`foo:/bar` | ||
* ``` | ||
* | ||
* The `QRL` looks up `foo` in the document's `<link ref="q.protocol.foo" href="somePath">` | ||
* resulting in `somePath/bar` | ||
* | ||
* @param doc | ||
* @param qrl | ||
* @returns URL where the custom protocol has been resolved. | ||
*/ | ||
function adjustProtocol(doc: Document, qrl: string | QRL): string { | ||
return String(qrl).replace(/(^\w+):\/?/, (all, protocol) => { | ||
let value = getConfig(doc, `protocol.` + protocol); | ||
if (value && !value.endsWith('/')) { | ||
value = value + '/'; | ||
if (url === undefined) { | ||
// recursive call | ||
if (element) { | ||
_url = element.getAttribute('q:base')!; | ||
_base = toUrl( | ||
doc, | ||
element.parentNode && (element.parentNode as HTMLElement).closest('[q\\:base]') | ||
); | ||
} else { | ||
_url = doc.baseURI; | ||
} | ||
return value || all; | ||
}); | ||
} | ||
|
||
function getConfig(doc: Document, configKey: string) { | ||
const linkElm = doc.querySelector(`link[rel="q.${configKey}"]`) as HTMLLinkElement; | ||
return linkElm && linkElm.getAttribute('href'); | ||
} else if (url) { | ||
(_url = url), (_base = toUrl(doc, element!.closest('[q\\:base]'))); | ||
} else { | ||
throw new Error('INTERNAL ERROR'); | ||
} | ||
return new URL(String(_url), _base); | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not important, but why the
_
here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because it is cut and paste from a bootloader where they are parameters to save bytes and I wanted to make it clear that they are not to be used.