############################################################ # # Module: wadg::HTMLWriter # # Created: 07.May.2000 by Jeremy Wadsack for Wadsack-Allen Digital Group # Copyright (C) 2000,2002 Wadsack-Allen. All rights reserved. # # This package is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. ############################################################ # Date Modification Author # ---------------------------------------------------------- # 2000.May.16 Limited cascade support through context JW # 2000.May.16 Moved specific output styles to subclasses JW # 2000.May.20 Added support for hash ref for -stylesheet JW ############################################################ package wadg::HTMLWriter; =head1 NAME HTMLWriter - An HTML Writing class with CSS support =head1 SYNOPSIS use wadg::HTMLWriter; $w = new HTMLWriter( -stylesheet => 'styles.css', -output => 'HTML 3.2' ); print $w->start_html; print $w->head( $w->title( 'Stylesheets for old browsers' ) ); print $w->h1( 'Stylesheets for old browsers' ); print $w->p( qq[This page was built with a style sheet, but no stylesheet is used in the output] ); print $w->end_html; =head1 DESCRIPTION A class that provides familiar, easy-to-use HTML element methods, and understands stylesheets. In particular, a stylesheet can be applied and the HTMLWriter will output using styles (for HTML 4.0 or XHTML output) or using tags for (HTML 3.2 output). =head1 METHODS Most of the methods for HTMLWriter are basic HTML elements (e.g. $w->h1), just handled differently depending on the output requirements. They closely correspond to HTML tags and are not documented here explicitly. The following methods are of special interest in HTMLWriter: =over 4 =cut use strict; BEGIN { use vars qw( $VERSION @ISA ); $VERSION = do { my @r = (q$Revision: 2.00 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker @ISA = qw(); } # end BEGIN # non-exported package globals go here use vars qw( $AUTOLOAD @EMPTY ); # List of paramters that may be empty (e.g. have no end tag). This is loaded # into the objects space at $self->{_EMPTY} so that it can be overridden in # the constructor of subclasses (e.g. $self->{_EMPTY} = qw(...)) # This one is HTML 4+ including XHTML 1.0 @EMPTY = qw( BASE META LINK HR BR PARAM IMG AREA INPUT COL FRAME ); ############################ ## The object constructor ## ############################ =item $w = new HTMLWriter( -output => 'HTML 3.2', -stylesheet => 'styles.css' ); =item $w = new HTMLWriter::HTML_3_2( -stylesheet => 'styles.css' ); Builds a new HTMLWriter object. In the first syntax style, the HTMLWriter will look for a subclass of itself that matches "::HTML_3_2", "::HTML_3" or "::HTML" and return that if found. Otherwise it will return the default HTMLWriter class. In the second format you are specifying the subclass (i.e. version) explicitly. If the subclass doesn't exist, then you will get a compile-time error. The HTMLWriter objects support the following named parameters in the constructor: -stylesheet A scalar containing a filename, stylesheet data, a handle to a stylesheet file (already open), or a reference to a hash of a hash containing stylesheet entries. Content can can also be pased through the style tag method. -output An output format specifier string. Valid strings are: 'HTML 3.2' Outputs HTML 3.2 compliant elements 'XHTML 1.0' Outputs XHTML 1.0 compliant elements using styles -file A handle to an open file, pipe, or other output stream to which write method calls will print their arguments. The HTMLWriter objects have the following public properties: output_type Corresponds to the 'word' part of the output format specifier. In the supported formats this is HTML or XHTML output_version Corresponds to the 'number' part of the output format speficier. For example, '3.2', '4.01', or '1.0' CONTEXT This is a stack representing the current HTML context. While this is mainly used internally for cascade support, it is exposed as a very simple syntax checker: after writing the output you can check $w->{CONTEXT} to see if any elements haven't been closed (like or ). Of course this will auto-close any contained elements, so if you call $w->end_html then everything else will be closed. =cut sub new { my $proto = shift; my %parms = @_; my $self = {}; bless( $self, ref $proto || $proto ); # Parse -output parameter to load subclass if possible if( defined $parms{-output} ) { # Get type and version my($out_type) = $parms{-output} =~ /^(\w+)\s+/; my($out_version) = $parms{-output} =~ /^\w+\s+([\d\.]+)/; # Remove it so we don't get an endless loop delete $parms{-output}; # Convert $out_version to package legal characters $out_version =~ s/\./_/; # Get full package name, major version package name and type package name my $full_package = "wadg::HTMLWriter::$out_type" . '_' . $out_version; my $major_package = $full_package; $major_package =~ s/_\d+$//; my $type_package = "wadg::HTMLWriter::$out_type"; # Now get the subclass for the version, if any if( $full_package->isa( 'wadg::HTMLWriter' ) ) { $self = $full_package->new( %parms ); } elsif( $major_package->isa( 'wadg::HTMLWriter' ) ) { $self = $major_package->new( %parms ); } elsif( $type_package->isa( 'wadg::HTMLWriter' ) ) { $self = $type_package->new( %parms ); } # end if # Store the version and type $self->{output_type} = $out_type; $self->{output_version} = $out_version; } # end if # Parse other named parameters foreach ( keys %parms ) { my( $k ) = /^-?([^-].*)$/; # Remove leading '-', if any if( $k eq 'stylesheet' ) { $self->_parse_stylesheet( $parms{$_} ); } else { $self->{$k} = $parms{$_}; } # end if } # end while # Setup object variables $self->{CONTEXT} = []; $self->{_EMPTY} = \@EMPTY; $self->{file} = \*STDOUT unless defined $self->{file}; return $self; } # end new ########################## ## ## ## PUBLIC METHODS ## ## ## ########################## # ---------------------------------------------------------- # Sub: AUTOLOAD # # Args: (Anything) # # Description: Called by the system for undefined methods. # This just pushes the tag (undefined method) name and the # parameters to our _auto_tag method which can be called # from other (defined) methods or from subclasses or can # be overridden in subclasses # ---------------------------------------------------------- # Date Modification Author # ---------------------------------------------------------- # 2000May16 Moved processing to _auto_tag JW # ---------------------------------------------------------- sub AUTOLOAD { my $self = shift; my $name = $AUTOLOAD; $name =~ s/.*://; return $self->_auto_tag( $name, @_ ); } # end AUTOLOAD =item doctype Outputs the !DOCTYPE header for the current output style. In the default inplementation this just outputs something like this: In subclasses (or formats) this outputs with the proper version. =cut # ---------------------------------------------------------- # Date Modification Author # ---------------------------------------------------------- # ---------------------------------------------------------- sub doctype { my $self = shift; return ''; } # end doctype =item head( \%attrs, @content ); Outputs a element set, including the content, if any. In addition, this will include a elements) and will try to load I external style sheets (in elements). It will ignore C<@import> rules and inline styles (in the STYLE attribute of an HTML element). It will also ignore any non-css style sheets. =item CGI This has not been tested under mod_perl, PerlEx or any other standard or non-standard CGI interfaces. =item Redundancy Yes, this kind of functionality is provided by things like C, C, C, etc. but not in a way that works well here. C is not an OO interface and C cannot easily be subclassed (though it could be delegated). The Cs would require the whole overhead of the parser and element tree classes and cannot be streamed, unbuffered, to the output. So this works, for our needs in the space between those libraries. Perhaps these could all be coalleced into one HTML writing / building library that works for all situations. Especially if that tool could be assocaited with DTDs and properly manage systax checking, tree building, etc. as well as providing the forward-looking, backwards-compatability rendering offered by the HTML 3.2 version of this class. :) =back =head1 VERSION 2.00 =head1 AUTHOR Jeremy Wadsack for Wadsack-Allen Digital Group (dgsupport@wadsack-allen.com) =head1 COPYRIGHT Copyright (C) 2000,2001 Wadsack-Allen. All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # so the require or use succeeds