diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 6fadc82cde..8881cbb558 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,4 +1,9 @@
-import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ inject,
+ OnInit,
+} from '@angular/core';
import { NavigationEnd, NavigationStart, Router } from '@angular/router';
import { PlatformService } from 'src/app/site-common/platform.service';
import { environment } from '../environments/environment';
@@ -7,18 +12,20 @@ import { SiteMetaService } from './site-common/site-meta.service';
import { TrackService } from './site-common/track.service';
import { filter, pairwise, startWith } from 'rxjs';
-declare let gtag: Function;
+declare const gtag: (
+ command: string,
+ action: string,
+ config: { page_path: string }
+) => void;
@Component({
standalone: true,
selector: 'app-root',
- imports: [
- LayoutComponent,
- ],
+ imports: [LayoutComponent],
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class AppComponent {
+export class AppComponent implements OnInit {
private router = inject(Router);
private platformService = inject(PlatformService);
private siteMetaService = inject(SiteMetaService);
@@ -42,10 +49,14 @@ export class AppComponent {
startWith(null),
pairwise()
)
- .subscribe((events: [any, any]) => {
+ .subscribe((events) => {
if (!this.platformService.isServer && environment.production) {
- this.trackService.sendTrack(events[0]?.url || '');
- gtag('event', 'page_view', { page_path: events[1].url });
+ this.trackService.sendTrack(
+ (events[0] as NavigationEnd | null)?.url || ''
+ );
+ gtag('event', 'page_view', {
+ page_path: (events[1] as NavigationEnd | null)?.url || '',
+ });
}
});
}
diff --git a/src/app/blog/blog-archives/blog-archives-posts-resolve.ts b/src/app/blog/blog-archives/blog-archives-posts-resolve.ts
index f9b374e771..f9538d2819 100644
--- a/src/app/blog/blog-archives/blog-archives-posts-resolve.ts
+++ b/src/app/blog/blog-archives/blog-archives-posts-resolve.ts
@@ -1,5 +1,4 @@
import { Injectable, inject } from '@angular/core';
-import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { PostMetaWithSlug } from '../../site-common/post-meta.interface';
import { SitePostService } from '../../site-common/site-post.service';
@@ -10,10 +9,7 @@ import { SitePostService } from '../../site-common/site-post.service';
export class BlogArchivesPostsResolve {
private sitePostService = inject(SitePostService);
- resolve(
- route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot
- ): Observable {
+ resolve(): Observable {
return this.sitePostService.postsMetaWithSlugAndSortDesc$;
}
}
diff --git a/src/app/blog/blog-archives/blog-archives.component.ts b/src/app/blog/blog-archives/blog-archives.component.ts
index 02260f49d1..cd304dc30a 100644
--- a/src/app/blog/blog-archives/blog-archives.component.ts
+++ b/src/app/blog/blog-archives/blog-archives.component.ts
@@ -105,7 +105,7 @@ export class BlogArchivesComponent {
return pagePosts.reduce((prev, curr) => {
const year = curr.date.slice(0, 4);
- let yearPosts = prev.find((item) => item.year === year);
+ const yearPosts = prev.find((item) => item.year === year);
if (!yearPosts) {
prev.push({
year,
diff --git a/src/app/blog/blog-categories/blog-categories-posts-resolve.ts b/src/app/blog/blog-categories/blog-categories-posts-resolve.ts
index 9a43461aa5..8657488a99 100644
--- a/src/app/blog/blog-categories/blog-categories-posts-resolve.ts
+++ b/src/app/blog/blog-categories/blog-categories-posts-resolve.ts
@@ -1,5 +1,5 @@
import { Injectable, inject } from '@angular/core';
-import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { ActivatedRouteSnapshot } from '@angular/router';
import { descend, prop, sortWith } from 'ramda';
import { Observable, map } from 'rxjs';
import { PostMetaWithSlug } from '../../site-common/post-meta.interface';
@@ -12,7 +12,7 @@ import { findPosts } from '../find-posts';
export class BlogCategoriesPostsResolve {
private sitePostService = inject(SitePostService);
- resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
+ resolve(route: ActivatedRouteSnapshot): Observable {
const categorySlug = route.paramMap.get('category-slug') as string;
return this.sitePostService.categoriesAndPosts$
diff --git a/src/app/blog/blog-categories/blog-categories-resolve.ts b/src/app/blog/blog-categories/blog-categories-resolve.ts
index 698a09183d..bfef7d9c0c 100644
--- a/src/app/blog/blog-categories/blog-categories-resolve.ts
+++ b/src/app/blog/blog-categories/blog-categories-resolve.ts
@@ -1,5 +1,4 @@
import { Injectable, inject } from '@angular/core';
-import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { PostMetaWithSlug } from '../../site-common/post-meta.interface';
import { SitePostService } from '../../site-common/site-post.service';
@@ -10,7 +9,7 @@ import { SitePostService } from '../../site-common/site-post.service';
export class BlogCategoriesResolve {
private sitePostService = inject(SitePostService);
- resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<{ [key:string] :PostMetaWithSlug[]}> {
+ resolve(): Observable<{ [key:string] :PostMetaWithSlug[]}> {
return this.sitePostService.categoriesAndPosts$;
}
}
diff --git a/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts b/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts
index 07df9d0693..27d0170a76 100644
--- a/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts
+++ b/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts
@@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http';
import { Injectable, TransferState, inject, makeStateKey } from '@angular/core';
-import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable, catchError, map, of, tap, timeout } from 'rxjs';
import { MarkdownMeta, parseMarkdownMeta } from 'site-utils';
import { environment } from '../../../../environments/environment';
@@ -14,7 +14,7 @@ export class BlogContentResolve {
private state = inject(TransferState);
private platformService = inject(PlatformService);
- resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
+ resolve(route: ActivatedRouteSnapshot): Observable {
return this.getMarkdownContent(route.paramMap.get('slug') as string);
}
diff --git a/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts b/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts
index 67d1137bff..46d34ca5be 100644
--- a/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts
+++ b/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts
@@ -6,7 +6,7 @@ import {
OnDestroy,
TransferState,
inject,
- makeStateKey
+ makeStateKey,
} from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { Observable, ReplaySubject, map, startWith, switchMap } from 'rxjs';
@@ -85,7 +85,7 @@ const HEADINGS_CACHE_KEY = makeStateKey('POST_TOC');
}`,
standalone: true,
imports: [],
- changeDetection: ChangeDetectionStrategy.OnPush
+ changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BlogPostTocComponent implements OnDestroy {
private transferState = inject(TransferState);
@@ -170,7 +170,7 @@ export class BlogPostTocComponent implements OnDestroy {
const containerElement = element.closest(
'.mat-drawer-content.main-content'
);
- let options = {
+ const options = {
root: containerElement,
rootMargin: '0px',
threshold: 1.0,
@@ -213,17 +213,19 @@ export class BlogPostTocComponent implements OnDestroy {
}
private getTocHeadings(element: HTMLElement) {
- let result: any[] = [];
+ const result: Array<{
+ text: string | null;
+ level: number;
+ element: Element | null;
+ active: boolean;
+ }> = [];
element.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach((head) => {
- result = [
- ...result,
- {
- text: head.textContent,
- level: +head.tagName.replace(/h(.)/i, '$1'),
- element: this.platformService.isServer ? null : head,
- active: false,
- },
- ];
+ result.push({
+ text: head.textContent,
+ level: +head.tagName.replace(/h(.)/i, '$1'),
+ element: this.platformService.isServer ? null : head,
+ active: false,
+ });
});
return result;
}
diff --git a/src/app/blog/blog-posts/blog-post/blog-post.component.ts b/src/app/blog/blog-posts/blog-post/blog-post.component.ts
index 8a5398df28..5c724f7ee2 100644
--- a/src/app/blog/blog-posts/blog-post/blog-post.component.ts
+++ b/src/app/blog/blog-posts/blog-post/blog-post.component.ts
@@ -13,7 +13,7 @@ import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { DomSanitizer } from '@angular/platform-browser';
-import { ActivatedRoute, RouterLink } from '@angular/router';
+import { RouterLink } from '@angular/router';
import { MarkdownMeta } from 'site-utils';
import { getRouteData } from 'src/app/site-common/route-utils';
import { findMainContentContainer, scrollTo } from '../../../../utils';
diff --git a/src/app/blog/blog-tags/blog-tags-posts-resolve.ts b/src/app/blog/blog-tags/blog-tags-posts-resolve.ts
index c247250ab8..2b0fec9b58 100644
--- a/src/app/blog/blog-tags/blog-tags-posts-resolve.ts
+++ b/src/app/blog/blog-tags/blog-tags-posts-resolve.ts
@@ -1,5 +1,5 @@
import { Injectable, inject } from '@angular/core';
-import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { ActivatedRouteSnapshot } from '@angular/router';
import { descend, prop, sortWith } from 'ramda';
import { Observable, map } from 'rxjs';
import { PostMetaWithSlug } from '../../site-common/post-meta.interface';
@@ -12,10 +12,7 @@ import { findPosts } from '../find-posts';
export class BlogTagsPostsResolve {
private sitePostService = inject(SitePostService);
- resolve(
- route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot
- ): Observable {
+ resolve(route: ActivatedRouteSnapshot): Observable {
const tagSlug = route.paramMap.get('tag-slug') as string;
return this.sitePostService.tagsAndPosts$.pipe(
diff --git a/src/app/blog/blog-tags/blog-tags-resolve.ts b/src/app/blog/blog-tags/blog-tags-resolve.ts
index 45c307d830..919fdd652d 100644
--- a/src/app/blog/blog-tags/blog-tags-resolve.ts
+++ b/src/app/blog/blog-tags/blog-tags-resolve.ts
@@ -1,5 +1,4 @@
import { Injectable, inject } from '@angular/core';
-import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { PostMetaWithSlug } from '../../site-common/post-meta.interface';
import { SitePostService } from '../../site-common/site-post.service';
@@ -10,10 +9,7 @@ import { SitePostService } from '../../site-common/site-post.service';
export class BlogTagsResolve {
private sitePostService = inject(SitePostService);
- resolve(
- route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot
- ): Observable<{ [key: string]: PostMetaWithSlug[] }> {
+ resolve(): Observable<{ [key: string]: PostMetaWithSlug[] }> {
return this.sitePostService.tagsAndPosts$;
}
}
diff --git a/src/app/layout/layout.component.ts b/src/app/layout/layout.component.ts
index a99a78635c..25730ce843 100644
--- a/src/app/layout/layout.component.ts
+++ b/src/app/layout/layout.component.ts
@@ -166,7 +166,7 @@ export class LayoutComponent implements OnInit {
ngOnInit() {
this.router.events
.pipe(filter((event) => event instanceof NavigationStart))
- .subscribe((url) => {
+ .subscribe(() => {
if (this.matDrawerContent) {
this.matDrawerContent.scrollTo({ top: 0, left: 0 });
this.cdr.detectChanges();
diff --git a/src/app/site-common/blog-post-subtitle.component.ts b/src/app/site-common/blog-post-subtitle.component.ts
index 562403b0b7..b9fbb1c31e 100644
--- a/src/app/site-common/blog-post-subtitle.component.ts
+++ b/src/app/site-common/blog-post-subtitle.component.ts
@@ -1,9 +1,9 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, Input } from '@angular/core';
+import { MatIconModule } from '@angular/material/icon';
+import { RouterLink } from '@angular/router';
import { MarkdownMeta } from 'site-utils';
import { PostMeta } from './post-meta.interface';
import { SlugifyPipe } from './slugify.pipe';
-import { RouterLink } from '@angular/router';
-import { MatIconModule } from '@angular/material/icon';
@Component({
selector: 'app-blog-post-subtitle',
diff --git a/src/app/site-common/pagination.component.ts b/src/app/site-common/pagination.component.ts
index 89e90aefa5..37f0649aac 100644
--- a/src/app/site-common/pagination.component.ts
+++ b/src/app/site-common/pagination.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { RouterLink } from '@angular/router';
import { MatTooltipModule } from '@angular/material/tooltip';
diff --git a/src/app/site-common/platform.service.ts b/src/app/site-common/platform.service.ts
index 34fe3dc94a..503968387b 100644
--- a/src/app/site-common/platform.service.ts
+++ b/src/app/site-common/platform.service.ts
@@ -1,6 +1,6 @@
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { isPlatformServer } from '@angular/common';
-import { Inject, Injectable, PLATFORM_ID, inject } from '@angular/core';
+import { Injectable, PLATFORM_ID, inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { map, shareReplay } from 'rxjs';
diff --git a/src/app/site-common/route-utils.ts b/src/app/site-common/route-utils.ts
index 775776da29..16b30b6f95 100644
--- a/src/app/site-common/route-utils.ts
+++ b/src/app/site-common/route-utils.ts
@@ -8,6 +8,7 @@ export const getRouteParam = (getFn: (paramMap: ParamMap, index?: number) =>
const param$ = route.paramMap.pipe(
map(getFn)
);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
return toSignal(param$, { initialValue: initialValue as any }) as Signal;
};
@@ -16,5 +17,6 @@ export const getRouteData = (getFn: (data: Data, index?: number) => T, initia
const data$ = route.data.pipe(
map(getFn)
);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
return toSignal(data$, { initialValue: initialValue as any })as Signal;
}
diff --git a/src/app/site-common/search-posts.ts b/src/app/site-common/search-posts.ts
index 46d708934e..0f17a2e3ae 100644
--- a/src/app/site-common/search-posts.ts
+++ b/src/app/site-common/search-posts.ts
@@ -3,46 +3,60 @@ import { PostMetaWithSlug } from './post-meta.interface';
const searchFieldMapping = {
tag: '標籤',
- category: '分類'
-}
+ category: '分類',
+};
-const getSearchFieldName = (fieldName: string) => {
- return (searchFieldMapping as any)[fieldName] || '';
-}
-
-export const searchPostsByDateRange = (start?: Date, end?: Date) => (posts: PostMetaWithSlug[]) => {
- return posts.filter(post => {
- const postDate = new Date(post.date);
- return (start ? postDate >= new Date(start) : true) && (end ? postDate <= new Date(end) : true);
- });
-}
+const getSearchFieldName = (fieldName: '' | 'tag' | 'category') => {
+ if (!fieldName) {
+ return '';
+ }
+ return searchFieldMapping[fieldName] || '';
+};
-export const searchPosts = (posts: PostMetaWithSlug[], keywordString: string) => {
+export const searchPostsByDateRange =
+ (start?: Date, end?: Date) => (posts: PostMetaWithSlug[]) => {
+ return posts.filter((post) => {
+ const postDate = new Date(post.date);
+ return (
+ (start ? postDate >= new Date(start) : true) &&
+ (end ? postDate <= new Date(end) : true)
+ );
+ });
+ };
+export const searchPosts = (
+ posts: PostMetaWithSlug[],
+ keywordString: string
+) => {
if (!keywordString) {
- return posts.map(post => ({
+ return posts.map((post) => ({
type: '文章',
text: post.title,
date: post.date,
link: `/blog/${post.date.slice(0, 10).replace(/-/g, '/')}/${post.slug}`,
- toString: () => ''
+ toString: () => '',
}));
}
const filterPostBy = (keyword: string) => (post: PostMetaWithSlug) =>
- post.title.toLowerCase().indexOf(keyword.toLowerCase()) >= 0
- || post.summary.toLowerCase().indexOf(keyword.toLowerCase()) >= 0;
+ post.title.toLowerCase().indexOf(keyword.toLowerCase()) >= 0 ||
+ post.summary.toLowerCase().indexOf(keyword.toLowerCase()) >= 0;
- let result = [];
+ const result: Array<{
+ type: string;
+ text: string;
+ date: string;
+ link: string;
+ }> = [];
let searchType = 'any';
- let searchField = '';
+ let searchField: 'tag' | 'category' | '' = '';
let searchFrom = '';
let keyword = '';
const chunks = keywordString.split(':');
if (chunks.length > 2) {
searchType = 'post';
- searchField = chunks[0];
+ searchField = chunks[0] as 'tag' | 'category' | '';
searchFrom = chunks[1];
keyword = chunks[2];
} else if (chunks.length > 1) {
@@ -54,61 +68,97 @@ export const searchPosts = (posts: PostMetaWithSlug[], keywordString: string) =>
if (searchType === 'any' || searchType === 'post') {
const relatePosts = posts
- .filter(post => {
+ .filter((post) => {
const filterKeywordFn = filterPostBy(keyword);
if (searchField === 'category') {
- return filterKeywordFn(post) && !!(post.categories || []).find((category) => category.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0);
+ return (
+ filterKeywordFn(post) &&
+ !!(post.categories || []).find(
+ (category) =>
+ category.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0
+ )
+ );
} else if (searchField === 'tag') {
- return filterKeywordFn(post) && !!(post.tags || []).find((tag) => tag.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0);
+ return (
+ filterKeywordFn(post) &&
+ !!(post.tags || []).find(
+ (tag) => tag.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0
+ )
+ );
} else {
return filterKeywordFn(post);
}
})
- .sort((postA, postB) =>
- postA.title.toLowerCase().indexOf(keyword.toLowerCase()) - postB.title.toLowerCase().indexOf(keyword.toLowerCase()))
- result.push(...relatePosts.map(post => ({
- type: `${getSearchFieldName(searchField)}${searchField ? ':' : ''}${searchFrom}${searchFrom ? ';' : ''}文章`,
- text: post.title,
- date: post.date,
- link: `/blog/${post.date.slice(0, 10).replace(/-/g, '/')}/${post.slug}`,
- toString: () => ''
- })));
+ .sort(
+ (postA, postB) =>
+ postA.title.toLowerCase().indexOf(keyword.toLowerCase()) -
+ postB.title.toLowerCase().indexOf(keyword.toLowerCase())
+ );
+ result.push(
+ ...relatePosts.map((post) => ({
+ type: `${getSearchFieldName(searchField)}${
+ searchField ? ':' : ''
+ }${searchFrom}${searchFrom ? ';' : ''}文章`,
+ text: post.title,
+ date: post.date,
+ link: `/blog/${post.date.slice(0, 10).replace(/-/g, '/')}/${post.slug}`,
+ toString: () => '',
+ }))
+ );
}
if (searchType === 'any' || searchType === 'category') {
- const allCategories = posts
- .reduce((curr, post) => ([...new Set([...curr, ...post.categories || []])]), [] as string[])
+ const allCategories = posts.reduce(
+ (curr, post) => [...new Set([...curr, ...(post.categories || [])])],
+ [] as string[]
+ );
- const relatedCategories = allCategories.filter((category: string) =>
- category.toLowerCase().indexOf(keyword.toLowerCase()) >= 0
- )
- .sort((categoryA, categoryB) =>
- categoryA.toLowerCase().indexOf(keyword.toLowerCase()) - categoryB.toLowerCase().indexOf(keyword.toLowerCase()))
- result.push(...relatedCategories.map(category => ({
- type: '分類',
- text: category,
- date: '',
- link: `/blog/categories/${slugify(category)}`,
- toString: () => ''
- })));
+ const relatedCategories = allCategories
+ .filter(
+ (category: string) =>
+ category.toLowerCase().indexOf(keyword.toLowerCase()) >= 0
+ )
+ .sort(
+ (categoryA, categoryB) =>
+ categoryA.toLowerCase().indexOf(keyword.toLowerCase()) -
+ categoryB.toLowerCase().indexOf(keyword.toLowerCase())
+ );
+ result.push(
+ ...relatedCategories.map((category) => ({
+ type: '分類',
+ text: category,
+ date: '',
+ link: `/blog/categories/${slugify(category)}`,
+ toString: () => '',
+ }))
+ );
}
if (searchType === 'any' || searchType === 'tag') {
- const allTags = posts
- .reduce((curr, post) => ([...new Set([...curr, ...post.tags || []])]), [] as string[])
+ const allTags = posts.reduce(
+ (curr, post) => [...new Set([...curr, ...(post.tags || [])])],
+ [] as string[]
+ );
const relatedTags = allTags
- .filter((tag: string) => tag.toLowerCase().indexOf(keyword.toLowerCase()) >= 0)
- .sort((tagA, tagB) =>
- tagA.toLowerCase().indexOf(keyword.toLowerCase()) - tagB.toLowerCase().indexOf(keyword.toLowerCase()))
- result.push(...relatedTags.map(tag => ({
- type: '標籤',
- text: tag,
- date: '',
- link: `/blog/tags/${slugify(tag)}`,
- toString: () => ''
- })));
+ .filter(
+ (tag: string) => tag.toLowerCase().indexOf(keyword.toLowerCase()) >= 0
+ )
+ .sort(
+ (tagA, tagB) =>
+ tagA.toLowerCase().indexOf(keyword.toLowerCase()) -
+ tagB.toLowerCase().indexOf(keyword.toLowerCase())
+ );
+ result.push(
+ ...relatedTags.map((tag) => ({
+ type: '標籤',
+ text: tag,
+ date: '',
+ link: `/blog/tags/${slugify(tag)}`,
+ toString: () => '',
+ }))
+ );
}
return result;
-}
+};
diff --git a/src/app/site-common/trailing-slash-url-serializer.ts b/src/app/site-common/trailing-slash-url-serializer.ts
index 0c3a43e554..061972e38e 100644
--- a/src/app/site-common/trailing-slash-url-serializer.ts
+++ b/src/app/site-common/trailing-slash-url-serializer.ts
@@ -11,7 +11,7 @@ export class TrailingSlashUrlSerializer extends DefaultUrlSerializer {
const pathArr = url.split(splitOn);
if (!pathArr[0].endsWith('/')) {
- let fileName: string = url.substring( url.lastIndexOf('/') + 1);
+ const fileName = url.substring( url.lastIndexOf('/') + 1);
if (fileName.indexOf('.') === -1) {
pathArr[0] += '/';
}