[Jifty-commit] r2924 - in jifty/trunk: . examples/Chat/etc examples/HelloKitty examples/HelloKitty/bin examples/HelloKitty/doc examples/HelloKitty/lib examples/HelloKitty/lib/HelloKitty examples/HelloKitty/lib/HelloKitty/Action examples/HelloKitty/lib/HelloKitty/Model examples/HelloKitty/log examples/HelloKitty/share examples/HelloKitty/share/po examples/HelloKitty/share/web examples/HelloKitty/share/web/static examples/HelloKitty/share/web/templates examples/HelloKitty/t examples/HelloKitty/var examples/HelloKitty/var/mason lib lib/Jifty lib/Jifty/Action lib/Jifty/Action/Record lib/Jifty/Plugin lib/Jifty/Plugin/AdminUI lib/Jifty/Plugin/Authentication lib/Jifty/Plugin/Authentication/Password lib/Jifty/Plugin/Authentication/Password/Action lib/Jifty/Plugin/Authentication/Password/Model lib/Jifty/Plugin/CompressedCSSandJS lib/Jifty/Plugin/ErrorTemplates lib/Jifty/Plugin/Halo lib/Jifty/Plugin/OnlineDocs lib/Jifty/Plugin/SkeletonApp lib/Jifty/Plugin/User lib/Jifty/Plugin/User/Model lib/Jifty/Plugin/Yullio lib/Jifty/View lib/Jifty/View/Declare lib/Jifty/Web lib/Jifty/Web/Form lib/Jifty/Web/Form/Field share/plugins share/plugins/Jifty share/plugins/Jifty/Plugin share/plugins/Jifty/Plugin/AdminUI share/plugins/Jifty/Plugin/AdminUI/web share/plugins/Jifty/Plugin/AdminUI/web/templates share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/_elements share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/action share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/model share/plugins/Jifty/Plugin/OnlineDocs share/plugins/Jifty/Plugin/OnlineDocs/web share/plugins/Jifty/Plugin/OnlineDocs/web/templates share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs share/web share/web/templates/__jifty/admin share/web/templates/__jifty/css share/web/templates/__jifty/js share/web/templates/__jifty/online_docs t/TestApp-Plugin-PasswordAuth t/TestApp-Plugin-PasswordAuth/bin t/TestApp-Plugin-PasswordAuth/doc t/TestApp-Plugin-PasswordAuth/etc t/TestApp-Plugin-PasswordAuth/lib t/TestApp-Plugin-PasswordAuth/lib/TestApp t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Action t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Model t/TestApp-Plugin-PasswordAuth/log t/TestApp-Plugin-PasswordAuth/share t/TestApp-Plugin-PasswordAuth/share/po t/TestApp-Plugin-PasswordAuth/share/web t/TestApp-Plugin-PasswordAuth/share/web/static t/TestApp-Plugin-PasswordAuth/share/web/templates t/TestApp-Plugin-PasswordAuth/t t/TestApp-Plugin-PasswordAuth/var t/TestApp-Plugin-PasswordAuth/var/mason t/TestApp-Plugin-PasswordAuth/var/mason/cache t/TestApp-Plugin-PasswordAuth/var/mason/obj t/TestApp/lib/TestApp t/TestApp/t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Thu Mar 8 17:07:08 EST 2007


Author: jesse
Date: Thu Mar  8 17:06:55 2007
New Revision: 2924

Added:
   jifty/trunk/examples/HelloKitty/
   jifty/trunk/examples/HelloKitty/Makefile.PL
   jifty/trunk/examples/HelloKitty/bin/
   jifty/trunk/examples/HelloKitty/bin/jifty   (contents, props changed)
   jifty/trunk/examples/HelloKitty/doc/
   jifty/trunk/examples/HelloKitty/etc/
   jifty/trunk/examples/HelloKitty/etc/config.yml
   jifty/trunk/examples/HelloKitty/hellokitty   (contents, props changed)
   jifty/trunk/examples/HelloKitty/lib/
   jifty/trunk/examples/HelloKitty/lib/HelloKitty/
   jifty/trunk/examples/HelloKitty/lib/HelloKitty/Action/
   jifty/trunk/examples/HelloKitty/lib/HelloKitty/Model/
   jifty/trunk/examples/HelloKitty/lib/HelloKitty/View.pm
   jifty/trunk/examples/HelloKitty/log/
   jifty/trunk/examples/HelloKitty/share/
   jifty/trunk/examples/HelloKitty/share/po/
   jifty/trunk/examples/HelloKitty/share/web/
   jifty/trunk/examples/HelloKitty/share/web/static/
   jifty/trunk/examples/HelloKitty/share/web/templates/
   jifty/trunk/examples/HelloKitty/t/
   jifty/trunk/examples/HelloKitty/var/
   jifty/trunk/examples/HelloKitty/var/jifty-server.pid
   jifty/trunk/examples/HelloKitty/var/mason/
   jifty/trunk/lib/Jifty/Plugin/AdminUI/
   jifty/trunk/lib/Jifty/Plugin/AdminUI.pm
   jifty/trunk/lib/Jifty/Plugin/AdminUI/View-not-yet.pm
   jifty/trunk/lib/Jifty/Plugin/Authentication/
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password/
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password.pm
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm   (contents, props changed)
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/Login.pm   (contents, props changed)
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Model/
   jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Model/User.pm
   jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS/
   jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS.pm
   jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm
   jifty/trunk/lib/Jifty/Plugin/ErrorTemplates/
   jifty/trunk/lib/Jifty/Plugin/ErrorTemplates.pm
   jifty/trunk/lib/Jifty/Plugin/ErrorTemplates/View.pm
   jifty/trunk/lib/Jifty/Plugin/Halo/
   jifty/trunk/lib/Jifty/Plugin/Halo.pm
   jifty/trunk/lib/Jifty/Plugin/OnlineDocs/
   jifty/trunk/lib/Jifty/Plugin/OnlineDocs.pm
   jifty/trunk/lib/Jifty/Plugin/SkeletonApp/
   jifty/trunk/lib/Jifty/Plugin/SkeletonApp.pm
   jifty/trunk/lib/Jifty/Plugin/SkeletonApp/Dispatcher.pm
   jifty/trunk/lib/Jifty/Plugin/SkeletonApp/View.pm
   jifty/trunk/lib/Jifty/Plugin/User/
   jifty/trunk/lib/Jifty/Plugin/User.pm
   jifty/trunk/lib/Jifty/Plugin/User/Model/
   jifty/trunk/lib/Jifty/Plugin/User/Model/User.pm
   jifty/trunk/lib/Jifty/Plugin/Yullio/
   jifty/trunk/lib/Jifty/Plugin/Yullio/View.pm
   jifty/trunk/lib/Jifty/View/Declare/
   jifty/trunk/lib/Jifty/View/Declare.pm
   jifty/trunk/lib/Jifty/View/Declare/BaseClass.pm
   jifty/trunk/lib/Jifty/View/Declare/CoreTemplates.pm
   jifty/trunk/lib/Jifty/View/Declare/Handler.pm
   jifty/trunk/lib/Jifty/View/Declare/Helpers.pm
   jifty/trunk/share/plugins/
   jifty/trunk/share/plugins/Jifty/
   jifty/trunk/share/plugins/Jifty/Plugin/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/_elements/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/_elements/nav   (contents, props changed)
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/action/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/action/dhandler
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/autohandler
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/header
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/list
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/new_item
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/search
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/update
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/view
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/index.html
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/model/
   jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/model/dhandler
   jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/
   jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/
   jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/templates/
   jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/
   jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/
      - copied from r2918, /jifty/trunk/share/web/templates/__jifty/online_docs/
   jifty/trunk/share/web/transform_templates
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/Makefile.PL
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/bin/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/bin/jifty   (contents, props changed)
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/doc/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/etc/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/etc/config.yml
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FasterSwallow.pm
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FavoriteColor.pm
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Action/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Model/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Model/User.pm
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/log/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/share/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/share/po/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/share/web/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/share/web/static/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/share/web/templates/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/t/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/t/mailbox
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/var/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/var/mason/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/var/mason/cache/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/var/mason/obj/
   jifty/trunk/t/TestApp-Plugin-PasswordAuth/var/mason/obj/.__obj_create_marker
   jifty/trunk/t/TestApp/lib/TestApp/View.pm
Removed:
   jifty/trunk/share/web/templates/__jifty/admin/
   jifty/trunk/share/web/templates/__jifty/css/
   jifty/trunk/share/web/templates/__jifty/js/
   jifty/trunk/share/web/templates/__jifty/online_docs/
Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/MANIFEST
   jifty/trunk/Makefile.PL
   jifty/trunk/examples/Chat/etc/config.yml
   jifty/trunk/lib/Jifty.pm
   jifty/trunk/lib/Jifty/Action/Record.pm
   jifty/trunk/lib/Jifty/Action/Record/Create.pm
   jifty/trunk/lib/Jifty/ClassLoader.pm
   jifty/trunk/lib/Jifty/Config.pm
   jifty/trunk/lib/Jifty/CurrentUser.pm
   jifty/trunk/lib/Jifty/Dispatcher.pm
   jifty/trunk/lib/Jifty/Everything.pm
   jifty/trunk/lib/Jifty/Handler.pm
   jifty/trunk/lib/Jifty/I18N.pm
   jifty/trunk/lib/Jifty/Plugin.pm
   jifty/trunk/lib/Jifty/Plugin/ClassLoader.pm
   jifty/trunk/lib/Jifty/Plugin/REST.pm
   jifty/trunk/lib/Jifty/Record.pm
   jifty/trunk/lib/Jifty/Request.pm
   jifty/trunk/lib/Jifty/Server.pm
   jifty/trunk/lib/Jifty/TestServer.pm
   jifty/trunk/lib/Jifty/Web.pm
   jifty/trunk/lib/Jifty/Web/Form.pm
   jifty/trunk/lib/Jifty/Web/Form/Clickable.pm
   jifty/trunk/lib/Jifty/Web/Form/Field/Button.pm
   jifty/trunk/lib/Jifty/Web/PageRegion.pm
   jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/index.html
   jifty/trunk/t/TestApp/t/i18n-standalone.t

Log:
* "final" Mergedown of the Template-Declare branch of Jifty.
  - New Template::Declare based templating system (optional)
  - Significant work on plugins
  - Significant refactoring
  - Many jifty features extracted to 'mandatory' plugin applets. 
    (These should be made optional or removable over time)
  


Modified: jifty/trunk/MANIFEST
==============================================================================
--- jifty/trunk/MANIFEST	(original)
+++ jifty/trunk/MANIFEST	Thu Mar  8 17:06:55 2007
@@ -24,6 +24,7 @@
 doc/jifty-action-record-search
 doc/jifty-dispatcher.graffle
 doc/jifty-dispatcher.svg
+doc/jifty-model-svk
 doc/jifty-plugins-2.0
 doc/jifty-web-form-etc
 doc/packaging
@@ -37,6 +38,7 @@
 etc/config.yml
 etc/site_config.yml
 examples/Chat/bin/jifty
+examples/Chat/chat
 examples/Chat/etc/config.yml
 examples/Chat/lib/Chat/Action/Send.pm
 examples/Chat/lib/Chat/Event/Message.pm
@@ -55,6 +57,11 @@
 examples/Clock/Makefile.PL
 examples/Clock/share/web/templates/fragments/time
 examples/Clock/share/web/templates/index.html
+examples/HelloKitty/bin/jifty
+examples/HelloKitty/etc/config.yml
+examples/HelloKitty/hellokitty
+examples/HelloKitty/lib/HelloKitty/View.pm
+examples/HelloKitty/Makefile.PL
 examples/MyWeblog/bin/jifty
 examples/MyWeblog/etc/config.yml
 examples/MyWeblog/lib/MyWeblog/Model/Post.pm
@@ -123,6 +130,7 @@
 lib/Jifty/Manual/Actions.pod
 lib/Jifty/Manual/Continuations.pod
 lib/Jifty/Manual/Cookbook.pod
+lib/Jifty/Manual/Deploying.pod
 lib/Jifty/Manual/FAQ.pod
 lib/Jifty/Manual/Glossary.pod
 lib/Jifty/Manual/Models.pod
@@ -133,6 +141,7 @@
 lib/Jifty/Manual/Tutorial.pod
 lib/Jifty/Manual/Tutorial_de.pod
 lib/Jifty/Manual/Tutorial_ja.pod
+lib/Jifty/Manual/TutorialRest.pod
 lib/Jifty/Manual/Upgrading.pod
 lib/Jifty/Manual/UsingCSSandJS.pod
 lib/Jifty/Mason/Halo.pm
@@ -145,9 +154,22 @@
 lib/Jifty/Param.pm
 lib/Jifty/Param/Schema.pm
 lib/Jifty/Plugin.pm
+lib/Jifty/Plugin/AdminUI.pm
+lib/Jifty/Plugin/AdminUI/View-not-yet.pm
+lib/Jifty/Plugin/Authentication/Password.pm
+lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm
+lib/Jifty/Plugin/Authentication/Password/Action/Login.pm
+lib/Jifty/Plugin/Authentication/Password/Model/User.pm
 lib/Jifty/Plugin/ClassLoader.pm
+lib/Jifty/Plugin/CompressedCSSandJS.pm
+lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm
+lib/Jifty/Plugin/Halo.pm
+lib/Jifty/Plugin/OnlineDocs.pm
 lib/Jifty/Plugin/REST.pm
 lib/Jifty/Plugin/REST/Dispatcher.pm
+lib/Jifty/Plugin/User.pm
+lib/Jifty/Plugin/User/Model/User.pm
+lib/Jifty/Plugin/Yullio/View.pm
 lib/Jifty/Record.pm
 lib/Jifty/Request.pm
 lib/Jifty/Request/Mapper.pm
@@ -156,8 +178,10 @@
 lib/Jifty/RightsFrom.pm
 lib/Jifty/Script.pm
 lib/Jifty/Script/Action.pm
+lib/Jifty/Script/Adopt.pm
 lib/Jifty/Script/App.pm
 lib/Jifty/Script/Deps.pm
+lib/Jifty/Script/Env.pm
 lib/Jifty/Script/FastCGI.pm
 lib/Jifty/Script/Help.pm
 lib/Jifty/Script/Model.pm
@@ -174,6 +198,15 @@
 lib/Jifty/Upgrade.pm
 lib/Jifty/Upgrade/Internal.pm
 lib/Jifty/Util.pm
+lib/Jifty/View/Declare.pm
+lib/Jifty/View/Declare/BaseClass.pm
+lib/Jifty/View/Declare/CoreTemplates.pm
+lib/Jifty/View/Declare/ErrorHandlers.pm
+lib/Jifty/View/Declare/Handler.pm
+lib/Jifty/View/Declare/Helpers.pm
+lib/Jifty/View/Declare/Helpers.pm.tdy
+lib/Jifty/View/Declare/SkeletonApp.pm
+lib/Jifty/View/Declare/WebServices.pm
 lib/Jifty/View/Mason/Handler.pm
 lib/Jifty/View/Static/Handler.pm
 lib/Jifty/Web.pm
@@ -205,6 +238,7 @@
 MANIFEST			This list of files
 MANIFEST.SKIP
 META.yml
+my-diff-of-td-branch
 plugins/AuthCASLogin/debian/changelog
 plugins/AuthCASLogin/debian/compat
 plugins/AuthCASLogin/debian/control
@@ -361,11 +395,36 @@
 plugins/ProfileBehaviour/Makefile.PL
 plugins/ProfileBehaviour/share/web/static/css/behaviour-profile.css
 plugins/ProfileBehaviour/share/web/static/js/behaviour.js
+plugins/Users-Identity-File/lib/Jifty/Plugin/Users/Identity/File.pm
+plugins/Users-Identity-File/lib/Jifty/Plugin/Users/Identity/File/Action/Login.pm
+plugins/Users-Identity-File/lib/Jifty/Plugin/Users/Identity/File/Dispatcher.pm
+plugins/Users-Identity-File/Makefile.PL
+plugins/Users-Identity-File/share/web/templates/login
+plugins/Users/lib/Jifty/Plugin/Users.pm
+plugins/Users/lib/Jifty/Plugin/Users/CurrentUser.pm
+plugins/Users/lib/Jifty/Plugin/Users/Dispatcher.pm
+plugins/Users/lib/Jifty/Plugin/Users/Model/User.pm
+plugins/Users/Makefile.PL
 README
 share/dtd/xhtml-lat1.ent
 share/dtd/xhtml-special.ent
 share/dtd/xhtml-symbol.ent
 share/dtd/xhtml1-strict.dtd
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/_elements/nav
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/action/dhandler
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/autohandler
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/header
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/list
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/new_item
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/search
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/update
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/view
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/index.html
+share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/model/dhandler
+share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/autohandler
+share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/content.html
+share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/index.html
+share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/toc.html
 share/po/en.po
 share/po/fr.po
 share/po/ja.po
@@ -393,6 +452,7 @@
 share/web/static/images/css/bullet_arrow_up.png
 share/web/static/images/css/fieldbg-autocomplete.gif
 share/web/static/images/css/fieldbg.gif
+share/web/static/images/iepngfix/blank.gif
 share/web/static/images/pony.jpg
 share/web/static/images/silk/bullet_arrow_down.png
 share/web/static/images/silk/bullet_arrow_up.png
@@ -421,6 +481,7 @@
 share/web/static/js/dom-drag.js
 share/web/static/js/formatDate.js
 share/web/static/js/halo.js
+share/web/static/js/iepngfix.htc
 share/web/static/js/jifty.js
 share/web/static/js/jifty_smoothscroll.js
 share/web/static/js/jifty_subs.js
@@ -451,19 +512,7 @@
 share/web/static/js/yui/tabview.js
 share/web/static/js/yui/yahoo.js
 share/web/templates/=/subs
