#!/usr/bin/perl use strict; use warnings; use lib 't'; our $tests; BEGIN { ++$INC{'tests.pm'} } sub tests'VERSION { $tests += pop }; use Test::More; plan tests => $tests; use HTML::DOM; my $doc = new HTML::DOM; # -------------------------------- # use tests 17; # ElementCSSInlineStyle { (my $elem = $doc->createElement('div')) ->setAttribute('style', 'margin-top: 3px'); isa_ok($elem->style, 'CSS::DOM::Style'); is $elem->style->marginTop, '3px', 'the css dom is copied from the style attribute'; $elem->style->marginTop('4em'); is $elem->getAttribute('style'), 'margin-top: 4em', 'modifications to the css dom are reflected in the attr'; $elem->setAttribute('style', 'margin-bottom: 2px'); is $elem->style->marginBottom(), '2px', 'Subsequent changes to the attr change the dom,'; is $elem->style->marginTop, '', 'even deleting properties.'; $elem->removeAttribute('style'); like $elem->style->cssText, qr/^\s*\z/, 'removeAttribute erases the css data'; $elem->style->paddingTop('3in'); is $elem->getAttributeNode('style')->value, 'padding-top: 3in', 'getAttributeNode reads the CSS data'; my $attr = $doc->createAttribute('style'); $attr->value('padding-top: 4cm'); $elem->setAttributeNode($attr); is $elem->style->paddingTop,'4cm', 'setAttributeNode sets the CSS data'; # (Actually, it deletes it, but that’s merely an implemen- # tation detail.) $elem->removeAttributeNode($elem->getAttributeNode('style')); like $elem->style->cssText, qr/^\s*\z/, 'removeAttributeNode erases the css data'; $elem->setAttribute('style' => ''); $attr = $elem->getAttributeNode('style'); (my $style = $elem->style)->marginTop('30px'); is $attr->value, 'margin-top: 30px', 'changes to the style obj are reflected in the attr node'; is $elem->style, $style, 'without the style object getting clobbered'; $attr->value('color:red'); is $elem->style->cssText, 'color: red', 'changes to the attr node are reflected in the style obj'; $attr->firstChild->data('hand-color:red'); is $elem->style->cssText, 'hand-color: red', 'changes to the attr\'s child text node change the style obj'; $elem->removeAttribute('style'); $elem->setAttribute('style', 'color:red'); $attr = $elem->getAttributeNode('style'); $elem->style->color('blue'); is $attr->value, 'color: blue', 'style mods change the attr when attr was auto-vivved B4 style'; my $new_attr = $doc->createAttribute('style'); $new_attr->value( "foo:bar"); $elem->setAttributeNode($new_attr); is $elem->style->cssText, 'foo: bar', 'replacing the attr node clobbers the style obj'; $elem->removeAttribute('style'); $elem->setAttribute('style','color:red'); $attr = $elem->getAttributeNode('style'); $attr->style # auto-viv ->color('green'); is $attr->firstChild # auto-viv ->data, 'color: green', "an attr's text node auto-vivved after the style obj is in synch"; is $elem->getAttribute('style'), 'color: green', 'style attr nodes stringify properly'; } # -------------------------------- # use tests 10; # LinkStyle { (my $elem = $doc->createElement('style'))->appendChild( $doc->createTextNode('a { color: black}') ); isa_ok $elem->sheet, 'CSS::DOM', '<style> ->sheet'; is +($elem->sheet->cssRules)[0]->selectorText, 'a', 'contents are there'; my $doc = new HTML::DOM; my $css ; $doc->css_url_fetcher(sub{$css}); $doc->write("<link href='data:text/css,'>"); $doc->write("<link rel=stylesheet href='data:text/css,'>"); $doc->close; my @links = $doc->find('link'); is +()=$links[0]->sheet, 0, 'sheet returns null when rel != stylesheet'; is +()=$links[1]->sheet, 0, 'sheet returns null when rel == stylesheet, & cuf returns undef'; $css=''; $doc->write("<link href='data:text/css,'>"); $doc->write("<link rel=stylesheet href='data:text/css,'>"); $doc->close; @links = $doc->find('link'); is +()=$links[0]->sheet, 0, 'sheet returns null when rel != stylesheet, even w/cuf'; isa_ok $links[1]->sheet, 'CSS::DOM', '<link> ->sheet when rel == stylesheet and cuf returns defined'; $css='a{color:green}'; $links[1]->setAttribute('href', 'dware'); is $links[1]->sheet->cssRules->length, 1, 'setting the href attribute updates the sheet'; $css='a{color:green}p{text-align:center}'; $links[1]->getAttributeNode('href')->firstChild->data('cring'); is $links[1]->sheet->cssRules->length, 2, 'modifying the href attribute node updates the sheet'; my $cuf = $doc->css_url_fetcher; $css='ceck'; is &$cuf, 'ceck', 'css_url_fetcher returns the previous assigned sub'; is $doc->css_url_fetcher(sub{}), $cuf, 'css_url_fetcher returns the old value on assignment'; } # -------------------------------- # use tests 17; # DocumentStyle { use Scalar::Util 'refaddr'; my $doc = new HTML::DOM; $doc->css_url_fetcher(sub{''}); $doc->write(' <style id=stile>b { font-weight: bold }</style> <link id=foo rel=stylesheet> <link rel=bar> '); $doc->close; isa_ok my $list = $doc->styleSheets, 'CSS::DOM::StyleSheetList', 'retval of styleSheets'; is $list->length, 2, 'sheet list doesn\'t include <link rel=bar>'; is my @list = $doc->styleSheets, 2, 'styleSheets in list context'; is refaddr $list->[0], refaddr $list[0], 'both retvals have the same first item'; is refaddr $list->[1], refaddr $list[1], 'both retvals have the same second item'; is refaddr $list[0], refaddr $doc->getElementById('stile')->sheet, 'the style elem\'s sheet is in the list'; is refaddr $list[1], refaddr +(my $link = $doc->getElementById('foo'))->sheet, 'the link elem\'s sheet is in the list'; # $list should update automatically, since it is a reference to the # doc’s own style sheet list. # @list is static. $link->setAttribute(rel => "a nice big\xa0stylesheet\nhere"); is refaddr $list->[1], refaddr $list[1], 'setAttribute w/o changing whether rel contains "stylesheet"'; $link->setAttribute(rel => 'contents'); is @$list, 1, 'setAttribute(rel => contents) deletes the style sheet obj'; $link->setAttribute(rel => 'a stylesheet'); is @$list, 2, 'setAttribute adds the style sheet to the list'; SKIP: { skip 'What is the correct behaviour?' ,1; isn't refaddr $list->[1], refaddr $list[1], 'creating it from scratch'; } @list = @$list; (my $attr = $doc->createAttribute('rel'))->nodeValue('stylesheEt'); $link->setAttributeNode($attr); is refaddr $list[1], refaddr $list->[1], 'setAttributeNode w/o changing whether rel =~ "stylesheet"'; (my $attr2 = $doc->createAttribute('rel'))->nodeValue('contents'); $link->setAttributeNode($attr2); is @$list, 1, 'setAttributeNode(contents) deletes the style sheet obj'; $link->setAttributeNode($attr); is @$list, 2, 'setAttributeNode adds the style sheet to the list ...'; SKIP: { skip 'What is the correct behaviour?' ,1; isn't refaddr $list->[1], refaddr $list[1], '... creating it from scratch'; } $link->removeAttribute('rel'); is @$list, 1, 'removeAttribute removes the style sheet'; $link->setAttribute(rel => 'stylesheet'); $link->removeAttributeNode($link->getAttributeNode('rel')); is @$list, 1, 'removeAttributeNode removes the style sheet'; } # -------------------------------- # use tests 23; # ViewCSS { package TestView; require HTML'DOM'View; our @ISA = HTML::DOM::View::; sub new { bless [], shift } sub ua_style_sheet { return $_[0][0] } sub user_style_sheet { return $_[0][1] } package main; my $doc = new HTML::DOM; (my $view = new TestView) -> document ( $doc ); require CSS::DOM; VERSION CSS'DOM 0.07; $view->[0] = CSS'DOM'parse(' /* UA style sheet */ #twelve { font-size: 13px } #thirteen { font-size: 14px } #fourteen { font-size: 15px '); $view->[1] = CSS'DOM'parse(' /* User style sheet */ #twelve { font-size: 3px } #thirteen { font-size: 4px } '); $doc->write(<<'_END_'); <!-- Pilfered from http://www.w3.org/Style/CSS/Test/CSS2.1/current/html4/ t060401-c32-cascading-00-b.htm with some modifications. --> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <title>CSS Test: Cascading Order</title> <link rel="author" href="http://www.w3.org/Style/CSS/Test/CSS1/current/tsack.html" title="CSS1 Test Suite Contributors"> <link rel="author" href="censored in case someone is scraping this" title="Ian Hickson"> <link rel="stylesheet" href="support/c-red.css"> <style type="text/css"> body * { color: red; list-style: none; margin: 0; padding: 0; } span { color: red; } li span.a { color: red; } li span.b { color: red; } li span.c { color: red; } li span.d { color: red; } li span.e { color: red; } li span.f { color: red; } ul li span.a { color: green; } ul li span.b { color: green; } ul li li span.c { color: red; } ul li li span.d { color: red; } ul li li span.e { color: red; } ul li li span.f { color: red; } ul li li span.c { color: green; } li.test1 span.d { color: green; } ul li.test2 span.e { color: green; } ul li.test3 span.f { color: red; } ul li#test3 span.f { color: green; } .test4 { color: red; } .test4 { color: green; } .c { color: green; } #twelve { font-size: 5px } </style> <link rel="help" href="http://www.w3.org/TR/CSS21/cascade.html#cascading-order" title="6.4.1 Cascading order"> <link rel="help" href="http://www.w3.org/TR/CSS21/cascade.html#specificity" title="6.4.3 Calculating a selector's specificity"> </head> <body> <ul> <li> <span class="a" id=one> This should be green. </span> </li> <li> <span class="b" id=two> This should be green. </span> <ul> <li> <span class="c" id=three> This should be green. </span> </li> <li> <span class="c" id=four> This should be green. </span> </li> <li class="test1"> <span class="d" id=five> This should be green. </span> </li> </ul> </li> <li class="test2"> <span class="e" id=six> This should be green. </span> </li> <li id="test3" class="test3"> <span class="f" id=seven> This should be green. </span> </li> <li> <span class="a" id=eight> This should be green. </span> </li> </ul> <p style="color: green;" id=nine> This should be green. </p> <p class="test4" id=ten> This should be green. </p> <p class="c" id=eleven> This should be green. </p> <span id=twelve></span><span id=thirteen></span><span id=fourteen></span> </body> </html> _END_ $doc->close; #warn $view->getComputedStyle($doc->getElementById('one'))->cssText; #exit; my $green = qr/^(?:green|#0(?:0ff0|f)0|rgb\(0%?\s*,\s*(?:100%|255)\s*,\s*0%?\))\z/i; like $view->getComputedStyle($doc->getElementById($_))->color, $green, "cascade test $_ from t060401-c32-cascading-00-b.htm" for qw/ one two three four five six seven eight nine ten eleven /; is $view->getComputedStyle($doc->getElementById('twelve')) ->fontSize, '5px', 'author overrides user and ua'; is $view->getComputedStyle($doc->getElementById('thirteen')) ->fontSize, '4px', 'user overrides ua'; is $view->getComputedStyle($doc->getElementById('fourteen')) ->fontSize, '15px', 'fallback to ua'; $view->[0]=CSS'DOM'parse(' /* UA style sheet */ p { color: yellow ! important; } span { font-size: 38px !important } '); $view->[1]=CSS'DOM'parse(' /* User style sheet */ a { font-size: 14px ! important } '); $doc->write(<<'_TEMDOBEDXK>N'); <!-- Modified version of http://www.w3.org/Style/CSS/Test/CSS2.1/current/ html4/t060402-c31-important-00-b.htm --> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <title>CSS Test: important</title> <link rel="author" href="http://www.w3.org/Style/CSS/Test/CSS1/current/tsack.html" title="CSS1 Test Suite Contributors"> <link rel="author" href="mailto:ian at some server called hixie.ch" title="Ian Hickson"> <style type="text/css"> p { color: green ! important; } p { color: red; } p#id1 { color: red; } a { font-size: 1px !important } span { font-size: 23px } div { text-transform: none } div:first-line { text-transform: uppercase } </style> <link rel="help" href="http://www.w3.org/TR/CSS21/cascade.html#important-rules" title="6.4.2 !important rules"> <link rel="help" href="http://www.w3.org/TR/CSS21/cascade.html#cascading-order" title="6.4.1 Cascading order"> </head> <body> <p> This line should be green. </p> <p id="id1"> This line should be green. </p> <p style="color: red;"> This line should be green. </p> <a href=""></a><span id=s></span> <div></div> </body> </html> _TEMDOBEDXK>N $doc->close; my $ps = $doc->getElementsByTagName('p'); like $view->getComputedStyle($ps->[0])->color, $green, '!important overrides following rule with same specificiciciicty' . '(and also overrides an !important ua rule)'; like $view->getComputedStyle($ps->[1])->color, $green, '!important overrides following rule w/higher specificiciciicty'; like $view->getComputedStyle($ps->[2])->color, $green, '!important overrides style attr'; is $view->getComputedStyle($doc->links->[0])->fontSize, '14px', 'user !important overrides author !important'; is $view->getComputedStyle($doc->getElementById('s'))->fontSize, '38px', '!important ua decl overrides un!important author decl'; my $d = $doc->getElementsByTagName('div')->[0]; is $view->getComputedStyle($d)->textTransform, 'none', 'getComputedStyle without pseudo-elem'; # Opera 9.2 only supports this: is $view->getComputedStyle($d, 'first-line')->textTransform, 'uppercase', 'getComputedStyle with colonless pseudo-elem'; # FF 3 only supports these two: is $view->getComputedStyle($d, ':first-line')->textTransform, 'uppercase', 'getComputedStyle with monocolic pseudo-elem'; is $view->getComputedStyle($d, '::first-line')->textTransform, 'uppercase', 'getComputedStyle with dyocolic pseudo-elem'; # ~~~ computed values # ~~~ immutability }