mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-16 21:10:02 -04:00
321 lines
7.9 KiB
JavaScript
321 lines
7.9 KiB
JavaScript
/**
|
|
* @typedef {import('./index').default} Ultraviolet
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* @param {Ultraviolet} ctx
|
|
*/
|
|
export function attributes(ctx, meta = ctx.meta) {
|
|
const { html, js, attributePrefix } = ctx;
|
|
const origPrefix = attributePrefix + '-attr-';
|
|
|
|
html.on('attr', (attr, type) => {
|
|
if (
|
|
attr.node.tagName === 'base' &&
|
|
attr.name === 'href' &&
|
|
attr.options.document
|
|
) {
|
|
meta.base = new URL(attr.value, meta.url);
|
|
}
|
|
|
|
if (type === 'rewrite' && isUrl(attr.name, attr.tagName)) {
|
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
|
attr.value = ctx.rewriteUrl(attr.value, meta);
|
|
}
|
|
|
|
if (type === 'rewrite' && isSrcset(attr.name)) {
|
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
|
attr.value = html.wrapSrcset(attr.value, meta);
|
|
}
|
|
|
|
if (type === 'rewrite' && isHtml(attr.name)) {
|
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
|
attr.value = html.rewrite(attr.value, {
|
|
...meta,
|
|
document: true,
|
|
injectHead: attr.options.injectHead || [],
|
|
});
|
|
}
|
|
|
|
if (type === 'rewrite' && isStyle(attr.name)) {
|
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
|
attr.value = ctx.rewriteCSS(attr.value, {
|
|
context: 'declarationList',
|
|
});
|
|
}
|
|
|
|
if (type === 'rewrite' && isForbidden(attr.name)) {
|
|
attr.name = origPrefix + attr.name;
|
|
}
|
|
|
|
if (type === 'rewrite' && isEvent(attr.name)) {
|
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
|
attr.value = js.rewrite(attr.value, meta);
|
|
}
|
|
|
|
if (type === 'source' && attr.name.startsWith(origPrefix)) {
|
|
if (attr.node.hasAttribute(attr.name.slice(origPrefix.length)))
|
|
attr.node.removeAttribute(attr.name.slice(origPrefix.length));
|
|
attr.name = attr.name.slice(origPrefix.length);
|
|
}
|
|
|
|
/*
|
|
if (isHtml(attr.name)) {
|
|
|
|
};
|
|
|
|
if (isStyle(attr.name)) {
|
|
|
|
};
|
|
|
|
if (isSrcset(attr.name)) {
|
|
|
|
};
|
|
*/
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {Ultraviolet} ctx
|
|
*/
|
|
export function text(ctx) {
|
|
const { html, js, css } = ctx;
|
|
|
|
html.on('text', (text, type) => {
|
|
if (text.element.tagName === 'script') {
|
|
text.value =
|
|
type === 'rewrite'
|
|
? js.rewrite(text.value)
|
|
: js.source(text.value);
|
|
}
|
|
|
|
if (text.element.tagName === 'style') {
|
|
text.value =
|
|
type === 'rewrite'
|
|
? css.rewrite(text.value)
|
|
: css.source(text.value);
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
export function isUrl(name, tag) {
|
|
return (
|
|
(tag === 'object' && name === 'data') ||
|
|
[
|
|
'src',
|
|
'href',
|
|
'ping',
|
|
'movie',
|
|
'action',
|
|
'poster',
|
|
'profile',
|
|
'background',
|
|
].indexOf(name) > -1
|
|
);
|
|
}
|
|
|
|
export function isEvent(name) {
|
|
return (
|
|
[
|
|
'onafterprint',
|
|
'onbeforeprint',
|
|
'onbeforeunload',
|
|
'onerror',
|
|
'onhashchange',
|
|
'onload',
|
|
'onmessage',
|
|
'onoffline',
|
|
'ononline',
|
|
'onpagehide',
|
|
'onpopstate',
|
|
'onstorage',
|
|
'onunload',
|
|
'onblur',
|
|
'onchange',
|
|
'oncontextmenu',
|
|
'onfocus',
|
|
'oninput',
|
|
'oninvalid',
|
|
'onreset',
|
|
'onsearch',
|
|
'onselect',
|
|
'onsubmit',
|
|
'onkeydown',
|
|
'onkeypress',
|
|
'onkeyup',
|
|
'onclick',
|
|
'ondblclick',
|
|
'onmousedown',
|
|
'onmousemove',
|
|
'onmouseout',
|
|
'onmouseover',
|
|
'onmouseup',
|
|
'onmousewheel',
|
|
'onwheel',
|
|
'ondrag',
|
|
'ondragend',
|
|
'ondragenter',
|
|
'ondragleave',
|
|
'ondragover',
|
|
'ondragstart',
|
|
'ondrop',
|
|
'onscroll',
|
|
'oncopy',
|
|
'oncut',
|
|
'onpaste',
|
|
'onabort',
|
|
'oncanplay',
|
|
'oncanplaythrough',
|
|
'oncuechange',
|
|
'ondurationchange',
|
|
'onemptied',
|
|
'onended',
|
|
'onerror',
|
|
'onloadeddata',
|
|
'onloadedmetadata',
|
|
'onloadstart',
|
|
'onpause',
|
|
'onplay',
|
|
'onplaying',
|
|
'onprogress',
|
|
'onratechange',
|
|
'onseeked',
|
|
'onseeking',
|
|
'onstalled',
|
|
'onsuspend',
|
|
'ontimeupdate',
|
|
'onvolumechange',
|
|
'onwaiting',
|
|
].indexOf(name) > -1
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {Ultraviolet} ctx
|
|
*/
|
|
export function injectHead(ctx) {
|
|
const { html } = ctx;
|
|
html.on('element', (element, type) => {
|
|
if (type !== 'rewrite') return false;
|
|
if (element.tagName !== 'head') return false;
|
|
if (!('injectHead' in element.options)) return false;
|
|
|
|
element.childNodes.unshift(...element.options.injectHead);
|
|
});
|
|
}
|
|
|
|
export function createJsInject(
|
|
cookies = '',
|
|
referrer = ''
|
|
) {
|
|
return (
|
|
`self.__uv$cookies = ${JSON.stringify(cookies)};` +
|
|
`self.__uv$referrer = ${JSON.stringify(referrer)};`
|
|
);
|
|
}
|
|
|
|
export function createHtmlInject(
|
|
handlerScript,
|
|
bundleScript,
|
|
clientScript,
|
|
configScript,
|
|
cookies,
|
|
referrer
|
|
) {
|
|
return [
|
|
{
|
|
tagName: 'script',
|
|
nodeName: 'script',
|
|
childNodes: [
|
|
{
|
|
nodeName: '#text',
|
|
value: createJsInject(cookies, referrer),
|
|
},
|
|
],
|
|
attrs: [
|
|
{
|
|
name: '__uv-script',
|
|
value: '1',
|
|
skip: true,
|
|
},
|
|
],
|
|
skip: true,
|
|
},
|
|
{
|
|
tagName: 'script',
|
|
nodeName: 'script',
|
|
childNodes: [],
|
|
attrs: [
|
|
{ name: 'src', value: bundleScript, skip: true },
|
|
{
|
|
name: '__uv-script',
|
|
value: '1',
|
|
skip: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
tagName: 'script',
|
|
nodeName: 'script',
|
|
childNodes: [],
|
|
attrs: [
|
|
{ name: 'src', value: clientScript, skip: true },
|
|
{
|
|
name: '__uv-script',
|
|
value: '1',
|
|
skip: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
tagName: 'script',
|
|
nodeName: 'script',
|
|
childNodes: [],
|
|
attrs: [
|
|
{ name: 'src', value: configScript, skip: true },
|
|
{
|
|
name: '__uv-script',
|
|
value: '1',
|
|
skip: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
tagName: 'script',
|
|
nodeName: 'script',
|
|
childNodes: [],
|
|
attrs: [
|
|
{ name: 'src', value: handlerScript, skip: true },
|
|
{
|
|
name: '__uv-script',
|
|
value: '1',
|
|
skip: true,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
}
|
|
|
|
export function isForbidden(name) {
|
|
return (
|
|
['http-equiv', 'integrity', 'sandbox', 'nonce', 'crossorigin'].indexOf(
|
|
name
|
|
) > -1
|
|
);
|
|
}
|
|
|
|
export function isHtml(name) {
|
|
return name === 'srcdoc';
|
|
}
|
|
|
|
export function isStyle(name) {
|
|
return name === 'style';
|
|
}
|
|
|
|
export function isSrcset(name) {
|
|
return name === 'srcset' || name === 'imagesrcset';
|
|
}
|