-share/web/templates/__jifty/admin/_elements/nav
-share/web/templates/__jifty/admin/action/dhandler
-share/web/templates/__jifty/admin/autohandler
-share/web/templates/__jifty/admin/fragments/list/header
-share/web/templates/__jifty/admin/fragments/list/list
-share/web/templates/__jifty/admin/fragments/list/new_item
-share/web/templates/__jifty/admin/fragments/list/search
-share/web/templates/__jifty/admin/fragments/list/update
-share/web/templates/__jifty/admin/fragments/list/view
-share/web/templates/__jifty/admin/index.html
-share/web/templates/__jifty/admin/model/dhandler
 share/web/templates/__jifty/autocomplete.xml
-share/web/templates/__jifty/css/dhandler
 share/web/templates/__jifty/empty
 share/web/templates/__jifty/error/_elements/error_text
 share/web/templates/__jifty/error/_elements/wrapper
@@ -472,11 +521,6 @@
 share/web/templates/__jifty/error/error.css
 share/web/templates/__jifty/error/mason_internal_error
 share/web/templates/__jifty/halo
-share/web/templates/__jifty/js/dhandler
-share/web/templates/__jifty/online_docs/autohandler
-share/web/templates/__jifty/online_docs/content.html
-share/web/templates/__jifty/online_docs/index.html
-share/web/templates/__jifty/online_docs/toc.html
 share/web/templates/__jifty/validator.xml
 share/web/templates/__jifty/webservices/json
 share/web/templates/__jifty/webservices/xml
@@ -492,6 +536,7 @@
 share/web/templates/dhandler
 share/web/templates/helpers/calendar.html
 share/web/templates/index.html
+share/web/transform_templates
 SIGNATURE
 t/00-load.t
 t/01-dependencies.t
@@ -541,6 +586,13 @@
 t/Mapper/t/00-prototype.t
 t/Mapper/t/01-raw-api.t
 t/Mapper/t/02-api.t
+t/TestApp-Plugin-PasswordAuth/bin/jifty
+t/TestApp-Plugin-PasswordAuth/etc/config.yml
+t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FasterSwallow.pm
+t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FavoriteColor.pm
+t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Model/User.pm
+t/TestApp-Plugin-PasswordAuth/Makefile.PL
+t/TestApp-Plugin-PasswordAuth/t/00-model-User.t
 t/TestApp-Plugin-REST/bin/jifty
 t/TestApp-Plugin-REST/etc/config.yml
 t/TestApp-Plugin-REST/lib/TestApp/Plugin/REST/Action/DoSomething.pm
@@ -557,7 +609,10 @@
 t/TestApp/lib/TestApp/CurrentUser.pm
 t/TestApp/lib/TestApp/Dispatcher.pm
 t/TestApp/lib/TestApp/Model/User.pm
+t/TestApp/lib/TestApp/Upgrade.pm
+t/TestApp/lib/TestApp/View.pm
 t/TestApp/share/web/static/images/pony.jpg
+t/TestApp/share/web/templates/concrete.html
 t/TestApp/share/web/templates/currentuser
 t/TestApp/share/web/templates/dispatch/basic
 t/TestApp/share/web/templates/dispatch/basic-show
@@ -565,10 +620,14 @@
 t/TestApp/share/web/templates/editform
 t/TestApp/share/web/templates/index.html
 t/TestApp/share/web/templates/manual_redirect
+t/TestApp/share/web/templates/regions/list
+t/TestApp/share/web/templates/regions/long
+t/TestApp/share/web/templates/regions/short
 t/TestApp/share/web/templates/somedir/dhandler
 t/TestApp/t/00-model-User.t
 t/TestApp/t/00-prototype.t
 t/TestApp/t/01-config.t
+t/TestApp/t/02-dispatch-show-rule-in-wrong-ruleset.t
 t/TestApp/t/02-dispatch.t
 t/TestApp/t/03-static.t
 t/TestApp/t/04-sessions.t
@@ -582,7 +641,10 @@
 t/TestApp/t/10-compress.t
 t/TestApp/t/11-current_user.t
 t/TestApp/t/12-search.t
+t/TestApp/t/13-page-regions.t
 t/TestApp/t/config-Cachable
 t/TestApp/t/config-Record
+t/TestApp/t/i18n-standalone.t
 t/TestApp/t/instance_id.t
 t/TestApp/t/regex_meta_in_path_info.t
+t/TestApp/t/upgrade.t

Modified: jifty/trunk/Makefile.PL
==============================================================================
--- jifty/trunk/Makefile.PL	(original)
+++ jifty/trunk/Makefile.PL	Thu Mar  8 17:06:55 2007
@@ -59,6 +59,7 @@
 requires('Shell::Command');
 requires('String::Koremutake');
 requires('SQL::ReservedWords');
+requires('Template::Declare');                # Template::Declare::Tags
 requires('Test::Base');
 requires('UNIVERSAL::require');
 requires('URI');

Modified: jifty/trunk/examples/Chat/etc/config.yml
==============================================================================
--- jifty/trunk/examples/Chat/etc/config.yml	(original)
+++ jifty/trunk/examples/Chat/etc/config.yml	Thu Mar  8 17:06:55 2007
@@ -17,7 +17,7 @@
   DevelMode: 0
   L10N:
     PoDir: share/po
-  LogLevel: INFO
+  LogLevel: DEBUG
   Mailer: Sendmail
   MailerArgs: []
   Plugins: []

Added: jifty/trunk/examples/HelloKitty/Makefile.PL
==============================================================================
--- (empty file)
+++ jifty/trunk/examples/HelloKitty/Makefile.PL	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,6 @@
+use inc::Module::Install;
+name('HelloKitty');
+version('0.01');
+requires('Jifty' => '0.61025');
+
+WriteAll;

Added: jifty/trunk/examples/HelloKitty/bin/jifty
==============================================================================
--- (empty file)
+++ jifty/trunk/examples/HelloKitty/bin/jifty	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,15 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use File::Basename qw(dirname); 
+use UNIVERSAL::require;
+
+BEGIN {
+    Jifty::Util->require or die $UNIVERSAL::require::ERROR;
+    my $root = Jifty::Util->app_root;
+    unshift @INC, "$root/lib" if ($root);
+}
+
+use Jifty::Script;
+$SIG{INT} = $SIG{TERM} = sub { warn "Stopped\n"; exit; };
+Jifty::Script->dispatch();

Added: jifty/trunk/examples/HelloKitty/etc/config.yml
==============================================================================
--- (empty file)
+++ jifty/trunk/examples/HelloKitty/etc/config.yml	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,41 @@
+--- 
+framework: 
+  AdminMode: 1
+  ApplicationClass: HelloKitty
+  ApplicationName: HelloKitty
+  Database: 
+    CheckSchema: 1
+    Database: hellokitty
+    Driver: SQLite
+    Host: localhost
+    Password: ''
+    RecordBaseClass: Jifty::DBI::Record::Cachable
+    User: ''
+    Version: 0.0.1
+  DevelMode: 1
+  L10N: 
+    PoDir: share/po
+  LogLevel: INFO
+  Mailer: Sendmail
+  MailerArgs: []
+
+  Plugins: []
+
+  PubSub: 
+    Backend: Memcached
+    Enable: ~
+  TemplateClass: HelloKitty::View
+  Web: 
+    BaseURL: http://localhost
+    DataDir: var/mason
+    Globals: []
+
+    MasonConfig: 
+      autoflush: 0
+      default_escape_flags: h
+      error_format: text
+      error_mode: fatal
+    Port: 8888
+    ServeStaticFiles: 1
+    StaticRoot: share/web/static
+    TemplateRoot: share/web/templates

Added: jifty/trunk/examples/HelloKitty/hellokitty
==============================================================================
Binary file. No diff available.

Added: jifty/trunk/examples/HelloKitty/lib/HelloKitty/View.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/examples/HelloKitty/lib/HelloKitty/View.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,22 @@
+use warnings;
+use strict;
+
+package HelloKitty::View;
+use base qw/Jifty::View::Declare::Templates/;
+use Template::Declare::Tags;
+use Jifty::View::Declare::Templates;
+
+template foo => sub {
+    html {
+        body {
+            show 'content';
+        }
+
+    }
+};
+
+template content => sub {
+    form {'woot'};
+};
+
+1;

Added: jifty/trunk/examples/HelloKitty/var/jifty-server.pid
==============================================================================
--- (empty file)
+++ jifty/trunk/examples/HelloKitty/var/jifty-server.pid	Thu Mar  8 17:06:55 2007
@@ -0,0 +1 @@
+26267
\ No newline at end of file

Modified: jifty/trunk/lib/Jifty.pm
==============================================================================
--- jifty/trunk/lib/Jifty.pm	(original)
+++ jifty/trunk/lib/Jifty.pm	Thu Mar  8 17:06:55 2007
@@ -191,6 +191,9 @@
     Jifty->handler(Jifty::Handler->new());
     Jifty->api(Jifty::API->new());
 
+    # We can only require view classes once we have our models and actions set.
+    $class_loader->require_views;
+
     # Let's get the database rocking and rolling
     Jifty->setup_database_connection(%args);
 

Modified: jifty/trunk/lib/Jifty/Action/Record.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Action/Record.pm	(original)
+++ jifty/trunk/lib/Jifty/Action/Record.pm	Thu Mar  8 17:06:55 2007
@@ -291,12 +291,11 @@
                 };
             }
 
-            my $canonicalize_method = "canonicalize_" . $field;
-            if ( $self->record->can($canonicalize_method) ) {
+            if ( $self->record->has_canonicalizer_for_column($field) ) {
                 $info->{'ajax_canonicalizes'} = 1;
                 $info->{'canonicalizer'} ||= sub {
                     my ( $self, $value ) = @_;
-                    return $self->record->$canonicalize_method($value);
+                    return $self->record->run_canonicalization_for_column(column => $field, value => $value);
                 };
             } elsif ( $render_as eq 'date')
             {

Modified: jifty/trunk/lib/Jifty/Action/Record/Create.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Action/Record/Create.pm	(original)
+++ jifty/trunk/lib/Jifty/Action/Record/Create.pm	Thu Mar  8 17:06:55 2007
@@ -78,7 +78,7 @@
     }
 
     if (! $record->id ) {
-        $self->log->debug(_("Create of %1 failed: %2", ref($record), $msg));
+        $self->log->warn(_("Create of %1 failed: %2", ref($record), $msg));
         $self->result->error($msg || _("An error occurred.  Try again later"));
     }
 

Modified: jifty/trunk/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/trunk/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/trunk/lib/Jifty/ClassLoader.pm	Thu Mar  8 17:06:55 2007
@@ -134,6 +134,11 @@
                   "use warnings; use strict; package $module;\n"
                 . "use base qw/Jifty::$1/; sub _autogenerated { 1 };\n"
                 . "1;" );
+    } elsif ( $module =~ m!^(?:$base)::View$! ) {
+        return $self->return_class(
+                  "use warnings; use strict; package $module;\n"
+                . "use base qw/Jifty::View::Declare::Helpers/; sub _autogenerated { 1 };\n"
+                . "1;" );
     } elsif ( $module =~ m!^(?:$base)::CurrentUser$! ) {
         return $self->return_class(
                   "use warnings; use strict; package $module;\n"
@@ -213,8 +218,8 @@
     
 
     Jifty::Module::Pluggable->import(
-        search_path =>
-          [ map { $base . "::" . $_ } 'Model', 'Action', 'Notification', 'Event' ],
+        # $base goes last so we pull in the view class AFTER the model classes
+        search_path => [map { $base . "::" . $_ } ('Model', 'Action', 'Notification', 'Event')],
         require => 1,
         except  => qr/\.#/,
         inner   => 0
@@ -268,6 +273,21 @@
     }
 }
 
+=head2 require_views
+
+Load up C<$appname::View>, the view class for the application.
+
+=cut
+
+sub require_views {
+    my $self = shift;
+    
+    my $base = $self->{base};
+    # if we don't even have an application class, this trick will not work
+    return unless ($base); 
+    Jifty::Util->require($base."::View");
+}
+
 =head2 models
 
 Accessor to the list of models this application has loaded.

Modified: jifty/trunk/lib/Jifty/Config.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Config.pm	(original)
+++ jifty/trunk/lib/Jifty/Config.pm	Thu Mar  8 17:06:55 2007
@@ -240,6 +240,7 @@
             AdminMode        => 1,
             DevelMode        => 1,
             ApplicationClass => $app_class,
+            TemplateClass    => $app_class."::View",
             ApplicationName  => $app_name,
             ApplicationUUID  => $app_uuid,
             LogLevel         => 'INFO',
@@ -262,7 +263,15 @@
             L10N       => {
                 PoDir => "share/po",
             },
-            Plugins    => [],
+            Plugins    => [
+            { REST => {},
+        },
+        {       Halo => {},},
+        {ErrorTemplates => {},},
+        {OnlineDocs => {},},
+        {        CompressedCSSandJS => {},},
+        {AdminUI => {},}
+            ],
             Web        => {
                 Port => '8888',
                 BaseURL => 'http://localhost',

Modified: jifty/trunk/lib/Jifty/CurrentUser.pm
==============================================================================
--- jifty/trunk/lib/Jifty/CurrentUser.pm	(original)
+++ jifty/trunk/lib/Jifty/CurrentUser.pm	Thu Mar  8 17:06:55 2007
@@ -34,6 +34,8 @@
 Creates a new L<Jifty::CurrentUser> object.  Calls L<_init>, an
 app-specific initialization routine.
 
+If you call it with the C<_bootstrap> argument, Jifty will set the user up as a bootstrap user, who's usually allowed to do just about anything without any access control
+
 =cut
 
 sub new {

Modified: jifty/trunk/lib/Jifty/Dispatcher.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Dispatcher.pm	(original)
+++ jifty/trunk/lib/Jifty/Dispatcher.pm	Thu Mar  8 17:06:55 2007
@@ -761,6 +761,7 @@
 
     $self->log->debug("Showing path $path");
 
+
     # If we've got a working directory (from an "under" rule) and we have
     # a relative path, prepend the working directory
     $path = "$self->{cwd}/$path" unless $path =~ m{^/};
@@ -770,18 +771,14 @@
         $path .= "/index.html";
     }
 
-    my $abs_template_path = Jifty::Util->absolute_path(
-        Jifty->config->framework('Web')->{'TemplateRoot'} . $path );
-    my $abs_root_path = Jifty::Util->absolute_path(
-        Jifty->config->framework('Web')->{'TemplateRoot'} );
+    my $abs_template_path = Jifty::Util->absolute_path( Jifty->config->framework('Web')->{'TemplateRoot'} . $path );
+    my $abs_root_path = Jifty::Util->absolute_path( Jifty->config->framework('Web')->{'TemplateRoot'} );
 
     if ( $abs_template_path !~ /^\Q$abs_root_path\E/ ) {
-        request->path('/__jifty/errors/500');
+        $self->render_template('/__jifty/errors/500');
     } else {
-        # Set the request path
-        request->path($path);
+        $self->render_template( $path);
     }
-    $self->render_template( request->path );
 
     last_rule;
 }
@@ -1141,8 +1138,16 @@
     my $self = shift;
     my $template = shift;
 
-    $self->log->debug( "Handling template " . $template );
-    eval { Jifty->handler->mason->handle_comp( $template ); };
+    eval { 
+        my( $val) = Jifty->handler->declare_handler->template_exists($template);
+        if ($val) {
+            Jifty->handler->declare_handler->show($template);
+        } else {
+            Jifty->handler->mason->handle_comp( $template ); 
+        }
+    
+    
+    };
     my $err = $@;
 
     # Handle parse errors
@@ -1159,8 +1164,7 @@
         warn "$err";
 
         # Redirect with a continuation
-        Jifty->web->_redirect(
-            "/__jifty/error/mason_internal_error?J:C=" . $c->id );
+        Jifty->web->_redirect( "/__jifty/error/mason_internal_error?J:C=" . $c->id );
     }
     elsif ($err) {
         die $err;

Modified: jifty/trunk/lib/Jifty/Everything.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Everything.pm	(original)
+++ jifty/trunk/lib/Jifty/Everything.pm	Thu Mar  8 17:06:55 2007
@@ -45,6 +45,7 @@
 use Jifty::Logger ();
 use Jifty::Handler ();
 use Jifty::View::Static::Handler ();
+use Jifty::View::Declare::Handler ();
 use Jifty::View::Mason::Handler ();
 
 use Jifty::Model::Metadata ();

Modified: jifty/trunk/lib/Jifty/Handler.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Handler.pm	(original)
+++ jifty/trunk/lib/Jifty/Handler.pm	Thu Mar  8 17:06:55 2007
@@ -26,6 +26,7 @@
 
 use base qw/Class::Accessor::Fast/;
 use Module::Refresh ();
+use Jifty::View::Declare::Handler ();
 
 BEGIN {
     # Creating a new CGI object breaks FastCGI in all sorts of painful
@@ -47,7 +48,7 @@
 
 
 
-__PACKAGE__->mk_accessors(qw(mason dispatcher static_handler cgi apache stash));
+__PACKAGE__->mk_accessors(qw(mason dispatcher declare_handler static_handler cgi apache stash));
 
 =head2 new
 
@@ -61,20 +62,29 @@
     bless $self, $class;
 
     $self->create_cache_directories();
-#    wrap 'CGI::new', pre => sub {
-#        $_[-1] = Jifty->handler->cgi if Jifty->handler->cgi;
-#    };
 
     $self->dispatcher( Jifty->app_class( "Dispatcher" ) );
     Jifty::Util->require( $self->dispatcher );
     $self->dispatcher->import_plugins;
-    $self->dispatcher->dump_rules;
-    
-    $self->mason( Jifty::View::Mason::Handler->new( $self->mason_config ) );
+ 
+    $self->setup_view_handlers();
+    return $self;
+}
 
-    $self->static_handler(Jifty::View::Static::Handler->new());
+=head2 setup_view_handlers
 
-    return $self;
+Initialize all of our view handlers. 
+
+XXX TODO: this should take pluggable views
+
+=cut
+
+sub setup_view_handlers {
+    my $self = shift;
+
+    $self->declare_handler( Jifty::View::Declare::Handler->new( $self->templatedeclare_config));
+    $self->mason( Jifty::View::Mason::Handler->new( $self->mason_config ) );
+    $self->static_handler(Jifty::View::Static::Handler->new());
 }
 
 
@@ -127,9 +137,13 @@
 
     for my $plugin (Jifty->plugins) {
         my $comp_root = $plugin->template_root;
-        next unless $comp_root;
+        unless  ( $comp_root and -d $comp_root) {
+            Jifty->log->debug( "Plugin @{[ref($plugin)]} doesn't appear to have a valid mason template component root (@{[$comp_root ||'']})");
+            next;
+        }
         push @{ $config{comp_root} }, [ ref($plugin)."-".Jifty->web->serial => $comp_root ];
     }
+    push @{$config{comp_root}}, [jifty => Jifty->config->framework('Web')->{'DefaultTemplateRoot'}];
 
     push @{ $config{comp_root} }, [jifty => Jifty->config->framework('Web')->{'DefaultTemplateRoot'}];
 
@@ -139,10 +153,38 @@
         $config{static_source}    = 0;
         $config{use_object_files} = 0;
     }
