! cont-html v0.5 ! ! Copyright (C) 2004 Chris Double. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, ! this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, ! this list of conditions and the following disclaimer in the documentation ! and/or other materials provided with the distribution. ! ! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IN: cont-html USE: strings USE: lists USE: format USE: stack USE: combinators USE: stdio USE: namespaces USE: words USE: vocabularies USE: logic ! These words in cont-html are used to provide a means of writing ! formatted HTML to standard output with a familiar 'html' look ! and feel in the code. ! ! HTML tags can be used in a number of different ways. The highest ! level involves a similar syntax to HTML: ! !

[ "someoutput" write ]

! !

will push the tag on the stack and

will call the ! quotation wrapping the output in the tag with no attributes. ! !

[ "someoutput" write ]

! ! This time the opening tag does not have the '>'. It pushes ! the tag on the stack with a boolean at the top for indicating no ! prior attribute value. The next word is assumed to be an attribute ! word. These words are the attribute name followed by '='. ! They set any previous attributes in tbe word and set in the tag ! the current attribute to be processed. ! Immediately after the attribute word should come the value ! that that attribute will be set to. ! The next attribute word or finishing word (which is the ! html word followed by '>') will actually set the attribute to ! that value in the tag. ! The remaining words are a quotation and the closing tag which ! calls the quotation and displays the attributed HTML tag around ! its output. ! ! The opening tag words push the tag onto the namespace stack ! so values for attributes can be used directly without any stack ! operations: ! ! (url -- ) ! [ "Click me" write ] ! ! (url -- ) ! [ "click" write ] ! ! (url -- ) ! a> [ "click" write ] ! ! Tags that have no 'closing' equivalent have a trailing tag/> form: ! ! : ( closed? name -- ) #! Return a object which describes the named #! HTML tag. closed? should be true false if the #! tag does not need have a closing tag printed #! (eg.
, ). 'attrs' contains a #! namespace of name/values for the attributes. [ "tag" set "closed?" set "attrs" put "last-name" f put ] extend ; : set-attr ( value name -- ) #! Set the attribute of the to the given value. [ "attrs" get [ set ] bind ] bind ; : attribute-assign ( name value -- ) #! If value is not false then set the attribute in the #! tag, otherwise do nothing (ie. just drop the false values). 2dup and [ swap pick set-attr ] [ 2drop ] ifte ; : attrs>string ( namespace -- string ) #! Convert the attrs namespace to a string #! suitable for embedding in an html tag. [ vars-values <% [ dup car % "='" % cdr % "' " % ] each %> ] bind ; : write-open-tag ( -- ) #! Write to standard output the opening HTML tag plus #! attributes if any. [ "<" write "tag" get write "attrs" get [ " " write attrs>string write ] when* ">" write ] bind ; : write-close-tag ( -- ) #! Write to standard output the closing HTML tag if #! the tag requires it. [ "closed?" get [ "" write ] when ] bind ; : write-tag ( quot -- ) #! Call the quotation, wrapping any output to standard #! output within the given HTML tag. over write-open-tag dip write-close-tag ; ! HTML tag words ! ! Each closable HTML tag has four words defined. The example below is for !

: ! !:

( -- ) ! #! Pushes the HTML tag on the stack ! t "p" ; ! !:

) ! #! Used for setting inline attributes. ! t "p" >n f ; ! !: p> ( n: last-value -- ) ! #! Used to close off inline attribute version of word. ! "last-name" get n> -rot swap attribute-assign ; ! !:

( quot -- ) ! #! Calls the quotation, wrapping the output in the tag. ! write-tag ; ! ! Each open only HTML tag has only three words: ! ! : ( -- ) ! #! Used for printing the tag with no attributes. ! f "input" [ ] write-tag ; ! ! : attr-value ) ! #! Used for setting inline attributes. ! f "input" >n f ; ! ! : input/> ( n: value or f -- ) ! #! Used to close off inline attribute version of word ! #! and print the tag/ ! "last-name" get n> -rot swap attribute-assign [ ] write-tag ; ! ! Each attribute word has the form xxxx= where 'xxxx' is the attribute ! name. The example below is for href: ! !: href= ( n: value or f -- n: ) ! "last-name" get n> -rot swap attribute-assign >n "href" "last-name" set ; : define-compound ( vocab name def -- ) #! Define 'word creating' word to allow #! dynamically creating words. >r 2dup swap create r> define ; : closed-html-word-names ( name -- ) #! Return a list of the names of the words #! used for a closable HTML tag. dup [ "<" swap ">" cat3 ] dip dup [ "<" swap cat2 ] dip dup [ ">" cat2 ] dip "" cat3 3list cons ; : closed-html-word-code ( name -- ) #! Return a list of the code for the words #! used for the closable HTML tag. dup [ ] cons t swons swap [ >n f ] cons t swons [ "last-name" get n> -rot swap attribute-assign ] [ write-tag ] 3list cons ; : 2car>pair ( list1 list2 -- cdr cdr pair ) #! Take the car of two lists and put then in a #! pair. The cdr of the two lists remain on the #! stack. >r uncons swap r> uncons -rot cons ; : 2list>alist ( list1 list2 alist -- alist ) #! Append two lists to an alist by #! taking the car of each list and #! forming it into a pair recursively. >r dup [ 2car>pair r> swap add 2list>alist ] [ drop drop r> ] ifte ; : define-closed-html-word ( name -- ) #! Given an HTML tag name, define the words for #! that closable HTML tag. dup closed-html-word-names swap closed-html-word-code [ ] 2list>alist [ uncons "cont-html" -rot define-compound ] each ; : open-html-word-names ( name -- ) #! Return a list of the names of the words #! used for a open only HTML tag. dup [ "<" swap "/>" cat3 ] dip dup [ "<" swap cat2 ] dip "/>" cat2 2list cons ; : open-html-word-code ( name -- ) #! Return a list of the code for the words #! used for the open only HTML tag. dup [ [ ] write-tag ] cons f swons swap [ >n f ] cons f swons [ "last-name" get n> -rot swap attribute-assign [ ] write-tag ] 2list cons ; : define-open-html-word ( name -- ) #! Given an HTML tag name, define the words for #! that open only HTML tag. dup open-html-word-names swap open-html-word-code [ ] 2list>alist [ uncons "cont-html" -rot define-compound ] each ; : define-attribute-word ( name -- ) #! Given an attribute name, define the word for #! that attribute. "cont-html" swap dup "=" cat2 swap [ "last-name" get n> -rot swap attribute-assign >n ] swap add [ "last-name" set ] append define-compound ; ! Define some open HTML tags [ "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" "h9" "ol" "li" "form" "a" "p" "html" "head" "body" "title" "b" "i" "ul" "table" "tr" "td" "th" "pre" "textarea" ] [ define-closed-html-word ] each ! Define some closed HTML tags [ "input" "br" ] [ define-open-html-word ] each ! Define some attributes [ "method" "action" "type" "value" "name" "size" "href" "class" "border" "rows" "cols" ] [ define-attribute-word ] each