[ci] format
This commit is contained in:
parent
05915fec01
commit
1cfbd5923f
22 changed files with 172 additions and 159 deletions
|
@ -10,6 +10,7 @@ import { vitePluginAstroServer } from '../vite-plugin-astro-server/index.js';
|
|||
import astroVitePlugin from '../vite-plugin-astro/index.js';
|
||||
import configAliasVitePlugin from '../vite-plugin-config-alias/index.js';
|
||||
import envVitePlugin from '../vite-plugin-env/index.js';
|
||||
import astroHeadPropagationPlugin from '../vite-plugin-head-propagation/index.js';
|
||||
import htmlVitePlugin from '../vite-plugin-html/index.js';
|
||||
import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/index.js';
|
||||
import jsxVitePlugin from '../vite-plugin-jsx/index.js';
|
||||
|
@ -18,7 +19,6 @@ import legacyMarkdownVitePlugin from '../vite-plugin-markdown-legacy/index.js';
|
|||
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
|
||||
import astroScriptsPlugin from '../vite-plugin-scripts/index.js';
|
||||
import astroScriptsPageSSRPlugin from '../vite-plugin-scripts/page-ssr.js';
|
||||
import astroHeadPropagationPlugin from '../vite-plugin-head-propagation/index.js';
|
||||
import { createCustomViteLogger } from './errors/dev/index.js';
|
||||
import { resolveDependency } from './util.js';
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import type { SSRResult } from '../../../@types/astro';
|
|||
|
||||
import type { ModuleInfo, ModuleLoader } from '../../module-loader/index';
|
||||
|
||||
import { viteID } from '../../util.js';
|
||||
import { getAstroMetadata } from '../../../vite-plugin-astro/index.js';
|
||||
import { viteID } from '../../util.js';
|
||||
import { crawlGraph } from './vite.js';
|
||||
|
||||
export async function getPropagationMap(
|
||||
|
@ -13,7 +13,7 @@ export async function getPropagationMap(
|
|||
const map: SSRResult['propagation'] = new Map();
|
||||
|
||||
const rootID = viteID(filePath);
|
||||
addInjection(map, loader.getModuleInfo(rootID))
|
||||
addInjection(map, loader.getModuleInfo(rootID));
|
||||
for await (const moduleNode of crawlGraph(loader, rootID, true)) {
|
||||
const id = moduleNode.id;
|
||||
if (id) {
|
||||
|
@ -28,7 +28,7 @@ function addInjection(map: SSRResult['propagation'], modInfo: ModuleInfo | null)
|
|||
if (modInfo) {
|
||||
const astro = getAstroMetadata(modInfo);
|
||||
if (astro && astro.propagation) {
|
||||
map.set(modInfo.id, astro.propagation)
|
||||
map.set(modInfo.id, astro.propagation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ import { createRenderContext, renderPage as coreRenderPage } from '../index.js';
|
|||
import { filterFoundRenderers, loadRenderer } from '../renderer.js';
|
||||
import { getStylesForURL } from './css.js';
|
||||
import type { DevelopmentEnvironment } from './environment';
|
||||
import { getScriptsForURL } from './scripts.js';
|
||||
import { getPropagationMap } from './head.js';
|
||||
import { getScriptsForURL } from './scripts.js';
|
||||
export { createDevelopmentEnvironment } from './environment.js';
|
||||
export type { DevelopmentEnvironment };
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export { createComponent } from './astro-component.js';
|
||||
export { createAstro } from './astro-global.js';
|
||||
export { renderEndpoint } from './endpoint.js';
|
||||
export { escapeHTML, HTMLBytes, HTMLString, markHTMLString, unescapeHTML } from './escape.js';
|
||||
|
@ -18,17 +19,19 @@ export {
|
|||
renderSlot,
|
||||
renderTemplate as render,
|
||||
renderTemplate,
|
||||
renderUniqueStylesheet,
|
||||
renderToString,
|
||||
renderUniqueStylesheet,
|
||||
stringifyChunk,
|
||||
voidElementNames,
|
||||
} from './render/index.js';
|
||||
export { createComponent } from './astro-component.js';
|
||||
export type { AstroComponentFactory, AstroComponentInstance, RenderInstruction } from './render/index.js';
|
||||
export type {
|
||||
AstroComponentFactory,
|
||||
AstroComponentInstance,
|
||||
RenderInstruction,
|
||||
} from './render/index.js';
|
||||
|
||||
import { markHTMLString } from './escape.js';
|
||||
import { Renderer } from './render/index.js';
|
||||
import { addAttribute } from './render/index.js';
|
||||
import { addAttribute, Renderer } from './render/index.js';
|
||||
|
||||
export function mergeSlots(...slotted: unknown[]) {
|
||||
const slots: Record<string, () => any> = {};
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { escapeHTML, isHTMLString, markHTMLString } from '../escape.js';
|
||||
import { isRenderTemplateResult, renderAstroTemplateResult } from './astro/index.js';
|
||||
import { isAstroComponentInstance } from './astro/index.js';
|
||||
import {
|
||||
isAstroComponentInstance,
|
||||
isRenderTemplateResult,
|
||||
renderAstroTemplateResult,
|
||||
} from './astro/index.js';
|
||||
import { SlotString } from './slot.js';
|
||||
|
||||
export async function* renderChild(child: any): AsyncIterable<any> {
|
||||
|
@ -25,8 +28,7 @@ export async function* renderChild(child: any): AsyncIterable<any> {
|
|||
yield markHTMLString(escapeHTML(child));
|
||||
} else if (!child && child !== 0) {
|
||||
// do nothing, safe to ignore falsey values.
|
||||
}
|
||||
else if(isRenderTemplateResult(child)) {
|
||||
} else if (isRenderTemplateResult(child)) {
|
||||
yield* renderAstroTemplateResult(child);
|
||||
} else if (isAstroComponentInstance(child)) {
|
||||
yield* child.render();
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import type { SSRResult, PropagationHint } from '../../../../@types/astro';
|
||||
import type { PropagationHint, SSRResult } from '../../../../@types/astro';
|
||||
import type { HeadAndContent } from './head-and-content';
|
||||
import type { RenderTemplateResult } from './render-template';
|
||||
|
||||
import { renderAstroTemplateResult } from './render-template.js';
|
||||
import { isHeadAndContent } from './head-and-content.js';
|
||||
import { HTMLParts } from '../common.js';
|
||||
import { isHeadAndContent } from './head-and-content.js';
|
||||
import { renderAstroTemplateResult } from './render-template.js';
|
||||
|
||||
export type AstroFactoryReturnValue = RenderTemplateResult | Response | HeadAndContent;
|
||||
|
||||
|
@ -40,11 +40,13 @@ export async function renderToString(
|
|||
parts.append(chunk, result);
|
||||
}
|
||||
|
||||
|
||||
return parts.toString();
|
||||
}
|
||||
|
||||
export function isAPropagatingComponent(result: SSRResult, factory: AstroComponentFactory): boolean {
|
||||
export function isAPropagatingComponent(
|
||||
result: SSRResult,
|
||||
factory: AstroComponentFactory
|
||||
): boolean {
|
||||
let hint: PropagationHint = factory.propagation || 'none';
|
||||
if (factory.moduleId && result.propagation.has(factory.moduleId) && hint === 'none') {
|
||||
hint = result.propagation.get(factory.moduleId)!;
|
||||
|
|
|
@ -6,10 +6,10 @@ export type HeadAndContent = {
|
|||
[headAndContentSym]: true;
|
||||
head: string | RenderTemplateResult;
|
||||
content: RenderTemplateResult;
|
||||
}
|
||||
};
|
||||
|
||||
export function isHeadAndContent(obj: unknown): obj is HeadAndContent {
|
||||
return typeof obj === 'object' && !!((obj as any)[headAndContentSym]);
|
||||
return typeof obj === 'object' && !!(obj as any)[headAndContentSym];
|
||||
}
|
||||
|
||||
export function createHeadAndContent(
|
||||
|
@ -19,6 +19,6 @@ export function createHeadAndContent(
|
|||
return {
|
||||
[headAndContentSym]: true,
|
||||
head,
|
||||
content
|
||||
}
|
||||
content,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,25 +1,10 @@
|
|||
|
||||
export {
|
||||
createAstroComponentInstance,
|
||||
isAstroComponentInstance
|
||||
} from './instance.js';
|
||||
export {
|
||||
isAstroComponentFactory,
|
||||
renderToString
|
||||
} from './factory.js';
|
||||
export type { AstroComponentFactory } from './factory';
|
||||
export { isAstroComponentFactory, renderToString } from './factory.js';
|
||||
export { createHeadAndContent, isHeadAndContent } from './head-and-content.js';
|
||||
export type { AstroComponentInstance } from './instance';
|
||||
export { createAstroComponentInstance, isAstroComponentInstance } from './instance.js';
|
||||
export {
|
||||
isRenderTemplateResult,
|
||||
renderAstroTemplateResult,
|
||||
renderTemplate
|
||||
renderTemplate,
|
||||
} from './render-template.js';
|
||||
export {
|
||||
isHeadAndContent,
|
||||
createHeadAndContent
|
||||
} from './head-and-content.js';
|
||||
|
||||
export type {
|
||||
AstroComponentFactory
|
||||
} from './factory';
|
||||
export type {
|
||||
AstroComponentInstance
|
||||
} from './instance';
|
||||
|
|
|
@ -2,10 +2,10 @@ import type { SSRResult } from '../../../../@types/astro';
|
|||
import type { AstroComponentFactory, AstroFactoryReturnValue } from './factory.js';
|
||||
|
||||
import { HydrationDirectiveProps } from '../../hydration.js';
|
||||
import { renderChild } from '../any.js';
|
||||
import { isHeadAndContent } from './head-and-content.js';
|
||||
import { isAPropagatingComponent } from './factory.js';
|
||||
import { isPromise } from '../../util.js';
|
||||
import { renderChild } from '../any.js';
|
||||
import { isAPropagatingComponent } from './factory.js';
|
||||
import { isHeadAndContent } from './head-and-content.js';
|
||||
|
||||
type ComponentProps = Record<string | number, any>;
|
||||
|
||||
|
@ -19,7 +19,12 @@ export class AstroComponentInstance {
|
|||
private readonly slots: any;
|
||||
private readonly factory: AstroComponentFactory;
|
||||
private returnValue: ReturnType<AstroComponentFactory> | undefined;
|
||||
constructor(result: SSRResult, props: ComponentProps, slots: any, factory: AstroComponentFactory) {
|
||||
constructor(
|
||||
result: SSRResult,
|
||||
props: ComponentProps,
|
||||
slots: any,
|
||||
factory: AstroComponentFactory
|
||||
) {
|
||||
this.result = result;
|
||||
this.props = props;
|
||||
this.slots = slots;
|
||||
|
@ -78,5 +83,5 @@ export function createAstroComponentInstance(
|
|||
}
|
||||
|
||||
export function isAstroComponentInstance(obj: unknown): obj is AstroComponentInstance {
|
||||
return typeof obj === 'object' && !!((obj as any)[astroComponentInstanceSym]);
|
||||
return typeof obj === 'object' && !!(obj as any)[astroComponentInstanceSym];
|
||||
}
|
||||
|
|
|
@ -52,9 +52,7 @@ export class RenderTemplateResult {
|
|||
|
||||
// Determines if a component is an .astro component
|
||||
export function isRenderTemplateResult(obj: unknown): obj is RenderTemplateResult {
|
||||
return (
|
||||
typeof obj === 'object' && !!((obj as any)[renderTemplateResultSym])
|
||||
);
|
||||
return typeof obj === 'object' && !!(obj as any)[renderTemplateResultSym];
|
||||
}
|
||||
|
||||
export async function* renderAstroTemplateResult(
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
import type {
|
||||
AstroComponentMetadata,
|
||||
RouteData,
|
||||
SSRLoadedRenderer,
|
||||
SSRResult,
|
||||
} from '../../../@types/astro';
|
||||
import type { AstroComponentMetadata, SSRLoadedRenderer, SSRResult } from '../../../@types/astro';
|
||||
import type { RenderInstruction } from './types.js';
|
||||
|
||||
import { AstroError, AstroErrorData } from '../../../core/errors/index.js';
|
||||
|
@ -11,19 +6,19 @@ import { HTMLBytes, markHTMLString } from '../escape.js';
|
|||
import { extractDirectives, generateHydrateScript } from '../hydration.js';
|
||||
import { serializeProps } from '../serialize.js';
|
||||
import { shorthash } from '../shorthash.js';
|
||||
import { isPromise } from '../util.js';
|
||||
import {
|
||||
createAstroComponentInstance,
|
||||
isAstroComponentFactory,
|
||||
isAstroComponentInstance,
|
||||
renderAstroTemplateResult,
|
||||
renderTemplate,
|
||||
type AstroComponentInstance
|
||||
type AstroComponentInstance,
|
||||
} from './astro/index.js';
|
||||
import { Fragment, Renderer, stringifyChunk } from './common.js';
|
||||
import { componentIsHTMLElement, renderHTMLElement } from './dom.js';
|
||||
import { renderSlot, renderSlots } from './slot.js';
|
||||
import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from './util.js';
|
||||
import { isPromise } from '../util.js';
|
||||
|
||||
const rendererAliases = new Map([['solid', 'solid-js']]);
|
||||
|
||||
|
@ -55,9 +50,7 @@ function isFragmentComponent(Component: unknown) {
|
|||
}
|
||||
|
||||
function isHTMLComponent(Component: unknown) {
|
||||
return (
|
||||
Component && typeof Component === 'object' && (Component as any)['astro:html']
|
||||
);
|
||||
return Component && typeof Component === 'object' && (Component as any)['astro:html'];
|
||||
}
|
||||
|
||||
async function renderFrameworkComponent(
|
||||
|
@ -65,7 +58,7 @@ async function renderFrameworkComponent(
|
|||
displayName: string,
|
||||
Component: unknown,
|
||||
_props: Record<string | number, any>,
|
||||
slots: any = {},
|
||||
slots: any = {}
|
||||
): Promise<ComponentIterable> {
|
||||
if (!Component && !_props['client:only']) {
|
||||
throw new Error(
|
||||
|
@ -359,7 +352,7 @@ export function renderComponent(
|
|||
slots: any = {}
|
||||
): Promise<ComponentIterable> | ComponentIterable | AstroComponentInstance {
|
||||
if (isPromise(Component)) {
|
||||
return Promise.resolve(Component).then(Unwrapped => {
|
||||
return Promise.resolve(Component).then((Unwrapped) => {
|
||||
return renderComponent(result, displayName, Unwrapped, props, slots) as any;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type { SSRResult } from '../../../@types/astro';
|
||||
|
||||
import { markHTMLString } from '../escape.js';
|
||||
import { renderElement } from './util.js';
|
||||
import { renderChild } from './any.js';
|
||||
import { renderElement } from './util.js';
|
||||
|
||||
// Filter out duplicate elements in our set
|
||||
const uniqueElements = (item: any, index: number, all: any[]) => {
|
||||
|
@ -35,7 +35,7 @@ function renderAllHeadContent(result: SSRResult) {
|
|||
.filter(uniqueElements)
|
||||
.map((link) => renderElement('link', link, false));
|
||||
|
||||
const baseHeadContent = markHTMLString(links.join('\n') + styles.join('\n') + scripts.join('\n'))
|
||||
const baseHeadContent = markHTMLString(links.join('\n') + styles.join('\n') + scripts.join('\n'));
|
||||
|
||||
if (result.extraHead.length > 0) {
|
||||
return renderExtraHead(result, baseHeadContent);
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
export type { RenderInstruction } from './types';
|
||||
export type { AstroComponentFactory, AstroComponentInstance } from './astro/index';
|
||||
|
||||
export { createHeadAndContent, renderAstroTemplateResult, renderToString, renderTemplate } from './astro/index.js';
|
||||
export {
|
||||
createHeadAndContent,
|
||||
renderAstroTemplateResult,
|
||||
renderTemplate,
|
||||
renderToString,
|
||||
} from './astro/index.js';
|
||||
export { Fragment, Renderer, stringifyChunk } from './common.js';
|
||||
export { renderComponent, renderComponentToIterable } from './component.js';
|
||||
export { renderHTMLElement } from './dom.js';
|
||||
export { maybeRenderHead, renderHead } from './head.js';
|
||||
export { renderPage } from './page.js';
|
||||
export { renderSlot } from './slot.js';
|
||||
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
|
||||
export { renderUniqueStylesheet } from './stylesheet.js';
|
||||
export type { RenderInstruction } from './types';
|
||||
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
|
||||
|
|
|
@ -8,9 +8,9 @@ import { createResponse } from '../response.js';
|
|||
import {
|
||||
isAstroComponentFactory,
|
||||
isAstroComponentInstance,
|
||||
isRenderTemplateResult,
|
||||
isHeadAndContent,
|
||||
renderAstroTemplateResult
|
||||
isRenderTemplateResult,
|
||||
renderAstroTemplateResult,
|
||||
} from './astro/index.js';
|
||||
import { chunkToByteArray, encoder, HTMLParts } from './common.js';
|
||||
import { renderComponent } from './component.js';
|
||||
|
@ -85,7 +85,7 @@ export async function renderPage(
|
|||
componentFactory.name,
|
||||
componentFactory,
|
||||
pageProps,
|
||||
null,
|
||||
null
|
||||
);
|
||||
if (isAstroComponentInstance(renderResult)) {
|
||||
output = renderResult.render();
|
||||
|
@ -123,7 +123,9 @@ export async function renderPage(
|
|||
if (isRenderTemplateResult(factoryReturnValue) || factoryIsHeadAndContent) {
|
||||
// Wait for head content to be buffered up
|
||||
await bufferHeadContent(result);
|
||||
const templateResult = factoryIsHeadAndContent ? factoryReturnValue.content : factoryReturnValue;
|
||||
const templateResult = factoryIsHeadAndContent
|
||||
? factoryReturnValue.content
|
||||
: factoryReturnValue;
|
||||
|
||||
let iterable = renderAstroTemplateResult(templateResult);
|
||||
let init = result.response;
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
import { SSRResult } from '../../../@types/astro';
|
||||
import { renderElement } from './util.js';
|
||||
import { markHTMLString } from '../escape.js';
|
||||
import { renderElement } from './util.js';
|
||||
|
||||
const stylesheetRel = 'stylesheet';
|
||||
|
||||
export function renderStylesheet({ href }: { href: string }) {
|
||||
return markHTMLString(renderElement('link', {
|
||||
return markHTMLString(
|
||||
renderElement(
|
||||
'link',
|
||||
{
|
||||
props: {
|
||||
rel: stylesheetRel,
|
||||
href
|
||||
href,
|
||||
},
|
||||
children: ''
|
||||
}, false));
|
||||
children: '',
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function renderUniqueStylesheet(result: SSRResult, link: { href: string }) {
|
||||
|
|
|
@ -18,8 +18,8 @@ import { normalizeFilename } from '../vite-plugin-utils/index.js';
|
|||
import { cachedFullCompilation } from './compile.js';
|
||||
import { handleHotUpdate } from './hmr.js';
|
||||
import { parseAstroRequest, ParsedRequestResult } from './query.js';
|
||||
export type { AstroPluginMetadata };
|
||||
export { getAstroMetadata } from './metadata.js';
|
||||
export type { AstroPluginMetadata };
|
||||
|
||||
interface AstroPluginOptions {
|
||||
settings: AstroSettings;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { PluginMetadata } from './types';
|
||||
import type { ModuleInfo } from '../core/module-loader';
|
||||
import type { PluginMetadata } from './types';
|
||||
|
||||
export function getAstroMetadata(modInfo: ModuleInfo): PluginMetadata['astro'] | undefined {
|
||||
if (modInfo.meta?.astro) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { AstroSettings } from '../@types/astro';
|
||||
import type { ModuleInfo } from 'rollup';
|
||||
import type { AstroSettings } from '../@types/astro';
|
||||
|
||||
import * as vite from 'vite';
|
||||
import { getAstroMetadata } from '../vite-plugin-astro/index.js';
|
||||
|
@ -16,7 +16,12 @@ export default function configHeadPropagationVitePlugin({
|
|||
}: {
|
||||
settings: AstroSettings;
|
||||
}): vite.Plugin {
|
||||
function addHeadInjectionInTree(graph: vite.ModuleGraph, id: string, getInfo: (id: string) => ModuleInfo | null, seen: Set<string> = new Set()) {
|
||||
function addHeadInjectionInTree(
|
||||
graph: vite.ModuleGraph,
|
||||
id: string,
|
||||
getInfo: (id: string) => ModuleInfo | null,
|
||||
seen: Set<string> = new Set()
|
||||
) {
|
||||
const mod = server.moduleGraph.getModuleById(id);
|
||||
for (const parent of mod?.importers || []) {
|
||||
if (parent.id) {
|
||||
|
@ -49,6 +54,6 @@ export default function configHeadPropagationVitePlugin({
|
|||
if (injectExp.test(source)) {
|
||||
addHeadInjectionInTree(server.moduleGraph, id, (child) => this.getModuleInfo(child));
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ ${tsResult}`;
|
|||
clientOnlyComponents: transformResult.clientOnlyComponents,
|
||||
hydratedComponents: transformResult.hydratedComponents,
|
||||
scripts: transformResult.scripts,
|
||||
propagation: 'none'
|
||||
propagation: 'none',
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
@ -55,12 +55,15 @@ describe('head injection', () => {
|
|||
root
|
||||
);
|
||||
|
||||
await runInContainer({
|
||||
fs, root,
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
root,
|
||||
userConfig: {
|
||||
vite: { server: { middlewareMode: true } }
|
||||
}
|
||||
}, async (container) => {
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
async (container) => {
|
||||
const { req, res, done, text } = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
|
@ -72,7 +75,8 @@ describe('head injection', () => {
|
|||
|
||||
expect($('link[rel=stylesheet][href="/some/fake/styles.css"]')).to.have.a.lengthOf(1);
|
||||
expect($('#other')).to.have.a.lengthOf(1);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Dynamic injection from a layout component', async () => {
|
||||
|
@ -138,12 +142,15 @@ describe('head injection', () => {
|
|||
root
|
||||
);
|
||||
|
||||
await runInContainer({
|
||||
fs, root,
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
root,
|
||||
userConfig: {
|
||||
vite: { server: { middlewareMode: true } }
|
||||
}
|
||||
}, async (container) => {
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
async (container) => {
|
||||
const { req, res, done, text } = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
|
@ -155,6 +162,7 @@ describe('head injection', () => {
|
|||
|
||||
expect($('link[rel=stylesheet][href="/some/fake/styles.css"]')).to.have.a.lengthOf(1);
|
||||
expect($('#other')).to.have.a.lengthOf(1);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue