]> gitweb.factorcode.org Git - factor.git/commitdiff
Move HTML components to html.components, refactor
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Fri, 23 May 2008 22:33:31 +0000 (17:33 -0500)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Fri, 23 May 2008 22:33:31 +0000 (17:33 -0500)
16 files changed:
extra/html/authors.txt [deleted file]
extra/html/components/components-tests.factor [new file with mode: 0644]
extra/html/components/components.factor [new file with mode: 0644]
extra/html/elements/elements-tests.factor
extra/html/elements/elements.factor
extra/html/html-tests.factor [deleted file]
extra/html/html.factor [deleted file]
extra/html/streams/authors.txt [new file with mode: 0644]
extra/html/streams/streams-tests.factor [new file with mode: 0644]
extra/html/streams/streams.factor [new file with mode: 0755]
extra/html/streams/summary.txt [new file with mode: 0644]
extra/html/streams/tags.txt [new file with mode: 0644]
extra/html/stylesheet.css [deleted file]
extra/html/summary.txt [deleted file]
extra/html/tags.txt [deleted file]
extra/validators/validators.factor

diff --git a/extra/html/authors.txt b/extra/html/authors.txt
deleted file mode 100644 (file)
index 65da810..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Slava Pestov
-Matthew Willis
-Chris Double
diff --git a/extra/html/components/components-tests.factor b/extra/html/components/components-tests.factor
new file mode 100644 (file)
index 0000000..6ecd2b0
--- /dev/null
@@ -0,0 +1,145 @@
+IN: html.components.tests
+USING: html.components tools.test kernel io.streams.string
+io.streams.null accessors ;
+
+[ ] [ blank-values ] unit-test
+
+[ ] [ 3 "hi" set-value ] unit-test
+
+[ 3 ] [ "hi" value ] unit-test
+
+TUPLE: color red green blue ;
+
+[ ] [ 1 2 3 color boa from-tuple ] unit-test
+
+[ 1 ] [ "red" value ] unit-test
+
+[ ] [ "jimmy" "red" set-value ] unit-test
+
+[ "123.5" ] [ 123.5 object>string ] unit-test
+
+[ "jimmy" ] [
+    [
+        "red" label render
+    ] with-string-writer
+] unit-test
+
+[ ] [ "<jimmy>" "red" set-value ] unit-test
+
+[ "&lt;jimmy&gt;" ] [
+    [
+        "red" label render
+    ] with-string-writer
+] unit-test
+
+[ "<input type='hidden' name='red' value='<jimmy>'/>" ] [
+    [
+        "red" hidden render
+    ] with-string-writer
+] unit-test
+
+[ ] [ "'jimmy'" "red" set-value ] unit-test
+
+[ "<input type='text' size='5' name='red' value='&apos;jimmy&apos;'/>" ] [
+    [
+        "red" <field> 5 >>size render
+    ] with-string-writer
+] unit-test
+
+[ "<input type='password' size='5' name='red' value=''/>" ] [
+    [
+        "red" <password> 5 >>size render
+    ] with-string-writer
+] unit-test
+
+[ ] [
+    [
+        "green" <textarea> render
+    ] with-null-writer
+] unit-test
+
+[ ] [
+    [
+        "green" <textarea> 25 >>rows 30 >>columns render
+    ] with-null-writer
+] unit-test
+
+[ ] [ blank-values ] unit-test
+
+[ ] [ "new york" "city1" set-value ] unit-test
+
+[ ] [
+    [
+        "city1"
+        <choice>
+            { "new york" "los angeles" "chicago" } >>choices
+        render
+    ] with-null-writer
+] unit-test
+
+[ ] [ { "los angeles" "new york" } "city2" set-value ] unit-test
+
+[ ] [
+    [
+        "city2"
+        <choice>
+            { "new york" "los angeles" "chicago" } >>choices
+            t >>multiple
+        render
+    ] with-null-writer
+] unit-test
+
+[ ] [
+    [
+        "city2"
+        <choice>
+            { "new york" "los angeles" "chicago" } >>choices
+            t >>multiple
+            5 >>size
+        render
+    ] with-null-writer
+] unit-test
+
+[ ] [ blank-values ] unit-test
+
+[ ] [ t "delivery" set-value ] unit-test
+
+[ "<input type='checkbox' name='delivery' selected='true'>Delivery</input>" ] [
+    [
+        "delivery"
+        <checkbox>
+            "Delivery" >>label
+        render
+    ] with-string-writer
+] unit-test
+
+[ ] [ f "delivery" set-value ] unit-test
+
+[ "<input type='checkbox' name='delivery'>Delivery</input>" ] [
+    [
+        "delivery"
+        <checkbox>
+            "Delivery" >>label
+        render
+    ] with-string-writer
+] unit-test
+
+SINGLETON: link-test
+
+M: link-test link-title drop "<Link Title>" ;
+
+M: link-test link-href drop "http://www.apple.com/foo&bar" ;
+
+[ ] [ link-test "link" set-value ] unit-test
+
+[ "<a href='http://www.apple.com/foo&amp;bar'>&lt;Link Title&gt;</a>" ] [
+    [ "link" link render ] with-string-writer
+] unit-test
+
+[ ] [
+    "<html>arbitrary <b>markup</b> for the win!</html>" "html" set-value
+] unit-test
+
+[ "<html>arbitrary <b>markup</b> for the win!</html>" ] [
+    [ "html" html render ] with-string-writer
+] unit-test
diff --git a/extra/html/components/components.factor b/extra/html/components/components.factor
new file mode 100644 (file)
index 0000000..ef4def8
--- /dev/null
@@ -0,0 +1,150 @@
+! Copyright (C) 2008 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel namespaces io math.parser assocs classes
+classes.tuple words arrays sequences splitting mirrors
+hashtables combinators continuations math strings
+fry locals calendar calendar.format xml.entities validators
+html.elements ;
+IN: html.components
+
+SYMBOL: values
+
+: value values get at ;
+
+: set-value values get set-at ;
+
+: blank-values H{ } clone values set ;
+
+: from-tuple <mirror> values set ;
+
+: values-tuple values get object>> ;
+
+: object>string ( object -- string )
+    {
+        { [ dup real? ] [ number>string ] }
+        { [ dup timestamp? ] [ timestamp>string ] }
+        { [ dup string? ] [ ] }
+        { [ dup not ] [ drop "" ] }
+    } cond ;
+
+GENERIC: render* ( value name render -- )
+
+: render ( name renderer -- )
+    over validation-messages get at [
+        [ value>> ] [ message>> ] bi
+        [ -rot render* ] dip
+        render-error
+    ] [
+        [ [ value ] keep ] dip render*
+    ] if* ;
+
+<PRIVATE
+
+: render-input ( value name type -- )
+    <input =type =name object>string =value input/> ;
+
+PRIVATE>
+
+SINGLETON: label
+
+M: label render* 2drop object>string escape-string write ;
+
+SINGLETON: hidden
+
+M: hidden render* drop "hidden" render-input ;
+
+: render-field ( value name size type -- )
+    <input
+        =type
+        [ number>string =size ] when*
+        =name
+        object>string =value
+    input/> ;
+
+TUPLE: field size ;
+
+: <field> ( -- field )
+    field new ;
+
+M: field render* size>> "text" render-field ;
+
+TUPLE: password size ;
+
+: <password> ( -- password )
+    password new ;
+
+M: password render*
+    #! Don't send passwords back to the user
+    [ drop "" ] 2dip size>> "password" render-field ;
+
+! Text areas
+TUPLE: textarea rows columns ;
+
+: <textarea> ( -- renderer )
+    textarea new ;
+
+M: textarea render*
+    <textarea
+        [ rows>> [ number>string =rows ] when* ]
+        [ columns>> [ number>string =cols ] when* ] bi
+        =name
+    textarea>
+        object>string escape-string write
+    </textarea> ;
+
+! Choice
+TUPLE: choice size choices multiple ;
+
+: <choice> ( -- choice )
+    choice new ;
+
+: render-option ( text selected? -- )
+    <option [ "true" =selected ] when option>
+        escape-string write
+    </option> ;
+
+: render-options ( options selected -- )
+    '[ dup , member? render-option ] each ;
+
+M: choice render*
+    <select
+        swap =name
+        dup size>> [ number>string =size ] when*
+        dup multiple>> [ "true" =multiple ] when
+    select>
+        [ choices>> ] [ multiple>> ] bi
+        [ swap ] [ swap 1array ] if
+        render-options
+    </select> ;
+
+! Checkboxes
+TUPLE: checkbox label ;
+
+: <checkbox> ( -- checkbox )
+    checkbox new ;
+
+M: checkbox render*
+    <input
+        "checkbox" =type
+        swap =name
+        swap [ "true" =selected ] when
+    input>
+        label>> escape-string write
+    </input> ;
+
+! Link components
+GENERIC: link-title ( obj -- string )
+GENERIC: link-href ( obj -- url )
+
+SINGLETON: link
+
+M: link render*
+    2drop
+    <a dup link-href =href a>
+        link-title object>string escape-string write
+    </a> ;
+
+! HTML component
+SINGLETON: html
+
+M: html render* 2drop write ;
index aa6a017540e08707f2a44cd9b68c9584dd56f10d..1178deab3838cb5a8ee7142e0e89c929f2ec0c16 100644 (file)
@@ -1,8 +1,5 @@
 IN: html.elements.tests
