Skip to content

Commit 7ab110d

Browse files
authored
Merge pull request ucfopen#1076 from kingjellyfishh/InlineCSSADD
Added inlineCSS form and updated EN/ES translations.
2 parents 9db8c02 + 4dc8fdf commit 7ab110d

File tree

4 files changed

+212
-6
lines changed

4 files changed

+212
-6
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import React, { useState, useEffect } from 'react'
2+
import FormSaveOrReview from './FormSaveOrReview'
3+
import * as Html from '../../Services/Html'
4+
import * as Text from '../../Services/Text'
5+
import { getIssueHtml } from '../../Services/Html'
6+
7+
export default function InlineCSSForm ({
8+
t,
9+
settings,
10+
activeIssue,
11+
handleIssueSave,
12+
isDisabled,
13+
handleActiveIssue,
14+
markAsReviewed,
15+
setMarkAsReviewed
16+
}) {
17+
18+
const [isStyleToggleChecked, setisStyleToggleChecked] = useState(false)
19+
const [isImportantToggleChecked, setIsImportantToggleChecked] = useState(false)
20+
21+
const [formErrors, setFormErrors] = useState([])
22+
23+
const getInlineCSS = () => {
24+
let html = activeIssue.sourceHtml
25+
if(activeIssue.status > 0 && activeIssue.newHtml){
26+
html = activeIssue.newHtml
27+
}
28+
29+
let element = Html.toElement(html)
30+
31+
let elementInlineCSS = element.style;
32+
let elementInlineCSSText = elementInlineCSS.cssText
33+
elementInlineCSSText = elementInlineCSSText.split(";")
34+
return elementInlineCSSText
35+
}
36+
37+
const handleRemoveInlineStylesCheck = () => {
38+
setisStyleToggleChecked(!isStyleToggleChecked)
39+
}
40+
41+
const handleImportantCheckbox = () => {
42+
setIsImportantToggleChecked(!isImportantToggleChecked)
43+
}
44+
45+
useEffect (() => {
46+
updateHtmlContent()
47+
checkFormErrors()
48+
}, [isStyleToggleChecked, isImportantToggleChecked, markAsReviewed])
49+
50+
const updateHtmlContent = () => {
51+
let issue = activeIssue
52+
issue.isModified = true
53+
54+
if (markAsReviewed) {
55+
issue.newHtml = issue.initialHtml
56+
handleActiveIssue(issue)
57+
return
58+
}
59+
60+
let html = getIssueHtml(activeIssue)
61+
let updatedElement = Html.toElement(html)
62+
63+
let updatedInlineStyles = removeInlineStyles()
64+
65+
updatedElement.setAttribute("style", updatedInlineStyles.join(';'))
66+
issue.newHtml = Html.toString(updatedElement)
67+
handleActiveIssue(issue)
68+
}
69+
70+
const checkFormErrors = () => {
71+
let tempErrors = []
72+
73+
if(!isStyleToggleChecked && !isImportantToggleChecked){
74+
tempErrors.push({text:'', type: 'error'})
75+
}
76+
77+
setFormErrors(tempErrors)
78+
}
79+
80+
const removeInlineStyles = () => {
81+
let tempstyles = getInlineCSS()
82+
83+
if(isStyleToggleChecked){
84+
let isInStylesLH = tempstyles.findIndex(item => item.includes("line-height"));
85+
if(isInStylesLH>-1){
86+
tempstyles.splice(isInStylesLH, 1)
87+
}
88+
let isInStylesWS = tempstyles.findIndex(item => item.includes("word-spacing"));
89+
if(isInStylesWS>-1){
90+
tempstyles.splice(isInStylesWS, 1)
91+
}
92+
let isInStylesLS = tempstyles.findIndex(item => item.includes("letter-spacing"));
93+
if(isInStylesLS>-1){
94+
tempstyles.splice(isInStylesLS, 1)
95+
}
96+
}
97+
98+
if(isImportantToggleChecked){
99+
let isInStylesLH = tempstyles.findIndex(item => item.includes("line-height"));
100+
if(isInStylesLH>-1){
101+
tempstyles[isInStylesLH] = tempstyles[isInStylesLH].replace('!important', '').trim()
102+
}
103+
let isInStylesWS = tempstyles.findIndex(item => item.includes("word-spacing"));
104+
if(isInStylesWS>-1){
105+
tempstyles[isInStylesWS] = tempstyles[isInStylesWS].replace('!important', '').trim()
106+
}
107+
let isInStylesLS = tempstyles.findIndex(item => item.includes("letter-spacing"));
108+
if(isInStylesLS>-1){
109+
tempstyles[isInStylesLS] = tempstyles[isInStylesLS].replace('!important', '').trim()
110+
}
111+
}
112+
113+
return tempstyles
114+
}
115+
116+
const updateCheckboxes = () => {
117+
let tempstyles = getInlineCSS()
118+
119+
let isInStylesLH = tempstyles.findIndex(item => item.includes("line-height"));
120+
let isInStylesWS = tempstyles.findIndex(item => item.includes("word-spacing"));
121+
let isInStylesLS = tempstyles.findIndex(item => item.includes("letter-spacing"));
122+
let tempimp = "!important"
123+
124+
if((isInStylesLH<=-1 && isInStylesWS<=-1 && isInStylesLS<=-1)){
125+
setisStyleToggleChecked(true)
126+
}
127+
else{
128+
setisStyleToggleChecked(false)
129+
}
130+
131+
if(
132+
(tempstyles[isInStylesLH]?.includes(tempimp))||
133+
(tempstyles[isInStylesWS]?.includes(tempimp))||
134+
(tempstyles[isInStylesLS]?.includes(tempimp))) {
135+
setIsImportantToggleChecked(false)
136+
}
137+
else{
138+
setIsImportantToggleChecked(true)
139+
}
140+
}
141+
142+
useEffect(() => {
143+
if (!activeIssue) {
144+
return
145+
}
146+
147+
updateCheckboxes()
148+
checkFormErrors()
149+
}, [activeIssue])
150+
151+
const handleSubmit = () => {
152+
if (markAsReviewed || formErrors.length === 0) {
153+
handleIssueSave(activeIssue)
154+
}
155+
}
156+
157+
return (
158+
<>
159+
<div className="flex-row justify-content-start gap-1 mt-2">
160+
<input
161+
type="checkbox"
162+
id="removeInlineStylesCheck"
163+
name="removeInlineStylesCheck"
164+
tabIndex="0"
165+
disabled={isDisabled}
166+
checked={isStyleToggleChecked}
167+
onChange={handleRemoveInlineStylesCheck} />
168+
<label htmlFor="removeInlineStylesCheck" className="instructions">{t('form.invalid_css.label.remove_style')}</label>
169+
</div>
170+
<div className="flex-row justify-content-start gap-1 mt-2">
171+
<input
172+
type="checkbox"
173+
id="removeImportantStylesCheck"
174+
name="removeImportantStylesCheck"
175+
tabIndex="0"
176+
disabled={isDisabled}
177+
checked={isImportantToggleChecked}
178+
onChange={handleImportantCheckbox} />
179+
<label htmlFor="removeImportantStylesCheck" className="instructions">{t('form.invalid_css.label.remove_important')}</label>
180+
</div>
181+
<FormSaveOrReview
182+
t={t}
183+
settings={settings}
184+
activeIssue={activeIssue}
185+
isDisabled={isDisabled}
186+
handleSubmit={handleSubmit}
187+
formErrors={formErrors}
188+
markAsReviewed={markAsReviewed}
189+
setMarkAsReviewed={setMarkAsReviewed} />
190+
</>
191+
)
192+
}

