The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
<!DOCTYPE html>
<html>
  <!-- TODO: rewrite this with templates and new info -->
  <head>
    <title>Yote</title>
    <script src="/yote/js"></script>

    <script src="/js/main.js"></script>

    <link href="/yote.css" rel="stylesheet" type="text/css" media="all" />
    <link href="/css/main.css" rel="stylesheet" type="text/css" media="all" />

    <META NAME="Author" CONTENT="Eric Wolf, coyocanid@gmail.com">

    <STYLE>
      .overlesson { min-width: 900px; display:inline;}
      .sample    { border: 0; }
      .sidebar   { top:0px; width:200px; display:inline-block; vertical-align:top; }
      .mainpanel { top:0px; width:700px; display:inline-block; }
      .sample td { height: auto; vertical-align:middle; }

      .code_box  { margin-top:25px; }
      .server_col { border:ridge 4px lightblue; padding: 5px; background-color: #E1EEED; }
      .javascript_col { border:ridge 4px lightblue; padding: 5px; background-color: #E1EEED; }
      .html_col { border:ridge 4px lightblue; padding: 5px; background-color: #E1EEED; }

      .uc_title   { margin-top:20px; font-family: sans-serif; font-size: large; border-top : solid 3px rgb(0, 238, 119); }
      .uc_body    { font-family: serif; padding:5px 25px 25px 25px;  }
      .body_code  { background-color : rgba( 255,255,255,.3 ); }
      .faint      { font-style:bold; color : rgba( 0,0,0,.6 ); font-size: small; }
    </STYLE>

    <script>
    $().ready(function(){

	$.yote.init();

	make_menus( '#top_nav' );

	var sample_template =
	    {
		title             : '',
		summary           : '',
		use_cases         : [],
		html              : '',
		javascript        : '',
		server            : '',
		discussion        : '',
		server_discussion : '',
		client_discussion : ''
	    };

	var samples = [
	    {
		title             : 'Web Counter',
		summary           : 'A simple counter that increments each time a page is served.',
		use_cases         : [ 'Increment the number of times the page (given by name) has been seen and return this number.' ],
		html              : '\
&lt;DIV&gt;This page has been viewed &lt;SPAN id="counter_span"&gt; times.&lt;/DIV&gt;\
',
		javascript            : 'var page_counter = $.yote.fetch_app("Yote::Util::Counter");\n\n\
page_counter.increment(\n\
   "My Page", // sent as the argument to the server\n\
   function( count ) { // handler for success \n\
     $("#counter_span").empty().append( count );\n\
   },\n\
   function( err ) { // handler for fail \n\
       console.log( "Count got error " + err );\n\
   },\n\
   true // async \n\
);',
		server            : 'package Yote::Util::Counter;\n\
\n\
use strict;\n\
\n\
use base "Yote::AppRoot";\n\
\n\
sub increment {\n\
    my( $self, $page_name ) = @_;\n\
    my $count = $self->get__counts( {} )->{$page_name} + 1; \n\
    $self->get__counts()->{$page_name} = $count; \n\
    return $count;\n\
}\n\
\n\
1;',
		discussion        : 'This simple example does not take IP origin into account. \
The IP is passed in to all yote methods as part of the environment hash reference passed in as the fourth argument.',

		server_discussion : 'The call <code>get__counts( {} )</code> ensures that the <code>_counts</code> variable is populated.\
Under the hood, Yote has a single process that runs calculations or updates the database, so there can not be two page hits that update the \
count to the same value.\
',

		client_discussion : 'The client is being called asyncronously. The second argument is the handler for when this completes.\
It is given the return value as a single parameter. The third argument is for a handler for the error case. The error message\
is given as the single parameter for this case.'
	    },



	    {
		title             : 'To Do App',
		summary           : '<P>A simple to do app that shows one thing to do at a time. The user has the choice of marking that \
item complete or asking for a different item which is picked randomly.<p>\
<p\>The task has 5 use cases and when those are completed in the order shown below, the task will be complete, except for the surrounding css, html and calls \
to get the javascript files.\
</P>',
		use_cases         : [
		    { title : 'Give a new user a task when they sign into this app the first time.',
		      body  : '<code><h4>Server Side</h4><pre class="body_code">\
package Yote::Util::Todo;\n\
use strict;\n\
use base "Yote::AppRoot"\n\
sub _init_account {  \n\
  my( $self, $account ) = @_;\n\
\n\
  my $first_todo_item = "Enter todo items";\n\
  $account->set_current_todo( $first_todo_item ); \n\
  $account->add_to_my_todos( $first_todo_item ); \n\
}\n\
\n\
1;</pre></code><p>For this use case, we will define the app class for todo items and write the code to assign the first task to a new user account.\
If this class is in Perl\'s classpath, Yote will create a singleton app object for it which can be called on the client using <code>fetch_app</code>.\
</P><p>\
When the user uses any app for the first time, an account objects specific to that user and this app is created and the <code>_init_account</code> method on the app is fired\
and passed a reference to the newly created account.\</P>\
<p>When <code>set_current_todo</code> is called, it creates a <code><i>current_todo</i></code> property on the account and assigns the string value to it. \
When <code>add_to_my_todos</code> is called, a list named <code><i>my_todos</i></code>  is created, populated with the string value and attached to the account.</p>'
		    },
		    { title : 'The current item should show on the page',
		      body  : '\
<code><h4>Client Side HTML</h4><pre class="body_code">\
 The current task is &lt;span id="current_task"&gt; &lt;/span&gt;\
</pre></code>\
<code><h4>Client Side Javascript</h4><pre class="body_code">\
$.yote.init();\n\
var todo_app = $.yote.fetch_app( "Yote::Util::Todo" );\n\
var account = todo_app.account();\n\
$( "#current_task" ).empty().append( account.get_current_task() );\n\
</pre></code>\
The account is obtained by caling the <code>account</code> \
method on the app, which always returns the account of the currently logged in user. The account\'s public data fields \
are visible to the client.'
		    },
		    { title : 'The user types in a new task and hits submit. The task is recorded on the server side.',
		      body  : '\
<code><h4>Client Side HTML</h4><pre class="body_code">\
<span class="faint"> The current task is &lt;b id="current_task"&gt; &lt;/b &gt;\</span>\n\
 &lt;DIV&gt;\n  Enter a new task &lt;INPUT type="text" id="new_task"&gt;\n\
  &lt;BUTTON type="BUTTON" id="submit_task" &gt;Submit&lt;/BUTTON&gt;\n&lt;/DIV&gt;\
</pre></code>\
<code><h4>Client Side Javascript</h4><pre class="body_code">\
<span class="faint">$.yote.init();\n\
var todo_app = $.yote.fetch_app( "Yote::Util::Todo" );\n\
var account = todo_app.account();\n\
$( "#current_task" ).empty().append( account.get_current_task() );</span>\n\
$( "#submit_task" ).click(function() {\n\
   todo_app.add_item( $( "#current_task" ).val() );\n\
}\n\
</pre></code>\
<code><h4>Server Side</h4><pre class="body_code"><span class="faint">\
package Yote::Util::Todo;\n\
use strict;\n\
use base "Yote::AppRoot"\n\
sub _init_account {  \n\
  my( $self, $account ) = @_;\n\
\n\
  my $first_todo_item = "Enter todo items";\n\
  $account->set_current_todo( $first_todo_item ); \n\
  $account->add_to_my_todos( $first_todo_item ); \n\
}\n\
</span>\n\
sub add_item {\n\
  my( $self, $todo_item, $account ) = @_;\n\
  $account->add_to_my_todos( $todo_item );\n\
}\n\n\
<span class="faint">1;</span></pre></code>'
		    },
		    { title : 'The user presses a button and gets a random new task.',
		      body  : '\
<code><h4>Client Side HTML</h4><pre class="body_code">\
<span class="faint"> The current task is &lt;b id="current_task"&gt; &lt;/b &gt;\n\
 &lt;DIV&gt;\n  Enter a new task &lt;INPUT type="text" id="new_task"&gt;\n\
  &lt;BUTTON type="BUTTON" id="submit_task" &gt;Submit&lt;/BUTTON&gt;\n&lt;/DIV&gt;</span>\n\
 &lt;BUTTON type="BUTTON" id="change_task" &gt;Change Task&lt;/BUTTON&gt;\n\
</pre></code>\
<code><h4>Client Side Javascript</h4><pre class="body_code">\
<span class="faint">$.yote.init();\n\
var todo_app = $.yote.fetch_app( "Yote::Util::Todo" );\n\
var account = todo_app.account();\n\
$( "#current_task" ).empty().append( account.get_current_task() );\n\
$( "#submit_task" ).click(function() {\n\
   todo_app.add_item( $( "#current_task" ).val() );\n\
}</span>\n\
$( "#change_task" ).click(function() {\n\
   todo_app.pick_random_todo();\n\
}\n\
</pre></code>\
<code><h4>Server Side</h4><pre class="body_code"><span class="faint">\
package Yote::Util::Todo;\n\
use strict;\n\
use base "Yote::AppRoot"\n\
sub _init_account {  \n\
  my( $self, $account ) = @_;\n\
\n\
  my $first_todo_item = "Enter todo items";\n\
  $account->set_current_todo( $first_todo_item ); \n\
  $account->add_to_my_todos( $first_todo_item ); \n\
}\n\
sub add_item {\n\
  my( $self, $todo_item, $account ) = @_;\n\
  $account->add_to_my_todos( $todo_item );\n\
}\n\
</span>\n\
sub pick_random_todo {\n\
  my( $self, $data, $account ) = @_;\n\
  \n\
  my $todos = $account->get_my_todos();\n\
  my $rand = $todos->[ rand( @$todos ) ];\n\
  $self->set_current_todo( $rand );\n\
  return $rand;\n\
}\n\n\
<span class="faint">1;</span></pre></code>'
		    },
		    { title : 'The user marks the current task complete and the app presents them with a random new task.',
		      body  : '\
<code><h4>Client Side HTML</h4><pre class="body_code">\
<span class="faint"> The current task is &lt;b id="current_task"&gt; &lt;/b &gt;\n\
 &lt;DIV&gt;\n  Enter a new task &lt;INPUT type="text" id="new_task"&gt;\n\
  &lt;BUTTON type="BUTTON" id="submit_task" &gt;Submit&lt;/BUTTON&gt;\n&lt;/DIV&gt;\n\
 &lt;BUTTON type="BUTTON" id="change_task" &gt;Change Task&lt;/BUTTON&gt;</span>\n\
 &lt;BUTTON type="BUTTON" id="complete_task" &gt;Complete Task&lt;/BUTTON&gt;</span>\n\
</pre></code>\
<code><h4>Client Side Javascript</h4><pre class="body_code">\
<span class="faint">$.yote.init();\n\
var todo_app = $.yote.fetch_app( "Yote::Util::Todo" );\n\
var account = todo_app.account();\n\
$( "#current_task" ).empty().append( account.get_current_task() );\n\
$( "#submit_task" ).click(function() {\n\
   todo_app.add_item( $( "#current_task" ).val() );\n\
}\n\
$( "#change_task" ).click(function() {\n\
   todo_app.pick_random_todo();\n\
}</span>\n\
$( "#complete_task" ).click(function() {\n\
   todo_app.complete_current_item();\n\
}\n\
</pre></code>\
<code><h4>Server Side</h4><pre class="body_code"><span class="faint">\
package Yote::Util::Todo;\n\
use strict;\n\
use base "Yote::AppRoot"\n\
sub _init_account {  \n\
  my( $self, $account ) = @_;\n\
\n\
  my $first_todo_item = "Enter todo items";\n\
  $account->set_current_todo( $first_todo_item ); \n\
  $account->add_to_my_todos( $first_todo_item ); \n\
}\n\
sub add_item {\n\
  my( $self, $todo_item, $account ) = @_;\n\
  $account->add_to_my_todos( $todo_item );\n\
}\n\
sub pick_random_todo {\n\
  my( $self, $data, $account ) = @_;\n\
  \n\
  my $todos = $account->get_my_todos();\n\
  my $rand = $todos->[ rand( @$todos ) ];\n\
  $self->set_current_todo( $rand );\n\
  return $rand;\n\
}\n\n\
</span>\n\
sub complete_current_item {\n\
  my( $self, $data, $account ) = @_;\n\
\n\
  my $current = $account->get_current_todo();\n\
  $account->remove_from_my_todos( $current );\n\
\n\
  return $self->pick_random_todo( $data, $account );\n\
}\n\n\
<span class="faint">1;</span></pre></code>'
		    }
		],
		html : '\
',
		discussion        : '',
		server_discussion : '',
		client_discussion : ''
	    },
	    {
		title             : 'Chat',
		summary           : 'A simple chat that allows users to communicate with each other on the page. In this example, the users must be logged in and no anonymous messages are permitted. The chat will contain at most 50 messages.',
		html : '\
&lt;input type="TEXT" id="message_txt" placeholder="Enter a message" size="15"&gt; \n\
&lt;BUTTON type="BUTTON" id="message_b"&gt;Send&lt;/BUTTON&gt;\n\
&lt;BUTTON type="BUTTON" id="refresh_b"&gt;Refresh&lt;/BUTTON&gt;\n\
&lt;DIV id="messages_div"&gt;&lt;/DIV&gt;\
',
		javascript : '\
$.yote.init();\n\
var chat_app = $.yote.fetch_app( "Yote::Util::ChatBoard" );\n\
\n\
function refresh_chat() {\n\
  var buf = "";\n\
  var rows = chat_app.get_posts();\n\
  for( var i=0; i < rows.length(); i++ ) { //length is a method in this case\n\
      // a row is a list of user handle, message and time\n\
      var row = rows.get( i );\n\
      var when = new Date( row.get( 2 ) * 1000 );\n\
      buf += row.get( 0 ) + " said : " + row.get( 1 ) + \n\
             " at " + when.toLocaleTimeString() + "&lt;BRgt;";\n\
  }\n\
  $( "#messages_div" ).empty().append( buf );\n\
}\n\
\n\
$( "#message_b" ).click(function(){\n\
  chat_app.post( $( "#message_txt" ).val() );\n\
  refresh_chat();\n\
});\n\
\n\
$( "#refresh_b" ).click(function(){\n\
  refresh_chat();\n\
});\
',
		server : '\
package Yote::Util::ChatBoard;\n\
\n\
use strict;\n\
\n\
use base "Yote::AppRoot";\n\
\n\
sub post {\n\
    my( $self, $post, $acct ) = @_;\n\
\n\
    die "Need to be logged in to post" unless $acct;\n\
\n\
    my $posts = $self->get_posts( [] );\n\
\n\
    unshift @$posts, [ $acct->get_handle(), $post, time() ];\n\
\n\
    pop @$posts if @$posts > $self->get_size( 50 );\n\
}\n\n\
1;\
',
		discussion        : '',
		server_discussion : '',
		client_discussion : ''
	    },
	    {
		title             : 'Blog',
		summary           : '<P>The Blog lets users make and edit postings. The postings are composed of the following fields : author, content, subject, created_on, last_edited, and the blog object that has the posting. The blog itself is composed of a list of posts.</P><p>The news on this site uses the Blog code. The examples below highlight the brevity of writing apps in Yote. The blog is fully functional and no exotic libraries were needed to make it.</p>',
		use_cases         : [ "User posts a blog Entry", "Entries are displayed"],
		html              : '\
&lt!-- for posting ------ --&gt;\n\
&lt;input type="text" placeholder="Title" id="blog_title"&gt; \n\
&lt;textarea id="blog_entry"&gt;&lt;/textarea&gt;\n\
&lt;button type="button" id="post_blog"&gt;Post&lt;/button&gt;\n\
\n\
\n\
&lt!-- for display ------ --&gt;\n\
A Blog : \n\
&lt;div id="blog_entries"&gt;&lt;/div&gt;\n\
\n\
',
		javascript        : '\
$.yote.init();\n\
var blog = $.yote.fetch_app( "MyBlogger" ).get_blog();\n\
\n\
$( "#post_blog" ).click( function() {\n\
  blog.post( { subject : $( "#blog_title" ).val(), \n\
               content : $( "#blog_entry" ).val() } );\n\
  refresh();\n\
\n\
} );\n\
sub refresh() {\n\
  var entries = blog.get_posts();\n\
  var buf = "";\n\
  for( var i=0; i &lt; entries.length(); i++ ) {\n\
    var entry = entries.get( i );\n\
    var when = new Date( entry.get_created_on() * 1000 );\n\
    buf += "&lt;h2&gt;" + entry.get_subject() + "&lt;/h2&gt;";\n\
    buf += "&lt;DIV&gt;" + entry.get_content() + "&lt;/DIV&gt;";\n\
    buf += "&lt;SPAN&gt;Posted by " + entry.get_author().get_handle() + \n\
        " on " + when.toLocaleTimeString() + "&lt;/SPAN&gt;";\n\
  }\n\
  $( "#blog_entries" ).empty().append( buf );\n\
}\n\
',
		server            : '\
# ----- There are three yote classes for this case ----\n\
\n\
package MyBlogger;\n\
\n\
use strict;\n\
\n\
use base "Yote::AppRoot";\n\
\n\
use Yote::Util::Blog;\n\
\n\
sub _init {\n\
  my $self = shift;\n\
  $self->set_blog( new Yote::Util::Blog() );\n\
}\n\
\n\
1;\n\
# -----------------------------------------------\n\
\n\
package Yote::Util::Blog;\n\
\n\
use strict;\n\
\n\
use base "Yote::Obj";\n\
\n\
use Yote::Util::BlogPost;\n\
\n\
sub post {\n\
    my( $self, $data, $acct ) = @_;\n\
\n\
    my $post = new Yote::Util::BlogPost();\n\
    $post->set_blog( $self );\n\
    $post->set_author( $acct );\n\
\n\
    $post->set_content( $data->{ content } );\n\
    $post->set_subject( $data->{ subject } );\n\
    $post->set_created_on( time() );\n\
\n\
    $self->add_to_posts( $post );\n\
\n\
    return $post;\n\
} #post\n\
\n\
sub remove_post {\n\
    my( $self, $data, $acct ) = @_;\n\
\n\
    die "Not authorized to remove" unless $acct && \n\
      ( $acct->get_login()->is_root() || $acct->_is( $data->get_author() ) );\n\
\n\
    $self->remove_from_posts( $data );\n\
\n\
} #remove_post\n\
\n\
1;\n\
\n\
# -----------------------------------------------\n\
\n\
package Yote::Util::BlogPost;\n\
\n\
use strict;\n\
\n\
use base "Yote::Obj";\n\
\n\
sub update {\n\
    my( $self, $data, $acct ) = @_;\n\
\n\
    die "No post given" unless $data;\n\
    die "Not author of post" unless $acct && \n\
     ( $acct->_is( $self->get_author() ) || $acct->is_root() );\n\
\n\
    my $dirty = $self->_update( $data,  qw( subject content ) );\n\
    if( $dirty ) {\n\
	$self->set_last_edited_on( time() );\n\
    }\n\
\n\
} #edit_post\n\
\n\
1;\
',
		discussion        : '',
		server_discussion : '<p>There are three different methods being introduced here. \
<p><code>$account->is_root</code> is a method that returns true if this account is a root one.</p>\
<p><code>$obj->_is( $other_obj )</code> returns true if $obj and $other_obj are the same.</p>\
<p><code>$obj->_update( $data_hash )</code> is a method that, when overridden, updates the data in the object.\
The <code>_update</code> dies by default and is called by the server when the client tries to update an object.\
In this case, only the subject and content may be updated.</p></p>\
',
		client_discussion : ''
	    }
	];

	var buf = '';
	for( var i=0; i < samples.length; i++ ) {
	    var sample = samples[ i ];
	    buf += '<LI id="li_' + i + '"><A HREF="#" id="sample_' + i + '"> ' +
		sample[ 'title' ] + '</LI>';
	}

	$( '#navcol' ).empty().append( buf );
	for( var i=0; i < samples.length; i++ ) {
	    $( '#sample_' + i ).click( (function(ii) {
		return function() {
		    show_sample( ii );
		}
	    } )( i ) );
	}

	function show_sample( sample_idx ) {
	    var sample = samples[ sample_idx ];
	    $( '#navcol a' ).removeClass( 'active' );
	    $( '#li_' + sample_idx + ' a' ).addClass( 'active' );
	    if( ! sample ) {
		return;
	    }
	    var buf = '<DIV class="page-header"><h2>' +
		sample[ 'title' ] + '</h2>' + sample[ 'summary' ] + '</DIV>';

	    if( sample[ 'use_cases' ] && sample[ 'use_cases' ].length > 0 ) {
		buf += '<div class="use_case">';
		if( sample[ 'use_cases' ].length == 1 ) {
		    buf += '<b>Use Case</b> : ' + sample[ 'use_cases' ][ 0 ];
		    buf += '<BR>';
		} else {
		    buf += "<h2>Use Cases</h2>";
		    var ucbuf = '';
		    var is_list = false;
		    for( var j=0 ; j <  sample[ 'use_cases' ].length; j++ ) {
			var uc = sample[ 'use_cases' ][ j ];
			if( typeof uc === 'object' ) {
			    ucbuf += '<div class="uc_title">' + uc.title + '</div>' +
				'<div class="uc_body">' + uc.body + '</div>';
			    is_list = true;
			} else {
			    ucbuf += '<li>' + uc + "</li>";
			}
		    }
		    if( is_list ) {
			buf += '<ul>' + ucbuf + '</ul>';
		    } else {
			buf += ucbuf;
		    }
		}
		buf += '</div>';
	    }

	    if( sample[ 'html' ] ) {
		buf += '<DIV class="code_box"><h3>HTML Client code</h3><DIV class="html_col"><pre class="codebox"><code>' + sample[ 'html' ] + '</code></pre></div></DIV>';
	    }
	    if( sample[ 'javascript' ] ) {
		buf += '<DIV class="code_box"><h3>Javascript Client code</h3><DIV class="javascript_col"><pre class="codebox"><code>' + sample[ 'javascript' ] + '</code></pre></div></DIV>';
	    }
	    if( sample[ 'server' ] ) {
		buf += '<DIV class="code_box"><h3>Perl Server Code</h3><DIV class="server_col"><pre class="codebox"><code>' + sample[ 'server' ] + '</code></pre></div></DIV>';
	    }

	    if( sample[ 'server_discussion' ] ) {
		buf += '<p><h4>Server Notes</h4>' + sample[ 'server_discussion' ] + '</p>';
	    }
	    if( sample[ 'client_discussion' ] ) {
		buf += '<p><h4>Client Notes</h4>' + sample[ 'client_discussion' ] + '</p>';
	    }
	    if( sample[ 'discussion' ] ) {
		buf += '<p><h4>Discussion</h4>' + sample[ 'discussion' ] + '</p>';
	    }
	    buf += '<div style="padding:0 300px 0 300px;display:inline">';
	    if( sample_idx > 0 ) {
		// can move backwards
		buf += '<a id="back" href="#">Previous</a>';
	    }
	    if( sample_idx < (samples.length-1) ) {
		// can move forwards
		buf += '<a id="ahead" href="#" style="float:right">Next</a>';
	    }
	    buf += '</div>';

	    $( '#sample' ).empty().append( buf );

	    $( '#back' ).click( (function(newidx) {
		return function() { show_sample( newidx ); }
	    } )( sample_idx - 1 ) );

	    $( '#ahead' ).click( (function(newidx) {
		return function() { show_sample( newidx ); }
	    } )( sample_idx + 1 ) );

	} //show_sample

	show_sample( 0 );

	attach_login( {
	    attachpoint         : '#logged_in_status',
	    message_attachpoint : '#msg_div'
	} );
    });
    </script>
  </head>

  <BODY>

    <DIV class="header">
      <A href="/index.html" style="display:block">
	<img height="70px" width="151px" src="yotelogo.png">
      </A>
      <UL id="top_nav" class="nav"></UL>
      <DIV class="login logged_in" id="logged_in_status"></DIV>
      <DIV id="msg_div"></DIV>
    </DIV>

    <DIV class="page_div">
      <DIV class="sidebar">
        <h3>Sample Apps</h3>
        <UL id="navcol" class="navlink"/>
      </DIV>

      <DIV class="mainpanel">
	<h1>Samples</h1>
	<P>
          The samples page features apps that are used on this site.
          The apps may be slightly simplified for clarity.
        </p>
	<HR>
	<SECTION id="sample">
	</SECTION>
      </DIV>
    </DIV>
    <footer>
      This page has been viewed <span id="counter"></span> times.
    </footer>

  </body>
</html>


    <script src="/js/local.js"></script>
</body>

<noscript>
<body style="cursor: auto;">

    <div class="header">
      <img src="yotelogo.png">
      <ul id="top_nav" class="nav"><li><a href="index.html">About</a></li><li><a href="quickstart.html">Quickstart</a></li><li><a href="install.html">Install</a></li><li><a href="client_docs.html">Client</a></li><li><a href="server_docs.html">Server</a></li><li><a class="active" href="samples.html">Samples</a></li><li><a href="Todo.html">Wishlist</a></li><li><a href="Yote-current.tar.gz">Download</a></li><li><a href="admin.html">Admin</a></li></ul>
        <div class="login logged_in" id="logged_in_status">Logged in as wolf<br><a href="#" id="logout">Log Out</a></div>
        <div id="msg_div"></div>
    </div>

    <div class="page_div">
      <div class="sidebar">
        <h3>Sample Apps</h3>
        <ul id="navcol" class="navlink"><li id="li_0"><a href="#" id="sample_0"> Web Counter</a></li><li id="li_1"><a href="#" id="sample_1"> To Do App</a></li><li id="li_2"><a href="#" id="sample_2"> Chat</a></li><li id="li_3"><a href="#" id="sample_3" class="active"> Blog</a></li></ul></div>

      <div class="mainpanel">
	<h1>Samples</h1>
	<p>
          The samples page features apps that are used on this site.
          The apps may be slightly simplified for clarity.
        </p>
	<hr>
	<section id="sample"><div class="page-header"><h2>Blog</h2><p>The Blog lets users make and edit postings. The postings are composed of the following fields : author, content, subject, created_on, last_edited, and the blog object that has the posting. The blog itself is composed of a list of posts.</p><p>The news on this site uses the Blog code. The examples below highlight the brevity of writing apps in Yote. The blog is fully functional and no exotic libraries were needed to make it.</p></div><div class="use_case"><h2>Use Cases</h2><li>User posts a blog Entry</li><li>Entries are displayed</li></div><div class="code_box"><h3>HTML Client code</h3><div class="html_col"><pre class="codebox"><code>&lt;!-- for posting ------ --&gt;
&lt;input type="text" placeholder="Title" id="blog_title"&gt; 
&lt;textarea id="blog_entry"&gt;&lt;/textarea&gt;
&lt;button type="button" id="post_blog"&gt;Post&lt;/button&gt;


&lt;!-- for display ------ --&gt;
A Blog : 
&lt;div id="blog_entries"&gt;&lt;/div&gt;

</code></pre></div></div><div class="code_box"><h3>Javascript Client code</h3><div class="javascript_col"><pre class="codebox"><code>$.yote.init();
var blog = $.yote.fetch_app( "MyBlogger" ).get_blog();

$( "#post_blog" ).click( function() {
  blog.post( { subject : $( "#blog_title" ).val(), 
               content : $( "#blog_entry" ).val() } );
  refresh();

} );
sub refresh() {
  var entries = blog.get_posts();
  var buf = "";
  for( var i=0; i &lt; entries.length(); i++ ) {
    var entry = entries.get( i );
    var when = new Date( entry.get_created_on() * 1000 );
    buf += "&lt;h2&gt;" + entry.get_subject() + "&lt;/h2&gt;";
    buf += "&lt;DIV&gt;" + entry.get_content() + "&lt;/DIV&gt;";
    buf += "&lt;SPAN&gt;Posted by " + entry.get_author().get_handle() + 
        " on " + when.toLocaleTimeString() + "&lt;/SPAN&gt;";
  }
  $( "#blog_entries" ).empty().append( buf );
}
</code></pre></div></div><div class="code_box"><h3>Perl Server Code</h3><div class="server_col"><pre class="codebox"><code># ----- There are three yote classes for this case ----

package MyBlogger;

use strict;

use base "Yote::AppRoot";

use Yote::Util::Blog;

sub _init {
  my $self = shift;
  $self-&gt;set_blog( new Yote::Util::Blog() );
}

1;
# -----------------------------------------------

package Yote::Util::Blog;

use strict;

use base "Yote::Obj";

use Yote::Util::BlogPost;

sub post {
    my( $self, $data, $acct ) = @_;

    my $post = new Yote::Util::BlogPost();
    $post-&gt;set_blog( $self );
    $post-&gt;set_author( $acct );

    $post-&gt;set_content( $data-&gt;{ content } );
    $post-&gt;set_subject( $data-&gt;{ subject } );
    $post-&gt;set_created_on( time() );

    $self-&gt;add_to_posts( $post );

    return $post;
} #post

sub remove_post {
    my( $self, $data, $acct ) = @_;

    die "Not authorized to remove" unless $acct &amp;&amp; 
      ( $acct-&gt;get_login()-&gt;is_root() || $acct-&gt;_is( $data-&gt;get_author() ) );

    $self-&gt;remove_from_posts( $data );

} #remove_post

1;

# -----------------------------------------------

package Yote::Util::BlogPost;

use strict;

use base "Yote::Obj";

sub update {
    my( $self, $data, $acct ) = @_;

    die "No post given" unless $data;
    die "Not author of post" unless $acct &amp;&amp; 
     ( $acct-&gt;_is( $self-&gt;get_author() ) || $acct-&gt;is_root() );

    my $dirty = $self-&gt;_update( $data,  qw( subject content ) );
    if( $dirty ) {
		  $self-&gt;set_last_edited_on( time() );
    }

} #edit_post

1;</code></pre></div></div><p></p><h4>Server Notes</h4><p>There are three different methods being introduced here. </p><p><code>$account-&gt;is_root</code> is a method that returns true if this account is a root one.</p><p><code>$obj-&gt;_is( $other_obj )</code> returns true if $obj and $other_obj are the same.</p><p><code>$obj-&gt;_update( $data_hash )</code> is a method that, when overridden, updates the data in the object.The <code>_update</code> dies by default and is called by the server when the client tries to update an object.In this case, only the subject and content may be updated.</p><p></p><p></p><div style="padding:0 300px 0 300px;display:inline"><a id="back" href="#">Previous</a></div></section>
      </div>
    </div>
    <footer>
    </footer>

  



    <script src="/js/local.js"></script>


</body></noscript>

</html>