-    return (%config);
+    return %config;
         
 }
 
+
+=head2 templatedeclare_config
+
+=cut
+
+sub templatedeclare_config {
+    
+    use Jifty::View::Declare::CoreTemplates;
+    my %config = (
+        roots => [ 'Jifty::View::Declare::CoreTemplates' ],
+        %{ Jifty->config->framework('Web')->{'TemplateDeclareConfig'} ||{}},
+    );
+
+    for my $plugin ( Jifty->plugins ) {
+        my $comp_root = $plugin->template_class;
+        Jifty::Util->require($comp_root);
+        unless (defined $comp_root and $comp_root->isa('Template::Declare') ){
+            Jifty->log->debug( "Plugin @{[ref($plugin)]} doesn't appear to have a ::View class that's a Template::Declare subclass");
+            next;
+        }
+        push @{ $config{roots} }, $comp_root ;
+    }
+
+    push @{$config{roots}}, Jifty->config->framework('TemplateClass');
+
+    return %config;
+}
+
 =head2 cgi
 
 Returns the L<CGI> object for the current request, or C<undef> if

Modified: jifty/trunk/lib/Jifty/I18N.pm
==============================================================================
--- jifty/trunk/lib/Jifty/I18N.pm	(original)
+++ jifty/trunk/lib/Jifty/I18N.pm	Thu Mar  8 17:06:55 2007
@@ -63,6 +63,7 @@
     $lang = [defined $lang ? $lang : ()] unless ref($lang) eq 'ARRAY';
 
     my $lh = $class->get_handle(@$lang);
+
     $DynamicLH = \$lh unless @$lang; 
     $self->init;
 
@@ -80,6 +81,7 @@
         my @stringified_args = map {"$_"} @_;
         my $result = eval { $lh->maketext(@stringified_args) };
         if ($@) {
+            warn $@;
             # Sometimes Locale::Maketext fails to localize a string and throws
             # an exception instead.  In that case, we just return the input.
             return join(' ', @stringified_args);

Modified: jifty/trunk/lib/Jifty/Plugin.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Plugin.pm	(original)
+++ jifty/trunk/lib/Jifty/Plugin.pm	Thu Mar  8 17:06:55 2007
@@ -55,11 +55,8 @@
     Jifty::Util->require($class->dispatcher);
 
     # Start a plugin classloader set up on behalf of the application
-    require Jifty::Plugin::ClassLoader;
-    Jifty::Plugin::ClassLoader->new(
-	base => Jifty->app_class,
-	plugin => $class,
-    )->require;
+    Jifty::Util->require('Jifty::Plugin::ClassLoader');
+    Jifty::Plugin::ClassLoader->new( base => Jifty->app_class, plugin => $class,)->require;
 
     # XXX TODO: Add .po path
 
@@ -94,23 +91,52 @@
     Jifty->api->allow(qr/^\Q$class\E::Action/);
 }
 
+sub _calculate_share {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    unless ( $self->{share} ) {
+        local $@; # We're just avoiding File::ShareDir's failure behaviour of dying
+        eval { $self->{share} = File::ShareDir::module_dir($class) };
+    }
+    unless ( $self->{share} ) {
+        local $@ ; # We're just avoiding File::ShareDir's failure behaviour of dying
+        eval { $self->{share} = File::ShareDir::module_dir('Jifty') };
+        if ( $self->{'share'} ) {
+            my $class_to_path = $class;
+            $class_to_path =~ s|::|/|g;
+            $self->{share} .= "/plugins/" . $class_to_path;
+        }
+    }
+}
+
+
 =head2 template_root
 
-Returns the root of the template directory for this plugin
+Returns the root of the C<HTML::Mason> template directory for this plugin
 
 =cut
 
 sub template_root {
     my $self = shift;
-    my $class = ref($self) || $self;
-    unless (exists $self->{share}) {
-        $self->{share} = undef;
-        eval { $self->{share} = File::ShareDir::module_dir($class) };
-    }
+    $self->{share} ||= $self->_calculate_share();
     return unless $self->{share};
     return $self->{share}."/web/templates";
 }
 
+
+=head2 template_class
+
+Returns the Template::Declare view package for this plugin
+
+=cut
+
+sub template_class {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    return $class.'::View';
+}
+
+
 =head2 static_root
 
 Returns the root of the static directory for this plugin
@@ -119,11 +145,7 @@
 
 sub static_root {
     my $self = shift;
-    my $class = ref($self) || $self;
-    unless (exists $self->{share}) {
-        $self->{share} = undef;
-        eval { $self->{share} = File::ShareDir::module_dir($class) };
-    }
+    $self->{share} ||= $self->_calculate_share();
     return unless $self->{share};
     return $self->{share}."/web/static";
 }

Added: jifty/trunk/lib/Jifty/Plugin/AdminUI.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/AdminUI.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::AdminUI;
+use base qw/Jifty::Plugin/;
+
+
+=head2 NAME
+
+Jifty::Plugin::AdminUI
+
+=head2  DESCRIPTION
+
+This plugin provides a basic administrative CRUD view for your application. It's included in every jifty application
+by default.  While it's only accessible to the superuser, it's currently a bug that you can't disable it.
+
+=cut
+
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/AdminUI/View-not-yet.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/AdminUI/View-not-yet.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,495 @@
+package Jifty::Plugin::AdminUI::View;
+
+use strict;
+use warnings;
+
+use Jifty::View::Declare -base;
+
+use Scalar::Defer;
+
+=head1 NAME
+
+Jifty::Plugin::AdminUI::View
+
+=head1 DESCRIPTION
+
+Work In progress. Needs more factoring, tests, etc
+
+=cut
+
+template '__jifty/admin/_elements/nav' => sub {
+    my $nav =
+      Jifty->web->navigation->child(
+        "Administration" => url => '/__jifty/admin/' );
+    foreach my $model ( Jifty->class_loader->models ) {
+        next unless $model->isa('Jifty::Record');
+        next unless ( $model =~ /^(?:.*)::(.*?)$/ );
+        my $type = $1;
+        $nav->child( $type => url => '/__jifty/admin/model/' . $type );
+    }
+    return;
+};
+
+template '__jifty/admin/action/dhandler' => sub {
+    # XXX move to dispatcher
+    my $action_class = Jifty->api->qualify( die('$m->dhandler_arg') );
+
+    my $object_type = die "No object type defined";
+
+    my $action = new_action(
+        class   => $action_class,
+        moniker => "run-$action_class",
+    );
+
+    $action->sticky_on_failure(1);
+    page {
+        title is { _('Manage records: [_1]',$object_type) };
+        form {
+
+            for ( $action->argument_names ) {
+                render_param( $action, $_ );
+            }
+
+            Jifty->web->form->submit( label => _("Run the action") );
+        };
+
+        h2 { _('Done?') };
+        hyperlink(
+            url   => "/__jifty/admin/",
+            label => _('Back to the admin console')
+        );
+
+      }
+};
+
+template '__jifty/admin/autohandler' => sub {
+
+# If "AdminMode" is turned off in Jifty's config file, don't let people at the admin UI.
+    unless ( Jifty->config->framework('AdminMode') ) {
+        redirect('/__jifty/error/permission_denied');
+        return;
+    }
+    show('/__jifty/admin/elements/nav'); # XXX TODO hm. should be in dispatcher.
+};
+
+template '__jifty/admin/fragments/list/list' => sub {
+    my ( $object_type, $page, $new_slot, $item_path, $list_path, $limit_field, $limit_val, $per_page, $sort_by, $order, $search_slot ) =
+      get(qw( object_type page new_slot item_path list_path limit_field limit_val per_page sort_by order search_slot));
+
+    $page ||= 1;
+    $new_slot = 1 unless defined $new_slot;
+    $item_path ||= "/__jifty/admin/fragments/list/view";
+    $list_path ||= "/__jifty/admin/fragments/list";
+    $per_page ||=25;
+    $search_slot ||=1; 
+
+
+
+    my $collection_class =
+      Jifty->app_class( "Model", $object_type . "Collection" );
+    my $search = Jifty->web->response->result('search');
+    my $collection  = $collection_class->new();
+;
+    if ( !$search ) {
+   if ( $limit_field && $limit_val ) {
+      $collection->limit(column => $limit_field, value => $limit_val);
+   } else {
+      $collection->unlimit();
+   }
+   $collection->order_by(column => $sort_by, order=>'ASC') if ($sort_by && !$order);
+   $collection->order_by(column => $sort_by, order=>'DESC') if ($sort_by && $order);
+    }
+    else {
+        $collection = $search->content('search');
+        warn $collection->build_select_query;
+    }
+
+    $collection->set_page_info(
+        current_page => $page,
+        per_page     => $per_page
+    );
+
+if ($search_slot) {
+    my $search_region = Jifty::Web::PageRegion->new(
+        name => 'search',
+        path => '/__jifty/empty',
+    );
+
+    hyperlink(
+        onclick => [
+            {
+                region       => $search_region->qualified_name,
+                replace_with => $list_path. 'search',
+                toggle       => 1,
+                args         => { object_type => $object_type }
+            },
+        ],
+        label => _('Toggle search')
+    );
+
+    $search_region->render;
+}
+    if ( $collection->pager->last_page > 1 ) {
+        with( class => "page-count" ), span {
+            _( 'Page %1 of %2', $page, $collection->pager->last_page );
+          }
+    }
+
+    if ( $collection->pager->total_entries == 0 ) {
+        outs(_('No items found'));
+    } else {
+        outs(_('%1 entries', $collection-> count));
+        show( $list_path.'header', object_type => $object_type, list_path => $list_path, 
+    mask_field => $limit_field, mask_val => $limit_val, sort_by => $sort_by, order => $order);
+    }
+
+    with( class => "list" ), div {
+        while ( my $item = $collection->next ) {
+            Jifty->web->region(
+                name     => 'item-' . $item->id,
+                path     => $item_path,
+                defaults => { id => $item->id, object_type => $object_type,
+list_path => $list_path, mask_field => $limit_field , mask_val => $limit_val 
+ }
+            );
+        }
+
+    };
+
+    with( class => "paging" ), div {
+        if ( $collection->pager->previous_page ) {
+            with( class => "prev-page" ), span {
+                hyperlink(
+                    label   => _("Previous Page"),
+                    onclick =>
+                      { args => { page => $collection->pager->previous_page } }
+                );
+              }
+        }
+        if ( $collection->pager->next_page ) {
+            with( class => "next-page" ), span {
+                hyperlink(
+                    label   => _("Next Page"),
+                    onclick =>
+                      { args => { page => $collection->pager->next_page } }
+                );
+              }
+        }
+    };
+
+    if ($new_slot) {
+        Jifty->web->region(
+            name     => 'new_item',
+        path => $list_path.'new_item',
+        defaults => {   object_type => $object_type, list_path => $list_path,
+                     mask_field => $limit_field , mask_val => $limit_val },
+        );
+    }
+
+};
+
+# When you hit "save" and create a item, you want to put a fragment
+# containing the new item in the associated list and refresh the current
+# fragment
+#
+template '__jifty/admin/fragments/list/new_item' => sub {
+    my ( $object_type, $region, $mask_field, $mask_val, $list_path ) = get(qw(object_type region mask_field mask_val list_path));
+    my $record_class = Jifty->app_class( "Model", $object_type );
+    my $create = new_action( class => 'Create' . $object_type );
+    if ($mask_field) {
+        $create->hidden($mask_field,$mask_val);
+        }
+
+    div {
+    attr{ class => "jifty_admin create item inline" };
+        foreach my $argument ( $create->argument_names ) {
+            if ( $argument ne $mask_field ) {
+            render_param( $create => $argument );
+        }
+        }
+    };
+
+    Jifty->web->form->submit(
+        label   => _('Create'),
+        onclick => [
+            { submit       => $create },
+            { refresh_self => 1 },
+            {
+                element => $region->parent->get_element('div.list'),
+                append  => $list_path.'view',
+                args    => {
+                    object_type => $object_type,
+                    list_path => $list_path,
+                    id          => { result_of => $create, name => 'id' },
+                },
+            },
+        ]
+      )
+
+};
+
+template '__jifty/admin/fragments/list/header' => sub {
+my ($object_type, $mask_val , $mask_field, $sort_by, $order, $list_path) =
+get(qw(object_type mask_val mask_field sort_by order list_path));
+my $record_class = Jifty->app_class("Model", $object_type);
+my $record = $record_class->new();
+ my $update = Jifty->web->new_action(class => 'Update'.$object_type);
+div {
+attr { class=>"jifty_admin_header" };
+
+ foreach my $argument ($update->argument_names) {
+ unless( $argument eq $mask_field ||  $argument eq 'id' || $argument =~ /_confirm$/i
+        && lc $update->arguments->{$argument}{render_as} eq 'password') {
+span { attr {class=>"<% ($sort_by && !$order && $sort_by eq $argument)?'up_select':'up' %>"};
+
+    hyperlink(
+        label   => _("asc"),
+        onclick => 
+            { 
+            replace_with => $list_path.'list' ,
+            args   => {
+                object_type => $object_type,
+                limit_val => $mask_val,
+                limit_field => $mask_field,
+                list_path => $list_path,
+                sort_by => $argument,
+                order => undef
+                },
+            },
+        #as_button => 1
+        );
+}
+span { attr{ class=>"<% ($sort_by && $order && $sort_by eq $argument )?'down_select':'down' %>" };
+    hyperlink(
+        label   => _("desc"),
+        onclick => 
+            {
+            replace_with => $list_path.'list',
+            args   => {
+                object_type => $object_type,
+                limit_val => $mask_val,
+                limit_field => $mask_field,
+                list_path => $list_path,
+                sort_by => $argument,
+                order => 'D'
+                },
+            },
+        #as_button => 1
+        )
+}
+span { attr { class=>"field" };
+    outs ($argument );
+}
+ }
+ }
+hr {};
+}
+};
+
+
+template '__jifty/admin/fragments/list/search' => sub {
+    my ($object_type) = get(qw(object_type));
+    my $search = new_action(
+        class             => "Search" . $object_type,
+        moniker           => "search",
+        sticky_on_success => 1,
+    );
+
+    with( class => "jifty_admin" ), div {
+        for my $arg ( $search->argument_names ) {
+            render_param( $search => $arg );
+        }
+
+        $search->button(
+            label   => _('Search'),
+            onclick => {
+                submit  => $search,
+                refresh => Jifty->web->current_region->parent,
+                args    => { page => 1 }
+            }
+        );
+        hr {};
+      }
+};
+
+template '__jifty/admin/fragments/list/update' => sub {
+    my ( $id, $object_type, $mask_field, $mask_val, $list_path ) = get(qw(id object_type mask_field mask_val list_path));
+    my $record_class = Jifty->app_class( "Model", $object_type );
+    my $record       = $record_class->new();
+    my $update       = new_action(
+        class   => "Update" . $object_type,
+        moniker => "update-" . Jifty->web->serial,
+        record  => $record
+    );
+    with( class => "jifty_admin update item inline $object_type" ), div {
+        with( class => "editlink" ), div {
+            hyperlink(
+                label   => _("Save"),
+                onclick => [
+                    { submit => $update },
+                    {
+                        replace_with => $list_path.'view',
+                        args => { object_type => $object_type, id => $id, list_path => $list_path }
+                    }
+                ]
+            );
+
+            hyperlink(
+                label   => _("Cancel"),
+                onclick => {
+                    replace_with => $list_path.'view',
+                    args         => { object_type => $object_type, id => $id, list_path => $list_path}
+                },
+                as_button => 1
+            );
+
+        };
+        if ($mask_field) {
+        $update->hidden($mask_field, $mask_val);
+        }
+
+        foreach my $argument ( $update->argument_names ) {
+            if ( $argument ne $mask_field ) {
+            render_param( $update => $argument );
+            }
+        }
+        hr {};
+    };
+};
+
+template '__jifty/admin/fragments/list/view' => sub {
+    my ( $id, $object_type, $mask_field, $mask_val, $list_path ) = get(qw( id object_type mask_field mask_val list_path ));
+    my $record_class = Jifty->app_class( "Model", $object_type );
+    my $record = $record_class->new();
+    $record->load($id);
+    my $update = new_action(
+        class   => "Update" . $object_type,
+        moniker => "update-" . Jifty->web->serial,
+        record  => $record
+    );
+    my $delete = new_action(
+        class   => "Delete" . $object_type,
+        moniker => "delete-" . Jifty->web->serial,
+        record  => $record
+    );
+
+    with( class => "jifty_admin read item inline" ), div {
+
+        Jifty->web->form->submit(
+            class   => "editlink",
+            label   => _("Delete"),
+            onclick => [
+               { confirm => _("Confirm delete?")},
+                {submit  => $delete},
+                {delete  => Jifty->web->current_region->qualified_name }
+            ]
+        );
+        hyperlink(
+            label   => _("Edit"),
+            class   => "editlink",
+            onclick => {
+                replace_with => $list_path."update",
+                args         => { object_type => $object_type, id => $id, 
+list_path => $list_path, mask_field => $mask_field, mask_val => $mask_val}
+            },
+            as_button => 1
+        );
+
+        $delete->hidden( 'id', $id );
+        foreach my $argument ( $update->argument_names ) {
+            unless ( $argument eq $mask_field ||  $argument =~ /_confirm$/
+                && lc $update->arguments->{$argument}{render_as} eq 'password' )
+            {
+                render_param( $update => $argument, render_mode => 'read' );
+            }
+        }
+
+        hr {};
+    };
+
+};
+
+template '__jifty/admin/index' => page {
+    title is 'Jifty Administrative Console' ;
+
+        h1 { _('Database Administration') };
+
+        p {
+            _(
+'This console lets you manage the records in your Jifty database. Below, you should see a list of all your database tables. Feel free to go through and add, delete or modify records.'
+            );
+        };
+
+        p {
+            _(
+'To disable this administrative console, add "AdminMode: 0" under the "framework:" settings in the config file (etc/config.yml).'
+            );
+        };
+
+        h2 { _('Models') };
+        ul {
+            foreach my $model ( Jifty->class_loader->models ) {
+                next unless $model->isa('Jifty::Record');
+                next unless ( $model =~ /^(?:.*)::(.*?)$/ );
+                my $type = $1;
+                li {
+                    hyperlink(
+                        url   => '/__jifty/admin/model/' . $type,
+                        label => $type
+                    );
+                };
+            }
+        };
+        h2 { _('Actions') };
+        ul {
+            foreach my $action ( Jifty->api->actions ) {
+                Jifty::Util->require($action);
+                next
+                  if (  $action->can('autogenerated')
+                    and $action->autogenerated );
+                li {
+                    hyperlink(
+                        url   => '/__jifty/admin/action/' . $action,
+                        label => $action
+                    );
+                };
+            }
+        };
+        h2 { _('Done?') };
+        Jifty->web->return(
+            to    => "/",
+            label => _('Back to the application')
+        );
+};
+
+template '__jifty/admin/model/dhandler' => page {
+    # XXX move to dispatcher
+    my $object_type = die('$m->dhandler_arg');
+
+    my $collection_class =
+      Jifty->app_class( "Model", $object_type . "Collection" );
+    my $records = $collection_class->new();
+    $records->unlimit;
+        h1 { _( 'Manage records: [_1]', $object_type ) };
+        form {
+            Jifty->web->region(
+                name     => "admin-$object_type",
+                path     => "/__jifty/admin/fragments/list/list",
+                defaults => {
+                    object_type   => $object_type,
+                    render_submit => 1
+                }
+            );
+
+        };
+
+        h2 { _('Done?') };
+        hyperlink(
+            url   => "/__jifty/admin/",
+            label => _('Back to the admin console')
+        );
+
+};
+
+warn "and here";
+1;