-USING: tools.test html html.elements io.streams.string ;
-
-: make-html-string
-    [ with-html-stream ] with-string-writer ;
+USING: tools.test html.elements io.streams.string ;
 
 [ "<a href='h&amp;o'>" ]
-[ [ <a "h&o" =href a> ] make-html-string ] unit-test
+[ [ <a "h&o" =href a> ] with-string-writer ] unit-test
index 49782fa305e4c611e61d72543ed0a901c0b6a670..e5377cedf8f168dfbb65d22817d0f5189a29135e 100644 (file)
@@ -57,6 +57,8 @@ SYMBOL: html
 : print-html ( str -- )
     write-html "\n" write-html ;
 
+<<
+
 : html-word ( name def effect -- )
     #! Define 'word creating' word to allow
     #! dynamically creating words.
@@ -137,30 +139,46 @@ SYMBOL: html
     dup "=" prepend swap
     [ write-attr ] curry attribute-effect html-word ;
 
+! Define some closed HTML tags
+[
+    "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" "h9"
+    "ol" "li" "form" "a" "p" "html" "head" "body" "title"
+    "b" "i" "ul" "table" "tbody" "tr" "td" "th" "pre" "textarea"
+    "script" "div" "span" "select" "option" "style" "input"
+] [ define-closed-html-word ] each
+
+! Define some open HTML tags
+[
+    "input"
+    "br"
+    "link"
+    "img"
+] [ define-open-html-word ] each
+
+! Define some attributes
 [
-    ! Define some closed HTML tags
-    [
-        "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" "h9"
-        "ol" "li" "form" "a" "p" "html" "head" "body" "title"
-        "b" "i" "ul" "table" "tbody" "tr" "td" "th" "pre" "textarea"
-        "script" "div" "span" "select" "option" "style" "input"
-    ] [ define-closed-html-word ] each
-
-    ! Define some open HTML tags
-    [
-        "input"
-        "br"
-        "link"
-        "img"
-    ] [ define-open-html-word ] each
-
-    ! Define some attributes
-    [
-        "method" "action" "type" "value" "name"
-        "size" "href" "class" "border" "rows" "cols"
-        "id" "onclick" "style" "valign" "accesskey"
-        "src" "language" "colspan" "onchange" "rel"
-        "width" "selected" "onsubmit" "xmlns" "lang" "xml:lang"
-        "media" "title" "multiple"
-    ] [ define-attribute-word ] each
-] with-compilation-unit
+    "method" "action" "type" "value" "name"
+    "size" "href" "class" "border" "rows" "cols"
+    "id" "onclick" "style" "valign" "accesskey"
+    "src" "language" "colspan" "onchange" "rel"
+    "width" "selected" "onsubmit" "xmlns" "lang" "xml:lang"
+    "media" "title" "multiple"
+] [ define-attribute-word ] each
+
+>>
+
+: xhtml-preamble ( -- )
+    "<?xml version=\"1.0\"?>" write-html
+    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" write-html ;
+
+: simple-page ( title quot -- )
+    #! Call the quotation, with all output going to the
+    #! body of an html page with the given title.
+    xhtml-preamble
+    <html "http://www.w3.org/1999/xhtml" =xmlns "en" =xml:lang "en" =lang html>
+        <head> <title> swap write </title> </head>
+        <body> call </body>
+    </html> ;
+
+: render-error ( message -- )
+    <span "error" =class span> escape-string write </span> ;
diff --git a/extra/html/html-tests.factor b/extra/html/html-tests.factor
deleted file mode 100644 (file)
index 9f1ce6b..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-USING: html http io io.streams.string io.styles kernel
-namespaces tools.test xml.writer sbufs sequences html.private ;
-IN: html.tests
-
-: make-html-string
-    [ with-html-stream ] with-string-writer ; inline
-
-[ [ ] make-html-string ] must-infer
-
-[ ] [
-    512 <sbuf> <html-stream> drop
-] unit-test
-
-[ "" ] [
-    [ "" write ] make-html-string
-] unit-test
-
-[ "a" ] [
-    [ CHAR: a write1 ] make-html-string
-] unit-test
-
-[ "&lt;" ] [
-    [ "<" write ] make-html-string
-] unit-test
-
-[ "<" ] [
-    [ "<" H{ } output-stream get format-html-span ] make-html-string
-] unit-test
-
-TUPLE: funky town ;
-
-M: funky browser-link-href
-    "http://www.funky-town.com/" swap funky-town append ;
-
-[ "<a href='http://www.funky-town.com/austin'>&lt;</a>" ] [
-    [
-        "<" "austin" funky boa write-object
-    ] make-html-string
-] unit-test
-
-[ "<span style='font-family: monospace; '>car</span>" ]
-[
-    [
-        "car"
-        H{ { font "monospace" } }
-        format
-    ] make-html-string
-] unit-test
-
-[ "<span style='color: #ff00ff; '>car</span>" ]
-[
-    [
-        "car"
-        H{ { foreground { 1 0 1 1 } } }
-        format
-    ] make-html-string
-] unit-test
-
-[ "<div style='background-color: #ff00ff; white-space: pre; font-family: monospace; '>cdr</div>" ]
-[
-    [
-        H{ { page-color { 1 0 1 1 } } }
-        [ "cdr" write ] with-nesting
-    ] make-html-string
-] unit-test
-
-[
-    "<div style='white-space: pre; font-family: monospace; '></div>"
-] [
-    [ H{ } [ ] with-nesting nl ] make-html-string
-] unit-test
diff --git a/extra/html/html.factor b/extra/html/html.factor
deleted file mode 100755 (executable)
index 71862b0..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-! Copyright (C) 2004, 2006 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: generic assocs help http io io.styles io.files continuations
-io.streams.string kernel math math.order math.parser namespaces
-quotations assocs sequences strings words html.elements
-xml.entities sbufs continuations destructors ;
-IN: html
-
-GENERIC: browser-link-href ( presented -- href )
-
-M: object browser-link-href drop f ;
-
-TUPLE: html-stream last-div? ;
-
-! A hack: stream-nl after with-nesting or tabular-output is
-! ignored, so that HTML stream output looks like UI pane output
-: test-last-div? ( stream -- ? )
-    dup html-stream-last-div?
-    f rot set-html-stream-last-div? ;
-
-: not-a-div ( stream -- stream )
-    dup test-last-div? drop ; inline
-
-: a-div ( stream -- straem )
-    t over set-html-stream-last-div? ; inline
-
-: <html-stream> ( stream -- stream )
-    html-stream construct-delegate ;
-
-<PRIVATE
-
-TUPLE: html-sub-stream style stream ;
-
-: (html-sub-stream) ( style stream -- stream )
-    html-sub-stream boa
-    512 <sbuf> <html-stream> over set-delegate ;
-
-: <html-sub-stream> ( style stream class -- stream )
-    >r (html-sub-stream) r> construct-delegate ; inline
-
-: end-sub-stream ( substream -- string style stream )
-    dup delegate >string
-    over html-sub-stream-style
-    rot html-sub-stream-stream ;
-
-: delegate-write ( string -- )
-    output-stream get delegate stream-write ;
-
-: object-link-tag ( style quot -- )
-    presented pick at [
-        browser-link-href [
-            <a =href a> call </a>
-        ] [ call ] if*
-    ] [ call ] if* ; inline
-
-: hex-color, ( triplet -- )
-    3 head-slice
-    [ 255 * >fixnum >hex 2 CHAR: 0 pad-left % ] each ;
-
-: fg-css, ( color -- )
-    "color: #" % hex-color, "; " % ;
-
-: bg-css, ( color -- )
-    "background-color: #" % hex-color, "; " % ;
-
-: style-css, ( flag -- )
-    dup
-    { italic bold-italic } member?
-    "font-style: " % "italic" "normal" ? % "; " %
-    { bold bold-italic } member?
-    "font-weight: " % "bold" "normal" ? % "; " % ;
-
-: size-css, ( size -- )
-    "font-size: " % # "pt; " % ;
-
-: font-css, ( font -- )
-    "font-family: " % % "; " % ;
-
-: apply-style ( style key quot -- style gadget )
-    >r over at r> when* ; inline
-
-: make-css ( style quot -- str )
-    "" make nip ; inline
-
-: span-css-style ( style -- str )
-    [
-        foreground [ fg-css,    ] apply-style
-        background [ bg-css,    ] apply-style
-        font       [ font-css,  ] apply-style
-        font-style [ style-css, ] apply-style
-        font-size  [ size-css,  ] apply-style
-    ] make-css ;
-
-: span-tag ( style quot -- )
-    over span-css-style dup empty? [
-        drop call
-    ] [
-        <span =style span> call </span>
-    ] if ; inline
-
-: format-html-span ( string style stream -- )
-    [
-        [ [ drop delegate-write ] span-tag ] object-link-tag
-    ] with-output-stream* ;
-
-TUPLE: html-span-stream ;
-
-M: html-span-stream dispose
-    end-sub-stream not-a-div format-html-span ;
-
-: border-css, ( border -- )
-    "border: 1px solid #" % hex-color, "; " % ;
-
-: padding-css, ( padding -- ) "padding: " % # "px; " % ;
-
-: pre-css, ( margin -- )
-    [ "white-space: pre; font-family: monospace; " % ] unless ;
-
-: div-css-style ( style -- str )
-    [
-        page-color   [ bg-css,      ] apply-style
-        border-color [ border-css,  ] apply-style
-        border-width [ padding-css, ] apply-style
-        wrap-margin over at pre-css,
-    ] make-css ;
-
-: div-tag ( style quot -- )
-    swap div-css-style dup empty? [
-        drop call
-    ] [
-        <div =style div> call </div>
-    ] if ; inline
-
-: format-html-div ( string style stream -- )
-    [
-        [ [ delegate-write ] div-tag ] object-link-tag
-    ] with-output-stream* ;
-
-TUPLE: html-block-stream ;
-
-M: html-block-stream dispose ( quot style stream -- )
-    end-sub-stream a-div format-html-div ;
-
-: border-spacing-css,
-    "padding: " % first2 max 2 /i # "px; " % ;
-
-: table-style ( style -- str )
-    [
-        table-border [ border-css,         ] apply-style
-        table-gap    [ border-spacing-css, ] apply-style
-    ] make-css ;
-
-: table-attrs ( style -- )
-    table-style " border-collapse: collapse;" append =style ;
-
-: do-escaping ( string style -- string )
-    html swap at [ escape-string ] unless ;
-
-PRIVATE>
-
-! Stream protocol
-M: html-stream stream-write1 ( char stream -- )
-    >r 1string r> stream-write ;
-
-M: html-stream stream-write ( str stream -- )
-    not-a-div >r escape-string r> delegate stream-write ;
-
-M: html-stream make-span-stream ( style stream -- stream' )
-    html-span-stream <html-sub-stream> ;
-
-M: html-stream stream-format ( str style stream -- )
-    >r html over at [ >r escape-string r> ] unless r>
-    format-html-span ;
-
-M: html-stream make-block-stream ( style stream -- stream' )
-    html-block-stream <html-sub-stream> ;
-
-M: html-stream stream-write-table ( grid style stream -- )
-    a-div [
-        <table dup table-attrs table> swap [
-            <tr> [
-                <td "top" =valign swap table-style =style td>
-                    >string write-html
-                </td>
-            ] with each </tr>
-        ] with each </table>
-    ] with-output-stream* ;
-
-M: html-stream make-cell-stream ( style stream -- stream' )
-    (html-sub-stream) ;
-
-M: html-stream stream-nl ( stream -- )
-    dup test-last-div? [ drop ] [ [ <br/> ] with-output-stream* ] if ;
-
-! Utilities
-: with-html-stream ( quot -- )
-    output-stream get <html-stream> swap with-output-stream* ; inline
-
-: xhtml-preamble
-    "<?xml version=\"1.0\"?>" write-html
-    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" write-html ;
-
-: html-document ( body-quot head-quot -- )
-    #! head-quot is called to produce output to go
-    #! in the html head portion of the document.
-    #! body-quot is called to produce output to go
-    #! in the html body portion of the document.
-    xhtml-preamble
-    <html "http://www.w3.org/1999/xhtml" =xmlns "en" =xml:lang "en" =lang html>
-        <head> call </head>
-        <body> call </body>
-    </html> ;
-
-: default-css ( -- )
-    <link
-    "stylesheet" =rel "text/css" =type
-    "/responder/resources/extra/html/stylesheet.css" =href
-    link/> ;
-
-: simple-html-document ( title quot -- )
-    swap [
-        <title> write </title>
-        default-css
-    ] html-document ;
-
-: vertical-layout ( list -- )
-    #! Given a list of HTML components, arrange them vertically.
-    <table>
-    [ <tr> <td> call </td> </tr> ] each
-    </table> ;
-
-: horizontal-layout ( list -- )
-    #! Given a list of HTML components, arrange them horizontally.
-    <table>
-     <tr "top" =valign tr> [ <td> call </td> ] each </tr>
-    </table> ;
-
-: button ( label -- )
-    #! Output an HTML submit button with the given label.
-    <input "submit" =type =value input/> ;
-
-: paragraph ( str -- )
-    #! Output the string as an html paragraph
-    <p> write </p> ;
-
-: simple-page ( title quot -- )
-    #! Call the quotation, with all output going to the
-    #! body of an html page with the given title.
-    <html>
-        <head> <title> swap write </title> </head>
-        <body> call </body>
-    </html> ;
-
-: styled-page ( title stylesheet-quot quot -- )
-    #! Call the quotation, with all output going to the
-    #! body of an html page with the given title. stylesheet-quot
-    #! is called to generate the required stylesheet.
-    <html>
-        <head>
-             <title> rot write </title>
-             swap call
-        </head>
-        <body> call </body>
-    </html> ;
-
-: render-error ( message -- )
-    <span "error" =class span> escape-string write </span> ;
diff --git a/extra/html/streams/authors.txt b/extra/html/streams/authors.txt
new file mode 100644 (file)
index 0000000..65da810
--- /dev/null
@@ -0,0 +1,3 @@
+Slava Pestov
+Matthew Willis
+Chris Double
diff --git a/extra/html/streams/streams-tests.factor b/extra/html/streams/streams-tests.factor
new file mode 100644 (file)
index 0000000..2084c7d
--- /dev/null
@@ -0,0 +1,72 @@
+USING: html.streams html.streams.private
+io io.streams.string io.styles kernel
+namespaces tools.test xml.writer sbufs sequences ;
+IN: html.streams.tests
+
+: make-html-string
+    [ with-html-stream ] with-string-writer ; inline
+
+[ [ ] make-html-string ] must-infer
+
+[ ] [
+    512 <sbuf> <html-stream> drop
+] unit-test
+
+[ "" ] [
+    [ "" write ] make-html-string
+] unit-test
+
+[ "a" ] [
+    [ CHAR: a write1 ] make-html-string
+] unit-test
+
+[ "&lt;" ] [
+    [ "<" write ] make-html-string
+] unit-test
+
+[ "<" ] [
+    [ "<" H{ } output-stream get format-html-span ] make-html-string
+] unit-test
+
+TUPLE: funky town ;
+
+M: funky browser-link-href
+    "http://www.funky-town.com/" swap funky-town append ;
+
+[ "<a href='http://www.funky-town.com/austin'>&lt;</a>" ] [
+    [
+        "<" "austin" funky boa write-object
+    ] make-html-string
+] unit-test
+
+[ "<span style='font-family: monospace; '>car</span>" ]
+[
+    [
+        "car"
+        H{ { font "monospace" } }
+        format
+    ] make-html-string
+] unit-test
+
+[ "<span style='color: #ff00ff; '>car</span>" ]
+[
+    [
+        "car"
+        H{ { foreground { 1 0 1 1 } } }
+        format
+    ] make-html-string
+] unit-test
+
+[ "<div style='background-color: #ff00ff; white-space: pre; font-family: monospace; '>cdr</div>" ]
+[
+    [
+        H{ { page-color { 1 0 1 1 } } }
+        [ "cdr" write ] with-nesting
+    ] make-html-string
+] unit-test
+
+[
+    "<div style='white-space: pre; font-family: monospace; '></div>"
+] [
+    [ H{ } [ ] with-nesting nl ] make-html-string
+] unit-test
diff --git a/extra/html/streams/streams.factor b/extra/html/streams/streams.factor
new file mode 100755 (executable)
index 0000000..b35f383
--- /dev/null
@@ -0,0 +1,196 @@
+! Copyright (C) 2004, 2006 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: generic assocs help http io io.styles io.files continuations
+io.streams.string kernel math math.order math.parser namespaces
+quotations assocs sequences strings words html.elements
+xml.entities sbufs continuations destructors ;
+IN: html.streams
+
+GENERIC: browser-link-href ( presented -- href )
+
+M: object browser-link-href drop f ;
+
+TUPLE: html-stream last-div? ;
+
+! A hack: stream-nl after with-nesting or tabular-output is
+! ignored, so that HTML stream output looks like UI pane output
+: test-last-div? ( stream -- ? )
+    dup html-stream-last-div?
+    f rot set-html-stream-last-div? ;
+
+: not-a-div ( stream -- stream )
+    dup test-last-div? drop ; inline
+
+: a-div ( stream -- straem )
+    t over set-html-stream-last-div? ; inline
+
+: <html-stream> ( stream -- stream )
+    html-stream construct-delegate ;
+
+<PRIVATE
+
+TUPLE: html-sub-stream style stream ;
+
+: (html-sub-stream) ( style stream -- stream )
+    html-sub-stream boa
+    512 <sbuf> <html-stream> over set-delegate ;
+
+: <html-sub-stream> ( style stream class -- stream )
+    >r (html-sub-stream) r> construct-delegate ; inline
+
+: end-sub-stream ( substream -- string style stream )
+    dup delegate >string
+    over html-sub-stream-style
+    rot html-sub-stream-stream ;
+
+: delegate-write ( string -- )
+    output-stream get delegate stream-write ;
+
+: object-link-tag ( style quot -- )
+    presented pick at [
+        browser-link-href [
+            <a =href a> call </a>
+        ] [ call ] if*
+    ] [ call ] if* ; inline
+
+: hex-color, ( triplet -- )
+    3 head-slice
+    [ 255 * >fixnum >hex 2 CHAR: 0 pad-left % ] each ;
+
+: fg-css, ( color -- )
+    "color: #" % hex-color, "; " % ;
+
+: bg-css, ( color -- )
+    "background-color: #" % hex-color, "; " % ;
+
+: style-css, ( flag -- )
+    dup
+    { italic bold-italic } member?
+    "font-style: " % "italic" "normal" ? % "; " %
+    { bold bold-italic } member?
+    "font-weight: " % "bold" "normal" ? % "; " % ;
+
+: size-css, ( size -- )
+    "font-size: " % # "pt; " % ;
+
+: font-css, ( font -- )
+    "font-family: " % % "; " % ;
+
+: apply-style ( style key quot -- style gadget )
+    >r over at r> when* ; inline
+
+: make-css ( style quot -- str )
+    "" make nip ; inline
+
+: span-css-style ( style -- str )
+    [
+        foreground [ fg-css,    ] apply-style
+        background [ bg-css,    ] apply-style
+        font       [ font-css,  ] apply-style
+        font-style [ style-css, ] apply-style
+        font-size  [ size-css,  ] apply-style
+    ] make-css ;
+
+: span-tag ( style quot -- )
+    over span-css-style dup empty? [
+        drop call
+    ] [
+        <span =style span> call </span>
+    ] if ; inline
+
+: format-html-span ( string style stream -- )
+    [
+        [ [ drop delegate-write ] span-tag ] object-link-tag
+    ] with-output-stream* ;
+
+TUPLE: html-span-stream ;
+
+M: html-span-stream dispose
+    end-sub-stream not-a-div format-html-span ;
+
+: border-css, ( border -- )
+    "border: 1px solid #" % hex-color, "; " % ;
+
+: padding-css, ( padding -- ) "padding: " % # "px; " % ;
+
+: pre-css, ( margin -- )
+    [ "white-space: pre; font-family: monospace; " % ] unless ;
+
+: div-css-style ( style -- str )
+    [
+        page-color   [ bg-css,      ] apply-style
+        border-color [ border-css,  ] apply-style
+        border-width [ padding-css, ] apply-style
+        wrap-margin over at pre-css,
+    ] make-css ;
+
+: div-tag ( style quot -- )
+    swap div-css-style dup empty? [
+        drop call
+    ] [
+        <div =style div> call </div>
+    ] if ; inline
+
+: format-html-div ( string style stream -- )
+    [
+        [ [ delegate-write ] div-tag ] object-link-tag
+    ] with-output-stream* ;
+
+TUPLE: html-block-stream ;
+
+M: html-block-stream dispose ( quot style stream -- )
+    end-sub-stream a-div format-html-div ;
+
+: border-spacing-css,
+    "padding: " % first2 max 2 /i # "px; " % ;
+
+: table-style ( style -- str )
+    [
+        table-border [ border-css,         ] apply-style
+        table-gap    [ border-spacing-css, ] apply-style
+    ] make-css ;
+
+: table-attrs ( style -- )
+    table-style " border-collapse: collapse;" append =style ;
+
+: do-escaping ( string style -- string )
+    html swap at [ escape-string ] unless ;
+
+PRIVATE>
+
+! Stream protocol
+M: html-stream stream-write1 ( char stream -- )
+    >r 1string r> stream-write ;
+
+M: html-stream stream-write ( str stream -- )
+    not-a-div >r escape-string r> delegate stream-write ;
+
+M: html-stream make-span-stream ( style stream -- stream' )
+    html-span-stream <html-sub-stream> ;
+
+M: html-stream stream-format ( str style stream -- )
+    >r html over at [ >r escape-string r> ] unless r>
+    format-html-span ;
+
+M: html-stream make-block-stream ( style stream -- stream' )
+    html-block-stream <html-sub-stream> ;
+
+M: html-stream stream-write-table ( grid style stream -- )
+    a-div [
+        <table dup table-attrs table> swap [
+            <tr> [
+                <td "top" =valign swap table-style =style td>
+                    >string write-html
+                </td>
+            ] with each </tr>
+        ] with each </table>
+    ] with-output-stream* ;
+
+M: html-stream make-cell-stream ( style stream -- stream' )
+    (html-sub-stream) ;
+
+M: html-stream stream-nl ( stream -- )
+    dup test-last-div? [ drop ] [ [ <br/> ] with-output-stream* ] if ;
+
+: with-html-stream ( quot -- )
+    output-stream get <html-stream> swap with-output-stream* ; inline
diff --git a/extra/html/streams/summary.txt b/extra/html/streams/summary.txt
new file mode 100644 (file)
index 0000000..29ec8d3
--- /dev/null
@@ -0,0 +1 @@
+HTML reader, writer and utilities
diff --git a/extra/html/streams/tags.txt b/extra/html/streams/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/extra/html/stylesheet.css b/extra/html/stylesheet.css
deleted file mode 100644 (file)
index a1afce7..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-a:link { text-decoration: none; color: black; }
-a:visited { text-decoration: none; color: black; }
-a:active { text-decoration: none; color: black; }
-a:hover { text-decoration: underline; color: black; }
diff --git a/extra/html/summary.txt b/extra/html/summary.txt
deleted file mode 100644 (file)
index 29ec8d3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-HTML reader, writer and utilities
diff --git a/extra/html/tags.txt b/extra/html/tags.txt
deleted file mode 100644 (file)
index c077218..0000000
+++ /dev/null
@@ -1 +0,0 @@
-web
index 23bda8cb6c619a0ea99ebd890d98449478100058..9d6c4bed901da61c7d92f60940aad3491ac072bd 100644 (file)
@@ -56,6 +56,7 @@ IN: validators
 
 : v-email ( str -- str )
     #! From http://www.regular-expressions.info/email.html
+    60 v-max-length
     "e-mail"
     R' [A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'i
     v-regexp ;