assets/js/Services/Ufixit.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import QuoteForm from '../Components/Forms/QuoteForm'
2222
import SensoryMisuseForm from '../Components/Forms/SensoryMisuseForm'
2323
import TableCaptionForm from '../Components/Forms/TableCaptionForm'
2424
import TableHeadersForm from '../Components/Forms/TableHeadersForm'
25+
26+
import InlineCSSForm from '../Components/Forms/InlineCSSForm'
27+
2528
import UfixitReviewOnly from '../Components/Forms/UfixitReviewOnly'
2629

2730
// These form names strictly match the translation keys in the language files (e.g. en.json).
@@ -53,6 +56,8 @@ export const formNames = {
5356
TABLE_CAPTION: 'table_caption',
5457
TABLE_HEADERS: 'table_headers',
5558

59+
INLINE_CSS: 'inline_css',
60+
5661
REVIEW_ONLY: 'review_only',
5762
}
5863

@@ -91,6 +96,8 @@ const formTypes = {
9196
[formNames.TABLE_CAPTION]: TableCaptionForm,
9297
[formNames.TABLE_HEADERS]: TableHeadersForm,
9398

99+
[formNames.INLINE_CSS]: InlineCSSForm,
100+
94101
[formNames.REVIEW_ONLY]: UfixitReviewOnly,
95102
}
96103