Added: jifty/trunk/lib/Jifty/Plugin/Authentication/Password.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/Authentication/Password.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,24 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::Authentication::Password;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+=head1 NAME
+
+Jifty::Plugin::Authentication::Password
+
+=head1 DESCRIPTION
+
+When finished, this plugin will provide password authentication for 
+your Jifty application. (It adds a "password" column to your "User" model class).
+
+Right now, it's useless and should be ignored.
+
+
+=cut
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,53 @@
+use warnings;
+use strict;
+
+=head1 NAME
+
+Jifty::Plugin::Authentication::PasswordAction::GeneratePasswordToken
+
+=cut
+
+package Jifty::Plugin::Authentication::PasswordAction::GeneratePasswordToken;
+use base qw/Jifty::Action/;
+
+=head2 arguments
+
+We need the username of the user we're fetching a token for, so we can
+return the salt.
+
+=cut
+
+sub arguments { 
+    return( { username => { mandatory => 1 } });
+
+}
+
+
+=head2 take_action
+
+Generate a token and throw it back to the browser.  Also, return the
+user's password salt in $self->result->content.
+
+
+=cut
+
+sub take_action {
+    my $self = shift;
+
+    my $username = $self->argument_value('username');
+    my $class = Jifty->app_class('Model','User');
+    my $user = $class->new(current_user => Jifty::CurrentUser->superuser);
+    $user->load_by_cols(username => $username);
+    unless($user->id) {
+        $self->result->error('No such user');
+    }
+
+    my $password = $user->_value('password');
+    
+    my $token = time();
+    $self->result->content(token => $token);
+    $self->result->content(salt  => ($password ? $password->[1] : ""));
+    Jifty->web->session->set(login_token => $token);
+}
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/Login.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Action/Login.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,166 @@
+use warnings;
+use strict;
+
+=head1 NAME
+
+Jifty::Plugin::Authentication::Password::Action::Login
+
+=cut
+
+package Jifty::Plugin::Authentication::Password::Action::Login;
+use base qw/Jifty::Action/;
+use Digest::MD5 qw(md5_hex);
+
+use constant TOKEN_EXPIRE_TIME => 30;
+
+=head2 arguments
+
+Return the username and password form fields
+
+=cut
+
+sub arguments { 
+    return( { username => { label => 'Email username',
+                           mandatory => 1,
+                           ajax_validates => 1,
+                            }  ,
+
+              password => { type => 'password',
+                            label => 'Password',
+			    # mandatory in some cases; see validate_password
+                            mandatory => 0,
+                        },
+              hashed_password => { type => 'hidden',
+                            label => 'Hashed Password',
+                        },
+              remember => { type => 'checkbox',
+                            label => 'Remember me?',
+                            hints => 'Your browser can remember your login for you',
+                            default => 0,
+                          },
+	      token => { type => 'hidden',
+			 label => 'token',
+			 mandatory => 0 },
+
+          });
+
+}
+
+=head2 validate_username ADDRESS
+
+Makes sure that the username submitted is a legal username and that there's a user in the database with it.
+
+Overridden from Jifty::Action::Record.
+
+=cut
+
+sub validate_username {
+    my $self  = shift;
+    my $username = shift;
+
+    my $u = Jifty::Plugin::Authentication::Password::Model::User->new(current_user => Jifty::Plugin::Authentication::Password::CurrentUser->superuser);
+    $u->load_by_cols( username => $username );
+    return $self->validation_error(username => 'We do not have an account that matches that username.') unless ($u->id);
+
+    return $self->validation_ok('username');
+}
+
+
+=head2 validate_password PASSWORD
+
+Makes sure that the password submitted actually exists, unless there's a token and a hashed
+password.
+
+Overridden from Jifty::Action::Record.
+
+=cut
+
+sub validate_password {
+    my $self  = shift;
+    my $pw = shift;
+    my $token =  $self->argument_value('token') ||'';
+    my $hashedpw =  $self->argument_value('hashed_password') ;
+
+
+    if ($token eq '') { # we have no token, validate in a standard way
+        if ($pw eq '') {
+            return $self->validation_error(password => "Please fill in this field." );
+        }
+    } else { # we have a token, so we should have a hashed pw
+        my $emptypw = '';
+        my $blankhash = md5_hex("$token $emptypw");
+        if ($hashedpw eq $blankhash) {
+            return $self->validation_error(password => "Please fill in this field." );
+        }
+        
+    }
+
+
+    return $self->validation_ok('password');
+}
+
+=head2 validate_token TOKEN
+
+Make sure we issued the token within the last 30 seconds, otherwise
+time out the request.
+
+=cut
+
+sub validate_token {
+    my $self = shift;
+    my $value = shift;
+    if ($value) {
+        if(int $value < (time - TOKEN_EXPIRE_TIME)) { 
+            return $self->validation_error(token => "Your login attempt has timed out. Please try again.");
+        }
+        if ($value ne Jifty->web->session->get('login_token')) {
+            return $self->validation_error(token => "That didn't work. Please try again.");
+        }
+        Jifty->web->session->set(login_token => '');
+    }
+    return $self->validation_ok("token");
+}
+
+=head2 take_action
+
+Actually check the user's password. If it's right, log them in.
+Otherwise, throw an error.
+
+
+=cut
+
+sub take_action {
+    my $self = shift;
+    my $user = Jifty->app_class('CurrentUser')->new( username => $self->argument_value('username'));
+
+    my $password = $self->argument_value('password');
+    my $token = $self->argument_value('token') || '';
+    my $hashedpw = $self->argument_value('hashed_password');
+
+    if ($token ne '') {   # browser supports javascript, do password hashing
+	unless ( $user->id  && $user->hashed_password_is($hashedpw, $token)){
+	    $self->result->error( 'You may have mistyped your username or password. Give it another shot.' );
+	    return;
+	}
+        Jifty->web->session->set(login_token => '');
+    }
+    else {  # no password hashing over the wire
+	unless ( $user->id  && $user->password_is($password)){
+	    $self->result->error( 'You may have mistyped your username or password. Give it another shot.' );
+	    return;
+	}
+    }
+
+
+    # Set up our login message
+    $self->result->message("Welcome back, " . $user->user_object->name . "." );
+
+    # Actually do the signin thing.
+    Jifty->web->current_user($user);
+    Jifty->web->session->expires($self->argument_value('remember') ? '+1y' : undef);
+    Jifty->web->session->set_cookie;
+
+    return 1;
+}
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Model/User.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/Authentication/Password/Model/User.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,128 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::Authentication::Password::Model::User;
+use Jifty::DBI::Schema;
+use base 'Jifty::DBI::Record::Plugin';
+
+use Digest::MD5 qw'';
+
+our @EXPORT = qw(password_is);
+
+use Jifty::Plugin::Authentication::Password::Record schema {
+
+
+column auth_token =>
+  render_as 'unrendered',
+  type is 'varchar',
+  default is '',
+  label is 'Authentication token',
+  since '0.2.34';
+    
+
+
+column password =>
+  is mandatory,
+  is unreadable,
+  label is 'Password',
+  type is 'varchar',
+  hints is 'Your password should be at least six characters',
+  render_as 'password',
+  filters are 'Jifty::DBI::Filter::SaltHash';
+
+
+};
+
+
+
+=head2 password_is PASSWORD
+
+Checks if the user's password matches the provided I<PASSWORD>.
+
+=cut
+
+sub password_is {
+    my $self = shift;
+    my $pass = shift;
+
+    return undef unless $self->_value('password');
+
+    my ($hash, $salt) = @{$self->_value('password')};
+
+    return 1 if ( $hash eq Digest::MD5::md5_hex($pass . $salt) );
+    return undef;
+
+}
+
+=head2 hashed_password_is HASH TOKEN
+
+Check if the given I<HASH> is the result of hashing our (already
+salted and hashed) password with I<TOKEN>
+
+=cut
+
+sub hashed_password_is {
+    my $self = shift;
+    my $hash = shift;
+    my $token = shift;
+
+    my $password = $self->_value('password');
+    return $password && Digest::MD5::md5_hex("$token " . $password->[0]) eq $hash;
+}
+
+
+=head2 validate_password
+
+Makes sure that the password is six characters long or longer.
+
+=cut
+
+sub validate_password {
+    my $self      = shift;
+    my $new_value = shift;
+
+    return ( 0, q{Passwords need to be at least six characters long} )
+        if length($new_value) < 6;
+
+    return 1;
+}
+
+
+sub after_create {
+    my $self = shift;
+    $self->regenerate_auth_token;
+
+
+}
+
+=head2 after_set_password
+
+Regenerate auth tokens on password change
+
+=cut
+
+sub after_set_password {
+    my $self = shift;
+    $self->regenerate_auth_token;
+}
+
+=head2 regenerate_auth_token
+
+Generate a new auth_token for this user. This will invalidate any
+existing feed URLs.
+
+=cut
+
+sub regenerate_auth_token {
+    my $self = shift;
+    my $auth_token = '';
+
+    $auth_token .= unpack('H2', chr(int rand(255))) for (1..16);
+
+    $self->set_auth_token($auth_token);
+}
+
+
+
+1;
+

Modified: jifty/trunk/lib/Jifty/Plugin/ClassLoader.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Plugin/ClassLoader.pm	(original)
+++ jifty/trunk/lib/Jifty/Plugin/ClassLoader.pm	Thu Mar  8 17:06:55 2007
@@ -32,7 +32,12 @@
 
 sub new {
     my $class = shift;
-    my $self = bless {@_}, $class;
+    my %args = (@_);
+    my @exist = grep {ref $_ eq $class and $_->{base} eq $args{base}} @INC;
+     return $exist[0] if @exist;
+
+
+    my $self = bless {%args}, $class;
 
     push @INC, $self;
     return $self;
@@ -204,4 +209,29 @@
     }
 }
 
+=head2 DESTROY
+
+When the ClassLoader gets garbage-collected, its entry in @INC needs
+to be removed.
+
+=cut
+
+# The entries in @INC end up having SvTYPE == SVt_RV, but SvRV(sv) ==
+# 0x0 and !SvROK(sv) (!?)  This may be something that perl should cope
+# with more cleanly.
+#
+# We call this explictly in an END block in Jifty.pm, because
+# otherwise the DESTROY block gets called *after* there's already a
+# bogus entry in @INC
+
+# This bug manifests itself as warnings that look like this:
+
+# Use of uninitialized value in require at /tmp/7730 line 9 during global destruction.
+
+
+sub DESTROY {
+    my $self = shift;
+    @INC = grep {!$self} @INC;
+}
+
 1;

Added: jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::CompressedCSSandJS;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+=head1 NAME
+
+Jifty::Plugin::CompressedCSSandJS
+
+=head1 DESCRIPTION
+
+This plugin provides auto-compilation and on-wire compression of your application's CSS and Javascript. It is enabled by default.
+
+=cut
+
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,108 @@
+use warnings;
+use strict;
+
+package Jifty::Plugin::CompressedCSSandJS::Dispatcher;
+
+=head1 NAME
+
+Jifty::Plugin::CompressedCSSandJS::Dispatcher
+
+=head1 DESCRIPTION
+
+Adds dispatcher rules for C</__jifty/js/*> and C</__jifty/css/*/>,
+which serve out compiled and compressed CSS and Javascript rules.
+
+=cut
+
+
+use Jifty::Dispatcher -base;
+
+on '/__jifty/js/*' => run {
+    my $arg = $1;
+    warn "My arg is $arg";
+    if ( $arg !~ /^[0-9a-f]{32}\.js$/ ) {
+
+        # This doesn't look like a real request for squished JS,
+        # so redirect to a more failsafe place
+        Jifty->web->redirect( "/static/js/" . $arg );
+    }
+
+    Jifty->web->generate_javascript;
+
+    use HTTP::Date ();
+
+    if ( Jifty->handler->cgi->http('If-Modified-Since')
+        and $arg eq Jifty->web->cached_javascript_digest . '.js' )
+    {
+        Jifty->log->debug("Returning 304 for cached javascript");
+        Jifty->handler->apache->header_out( Status => 304 );
+        Jifty->handler->apache->send_http_header();
+        return;
+    }
+
+    Jifty->handler->apache->content_type("application/x-javascript");
+    Jifty->handler->apache->header_out( 'Expires' => HTTP::Date::time2str( time + 31536000 ) );
+
+    # XXX TODO: If we start caching the squished JS in a file somewhere, we
+    # can have the static handler serve it, which would take care of gzipping
+    # for us.
+    use Compress::Zlib qw();
+
+    if ( Jifty::View::Static::Handler->client_accepts_gzipped_content ) {
+        Jifty->log->debug("Sending gzipped squished JS");
+        Jifty->handler->apache->header_out( "Content-Encoding" => "gzip" );
+        Jifty->handler->apache->send_http_header();
+        binmode STDOUT;
+        print Compress::Zlib::memGzip( Jifty->web->cached_javascript );
+    } else {
+        Jifty->log->debug("Sending squished JS");
+        Jifty->handler->apache->send_http_header();
+        print Jifty->web->cached_javascript;
+    }
+    abort;
+};
+
+on '/__jifty/css/*' => run {
+    my $arg = $1;
+    warn "My arg is $arg";
+    if ( $arg !~ /^[0-9a-f]{32}\.css$/ ) {
+
+        # This doesn't look like a real request for squished CSS,
+        # so redirect to a more failsafe place
+        Jifty->web->redirect( "/static/css/" . $arg );
+    }
+
+    Jifty->web->generate_css;
+
+    use HTTP::Date ();
+
+    if ( Jifty->handler->cgi->http('If-Modified-Since')
+        and $arg eq Jifty->web->cached_css_digest . '.css' )
+    {
+        Jifty->log->debug("Returning 304 for cached css");
+        Jifty->handler->apache->header_out( Status => 304 );
+        return;
+    }
+
+    Jifty->handler->apache->content_type("text/css");
+    Jifty->handler->apache->header_out( 'Expires' => HTTP::Date::time2str( time + 31536000 ) );
+
+    # XXX TODO: If we start caching the squished CSS in a file somewhere, we
+    # can have the static handler serve it, which would take care of gzipping
+    # for us.
+    use Compress::Zlib qw();
+
+    if ( Jifty::View::Static::Handler->client_accepts_gzipped_content ) {
+        Jifty->log->debug("Sending gzipped squished CSS");
+        Jifty->handler->apache->header_out( "Content-Encoding" => "gzip" );
+        Jifty->handler->apache->send_http_header();
+        binmode STDOUT;
+        print Compress::Zlib::memGzip( Jifty->web->cached_css );
+    } else {
+        Jifty->log->debug("Sending squished CSS");
+        Jifty->handler->apache->send_http_header();
+        print Jifty->web->cached_css;
+    }
+    abort;
+};
+1;

