<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="chrome://global/skin/" type="text/css"?><?xml-stylesheet href="takahashi.css" type="text/css"?><page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="presentation" xmlns:html="http:/www.w3.org/1999/xhtml" orient="vertical" onkeypress="Presentation.onKeyPress(event);">
<html:textarea id="builtinCode" style="visibility: collapse">

&#9832; Jifty
----
Jesse Vincent

Best Practical 
----
We 
Make 
RT
----
We 
Make
SVK
----
We
Make
Jifty
----
 Java
  
  
  
                 
----
 Java
 Integration
  
  
                 
----
 Java
 Integration
 Framework
  
                 
----
 Java
 Integration
 Framework
 Toolkit
                 
----
 Java
 Integration
 Framework
 Toolkit
 Yes, I'm kidding
----
Jifty
----
Silver
Bullet
----
Ok. I'm
Lying
----
Tool
----
Web App
Framework
----
Hides the
Complexity
----
Jifty
is
JFDI
----
Lets you
JFDI
----
Let's 
JFDI
----
Demo
App
----
Let's set
it up
----
{{img src="npw.2006/jifty_app.png" width="552" height="364"}}
----
Lots of
directories
---- 
Three 
files
---- 
{{img src="npw.2006/jifty_3_files.png" width="552" height="364"}}
----
It runs!
----
{{img src="npw.2006/jifty_web_1.png" width="800" height="622"}}
----
(Not a very
good blog)
----
Good blogs 
have entries
----
{{img src="npw.2006/jifty_model.png" width="552" height="364"}}
----
{{img src="npw.2006/jifty_edit_model.png" width="552" height="364"}}
----
{{img src="npw.2006/jifty_schema_setup.png" width="552" height="364"}}
----
{{img src="npw.2006/jifty_server.png" width="552" height="364"}}
----
{{img src="npw.2006/jifty_web_1.png" width="800" height="622"}}
----
{{img src="npw.2006/jifty_web_dbadmin.png" width="800" height="622"}}
----
{{img src="npw.2006/jifty_web_crud_new.png" width="800" height="622"}}
----
{{img src="npw.2006/jifty_web_crud_edit.png" width="800" height="622"}}
----
{{img src="npw.2006/jifty_web_crud_create_2.png" width="800" height="622"}}
----
{{img src="npw.2006/jifty_web_crud_edited.png" width="800" height="622"}}
----
Nice
----
Not a
weblog
----
{{#i|./lib/Blog/Dispatcher.pm}}
----
 package Blog::Dispatcher;
 use Jifty::Dispatcher -base;
 
 before '*' => run {
    my $top = Jifty->web->navigation;
    $top->child('List Entries' => url => '/'); 
    $top->child('New Entry'    => url => '/new_entry');
 }
----
 on '/' => run {
     my $entries = 
        Blog::Model::EntryCollection->new();
     $entries->unlimit();
 
     set entries => $entries;
 };
---- 
 on '/new_entry' => run {
     set create => Jifty->web->new_action(
         class => 'CreateEntry'
     );
 };
----
{{#i|./web/templates/new_entry}}
----
{{img src="npw.2006/new_entry.png" width="707" height="476"}}
----
 &lt;%ARGS>
 $create # From the dispatcher
 &lt;/%ARGS>
 &lt;&amp;|/_elements/wrapper, 
    title => 'Create an article' &amp;>
 &lt;% Jifty->web->form->start %>
 % foreach my $arg ($create->argument_names) {
 &lt;% $create->form_field($arg) %>
 % }
 &lt;% Jifty->web->form->submit( label => 'Save' ) %>
 &lt;% Jifty->web->form->end %>
 &lt;/&amp;>
----
{{#i|./web/templates/index.html}}
----
{{img src="npw.2006/blog.png" width="707" height="476"}}
----
 &lt;%ARGS>
 $entries # From the dispatcher
 &lt;/%ARGS>
 &lt;&amp;|/_elements/wrapper&amp;>
 % while (my $entry = $entries->next) {
  &lt;h2>&lt;% $entry->title %>&lt;/h2>
  &lt;div class="body">
    &lt;% $entry->body %>
  &lt;/div>
 % }
 &lt;/&amp;>
----
  Your files:

 lib/Blog/Model/Entry.pm
 lib/Blog/Dispatcher.pm
 web/templates/new_entry
 web/templates/index.html
----
All Done!
----
It runs
----
Ship it
----
Oh wait
----
(There's always 
an "Oh wait")
----
I'm from the US
----
New law
----
...banning profanity
----
(We need to protect
the children!)
----
From the
Internet
----
So, we need to
censor blogs
----
No problem!
----
(Except the political one)
----
Back to the code!
----
 # vi lib/Blog/Model/Entry.pm

 use Regexp::Common 'profanity_us';

 sub validate_body {
    my $self = shift;
    my $body = shift;
    if ( $body =~ /$RE{profanity}/i) {
        return
         (0, 'Would you speak like that in front of your mother? *cough*')
    }
    return (1, "OK");
 }
----
{{img src="npw.2006/validate_entry.png" width="707" height="476"}}
----
Not 
good 
enough
----
Stops people 
from blogging
----
Clean it up 
directly
----
 # vi lib/Blog/Model/Entry.pm

 sub canonicalize_body {
    my $self = shift;
    my $body = shift;
    $body =~ s/$RE{profanity}/**expletives**/gi;
    return $body;
 }

----
{{img src="npw.2006/canonicalize_entry.png" width="707" height="476"}}
----
(Autocompleters
work the same)
----
{{#i|now}} we
ship it
----
{{#tag|Anatomy of a}}
{{#tag|Jifty app}}
----
 {{#i|Schema (Model)}}
 {{#i|Actions (Controller)}}
 {{#i|Dispatcher (Kernel) }}
 {{#i|ClassLoader (Bootloader)}}
 {{#i|Continuations (Job Control)}}
 {{#i|Templates and Fragments (View)}}
----
{{#tag|Schema (Model)}}
----
Jifty::DBI
----
 {{#i|Data}}
 {{#i|Model}}
 {{#i|Management}}
----
No more...
----
CREATE TABLE
----
ALTER TABLE
----
CREATE FOREIGN KEY
----
{{#i|Object}}
{{#i|Relational}}
{{#i|Mapper}}
----
No more...
----
SELECT
----
INSERT
----
UPDATE
----
DELETE
----
Inside
{{#i|Jifty::DBI}}
----
Three object types
----
 - Handles
 - Records
 - Collections
----
{{#i|Jifty::DBI::Handle}}
----
Database 
independence
----
SQLite
----
Postgres
----
MySQL
----
Oracle
----
(Oracle's still a bit broken)
----
{{#i|Jifty::DBI::Record}}
----
Records == 
Database Rows
----
{{#i|Declarative Syntax}}
----
Remember
our blog?
----
Time for
0.0.2
----
 package Blog::Model::Comment::Schema;
 since '0.0.2';
 column entry => refers_to Blog::Model:Entry;
 column author => refers_to Blog::Model::User;
 column body =>
    label is 'Content',
    type is 'text',
    render as 'Textarea',
    default is 'First Post!';
----
 column title =>
    label is 'Title',
    length is 40,
    hints is '40 bytes max',
    is mandatory;
----
Database
upgrades
suck  
----
Database
upgrades
sucked
----
Jifty 
provides
help
----
 # vi etc/config.yml (Set version to 0.0.2)

 # jifty server

 Application schema version in database (v0.0.1) doesn't match 
 application schema version (0.0.2)
 Please run `bin/jifty schema --setup` to upgrade the database.

----

 # jifty schema --setup 

 Jifty version 0.605070 up to date.
 INFO - Gerating SQL to upgrade Blog v0.0.1 database to v0.0.2
 INFO - Upgraded to version v0.0.2

 # jifty server
 INFO - You can connect to your server at http://localhost:8888/

----
 column tags =>
    since '0.0.3',
    refers_to Blog::Model::TagCollection by 'entry';
----
 column mood => 
    since '0.0.4',
    default is => 'happy',
    valid_values are     
        { display => 'Sad',   value => 'sad' },
        { display => 'Happy', value => 'happy' };
----
 column created =>
    since '0.0.5',
    is immutable,    
    type is 'timestamp',
    default is literal 'now()',
    filters are 'Jifty::DBI::Filter::DateTime';

----
Two-step
upgrade
----
 # vi etc/config.yml

 (Bump the version to 0.0.5)

 # jifty schema --setup 
----
Jifty::DBI
caches, too!
----
Single Process
{{#i|Cache::Simple::TimedExpirey}}
----
Multi-Host
{{#i|Cache::Memcached}}
----
{{#i|Jifty::DBI::Collection}}
----
Joins
----
Paging
{{#i|Data::Page}}
----
{{#tag|Actions (Controller)}}
----
Actions are 
APIs to your app
----
(You might call them
a facade over your code)
----
Actions define
method calls
----
Actions takes 
typed arguments 
----
Action return
 results
----
Actions are 
Web Services
----
Getting started 
with actions
----
Jifty provides three 
actions for each of 
your model classes
----
 - Create
  (Blog::Action::CreateEntry)
 - Update
  (Blog::Action::UpdateEntry)
 - Delete
   (Blog::Action::DeleteEntry)
----
Just extend 
(subclass) 
the defaults
----
If we had more time, 
we'd show you that 
every action is made of:
----
 sub arguments {}
----
 sub validate_arguments {}
----
 sub take_action {}
----
{{#tag|Jifty::Dispatcher (Kernel)}}
(See Audrey at OSCON!)
----
Simple
----
Declarative
----
Three 
stages
----
 - before
 - on
 - after
----
Before:
sets up your state
----
On: 
shows your pages
----
After: 
cleans your state
----
{{#tag|Jifty::ClassLoader (Bootloader)}}
----
I hate
scaffolds
----
They're 
ugly
----
They're
redundant
----
They're
annoying
----
Why have
{{#i|empty}}
classes?
----
Enter
{{#i|Jifty::ClassLoader}}
----
Autocreates
----
Blog
----
Blog::Record
----
Blog::Collection
----
Blog::Model::EntryCollection
Blog::Model::CommentCollection
----
Blog::Action::{Create,Update,Delete}Entry
Blog::Action::{Create,Update,Delete}Comment
----
Blog::Bootstrap
----
Blog::Upgrade
----
Blog::Dispatcher
----
Blog::CurrentUser
----
{{#tag|Continuations (Job Control)}}
----
Continuations?
In Perl?
----
Isn't that
impossible?
----
I don't 
know
----
Ours
are
fake
----
Well,
kind of
fake
----
Continuations
serialize
the world
----
App state...
----
Your
%ENV...
----
Your 
DBI handle...
----
Your
log handle...
----
Phase of
the moon
----
Maybe we don't 
need all that
----
Jifty::Continuations
serialize your app's
request state
----
That's all
you need
----
Why continuations?
----
They make your
life better
----
The web is built on
----
GOTO
----
Do you {{#i|like}}
----
GOTO?
----
Continuations 
give you
----
GOSUB
----
Welcome to
civilization
----
Back to 
our Blog
----
Requiring
Login
----
{{#i|Blog::Dispatcher}}
----
 ## Auth and login
 before '*' => run {
     if (not Jifty->web->current_user->id ) {
        Jifty->web->tangent(url => '/login');
     }
 };
----
{{#i|share/web/templates/login}}
----
 &lt;%init>
 my $action = Jifty->web->new_action(class => 'Login', moniker => 'loginbox' );
 &lt;/%init>
 &lt;&amp;|/_elements/wrapper,
     title => 'Login' &amp;>
 &lt;h2>Login&lt;/h2>
  &lt;% Jifty->web->form->start() %>
    &lt;% $action->form_field('address') %>
    &lt;% $action->form_field('password') %>
    &lt;% Jifty->web->return( label => 'Login') %>
  &lt;% Jifty->web->form->end %>
 &lt;/&amp;>

~ call => Jifty->web->request->continuation) %>
~ alexmv, do we need this in form->start?
----
Didn't show:
{{#i|Blog::Action::Login}}
----
{{#tag|Templates and Fragments (View)}}
----
Mason
----
(TT Coming Soon?)
----
Mason Provides
"Components"
----
Server-side 
inclusion
----
Not very 
Web 2.0,
 is it?
----
Welcome to
fragments
----
Just like
components...
----
With a
twist
----
Client side
inclusion
----
(for AJAX/AHAH)
----
Server Side
inclusion
----
(remember lynx?)
----
(or your phone)
----
Don't worry
----
No      
special
setup
----
Not much
special
setup
----
Instead of
----
 &lt;&amp; /fragments/page_of_posts &amp;>
----
You write
----
 &lt;% Jifty->web->region(
	name => "myweblog-posts",
        path => "/fragments/page_of_posts") 
 %>
----
Then
you're
done
----
{{#tag|DEVELOPMENT}}
{{#tag|TOOLS}}
----
Standalone Server
{{#i|HTTP::Server::Simple}}
----
{{#i|Module::Install}}
{{img src="npw.2006/makefile_pl.png" width="552" height="364"}}
----
Halos
----
Template 
Profiling
----
SQL Logging
----
SQL Profiling
----
View Introspection
----
Online Editing
----
{{img src="npw.2006/halo.png" width="428" height="391"}}
----
{{img src="npw.2006/halo2.png" width="468" height="665"}}
----
{{#i|Module::Refresh}}
----
Magic Profiling
----
Devel Mode
----
Online Docs
----
{{img src="npw.2006/online_docs.png" width="800" height="622"}}
----
{{#tag|DEPLOYMENT}}
----
Run 
fast
----
FastCGI
(Apache or
lightttpd)
----
Memcached
----
I18N
----
{{#i|CSS::Squish}}
----
{{#i|JS::Crunch}}
(Coming soon)
----
Jifty::Web::Session
(Designed for AJAX)
---- 
{{#tag|THE FUTURE}}
----
Wiki-style
UI Editor
----
Even less
code
----
More
docs
----
Sample
apps
----
"Jifty in a Jiffy"
movies and
music videos
----
{{#tag|GET JIFTY}}
----
 cpan Jifty
----
 svn co
   http://svn.jifty.org/svn/jifty.org
----
 http://jifty.org/
----
Getting started?
----
 perldoc Jifty::Manual::Tutorial
----
 #jifty on freenode.net
----
 jifty-devel@lists.jifty.org
</html:textarea>
<deck flex="1" id="deck">
<vbox flex="1" onmousemove="Presentation.onMouseMoveOnCanvas(event);">
<toolbox id="canvasToolbar">
<toolbar>
<toolbarbutton oncommand="Presentation.home()" label="|&lt;&lt;" observes="canBack"/>
<toolbarbutton oncommand="Presentation.back()" label="&lt;" observes="canBack"/>
<toolbarbutton oncommand="Presentation.forward()" label="&gt;" observes="canForward"/>
<toolbarbutton oncommand="Presentation.end()" label="&gt;&gt;|" observes="canForward"/>
<toolbarseparator/>
<hbox align="center">
<textbox id="current_page" size="4" oninput="if (this.value) Presentation.showPage(parseInt(this.value)-1);"/>
<description value="/"/>
<description id="max_page"/>
</hbox>
<toolbarseparator/>
<vbox flex="2">
<spacer flex="1"/>
<scrollbar id="scroller" align="center" orient="horizontal" oncommand="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));" onclick="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));" onmousedown="Presentation.onScrollerDragStart();" onmousemove="Presentation.onScrollerDragMove();" onmouseup="Presentation.onScrollerDragDrop();"/>
<spacer flex="1"/>
</vbox>
<toolbarseparator/>
<spacer flex="1"/>
<toolbarseparator/>
<toolbarbutton id="toggleEva" label="Eva" type="checkbox" autoCheck="false" oncommand="Presentation.toggleEvaMode();"/>
<toolbarseparator/>
<toolbarbutton label="Edit" oncommand="Presentation.toggleEditMode();"/>
<toolbarbutton oncommand="Presentation.reload();" label="Reload"/>
</toolbar>
</toolbox>
<vbox flex="1" id="canvas" onclick="Presentation.onPresentationClick(event);">
<spacer flex="1"/>
<hbox flex="1">
<spacer flex="1"/>
<vbox id="content">
</vbox>
<spacer flex="1"/>
</hbox>
<spacer flex="1"/>
</vbox>
</vbox>
<vbox flex="1" id="edit">
<toolbox>
<toolbar>
<toolbarbutton label="New Page" oncommand="Presentation.addPage()"/>
<spacer flex="1"/>
<toolbarseparator/>
<toolbarbutton label="View" oncommand="Presentation.toggleEditMode();"/>
<toolbarbutton oncommand="Presentation.reload();" label="Reload"/>
</toolbar>
</toolbox>
<textbox id="textField" flex="1" multiline="true" oninput="Presentation.onEdit()"/>
<hbox collapsed="true">
<iframe id="dataLoader" onload="if (window.Presentation) Presentation.onDataLoad();"/>
</hbox>
</vbox>
</deck>
<broadcasterset>
<broadcaster id="canBack"/>
<broadcaster id="canForward"/>
</broadcasterset>
<commandset>
<command id="cmd_forward" oncommand="if (Presentation.isPresentationMode) Presentation.forward();"/>
<command id="cmd_back" oncommand="if (Presentation.isPresentationMode) Presentation.back();"/>
<command id="cmd_home" oncommand="if (Presentation.isPresentationMode) Presentation.home();"/>
<command id="cmd_end" oncommand="if (Presentation.isPresentationMode) Presentation.end();"/>
</commandset>
<keyset>
<key key=" "      command="cmd_forward"/>
<key keycode="VK_ENTER"      command="cmd_forward"/>
<key keycode="VK_RETURN"     command="cmd_forward"/>
<key keycode="VK_PAGE_DOWN"  command="cmd_forward"/>
<key keycode="VK_RIGHT"      command="cmd_forward"/>
<key keycode="VK_DOWN"       command="cmd_forward"/>
<!--key keycode="VK_BACK_SPACE" command="cmd_back"/-->
<key keycode="VK_UP"    command="cmd_back"/>
<key keycode="VK_PAGE_UP"    command="cmd_back"/>
<!--
<key keycode="VK_BACK_UP"    command="cmd_back"/>-->
<!--
<key keycode="VK_BACK_LEFT"  command="cmd_back"/>-->
<key keycode="VK_HOME"       command="cmd_home"/>
<!--
<key keycode="VK_END"        command="cmd_end"/>-->
<key key="n" modifiers="accel" oncommand="Presentation.addPage();"/>
<key key="r" modifiers="accel" oncommand="window.location.reload();"/>
<key key="e" modifiers="accel" oncommand="Presentation.toggleEditMode();"/>
<key key="a" modifiers="accel" oncommand="Presentation.toggleEvaMode();"/>
</keyset>
<script src="takahashi.js" type="application/x-javascript" />
</page>

<!-- ***** BEGIN LICENSE BLOCK *****
   - Version: MPL 1.1
   -
   - The contents of this file are subject to the Mozilla Public License Version
   - 1.1 (the "License"); you may not use this file except in compliance with
   - the License. You may obtain a copy of the License at
   - http://www.mozilla.org/MPL/
   -
   - Software distributed under the License is distributed on an "AS IS" basis,
   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   - for the specific language governing rights and limitations under the
   - License.
   -
   - The Original Code is the Takahashi-Method-based Presentation Tool in XUL.
   -
   - The Initial Developer of the Original Code is SHIMODA Hiroshi.
   - Portions created by the Initial Developer are Copyright (C) 2005
   - the Initial Developer. All Rights Reserved.
   -
   - Contributor(s): SHIMODA Hiroshi <piro@p.club.ne.jp>
   -
   - ***** END LICENSE BLOCK ***** -->


