From 52bb787631a910b47e72b3a4d7e5b8f9f9cb534a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 14 Dec 2007 01:16:47 -0500 Subject: [PATCH 1/4] Fix Enter key in deploy tool --- extra/ui/gadgets/editors/editors.factor | 28 ++++++++++++++------- extra/ui/tools/deploy/deploy.factor | 2 +- extra/ui/tools/interactor/interactor.factor | 5 ++-- extra/ui/tools/search/search.factor | 3 ++- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/extra/ui/gadgets/editors/editors.factor b/extra/ui/gadgets/editors/editors.factor index eb1d5daf26..2d447db1e9 100755 --- a/extra/ui/gadgets/editors/editors.factor +++ b/extra/ui/gadgets/editors/editors.factor @@ -34,14 +34,10 @@ focused? ; : field-theme ( gadget -- ) gray swap set-gadget-boundary ; -: construct-editor ( class -- tuple ) - >r { set-gadget-delegate } r> construct +: construct-editor ( object class -- tuple ) + >r { set-gadget-delegate } r> construct dup dup set-editor-self ; inline -TUPLE: source-editor ; - -: source-editor construct-editor ; - : activate-editor-model ( editor model -- ) 2dup add-connection dup activate-model @@ -340,9 +336,6 @@ M: editor gadget-text* editor-string % ; : delete-to-end-of-line T{ one-line-elt } editor-backspace ; editor "general" f { - { T{ key-down f f "RET" } insert-newline } - { T{ key-down f { S+ } "RET" } insert-newline } - { T{ key-down f f "ENTER" } insert-newline } { T{ key-down f f "DELETE" } delete-next-character } { T{ key-down f { S+ } "DELETE" } delete-next-character } { T{ key-down f f "BACKSPACE" } delete-previous-character } @@ -448,6 +441,23 @@ editor "selection" f { { T{ key-down f { S+ C+ } "END" } select-end-of-document } } define-command-map +! Multi-line editors +TUPLE: multiline-editor ; + +: ( -- editor ) + multiline-editor construct-editor ; + +multiline-editor "general" f { + { T{ key-down f f "RET" } insert-newline } + { T{ key-down f { S+ } "RET" } insert-newline } + { T{ key-down f f "ENTER" } insert-newline } +} define-command-map + +TUPLE: source-editor ; + +: ( -- editor ) + source-editor construct-editor ; + ! Fields are like editors except they edit an external model TUPLE: field model editor ; diff --git a/extra/ui/tools/deploy/deploy.factor b/extra/ui/tools/deploy/deploy.factor index e7d9161079..7b20c4591f 100755 --- a/extra/ui/tools/deploy/deploy.factor +++ b/extra/ui/tools/deploy/deploy.factor @@ -95,7 +95,7 @@ deploy-gadget "toolbar" f { { f com-help } { f com-revert } { f com-save } - { T{ key-down f f "RETURN" } com-deploy } + { T{ key-down f f "RET" } com-deploy } } define-command-map : buttons, diff --git a/extra/ui/tools/interactor/interactor.factor b/extra/ui/tools/interactor/interactor.factor index b603cc5eea..45494124c8 100755 --- a/extra/ui/tools/interactor/interactor.factor +++ b/extra/ui/tools/interactor/interactor.factor @@ -33,9 +33,8 @@ help ; : ( output -- gadget ) - { set-interactor-output set-gadget-delegate } - interactor construct - dup dup set-editor-self + interactor construct-editor + tuck set-interactor-output dup init-interactor-history dup init-caret-help ; diff --git a/extra/ui/tools/search/search.factor b/extra/ui/tools/search/search.factor index 157e8473ef..f77cf59fad 100755 --- a/extra/ui/tools/search/search.factor +++ b/extra/ui/tools/search/search.factor @@ -33,7 +33,8 @@ M: live-search handle-gesture* ( gadget gesture delegate -- ? ) TUPLE: search-field ; -: ( -- gadget ) search-field construct-editor ; +: ( -- gadget ) + search-field construct-editor ; search-field H{ { T{ key-down f f "UP" } [ find-search-list select-previous ] } From 69d056187b2d499783574fff754abfd6feeaeca0 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Tue, 18 Dec 2007 02:08:34 -0600 Subject: [PATCH 2/4] rearrange package order --- misc/factor.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/factor.sh b/misc/factor.sh index 11ea2a9cdf..12fb45a3e9 100755 --- a/misc/factor.sh +++ b/misc/factor.sh @@ -270,7 +270,7 @@ refresh_image() { } install_libraries() { - sudo apt-get install libc6-dev libfreetype6-dev wget git-core git-doc libx11-dev glutg3-dev rlwrap + sudo apt-get install libc6-dev libfreetype6-dev libx11-dev xorg-dev glutg3-dev wget git-core git-doc rlwrap } case "$1" in From 1c3c7db0bc524c41aae3542fc552dfb71f7e4c8f Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Tue, 18 Dec 2007 02:24:05 -0600 Subject: [PATCH 3/4] Overhaul furnace - validators work! - added sessions - add error checking to pastebin - add define-form, defalut-values --- extra/furnace/authors.txt | 2 + extra/furnace/furnace-tests.factor | 2 +- extra/furnace/furnace.factor | 208 ++++++++++++------ extra/furnace/sessions/sessions.factor | 31 +++ extra/http/http.factor | 19 +- extra/webapps/pastebin/annotate-paste.furnace | 24 +- extra/webapps/pastebin/modes.furnace | 4 +- extra/webapps/pastebin/new-paste.furnace | 16 +- extra/webapps/pastebin/pastebin.factor | 33 ++- extra/webapps/pastebin/style.css | 4 + 10 files changed, 245 insertions(+), 98 deletions(-) create mode 100644 extra/furnace/authors.txt create mode 100644 extra/furnace/sessions/sessions.factor diff --git a/extra/furnace/authors.txt b/extra/furnace/authors.txt new file mode 100644 index 0000000000..f372b574ae --- /dev/null +++ b/extra/furnace/authors.txt @@ -0,0 +1,2 @@ +Slava Pestov +Doug Coleman diff --git a/extra/furnace/furnace-tests.factor b/extra/furnace/furnace-tests.factor index 85fc6c8727..6a14d40cde 100644 --- a/extra/furnace/furnace-tests.factor +++ b/extra/furnace/furnace-tests.factor @@ -28,7 +28,7 @@ TUPLE: test-tuple m n ; [ H{ { "bar" "hello" } - } \ foo query>quot + } \ foo query>seq ] with-scope ] unit-test diff --git a/extra/furnace/furnace.factor b/extra/furnace/furnace.factor index 756fa13d1c..6d6ce6b4bf 100644 --- a/extra/furnace/furnace.factor +++ b/extra/furnace/furnace.factor @@ -1,48 +1,39 @@ -! Copyright (C) 2006 Slava Pestov +! Copyright (C) 2006 Slava Pestov, Doug Coleman ! See http://factorcode.org/license.txt for BSD license. -USING: kernel vectors io assocs quotations splitting strings - words sequences namespaces arrays hashtables debugger - continuations tuples classes io.files - http http.server.templating http.basic-authentication - webapps.callback html html.elements - http.server.responders furnace.validator vocabs ; +USING: arrays assocs debugger furnace.sessions furnace.validator +hashtables html.elements http http.server.responders +http.server.templating +io.files kernel namespaces quotations sequences splitting words +strings vectors webapps.callback ; +USING: continuations io prettyprint ; IN: furnace -SYMBOL: default-action +: code>quotation ( word/quot -- quot ) + dup word? [ 1quotation ] when ; +SYMBOL: default-action SYMBOL: template-path -: define-authenticated-action ( word params realm -- ) - pick swap "action-realm" set-word-prop +: render-template ( template -- ) + template-path get swap path+ + ".furnace" append resource-path + run-template-file ; + +: define-action ( word hash -- ) over t "action" set-word-prop "action-params" set-word-prop ; -: define-action ( word params -- ) - f define-authenticated-action ; +: define-form ( word1 word2 hash -- ) + dupd define-action + swap code>quotation "form-failed" set-word-prop ; -: define-redirect ( word quot -- ) - "action-redirect" set-word-prop ; +: default-values ( word hash -- ) + "default-values" set-word-prop ; -: responder-vocab ( name -- vocab ) - "webapps." swap append ; - -: lookup-action ( name webapp -- word ) - responder-vocab lookup dup [ - dup "action" word-prop [ drop f ] unless - ] when ; - -: truncate-url ( url -- action-name ) - CHAR: / over index [ head ] when* ; - -: current-action ( url -- word/f ) - dup empty? [ drop default-action get ] when - truncate-url "responder" get lookup-action ; - -PREDICATE: word action "action" word-prop ; - -: quot>query ( seq action -- hash ) - >r >array r> "action-params" word-prop - [ first swap 2array ] 2map >hashtable ; +SYMBOL: request-params +SYMBOL: current-action +SYMBOL: validators-errored +SYMBOL: validation-errors : action-link ( query action -- url ) [ @@ -52,6 +43,34 @@ PREDICATE: word action "action" word-prop ; word-name % ] "" make swap build-url ; +: action-param ( hash paramsepc -- obj error/f ) + unclip rot at swap >quotation apply-validators ; + +: query>seq ( hash word -- seq ) + "action-params" word-prop [ + dup first -rot + action-param [ + t validators-errored >session + rot validation-errors session> set-at + ] [ + nip + ] if* + ] curry* map ; + +: lookup-session ( hash -- session ) + "furnace-session-id" over at* [ + sessions get-global at + [ nip ] [ "furnace-session-id" over delete-at lookup-session ] if* + ] [ + drop new-session rot "furnace-session-id" swap set-at + ] if ; + +: quot>query ( seq action -- hash ) + >r >array r> "action-params" word-prop + [ first swap 2array ] 2map >hashtable ; + +PREDICATE: word action "action" word-prop ; + : action-call? ( quot -- ? ) >vector dup pop action? >r [ word? not ] all? r> and ; @@ -64,62 +83,94 @@ PREDICATE: word action "action" word-prop ; t register-html-callback ] if ; -: render-link ( quot name -- ) - write ; +: replace-variables ( quot -- quot ) + [ dup string? [ request-params session> at ] when ] map ; -: action-param ( params paramspec -- obj error/f ) - unclip rot at swap >quotation apply-validators ; +: furnace-session-id ( -- hash ) + "furnace-session-id" request-params session> at + "furnace-session-id" associate ; -: query>quot ( params action -- seq ) - "action-params" word-prop [ action-param drop ] curry* map ; +: redirect-to-action ( -- ) + current-action session> + "form-failed" word-prop replace-variables + quot-link furnace-session-id build-url permanent-redirect ; -SYMBOL: request-params +: if-form-page ( if then -- ) + current-action session> "form-failed" word-prop -rot if ; -: perform-redirect ( action -- ) - "action-redirect" word-prop - [ dup string? [ request-params get at ] when ] map - [ quot-link permanent-redirect ] when* ; +: do-action + current-action session> [ query>seq ] keep add >quotation call ; -: (call-action) ( params action -- ) - over request-params set - [ query>quot ] keep [ add >quotation call ] keep - perform-redirect ; +: process-form ( -- ) + H{ } clone validation-errors >session + request-params session> current-action session> query>seq + validators-errored session> [ + drop redirect-to-action + ] [ + current-action session> add >quotation call + ] if ; -: call-action ( params action -- ) - dup "action-realm" word-prop [ - [ (call-action) ] with-basic-authentication - ] [ (call-action) ] if* ; +: page-submitted ( -- ) + [ process-form ] [ request-params session> do-action ] if-form-page ; -: service-request ( params url -- ) - current-action [ +: action-first-time ( -- ) + request-params session> current-action session> + [ "default-values" word-prop swap union request-params >session ] keep + request-params session> do-action ; + +: page-not-submitted ( -- ) + [ redirect-to-action ] [ action-first-time ] if-form-page ; + +: setup-call-action ( hash word -- ) + over lookup-session session set + current-action >session + request-params session> swap union + request-params >session + f validators-errored >session ; + +: call-action ( hash word -- ) + setup-call-action + "furnace-form-submitted" request-params session> at + [ page-submitted ] [ page-not-submitted ] if ; + +: responder-vocab ( str -- newstr ) + "webapps." swap append ; + +: lookup-action ( str webapp -- word ) + responder-vocab lookup dup [ + dup "action" word-prop [ drop f ] unless + ] when ; + +: truncate-url ( str -- newstr ) + CHAR: / over index [ head ] when* ; + +: parse-action ( str -- word/f ) + dup empty? [ drop default-action get ] when + truncate-url "responder" get lookup-action ; + +: service-request ( hash str -- ) + parse-action [ [ call-action ] [
 print-error 
] recover ] [ "404 no such action: " "argument" get append httpd-error ] if* ; -: service-get ( url -- ) "query" get swap service-request ; +: service-get + "query" get swap service-request ; -: service-post ( url -- ) "response" get swap service-request ; +: service-post + "response" get swap service-request ; -: send-resource ( name -- ) - template-path get swap path+ resource-path - stdio get stream-copy ; - -: render-template ( template -- ) - template-path get swap path+ - ".furnace" append resource-path - run-template-file ; - -: web-app ( name default path -- ) +: web-app ( name defaul path -- ) [ template-path set default-action set "responder" set [ service-get ] "get" set [ service-post ] "post" set - ! [ service-head ] "head" set ] make-responder ; +USING: classes html tuples vocabs ; : explode-tuple ( tuple -- ) dup tuple-slots swap class "slot-names" word-prop [ set ] 2each ; @@ -138,3 +189,24 @@ SYMBOL: model vocab-link browser-link-href =href a> "Browse source" write ; + +: send-resource ( name -- ) + template-path get swap path+ resource-path + stdio get stream-copy ; + +: render-link ( quot name -- ) + write ; + +: session-var ( str -- newstr ) + request-params session> at ; + +: render ( str -- ) + request-params session> at [ write ] when* ; + +: render-error ( str error-str -- ) + swap validation-errors session> at validation-error? [ + write + ] [ + drop + ] if ; + diff --git a/extra/furnace/sessions/sessions.factor b/extra/furnace/sessions/sessions.factor new file mode 100644 index 0000000000..d253ae165b --- /dev/null +++ b/extra/furnace/sessions/sessions.factor @@ -0,0 +1,31 @@ +USING: assocs calendar init kernel math.parser namespaces random ; +IN: furnace.sessions + +SYMBOL: sessions + +[ H{ } clone sessions set-global ] "furnace.sessions" add-init-hook + +: new-session-id ( -- str ) + 1 big-random number>string ; + +TUPLE: session created last-seen user-agent namespace ; + +: ( -- obj ) + now dup H{ } clone + [ set-session-created set-session-last-seen set-session-namespace ] + \ session construct ; + +: new-session ( -- obj id ) + new-session-id [ sessions get-global set-at ] 2keep ; + +: get-session ( id -- obj/f ) + sessions get-global at* [ "no session found 1" throw ] unless ; + +: destroy-session ( id -- ) + sessions get-global delete-at ; + +: session> ( str -- obj ) + session get session-namespace at ; + +: >session ( value key -- ) + session get session-namespace set-at ; diff --git a/extra/http/http.factor b/extra/http/http.factor index f6ea3d699f..6ecb3c5a71 100644 --- a/extra/http/http.factor +++ b/extra/http/http.factor @@ -60,11 +60,18 @@ IN: http : url-decode ( str -- str ) [ 0 swap url-decode-iter ] "" make ; -: build-url ( path query-params -- str ) +: hash>query ( hash -- str ) + [ [ url-encode ] 2apply "=" swap 3append ] { } assoc>map + "&" join ; + +: build-url ( str query-params -- newstr ) [ - swap % dup assoc-empty? [ - "?" % dup - [ [ url-encode ] 2apply "=" swap 3append ] { } assoc>map - "&" join % - ] unless drop + over % + dup assoc-empty? [ + 2drop + ] [ + CHAR: ? rot member? "&" "?" ? % + hash>query % + ] if ] "" make ; + diff --git a/extra/webapps/pastebin/annotate-paste.furnace b/extra/webapps/pastebin/annotate-paste.furnace index abb5cc3d07..14a424f776 100755 --- a/extra/webapps/pastebin/annotate-paste.furnace +++ b/extra/webapps/pastebin/annotate-paste.furnace @@ -6,16 +6,16 @@ -string write %>" /> - - + + - + + @@ -23,11 +23,25 @@ + + + + + + + - +
Summary:" /><% "summary" "*Required" render-error %>
Your name:" /><% "author" "*Required" render-error %>
<% "modes" render-template %>
<% "contents" "*Required" render-error %>
Content:
+string write %>" /> + diff --git a/extra/webapps/pastebin/modes.furnace b/extra/webapps/pastebin/modes.furnace index 960b7d4e27..18bbec180a 100644 --- a/extra/webapps/pastebin/modes.furnace +++ b/extra/webapps/pastebin/modes.furnace @@ -1,7 +1,7 @@ -<% USING: xmode.catalog sequences kernel html.elements assocs io sorting ; %> +<% USING: furnace xmode.catalog sequences kernel html.elements assocs io sorting continuations ; %> diff --git a/extra/webapps/pastebin/new-paste.furnace b/extra/webapps/pastebin/new-paste.furnace index 8f48f670d3..b21e19734d 100755 --- a/extra/webapps/pastebin/new-paste.furnace +++ b/extra/webapps/pastebin/new-paste.furnace @@ -1,4 +1,4 @@ -<% USING: furnace namespaces ; %> +<% USING: continuations furnace namespaces ; %> <% "New paste" "title" set @@ -11,12 +11,14 @@ Summary: - +" /> +<% "summary" "*Required" render-error %> Your name: - +" /> +<% "author" "*Required" render-error %> @@ -31,12 +33,18 @@ --> + + +<% "contents" "*Required" render-error %> + + Content: - + + diff --git a/extra/webapps/pastebin/pastebin.factor b/extra/webapps/pastebin/pastebin.factor index 8e4c0a5be9..13d6846aa3 100755 --- a/extra/webapps/pastebin/pastebin.factor +++ b/extra/webapps/pastebin/pastebin.factor @@ -84,28 +84,37 @@ C: annotation store save-store ] keep paste-link permanent-redirect ; +\ new-paste \ submit-paste { - { "summary" "- no summary -" v-default } - { "author" "- no author -" v-default } - { "channel" "#concatenative" v-default } - { "mode" "factor" v-default } + { "summary" v-required } + { "author" v-required } + { "channel" } + { "mode" v-required } { "contents" v-required } -} define-action +} define-form + +\ new-paste { + { "channel" "#concatenative" } + { "mode" "factor" } +} default-values : annotate-paste ( n summary author mode contents -- ) swap get-paste - paste-annotations push - store save-store ; + [ paste-annotations push store save-store ] keep + paste-link permanent-redirect ; +[ "n" show-paste ] \ annotate-paste { { "n" v-required v-number } - { "summary" "- no summary -" v-default } - { "author" "- no author -" v-default } - { "mode" "factor" v-default } + { "summary" v-required } + { "author" v-required } + { "mode" v-required } { "contents" v-required } -} define-action +} define-form -\ annotate-paste [ "n" show-paste ] define-redirect +\ show-paste { + { "mode" "factor" } +} default-values : style.css ( -- ) "text/css" serving-content diff --git a/extra/webapps/pastebin/style.css b/extra/webapps/pastebin/style.css index e3c7c19fc5..4a469f92cb 100644 --- a/extra/webapps/pastebin/style.css +++ b/extra/webapps/pastebin/style.css @@ -35,3 +35,7 @@ pre.code { border: 1px solid #C1DAD7; padding: 10px; } + +.error { + color: red; +} From 2447a20ad55c00fa1646be029309f45f70b44073 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Tue, 18 Dec 2007 02:24:41 -0600 Subject: [PATCH 4/4] Update help webapp to work with the overhauled furnace --- extra/webapps/help/help.factor | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/extra/webapps/help/help.factor b/extra/webapps/help/help.factor index 145df4119a..28d73607ba 100644 --- a/extra/webapps/help/help.factor +++ b/extra/webapps/help/help.factor @@ -6,18 +6,19 @@ USING: kernel furnace furnace.validator http.server.responders arrays io.files ; IN: webapps.help +! : string>topic ( string -- topic ) + ! " " split dup length 1 = [ first ] when ; + : show-help ( topic -- ) serving-html dup article-title [ [ help ] with-html-stream ] simple-html-document ; -: string>topic ( string -- topic ) - " " split dup length 1 = [ first ] when ; - \ show-help { - { "topic" "handbook" v-default string>topic } + { "topic" } } define-action +\ show-help { { "topic" "handbook" } } default-values M: link browser-link-href link-name @@ -32,9 +33,10 @@ M: link browser-link-href lookup show-help ; \ show-word { - { "word" "call" v-default } - { "vocab" "kernel" v-default } + { "word" } + { "vocab" } } define-action +\ show-word { { "word" "call" } { "vocab" "kernel" } } default-values M: f browser-link-href drop \ f browser-link-href ; @@ -47,9 +49,11 @@ M: word browser-link-href f >vocab-link show-help ; \ show-vocab { - { "vocab" "kernel" v-default } + { "vocab" } } define-action +\ show-vocab { { "vocab" "kernel" } } default-values + M: vocab-spec browser-link-href vocab-name [ show-vocab ] curry quot-link ;