@@ -246,6 +253,7 @@ const rulesToFormNameMap = {
246253
table_structure_misuse: formNames.TABLE_HEADERS,
247254

248255
text_sensory_misuse: formNames.SENSORY_MISUSE,
256+
text_spacing_valid: formNames.INLINE_CSS
249257
}
250258

251259
/* When a REVIEW_ONLY rule uses the same summary as another rule, add it here.
@@ -296,7 +304,7 @@ export const sharedRuleDescriptions = {
296304
skip_main_described: 'rule.desc.html_skipnav_exists',
297305
skip_main_exists: 'rule.desc.html_skipnav_exists',
298306
style_viewport_resizable: 'rule.desc.meta_viewport_zoomable',
299-
widget_tabbable_single: 'rule.desc.widget_tabbable_exists',
307+
widget_tabbable_single: 'rule.desc.widget_tabbable_exists'
300308
}
301309

302310
export function formFromIssue(activeIssue) {

translations/en.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,6 @@
434434
"form.heading_style.label.select": "Select Heading Level",
435435
"form.heading_style.label.none_selected": "Remove Heading Level",
436436
"form.heading_style.label.remove_styling": "Remove Additional Styling (Optional)",
437-
"rule.desc.heading_markup_misuse": "",
438-
"rule.desc.text_block_heading": "",
439437
"rule.info.heading_markup_misuse": "This text is marked as a heading, but does not appear to be one. If it is, you may ignore this issue and mark it as reviewed. If it is not a heading, remove the heading level.",
440438
"rule.info.text_block_heading": "This text seems to be a heading, but is not marked as one. If it is a heading, select an appropriate heading level. If not, you may remove any styling or mark that no changes are needed.",
441439

@@ -477,9 +475,9 @@
477475
"rule.info.table_aria_descendants": "Elements inside a table (<code>&lt;tr&gt;</code>, <code>&lt;th&gt;</code>, and <code>&lt;td&gt;</code>) should not have the <code>role</code> attribute.",
478476
"rule.info.table_scope_valid": "<code>th</code> elements inside a table should have a <code>scope</code> attribute with the value of <code>row</code>, <code>col</code>, <code>rowgroup</code>, or <code>colgroup</code>.",
479477

480-
"form.invalid_css.title": "Text Spacing Should Not Be Forced",
481-
"form.invalid_css.summary": "Forcing specific text spacing can cause issues for users who need to customize spacing for readability.",
482-
"form.invalid_css.learn_more": "<h3>Ensuring Readability</h3><p>Some users with low vision or reading disabilities need to adjust text spacing in order to read more easily. If CSS or the <code>style</code> attributes include the <code>!important</code> declaration, it will override user settings and make it difficult for them to read. For instance, the CSS property <code>line-height</code> can be used to adjust the spacing between lines of text. If this property is forced to a fixed value, like using <code>style=&quot;line-height: 16px !important&quot;</code>, it can prevent users from adjusting the line spacing to their needs.</p><p>Specifically, never use <code>!important</code> to override the <code>letter-spacing</code>, <code>word-spacing</code>, or <code>line-height</code> styles.</p><h3>Best Practices</h3><ul><li>Avoid using CSS properties that force a specific letter spacing, word spacing, or line height</li><li>Use relative units (like <code>em</code> or <code>rem</code>) instead of fixed units (like <code>px</code>) for text spacing</li></ul></p><h3>For More Information</h3><p>W3.org: <a href='https://www.w3.org/WAI/WCAG21/Understanding/text-spacing.html' target='_blank'>Text Spacing</a></p>",
478+
"form.inline_css.title": "Text Spacing Should Not Be Forced",
479+
"form.inline_css.summary": "Forcing specific text spacing can cause issues for users who need to customize spacing for readability.",
480+
"form.inline_css.learn_more": "<h3>Ensuring Readability</h3><p>Some users with low vision or reading disabilities need to adjust text spacing in order to read more easily. If CSS or the <code>style</code> attributes include the <code>!important</code> declaration, it will override user settings and make it difficult for them to read. For instance, the CSS property <code>line-height</code> can be used to adjust the spacing between lines of text. If this property is forced to a fixed value, like using <code>style=&quot;line-height: 16px !important&quot;</code>, it can prevent users from adjusting the line spacing to their needs.</p><p>Specifically, never use <code>!important</code> to override the <code>letter-spacing</code>, <code>word-spacing</code>, or <code>line-height</code> styles.</p><h3>Best Practices</h3><ul><li>Avoid using CSS properties that force a specific letter spacing, word spacing, or line height</li><li>Use relative units (like <code>em</code> or <code>rem</code>) instead of fixed units (like <code>px</code>) for text spacing</li></ul></p><h3>For More Information</h3><p>W3.org: <a href='https://www.w3.org/WAI/WCAG21/Understanding/text-spacing.html' target='_blank'>Text Spacing</a></p>",
483481
"rule.desc.text_spacing_valid": "",
484482

485483
"form.keyboard_tabbable.title": "Interactive Elements Must Be Keyboard Accessible",
@@ -495,6 +493,11 @@
495493
"rule.info.element_scrollable_tabbable": "The highlighted area seems to be scrollable. For keyboard user to scroll up and down, the area must be added to the keyboard navigation.",
496494
"rule.info.element_tabbable_role_valid": "The highlighted element can be reached by keyboard, but has a <code>role</code> that is not interactive. If it is supposed to be interactive, remove the <code>role</code> or change it to a <a href='https://www.w3.org/TR/wai-aria-1.2/#widget' target='_blank'>valid widget role</a>. Otherwise, add the attribute <code>tabindex=&quot;-1&quot;</code>.",
497495
"rule.info.iframe_interactive_tabbable": "If this embedded content is interactive, it must be added to the keyboard navigation.",
496+
"rule.desc.heading_markup_misuse": "This text is marked as a heading, but does not appear to be one. If it is, you may ignore this issue and mark it as reviewed. If it is not a heading, remove the heading level.",
497+
"rule.desc.text_block_heading": "This text seems to be a heading, but is not marked as one. If it is a heading, select an appropriate heading level. If not, you may remove any styling or mark that no changes are needed.",
498+
499+
"form.invalid_css.label.remove_style": "Remove Text Spacing Styles",
500+
"form.invalid_css.label.remove_important": "De-emphasize Text Spacing Styles",
498501

499502
"form.label.title": "Interactive and Landmark Areas Should Have Labels",
500503
"form.label.summary": "Interactive elements like buttons, links, and form fields should have descriptive labels that help users understand their purpose. Landmark regions should also have unique labels to help users navigate the page.",

translations/es.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@
496496
"rule.info.element_tabbable_role_valid": "TODO: The highlighted element can be reached by keyboard, but has a <code>role</code> that is not interactive. If it is supposed to be interactive, remove the <code>role</code> or change it to a <a href='https://www.w3.org/TR/wai-aria-1.2/#widget' target='_blank'>valid widget role</a>. Otherwise, add the attribute <code>tabindex=&quot;-1&quot;</code>.",
497497
"rule.info.iframe_interactive_tabbable": "TODO: If this embedded content is interactive, it must be added to the keyboard navigation.",
498498

499+
"form.invalid_css.label.remove_style": "TODO: Remove Text Spacing Styles",
500+
"form.invalid_css.label.remove_important": "TODO: De-emphasize Text Spacing Styles",
501+
499502
"form.label.title": "Las Áreas Interactivas y de Referencia Deben Tener Etiquetas",
500503
"form.label.summary": "Los elementos interactivos como botones, enlaces y campos de formulario deben tener etiquetas descriptivas que ayuden a los usuarios a entender su propósito. Las regiones de referencia (Landmark Regions) también deben tener etiquetas únicas que ayuden a los usuarios a navegar por la página.",
501504
"form.label.learn_more": "<h3>Navegar Usando Landmarks</h3><p>El contenido web generalmente está separado en patrones consistentes: un encabezado en la parte superior, menús de navegación, contenido principal, barras laterales, pies de página, etc. Las secciones estándar son conocidas como &quot;landmarks&quot;, y ayudan a los usuarios de tecnología asistida (AT) a orientarse y navegar fácilmente a varias regiones de una página. Cuando existen múltiples regiones con el mismo rol en la misma página (imagina dos menús de &quot;navegacion&quot; o una página larga con múltiples &quot;articles&quot;), las personas que usan AT tendrán dificultad para identificar o distinguir entre ellos.<p><p>Los landmarks son creados usando etiquetas HTML específicas, como <code>&lt;nav&gt;</code>, <code>&lt;main&gt;</code>, y <code>&lt;footer&gt;</code>, o agregando el atributo <code>role</code> a una etiqueta genérica, como <code>role=&quot;navigation&quot;</code>.</p><p>Importante, algunos landmarks solo pueden ser usados una vez por página. Si tienes múltiples de estos landmarks, necesitarás eliminar los extras o cambiar sus valores de <code>role</code>.<table><caption>Landmarks HTML y Valores de Rol Equivalentes</caption><thead><th scope='col'>HTML Tag</th><th scope='col'>Equivalent Role</th><th scope='col'>Allowed Once</th></thead><tbody><tr><td>&lt;header&gt;</td><td>role=&quot;banner&quot;</td><td><strong>Sí</strong></td></tr><tr><td>&lt;nav&gt;</td><td>role=&quot;navigation&quot;</td><td>No</td></tr><tr><td>N/A</td><td>role=&quot;search&quot;</td><td>No</td></tr><tr><td>&lt;aside&gt;</td><td>role=&quot;complementary&quot;</td><td>No</td></tr><tr><td>&lt;main&gt;</td><td>role=&quot;main&quot;</td><td><strong>Sí</strong></td></tr><tr><td>&lt;h1&gt;</td><td>N/A</td><td><strong>Sí</strong></td></tr><tr><td>&lt;article&gt;</td><td>role=&quot;article&quot;</td><td>No</td></tr><tr><td>&lt;section&gt;</td><td>role=&quot;region&quot;</td><td>No</td></tr><tr><td>&lt;form&gt;</td><td>role=&quot;form&quot;</td><td>No</td></tr><tr><td>&lt;footer&gt;</td><td>role=&quot;contentinfo&quot;</td><td><strong>Sí</strong></td></tr></table><h3>Mejores Prácticas</h3><ul><li>Utiliza valores únicos de <code>aria-label</code> para distinguir landmarks con el mismo rol</li><li>Asegúrate de que solo haya un landmark de cada <code>&lt;header&gt;</code>, <code>&lt;main&gt;</code>, <code>&lt;h1&gt;</code>, y <code>&lt;footer&gt;</code></li></ul><h3>Para Más Información</h3><p>WebAIM.org: <a href='https://webaim.org/techniques/semanticstructure/' target='_blank'>Estructura Semántica</a> y <a href='https://webaim.org/techniques/aria/#landmarks' target='_blank'>Roles de Landmark ARIA</a></p><p>W3.org: <a href='https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/' target='blank'>Regiones de Referencia</a></p>",

0 commit comments

Comments
 (0)