00001 <?php
00025
00026
00038 class aAdjacentWithSameResourceShouldBeCombined extends quailTest {
00039
00043 var $default_severity = QUAIL_TEST_SEVERE;
00044
00048 function check() {
00049 foreach($this->getAllElements('a') as $a) {
00050 if($this->propertyIsEqual($a->nextSibling, 'wholeText', '', true))
00051 $next = $a->nextSibling->nextSibling;
00052 else
00053 $next = $a->nextSibling;
00054 if($this->propertyIsEqual($next, 'tagName', 'a')) {
00055 if($a->getAttribute('href') == $next->getAttribute('href'))
00056 $this->addReport($a);
00057 }
00058 }
00059 }
00060 }
00061
00067 class aImgAltNotRepetative extends quailTest {
00068
00072 var $default_severity = QUAIL_TEST_SEVERE;
00073
00074
00078 function check() {
00079 foreach($this->getAllElements('a') as $a) {
00080 foreach($a->childNodes as $child) {
00081 if($this->propertyIsEqual($child, 'tagName', 'img')) {
00082 if(trim($a->nodeValue) == trim($child->getAttribute('alt')))
00083 $this->addReport($child);
00084 }
00085 }
00086 }
00087 }
00088 }
00089
00095 class aLinkTextDoesNotBeginWithRedundantWord extends quailTest {
00096
00100 var $default_severity = QUAIL_TEST_SEVERE;
00101
00105 var $strings = array('en' => array('link to', 'go to'),
00106 'es' => array('enlaces a', 'ir a')
00107 );
00108
00112 function check() {
00113 foreach($this->getAllElements('a') as $a) {
00114 if(!$a->nodeValue) {
00115 if(property_exists($a, 'firstChild') && $this->propertyIsEqual($a->firstChild, 'tagName', 'img')) {
00116 $text = $a->firstChild->getAttribute('alt');
00117 }
00118 }
00119 else
00120 $text = $a->nodeValue;
00121 foreach($this->translation() as $word) {
00122 if(strpos(trim($text), $word) === 0)
00123 $this->addReport($a);
00124 }
00125 }
00126 }
00127 }
00128
00134 class aLinksAreSeperatedByPrintableCharacters extends quailTest {
00135
00139 var $default_severity = QUAIL_TEST_SEVERE;
00140
00144 function check() {
00145 foreach($this->getAllElements('a') as $a) {
00146 if(property_exists($a, 'nextSibling')
00147 && is_object($a->nextSibling)
00148 && property_exists($a->nextSibling, 'nextSibling')
00149 && $this->propertyIsEqual($a->nextSibling->nextSibling, 'tagName', 'a')
00150 && ($this->propertyIsEqual($a->nextSibling, 'wholeText', '', true)
00151 || !property_exists($a->nextSibling, 'wholeText')
00152 || $this->propertyIsEqual($a->nextSibling, 'nodeValue', '', true)
00153 )
00154 ) {
00155 $this->addReport($a);
00156 }
00157 }
00158 }
00159 }
00160
00166 class aLinksDontOpenNewWindow extends quailTest {
00167
00171 var $default_severity = QUAIL_TEST_SEVERE;
00172
00176 var $allowed_targets = array('_self', '_parent', '_top');
00177
00181 function check() {
00182 foreach($this->getAllElements('a') as $a) {
00183 if($a->hasAttribute('target')
00184 && !in_array($a->getAttribute('target'), $this->allowed_targets)) {
00185 $this->addReport($a);
00186 }
00187 }
00188 }
00189
00190 }
00191
00197 class aLinksMakeSenseOutOfContext extends quailTest {
00198
00202 var $default_severity = QUAIL_TEST_SUGGESTION;
00203
00207 function check() {
00208 foreach($this->getAllElements('a') as $a) {
00209 if(strlen($a->nodeValue) > 1)
00210 $this->addReport($a);
00211 }
00212 }
00213
00214 }
00215
00221 class aLinksToMultiMediaRequireTranscript extends quailTest {
00222
00226 var $default_severity = QUAIL_TEST_SUGGESTION;
00227
00231 var $extensions = array('wmv', 'mpg', 'mov', 'ram', 'aif');
00232
00236 function check() {
00237 foreach($this->getAllElements('a') as $a) {
00238 if($a->hasAttribute('href')) {
00239 $filename = explode('.', $a->getAttribute('href'));
00240 $extension = array_pop($filename);
00241 if(in_array($extension, $this->extensions))
00242 $this->addReport($a);
00243 }
00244 }
00245 }
00246
00247 }
00248
00254 class aLinksToSoundFilesNeedTranscripts extends quailTest {
00255
00259 var $default_severity = QUAIL_TEST_SUGGESTION;
00260
00264 var $extensions = array('wav', 'snd', 'mp3', 'iff', 'svx', 'sam', 'smp', 'vce', 'vox', 'pcm', 'aif');
00265
00269 function check() {
00270 foreach($this->getAllElements('a') as $a) {
00271 if($a->hasAttribute('href')) {
00272 $filename = explode('.', $a->getAttribute('href'));
00273 $extension = array_pop($filename);
00274 if(in_array($extension, $this->extensions))
00275 $this->addReport($a);
00276 }
00277 }
00278 }
00279 }
00280
00285 class aMultimediaTextAlternative extends quailTest {
00286
00290 var $default_severity = QUAIL_TEST_SUGGESTION;
00291
00295 var $extensions = array('wmv', 'wav', 'mpg', 'mov', 'ram', 'aif');
00296
00300 function check() {
00301 foreach($this->getAllElements('a') as $a) {
00302 if($a->hasAttribute('href')) {
00303 $extension = substr($a->getAttribute('href'),
00304 (strrpos($a->getAttribute('href'), '.') + 1), 4);
00305 if(in_array($extension, $this->extensions))
00306 $this->addReport($a);
00307 }
00308 }
00309 }
00310 }
00311
00317 class aMustContainText extends quailTest {
00318
00322 var $default_severity = QUAIL_TEST_SEVERE;
00323
00327 function check() {
00328 foreach($this->getAllElements('a') as $a) {
00329 if(!$this->elementContainsReadableText($a) && ($a->hasAttribute('href'))) {
00330 $this->addReport($a);
00331 }
00332 }
00333 }
00334
00341 function isNotAnchor($a) {
00342 return (!($a->hasAttribute('name') && !$a->hasAttribute('href')));
00343 }
00344 }
00345
00351 class aMustHaveTitle extends quailTest {
00352
00356 var $default_severity = QUAIL_TEST_SEVERE;
00357
00361 function check() {
00362 foreach($this->getAllElements('a') as $a) {
00363 if(!$a->hasAttribute('title'))
00364 $this->addReport($a);
00365 }
00366
00367 }
00368 }
00369
00375 class aMustNotHaveJavascriptHref extends quailTest {
00376
00380 var $default_severity = QUAIL_TEST_SEVERE;
00381
00385 function check() {
00386 foreach($this->getAllElements('a') as $a) {
00387 if(substr(trim($a->getAttribute('href')), 0, 11) == 'javascript:')
00388 $this->addReport($a);
00389 }
00390 }
00391 }
00392
00398 class aSuspiciousLinkText extends quailTest {
00399
00403 var $default_severity = QUAIL_TEST_SEVERE;
00404
00408 var $strings = array('en' => array('click here', 'click', 'more', 'here'),
00409 'es' => array('clic aquí', 'clic', 'haga clic', 'más', 'aquí'));
00410
00414 function check() {
00415 foreach($this->getAllElements('a') as $a) {
00416 if(in_array(strtolower(trim($a->nodeValue)), $this->translation()))
00417 $this->addReport($a);
00418 }
00419
00420 }
00421 }
00422
00428 class aTitleDescribesDestination extends quailTest {
00429
00433 var $default_severity = QUAIL_TEST_SUGGESTION;
00434
00438 function check() {
00439 foreach($this->getAllElements('a') as $a) {
00440 if($a->hasAttribute('title'))
00441 $this->addReport($a);
00442 }
00443
00444 }
00445 }
00446
00452 class addressForAuthor extends quailTest {
00453
00457 var $default_severity = QUAIL_TEST_SEVERE;
00458
00462 var $cms = false;
00463
00467 function check() {
00468 foreach($this->getAllElements('address') as $address) {
00469 foreach($address->childNodes as $child) {
00470 if($this->propertyIsEqual($child, 'tagName', 'a'))
00471 return true;
00472 }
00473 }
00474 $this->addReport(null, null, false);
00475 }
00476
00477 }
00478
00484 class addressForAuthorMustBeValid extends quailTest {
00485
00489 var $default_severity = QUAIL_TEST_MODERATE;
00490
00494 function check() {
00495 foreach($this->getAllElements('address') as $address) {
00496 if ($this->validateEmailAddress($address->nodeValue, array('check_domain' => $this->checkDomain)))
00497 return true;
00498 foreach($address->childNodes as $child) {
00499 if($this->propertyIsEqual($child, 'tagName', 'a')
00500 && substr(strtolower($child->getAttribute('href')), 0, 7) == 'mailto:') {
00501 if($this->validateEmailAddress(trim(str_replace('mailto:', '', $child->getAttribute('href'))),
00502 array('check_domain' => $this->checkDomain)))
00503 return true;
00504
00505 }
00506 }
00507 }
00508 $this->addReport(null, null, false);
00509 }
00510
00511
00512 function validateEmailAddress($email) {
00513
00514
00515 if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) {
00516
00517
00518 return false;
00519 }
00520
00521 $email_array = explode("@", $email);
00522 $local_array = explode(".", $email_array[0]);
00523 for ($i = 0; $i < sizeof($local_array); $i++) {
00524 if
00525 (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$",
00526 $local_array[$i])) {
00527 return false;
00528 }
00529 }
00530
00531
00532 if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) {
00533 $domain_array = explode(".", $email_array[1]);
00534 if (sizeof($domain_array) < 2) {
00535 return false;
00536 }
00537 for ($i = 0; $i < sizeof($domain_array); $i++) {
00538 if
00539 (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$",
00540 $domain_array[$i])) {
00541 return false;
00542 }
00543 }
00544 }
00545 return true;
00546 }
00547
00548 }
00549
00555 class appletContainsTextEquivalent extends quailTest {
00556
00560 var $default_severity = QUAIL_TEST_SEVERE;
00561
00565 function check() {
00566 foreach($this->getAllElements('applet') as $applet) {
00567 if(trim($applet->nodeValue) == '' || !$applet->nodeValue)
00568 $this->addReport($applet);
00569
00570 }
00571 }
00572
00573 }
00574
00580 class appletContainsTextEquivalentInAlt extends quailTest {
00581
00585 var $default_severity = QUAIL_TEST_MODERATE;
00586
00587
00591 function check() {
00592 foreach($this->getAllElements('applet') as $applet) {
00593 if(!$applet->hasAttribute('alt') || $applet->getAttribute('alt') == '')
00594 $this->addReport($applet);
00595
00596 }
00597 }
00598
00599 }
00600
00606 class appletProvidesMechanismToReturnToParent extends quailTagTest {
00607
00611 var $default_severity = QUAIL_TEST_SUGGESTION;
00612
00613
00617 var $tag = 'applet';
00618 }
00619
00624 class appletTextEquivalentsGetUpdated extends quailTagTest {
00625
00629 var $default_severity = QUAIL_TEST_SUGGESTION;
00630
00634 var $tag = 'applet';
00635
00636 }
00637
00643 class appletUIMustBeAccessible extends quailTagTest {
00644
00648 var $default_severity = QUAIL_TEST_SUGGESTION;
00649
00653 var $tag = 'applet';
00654 }
00655
00661 class appletsDoNotFlicker extends quailTagTest {
00662
00666 var $default_severity = QUAIL_TEST_SUGGESTION;
00667
00671 var $tag = 'applet';
00672
00673 }
00674
00680 class appletsDoneUseColorAlone extends quailTagTest {
00681
00685 var $default_severity = QUAIL_TEST_SUGGESTION;
00686
00690 var $tag = 'applet';
00691 }
00692
00698 class areaAltIdentifiesDestination extends quailTagTest {
00699
00703 var $default_severity = QUAIL_TEST_SUGGESTION;
00704
00708 var $tag = 'area';
00709
00710 }
00711
00717 class areaAltRefersToText extends quailTagTest {
00718
00722 var $default_severity = QUAIL_TEST_SUGGESTION;
00723
00727 var $tag = 'area';
00728 }
00729
00735 class areaDontOpenNewWindow extends quailTest {
00736
00740 var $default_severity = QUAIL_TEST_SEVERE;
00741
00745 var $allowed_targets = array('_self', '_parent', '_top');
00746
00750 function check() {
00751 foreach($this->getAllElements('area') as $area) {
00752 if($area->hasAttribute('target')
00753 && !in_array($area->getAttribute('target'), $this->allowed_targets)) {
00754 $this->addReport($area);
00755 }
00756 }
00757 }
00758
00759 }
00760
00766 class areaHasAltValue extends quailTest {
00767
00771 var $default_severity = QUAIL_TEST_SEVERE;
00772
00776 function check() {
00777 foreach($this->getAllElements('area') as $area) {
00778 if(!$area->hasAttribute('alt'))
00779 $this->addReport($area);
00780 }
00781 }
00782
00783 }
00784
00790 class areaLinksToSoundFile extends quailTest {
00791
00795 var $default_severity = QUAIL_TEST_SUGGESTION;
00796
00800 var $extensions = array('wav', 'snd', 'mp3', 'iff', 'svx', 'sam', 'smp', 'vce', 'vox', 'pcm', 'aif');
00801
00805 function check() {
00806 foreach($this->getAllElements('area') as $area) {
00807 if($area->hasAttribute('href')) {
00808 $filename = explode('.', $area->getAttribute('href'));
00809 $extension = array_pop($filename);
00810 if(in_array($extension, $this->extensions))
00811 $this->addReport($area);
00812 }
00813 }
00814 }
00815
00816 }
00817
00823 class basefontIsNotUsed extends quailTagTest {
00824
00828 var $default_severity = QUAIL_TEST_SEVERE;
00829
00833 var $tag = 'basefont';
00834 }
00835
00841 class blinkIsNotUsed extends quailTagTest {
00842
00846 var $default_severity = QUAIL_TEST_SEVERE;
00847
00851 var $tag = 'blink';
00852
00853 }
00854
00860 class blockquoteNotUsedForIndentation extends quailTest {
00861
00865 var $default_severity = QUAIL_TEST_MODERATE;
00866
00870 function check() {
00871 foreach($this->getAllElements('blockquote') as $blockquote) {
00872 if(!$blockquote->hasAttribute('cite'))
00873 $this->addReport($blockquote);
00874 }
00875 }
00876 }
00877
00883 class blockquoteUseForQuotations extends quailTest {
00884
00888 var $default_severity = QUAIL_TEST_MODERATE;
00889
00893 function check() {
00894 foreach($this->getAllElements('p') as $paragraph) {
00895 if(in_array(substr(trim($paragraph->nodeValue), 0, 1), array('"', "'")) &&
00896 in_array(substr(trim($paragraph->nodeValue), -1, 1), array('"', "'"))) {
00897 $this->addReport($paragraph);
00898 }
00899 }
00900 }
00901
00902 }
00903
00909 class bodyActiveLinkColorContrast extends bodyColorContrast {
00910
00914 var $default_severity = QUAIL_TEST_SEVERE;
00915
00919 var $cms = false;
00920
00924 var $foreground = 'alink';
00925 }
00926
00927
00928
00929
00935 class bodyLinkColorContrast extends bodyColorContrast {
00936
00940 var $default_severity = QUAIL_TEST_SEVERE;
00941
00945 var $cms = false;
00946
00950 var $foreground = 'link';
00951 }
00952
00958 class bodyMustNotHaveBackground extends quailTest {
00959
00963 var $default_severity = QUAIL_TEST_SEVERE;
00964
00968 var $cms = false;
00969
00973 function check() {
00974 $body = $this->getAllElements('body');
00975 if(!$body)
00976 return false;
00977 $body = $body[0];
00978 if($body->hasAttribute('background'))
00979 $this->addReport(null, null, false);
00980 }
00981 }
00982
00988 class bodyVisitedLinkColorContrast extends bodyColorContrast {
00989
00993 var $default_severity = QUAIL_TEST_SEVERE;
00994
00998 var $cms = false;
00999
01003 var $foreground = 'vlink';
01004 }
01005
01011 class boldIsNotUsed extends quailTagTest {
01012
01016 var $default_severity = QUAIL_TEST_SEVERE;
01017
01021 var $tag = 'bold';
01022 }
01023
01029 class checkboxHasLabel extends inputHasLabel {
01030
01034 var $default_severity = QUAIL_TEST_SEVERE;
01035
01039 var $tag = 'input';
01040
01044 var $type = 'checkbox';
01045
01049 var $no_type = false;
01050 }
01051
01057 class checkboxLabelIsNearby extends quailTest {
01058
01062 var $default_severity = QUAIL_TEST_MODERATE;
01063
01067 function check() {
01068 foreach($this->getAllElements('input') as $input) {
01069 if($input->getAttribute('type') == 'checkbox')
01070 $this->addReport($input);
01071
01072 }
01073 }
01074 }
01075
01081 class cssDocumentMakesSenseStyleTurnedOff extends quailTest {
01082
01086 var $default_severity = QUAIL_TEST_SUGGESTION;
01087
01091 function check() {
01092 foreach($this->getAllElements('link') as $link) {
01093 if($link->parentNode->tagName == 'head') {
01094 if($link->getAttribute('rel') == 'stylesheet')
01095 $this->addReport($link);
01096 }
01097 }
01098 }
01099 }
01100
01106 class cssTextHasContrast extends quailColorTest {
01107
01111 var $default_severity = QUAIL_TEST_SEVERE;
01112
01116 var $default_background = '#ffffff';
01117
01121 var $default_color = '#000000';
01122
01126 function check() {
01127 if(isset($this->options['css_background'])) {
01128 $this->default_background = $this->options['css_background'];
01129 }
01130 if(isset($this->options['css_foreground'])) {
01131 $this->default_color = $this->options['css_foreground'];
01132 }
01133 $xpath = new DOMXPath($this->dom);
01134 $entries = $xpath->query('//*');
01135 foreach($entries as $element) {
01136 $style = $this->css->getStyle($element);
01137 if((isset($style['background']) || isset($style['background-color'])) && isset($style['color']) && $element->nodeValue) {
01138 $background = (isset($style['background-color']))
01139 ? $style['background-color']
01140 : $style['background'];
01141 if(!$background || $this->options['css_only_use_default']) {
01142 $background = $this->default_background;
01143 }
01144 $luminosity = $this->getLuminosity(
01145 $style['color'],
01146 $background
01147 );
01148 if($luminosity < 5) {
01149 $this->addReport($element, 'background: '. $background .' fore: '. $style['color'] . ' lum: '. $luminosity);
01150 }
01151 }
01152 }
01153
01154 }
01155
01156 }
01157
01163 class doctypeProvided extends quailTest {
01164
01168 var $default_severity = QUAIL_TEST_SEVERE;
01169
01173 function check() {
01174 if(!$this->dom->doctype->publicId)
01175 $this->addReport(null, null, false);
01176 }
01177
01178 }
01179
01185 class documentAbbrIsUsed extends quailTest {
01186
01190 var $default_severity = QUAIL_TEST_MODERATE;
01191
01195 var $acronym_tag = 'abbr';
01196
01200 function check() {
01201 foreach($this->getAllElements($this->acronym_tag) as $acronym) {
01202 $predefined[strtoupper(trim($acronym->nodeValue))] = $acronym->getAttribute('title');
01203 }
01204 $already_reported = array();
01205 foreach($this->getAllElements(null, 'text') as $text) {
01206
01207 $words = explode(' ', $text->nodeValue);
01208 if(count($words) > 1 && strtoupper($text->nodeValue) != $text->nodeValue) {
01209 foreach($words as $word) {
01210 $word = preg_replace("/[^a-zA-Zs]/", "", $word);
01211 if(strtoupper($word) == $word && strlen($word) > 1 && !isset($predefined[strtoupper($word)]))
01212
01213 if(!isset($already_reported[strtoupper($word)])) {
01214 $this->addReport($text, 'Word "'. $word .'" requires an <code>'. $this->acronym_tag .'</code> tag.');
01215 }
01216 $already_reported[strtoupper($word)] = true;
01217 }
01218 }
01219 }
01220
01221 }
01222
01223 }
01224
01231 class documentAcronymsHaveElement extends documentAbbrIsUsed {
01232
01236 var $default_severity = QUAIL_TEST_MODERATE;
01237
01241 var $acronym_tag = 'acronym';
01242 }
01243
01249 class documentAllColorsAreSet extends quailTest {
01250
01254 var $default_severity = QUAIL_TEST_SEVERE;
01255
01259 var $cms = false;
01260
01265 var $color_attributes = array('text', 'bgcolor', 'link', 'alink', 'vlink');
01266
01270 function check() {
01271 $body = $this->getAllElements('body');
01272 $body = $body[0];
01273 if($body) {
01274 $colors = 0;
01275 foreach($this->color_attributes as $attribute) {
01276 if($body->hasAttribute($attribute))
01277 $colors++;
01278 }
01279 if($colors > 0 && $colors < 5)
01280 $this->addReport(null, null, false);
01281 }
01282 }
01283 }
01284
01290 class documentAutoRedirectNotUsed extends quailTest {
01291
01295 var $default_severity = QUAIL_TEST_SEVERE;
01296
01300 var $cms = false;
01301
01305 function check() {
01306 foreach($this->getAllElements('meta') as $meta) {
01307 if($meta->getAttribute('http-equiv') == 'refresh' && !$meta->hasAttribute('content'))
01308 $this->addReport($meta);
01309 }
01310
01311 }
01312 }
01313
01319 class documentColorWaiActiveLinkAlgorithim extends bodyWaiErtColorContrast {
01320
01324 var $default_severity = QUAIL_TEST_SEVERE;
01325
01329 var $cms = false;
01330
01334 var $foreground = 'alink';
01335 }
01336
01342 class documentColorWaiAlgorithim extends bodyWaiErtColorContrast {
01343
01347 var $default_severity = QUAIL_TEST_SEVERE;
01348
01352 var $cms = false;
01353
01354 }
01355
01361 class documentColorWaiLinkAlgorithim extends bodyWaiErtColorContrast {
01362
01366 var $default_severity = QUAIL_TEST_SEVERE;
01367
01371 var $cms = false;
01372
01376 var $foreground = 'link';
01377 }
01378
01384 class documentColorWaiVisitedLinkAlgorithim extends bodyWaiErtColorContrast {
01385
01389 var $default_severity = QUAIL_TEST_SEVERE;
01390
01394 var $cms = false;
01395
01399 var $foreground = 'vlink';
01400 }
01401
01407 class documentContentReadableWithoutStylesheets extends quailTest {
01408
01412 var $default_severity = QUAIL_TEST_SUGGESTION;
01413
01417 var $cms = false;
01418
01422 function check() {
01423 foreach($this->getAllElements(null, 'text') as $text) {
01424 if($text->hasAttribute('style')) {
01425 $this->addReport(null, null, false);
01426 return false;
01427 }
01428 }
01429
01430 }
01431 }
01432
01438 class documentHasTitleElement extends quailTest {
01439
01443 var $default_severity = QUAIL_TEST_SEVERE;
01444
01448 var $cms = false;
01449
01453 function check() {
01454
01455 $element = $this->dom->getElementsByTagName('title');
01456 if(!$element->item(0))
01457 $this->addReport(null, null, false);
01458
01459 }
01460 }
01461
01467 class documentIDsMustBeUnique extends quailTest {
01468
01472 var $default_severity = QUAIL_TEST_SEVERE;
01473
01477 var $cms = false;
01478
01482 function check() {
01483 $xpath = new DOMXPath($this->dom);
01484 $entries = $xpath->query('//*');
01485 $ids = array();
01486 foreach($entries as $element) {
01487 if($element->hasAttribute('id'))
01488 $ids[$element->getAttribute('id')][] = $element;
01489 }
01490 if(count($ids) > 0) {
01491 foreach($ids as $id) {
01492 if(count($id) > 1)
01493 $this->addReport($id[1]);
01494 }
01495 }
01496 }
01497 }
01498
01504 class documentLangIsISO639Standard extends quailTest {
01505
01509 var $default_severity = QUAIL_TEST_SEVERE;
01510
01514 var $cms = false;
01515
01519 function check() {
01520 $languages = file(dirname(__FILE__).'/resources/iso639.txt');
01521
01522 $element = $this->dom->getElementsByTagName('html');
01523 $html = $element->item(0);
01524 if(!$html)
01525 return null;
01526 if($html->hasAttribute('lang'))
01527 if(in_array(strtolower($html->getAttribute('lang')), $languages))
01528 $this->addReport(null, null, false);
01529
01530 }
01531 }
01532
01538 class documentLangNotIdentified extends quailTest {
01539
01543 var $default_severity = QUAIL_TEST_SEVERE;
01544
01548 var $cms = false;
01549
01553 function check() {
01554 $element = $this->dom->getElementsByTagName('html');
01555 $html = $element->item(0);
01556 if(!$html) return null;
01557 if(!$html->hasAttribute('lang') || trim($html->getAttribute('lang')) == '')
01558 $this->addReport(null, null, false);
01559
01560 }
01561 }
01562
01568 class documentMetaNotUsedWithTimeout extends quailTest {
01569
01573 var $default_severity = QUAIL_TEST_SEVERE;
01574
01578 var $cms = false;
01579
01583 function check() {
01584 foreach($this->getAllElements('meta') as $meta) {
01585 if($meta->getAttribute('http-equiv') == 'refresh' && !$meta->getAttribute('content'))
01586 $this->addReport($meta);
01587 }
01588
01589 }
01590 }
01591
01603 class documentReadingDirection extends quailTest {
01604
01605
01609 var $default_severity = QUAIL_TEST_MODERATE;
01610
01614 var $cms = false;
01615
01619 var $right_to_left = array('he', 'ar');
01620
01624 function check() {
01625 $xpath = new DOMXPath($this->dom);
01626 $entries = $xpath->query('//*');
01627 foreach($entries as $element) {
01628 if(in_array($element->getAttribute('lang'), $this->right_to_left)) {
01629
01630 if($element->getAttribute('dir') != 'rtl')
01631 $this->addReport($element);
01632 }
01633 }
01634 }
01635 }
01636
01642 class documentStrictDocType extends quailTest {
01643
01647 var $default_severity = QUAIL_TEST_SEVERE;
01648
01652 var $cms = false;
01653
01657 function check() {
01658 if(strpos(strtolower($this->dom->doctype->publicId), 'strict') === false
01659 && strpos(strtolower($this->dom->doctype->systemId), 'strict') === false)
01660 $this->addReport(null, null, false);
01661 }
01662 }
01663
01669 class documentTitleDescribesDocument extends quailTest {
01670
01674 var $default_severity = QUAIL_TEST_SUGGESTION;
01675
01679 var $cms = false;
01680
01684 function check() {
01685 $placeholders = file(dirname(__FILE__).'/resources/placeholder.txt');
01686 $element = $this->dom->getElementsByTagName('title');
01687 $title = $element->item(0);
01688 if($title) {
01689 $this->addReport($title);
01690 }
01691 }
01692 }
01693
01699 class documentTitleIsNotPlaceholder extends quailTest {
01700
01704 var $default_severity = QUAIL_TEST_SEVERE;
01705
01709 var $cms = false;
01710
01714 function check() {
01715 $placeholders = file(dirname(__FILE__).'/resources/placeholder.txt');
01716 $element = $this->dom->getElementsByTagName('title');
01717 $title = $element->item(0);
01718 if($title) {
01719 if(in_array(strtolower($title->nodeValue), $placeholders))
01720 $this->addReport(null, null, false);
01721 }
01722 }
01723 }
01724
01730 class documentTitleIsShort extends quailTest {
01731
01735 var $default_severity = QUAIL_TEST_MODERATE;
01736
01740 var $cms = false;
01741
01745 function check() {
01746
01747 $element = $this->dom->getElementsByTagName('title');
01748 $title = $element->item(0);
01749 if($title) {
01750 if(strlen($title->nodeValue)> 150)
01751 $this->addReport(null, null, false);
01752 }
01753 }
01754 }
01755
01761 class documentTitleNotEmpty extends quailTest {
01762
01766 var $default_severity = QUAIL_TEST_SEVERE;
01767
01771 var $cms = false;
01772
01776 function check() {
01777
01778 $element = $this->dom->getElementsByTagName('title');
01779 if($element->length > 0) {
01780 $title = $element->item(0);
01781 if(trim($title->nodeValue) == '')
01782 $this->addReport(null, null, false);
01783 }
01784 }
01785 }
01786
01792 class documentValidatesToDocType extends quailTest {
01793
01797 var $default_severity = QUAIL_TEST_SEVERE;
01798
01802 var $cms = false;
01803
01807 function check() {
01808 if(!@$this->dom->validate())
01809 $this->addReport(null, null, false);
01810 }
01811 }
01812
01818 class documentVisualListsAreMarkedUp extends quailTest {
01819
01823 var $default_severity = QUAIL_TEST_SEVERE;
01824
01828 var $list_cues = array('*', '<br>*', '•', '•');
01829
01833 function check() {
01834 foreach($this->getAllElements(null, 'text') as $text) {
01835 foreach($this->list_cues as $cue) {
01836 $first = stripos($text->nodeValue, $cue);
01837 $second = strripos($text->nodeValue, $cue);
01838 if($first && $second && $first != $second)
01839 $this->addReport($text);
01840 }
01841 }
01842
01843 }
01844 }
01845
01851 class documentWordsNotInLanguageAreMarked extends quailTest {
01852
01856 var $default_severity = QUAIL_TEST_SUGGESTION;
01857
01861 function check() {
01862 $body = $this->getAllElements('body');
01863 if(!isset($body[0])) {
01864 return false;
01865 }
01866 $body = $body[0];
01867 if(!is_object($body)) {
01868 return false;
01869 }
01870 if(!property_exists($body, 'nodeValue')) {
01871 return false;
01872 }
01873 $words = explode(' ', $body->nodeValue);
01874
01875 if(count($words) > 10)
01876 $this->addReport(null, null, false);
01877 }
01878 }
01879
01885 class embedHasAssociatedNoEmbed extends quailTest {
01886
01890 var $default_severity = QUAIL_TEST_SEVERE;
01891
01895 function check() {
01896 foreach($this->getAllElements('embed') as $embed) {
01897 if(!$this->propertyIsEqual($embed->firstChild, 'tagName', 'noembed')
01898 && !$this->propertyIsEqual($embed->nextSibling, 'tagName', 'noembed')) {
01899 $this->addReport($embed);
01900 }
01901
01902 }
01903 }
01904 }
01905
01911 class embedMustHaveAltAttribute extends quailTest {
01912
01916 var $default_severity = QUAIL_TEST_SEVERE;
01917
01921 function check() {
01922 foreach($this->getAllElements('embed') as $embed) {
01923 if(!$embed->hasAttribute('alt'))
01924 $this->addReport($embed);
01925
01926 }
01927 }
01928 }
01929
01935 class embedMustNotHaveEmptyAlt extends quailTest {
01936
01940 var $default_severity = QUAIL_TEST_SEVERE;
01941
01945 function check() {
01946 foreach($this->getAllElements('embed') as $embed) {
01947 if($embed->hasAttribute('alt') && trim($embed->getAttribute('alt')) == '')
01948 $this->addReport($embed);
01949
01950 }
01951 }
01952 }
01953
01959 class embedProvidesMechanismToReturnToParent extends quailTagTest {
01960
01964 var $default_severity = QUAIL_TEST_SUGGESTION;
01965
01969 var $tag = 'embed';
01970 }
01971
01977 class emoticonsExcessiveUse extends quailTest {
01978
01982 var $default_severity = QUAIL_TEST_SEVERE;
01983
01987 function check() {
01988 $emoticons = file(dirname(__FILE__).'/resources/emoticons.txt', FILE_IGNORE_NEW_LINES);
01989 $count = 0;
01990 foreach($this->getAllElements(null, 'text') as $element) {
01991 if(strlen($element->nodeValue < 2)) {
01992 $words = explode(' ', $element->nodeValue);
01993 foreach($words as $word) {
01994 if(in_array($word, $emoticons)) {
01995 $count++;
01996 if($count > 4) {
01997 $this->addReport(null, null, false);
01998 return false;
01999 }
02000 }
02001 }
02002
02003 }
02004 }
02005
02006 }
02007 }
02008
02009 class emoticonsMissingAbbr extends quailTest {
02010
02014 var $default_severity = QUAIL_TEST_SEVERE;
02015
02019 function check() {
02020 $emoticons = file(dirname(__FILE__).'/resources/emoticons.txt', FILE_IGNORE_NEW_LINES);
02021 $count = 0;
02022 foreach($this->getAllElements('abbr') as $abbr) {
02023 $abbreviated[$abbr->nodeValue] = $abbr->getAttribute('title');
02024 }
02025 foreach($this->getAllElements(null, 'text') as $element) {
02026 if(strlen($element->nodeValue < 2)) {
02027 $words = explode(' ', $element->nodeValue);
02028 foreach($words as $word) {
02029 if(in_array($word, $emoticons)) {
02030 if(!isset($abbreviated[$word]))
02031 $this->addReport($element);
02032 }
02033 }
02034
02035 }
02036 }
02037
02038 }
02039 }
02040
02046 class fileHasLabel extends inputHasLabel {
02047
02051 var $default_severity = QUAIL_TEST_SEVERE;
02052
02056 var $tag = 'input';
02057
02061 var $type = 'file';
02062
02066 var $no_type = false;
02067 }
02068
02074 class fileLabelIsNearby extends quailTest {
02075
02079 var $default_severity = QUAIL_TEST_MODERATE;
02080
02084 function check() {
02085 foreach($this->getAllElements('input') as $input) {
02086 if($input->getAttribute('type') == 'file')
02087 $this->addReport($input);
02088
02089 }
02090 }
02091 }
02092
02098 class fontIsNotUsed extends quailTagTest {
02099
02103 var $default_severity = QUAIL_TEST_SEVERE;
02104
02108 var $tag = 'font';
02109 }
02110
02111 class formAllowsCheckIfIrreversable extends quailTagTest {
02112
02116 var $default_severity = QUAIL_TEST_SUGGESTION;
02117
02121 var $tag = 'form';
02122 }
02123
02129 class formDeleteIsReversable extends quailTest {
02130
02134 var $default_severity = QUAIL_TEST_SUGGESTION;
02135
02139 var $strings = array('en' => array('delete', 'remove', 'erase'),
02140 'es' => array('borrar', 'eliminar', 'suprimir'),
02141 );
02142
02146 function check() {
02147 foreach($this->getAllElements('input') as $input) {
02148 if($input->getAttribute('type') == 'submit') {
02149 foreach($this->translation() as $word) {
02150 if(strpos(strtolower($input->getAttribute('value')), $word) !== false)
02151 $this->addReport($this->getParent($input, 'form', 'body'));
02152 }
02153 }
02154 }
02155 }
02156 }
02157
02163 class formErrorMessageHelpsUser extends quailTagTest {
02164
02168 var $default_severity = QUAIL_TEST_SUGGESTION;
02169
02173 var $tag = 'form';
02174 }
02175
02181 class formHasGoodErrorMessage extends quailTagTest {
02182
02186 var $default_severity = QUAIL_TEST_SUGGESTION;
02187
02191 var $tag = 'form';
02192 }
02193
02194
02200 class formWithRequiredLabel extends quailTest {
02201
02205 var $default_severity = QUAIL_TEST_MODERATE;
02206
02210 var $suspect_styles = array('font-weight', 'color');
02211
02215 function check() {
02216 $labels = array();
02217 foreach($this->getAllElements('label') as $label) {
02218 $labels[] = $label;
02219 if(strpos($label->nodeValue, '*') !== false) {
02220 if($input = $this->dom->getElementById($label->getAttribute('for'))) {
02221 if(!$input->hasAttribute('aria-required') ||
02222 strtolower($input->getAttribute('aria-required')) != 'true') {
02223 $this->addReport($label);
02224 }
02225 }
02226 else {
02227 $this->addReport($label);
02228 }
02229 }
02230 }
02231 $styles = array();
02232 foreach($labels as $k => $label) {
02233
02234
02235 $styles[$k] = $this->css->getStyle($label);
02236 if($this->elementHasChild($label, 'strong') || $this->elementHasChild($label, 'b')) {
02237 $styles[$k]['font-weight'] = 'bold';
02238 }
02239 if($k) {
02240 foreach($this->suspect_styles as $style) {
02241 if($styles[$k][$style] != $styles[($k - 1)][$style]) {
02242 $form = $this->getElementAncestor($label, 'form');
02243 if($form) {
02244 $this->addReport($form);
02245 }
02246 else {
02247 $this->addReport($label);
02248 }
02249 }
02250 }
02251 }
02252 }
02253 }
02254 }
02255
02261 class frameIsNotUsed extends quailTagTest {
02262
02266 var $default_severity = QUAIL_TEST_SEVERE;
02267
02271 var $tag = 'frame';
02272
02276 var $cms = false;
02277
02278 }
02279
02285 class frameRelationshipsMustBeDescribed extends quailTest {
02286
02290 var $default_severity = QUAIL_TEST_MODERATE;
02291
02295 var $cms = false;
02296
02297
02301 function check() {
02302 foreach($this->getAllElements('frameset') as $frameset) {
02303
02304 if(!$frameset->hasAttribute('longdesc') && $frameset->childNodes->length > 2)
02305 $this->addReport($frameset);
02306 }
02307 }
02308
02309 }
02310
02316 class frameSrcIsAccessible extends quailTest {
02317
02321 var $default_severity = QUAIL_TEST_SUGGESTION;
02322
02326 var $cms = false;
02327
02331 function check() {
02332 foreach($this->getAllElements('frame') as $frame) {
02333 if($frame->hasAttribute('src')) {
02334 $extension = array_pop(explode('.', $frame->getAttribute('src')));
02335 if(in_array($extension, $this->image_extensions))
02336 $this->addReport($frame);
02337
02338 }
02339 }
02340 }
02341
02342 }
02343
02349 class frameTitlesDescribeFunction extends quailTest {
02350
02354 var $default_severity = QUAIL_TEST_SUGGESTION;
02355
02359 var $cms = false;
02360
02364 function check() {
02365 foreach($this->getAllElements('frame') as $frame) {
02366 if($frame->hasAttribute('title'))
02367 $this->addReport($frame);
02368 }
02369 }
02370
02371 }
02372
02378 class frameTitlesNotEmpty extends quailTest {
02379
02383 var $default_severity = QUAIL_TEST_SEVERE;
02384
02388 var $cms = false;
02389
02393 function check() {
02394 foreach($this->getAllElements('frame') as $frame) {
02395 if(!$frame->hasAttribute('title') || trim($frame->getAttribute('title')) == '')
02396 $this->addReport($frame);
02397 }
02398 }
02399 }
02400
02406 class frameTitlesNotPlaceholder extends quailTest {
02407
02411 var $default_severity = QUAIL_TEST_SEVERE;
02412
02416 var $cms = false;
02417
02421 var $strings = array('en' => array('title', 'frame', 'frame title', 'the title'),
02422 'es' => array('título', 'marco', 'título del marco', 'el título'),
02423 );
02424
02428 function check() {
02429 foreach($this->getAllElements('frame') as $frame) {
02430 if(in_array(trim(strtolower($frame->getAttribute('title'))), $this->translation()))
02431 $this->addReport($frame);
02432 }
02433 }
02434
02435 }
02436
02442 class framesHaveATitle extends quailTest {
02443
02447 var $default_severity = QUAIL_TEST_SEVERE;
02448
02452 var $cms = false;
02453
02457 function check() {
02458 foreach($this->getAllElements('frame') as $frame) {
02459 if(!$frame->hasAttribute('title'))
02460 $this->addReport($frame);
02461 }
02462 }
02463
02464 }
02465
02471 class framesetIsNotUsed extends quailTagTest {
02472
02476 var $default_severity = QUAIL_TEST_SEVERE;
02477
02481 var $cms = false;
02482
02486 var $tag = 'frameset';
02487 }
02488
02494 class framesetMustHaveNoFramesSection extends quailTest {
02495
02499 var $default_severity = QUAIL_TEST_SEVERE;
02500
02504 var $cms = false;
02505
02509 function check() {
02510 foreach($this->getAllElements('frameset') as $frameset) {
02511 if(!$this->elementHasChild($frameset, 'noframes'))
02512 $this->addReport($frameset);
02513 }
02514 }
02515
02516 }
02517
02523 class headerH1 extends quailHeaderTest {
02524
02528 var $tag = 'h1';
02529
02530 }
02531
02537 class headerH1Format extends quailTagTest{
02538
02542 var $default_severity = QUAIL_TEST_SUGGESTION;
02543
02547 var $tag = 'h1';
02548 }
02549
02555 class headerH2 extends quailHeaderTest {
02556
02560 var $tag = 'h2';
02561
02562 }
02563
02569 class headerH2Format extends quailTagTest{
02570
02574 var $default_severity = QUAIL_TEST_SUGGESTION;
02575
02579 var $tag = 'h2';
02580 }
02581
02587 class headerH3 extends quailHeaderTest {
02588
02592 var $tag = 'h3';
02593
02594 }
02595
02601 class headerH3Format extends quailTagTest{
02602
02606 var $default_severity = QUAIL_TEST_SUGGESTION;
02607
02611 var $tag = 'h3';
02612 }
02613
02619 class headerH4 extends quailHeaderTest {
02620
02624 var $tag = 'h4';
02625
02626 }
02627
02633 class headerH4Format extends quailTagTest{
02634
02638 var $default_severity = QUAIL_TEST_SUGGESTION;
02639
02643 var $tag = 'h4';
02644 }
02645
02646 class headerH5 extends quailHeaderTest {
02647
02651 var $tag = 'h5';
02652
02653 }
02654
02660 class headerH5Format extends quailTagTest{
02661
02665 var $default_severity = QUAIL_TEST_SUGGESTION;
02666
02670 var $tag = 'h5';
02671 }
02672
02678 class headerH6Format extends quailTagTest{
02679
02683 var $default_severity = QUAIL_TEST_SUGGESTION;
02684
02688 var $tag = 'h6';
02689 }
02690
02696 class headersUseToMarkSections extends quailTest {
02697
02701 var $default_severity = QUAIL_TEST_MODERATE;
02702
02706 var $non_header_tags = array('strong', 'b', 'em', 'i');
02707
02711 function check() {
02712 $headers = $this->getAllElements(null, 'header');
02713 $paragraphs = $this->getAllElements('p');
02714 if(count($headers) == 0 && count($paragraphs) > 1)
02715 $this->addReport(null, null, false);
02716 foreach($paragraphs as $p) {
02717 if((is_object($p->firstChild)
02718 && property_exists($p->firstChild, 'tagName')
02719 && in_array($p->firstChild->tagName, $this->non_header_tags)
02720 && trim($p->nodeValue) == trim($p->firstChild->nodeValue))
02721 || (is_object($p->firstChild->nextSibling)
02722 && property_exists($p->firstChild->nextSibling, 'tagName')
02723 && in_array($p->firstChild->nextSibling->tagName, $this->non_header_tags)
02724 && trim($p->nodeValue) == trim($p->firstChild->nextSibling->nodeValue))
02725 || (is_object($p->previousSibling)
02726 && property_exists($p->previousSibling, 'tagName')
02727 && in_array($p->previousSibling->tagName, $this->non_header_tags)
02728 && trim($p->nodeValue) == trim($p->previousSibling->nodeValue)))
02729 $this->addReport($p);
02730 }
02731 }
02732 }
02733
02739 class iIsNotUsed extends quailTagTest {
02740
02744 var $default_severity = QUAIL_TEST_SEVERE;
02745
02749 var $tag = 'i';
02750 }
02751
02757 class iframeMustNotHaveLongdesc extends quailTest {
02758
02762 var $default_severity = QUAIL_TEST_SEVERE;
02763
02767 function check() {
02768 foreach($this->getAllElements('iframe') as $iframe) {
02769 if($iframe->hasAttribute('longdesc'))
02770 $this->addReport($iframe);
02771
02772 }
02773 }
02774 }
02775
02781 class imageMapServerSide extends quailTest {
02782
02786 var $default_severity = QUAIL_TEST_SEVERE;
02787
02791 function check() {
02792 foreach($this->getAllElements('img') as $img) {
02793 if($img->hasAttribute('ismap'))
02794 $this->addReport($img);
02795 }
02796
02797 }
02798 }
02799
02805 class imgAltEmptyForDecorativeImages extends quailTest {
02806
02810 var $default_severity = QUAIL_TEST_SUGGESTION;
02811
02815 function check() {
02816 foreach($this->getAllElements('img') as $img) {
02817 if($img->hasAttribute('alt'))
02818 $this->addReport($img);
02819 }
02820 }
02821
02822 }
02823
02829 class imgAltIdentifiesLinkDestination extends quailTest {
02830
02834 var $default_severity = QUAIL_TEST_SUGGESTION;
02835
02839 function check() {
02840 foreach($this->getAllElements('a') as $a) {
02841 if(!$a->nodeValue) {
02842 foreach($a->childNodes as $child) {
02843 if($this->propertyIsEqual($child, 'tagName', 'img')
02844 && $child->hasAttribute('alt')) {
02845 $this->addReport($child);
02846 }
02847 }
02848 }
02849 }
02850
02851 }
02852 }
02853
02859 class imgAltIsDifferent extends quailTest {
02860
02864 var $default_severity = QUAIL_TEST_SEVERE;
02865
02869 function check() {
02870 foreach($this->getAllElements('img') as $img) {
02871 if(trim($img->getAttribute('src')) == trim($img->getAttribute('alt')))
02872 $this->addReport($img);
02873 }
02874 }
02875
02876 }
02877
02883 class imgAltIsSameInText extends quailTest {
02884
02888 var $default_severity = QUAIL_TEST_SUGGESTION;
02889
02893 function check() {
02894 foreach($this->getAllElements('img') as $img) {
02895 if($img->hasAttribute('alt'))
02896 $this->addReport($img);
02897 }
02898
02899 }
02900 }
02901
02907 class imgAltIsTooLong extends quailTest {
02908
02912 var $default_severity = QUAIL_TEST_SEVERE;
02913
02917 function check() {
02918 foreach($this->getAllElements('img') as $img) {
02919 if($img->hasAttribute('alt') && strlen($img->getAttribute('alt')) > 100)
02920 $this->addReport($img);
02921 }
02922
02923 }
02924 }
02925
02931 class imgAltNotEmptyInAnchor extends quailTest {
02932
02936 var $default_severity = QUAIL_TEST_SEVERE;
02937
02941 function check() {
02942 foreach($this->getAllElements('a') as $a) {
02943 if(!$a->nodeValue && $a->childNodes) {
02944 foreach($a->childNodes as $child) {
02945 if($this->propertyIsEqual($child, 'tagName', 'img')
02946 && trim($child->getAttribute('alt')) == '')
02947 $this->addReport($child);
02948 }
02949 }
02950 }
02951
02952 }
02953 }
02954
02960 class imgAltNotPlaceHolder extends quailTest {
02961
02965 var $default_severity = QUAIL_TEST_SEVERE;
02966
02970 var $strings = array('en' => array('nbsp', ' ', 'spacer', 'image', 'img', 'photo'),
02971 'es' => array('nbsp', ' ', 'spacer', 'espacio', 'imagen', 'img', 'foto')
02972 );
02973
02977 function check() {
02978 foreach($this->getAllElements('img') as $img) {
02979 if($img->hasAttribute('alt')) {
02980 if(strlen($img->getAttribute('alt')) > 0) {
02981 if(in_array($img->getAttribute('alt'), $this->translation())
02982 || ord($img->getAttribute('alt')) == 194) {
02983 $this->addReport($img);
02984 }
02985 elseif(preg_match("/^([0-9]*)(k|kb|mb|k bytes|k byte)?$/",
02986 strtolower($img->getAttribute('alt')))) {
02987 $this->addReport($img);
02988 }
02989 }
02990 }
02991 }
02992
02993 }
02994 }
02995
03001 class imgGifNoFlicker extends quailTest {
03002
03006 var $default_severity = QUAIL_TEST_SEVERE;
03007
03012 var $gif_control_extension = "/21f904[0-9a-f]{2}([0-9a-f]{4})[0-9a-f]{2}00/";
03013
03017 function check() {
03018 foreach($this->getAllElements('img') as $img) {
03019
03020 if(substr($img->getAttribute('src'), -4, 4) == '.gif') {
03021 $file = $this->getImageContent($this->getPath($img->getAttribute('src')));
03022 if($file) {
03023 $file = bin2hex($file);
03024
03025
03026 $total_delay = 0;
03027 preg_match_all($this->gif_control_extension, $file, $matches);
03028 foreach ($matches[1] as $match) {
03029
03030 $delay = hexdec(substr($match,-2) . substr($match, 0, 2));
03031 if ($delay == 0) $delay = 1;
03032 $total_delay += $delay;
03033 }
03034
03035
03036
03037
03038 if($total_delay > 0)
03039 $this->addReport($img);
03040 }
03041 }
03042 }
03043
03044 }
03045
03050 function getImageContent($image) {
03051 if(strpos($image, '://') == false) {
03052 return @file_get_contents($image);
03053 }
03054 if(function_exists('curl')) {
03055 $curl = new curl_init($image);
03056 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
03057 $result = curl_exec($curl);
03058 return $result;
03059 }
03060 return false;
03061 }
03062 }
03063
03068 class imgHasAlt extends quailTest {
03069
03073 var $default_severity = QUAIL_TEST_SEVERE;
03074
03078 function check() {
03079 foreach($this->getAllElements('img') as $img) {
03080 if(!$img->hasAttribute('alt'))
03081 $this->addReport($img);
03082 }
03083
03084 }
03085 }
03086
03092 class imgHasLongDesc extends quailTest {
03093
03097 var $default_severity = QUAIL_TEST_SEVERE;
03098
03102 function check() {
03103 foreach($this->getAllElements('img') as $img) {
03104 if($img->hasAttribute('longdesc')) {
03105 if(trim(strtolower($img->getAttribute('longdesc'))) ==
03106 trim(strtolower($img->getAttribute('alt')))) {
03107 $this->addReport($img);
03108 }
03109 }
03110 }
03111
03112 }
03113 }
03114
03120 class imgImportantNoSpacerAlt extends quailTest {
03121
03125 var $default_severity = QUAIL_TEST_SEVERE;
03126
03130 function check() {
03131 foreach($this->getAllElements('img') as $img) {
03132 if($img->hasAttribute('src') && $img->hasAttribute('alt') && trim($img->getAttribute('alt')) == '') {
03133 if($img->getAttribute('width') > 25 || $img->getAttribute('height') > 25) {
03134 $this->addReport($img);
03135 }
03136 elseif(function_exists('gd_info') && (!$img->hasAttribute('width') || !$img->hasAttribute('height'))) {
03137 $img_file = @getimagesize($this->getPath($img->getAttribute('src')));
03138 if($img_file) {
03139 if($img_file[0] > 25 || $img_file[1] > 25)
03140 $this->addReport($img);
03141 }
03142 }
03143 }
03144
03145 }
03146
03147 }
03148 }
03149
03155 class imgMapAreasHaveDuplicateLink extends quailTest {
03156
03160 var $default_severity = QUAIL_TEST_SEVERE;
03161
03165 function check() {
03166 $all_links = array();
03167 foreach($this->getAllElements('a') as $a) {
03168 $all_links[$a->getAttribute('href')] = $a->getAttribute('href');
03169 }
03170 $maps = $this->getElementsByAttribute('map', 'name', true);
03171
03172 foreach($this->getAllElements('img') as $img) {
03173 if($img->hasAttribute('usemap')) {
03174 $usemap = $img->getAttribute('usemap');
03175 if(substr($usemap, 0, 1) == '#') {
03176 $key = substr($usemap, -(strlen($usemap) - 1), (strlen($usemap) - 1));
03177 }
03178 else {
03179 $key = $usemap;
03180 }
03181 if(isset($maps[$key])) {
03182 foreach($maps[$key]->childNodes as $child) {
03183 if($this->propertyIsEqual($child, 'tagName', 'area')) {
03184 if(!isset($all_links[$child->getAttribute('href')])) {
03185 $this->addReport($img);
03186 }
03187 }
03188 }
03189 }
03190 }
03191 }
03192
03193 }
03194 }
03195
03201 class imgNeedsLongDescWDlink extends quailTest {
03202
03206 var $default_severity = QUAIL_TEST_SEVERE;
03207
03211 function check() {
03212 foreach($this->getAllElements('img') as $img) {
03213 if($img->hasAttribute('longdesc')) {
03214 $next = $this->getNextElement($img);
03215
03216 if(is_object($next) && $next->tagName != 'a') {
03217 $this->addReport($img);
03218 }
03219 else {
03220 if(((!$this->propertyIsEqual($next, 'nodeValue', '[d]', true, true)
03221 && !$this->propertyIsEqual($next, 'nodeValue', 'd', true, true)) )
03222 || $next->getAttribute('href') != $img->getAttribute('longdesc')) {
03223 $this->addReport($img);
03224 }
03225 }
03226
03227 }
03228 }
03229
03230 }
03231 }
03232
03238 class imgNonDecorativeHasAlt extends quailTest {
03239
03243 var $default_severity = QUAIL_TEST_MODERATE;
03244
03248 function check() {
03249 foreach($this->getAllElements('img') as $img) {
03250 if($img->hasAttribute('src') &&
03251 ($img->hasAttribute('alt') && html_entity_decode((trim($img->getAttribute('alt')))) == '')) {
03252 $this->addReport($img);
03253
03254 }
03255 }
03256
03257 }
03258 }
03259
03265 class imgNotReferredToByColorAlone extends quailTest {
03266
03270 var $default_severity = QUAIL_TEST_SUGGESTION;
03271
03275 function check() {
03276 foreach($this->getAllElements('img') as $img) {
03277 if($img->hasAttribute('alt'))
03278 $this->addReport($img);
03279 }
03280
03281 }
03282 }
03283
03289 class imgServerSideMapNotUsed extends quailTest {
03290
03294 var $default_severity = QUAIL_TEST_SEVERE;
03295
03299 function check() {
03300 foreach($this->getAllElements('img') as $img) {
03301 if($img->hasAttribute('ismap'))
03302 $this->addReport($img);
03303 }
03304 }
03305 }
03306
03312 class imgShouldNotHaveTitle extends quailTest {
03313
03317 var $default_severity = QUAIL_TEST_SEVERE;
03318
03322 function check() {
03323 foreach($this->getAllElements('img') as $img) {
03324 if($img->hasAttribute('title'))
03325 $this->addReport($img);
03326 }
03327
03328 }
03329 }
03330
03336 class imgWithMapHasUseMap extends quailTest {
03337
03341 var $default_severity = QUAIL_TEST_SEVERE;
03342
03346 function check() {
03347 foreach($this->getAllElements('img') as $img) {
03348 if($img->hasAttribute('ismap') && !$img->hasAttribute('usemap'))
03349 $this->addReport($img);
03350 }
03351
03352 }
03353 }
03354
03360 class imgWithMathShouldHaveMathEquivalent extends quailTest {
03361
03365 var $default_severity = QUAIL_TEST_SUGGESTION;
03366
03370 function check() {
03371 foreach($this->getAllElements('img') as $img) {
03372 if(($img->getAttribute('width') > 100
03373 || $img->getAttribute('height') > 100 )
03374 && (!$this->propertyIsEqual($img->nextSibling, 'tagName', 'math'))) {
03375 $this->addReport($img);
03376 }
03377
03378 }
03379 }
03380 }
03381
03387 class inputCheckboxHasTabIndex extends inputTabIndex {
03388
03392 var $default_severity = QUAIL_TEST_SEVERE;
03393
03397 var $tag = 'input';
03398
03402 var $type = 'checkbox';
03403 }
03404
03410 class inputCheckboxRequiresFieldset extends quailTest {
03411
03415 var $default_severity = QUAIL_TEST_SEVERE;
03416
03420 function check() {
03421 foreach($this->getAllElements('input') as $input) {
03422 if($input->getAttribute('type') == 'checkbox') {
03423 if(!$this->getParent($input, 'fieldset', 'body'))
03424 $this->addReport($input);
03425
03426 }
03427 }
03428 }
03429 }
03430
03436 class inputDoesNotUseColorAlone extends quailTest {
03437
03441 var $default_severity = QUAIL_TEST_SUGGESTION;
03442
03446 function check() {
03447 foreach($this->getAllElements('input') as $input) {
03448 if($input->getAttribute('type') != 'hidden')
03449 $this->addReport($input);
03450 }
03451 }
03452
03453 }
03454
03460 class inputElementsDontHaveAlt extends quailTest {
03461
03465 var $default_severity = QUAIL_TEST_SEVERE;
03466
03470 function check() {
03471 foreach($this->getAllElements('input') as $input) {
03472 if($input->getAttribute('type') != 'image' && $input->hasAttribute('alt'))
03473 $this->addReport($input);
03474 }
03475 }
03476 }
03477
03483 class inputFileHasTabIndex extends inputTabIndex {
03484
03488 var $default_severity = QUAIL_TEST_SEVERE;
03489
03493 var $tag = 'input';
03494
03498 var $type = 'file';
03499 }
03500
03506 class inputImageAltIdentifiesPurpose extends quailTest {
03507
03511 var $default_severity = QUAIL_TEST_SUGGESTION;
03512
03516 function check() {
03517 foreach($this->getAllElements('input') as $input) {
03518 if($input->getAttribute('type') == 'image')
03519 $this->addReport($input);
03520 }
03521 }
03522
03523 }
03524
03530 class inputImageAltIsNotFileName extends quailTest {
03531
03535 var $default_severity = QUAIL_TEST_SEVERE;
03536
03540 function check() {
03541 foreach($this->getAllElements('input') as $input) {
03542 if($input->getAttribute('type') == 'image'
03543 && strtolower($input->getAttribute('alt')) == strtolower($input->getAttribute('src')))
03544 $this->addReport($input);
03545 }
03546 }
03547
03548 }
03549
03555 class inputImageAltIsNotPlaceholder extends imgAltNotPlaceHolder {
03556
03560 var $default_severity = QUAIL_TEST_SEVERE;
03561
03565 function check() {
03566 foreach($this->getAllElements('input') as $input) {
03567 if($input->getAttribute('type') == 'image') {
03568 if(in_array($input->getAttribute('alt'), $this->translation()) || ord($input->getAttribute('alt')) == 194) {
03569 $this->addReport($input);
03570 }
03571 elseif(preg_match("/^([0-9]*)(k|kb|mb|k bytes|k byte)?$/", strtolower($input->getAttribute('alt')))) {
03572 $this->addReport($input);
03573 }
03574 }
03575 }
03576
03577 }
03578 }
03579
03585 class inputImageAltIsShort extends quailTest {
03586
03590 var $default_severity = QUAIL_TEST_SEVERE;
03591
03595 function check() {
03596 foreach($this->getAllElements('input') as $input) {
03597 if($input->getAttribute('type') == 'image' && strlen($input->getAttribute('alt')) > 100)
03598 $this->addReport($input);
03599 }
03600 }
03601
03602 }
03603
03609 class inputImageAltNotRedundant extends quailTest {
03610
03614 var $default_severity = QUAIL_TEST_SEVERE;
03615
03619 var $strings = array('en' => array('submit', 'button'),
03620 'es' => array('enviar', 'botón'),
03621 );
03622
03626 function check() {
03627 foreach($this->getAllElements('input') as $input) {
03628 if($input->getAttribute('type') == 'image') {
03629 foreach($this->translation() as $word) {
03630 if(strpos($input->getAttribute('alt'), $word) !== false)
03631 $this->addReport($input);
03632 }
03633 }
03634 }
03635 }
03636 }
03637
03643 class inputImageHasAlt extends quailTest {
03644
03648 var $default_severity = QUAIL_TEST_SEVERE;
03649
03653 function check() {
03654 foreach($this->getAllElements('input') as $input) {
03655 if($input->getAttribute('type') == 'image'
03656 && (trim($input->getAttribute('alt')) == '' || !$input->hasAttribute('alt')))
03657 $this->addReport($input);
03658 }
03659 }
03660
03661 }
03662
03668 class inputImageNotDecorative extends quailTest {
03669
03673 var $default_severity = QUAIL_TEST_SUGGESTION;
03674
03678 function check() {
03679 foreach($this->getAllElements('input') as $input) {
03680 if($input->getAttribute('type') == 'image')
03681 $this->addReport($input);
03682 }
03683 }
03684 }
03685
03691 class inputPasswordHasTabIndex extends inputTabIndex {
03692
03696 var $default_severity = QUAIL_TEST_SEVERE;
03697
03701 var $tag = 'input';
03702
03706 var $type = 'password';
03707 }
03708
03714 class inputRadioHasTabIndex extends inputTabIndex {
03715
03719 var $default_severity = QUAIL_TEST_SEVERE;
03720
03724 var $tag = 'input';
03725
03729 var $type = 'radio';
03730 }
03731
03737 class inputSubmitHasTabIndex extends inputTabIndex {
03738
03742 var $default_severity = QUAIL_TEST_SEVERE;
03743
03747 var $tag = 'input';
03748
03752 var $type = 'submit';
03753 }
03754
03760 class inputTextHasLabel extends inputHasLabel {
03761
03765 var $default_severity = QUAIL_TEST_SEVERE;
03766
03770 var $tag = 'input';
03771
03775 var $type = 'text';
03776
03780 var $no_type = false;
03781 }
03782
03788 class inputTextHasTabIndex extends inputTabIndex {
03789
03793 var $default_severity = QUAIL_TEST_SEVERE;
03794
03798 var $tag = 'input';
03799
03803 var $type = 'text';
03804 }
03805
03811 class inputTextHasValue extends quailTest {
03812
03816 var $default_severity = QUAIL_TEST_SEVERE;
03817
03818
03822 function check() {
03823 foreach($this->getAllElements('input') as $input) {
03824 if($input->getAttribute('type') == 'text' && !$input->hasAttribute('value'))
03825 $this->addReport($input);
03826
03827 }
03828
03829 }
03830 }
03831
03837 class inputTextValueNotEmpty extends quailTest {
03838
03842 var $default_severity = QUAIL_TEST_SEVERE;
03843
03847 function check() {
03848 foreach($this->getAllElements('input') as $input) {
03849 if(!$input->hasAttribute('value') || trim($input->getAttribute('value')) == '')
03850 $this->addReport($input);
03851
03852 }
03853 }
03854 }
03855
03861 class labelDoesNotContainInput extends quailTest {
03862
03866 var $default_severity = QUAIL_TEST_SEVERE;
03867
03871 function check() {
03872 foreach($this->getAllElements('label') as $label) {
03873 if($this->elementHasChild($label, 'input') || $this->elementHasChild($label, 'textarea'))
03874 $this->addReport($label);
03875 }
03876 }
03877 }
03878
03884 class labelMustBeUnique extends quailTest {
03885
03889 var $default_severity = QUAIL_TEST_SEVERE;
03890
03894 function check() {
03895 $labels = array();
03896 foreach($this->getAllElements('label') as $label) {
03897 if($label->hasAttribute('for'))
03898 $labels[$label->getAttribute('for')][] = $label;
03899 }
03900 foreach($labels as $label) {
03901 if(count($label) > 1)
03902 $this->addReport($label[1]);
03903 }
03904 }
03905 }
03906
03912 class labelMustNotBeEmpty extends quailTest {
03913
03917 var $default_severity = QUAIL_TEST_SEVERE;
03918
03922 function check() {
03923 foreach($this->getAllElements('label') as $label) {
03924 if(!$this->elementContainsReadableText($label)) {
03925 $this->addReport($label);
03926 }
03927 }
03928 }
03929 }
03930
03936 class legendDescribesListOfChoices extends quailTagTest {
03937
03941 var $default_severity = QUAIL_TEST_SUGGESTION;
03942
03946 var $tag = 'legend';
03947 }
03948
03954 class legendTextNotEmpty extends quailTest {
03955
03959 var $default_severity = QUAIL_TEST_SEVERE;
03960
03964 function check() {
03965 foreach($this->getAllElements('legend') as $legend) {
03966 if(!$legend->nodeValue || trim($legend->nodeValue) == '')
03967 $this->addReport($legend);
03968 }
03969 }
03970 }
03971
03977 class legendTextNotPlaceholder extends quailTest {
03978
03982 var $default_severity = QUAIL_TEST_SEVERE;
03983
03987 var $strings = array('en' => array(' ', ' ', 'legend'),
03988 'es' => array(' ', ' ', 'relato'),
03989 );
03990
03994 function check() {
03995 foreach($this->getAllElements('legend') as $legend) {
03996 if(in_array(trim($legend->nodeValue), $this->translation()))
03997 $this->addReport($legend);
03998 }
03999 }
04000
04001 }
04002
04003 class liDontUseImageForBullet extends quailTest {
04004
04008 var $default_severity = QUAIL_TEST_MODERATE;
04009
04013 function check() {
04014 foreach($this->getAllElements('li') as $li) {
04015 if(!$this->propertyIsEqual($li, 'nodeValue', '', true)
04016 && $this->propertyIsEqual($li->firstChild, 'tagName', 'img')) {
04017 $this->addReport($li);
04018 }
04019 }
04020
04021 }
04022 }
04023
04029 class linkUsedForAlternateContent extends quailTest {
04030
04034 var $default_severity = QUAIL_TEST_SUGGESTION;
04035
04039 function check() {
04040 $head = $this->getAllElements('head');
04041 $head = $head[0];
04042 if($head && property_exists($head, 'childNodes')) {
04043 foreach($head->childNodes as $child) {
04044 if($this->propertyIsEqual($child, 'tagName', 'link') && $child->getAttribute('rel') == 'alternate')
04045 return true;
04046 }
04047 }
04048 $this->addReport(null, null, false);
04049 }
04050 }
04051
04052
04053
04054
04060 class linkUsedToDescribeNavigation extends quailTest {
04061
04065 var $default_severity = QUAIL_TEST_SEVERE;
04066
04070 function check() {
04071 $head = $this->getAllElements('head');
04072 $head = $head[0];
04073 if($head->childNodes) {
04074 foreach($head->childNodes as $child) {
04075 if($this->propertyIsEqual($child, 'tagName', 'link') && $child->getAttribute('rel') != 'stylesheet')
04076 return true;
04077 }
04078 $this->addReport(null, null, false);
04079 }
04080 }
04081 }
04082
04088 class listNotUsedForFormatting extends quailTest {
04089
04093 var $default_severity = QUAIL_TEST_SUGGESTION;
04094
04098 function check() {
04099 foreach($this->getAllElements(array('ul', 'ol')) as $list) {
04100 $li_count = 0;
04101 foreach($list->childNodes as $child) {
04102 if($this->propertyIsEqual($child, 'tagName', 'li')) {
04103 $li_count++;
04104 }
04105 }
04106 if($li_count < 2)
04107 $this->addReport($list);
04108 }
04109
04110 }
04111 }
04112
04118 class marqueeIsNotUsed extends quailTagTest {
04119
04123 var $default_severity = QUAIL_TEST_SEVERE;
04124
04128 var $tag = 'marquee';
04129
04130 }
04131
04137 class menuNotUsedToFormatText extends quailTest {
04138
04142 var $default_severity = QUAIL_TEST_SUGGESTION;
04143
04147 function check() {
04148 foreach($this->getAllElements('menu') as $menu) {
04149 $list_items = 0;
04150 foreach($menu->childNodes as $child) {
04151 if($this->propertyIsEqual($child, 'tagName', 'li')) {
04152 $list_items++;
04153 }
04154 }
04155 if($list_items == 1)
04156 $this->addReport($menu);
04157 }
04158
04159 }
04160 }
04161
04167 class noembedHasEquivalentContent extends quailTagTest {
04168
04172 var $default_severity = QUAIL_TEST_SUGGESTION;
04173
04177 var $tag = 'noembed';
04178 }
04179
04185 class noframesSectionMustHaveTextEquivalent extends quailTest {
04186
04190 var $default_severity = QUAIL_TEST_MODERATE;
04191
04195 function check() {
04196 foreach($this->getAllElements('frameset') as $frameset) {
04197 if(!$this->elementHasChild($frameset, 'noframes'))
04198 $this->addReport($frameset);
04199 }
04200 foreach($this->getAllElements('noframes') as $noframes) {
04201 $this->addReport($noframes);
04202 }
04203 }
04204
04205 }
04206
04212 class objectContentUsableWhenDisabled extends quailTagTest {
04213
04217 var $default_severity = QUAIL_TEST_SUGGESTION;
04218
04222 var $tag = 'object';
04223 }
04224
04230 class objectDoesNotFlicker extends quailTagTest {
04231
04235 var $default_severity = QUAIL_TEST_SUGGESTION;
04236
04240 var $tag = 'object';
04241
04242 }
04243
04249 class objectDoesNotUseColorAlone extends quailTagTest {
04250
04254 var $default_severity = QUAIL_TEST_SUGGESTION;
04255
04259 var $tag = 'object';
04260 }
04261
04267 class objectInterfaceIsAccessible extends quailTagTest {
04268
04272 var $default_severity = QUAIL_TEST_SUGGESTION;
04273
04277 var $tag = 'object';
04278 }
04279
04285 class objectLinkToMultimediaHasTextTranscript extends quailTest {
04286
04290 var $default_severity = QUAIL_TEST_SUGGESTION;
04291
04295 function check() {
04296 foreach($this->getAllElements('object') as $object) {
04297 if($object->getAttribute('type') == 'video')
04298 $this->addReport($object);
04299
04300 }
04301 }
04302
04303 }
04304
04310 class objectMustContainText extends quailTest {
04311
04315 var $default_severity = QUAIL_TEST_SEVERE;
04316
04320 function check() {
04321 foreach($this->getAllElements('object') as $object) {
04322 if(!$object->nodeValue || trim($object->nodeValue) == '')
04323 $this->addReport($object);
04324
04325 }
04326 }
04327 }
04328
04334 class objectMustHaveEmbed extends quailTest {
04335
04339 var $default_severity = QUAIL_TEST_SEVERE;
04340
04344 function check() {
04345 foreach($this->getAllElements('object') as $object) {
04346 if(!$this->elementHasChild($object, 'embed'))
04347 $this->addReport($object);
04348 }
04349 }
04350 }
04351
04357 class objectMustHaveTitle extends quailTest {
04358
04362 var $default_severity = QUAIL_TEST_SEVERE;
04363
04367 function check() {
04368 foreach($this->getAllElements('object') as $object) {
04369 if(!$object->hasAttribute('title'))
04370 $this->addReport($object);
04371
04372 }
04373 }
04374
04375 }
04376
04377
04378
04379
04385 class objectMustHaveValidTitle extends quailTest {
04386
04390 var $default_severity = QUAIL_TEST_SEVERE;
04391
04395 var $strings = array('en' => array('nbsp',
04396 ' ',
04397 'object',
04398 'an object',
04399 'spacer',
04400 'image',
04401 'img',
04402 'photo',
04403 ' '),
04404 'es' => array('nbsp',
04405 ' ',
04406 'objeto',
04407 'un objeto',
04408 'espacio',
04409 'imagen',
04410 'img',
04411 'foto',
04412 ' '),
04413 );
04414
04418 function check() {
04419 foreach($this->getAllElements('object') as $object) {
04420 if($object->hasAttribute('title')) {
04421 if(trim($object->getAttribute('title')) == '')
04422 $this->addReport($object);
04423 elseif(!in_array(trim(strtolower($object->getAttribute('title'))), $this->translation()))
04424 $this->addReport($object);
04425 }
04426 }
04427 }
04428
04429 }
04430
04436 class objectProvidesMechanismToReturnToParent extends quailTagTest {
04437
04441 var $default_severity = QUAIL_TEST_SUGGESTION;
04442
04446 var $tag = 'object';
04447 }
04448
04454 class objectShouldHaveLongDescription extends quailTagTest {
04455
04459 var $default_severity = QUAIL_TEST_SUGGESTION;
04460
04464 var $tag = 'object';
04465 }
04466
04472 class objectTextUpdatesWhenObjectChanges extends quailTagTest {
04473
04477 var $default_severity = QUAIL_TEST_SUGGESTION;
04478
04482 var $tag = 'object';
04483 }
04484
04490 class objectUIMustBeAccessible extends quailTagTest {
04491
04495 var $default_severity = QUAIL_TEST_SUGGESTION;
04496
04500 var $tag = 'object';
04501 }
04502
04508 class objectWithClassIDHasNoText extends quailTest {
04509
04513 var $default_severity = QUAIL_TEST_SEVERE;
04514
04518 function check() {
04519 foreach($this->getAllElements('object') as $object) {
04520 if($object->nodeValue && $object->hasAttribute('classid'))
04521 $this->addReport($object);
04522
04523 }
04524 }
04525 }
04526
04532 class pNotUsedAsHeader extends quailTest {
04533
04537 var $default_severity = QUAIL_TEST_SEVERE;
04538
04539 var $head_tags = array('strong', 'em', 'font', 'i', 'b', 'u');
04540
04544 function check() {
04545 foreach($this->getAllElements('p') as $p) {
04546 if(($p->nodeValue == $p->firstChild->nodeValue) &&
04547 is_object($p->firstChild) &&
04548 property_exists($p->firstChild, 'tagName') &&
04549 in_array($p->firstChild->tagName, $this->head_tags)) {
04550 $this->addReport($p);
04551
04552 }
04553 else {
04554 $style = $this->css->getStyle($p);
04555 if($style['font-weight'] == 'bold') {
04556 $this->addReport($p);
04557 }
04558 }
04559 }
04560 }
04561 }
04562
04568 class passwordHasLabel extends inputHasLabel {
04569
04573 var $default_severity = QUAIL_TEST_SEVERE;
04574
04578 var $tag = 'input';
04579
04583 var $type = 'password';
04584
04588 var $no_type = false;
04589 }
04590
04596 class passwordLabelIsNearby extends quailTest {
04597
04601 var $default_severity = QUAIL_TEST_MODERATE;
04602
04606 function check() {
04607 foreach($this->getAllElements('input') as $input) {
04608 if($input->getAttribute('type') == 'password')
04609 $this->addReport($input);
04610
04611 }
04612 }
04613 }
04614
04620 class preShouldNotBeUsedForTabularLayout extends quailTest {
04621
04625 var $default_severity = QUAIL_TEST_SUGGESTION;
04626
04630 function check() {
04631 foreach($this->getAllElements('pre') as $pre) {
04632 $rows = preg_split('/[\n\r]+/', $pre->nodeValue);
04633 if(count($rows) > 1)
04634 $this->addReport($pre);
04635 }
04636
04637 }
04638 }
04639
04645 class radioHasLabel extends inputHasLabel {
04646
04650 var $default_severity = QUAIL_TEST_SEVERE;
04651
04655 var $tag = 'input';
04656
04660 var $type = 'radio';
04661
04665 var $no_type = false;
04666 }
04667
04673 class radioLabelIsNearby extends quailTest {
04674
04678 function check() {
04679 foreach($this->getAllElements('input') as $input) {
04680 if($input->getAttribute('type') == 'radio')
04681 $this->addReport($input);
04682
04683 }
04684 }
04685 }
04686
04692 class radioMarkedWithFieldgroupAndLegend extends quailTest {
04693
04697 var $default_severity = QUAIL_TEST_SEVERE;
04698
04702 function check() {
04703 $radios = array();
04704 foreach($this->getAllElements('input') as $input) {
04705 if($input->getAttribute('type') == 'radio') {
04706 $radios[$input->getAttribute('name')][] = $input;
04707 }
04708 }
04709 foreach($radios as $radio) {
04710 if(count($radio > 1)) {
04711 if(!$this->getParent($radio[0], 'fieldset', 'body'))
04712 $this->addReport($radio[0]);
04713 }
04714 }
04715 }
04716 }
04717
04727 class scriptContentAccessibleWithScriptsTurnedOff extends quailTagTest {
04728
04732 var $default_severity = QUAIL_TEST_SUGGESTION;
04733
04737 var $tag = 'script';
04738 }
04739
04745 class scriptInBodyMustHaveNoscript extends quailTest {
04746
04750 var $default_severity = QUAIL_TEST_SEVERE;
04751
04755 function check() {
04756 foreach($this->getAllElements('script') as $script) {
04757 if(!$this->propertyIsEqual($script->nextSibling, 'tagName', 'noscript')
04758 && !$this->propertyIsEqual($script->parentNode, 'tagName', 'head'))
04759 $this->addReport($script);
04760
04761 }
04762 }
04763
04764 }
04765
04771 class scriptOnclickRequiresOnKeypress extends quailTest {
04772
04776 var $default_severity = QUAIL_TEST_SEVERE;
04777
04781 var $click_value = 'onclick';
04782
04786 var $key_value = 'onkeypress';
04787
04791 function check() {
04792 foreach($this->getAllElements(array_keys(htmlElements::$html_elements)) as $element) {
04793 if(($element->hasAttribute($this->click_value)) && !$element->hasAttribute($this->key_value))
04794 $this->addReport($element);
04795 }
04796 }
04797
04798 }
04799
04805 class scriptOndblclickRequiresOnKeypress extends scriptOnclickRequiresOnKeypress {
04806
04810 var $click_value = 'ondblclick';
04811 }
04812
04818 class scriptOnmousedownRequiresOnKeypress extends scriptOnclickRequiresOnKeypress {
04819
04823 var $click_value = 'onmousedown';
04824
04828 var $key_value = 'onkeydown';
04829 }
04830
04836 class scriptOnmousemove extends quailTest {
04837
04841 var $default_severity = QUAIL_TEST_SEVERE;
04842
04846 var $click_value = 'onmousemove';
04847
04851 var $key_value = 'onkeypress';
04852
04856 function check() {
04857 foreach($this->getAllElements(array_keys(htmlElements::$html_elements)) as $element) {
04858 if(($element->hasAttribute($this->click_value)))
04859 $this->addReport($element);
04860 }
04861 }
04862
04863 }
04864
04870 class scriptOnmouseoutHasOnmouseblur extends scriptOnclickRequiresOnKeypress {
04871
04875 var $click_value = 'onmouseout';
04876
04880 var $key_value = 'onblur';
04881 }
04882
04888 class scriptOnmouseoverHasOnfocus extends scriptOnclickRequiresOnKeypress {
04889
04893 var $click_value = 'onmouseover';
04894
04898 var $key_value = 'onfocus';
04899 }
04900
04906 class scriptOnmouseupHasOnkeyup extends scriptOnclickRequiresOnKeypress {
04907
04911 var $click_value = 'onmouseup';
04912
04916 var $key_value = 'onkeyup';
04917 }
04918
04924 class scriptUIMustBeAccessible extends quailTagTest {
04925
04929 var $default_severity = QUAIL_TEST_SUGGESTION;
04930
04934 var $tag = 'script';
04935 }
04936
04942 class scriptsDoNotFlicker extends quailTagTest {
04943
04947 var $default_severity = QUAIL_TEST_SUGGESTION;
04948
04952 var $tag = 'script';
04953 }
04954
04960 class scriptsDoNotUseColorAlone extends quailTagTest {
04961
04965 var $default_severity = QUAIL_TEST_SUGGESTION;
04966
04970 var $tag = 'script';
04971 }
04972
04978 class selectDoesNotChangeContext extends quailTest {
04979
04983 var $default_severity = QUAIL_TEST_SEVERE;
04984
04988 function check() {
04989 foreach($this->getAllElements('select') as $select) {
04990 if($select->hasAttribute('onchange'))
04991 $this->addReport($select);
04992
04993 }
04994 }
04995 }
04996
05002 class selectHasAssociatedLabel extends inputHasLabel {
05003
05007 var $default_severity = QUAIL_TEST_SEVERE;
05008
05012 var $tag = 'select';
05013
05017 var $no_type = true;
05018 }
05019
05025 class selectWithOptionsHasOptgroup extends quailTest {
05026
05030 var $default_severity = QUAIL_TEST_MODERATE;
05031
05035 function check() {
05036 foreach($this->getAllElements('select') as $select) {
05037 $options = 0;
05038 foreach($select->childNodes as $child) {
05039 if($this->propertyIsEqual($child, 'tagName', 'option')) {
05040 $options++;
05041 }
05042 }
05043 if($options >= 4) {
05044 $this->addReport($select);
05045 }
05046 }
05047 }
05048 }
05049
05055 class siteMap extends quailTest {
05056
05060 var $default_severity = QUAIL_TEST_SUGGESTION;
05061
05065 var $cms = false;
05066
05070 function check() {
05071 foreach($this->getAllElements('a') as $a) {
05072 if(strtolower(trim($a->nodeValue)) == 'site map')
05073 return true;
05074 }
05075 $this->addReport(null, null, false);
05076 }
05077 }
05078
05084 class skipToContentLinkProvided extends quailTest {
05085
05089 var $cms = false;
05090
05094 var $default_severity = QUAIL_TEST_MODERATE;
05095
05099 var $strings = array('en' => array('navigation', 'skip', 'content'),
05100 'es' => array('navegación', 'saltar', 'contenido'),
05101 );
05102
05106 function check() {
05107 $first_link = $this->getAllElements('a');
05108 if(!$first_link) {
05109 $this->addReport(null, null, false);
05110 return null;
05111 }
05112 $a = $first_link[0];
05113
05114 if(substr($a->getAttribute('href'), 0, 1) == '#') {
05115
05116 $link_text = explode(' ', strtolower($a->nodeValue));
05117 if(!in_array($this->translation(), $link_text)) {
05118 $report = true;
05119 foreach($a->childNodes as $child) {
05120 if(method_exists($child, 'hasAttribute')) {
05121 if($child->hasAttribute('alt')) {
05122 $alt = explode(' ', strtolower($child->getAttribute('alt') . $child->nodeValue));
05123 foreach($this->translation() as $word) {
05124 if(in_array($word, $alt)) {
05125 $report = false;
05126 }
05127 }
05128 }
05129 }
05130 }
05131 if($report) {
05132 $this->addReport(null, null, false);
05133 }
05134 }
05135
05136 }
05137 else
05138 $this->addReport(null, null, false);
05139
05140 }
05141
05142 }
05143
05144
05150 class tabIndexFollowsLogicalOrder extends quailTest {
05151
05155 var $default_severity = QUAIL_TEST_MODERATE;
05156
05160 function check() {
05161 $index = 0;
05162 foreach($this->getAllElements(null, 'form') as $form) {
05163 if(is_numeric($form->getAttribute('tabindex'))
05164 && intval($form->getAttribute('tabindex')) != $index + 1)
05165 $this->addReport($form);
05166 $index++;
05167 }
05168 }
05169 }
05170
05176 class tableCaptionIdentifiesTable extends quailTagTest {
05177
05181 var $default_severity = QUAIL_TEST_SUGGESTION;
05182
05186 var $tag = 'caption';
05187 }
05188
05194 class tableComplexHasSummary extends quailTableTest {
05195
05199 var $default_severity = QUAIL_TEST_SEVERE;
05200
05204 function check() {
05205 foreach($this->getAllElements('table') as $table) {
05206 if(!$table->hasAttribute('summary') && $table->firstChild->tagName != 'caption') {
05207 $this->addReport($table);
05208
05209
05210 }
05211 }
05212
05213 }
05214 }
05215
05221 class tableDataShouldHaveTh extends quailTableTest {
05222
05226 var $default_severity = QUAIL_TEST_SEVERE;
05227
05231 function check() {
05232 foreach($this->getAllElements('table') as $table) {
05233 if(!$this->isData($table))
05234 $this->addReport($table);
05235
05236 }
05237
05238 }
05239
05240 }
05241
05247 class tableHeaderLabelMustBeTerse extends quailTableTest {
05248
05252 var $default_severity = QUAIL_TEST_MODERATE;
05253
05257 function check() {
05258 foreach($this->getAllElements('table') as $table) {
05259 foreach($table->childNodes as $child) {
05260 if($this->propertyIsEqual($child, 'tagName', 'tr')) {
05261 foreach($child->childNodes as $td) {
05262 if($this->propertyIsEqual($td, 'tagName', 'th')) {
05263 if(strlen($td->getAttribute('abbr')) > 20)
05264 $this->addReport($td);
05265
05266 }
05267 }
05268 }
05269 }
05270
05271 }
05272
05273 }
05274 }
05275
05280 class tableIsGrouped extends quailTest {
05281
05285 var $default_severity = QUAIL_TEST_MODERATE;
05286
05290 function check() {
05291 foreach($this->getAllElements('table') as $table) {
05292 if(!$this->elementHasChild($table, 'thead')
05293 || !$this->elementHasChild($table, 'tbody')
05294 || !$this->elementHasChild($table, 'tfoot')) {
05295 $rows = 0;
05296 foreach($table->childNodes as $child) {
05297 if($this->propertyIsEqual($child, 'tagName', 'tr'))
05298 $rows ++;
05299 }
05300 if($rows > 4)
05301 $this->addReport($table);
05302 }
05303 }
05304
05305 }
05306 }
05307
05313 class tableLayoutDataShouldNotHaveTh extends quailTableTest {
05314
05318 var $default_severity = QUAIL_TEST_SUGGESTION;
05319
05323 function check() {
05324 foreach($this->getAllElements('table') as $table) {
05325 if($this->isData($table))
05326 $this->addReport($table);
05327
05328 }
05329
05330 }
05331
05332 }
05333
05339 class tableLayoutHasNoCaption extends quailTableTest {
05340
05344 var $default_severity = QUAIL_TEST_SEVERE;
05345
05349 function check() {
05350 foreach($this->getAllElements('table') as $table) {
05351 if($this->elementHasChild($table, 'caption')) {
05352 $first_row = true;
05353 foreach($table->childNodes as $child) {
05354 if($this->propertyIsEqual($child, 'tagName', 'tr') && $first_row) {
05355 if(!$this->elementHasChild($child, 'th'))
05356 $this->addReport($table);
05357 $first_row = false;
05358 }
05359 }
05360 }
05361 }
05362
05363 }
05364 }
05365
05371 class tableLayoutHasNoSummary extends quailTableTest {
05372
05376 var $default_severity = QUAIL_TEST_SEVERE;
05377
05381 function check() {
05382 foreach($this->getAllElements('table') as $table) {
05383 if($table->hasAttribute('summary') && strlen(trim($table->getAttribute('summary'))) > 1) {
05384 $first_row = true;
05385 foreach($table->childNodes as $child) {
05386 if($this->propertyIsEqual($child, 'tagName', 'tr') && $first_row) {
05387 if(!$this->elementHasChild($child, 'th'))
05388 $this->addReport($table);
05389 $first_row = false;
05390 }
05391 }
05392 }
05393 }
05394
05395 }
05396 }
05397
05403 class tableLayoutMakesSenseLinearized extends quailTableTest {
05404
05408 var $default_severity = QUAIL_TEST_SUGGESTION;
05409
05413 function check() {
05414 foreach($this->getAllElements('table') as $table) {
05415 if(!$this->isData($table))
05416 $this->addReport($table);
05417
05418 }
05419
05420 }
05421
05422 }
05423
05429 class tableSummaryDescribesTable extends quailTest {
05430
05434 var $default_severity = QUAIL_TEST_SUGGESTION;
05435
05439 function check() {
05440 foreach($this->getAllElements('table') as $table) {
05441 if($table->hasAttribute('summary'))
05442 $this->addReport($table);
05443 }
05444 }
05445 }
05446
05452 class tableSummaryDoesNotDuplicateCaption extends quailTest {
05453
05457 var $default_severity = QUAIL_TEST_SEVERE;
05458
05462 function check() {
05463 foreach($this->getAllElements('table') as $table) {
05464 if($this->elementHasChild($table, 'caption') && $table->hasAttribute('summary')) {
05465 foreach($table->childNodes as $child) {
05466 if($this->propertyIsEqual($child, 'tagName', 'caption'))
05467 $caption = $child;
05468 }
05469 if(strtolower(trim($caption->nodeValue)) ==
05470 strtolower(trim($table->getAttribute('summary'))) )
05471 $this->addReport($table);
05472
05473 }
05474 }
05475 }
05476 }
05477
05483 class tableSummaryIsEmpty extends quailTableTest {
05484
05488 var $default_severity = QUAIL_TEST_SEVERE;
05489
05493 function check() {
05494 foreach($this->getAllElements('table') as $table) {
05495 if($table->hasAttribute('summary') && trim($table->getAttribute('summary')) == '') {
05496 $this->addReport($table);
05497
05498
05499 }
05500 }
05501
05502 }
05503 }
05504
05510 class tableSummaryIsSufficient extends quailTableTest {
05511
05515 var $default_severity = QUAIL_TEST_SUGGESTION;
05516
05520 function check() {
05521 foreach($this->getAllElements('table') as $table) {
05522 if($table->hasAttribute('summary') && strlen(trim($table->getAttribute('summary'))) < 11) {
05523 $this->addReport($table);
05524
05525
05526 }
05527 }
05528
05529 }
05530 }
05531
05536 class tableUseColGroup extends quailTableTest {
05537
05541 var $default_severity = QUAIL_TEST_SUGGESTION;
05542
05546 function check() {
05547 foreach($this->getAllElements('table') as $table) {
05548 if($this->isData($table)) {
05549 if(!$this->elementHasChild($table, 'colgroup') && !$this->elementHasChild($table, 'col'))
05550 $this->addReport($table);
05551 }
05552 }
05553
05554 }
05555 }
05556
05562 class tableUsesAbbreviationForHeader extends quailTableTest {
05563
05567 var $default_severity = QUAIL_TEST_SUGGESTION;
05568
05572 function check() {
05573 foreach($this->getAllElements('table') as $table) {
05574 foreach($table->childNodes as $child) {
05575 if($this->propertyIsEqual($child, 'tagName', 'tr')) {
05576 foreach($child->childNodes as $td) {
05577 if($this->propertyIsEqual($td, 'tagName', 'th')) {
05578 if(strlen($td->nodeValue) > 20 && !$td->hasAttribute('abbr'))
05579 $this->addReport($table);
05580
05581 }
05582 }
05583 }
05584 }
05585
05586 }
05587
05588 }
05589 }
05590
05596 class tableUsesCaption extends quailTableTest {
05597
05601 var $default_severity = QUAIL_TEST_SEVERE;
05602
05606 function check() {
05607 foreach($this->getAllElements('table') as $table) {
05608 if($table->firstChild->tagName != 'caption')
05609 $this->addReport($table);
05610
05611 }
05612
05613 }
05614 }
05615
05621 class tableWithBothHeadersUseScope extends quailTest {
05622
05626 var $default_severity = QUAIL_TEST_MODERATE;
05627
05631 function check() {
05632 foreach($this->getAllElements('table') as $table) {
05633 $fail = false;
05634 foreach($table->childNodes as $child) {
05635 if($this->propertyIsEqual($child, 'tagName', 'tr')) {
05636 if($this->propertyIsEqual($child->firstChild, 'tagName', 'td')) {
05637 if(!$child->firstChild->hasAttribute('scope'))
05638 $fail = true;
05639 }
05640 else {
05641 foreach($child->childNodes as $td) {
05642 if($td->tagName == 'th' && !$td->hasAttribute('scope'))
05643 $fail = true;
05644 }
05645 }
05646 }
05647 }
05648 if($fail)
05649 $this->addReport($table);
05650 }
05651 }
05652 }
05653
05659 class tableWithMoreHeadersUseID extends quailTableTest {
05660
05664 var $default_severity = QUAIL_TEST_MODERATE;
05665
05669 function check() {
05670 foreach($this->getAllElements('table') as $table) {
05671 if($this->isData($table)) {
05672
05673 $row = 0;
05674 $multi_headers = false;
05675 foreach($table->childNodes as $child) {
05676 if($this->propertyIsEqual($child, 'tagName', 'tr')) {
05677 $row ++;
05678 foreach($child->childNodes as $cell) {
05679 if($this->propertyIsEqual($cell, 'tagName', 'th')) {
05680 $th[] = $cell;
05681 if($row > 1)
05682 $multi_headers = true;
05683 }
05684
05685 }
05686 }
05687 }
05688 if($multi_headers) {
05689 $fail = false;
05690 foreach($th as $cell) {
05691 if(!$cell->hasAttribute('id'))
05692 $fail = true;
05693 }
05694 if($fail)
05695 $this->addReport($table);
05696 }
05697
05698 }
05699 }
05700 }
05701 }
05702
05708 class tabularDataIsInTable extends quailTest {
05709
05713 var $default_severity = QUAIL_TEST_MODERATE;
05714
05718 function check() {
05719 foreach($this->getAllElements(null, 'text') as $text) {
05720 if(strpos($text->nodeValue, "\t") !== false || $text->tagName == 'pre')
05721 $this->addReport($text);
05722 }
05723 }
05724 }
05725
05731 class textareaHasAssociatedLabel extends inputHasLabel {
05732
05736 var $default_severity = QUAIL_TEST_SEVERE;
05737
05741 var $tag = 'textarea';
05742
05746 var $no_type = true;
05747 }
05748
05754 class textareaLabelPositionedClose extends quailTagTest {
05755
05759 var $default_severity = QUAIL_TEST_MODERATE;
05760
05764 var $tag = 'textarea';
05765 }
05766
05771 class svgContainsTitle extends quailTest {
05772
05776 var $default_severity = QUAIL_TEST_SEVERE;
05777
05781 function check() {
05782 foreach($this->getAllElements('svg') as $svg) {
05783 $title = false;
05784 foreach($svg->childNodes as $child) {
05785 if($this->propertyIsEqual($child, 'tagName', 'title')) {
05786 $title = true;
05787 }
05788 }
05789 if(!$title) {
05790 $this->addReport($svg);
05791 }
05792 }
05793 }
05794 }
05795
05800 class videoProvidesCaptions extends quailTagTest {
05801
05805 var $default_severity = QUAIL_TEST_SUGGESTION;
05806
05810 var $tag = 'video';
05811 }
05812
05817 class videosEmbeddedOrLinkedNeedCaptions extends quailTest {
05818
05822 var $default_severity = QUAIL_TEST_SEVERE;
05823
05828 var $services = array(
05829 'youtube' => 'media/youtube',
05830 );
05831
05835 function check() {
05836 foreach($this->getAllElements(array('a', 'embed')) as $video) {
05837 $attr = ($video->tagName == 'a')
05838 ? 'href'
05839 : 'src';
05840
05841 if($video->hasAttribute($attr)) {
05842 foreach($this->services as $service) {
05843 if($service->captionsMissing($video->getAttribute($attr))) {
05844 $this->addReport($video);
05845 }
05846 }
05847 }
05848 }
05849 }
05850
05851 }
05852
05858 class documentIsWrittenClearly extends quailTest {
05859
05863 var $default_severity = QUAIL_TEST_MODERATE;
05864
05869 var $services = array(
05870 'readability' => 'readability/readability',
05871 );
05872
05876 function check() {
05877 $readability = $this->services['readability'];
05878 foreach($this->getAllElements(null, 'text') as $element) {
05879 $text = strip_tags($element->nodeValue);
05880 if(str_word_count($text) > 25) {
05881 if($readability->flesch_kincaid_reading_ease($text) < 60) {
05882 $this->addReport($element);
05883 }
05884 }
05885 }
05886 }
05887
05888 }
05889
05894 class headersHaveText extends quailTest {
05895
05899 var $default_severity = QUAIL_TEST_SEVERE;
05900
05904 function check() {
05905 foreach($this->getAllElements(null, 'header', true) as $header) {
05906 if(!$this->elementContainsReadableText($header)) {
05907 $this->addReport($header);
05908 }
05909 }
05910 }
05911 }
05912
05919 class labelsAreAssignedToAnInput extends quailTest {
05920
05924 var $default_severity = QUAIL_TEST_SEVERE;
05925
05929 function check() {
05930 foreach($this->getAllElements('label') as $label) {
05931 if(!$label->hasAttribute('for') || !$input = $this->dom->getElementById($label->getAttribute('for'))) {
05932 $this->addReport($label);
05933 }
05934 if(!in_array($input->tagName, array('input', 'select', 'textarea'))) {
05935 $this->addReport($label);
05936 }
05937 }
05938 }
05939 }
05940
05946 class imgAltTextNotRedundant extends quailTest {
05947
05951 var $default_severity = QUAIL_TEST_SEVERE;
05952
05956 function check() {
05957 $alt = array();
05958 foreach($this->getAllElements('img') as $img) {
05959 if($img->hasAttribute('src') && $img->hasAttribute('alt')) {
05960 if(isset($alt[strtolower(trim($img->getAttribute('alt')))]) &&
05961 $alt[strtolower(trim($img->getAttribute('alt')))] !=
05962 strtolower(trim($img->getAttribute('src')))) {
05963 $this->addReport($img);
05964 }
05965 $alt[strtolower(trim($img->getAttribute('alt')))] = strtolower(trim($img->getAttribute('src')));
05966 }
05967 }
05968 unset($alt);
05969 }
05970 }
05971
05976 class selectJumpMenus extends quailTest {
05977
05981 var $default_severity = QUAIL_TEST_MODERATE;
05982
05986 function check() {
05987 foreach($this->getAllElements('select') as $select) {
05988 $parent = $this->getParent($select, 'form', 'body');
05989 $fail = true;
05990 if($parent) {
05991 foreach($this->getAllElements('input') as $input) {
05992 if($input->hasAttribute('type') && $input->getAttribute('type') == 'submit') {
05993 $parent_input = $this->getParent($input, 'form', 'body');
05994 if($parent_input->isSameNode($parent)) {
05995 $fail = false;
05996 }
05997 }
05998 }
05999 }
06000 if($fail) {
06001 $this->addReport($select);
06002 }
06003 }
06004 }
06005 }
06006
06007
06012 class textIsNotSmall extends quailTest {
06013
06017 var $default_severity = QUAIL_TEST_MODERATE;
06018
06022 function check() {
06023 foreach($this->getAllElements(null, 'text', true) as $text) {
06024 $style = $this->css->getStyle($text);
06025 if(isset($style['font-size'])) {
06026 if(substr($style['font-size'], -2, 2) == 'px') {
06027 if(intval($style['font-size']) < 10) {
06028 $this->addReport($text);
06029 }
06030 }
06031 if(substr($style['font-size'], -2, 2) == 'em') {
06032 if(floatval($style['font-size']) < .63) {
06033 $this->addReport($text);
06034 }
06035 }
06036 }
06037 }
06038 }
06039
06040 }
06041