diff --git a/assets/js/Components/Forms/LabelForm.js b/assets/js/Components/Forms/LabelForm.js new file mode 100644 index 00000000..00e6c9cf --- /dev/null +++ b/assets/js/Components/Forms/LabelForm.js @@ -0,0 +1,151 @@ +import React, { useEffect, useState } from 'react' +import { View } from '@instructure/ui-view' +import { TextInput } from '@instructure/ui-text-input' +import { Button } from '@instructure/ui-buttons' +import { IconCheckMarkLine } from '@instructure/ui-icons' +import { Checkbox } from '@instructure/ui-checkbox' +import { Spinner } from '@instructure/ui-spinner' +import * as Html from '../../Services/Html' + +export default function LabelForm(props) { + + let html = props.activeIssue.newHtml ? props.activeIssue.newHtml : props.activeIssue.sourceHtml + + if (props.activeIssue.status === '1') { + html = props.activeIssue.newHtml + } + + let element = Html.toElement(html) + + const [textInputValue, setTextInputValue] = useState(element ? Html.getAttribute(element, "aria-label") : "") + // const [deleteLabel, setDeleteLabel] = useState(!element && (props.activeIssue.status === "1")) + const [textInputErrors, setTextInputErrors] = useState([]) + + let formErrors = [] + + useEffect(() => { + let html = props.activeIssue.newHtml ? props.activeIssue.newHtml : props.activeIssue.sourceHtml + if (props.activeIssue.status === 1) { + html = props.activeIssue.newHtml + } + + let element = Html.toElement(html) + setTextInputValue(element ? Html.getAttribute(element, "aria-label") : "") + // setDeleteLabel(!element && props.activeIssue.status === 1) + + formErrors = [] + + }, [props.activeIssue]) + + useEffect(() => { + handleHtmlUpdate() + }, [textInputValue]) + + const handleHtmlUpdate = () => { + let updatedElement = Html.toElement(html) + + updatedElement = Html.setAttribute(updatedElement, "aria-label", textInputValue) + + // if (deleteLabel) { + // updatedElement = Html.removeAttribute(updatedElement, "aria-label") + // } + // else { + // updatedElement = Html.setAttribute(updatedElement, "aria-label", textInputValue) + // } + + let issue = props.activeIssue + issue.newHtml = Html.toString(updatedElement) + props.handleActiveIssue(issue) + + } + + const handleButton = () => { + formErrors = [] + + // if (!deleteLabel) { + // checkTextNotEmpty() + // } + + checkTextNotEmpty() + checkLabelIsUnique() + + if (formErrors.length > 0) { + setTextInputErrors(formErrors) + } + else { + props.handleIssueSave(props.activeIssue) + } + } + + const handleInput = (event) => { + setTextInputValue(event.target.value) + // handleHtmlUpdate() + } + + // const handleCheckbox = () => { + // setDeleteLabel(!deleteLabel) + // // handleHtmlUpdate() + // } + + const checkTextNotEmpty = () => { + const text = textInputValue.trim().toLowerCase() + if (text === '') { + formErrors.push({ text: "Empty label text.", type: "error" }) + } + } + + const checkLabelIsUnique = () => { + // in the case of aria_*_label_unique, messageArgs (from metadata) should have the offending label (at the first index) + // i guess we could get it from the aria-label itself as well... + const issue = props.activeIssue + const metadata = issue.metadata ? JSON.parse(issue.metadata) : {} + const labelFromMessageArgs = metadata.messageArgs ? metadata.messageArgs[0] : null + const text = textInputValue.trim().toLowerCase() + + if (labelFromMessageArgs) { + if (text == labelFromMessageArgs) { + formErrors.push({ text: "Cannot reuse label text.", type: "error" }) + } + } + + } + + const pending = props.activeIssue && props.activeIssue.pending == "1" + const buttonLabel = pending ? "form.processing" : "form.submit" + + return ( + + + + + {/* + + + + */} + + + + + ); +} \ No newline at end of file diff --git a/assets/js/Services/Ufixit.js b/assets/js/Services/Ufixit.js index 775bf94d..bb6d91d0 100644 --- a/assets/js/Services/Ufixit.js +++ b/assets/js/Services/Ufixit.js @@ -8,6 +8,7 @@ import TableHeaders from '../Components/Forms/TableHeaders' import Video from '../Components/Forms/Video' import LinkForm from '../Components/Forms/LinkForm' import EmphasisForm from '../Components/Forms/EmphasisForm' +import LabelForm from '../Components/Forms/LabelForm' const UfixitForms = { // phpAlly rules @@ -33,6 +34,8 @@ const UfixitForms = { // Equal Access Rules img_alt_misuse: AltText, + aria_application_labelled: LabelForm, + aria_application_label_unique: LabelForm, text_contrast_sufficient: ContrastForm, text_block_heading: HeadingStyleForm, heading_content_exists: HeadingEmptyForm, diff --git a/src/Services/AsyncEqualAccessReport.php b/src/Services/AsyncEqualAccessReport.php index fee28c89..9964a183 100644 --- a/src/Services/AsyncEqualAccessReport.php +++ b/src/Services/AsyncEqualAccessReport.php @@ -9,9 +9,12 @@ use Aws\Credentials\Credentials; use Aws\Signature\SignatureV4; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Pool; use GuzzleHttp\Psr7; use GuzzleHttp\Promise; use GuzzleHttp\Client; +use GuzzleHttp\Psr7\Response; use Psr\Http\Message\RequestInterface; use GuzzleHttp\Psr7\Request; @@ -75,11 +78,9 @@ public function createRequest($payload) { public function postMultipleArrayAsync(array $contentItems): array { $promises = []; - $client = new Client(); $contentItemsReport = []; - // $this->logToServer("Count contentItems:"); - // $this->logToServer(count($contentItems)); + $client = new Client(); // Combine every pages into a request $htmlArray = []; @@ -91,8 +92,6 @@ public function postMultipleArrayAsync(array $contentItems): array { // and create and sign a request that we send to the lambda function $payload = json_encode(["html" => $htmlArray]); - // $this->logToServer("Creating payload with size {$payloadSize}!"); - $request = $this->createRequest($payload); $signedRequest = $this->sign($request); @@ -102,9 +101,6 @@ public function postMultipleArrayAsync(array $contentItems): array { $htmlArray = []; } - // $this->logToServer("Building up array of size {$payloadSize}:"); - // $this->logToServer($contentItem->getTitle()); - // Get the HTML then clean up and push a page into an array $html = $contentItem->getBody(); $document = $this->getDomDocument($html)->saveHTML(); @@ -115,10 +111,6 @@ public function postMultipleArrayAsync(array $contentItems): array { // Send out any leftover pages we might have if (count($htmlArray) > 0) { - // $this->logToServer("Found some leftovers"); - // $pagesPayload = json_encode($htmlArray); - - // $this->logToServer(count($htmlArray)); $payload = json_encode(["html" => $htmlArray]); $request = $this->createRequest($payload); @@ -127,26 +119,36 @@ public function postMultipleArrayAsync(array $contentItems): array { $promises[] = $client->sendAsync($signedRequest); } - - // $this->logToServer("waiting for promises..."); + // $this->logToServer("Number of promises:"); // $this->logToServer(count($promises)); - $results = Promise\Utils::unwrap($promises); + $results = Promise\Utils::settle($promises)->wait(); + // $results = Promise\Utils::unwrap($promises); + + $errors = 0; foreach ($results as $result) { - // Every "block" of reports pages should be in a stringified + // Every "block" of reports pages should be in a stringified // JSON, so we need to decode the JSON to be able to iterate through - // it first. + // it first.} + + if (isset($result["value"])) { + $response = json_decode($result["value"]->getBody()->getContents(), true); + } + else if (isset($result["reason"])) { + $errors++; + } - $response = json_decode($result->getBody()->getContents(), true); + // $this->logToServer($result["value"]->getBody()->getContents()); foreach ($response as $report) { + // $this->logToServer(json_encode($report)); $contentItemsReport[] = $report; } } - // $this->logToServer("Number of contentItems we're sending back:"); - // $this->logToServer(count($contentItemsReport)); + // $this->logToServer("Number of errors:"); + // $this->logToServer($errors); return $contentItemsReport; }