Skip to content

Commit 84f7fd9

Browse files
authored
fix: missing functions css helper(#42)
1 parent e5ec6ee commit 84f7fd9

File tree

4 files changed

+120
-110
lines changed

4 files changed

+120
-110
lines changed

lib/css-helper.ts

Lines changed: 117 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,127 @@
11
export interface ExtendedStyleRule extends CSSStyleRule {
2-
isDeclaredAfter: (selector: string) => boolean;
2+
isDeclaredAfter: (selector: string) => boolean;
3+
}
4+
interface ExtendedStyleDeclaration extends CSSStyleDeclaration {
5+
getPropVal: (prop: string, strip?: boolean) => string;
6+
}
7+
8+
const getIsDeclaredAfter = (styleRule: CSSStyleRule) => (selector: string) => {
9+
const cssStyleRules = Array.from(
10+
styleRule.parentStyleSheet?.cssRules || []
11+
)?.filter(ele => ele.type === CSSRule.STYLE_RULE) as CSSStyleRule[];
12+
const previousStyleRule = cssStyleRules.find(
13+
ele => ele?.selectorText === selector
14+
);
15+
if (!previousStyleRule) return false;
16+
const currPosition = Array.from(
17+
styleRule.parentStyleSheet?.cssRules || []
18+
).indexOf(styleRule);
19+
const prevPosition = Array.from(
20+
previousStyleRule?.parentStyleSheet?.cssRules || []
21+
).indexOf(previousStyleRule);
22+
return currPosition > prevPosition;
23+
};
24+
25+
export class CSSHelp {
26+
doc: Document;
27+
constructor(doc: Document) {
28+
this.doc = doc;
329
}
4-
interface ExtendedStyleDeclaration extends CSSStyleDeclaration {
5-
getPropVal: (prop: string, strip?: boolean) => string;
30+
private _getStyleRules() {
31+
const styleSheet = this.getStyleSheet();
32+
return this.styleSheetToCssRulesArray(styleSheet).filter(
33+
ele => ele.type === CSSRule.STYLE_RULE
34+
) as CSSStyleRule[];
635
}
7-
8-
const getIsDeclaredAfter = (styleRule: CSSStyleRule) => (selector: string) => {
9-
const cssStyleRules = Array.from(
10-
styleRule.parentStyleSheet?.cssRules || []
11-
)?.filter(ele => ele.type === CSSRule.STYLE_RULE) as CSSStyleRule[];
12-
const previousStyleRule = cssStyleRules.find(
36+
37+
getStyleDeclarations(selector: string): CSSStyleDeclaration[] {
38+
return this._getStyleRules()
39+
?.filter(ele => ele?.selectorText === selector)
40+
.map(x => x.style);
41+
}
42+
getStyle(selector: string): ExtendedStyleDeclaration | null {
43+
const style = this._getStyleRules().find(
44+
ele => ele?.selectorText === selector
45+
)?.style as ExtendedStyleDeclaration | undefined;
46+
if (!style) return null;
47+
style.getPropVal = (prop: string, strip = false) => {
48+
return strip
49+
? style.getPropertyValue(prop).replace(/\s+/g, '')
50+
: style.getPropertyValue(prop);
51+
};
52+
return style;
53+
}
54+
getStyleRule(selector: string): ExtendedStyleRule | null {
55+
const styleRule = this._getStyleRules()?.find(
1356
ele => ele?.selectorText === selector
1457
);
15-
if (!previousStyleRule) return false;
16-
const currPosition = Array.from(
17-
styleRule.parentStyleSheet?.cssRules || []
18-
).indexOf(styleRule);
19-
const prevPosition = Array.from(
20-
previousStyleRule?.parentStyleSheet?.cssRules || []
21-
).indexOf(previousStyleRule);
22-
return currPosition > prevPosition;
23-
};
24-
export class CSSHelp {
25-
doc: HTMLDocument;
26-
constructor(doc: HTMLDocument) {
27-
this.doc = doc;
28-
}
29-
private _getStyleRules() {
30-
const styleSheet = this.getStyleSheet();
31-
return this.styleSheetToCssRulesArray(styleSheet).filter(
32-
ele => ele.type === CSSRule.STYLE_RULE
33-
) as CSSStyleRule[];
34-
}
35-
36-
getStyleDeclarations(selector: string): CSSStyleDeclaration[] {
37-
return this._getStyleRules()
38-
?.filter(ele => ele?.selectorText === selector)
39-
.map(x => x.style);
40-
}
41-
getStyle(selector: string): ExtendedStyleDeclaration | null {
42-
const style = this._getStyleRules().find(
43-
ele => ele?.selectorText === selector
44-
)?.style as ExtendedStyleDeclaration | undefined;
45-
if (!style) return null;
46-
style.getPropVal = (prop: string, strip = false) => {
47-
return strip
48-
? style.getPropertyValue(prop).replace(/\s+/g, '')
49-
: style.getPropertyValue(prop);
58+
if (styleRule) {
59+
return {
60+
...styleRule,
61+
isDeclaredAfter: (selector: string) =>
62+
getIsDeclaredAfter(styleRule)(selector)
5063
};
51-
return style;
52-
}
53-
getStyleRule(selector: string): ExtendedStyleRule | null {
54-
const styleRule = this._getStyleRules()?.find(
55-
ele => ele?.selectorText === selector
56-
);
57-
if (styleRule) {
58-
return {
59-
...styleRule,
60-
isDeclaredAfter: (selector: string) =>
61-
getIsDeclaredAfter(styleRule)(selector)
62-
};
63-
} else {
64-
return null;
65-
}
66-
}
67-
getCSSRules(element?: string): CSSRule[] {
68-
const styleSheet = this.getStyleSheet();
69-
const cssRules = this.styleSheetToCssRulesArray(styleSheet);
70-
switch (element) {
71-
case 'media':
72-
return cssRules.filter(ele => ele.type === CSSRule.MEDIA_RULE);
73-
case 'fontface':
74-
return cssRules.filter(ele => ele.type === CSSRule.FONT_FACE_RULE);
75-
case 'import':
76-
return cssRules.filter(ele => ele.type === CSSRule.IMPORT_RULE);
77-
case 'keyframes':
78-
return cssRules.filter(ele => ele.type === CSSRule.KEYFRAMES_RULE);
79-
default:
80-
return cssRules;
81-
}
82-
}
83-
isPropertyUsed(property: string): boolean {
84-
return this._getStyleRules().some(ele =>
85-
ele.style?.getPropertyValue(property)
86-
);
87-
}
88-
getRuleListsWithinMedia(mediaText: string): CSSStyleRule[] {
89-
const medias = this.getCSSRules('media') as CSSMediaRule[];
90-
const cond = medias?.find(x => x?.media?.mediaText === mediaText);
91-
const cssRules = cond?.cssRules;
92-
return Array.from(cssRules || []) as CSSStyleRule[];
64+
} else {
65+
return null;
9366
}
94-
getStyleSheet(): CSSStyleSheet | null {
95-
// TODO: Change selector to match exactly 'styles.css'
96-
const link: HTMLLinkElement | null = this.doc?.querySelector(
97-
"link[href*='styles']"
98-
);
99-
// Most* browser extensions inject styles with class/media attributes
100-
const style: HTMLStyleElement | null = this.doc?.querySelector(
101-
'style:not([class]):not([media])'
102-
);
103-
if (link?.sheet?.cssRules?.length) {
104-
return link.sheet;
105-
} else if (style) {
106-
return style.sheet;
107-
} else {
108-
return null;
109-
}
67+
}
68+
getCSSRules(element?: string): CSSRule[] {
69+
const styleSheet = this.getStyleSheet();
70+
const cssRules = this.styleSheetToCssRulesArray(styleSheet);
71+
switch (element) {
72+
case 'media':
73+
return cssRules.filter(ele => ele.type === CSSRule.MEDIA_RULE);
74+
case 'fontface':
75+
return cssRules.filter(ele => ele.type === CSSRule.FONT_FACE_RULE);
76+
case 'import':
77+
return cssRules.filter(ele => ele.type === CSSRule.IMPORT_RULE);
78+
case 'keyframes':
79+
return cssRules.filter(ele => ele.type === CSSRule.KEYFRAMES_RULE);
80+
default:
81+
return cssRules;
11082
}
111-
styleSheetToCssRulesArray(
112-
styleSheet: ReturnType<CSSHelp['getStyleSheet']>
113-
): CSSRule[] {
114-
return Array.from(styleSheet?.cssRules || []);
83+
}
84+
isPropertyUsed(property: string): boolean {
85+
return this._getStyleRules().some(ele =>
86+
ele.style?.getPropertyValue(property)
87+
);
88+
}
89+
getRuleListsWithinMedia(mediaText: string): CSSStyleRule[] {
90+
const medias = this.getCSSRules('media') as CSSMediaRule[];
91+
const cond = medias?.find(x => x?.media?.mediaText === mediaText);
92+
const cssRules = cond?.cssRules;
93+
return Array.from(cssRules || []) as CSSStyleRule[];
94+
}
95+
getStyleSheet(): CSSStyleSheet | null {
96+
// TODO: Change selector to match exactly 'styles.css'
97+
const link: HTMLLinkElement | null = this.doc?.querySelector(
98+
"link[href*='styles']"
99+
);
100+
101+
// When using the styles.css tab, we add a 'fcc-injected-styles' class so we can target that. This allows users to add external scripts without them interfering
102+
const stylesDotCss: HTMLStyleElement | null = this.doc?.querySelector(
103+
'style.fcc-injected-styles'
104+
);
105+
106+
// For steps that use <style> tags, where they don't add the above class - most* browser extensions inject styles with class/media attributes, so it filters those
107+
const styleTag: HTMLStyleElement | null = this.doc?.querySelector(
108+
'style:not([class]):not([media])'
109+
);
110+
111+
if (link?.sheet?.cssRules?.length) {
112+
return link.sheet;
113+
} else if (stylesDotCss) {
114+
return stylesDotCss.sheet;
115+
} else if (styleTag) {
116+
return styleTag.sheet;
117+
} else {
118+
return null;
115119
}
116120
}
117-
121+
styleSheetToCssRulesArray(
122+
styleSheet: ReturnType<CSSHelp['getStyleSheet']>
123+
): CSSRule[] {
124+
return Array.from(styleSheet?.cssRules || []);
125+
}
126+
}
127+

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@freecodecamp/curriculum-helpers",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "Helper functions to test challenges in freeCodecamp's curriculum",
55
"homepage": "https://freecodecamp.org",
66
"author": {

0 commit comments

Comments
 (0)