Added: jifty/trunk/lib/Jifty/Plugin/ErrorTemplates.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/ErrorTemplates.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,20 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::ErrorTemplates;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+=head1 NAME
+
+Jifty::Plugin::ErrorTemplates
+
+=head1 DESCRIPTION
+
+This plugin provides superusers with online documentation for Jifty and your application's API. It's included by default when using Jifty. (That's a bug).
+
+=cut
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/ErrorTemplates/View.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/ErrorTemplates/View.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,218 @@
+package Jifty::Plugin::ErrorTemplates::View;
+
+use strict;
+use warnings;
+use vars qw( $r );
+
+use Jifty::View::Declare -base;
+
+use Scalar::Defer;
+
+=head1 NAME
+
+Jifty::Plugin::ErrorTemplates::View;
+
+=head1 DESCRIPTION
+
+This class is a stub. It's not in use yet. It should be, but that would require mason libraries to be able to call Template::Declare libraries
+
+=cut
+
+
+template '__jifty/error/_elements/error_text' => sub {
+    my ($error) = get(qw(error));
+    h1 { 'Sorry, something went awry' };
+    p  {
+        _(
+"For one reason or another, you got to a web page that caused a bit of an error. And then you got to our 'basic' error handler. Which means we haven't written a pretty, easy to understand error message for you just yet. The message we do have is :"
+        );
+    };
+
+    blockquote {
+        b { $error };
+    };
+
+    p {
+        _(
+"There's a pretty good chance that error message doesn't mean anything to you, but we'd rather you have a little bit of information about what went wrong than nothing. We've logged this error, so we know we need to write something friendly explaining just what happened and how to fix it."
+        );
+    };
+
+    p {
+        hyperlink(
+            url   => "/",
+            label => _('Head on back home')
+        );
+        _("for now, and try to forget that we let you down.");
+    };
+};
+
+=head2 wrapper
+                              This exists as a fallback wrapper,
+                              in case the error in question is caused by the Jifty app's wrapper, for instance.
+=cut
+
+{
+    no warnings qw'redefine';
+
+    sub wrapper ($) {
+        my $code = shift;
+        html {
+            head {
+                title { _('Internal error') } link {
+                    attr {
+                        rel   => 'stylesheet',
+                        type  => 'text/css',
+                        href  => "/__jifty/error/error.css",
+                        media => 'all'
+                    }
+                };
+                }
+                body {
+                div {
+                    attr { id => 'headers' };
+                    h1  {'Internal Error'};
+                    div {
+                        attr { id => 'content' };
+                        a { attr { name => 'content' } };
+                        if ( Jifty->config->framework('AdminMode') ) {
+                            div {
+                                attr { class => "warning admin_mode" };
+                                outs(
+                                    'Alert:'
+                                        . tangent(
+                                        label => 'administration mode',
+                                        url   => '/__jifty/admin/'
+                                        )
+                                        . 'is enabled.'
+                                );
+                                }
+                        }
+                        Jifty->web->render_messages;
+                        $code->();
+                        }
+
+                    }
+                }
+            }
+    }
+}
+
+
+template '__jifty/error/dhandler' => sub {
+    my $error = get('error');
+                            Jifty->log->error( "Unhandled web error " . $error );
+                            page {
+                              title is 'Something went awry';
+                              show('_elements/error_text', error => $error );
+                        };
+                    };
+
+template '__jifty/error/error.css' => sub {
+                            Jifty->handler->apache->content_type("text/css");
+                            h1 {
+                              outs('color: red');
+                              }
+
+                          };
+
+
+template '/errors/404' => sub {
+    my $file = get('path');
+    Jifty->log->error( "404: user tried to get to " . $file );
+    Jifty->handler->apache->header_out( Status => '404' );
+    with( title => _("Something's not quite right") ), page {
+
+        with( id => "overview" ),
+        div {
+            p {
+                join( " ",
+                    _( "You got to a page that we don't think exists." ),
+                    _( "Anyway, the software has logged this error." ),
+                    _("Sorry about this.") );
+                }
+
+                p {
+                hyperlink(
+                    url   => "/",
+                    label => _('Go back home...')
+                );
+                }
+
+            }
+    };
+};
+
+
+
+template '__jifty/error/mason_internal_error' => page {
+    { title is _('Something went awry') }
+    my $cont = Jifty->web->request->continuation;
+    #my $wrapper = "/__jifty/error/_elements/wrapper" if $cont and $cont->request->path eq "/__jifty/error/mason_internal_error";
+
+    # If we're not in devel, bail
+    if ( not Jifty->config->framework("DevelMode") or not $cont ) {
+            show("_elements/error_text");
+    #    return;
+    }
+
+    my $e   = $cont->response->error;
+    if (ref($e)) {
+    my $msg = $e->message;
+    $msg =~ s/, <\S+> (line|chunk) \d+\././;
+
+    my $info  = $e->analyze_error;
+    my $file  = $info->{file};
+    my @lines = @{ $info->{lines} };
+    my @stack = @{ $info->{frames} };
+
+        outs('Error in ');
+        _error_line( $file, "@lines" );
+        pre {$msg};
+
+        Jifty->web->return( label => _("Try again") );
+
+    h2 { 'Call stack' };
+    ul {
+        for my $frame (@stack) {
+            next if $frame->filename =~ m{/HTML/Mason/};
+            li {
+                _error_line( $frame->filename, $frame->line );
+                }
+        }
+    }; 
+    } else {
+    pre {$e};
+    }
+};
+
+sub _error_line {
+
+    my ( $file, $line ) = (@_);
+    if ( -w $file ) {
+        my $path = $file;
+        for ( map { $_->[1] } @{ Jifty->handler->mason->interp->comp_root } )
+        {
+            last if $path =~ s/ ^ \Q $_\E //;
+        }
+        if ( $path ne $file ) {
+            outs('template ');
+            tangent(
+                url        => "/__jifty/edit/mason_component$path",
+                label      => "$path line " . $line,
+                parameters => { line => $line }
+            );
+        } else {
+            tangent(
+                url        => "/__jifty/edit/library$path",
+                label      => "$path line " . $line,
+                parameters => { line => $line }
+            );
+        }
+    } else {
+        outs( '%1 line %2', $file, $line );
+    }
+
+}
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/Halo.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/Halo.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,24 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::Halo;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+
+=head1 NAME
+
+Jifty::Plugin::Halo
+
+=head1 DESCRIPTION
+
+This plugin provides L<http://seaside.st|Seasidesque> halos for
+your application. It's included by default when using Jifty. (That's
+a bug).
+
+=cut
+
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/OnlineDocs.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/OnlineDocs.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,20 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::OnlineDocs;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+=head1 NAME
+
+Jifty::Plugin::OnlineDocs
+
+=head1 DESCRIPTION
+
+This plugin provides superusers with online documentation for Jifty and your application's API. It's included by default when using Jifty. (That's a bug).
+
+=cut
+
+1;

Modified: jifty/trunk/lib/Jifty/Plugin/REST.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Plugin/REST.pm	(original)
+++ jifty/trunk/lib/Jifty/Plugin/REST.pm	Thu Mar  8 17:06:55 2007
@@ -26,4 +26,5 @@
 how to access the RESTian resources.
 
 =cut
+
 1;

Added: jifty/trunk/lib/Jifty/Plugin/SkeletonApp.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/SkeletonApp.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::SkeletonApp;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+=head1 NAME
+
+Jifty::Plugin::SkeletonApp
+
+=head1 DESCRIPTION
+
+=cut
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/SkeletonApp/Dispatcher.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/SkeletonApp/Dispatcher.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,21 @@
+use warnings;
+use strict;
+
+package Jifty::Plugin::SkeletonApp::Dispatcher;
+
+=head1 NAME
+
+Jifty::Plugin::SkeletonApp::Dispatcher
+
+=head1 DESCRIPTION
+
+When a user asks for /, give them index.html.
+
+=cut
+
+
+use Jifty::Dispatcher -base;
+
+on '/' => run { show 'index.html' };
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/SkeletonApp/View.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/SkeletonApp/View.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,98 @@
+package Jifty::Plugin::SkeletonApp::View;
+
+use strict;
+use warnings;
+use vars qw( $r );
+
+use Jifty::View::Declare -base;
+
+use Scalar::Defer;
+
+=head1 NAME
+
+Jifty::Plugin::SkeletonApp::View
+
+=head1 DESCRIPTION
+
+This somewhat-finished (But not quite) template library implements
+Jifty's "pony" Application. It could certainly use some refactoring. (And some of the menu stuff should get factored out into a dispatcher or the other plugins that implement it.
+
+
+=cut
+
+template '_elements/nav' => sub {
+    my $top = Jifty->web->navigation;
+    $top->child( Home => url => "/", sort_order => 1, label => _('Home') );
+    if ( Jifty->config->framework('AdminMode') ) {
+        $top->child(
+            Administration =>
+              url          => "/__jifty/admin/",
+            label      => _('Administration'),
+            sort_order => 998
+        );
+        $top->child(
+            OnlineDocs =>
+              url      => "/__jifty/online_docs/",
+            label      => _('Online docs'),
+            sort_order => 999
+        );
+    }
+    return ();
+};
+
+template '_elements/sidebar' => sub {
+    with( id => "salutation" ), div {
+        if (    Jifty->web->current_user->id
+            and Jifty->web->current_user->user_object )
+        {
+            my $u      = Jifty->web->current_user->user_object;
+            my $method = $u->_brief_description;
+            _( 'Hiya, %1.', $u->$method() );
+        }
+        else {
+            _("You're not currently signed in.");
+        }
+    };
+    with( id => "navigation" ), div {
+        Jifty->web->navigation->render_as_menu;
+    };
+};
+
+template '__jifty/empty' => sub {
+        '';
+};
+
+
+template '_elements/header' => sub {
+    my ($title) = get_current_attr(qw(title));
+    Jifty->handler->apache->content_type('text/html; charset=utf-8');
+    head {
+        with(
+            'http-equiv' => "content-type",
+            content      => "text/html; charset=utf-8"
+          ),
+          meta {};
+        with( name => 'robots', content => 'all' ), meta {};
+        title { _($title) };
+
+        Jifty->web->include_css;
+        Jifty->web->include_javascript;
+      }
+};
+
+
+template '_elements/keybindings' => sub {
+    div { id is "keybindings" };
+};
+
+template 'index.html' => page {
+    { title is _('Welcome to your new Jifty application') }
+    img {
+        src is "/static/images/pony.jpg", alt is _(
+            'You said you wanted a pony. (Source %1)',
+            'http://hdl.loc.gov/loc.pnp/cph.3c13461'
+        );
+    };
+};
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/User.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/User.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::User;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+=head1 NAME
+
+Jifty::Plugin::User
+
+=head1 DESCRIPTION
+
+This plugin provides a "user" mixin for your application's user model class.
+
+See L<Jifty::Plugin::User/> for more details.
+
+=cut
+
+1;

Added: jifty/trunk/lib/Jifty/Plugin/User/Model/User.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/User/Model/User.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,40 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::User::Model::User;
+use Jifty::DBI::Schema;
+
+
+=head1 NAME
+
+Jifty::Plugin::User::Model::User
+
+=head1 DESCRIPTION
+
+package MyApp::Model::User;
+
+use Jifty::DBI::Schema;
+
+use MyApp::Record schema { 
+
+    # column definitions
+
+};
+
+use Jifty::Plugin::User::Model::User; # Imports two columns: name and username
+
+
+=cut
+
+
+use base 'Jifty::DBI::Record::Plugin';
+use Jifty::Plugin::User::Record schema {
+    column name => type is 'text', label is 'How should I display your name?';
+    column username => type is 'text';
+};
+
+
+# Your model-specific methods go here.
+
+1;
+

Added: jifty/trunk/lib/Jifty/Plugin/Yullio/View.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/Yullio/View.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,65 @@
+package Jifty::View::Declare::Yullio;
+use strict;
+use warnings;
+
+# XXX: To be converted to a plugin with included css and images.
+
+use Jifty::View::Declare -base;
+
+use base 'Exporter';
+our @EXPORT = qw(yullio);
+
+=head1 NAME
+
+Jifty::View::Declare::Yullio - Yullio layout bundles
+
+=head1 SYNOPSIS
+
+  use Jifty::View::Declare::Yullio
+  template 'index2.html' => page {
+    with ( width => 'doc2', column_template => 'yui-t6' ),
+    yullio
+     { outs('This is main content') }
+     sub { outs('This is something on the side') } };
+
+=head1 DESCRIPTION
+
+C<Jifty::View::Declare::Yullio> provides an alternative C<page>
+temlpate constructor that makes use of yui grid layouts.
+
+=cut
+
+sub _yullio_content {
+    my ($code1, $code2) = @_;
+    # XXX: fix get_current_attr with multiple arguments
+    my ($width, $column_template) = map {get_current_attr($_)}
+	qw(width column_template);
+    sub {
+	# XXX: T::D is propagating our with to deeper callstacks as we
+	# are not calling from "_tag"
+	with (),
+
+
+	div {
+	    { id is $width, class is $column_template }
+
+	    div { { id is 'hd' }
+		  div { { id is 'yui-main' }
+		        div { { class is 'yui-b' }
+                              div { { id is 'content' }
+                                    $code1->() } } };
+                  if ($column_template ne 'yui-t7') {
+		      div { { id is 'yui-b' }
+                            div { { id is 'utility' }
+                                  $code2->() } }
+		  } } }
+    };
+}
+
+sub yullio(&&) {
+    my ($code1, $code2) = @_;
+    _yullio_content($code1, $code2)->();
+}
+
+1;
+

Modified: jifty/trunk/lib/Jifty/Record.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Record.pm	(original)
+++ jifty/trunk/lib/Jifty/Record.pm	Thu Mar  8 17:06:55 2007
@@ -54,10 +54,10 @@
 =cut 
 
 sub create {
-    my $class    = shift;
+    my $class = shift;
     my $self;
-    if (ref($class)) { 
-        ($self,$class) = ($class,undef);
+    if ( ref($class) ) {
+        ( $self, $class ) = ( $class, undef );
     } else {
         $self = $class->new();
     }
@@ -71,47 +71,49 @@
     }
 
     foreach my $key ( keys %attribs ) {
-        my $attr = $attribs{$key};
-        my $method = "canonicalize_$key";
-        my $func = $self->can($method) or next;
-        $attribs{$key} = $self->$func( $attr);
+        $attribs{$key} = $self->run_canonicalization_for_column(
+            column => $key,
+            value  => $attribs{$key}
+        );
     }
     foreach my $key ( keys %attribs ) {
         my $attr = $attribs{$key};
-        my $method = "validate_$key";
-        if (my $func = $self->can($method)) {
-        my ( $val, $msg ) = $func->($self, $attr);
-        unless ($val) {
+        my ( $val, $msg ) = $self->run_validation_for_column(
+            column => $key,
+            value  => $attribs{$key}
+        );
+        if ( not $val ) {
             $self->log->error("There was a validation error for $key");
             if ($class) {
-                return($self);
+                return ($self);
             } else {
                 return ( $val, $msg );
             }
         }
-        }
+
         # remove blank values. We'd rather have nulls
-        if ( exists $attribs{$key} and (! defined $attr || ( not ref( $attr) and $attr eq '' ))) {
+        if ( exists $attribs{$key}
+            and ( !defined $attr || ( not ref($attr) and $attr eq '' ) ) )
+        {
             delete $attribs{$key};
         }
     }
 
-
     my $msg = $self->SUPER::create(%attribs);
-    if (ref($msg)  ) {
+    if ( ref($msg) ) {
+
         # It's a Class::ReturnValue
-        return $msg ;
+        return $msg;
     }
-    my ($id, $status) = $msg;
+    my ( $id, $status ) = $msg;
     $self->load_by_cols( id => $id ) if ($id);
     if ($class) {
         return $self;
     } else {
-        return wantarray ? ($id, $status) : $id;
+        return wantarray ? ( $id, $status ) : $id;
     }
 }
 
-
 =head2 id
 
 Returns the record id value.
@@ -230,8 +232,7 @@
 
 Internal helper to call L</current_user_can> with C<read>.
 
-Passes C<column> as a named parameter for the column the user is checking rights
-on.
+Passes C<column> as a named parameter for the column the user is checking rights on.
 
 =cut
 

Modified: jifty/trunk/lib/Jifty/Request.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Request.pm	(original)
+++ jifty/trunk/lib/Jifty/Request.pm	Thu Mar  8 17:06:55 2007
@@ -292,7 +292,7 @@
         
         $self->arguments->{$key} = $value;
 
-        # Continuation type is ofetn undef, so give it a sane default
+        # Continuation type is often undef, so give it a sane default
         # so we can use eq without warnings
         my $cont_type = $self->continuation_type || "";
 

Modified: jifty/trunk/lib/Jifty/Server.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Server.pm	(original)
+++ jifty/trunk/lib/Jifty/Server.pm	Thu Mar  8 17:06:55 2007
@@ -32,6 +32,11 @@
 
 =cut
 
+sub _send_http_status {
+      print STDOUT "HTTP/1.0 ".  (Jifty->handler->apache->{headers_out}->{'Status'} || '200 Jifty OK') .  "\n";
+};
+
+
 sub new {
     my $class = shift;
     my $self  = {};
@@ -40,11 +45,8 @@
     $self->recording_on if $ENV{'JIFTY_RECORD'};
 
     use Hook::LexWrap;
-    wrap 'HTML::Mason::FakeApache::send_http_header', pre => sub {
-        my $r = shift;
-        my $status = $r->header_out('Status') || '200 Jifty OK';
-        print STDOUT "HTTP/1.0 $status\n";
-    };
+    wrap 'HTML::Mason::FakeApache::send_http_header', pre => \&_send_http_status;
+    
 
     return ($self);
 

Modified: jifty/trunk/lib/Jifty/TestServer.pm
==============================================================================
--- jifty/trunk/lib/Jifty/TestServer.pm	(original)
+++ jifty/trunk/lib/Jifty/TestServer.pm	Thu Mar  8 17:06:55 2007
@@ -53,9 +53,20 @@
         $SIG{USR1} = sub { };
         sleep 15;
         $self->{started} = 1;
+        Jifty->handle->dbh->{'InactiveDestroy'} = 1;
         $Tester->ok(1, $text);
         # XXX: pull from jifty::config maybe
         return "http://localhost:".$self->port;
+    } else {
+        Jifty->handle->dbh->{'InactiveDestroy'} = 1;
+        # See DBI.pm: 
+        #
+        # This attribute is specifically designed for use in Unix applications
+        # that "fork" child processes. Either the parent or the child process,
+        # but not both, should set C<InactiveDestroy> true on all their shared handles.
+        # (Note that some databases, including Oracle, don't support passing a
+        # database connection across a fork.)
+        #
     }
 
     require POSIX;

Added: jifty/trunk/lib/Jifty/View/Declare.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/View/Declare.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,32 @@
+package Jifty::View::Declare;
+use Jifty::View::Declare::BaseClass ();
+
+use strict;
+use warnings;
+use constant BaseClass => 'Jifty::View::Declare::BaseClass';
+
+=head1 SYNOPSIS
+
+    package MyApp::View;
+    use Jifty::View::Declare -base;
+
+    template 'index.html' => page {
+        { title is 'Some Title' }
+        b { "The Index" };
+    };
+
+=cut
+
+sub import {
+    my ($class, $import) = @_;
+    ($import and $import eq '-base') or return;
+
+    no strict 'refs';
+    my $pkg = caller;
+    push @{ $pkg . '::ISA' }, BaseClass;
+
+    @_ = BaseClass;
+    goto &{BaseClass()->can('import')};
+}
+
+1;

Added: jifty/trunk/lib/Jifty/View/Declare/BaseClass.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/View/Declare/BaseClass.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,50 @@
+package Jifty::View::Declare::BaseClass;
+
+use strict;
+use warnings;
+use vars qw( $r );
+use base qw/Exporter Jifty::View::Declare::Helpers/;
+use Scalar::Defer;
+use Template::Declare::Tags;
+use Jifty::View::Declare::Helpers;
+
+our @EXPORT = (
+    @Jifty::View::Declare::Helpers::EXPORT,
+    @Template::Declare::Tags::EXPORT,
+);
+
+{
+    no warnings 'redefine';
+
+    sub show {
+        # Handle relative path here!
+
+        my $path = shift;
+        $path =~ s{^/}{};
+        Jifty::View::Declare::Helpers->can('show')->( $path, @_ );
+    }
+}
+
+
+
+1;
+__DATA__
+
+=head1 NAME
+
+Jifty::View::Declare::BaseClass
+
+=head1 DESCRIPTION
+
+This class provides a baseclass for your C<Template::Declare> derived view classes.
+
+
+=head1 METHODS
+
+=head2 show templatename arguments
+
+Render a C<Template::Declare> template.
+
+
+=cut
+

Added: jifty/trunk/lib/Jifty/View/Declare/CoreTemplates.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/View/Declare/CoreTemplates.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,346 @@
+package Jifty::View::Declare::CoreTemplates;
+
+use strict;
+use warnings;
+
+use Jifty::View::Declare -base;
+
+use Scalar::Defer;
+
+=head1 NAME 
+
+Jifty::View::Declare::CoreTemplates
+
+=head1 DESCRIPTION
+
+This library contains templates that Jifty can't function without:
+
+=over
+
+=item PubSub
+
+=item Validate
+
+=item Autocomplete
+
+=item Canonicalize
+
+=item YAML and XML webservice endpoints for core jifty functionality
+
+=cut
+
+template '__jifty/subs' => sub {
+    my ($forever) = get(qw(forever)) || 1;
+
+    Jifty->handler->apache->content_type("text/html; charset=utf-8");
+    Jifty->handler->apache->headers_out->{'Pragma'}        = 'no-cache';
+    Jifty->handler->apache->headers_out->{'Cache-control'} = 'no-cache';
+    Jifty->handler->apache->send_http_header;
+
+    my $writer = XML::Writer->new;
+    $writer->xmlDecl( "UTF-8", "yes" );
+
+    my $begin = <<'END';
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-strict.dtd">
+<html><head><title></title></head>
+END
+    chomp $begin;
+
+    if ($forever) {
+        my $whitespace = " " x ( 1024 - length $begin );
+        $begin =~ s/<body>$/$whitespace/s;
+    }
+
+    Jifty->web->out($begin);
+    $writer->startTag("body");
+
+    while (1) {
+        my $sent = _write_subs_once($writer);
+        flush STDOUT;
+        last if ( $sent && !$forever );
+        sleep 1;
+    }
+    $writer->endTag();
+    return;
+
+};
+
+sub _write_subs_once {
+    my $writer = shift;
+    Jifty::Subs::Render->render(
+        Jifty->web->session->id,
+        sub {
+            my ( $mode, $name, $content ) = @_;
+            $writer->startTag( "pushfrag", mode => $mode );
+            $writer->startTag( "fragment", id   => $name );
+            $writer->dataElement( "content", $content );
+            $writer->endTag();
+            $writer->endTag();
+        }
+    );
+}
+
+template '__jifty/autocomplete.xml' => sub {
+
+    # Note: the only point to this file is to set the content_type; the actual
+    # behavior is accomplished inside the framework.  It will go away once we
+    # have infrastructure for serving things of various content-types.
+    Jifty->handler->apache->content_type('text/xml; charset=UTF-8');
+    my $ref = Jifty->web->response->result('autocomplete')->content;
+    my @options = @{ $ref->{'completions'} || [] };
+    body {
+        ul {
+            foreach my $item (@options) {
+                if ( !ref($item) ) {
+                    li { $item };
+                }
+                elsif ( exists $item->{label} ) {
+                    li {
+                        with( class => "informal" ), span { $item->{label} };
+                        with( class => "hidden_value" ),
+                          span { $item->{value} };
+                    };
+                }
+                else {
+                    li { $item->{value} };
+                }
+            }
+        };
+    };
+};
+
+
+template '__jifty/validator.xml' => sub {
+    Jifty->handler->apache->content_type('text/xml; charset=UTF-8');
+    my $output = "";
+    use XML::Writer;
+    my $writer = XML::Writer->new( OUTPUT => \$output );
+    $writer->xmlDecl( "UTF-8", "yes" );
+    $writer->startTag("validation");
+    for my $ra ( Jifty->web->request->actions ) {
+        my $action = Jifty->web->new_action_from_request($ra);
+        $writer->startTag( "validationaction", id => $action->register_name );
+        for my $arg ( $action->argument_names ) {
+            if ( not $action->arguments->{$arg}->{ajax_validates} ) {
+                $writer->emptyTag( "ignored",
+                    id => $action->error_div_id($arg) );
+                $writer->emptyTag( "ignored",
+                    id => $action->warning_div_id($arg) );
+            }
+            elsif ( not defined $action->argument_value($arg)
+                    or length $action->argument_value($arg) == 0 )
+            {
+                $writer->emptyTag( "blank", id => $action->error_div_id($arg) );
+                $writer->emptyTag( "blank",
+                    id => $action->warning_div_id($arg) );
+            }
+            elsif ( $action->result->field_error($arg) ) {
+                $writer->dataElement(
+                    "error",
+                    $action->result->field_error($arg),
+                    id => $action->error_div_id($arg)
+                );
+                $writer->emptyTag( "ok", id => $action->warning_div_id($arg) );
+            }
+            elsif ( $action->result->field_warning($arg) ) {
+                $writer->dataElement(
+                    "warning",
+                    $action->result->field_warning($arg),
+                    id => $action->warning_div_id($arg)
+                );
+                $writer->emptyTag( "ok", id => $action->error_div_id($arg) );
+            }
+            else {
+                $writer->emptyTag( "ok", id => $action->error_div_id($arg) );
+                $writer->emptyTag( "ok", id => $action->warning_div_id($arg) );
+            }
+        }
+        $writer->endTag();
+        $writer->startTag( "canonicalizeaction", id => $action->register_name );
+        for my $arg ( $action->argument_names ) {
+            no warnings 'uninitialized';
+            if ( $ra->arguments->{$arg} eq $action->argument_value($arg) ) {
+
+                # if the value doesn' t change, it can be ignored .
+
+# canonicalizers can change other parts of the action, so we want to send all changes
+                $writer->emptyTag( "ignored",
+                    name => $action->form_field_name($arg) );
+            }
+            elsif ( not defined $action->argument_value($arg)
+                or length $action->argument_value($arg) == 0 )
+            {
+                $writer->emptyTag( "blank",
+                    name => $action->form_field_name($arg) );
+            }
+            else {
+                if ( $action->result->field_canonicalization_note($arg) ) {
+                    $writer->dataElement(
+                        "canonicalization_note",
+                        $action->result->field_canonicalization_note($arg),
+                        id => $action->canonicalization_note_div_id($arg)
+                    );
+                }
+                $writer->dataElement(
+                    "update",
+                    $action->argument_value($arg),
+                    name => $action->form_field_name($arg)
+                );
+            }
+        }
+        $writer->endTag();
+    }
+    $writer->endTag();
+    Jifty->web->out($output);
+};
+
+template '__jifty/webservices/xml' => sub {
+    my $output = "";
+    my $writer = XML::Writer->new(
+        OUTPUT => \$output,
+        UNSAFE => 1
+    );
+    $writer->xmlDecl( "UTF-8", "yes" );
+    $writer->startTag("response");
+    for my $f ( Jifty->web->request->fragments ) {
+
+        # Set up the region stack
+        local Jifty->web->{'region_stack'} = [];
+        my @regions;
+        do {
+            push @regions, $f;
+        } while ( $f = $f->parent );
+
+        for $f ( reverse @regions ) {
+            my $new =
+              Jifty->web->get_region( join '-',
+                grep { $_ } Jifty->web->qualified_region, $f->name );
+
+            # Arguments can be complex mapped hash values.  Get their
+            # real values by mapping.
+            my %defaults = %{ $f->arguments || {} };
+            for ( keys %defaults ) {
+                my ( $key, $value ) = Jifty::Request::Mapper->map(
+                    destination => $_,
+                    source      => $defaults{$_}
+                );
+                delete $defaults{$_};
+                $defaults{$key} = $value;
+            }
+
+            $new ||= Jifty::Web::PageRegion->new(
+                name           => $f->name,
+                path           => $f->path,
+                region_wrapper => $f->wrapper,
+                parent         => Jifty->web->current_region,
+                defaults       => \%defaults,
+            );
+            $new->enter;
+        }
+
+        # Stuff the rendered region into the XML
+        $writer->startTag( "fragment",
+            id => Jifty->web->current_region->qualified_name );
+        my %args = %{ Jifty->web->current_region->arguments };
+        $writer->dataElement( "argument", $args{$_}, name => $_ )
+          for sort keys %args;
+        $writer->cdataElement( "content",
+            Jifty->web->current_region->as_string );
+        $writer->endTag();
+
+        Jifty->web->current_region->exit while Jifty->web->current_region;
+    }
+
+    my %results = Jifty->web->response->results;
+    for ( keys %results ) {
+        $writer->startTag(
+            "result",
+            moniker => $_,
+            class   => $results{$_}->action_class
+        );
+        $writer->dataElement( "success", $results{$_}->success );
+
+        $writer->dataElement( "message", $results{$_}->message )
+          if $results{$_}->message;
+        $writer->dataElement( "error", $results{$_}->error )
+          if $results{$_}->error;
+
+        my %warnings = $results{$_}->field_warnings;
+        my %errors   = $results{$_}->field_errors;
+        my %fields;
+        $fields{$_}++ for keys(%warnings), keys(%errors);
+        for ( sort keys %fields ) {
+            next unless $warnings{$_} or $errors{$_};
+            $writer->startTag( "field", name => $_ );
+            $writer->dataElement( "warning", $warnings{$_} )
+              if $warnings{$_};
+            $writer->dataElement( "error", $errors{$_} )
+              if $errors{$_};
+            $writer->endTag();
+        }
+
+        # XXX TODO: Hack because we don't have a good way to serialize
+        # Jifty::DBI::Record's yet, which are technically circular data
+        # structures at some level (current_user of a
+        # current_user->user_object is itself)
+        use Scalar::Util qw(blessed);
+        my $content = $results{$_}->content;
+
+
+        $content = _stripkids($content);
+        use XML::Simple;
+        $writer->raw(
+            XML::Simple::XMLout(
+                $content,
+                NoAttr   => 1,
+                RootName => "content",
+                NoIndent => 1
+            )
+        ) if keys %{$content};
+
+        $writer->endTag();
+    }
+
+    $writer->endTag();
+    Jifty->handler->apache->content_type('text/xml; charset=UTF-8');
+
+    # For some reason, this line is needed, lest we end up outputting ISO-8859-1 text
+    utf8::decode($output);
+
+    outs_raw($output);
+};
+
+        sub _stripkids {
+            my $top = shift;
+            if ( not ref $top ) { return $top }
+            elsif (
+                blessed($top)
+                and (  $top->isa("Jifty::DBI::Record")
+                    or $top->isa("Jifty::DBI::Collection") )
+              )
+            {
+                return undef;
+            }
+            elsif ( ref $top eq 'HASH' ) {
+                foreach my $item ( keys %$top ) {
+                    $top->{$item} = _stripkids( $top->{$item} );
+                }
+            }
+            elsif ( ref $top eq 'ARRAY' ) {
+                for ( 0 .. $#{$top} ) {
+                    $top->[$_] = _stripkids( $top->[$_] );
+                }
+            }
+            return $top;
+        }
+
+
+template '__jifty/webservices/yaml' => sub {
+    Jifty->handler->apache->content_type("text/x-yaml");
+    outs( Jifty::YAML::Dump( { Jifty->web->response->results } ) );
+};
+
+
+1;
+1;

Added: jifty/trunk/lib/Jifty/View/Declare/Handler.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/View/Declare/Handler.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,70 @@
+package Jifty::View::Declare::Handler;
+
+use warnings;
+use strict;
+
+use base qw/Jifty::Object Class::Accessor/;
+use Template::Declare;
+
+
+__PACKAGE__->mk_accessors(qw/root_class/);
+
+=head1 NAME
+
+Jifty::View::Declare::Handler
+
+=head1 METHODS
+
+
+=head2 new
+
+
+Initialize C<Template::Declare>. Passes all arguments to Template::Declare->init
+
+=cut
+
+
+sub new {
+    my $class = shift;
+    my $self = {};
+    bless $self,$class;
+    Template::Declare->init(@_);
+    return $self;
+}
+
+
+=head2 show TEMPLATENAME
+
+Render a template. Expects that the template and any jifty methods called internally will end up being returned as a scalar, which we then print to STDOUT
+
+
+=cut
+
+sub show {
+    my $self          = shift;
+    my $template = shift;
+
+    no warnings qw/redefine utf8/;
+    local *Jifty::Web::out = sub {
+        shift;    # Turn the method into a function
+        goto &Template::Declare::Tags::outs_raw;
+    };
+    my $content =Template::Declare::Tags::show($template);
+        unless ( Jifty->handler->apache->http_header_sent ||Jifty->web->request->is_subrequest ) {
+            Jifty->handler->apache->send_http_header();
+        }
+    print STDOUT $content;
+    return undef;
+}
+
+=head2 template_exists TEMPLATENAME
+
+Given a template name, returns true if the template is in any of our Template::Declare template libraries. Otherwise returns false.
+
+=cut
+
+sub template_exists { my $pkg =shift;  
+
+return Template::Declare->resolve_template(@_);}
+
+1;

Added: jifty/trunk/lib/Jifty/View/Declare/Helpers.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/View/Declare/Helpers.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,366 @@
+use warnings;
+use strict;
+
+package Jifty::View::Declare::Helpers;
+
+use base qw/Exporter/;
+use Template::Declare::Tags;
+
+use base qw/Template::Declare/;
+our @EXPORT = (
+    qw(form hyperlink tangent redirect new_action form_submit form_next_page page wrapper request get set render_param current_user render_action render_region ),
+    @Template::Declare::Tags::EXPORT
+);
+
+
+=head1 NAME
+
+Jifty::View::Declare::Helpers
+
+=head1 DESCRIPTION
+
+This library provides mixins to help build your application's user interface.
+
+=head1 METHODS
+
+
+
+=cut
+
+{
+    no warnings qw/redefine/;
+
+
+=head2 form CODE
+
+Takes a subroutine reference or block of perl as its only argument and renders it as a Jifty C<form>. 
+Bug: you can't currently specify arguments to form->start.
+
+
+=cut
+
+    sub form (&) {
+        my $code = shift;
+        outs_raw( Jifty->web->form->start );
+        $code->();
+        outs_raw( Jifty->web->form->end );
+        return '';
+    }
+}
+
+=head2 hyperlink 
+
+Shortcut for L<Jifty::Web/link>.
+
+=cut
+
+sub hyperlink(@) {
+    outs_raw( Jifty->web->link(@_) );
+    return '';
+}
+
+=head2 tangent
+
+Shortcut for L<Jifty::Web/tangent>.
+
+=cut
+
+
+sub tangent(@) {
+    outs_raw( Jifty->web->tangent(@_) );
+    return '';
+}
+
+=head2 redirect
+
+Shortcut for L<Jifty::Web/redirect>.
+
+=cut
+
+sub redirect(@) {
+    Jifty->web->redirect(@_);
+    return '';
+}
+
+=head2 new_action
+
+Shortcut for L<Jifty::Web/new_action>.
+
+=cut
+
+sub new_action(@) {
+    return Jifty->web->new_action(@_);
+}
+
+
+=head2 render_region 
+
+A shortcut for Jifty::Web::PageRegion->new(@_)->render which does the
+Template::Declare magic necessary to not mix its output with your current
+page's.
+
+
+=cut
+
+sub render_region(@) {
+    unshift @_, 'name' if @_ % 2;
+    Template::Declare->new_buffer_frame;
+    Jifty::Web::PageRegion->new(@_)->render;
+    my $content = Template::Declare->buffer->data();
+    Template::Declare->end_buffer_frame;
+    Jifty->web->out($content);
+}
+
+
+=head2 render_action $action_object, $fields, $args_to_pass_to_action
+
+Renders an action out of whole cloth.
+
+Arguments
+
+=over 
+
+=item $action_object
+
+A Jifty::Action object which has already been initialized
+
+=item $fields
+
+A reference to an array of fields that should be rendered when
+displaying this action. If left undefined, all of the 
+action's fields will be rendered.
+
+=item $args_to_pass_to_action
+
+A hashref of arguments that should be passed to $action->form_field for
+every field of this action.
+
+=back
+
+
+=cut
+
+sub render_action(@) {
+    my ( $action, $fields, $field_args ) = @_;
+    my @f = $fields && @$fields ? @$fields : $action->argument_names;
+    foreach my $argument (@f) {
+        outs_raw( $action->form_field( $argument, %$field_args ) );
+    }
+}
+
+=head2 form_submit
+
+Shortcut for L<Jifty::Web::Form/submit>.
+
+=cut
+
+sub form_submit(@) {
+    outs_raw( Jifty->web->form->submit(@_) );
+    '';
+}
+
+=head2 form_next_page
+
+Shortcut for L<Jifty::Web::Form/next_page>.
+
+=cut
+
+
+sub form_next_page(@) {
+    Jifty->web->form->next_page(@_);
+}
+
+=head2 request
+
+Shortcut for L<Jifty::Web/request>.
+
+=cut
+
+sub request {
+    Jifty->web->request;
+}
+
+=head2 current_user
+
+Shortcut for L<Jifty::Web/current_user>.
+
+=cut
+
+
+sub current_user {
+    Jifty->web->current_user;
+}
+
+=head2 get args
+
+Returns arguments as set in the dispatcher or with L</set> below.
+If called in scalar context, pulls the first item in C<args> and returns it.
+If called in list context, returns the values of all items in C<args>.
+
+
+
+=cut
+
+sub get {
+    if (wantarray) {
+        map { request->argument($_) } @_;
+    } else {
+        request->argument( $_[0] );
+    }
+}
+
+
+=head2 set key => val [ key => val ...]
+
+Sets arguments for later grabbing with L<get>.
+
+
+=cut
+
+
+sub set {
+    while ( my ( $arg, $val ) = ( shift @_, shift @_ ) ) {
+        request->argument( $arg => $val );
+    }
+
+}
+
+=head2 render_param $action @args
+
+Takes an action and one or more arguments to pass to L<Jifty::Action->form_field>.
+
+=cut
+
+sub render_param {
+    my $action = shift;
+    outs_raw( $action->form_field(@_) );
+    return '';
+}
+
+=head2 page 
+
+ template 'foo' => page {{ title is 'Foo' } ... };
+
+Renders an HTML page wrapped in L</wrapper>, after calling
+"/_elements/nav" and setting a content type. Generally, you shouldn't
+be using "/_elements/nav" but a Dispatcher rule instead.
+
+=cut
+
+
+sub page (&) {
+    my $code = shift;
+    sub {
+        Jifty->handler->apache->content_type('text/html; charset=utf-8');
+        show('/_elements/nav');
+        wrapper($code);
+    };
+}
+
+
+=head2 wrapper $coderef
+
+Render a page. $coderef is a L<Template::Declare> coderef. 
+This badly wants to be redone.
+
+=cut
+
+
+sub wrapper ($) {
+    my $content_code = shift;
+
+    my ($title) = get_current_attr(qw(title));
+
+    my $done_header;
+    my $render_header = sub {
+        no warnings qw( uninitialized redefine once );
+
+        defined $title or return;
+        return if $done_header++;
+
+        Template::Declare->new_buffer_frame;
+        render_header($title);
+        $done_header = Template::Declare->buffer->data;
+        Template::Declare->end_buffer_frame;
+
+        '';
+    };
+
+    my $wrapped_content_code = sub {
+        no warnings qw( uninitialized redefine once );
+
+        local *is::title = sub {
+            shift;
+            $title = "@_";
+            &$render_header;
+        };
+
+        &$content_code;
+        if ( !$done_header ) {
+            $title = _("Untitled");
+            &$render_header;
+        }
+    };
+
+    body {
+        show('/_elements/sidebar');
+        with( id => "content" ), div {
+            with( name => 'content' ), a {};
+            if ( Jifty->config->framework('AdminMode') ) {
+                with( class => "warning admin_mode" ), div {
+                    outs( _('Alert') . ': ' );
+                    outs_raw(
+                        Jifty->web->tangent(
+                            label => _('Administration mode is enabled.'),
+                            url   => '/__jifty/admin/'
+                        )
+                    );
+                    }
+            }
+            Jifty->web->render_messages;
+            $wrapped_content_code->();
+
+            show('/_elements/keybindings');
+            with( id => "jifty-wait-message", style => "display: none" ),
+                div { _('Loading...') };
+
+# Jifty::Mason::Halo->render_component_tree if ( Jifty->config->framework('DevelMode') );
+
+           # This is required for jifty server push.  If you maintain your own
+           # wrapper, make sure you have this as well.
+            if (   Jifty->config->framework('PubSub')->{'Enable'}
+                && Jifty::Subs->list )
+            {
+                script { outs('new Jifty.Subs({}).start();') };
+            }
+        };
+    };
+
+    Template::Declare->buffer->data(
+        $done_header . Template::Declare->buffer->data );
+}
+
+
+=head2 render_header $title
+
+Renders an HTML "doctype", <head> and the first part of a page body. This bit isn't terribly well thought out and we're not happy with it.
+
+=cut
+
+sub render_header {
+    my ($title) = @_;
+    outs_raw(
+        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
+            . '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">' );
+    with( title => $title ), show('/_elements/header');
+    div {
+        { id is 'headers' }
+        hyperlink(
+            url   => "/",
+            label => _( Jifty->config->framework('ApplicationName') )
+        );
+        with( class => "title" ), h1 {$title};
+    };
+}
+
+1;

Modified: jifty/trunk/lib/Jifty/Web.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web.pm	(original)
+++ jifty/trunk/lib/Jifty/Web.pm	Thu Mar  8 17:06:55 2007
@@ -672,6 +672,7 @@
 
     # Clear out the mason output, if any
     $self->mason->clear_buffer if $self->mason;
+    Template::Declare->buffer->clear if(Template::Declare->buffer);
 
     my $apache = Jifty->handler->apache;
 

Modified: jifty/trunk/lib/Jifty/Web/Form.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form.pm	(original)
+++ jifty/trunk/lib/Jifty/Web/Form.pm	Thu Mar  8 17:06:55 2007
@@ -5,7 +5,7 @@
 
 use base qw/Jifty::Object Class::Accessor::Fast/;
 
-__PACKAGE__->mk_accessors(qw(actions printed_actions name call is_open disable_autocomplete));
+__PACKAGE__->mk_accessors(qw(actions printed_actions name call is_open disable_autocomplete target submit_to));
 
 =head2 new ARGS
 
@@ -39,6 +39,8 @@
     my %args = (
         name => undef,
         call => undef,
+        submit_to => undef,
+        target => undef,
         disable_autocomplete => undef,
         @_,
     );
@@ -70,6 +72,8 @@
     my $self = shift;
     my %args = (name => undef,
                 call => undef,
+                target => undef,
+                submit_to => undef,
                 disable_autocomplete => undef,
                 @_);
 
@@ -77,6 +81,8 @@
     $self->printed_actions( {} ) ;
     $self->name($args{name});
     $self->call($args{call});
+    $self->target($args{target});
+    $self->submit_to($args{'submit_to'});
     $self->disable_autocomplete($args{disable_autocomplete});
 }
 
@@ -184,8 +190,9 @@
         }
     }
 
-    my $form_start = qq!<form method="post" action="!  . Jifty->web->escape( $ENV{PATH_INFO} ) . qq!"!;
+    my $form_start = qq!<form method="post" action="!  . Jifty->web->escape( $self->submit_to || $ENV{PATH_INFO}) . qq!"!;
     $form_start .= qq! name="@{[ $self->name ]}"! if defined $self->name;
+    $form_start .= qq! target="@{[ $self->target ]}"! if defined $self->target;
     $form_start .= qq! autocomplete="off"!  if defined $self->disable_autocomplete;
     $form_start .= qq! enctype="multipart/form-data" >\n!;
     Jifty->web->out($form_start);

Modified: jifty/trunk/lib/Jifty/Web/Form/Clickable.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form/Clickable.pm	(original)
+++ jifty/trunk/lib/Jifty/Web/Form/Clickable.pm	Thu Mar  8 17:06:55 2007
@@ -326,7 +326,7 @@
 
 =head2 parameters
 
-Returns the generic list of parameters attached to the link as a hash.
+Returns the generic list of HTTP form parameters attached to the link as a hash.
 Use of this is discouraged in favor or L</post_parameters> and
 L</get_parameters>.
 

Modified: jifty/trunk/lib/Jifty/Web/Form/Field/Button.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form/Field/Button.pm	(original)
+++ jifty/trunk/lib/Jifty/Web/Form/Field/Button.pm	Thu Mar  8 17:06:55 2007
@@ -42,7 +42,7 @@
         '<input',
         'type="submit"',
         'name="' . $self->input_name . '" ',
-        'value="' . _($self->label ). '"',
+        'value="' . Jifty->web->escape(_($self->label )). '"',
         'id="'. Jifty->web->serial . '"',
         ($self->key_binding ? qq( accesskey="@{[$self->key_binding]}") : ''),
         $self->_widget_class('button', ($self->button_as_link ? ("button_as_link") : ())),

Modified: jifty/trunk/lib/Jifty/Web/PageRegion.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/PageRegion.pm	(original)
+++ jifty/trunk/lib/Jifty/Web/PageRegion.pm	Thu Mar  8 17:06:55 2007
@@ -321,6 +321,10 @@
     #XXX TODO: There's gotta be a better way to localize it
     my $region_content = '';
 
+    # template-declare based regions are printing to stdout
+    open my $output_fh, '>>', $out_method;
+    local *STDOUT = $output_fh;
+
     # Call into the dispatcher
     Jifty->handler->dispatcher->handle_request;
 

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/_elements/nav
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/_elements/nav	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,11 @@
+<%init>
+
+my $nav = Jifty->web->navigation->child("Administration" => url => '/__jifty/admin/');
+foreach my $model (Jifty->class_loader->models) {
+    next unless $model->isa('Jifty::Record');
+    next unless ($model =~ /^(?:.*)::(.*?)$/);
+    my $type = $1;
+    $nav->child($type   => url => '/__jifty/admin/model/'.$type);
+}
+return;
+</%init>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/action/dhandler
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/action/dhandler	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,27 @@
+<%init>
+my $action_class = Jifty->api->qualify($m->dhandler_arg);
+
+my $action = Jifty->web->new_action(
+    class   => $action_class,
+    moniker => "run-$action_class",
+);
+
+$action->sticky_on_failure(1);
+
+</%init>
+<&|/_elements/wrapper &>
+
+<% Jifty->web->form->start %>
+
+% for ($action->argument_names) {
+<% $action->form_field($_) %>
+% }
+
+<% Jifty->web->form->submit( label => _("Run the action") ) %>
+
+<% Jifty->web->form->end %>
+
+<h2>Done?</h2>
+<% Jifty->web->link( url => "/__jifty/admin/", label => _('Back to the admin console')) %>
+
+</&>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/autohandler
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/autohandler	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,10 @@
+<%init>
+
+# If "AdminMode" is turned off in Jifty's config file, don't let people at the admin UI.
+unless (Jifty->config->framework('AdminMode')) {
+    $m->redirect('/__jifty/error/permission_denied'); 
+    $m->abort();
+}
+$m->comp('_elements/nav');
+$m->call_next();
+</%init>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/header
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/header	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,61 @@
+<%args>
+$object_type
+$mask_val => ""
+$mask_field => ""
+$sort_by => ""
+$order => ""
+$list_path
+</%args>
+<%init>
+my $record_class = Jifty->app_class("Model", $object_type);
+my $record = $record_class->new();
+ my $update = Jifty->web->new_action(class => 'Update'.$object_type);
+</%init>
+<div class="jifty_admin_header">
+
+% foreach my $argument ($update->argument_names) {
+% unless( $argument eq $mask_field ||  $argument eq 'id' || $argument =~ /_confirm$/i
+%        && lc $update->arguments->{$argument}{render_as} eq 'password') {
+<span class="<% ($sort_by && !$order && $sort_by eq $argument)?'up_select':'up' %>">
+<%
+    Jifty->web->link(
+        label   => _("asc"),
+        onclick => 
+            { 
+            replace_with => $list_path.'list' ,
+            args   => {
+                object_type => $object_type,
+                limit_val => $mask_val,
+                limit_field => $mask_field,
+                list_path => $list_path,
+                sort_by => $argument,
+                order => undef
+                },
+            },
+        #as_button => 1
+        )
+%></span>
+<span class="<% ($sort_by && $order && $sort_by eq $argument )?'down_select':'down' %>">
+<%
+    Jifty->web->link(
+        label   => _("desc"),
+        onclick => 
+            {
+            replace_with => $list_path.'list',
+            args   => {
+                object_type => $object_type,
+                limit_val => $mask_val,
+                limit_field => $mask_field,
+                list_path => $list_path,
+                sort_by => $argument,
+                order => 'D'
+                },
+            },
+        #as_button => 1
+        )
+%></span>
+<span class="field"><% $argument %></span>
+% }
+% }
+<hr />
+</div>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/list
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/list	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,128 @@
+<%doc>
+
+You can copy this fragment directory to your app.
+And use it in a page like this :
+
+<% Jifty->web->region(name => "admin-subdomain",
+                      path => "/admin/fragments/list/list",
+                      defaults => { object_type => 'SubDomain',
+                                    list_path => '/admin/fragments/list/',
+                                    limit_field => 'domain',
+                                    limit_val => $domain,
+                                    search_slot => 0
+                                    per_page => 5,
+                                    render_submit => 1 }) %>
+
+limit_field, limit_val allow add to your sql query 
+ ... WHERE $limit_field = $limit_val
+so you can make "sub views" on a table limited by limit_field / limit_val
+
+</%doc>
+<%args>
+$object_type
+$page => 1
+$new_slot => 1
+$search_slot => 1
+$item_path => "/__jifty/admin/fragments/list/view"
+$list_path => "/__jifty/admin/fragments/list/"
+$limit_field => ""
+$limit_val => ""
+$per_page => 25
+$sort_by => undef
+$order => undef
+</%args>
+<%init>
+my $collection_class = Jifty->app_class("Model", $object_type."Collection");
+my $search = Jifty->web->response->result('search');
+my $collection = $collection_class->new();
+
+if(!$search) {
+   if ( $limit_field && $limit_val ) {
+      $collection->limit(column => $limit_field, value => $limit_val);
+   } else {
+      $collection->unlimit();
+   }
+   $collection->order_by(column => $sort_by, order=>'ASC') if ($sort_by && !$order);
+   $collection->order_by(column => $sort_by, order=>'DESC') if ($sort_by && $order);
+} else {
+    $collection = $search->content('search');
+    warn $collection->build_select_query;
+}
+
+$collection->set_page_info( current_page => $page,
+                            per_page     => $per_page
+                           );
+</%init>
+% if ($search_slot) {
+<%perl>    
+my $search_region = Jifty::Web::PageRegion->new(
+   name     => 'search',
+   path     => '/__jifty/empty',
+);
+</%perl>
+
+<% Jifty->web->link(
+    onclick => [{
+        region       => $search_region->qualified_name,
+        replace_with => $list_path.'search',
+        toggle       => 1,
+        args         => { object_type => $object_type }
+    },
+    ],
+    label => _('Toggle search')
+  )
+%>
+
+<% $search_region->render %>
+% }
+
+% if ($collection->pager->last_page > 1) {
+    <span class="page-count"><%_('Page %1 of %2', $page, $collection->pager->last_page) %></span>   
+% }
+
+<div class="list">
+% if ($collection->pager->total_entries == 0) {
+ <% _('No items found') %>
+% } else {
+  <% _('%1 entries', $collection-> count) %> 
+  <& $list_path.'header', object_type => $object_type, list_path => $list_path, 
+    mask_field => $limit_field, mask_val => $limit_val, sort_by => $sort_by, order => $order &>
+% }
+
+<%perl>
+while ( my $item = $collection->next ) {
+    Jifty->web->region(
+        name     => 'item-' . $item->id,
+        path     => $item_path,
+        defaults => { id => $item->id, object_type => $object_type, list_path => $list_path,
+                      mask_field => $limit_field , mask_val => $limit_val }
+    );
+}
+
+</%perl>
+</div>
+
+<div class="paging">
+% if ($collection->pager->previous_page) {
+<span class="prev-page">
+  <% Jifty->web->link( label => _("Previous Page"), onclick => { args => { page => $collection->pager->previous_page } } ) %>
+</span>
+% }
+% if ($collection->pager->next_page) {
+<span class="next-page">
+  <% Jifty->web->link( label => _("Next Page"), onclick => { args => { page => $collection->pager->next_page } } ) %>
+</span>
+% }
+</div>
+
+% if ($new_slot) {
+<% Jifty->web->region(
+        name => 'new_item',
+        path => $list_path.'new_item',
+        defaults => {   object_type => $object_type, list_path => $list_path,
+                     mask_field => $limit_field , mask_val => $limit_val },
+        ) %>
+
+% }
+
+

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/new_item
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/new_item	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,47 @@
+<%args>
+$object_type 
+$region
+$mask_field => ""
+$mask_val => ""
+$list_path
+</%args>
+<%init>
+my $record_class = Jifty->app_class("Model", $object_type);
+my $create = Jifty->web->new_action(class => 'Create'.$object_type);
+</%init>
+% if ($mask_field) {
+  <% $create->hidden($mask_field,$mask_val) %>
+% }
+<div class="jifty_admin create item inline">
+% foreach my $argument ($create->argument_names) {
+%  if ( $argument ne $mask_field ) {
+        <%$create->form_field($argument)%>
+%  }
+%}
+</div>
+<%
+
+Jifty->web->form->submit(
+    label    => _('Create'),
+    onclick  => [
+                 { submit => $create },
+                 { refresh_self => 1 },
+                 {
+                   element => $region->parent->get_element('div.list'),
+                   append => $list_path.'view',
+                   args   => { 
+                              object_type => $object_type,
+                              list_path => $list_path,
+                              id          => { result_of => $create, name => 'id' },
+                             },
+                 },
+                ]
+    ) %>
+
+<%doc>
+
+When you hit "save" and create a item, you want to put a fragment
+containing the new item in the associated list and refresh the current
+fragment
+
+</%doc>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/search
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/search	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,27 @@
+<%args>
+$object_type
+</%args>
+<%init>
+my $search = Jifty->web->new_action(
+    class             => "Search".$object_type,
+    moniker           => "search",
+    sticky_on_success => 1,
+);
+
+</%init>
+<div class="jifty_admin">
+% for my $arg ($search->argument_names) {
+ <% $search->form_field($arg) %>
+% }
+
+<% $search->button(
+    label   => _('Search'),
+    onclick => {
+        submit  => $search,
+        refresh => Jifty->web->current_region->parent,
+        args    => { page => 1}
+    }
+  )
+%>
+<hr />
+</div>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/update
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/update	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,52 @@
+<%args>
+$id => undef
+$object_type
+$mask_field => ""
+$mask_val => ""
+$list_path
+</%args>
+<%init>
+my $record_class = Jifty->app_class("Model", $object_type);
+my $record = $record_class->new();
+$record->load($id);
+my $update = Jifty->web->new_action(
+    class   => "Update".$object_type,
+    moniker => "update-" . Jifty->web->serial,
+    record  => $record
+);
+</%init>
+<div class="jifty_admin update item inline <%$object_type%>">
+<div class="editlink">
+  <% Jifty->web->link(
+      label   => _('Save'),
+      onclick => [
+          { submit => $update },
+          {   replace_with => $list_path.'view',
+              args         => { object_type => $object_type, id => $id, list_path => $list_path }
+          }
+      ]
+      ) %>
+
+  <% Jifty->web->link(
+      label     => _('Cancel'),
+      onclick   => {
+          replace_with => $list_path.'view',
+          args         => { object_type => $object_type, id => $id, list_path => $list_path }
+        },
+      as_button => 1
+  ) %>
+
+</div>
+
+% if ($mask_field) {
+<% $update->hidden($mask_field, $mask_val) %>
+% }
+% foreach my $argument ($update->argument_names) {
+%  if ( $argument ne $mask_field ) {
+<%$update->form_field($argument)%>
+%  }
+%}
+
+<hr />
+</div>
+

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/view
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/fragments/list/view	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,61 @@
+<%args>
+$id => undef
+$object_type
+$mask_field => ""
+$mask_val => ""
+$list_path
+</%args>
+<%init>
+my $record_class = Jifty->app_class("Model", $object_type);
+my $record = $record_class->new();
+$record->load($id);
+my $update = Jifty->web->new_action(
+    class   => "Update".$object_type,
+    moniker => "update-" . Jifty->web->serial,
+    record  => $record
+);
+my $delete = Jifty->web->new_action(
+    class   => "Delete".$object_type,
+    moniker => "delete-" . Jifty->web->serial,
+    record  => $record
+);
+
+</%init>
+<div class="jifty_admin read item inline">
+  
+<%
+    Jifty->web->form->submit(
+        class   => "editlink",
+        label   => _('Delete'),
+        onclick => [
+         { confirm => _("Confirm delete?")},
+         { submit => $delete },
+         { delete =>  Jifty->web->current_region->qualified_name }
+        ]
+        )
+%> 
+
+<%
+    Jifty->web->link(
+        label   => _('Edit'),
+        class   => "editlink",
+        onclick => {
+            replace_with => $list_path.'update',
+            args         => { object_type => $object_type, id => $id, list_path => $list_path,
+                            mask_field => $mask_field, mask_val => $mask_val }
+            },
+   #     as_button => 1
+        )
+%>
+
+<% $delete->hidden('id',$id) %>
+% foreach my $argument ($update->argument_names) {
+% unless( $argument eq $mask_field ||  $argument =~ /_confirm$/
+%        && lc $update->arguments->{$argument}{render_as} eq 'password') {
+  <%$update->form_field($argument, render_mode => 'read')%>
+% }
+% }
+
+<hr />
+</div>
+

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/index.html
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/index.html	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,31 @@
+<&| /_elements/wrapper, title => _('Jifty Administrative Console') &>
+
+<h1><% _('Database Administration') %></h1>
+
+<p><% _('This console lets you manage the records in your Jifty database. Below, you should see a list of all your database tables. Feel free to go through and add, delete or modify records.') %></p>
+
+<p><% _('To disable this administrative console, add "AdminMode: 0" under the "framework:" settings in the config file (etc/config.yml).') %></p>
+    
+<h2><% _('Models') %></h2>
+<ul>
+% foreach my $model (Jifty->class_loader->models) {
+% next unless $model->isa('Jifty::Record');
+% next unless ($model =~ /^(?:.*)::(.*?)$/);
+% my $type = $1;
+<li><% Jifty->web->link( url => '/__jifty/admin/model/'.$type, label => $type)%>
+%}
+</ul>
+
+<h2><% _('Actions') %></h2>
+<ul>
+% foreach my $action (Jifty->api->actions) {
+% Jifty::Util->require($action);
+% next if ( $action->can('autogenerated') and $action->autogenerated);
+<li><% Jifty->web->link( url => '/__jifty/admin/action/'.$action, label => $action) %></li>
+% }
+</ul>
+
+<h2><% _('Done?') %></h2>
+<% Jifty->web->return( to => "/", label => _('Back to the application')) %>
+
+</&>

Added: jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/model/dhandler
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/AdminUI/web/templates/__jifty/admin/model/dhandler	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,23 @@
+<%init>
+my $object_type = $m->dhandler_arg;
+
+my $collection_class =  Jifty->app_class("Model", $object_type."Collection");
+my $records = $collection_class->new();
+$records->unlimit;
+</%init>
+
+<&| /_elements/wrapper, title => _("Manage %1 records", $object_type) &>
+
+<h1><% _('Manage records:') %> <%$object_type%></h1>
+
+<% Jifty->web->form->start %>
+<% Jifty->web->region(name => "admin-$object_type",
+                      path => "/__jifty/admin/fragments/list/list", 
+                      defaults => { object_type => $object_type , 
+                                    render_submit => 1 }) %>
+<% Jifty->web->form->end %>
+
+<h2> <% _('Done?') %> </h2>
+<% Jifty->web->link( url => "/__jifty/admin/", label => _('Back to the admin console')) %>
+
+</&>

Modified: jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/index.html
==============================================================================
--- /jifty/trunk/share/web/templates/__jifty/online_docs/index.html	(original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/OnlineDocs/web/templates/__jifty/online_docs/index.html	Thu Mar  8 17:06:55 2007
@@ -10,8 +10,8 @@
 --></style>
 </head>
 <FRAMESET COLS="*, 250">
-    <FRAME src="./content.html" name="podcontent">
-    <FRAME src="./toc.html" name="podtoc">
+    <FRAME src="content.html" name="podcontent">
+    <FRAME src="toc.html" name="podtoc">
     <NOFRAMES>
         <a style="display: none" href="#toc"><%_('Table of Contents')%></a>
 <& content.html, Target => '' &>

Added: jifty/trunk/share/web/transform_templates
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/transform_templates	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,9 @@
+#!/usr/bin/perl 
+
+use warnings;
+use strict;
+
+my $lines = (join('',<STDIN>));
+$lines =~ s/\<(\w*?) (?:class="(.*?)")? (?:id="(.*?)")?\>/with { class => $2, id => $3 }, $1 { /g;
+print $lines;
+

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/Makefile.PL
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/Makefile.PL	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,7 @@
+use inc::Module::Install;
+
+name        'TestApp::Plugin::PasswordAuth';
+version     '0.01';
+requires    'Jifty' => '0.70117';
+
+WriteAll;

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/bin/jifty
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/bin/jifty	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,15 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use File::Basename qw(dirname); 
+use UNIVERSAL::require;
+
+BEGIN {
+    Jifty::Util->require or die $UNIVERSAL::require::ERROR;
+    my $root = Jifty::Util->app_root;
+    unshift @INC, "$root/lib" if ($root);
+}
+
+use Jifty::Script;
+local $SIG{INT} = sub { warn "Stopped\n"; exit; };
+Jifty::Script->dispatch();

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/etc/config.yml
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/etc/config.yml	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,58 @@
+--- 
+framework: 
+  AdminMode: 1
+  ApplicationClass: TestApp::Plugin::PasswordAuth
+  ApplicationName: TestApp-Plugin-PasswordAuth
+  ApplicationUUID: E6B4180A-C68F-11DB-893B-FEFB1AECF28B
+  Database: 
+    CheckSchema: 1
+    Database: testapp_plugin_passwordauth
+    Driver: SQLite
+    Host: localhost
+    Password: ''
+    RecordBaseClass: Jifty::DBI::Record::Cachable
+    User: ''
+    Version: 0.0.1
+  DevelMode: 1
+  L10N: 
+    PoDir: share/po
+  LogLevel: INFO
+  Mailer: Sendmail
+  MailerArgs: []
+
+  Plugins: 
+    - User: {}
+    - Authentication::Password: {}
+    - 
+      REST: {}
+
+    - 
+      Halo: {}
+
+    - 
+      OnlineDocs: {}
+
+    - 
+      CompressedCSSandJS: {}
+
+    - 
+      AdminUI: {}
+
+  PubSub: 
+    Backend: Memcached
+    Enable: ~
+  TemplateClass: TestApp::Plugin::PasswordAuth::View
+  Web: 
+    BaseURL: http://localhost
+    DataDir: var/mason
+    Globals: []
+
+    MasonConfig: 
+      autoflush: 0
+      default_escape_flags: h
+      error_format: text
+      error_mode: fatal
+    Port: 8888
+    ServeStaticFiles: 1
+    StaticRoot: share/web/static
+    TemplateRoot: share/web/templates

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FasterSwallow.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FasterSwallow.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,24 @@
+use strict;
+use warnings;
+
+package TestApp::Plugin::FasterSwallow;
+use base 'Jifty::DBI::Record::Plugin';
+use Jifty::DBI::Schema;
+use Jifty::DBI::Record schema {
+        column swallow_type => valid are qw(african european), default is 'african';
+    };
+
+
+sub register_triggers {
+    my $self = shift;
+    $self->add_trigger(name => 'before_create', callback => \&before_create, abortable => 1);
+}
+
+sub before_create {
+    my $self = shift;
+    my $args = shift;
+    return undef unless ($args->{'swallow_type'} eq 'african');
+    return 1;
+}
+
+1;

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FavoriteColor.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/FavoriteColor.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,40 @@
+use strict;
+use warnings;
+
+package TestApp::Plugin::FavoriteColor;
+use base 'Jifty::DBI::Record::Plugin';
+use Jifty::DBI::Schema;
+use Jifty::DBI::Record schema {
+        column color => type is 'text', default is 'Blue';
+    };
+
+
+
+sub register_triggers {
+    my $self = shift;
+    $self->add_trigger(name => 'validate_color', callback => \&validate_color, abortable => 1);
+    $self->add_trigger(name => 'canonicalize_color', callback => \&canonicalize_color, abortable => 0);
+}
+
+
+sub canonicalize_color {
+    my $self = shift;
+    my $color = shift;
+
+    if ($color eq 'grey') {
+        return 'gray';
+    }
+    return $color;
+
+}
+
+sub validate_color {
+    my $self = shift;
+    my $arg = shift;
+    return undef unless ($arg eq 'gray');
+    return 1;
+}
+
+
+
+1;

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Model/User.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/lib/TestApp/Plugin/PasswordAuth/Model/User.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+
+package TestApp::Plugin::PasswordAuth::Model::User;
+use Jifty::DBI::Schema;
+
+# Mixins
+
+use TestApp::Plugin::PasswordAuth::Record schema {
+
+};
+
+use Jifty::Plugin::User::Model::User;
+use TestApp::Plugin::FavoriteColor;
+use TestApp::Plugin::FasterSwallow;
+use Jifty::Plugin::Authentication::Password::Model::User 'password_is';
+
+# Your model-specific methods go here.
+
+1;
+

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,66 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+
+=head1 DESCRIPTION
+
+A basic test harness for the User model.
+
+=cut
+use lib 't/lib';
+use Jifty::SubTest;
+
+use Jifty::Test tests => 15;
+
+# Make sure we can load the model
+use_ok('TestApp::Plugin::PasswordAuth::Model::User');
+
+# Grab a system user
+my $system_user = TestApp::Plugin::PasswordAuth::CurrentUser->superuser;
+ok($system_user, "Found a system user");
+
+# Try testing a create
+my $o = TestApp::Plugin::PasswordAuth::Model::User->new(current_user => $system_user);
+my ($id) = $o->create( name => 'jesse',
+                       username => 'jrv',
+                       color => 'gray',
+                       swallow_type => 'african',
+                       password => 'secret');
+ok($id, "User create returned success");
+ok($o->id, "New User has valid id set");
+is($o->id, $id, "Create returned the right id");
+
+can_ok($o, 'name');
+
+is($o->name, 'jesse');
+ok(!$o->password, "Can't get the password");
+can_ok($o,'set_password');
+ok($o->password_is( 'secret'));
+is($o->color, 'gray');
+is ($o->swallow_type, 'african');
+
+
+my $p = TestApp::Plugin::PasswordAuth::Model::User->new(current_user => $system_user);
+ ($id) = $p->create( name => 'jesse2',
+                       username => 'jrv2',
+                       color => 'blue',
+                       swallow_type => 'african',
+                       password => 'secret');
+ok(!$id, "Users can't be created with the wrong favorite color");
+
+my $q = TestApp::Plugin::PasswordAuth::Model::User->new(current_user => $system_user);
+($id) = $p->create( name => 'jesse2',
+                       username => 'jrv2',
+                       color => 'gray',
+                       swallow_type => 'european',
+                       password => 'secret');
+ok(!$id, "Users can't be created if they don't know african swallow_types are faster");
+
+my $r = TestApp::Plugin::PasswordAuth::Model::User->new(current_user => $system_user);
+ ($id) = $r->create( name => 'jesse2',
+                       username => 'jrv2',
+                       color => 'grey',
+                       swallow_type => 'african',
+                       password => 'secret');
+ok($id, "Created with grey");
+

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/t/mailbox
==============================================================================

Added: jifty/trunk/t/TestApp-Plugin-PasswordAuth/var/mason/obj/.__obj_create_marker
==============================================================================

Added: jifty/trunk/t/TestApp/lib/TestApp/View.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp/lib/TestApp/View.pm	Thu Mar  8 17:06:55 2007
@@ -0,0 +1,20 @@
+package TestApp::View;
+use warnings;
+use strict;
+
+use Jifty::View::Declare -base;
+
+template 'concrete2.html' => sub  {
+   html {
+   body {
+    h1 { _( 'I have %1 concrete mixers', 2) };
+    }
+    }
+};
+
+
+template 'die.html' => sub {
+    die "this is an error";
+};
+
+1;

Modified: jifty/trunk/t/TestApp/t/i18n-standalone.t
==============================================================================
--- jifty/trunk/t/TestApp/t/i18n-standalone.t	(original)
+++ jifty/trunk/t/TestApp/t/i18n-standalone.t	Thu Mar  8 17:06:55 2007
@@ -5,7 +5,7 @@
 use lib 't/lib';
 use Jifty::SubTest;
 
-use Jifty::Test tests => 16;
+use Jifty::Test tests => 20;
 use Jifty::Test::WWW::Mechanize;
 use Net::HTTP;
 use URI;
@@ -32,6 +32,10 @@
 ok $res->is_success, "can access concrete";
 like $res->content, qr/2 concrete mixers/, 'en works for an unknown string';
 
+$res = $ua->get("$base/concrete2.html");
+ok $res->is_success, "can access concrete";
+like $res->content, qr/2 concrete mixers/, 'en works for an unknown string';
+
 $ua->default_header('Accept-Language' => "ja");
 $res = $ua->get("$base/__jifty/admin/");
 ok $res->is_success, "can access admin console";
@@ -41,6 +45,10 @@
 ok $res->is_success, "can access concrete";
 like $res->content, qr/2 concrete mixers/, 'ja works for an unknown string';
 
+$res = $ua->get("$base/concrete2.html");
+ok $res->is_success, "can access concrete";
+like $res->content, qr/2 concrete mixers/, 'en works for an unknown string';
+
 $ua->default_header('Accept-Language' => "fr");
 $res = $ua->get("$base/__jifty/admin/");
 ok $res->is_success, "can access admin console";


More information about the Jifty-commit mailing list