Я новичок в Angular, но сейчас я хотел бы создать компонент для анализа всех медиа-запросов из внутренних таблиц стилей, а также внешних и вывода их.Чтобы обработать все @import
s, я должен сделать запрос к внешним таблицам стилей с помощью метода fetchStyleSheetText()
:
// ...
export class MediaQueriesWidgetComponent implements OnInit, OnChanges {
@Input() content;
@Input() isContentLoading;
mediaQueriesList = [];
mediaReg: RegExp = /@media[^{]+ /g;
importReg: RegExp = /@import url\("(.+)"\) /g;
constructor(private cd: ChangeDetectorRef,
private _ApiService: ApiService) { }
ngOnInit(): void {
//this.fetchStyleSheetText();
}
ngOnChanges(changes: SimpleChanges) {
const contentChanges = changes.content;
if (contentChanges) {
const currentContent = contentChanges.currentValue && contentChanges.currentValue.content;
const element = this.parseHtml(currentContent), styleSheetsSelector = 'style,[style],link[rel*="stylesheet"]';
const styleSheets = this.getStyleSheets(element, styleSheetsSelector);
console.log(styleSheets);
this.mediaQueriesList = this.styleSheetsReducer(styleSheets);
}
parseHtml(html: string): DocumentFragment | HTMLTemplateElement {
const el = document.createElement('template');
el.innerHTML = html;
return el.content || el;
}
private getStyleSheets(element: DocumentFragment | HTMLTemplateElement, selector: string): Element[] {
return Array.from(element.querySelectorAll(selector));
}
private parseStyleSheetText(text: string): string[] {
let match: RegExpExecArray;
const importRules = [];
const mediaQueries = text.match(this.mediaReg) || [];
console.log(mediaQueries);
while (match = this.importReg.exec(text)) {
importRules.push(match[1]);
}
return importRules.reduce((result: string[], url: string) => {
return result.concat(this.fetchStyleSheetText(url));
}, mediaQueries.map(query => query.trim()));
}
private fetchStyleSheetText(url: string): string[] {
// const requestedCssText= this._ApiService.getFromApi(url, ActionType.webfiles, true));
// return this.parseStyleSheetText(requestedCssText);
}
styleSheetsReducer(styleSheets: Element[]): string[] {
return styleSheets.reduce((result: string[], element: any) => {
switch (element.localName) {
case 'style':
return result.concat(this.parseStyleSheetText(element.innerHTML));
case 'link':
return result.concat(this.fetchStyleSheetText(element.href));
default:
return result.concat(this.parseStyleSheetText(element.style.cssText));
}
}, []);
}
}
Для загрузки Id внешнего стиля хотелось бы использовать метод fetchStyleSheetText()
и передать ответ на parseStyleSheetText()
но я не знаю, как реализовать fetchStyleSheetText (), возможно, мне нужен хук жизненного цикла, например ngOnInit()
.
Я собираюсь использовать уже существующий Api-сервис:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from 'environments/environment';
import { BehaviorSubject, Observable } from 'rxjs';
import { shareReplay, take } from 'rxjs/operators';
export enum ActionType {
'content' = 'content',
'metatags' = 'metatags',
'microdata' = 'microdata',
'social' = 'social',
'httpdata' = 'httpdata',
'webfiles' = 'webfiles',
'whois' = 'whois',
'audience' = 'audience',
'mozdata' = 'mozdata',
'alexa' = 'alexa',
'google' = 'google',
'headers' = 'headers'
}
@Injectable()
export class ApiService {
private key: string;
private cache: {[propName: string]: [Observable<any>, string]} = {};
private loadingMap: {[propName: string]: BehaviorSubject<boolean>} =
{};
constructor(private http: HttpClient) {
this.loadingMap = Object.entries(ActionType)
.reduce((res, [key]) => ({...res, [key]: new BehaviorSubject(false)}), {});
}
getFromApi(url: string, type: ActionType, force?: boolean) {
let [obs$ = null, cacheUrl = ''] = this.cache[type] || [];
if (!obs$ || cacheUrl !== url || force) {
cacheUrl = url;
obs$ = this.makeRequest(url, type).pipe(
shareReplay(1)
);
this.processLoading(obs$, type);
this.cache[type] = [obs$, cacheUrl];
}
return obs$;
}
makeRequest(url: string, type: ActionType) {
return this.http.jsonp(this.getEndpoint(url, type), 'jsonp');
}
private getEndpoint(url, type) {
const params = new URLSearchParams();
params.set('key', this.key);
params.set('url', url);
let apiUrl = 'api.someurl.com';
if ('alexa' === type) {
apiUrl = 'www.someurl.com/api';
}
return `https://${apiUrl}/v1/${type}?${params.toString()}`;
}
}