Description
Adablog uses an MVC style model of programming similar for Ruby on Rails.
It demonstrates how flexible Gnoga can be and that it is just as capable in the area of web sites, as web apps or application GUIs.
An effort was made to also make more use of attaching to the DOM of existing pages and avoiding app data types.
This applications uses SQLite.
Source code
adablog.ads
with Gnoga.Server.Database.SQLite;
package AdaBlog is
   use Gnoga;
   use all type Gnoga.String;
   Connection : Gnoga.Server.Database.Connection_Access := Gnoga.Server.Database.SQLite.Connect ("adablog.db");
end AdaBlog;				adablog-controller.ads
with Gnoga.Gui.Window;
with Gnoga.Application.Multi_Connect;
package AdaBlog.Controller is
   procedure Index
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Connection  :        access Gnoga.Application.Multi_Connect.Connection_Holder_Type);
   procedure New_Entry
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Connection  :        access Gnoga.Application.Multi_Connect.Connection_Holder_Type);
   procedure Log_Out
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Connection  :        access Gnoga.Application.Multi_Connect.Connection_Holder_Type);
end AdaBlog.Controller;				adablog-controller.adb
with Ada.Calendar;
with Gnoga.Types;
with Gnoga.Gui.Base;
with Gnoga.Gui.Element;
with Gnoga.Gui.Element.Common;
with Gnoga.Gui.Element.Form;
with AdaBlog.View;
with AdaBlog.Model;
package body AdaBlog.Controller is
   procedure On_Create_User (Object : in out Gnoga.Gui.Base.Base_Type'Class);
   --  The create user button was clicked
   procedure On_User_Login (Object : in out Gnoga.Gui.Base.Base_Type'Class);
   --  User clicked the submit button for his user name and password
   procedure On_Submit_Entry (Object : in out Gnoga.Gui.Base.Base_Type'Class);
   --  User clicked the submit button to an a blog entry.
   procedure On_Create_User (Object : in out Gnoga.Gui.Base.Base_Type'Class) is
      Main_Window  : aliased Gui.Window.Window_Type;
      Message_Area : Gui.Element.Common.DIV_Type;
      User_Login   : Gui.Element.Common.Button_Type;
      username : Gui.Element.Form.Text_Type;
      password : Gui.Element.Form.Text_Type;
      pass2    : Gui.Element.Form.Text_Type;
      verify   : Gui.Element.Common.DIV_Type;
      User : AdaBlog.Model.Users.Active_Record;
   begin
      Main_Window.Attach (Object.Connection_ID);
      Message_Area.Attach_Using_Parent (Main_Window, "message");
      User_Login.Attach_Using_Parent (Main_Window, "login-button");
      User_Login.Disabled;
      username.Attach_Using_Parent (Main_Window, "username");
      password.Attach_Using_Parent (Main_Window, "pass");
      pass2.Attach_Using_Parent (Main_Window, "pass2");
      verify.Attach_Using_Parent (Main_Window, "verify-pass");
      verify.Display ("inline");
      if Gnoga.String'(password.Value) /= Gnoga.String'(pass2.Value) or pass2.Value = "" then
         Message_Area.Text ("Please verify password.");
         return;
      end if;
      if username.Value = "" then
         Message_Area.Text ("Username is required.");
         return;
      end if;
      User.Find_Where ("username='" & username.Value & "'");
      if User.Value ("id") /= "" then
         Message_Area.Text ("Username is already taken.");
         return;
      end if;
      User.Value ("username", Value => username.Value);
      User.Value ("pass", Value => password.Value);
      User.Value ("last_session", Value => Main_Window.Gnoga_Session_ID);
      User.Save;
      Main_Window.Location.URL ("/");
   end On_Create_User;
   procedure On_User_Login (Object : in out Gnoga.Gui.Base.Base_Type'Class) is
      Main_Window  : aliased Gui.Window.Window_Type;
      Message_Area : Gui.Element.Common.DIV_Type;
      username : Gui.Element.Form.Text_Type;
      password : Gui.Element.Form.Text_Type;
      User : AdaBlog.Model.Users.Active_Record;
   begin
      Main_Window.Attach (Object.Connection_ID);
      Message_Area.Attach_Using_Parent (Main_Window, "message");
      username.Attach_Using_Parent (Main_Window, "username");
      password.Attach_Using_Parent (Main_Window, "pass");
      User.Find_Where
        (Where      => "username ='" & username.Value & "'" & " AND " & "pass ='" & password.Value & "'",
         Create_New => False);
      User.Value ("last_session", Value => Main_Window.Gnoga_Session_ID);
      User.Save;
      Main_Window.Location.URL ("/");
   exception
      when others =>
         Message_Area.Text ("Invalid Login");
   end On_User_Login;
   procedure On_Submit_Entry (Object : in out Gnoga.Gui.Base.Base_Type'Class) is
      User    : AdaBlog.Model.Users.Active_Record;
      Entries : AdaBlog.Model.Blog_Entries.Active_Record;
      Main_Window : aliased Gui.Window.Window_Type;
      Text        : Gnoga.Gui.Element.Form.Text_Area_Type;
   begin
      Main_Window.Attach (Object.Connection_ID);
      Text.Attach_Using_Parent (Main_Window, "entry_text");
      User.Find_Where ("last_session ='" & Main_Window.Gnoga_Session_ID & "'");
      Entries.Value ("user_id", Value => User.Value ("id"));
      Entries.Value ("entry_date", Date_Value => Ada.Calendar.Clock);
      Entries.Value ("entry_text", Value => Text.Value);
      Entries.Save;
      Main_Window.Location.URL ("/");
   end On_Submit_Entry;
   procedure Index
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Connection  :        access Gnoga.Application.Multi_Connect.Connection_Holder_Type)
   is
      Content_Area : Gui.Element.Common.DIV_Type;
      Left_Area    : Gui.Element.Common.DIV_Type;
      User_Login   : Gui.Element.Common.Button_Type;
      Create_User  : Gui.Element.Common.Button_Type;
      User : AdaBlog.Model.Users.Active_Record;
      procedure Display_Row (Row : Gnoga.Types.Data_Map_Type);
      procedure Display_Row (Row : Gnoga.Types.Data_Map_Type) is
      begin
         AdaBlog.View.Display_Blog_Entry (Content_Area, Row);
      end Display_Row;
   begin
      User.Find_Where ("last_session ='" & Main_Window.Gnoga_Session_ID & "'");
      Main_Window.Disable_Auto_Set_View;
      Content_Area.Create (Parent => Main_Window, ID => "main-body");
      AdaBlog.Connection.Iterate
        (SQL =>
           "select username, entry_date, entry_text " & "from users, blog_entries " &
           "where users.id=blog_entries.user_id",
         Process => Display_Row'Unrestricted_Access);
      View.User_Panel (Main_Window => Main_Window, Panel => Left_Area, User_Record => User.Values);
      View.Template (Main_Window => Main_Window, Content => Content_Area, Left_Panel => Left_Area);
      User_Login.Attach_Using_Parent (Main_Window, "login-button");
      User_Login.On_Click_Handler (On_User_Login'Access);
      Create_User.Attach_Using_Parent (Main_Window, "create-button");
      Create_User.On_Click_Handler (On_Create_User'Access);
      Connection.Hold;
   end Index;
   procedure New_Entry
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Connection  :        access Gnoga.Application.Multi_Connect.Connection_Holder_Type)
   is
      User : AdaBlog.Model.Users.Active_Record;
      Content_Area : Gui.Element.Common.DIV_Type;
      Left_Area    : Gui.Element.Common.DIV_Type;
      Submit : Gui.Element.Common.Button_Type;
   begin
      User.Find_Where ("last_session ='" & Main_Window.Gnoga_Session_ID & "'");
      if User.Value ("id") = "" then
         Main_Window.Location.URL ("/");
         return;
      end if;
      Main_Window.Disable_Auto_Set_View;
      View.New_Entry_Form (Main_Window => Main_Window, Content => Content_Area);
      View.User_Panel (Main_Window => Main_Window, Panel => Left_Area, User_Record => User.Values);
      View.Template (Main_Window => Main_Window, Content => Content_Area, Left_Panel => Left_Area);
      Submit.Attach_Using_Parent (Main_Window, "submit_entry");
      Submit.On_Click_Handler (On_Submit_Entry'Access);
      Connection.Hold;
   end New_Entry;
   procedure Log_Out
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Connection  :        access Gnoga.Application.Multi_Connect.Connection_Holder_Type)
   is
      pragma Unreferenced (Connection);
      User : AdaBlog.Model.Users.Active_Record;
   begin
      User.Find_Where ("last_session ='" & Main_Window.Gnoga_Session_ID & "'");
      if User.Value ("id") /= "" then
         User.Value ("last_session", "");
         User.Save;
      end if;
      Main_Window.Location.URL ("/");
   end Log_Out;
begin
   Application.Multi_Connect.On_Connect_Handler (Controller.Index'Unrestricted_Access, "default");
   Application.Multi_Connect.On_Connect_Handler (Controller.Index'Unrestricted_Access, "main");
   Application.Multi_Connect.On_Connect_Handler (New_Entry'Unrestricted_Access, "new_entry");
   Application.Multi_Connect.On_Connect_Handler (Log_Out'Unrestricted_Access, "logout");
end AdaBlog.Controller;				adablog-view.ads
with Gnoga.Types;
with Gnoga.Gui.Window;
with Gnoga.Gui.Element.Common;
package AdaBlog.View is
   procedure Display_Blog_Entry
     (Parent : in out Gnoga.Gui.Element.Common.DIV_Type'Class;
      Data   : in     Gnoga.Types.Data_Map_Type);
   --  Adds blog entries to content
   procedure New_Entry_Form
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Content     : in out Gnoga.Gui.Element.Common.DIV_Type'Class);
   --  Creates new entry form for content
   procedure User_Panel
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Panel       : in out Gnoga.Gui.Element.Common.DIV_Type'Class;
      User_Record : in     Gnoga.Types.Data_Map_Type);
   --  Setup Panel with User_Record information or Login if User_Record empty
   procedure Template
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Content     : in out Gnoga.Gui.Element.Common.DIV_Type'Class;
      Left_Panel  : in out Gnoga.Gui.Element.Common.DIV_Type'Class);
   --  Content will be placed in to Content area of Template
end AdaBlog.View;				adablog-view.adb
package body AdaBlog.View is
   procedure Display_Blog_Entry
     (Parent : in out Gnoga.Gui.Element.Common.DIV_Type'Class;
      Data   : in     Gnoga.Types.Data_Map_Type)
   is
      Entry_Div : Gnoga.Gui.Element.Common.DIV_Type;
   begin
      Entry_Div.Create
        (Parent,
         "<div class='blog_entry'>" & "<div class='blog_user'>" & Data.Element ("username") & "</div>" &
         "<div class='blog_date'> said on " & Data.Element ("entry_date") & ":</div><br />" &
         "<div class='blog_text'>" & Data.Element ("entry_text") & "</div></div>");
   end Display_Blog_Entry;
   procedure New_Entry_Form
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Content     : in out Gnoga.Gui.Element.Common.DIV_Type'Class)
   is
   begin
      Content.Create
        (Parent  => Main_Window,
         Content =>
           "<div><form>" & "Blog Entry: <br />" & "<textarea cols=60 rows=10 id='entry_text' " &
           "name='entry_text' autofocus></textarea>" & "<input type='button' id='submit_entry' " &
           "value='Submit'></form></div>",
         ID => "main-body");
   end New_Entry_Form;
   procedure User_Panel
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Panel       : in out Gnoga.Gui.Element.Common.DIV_Type'Class;
      User_Record : in     Gnoga.Types.Data_Map_Type)
   is
   begin
      if not User_Record.Contains ("username") then
         Panel.Create
           (Parent  => Main_Window,
            Content =>
              "<form>" & "Username: <input type=text name='username' " & "id='username' size='20' autofocus><br />" &
              "Password : <input type=password name='pass' " & "id='pass' size='20'><br />" &
              "<div id='verify-pass' style='display:none'> " & "Verify Password : <input type=password name='pass2' " &
              "id='pass2' size='20'><br /></div>" & "<input id='login-button' type='button'" & " value='Submit'> " &
              "<input id='create-button' type='button'" & " value='Create'> <br/>" & "</form>",
            ID => "left-panel");
      else
         Panel.Create
           (Parent  => Main_Window,
            Content =>
              " Username: <b>" & User_Record.Element ("username") & "</b><br /><br />" & "<a href='/new_entry'>" &
              "Add Entry</a><br /><br />" & "<a href='/logout'>Logout</a ><br/>",
            ID => "left-panel");
      end if;
   end User_Panel;
   procedure Template
     (Main_Window : in out Gnoga.Gui.Window.Window_Type'Class;
      Content     : in out Gnoga.Gui.Element.Common.DIV_Type'Class;
      Left_Panel  : in out Gnoga.Gui.Element.Common.DIV_Type'Class)
   is
      Title_Div    : Gnoga.Gui.Element.Common.DIV_Type;
      Message_Area : Gnoga.Gui.Element.Common.DIV_Type;
   begin
      Main_Window.Document.Load_CSS ("/css/adablog.css");
      Main_Window.Disable_Auto_Set_View;
      Title_Div.Create (Parent => Main_Window, Content => "AdaBlog", ID => "title");
      Title_Div.Place_Inside_Top_Of (Main_Window.Document.Body_Element.all);
      Left_Panel.Place_After (Title_Div);
      Content.Place_After (Left_Panel);
      Message_Area.Create (Main_Window, ID => "message");
      Message_Area.Place_Inside_Top_Of (Content);
   end Template;
end AdaBlog.View;				adablog-migrations.adb
with Gnoga.Server.Migration;
procedure AdaBlog.Migrations (M : in out Gnoga.Server.Migration.Migration_Collection) is
begin
   --  Add migrations here
   M.Add_Migration_Up
     ("CREATE TABLE `users`" & " (" & AdaBlog.Connection.ID_Field_String & "," & "  username VARCHAR(80)," &
      "  pass VARCHAR(80)," & "  last_session VARCHAR(80))");
   M.Add_Migration_Down ("DROP TABLE `users`");
   M.Add_Migration_Up
     ("CREATE TABLE `blog_entries`" & " (" & AdaBlog.Connection.ID_Field_String & "," & "  user_id INTEGER," &
      "  entry_date DATE," & "  entry_text TEXT)");
   M.Add_Migration_Down ("DROP TABLE `blog_entries`");
end AdaBlog.Migrations;				adablog-model.ads
with Gnoga.Server.Model.Table;
package AdaBlog.Model is
   package Users is new Gnoga.Server.Model.Table ("users", Connection);
   package Blog_Entries is new Gnoga.Server.Model.Table ("blog_entries", Connection);
end AdaBlog.Model;				adablog-main.adb
with GNAT.OS_Lib;
with Gnoga.Application.Multi_Connect;
with Gnoga.Server.Migration;
with AdaBlog.Migrations;
with AdaBlog.Controller;
procedure AdaBlog.Main is
   pragma Linker_Options ("-lsqlite3");
begin
   if Gnoga.Server.Migration.Migrations_Handled_Command_Line (Connection, Migrations'Unrestricted_Access) then
      GNAT.OS_Lib.OS_Exit (0);
   end if;
   Application.Title ("AdaBlog - Gnoga Demo");
   Application.HTML_On_Close ("<b>Connection to Application has been terminated</b>");
   Application.Multi_Connect.Initialize (Boot => "debug.html");
   Application.Multi_Connect.Message_Loop;
exception
   when E : others =>
      Log (E);
end AdaBlog.Main;
				Project file
with "settings.gpr";
with "gnoga.gpr";
project AdaBlog is
   for Object_Dir use Settings.Obj_Dir;
   for Exec_Dir use Settings.Exe_Dir;
   for Main use ("adablog-main.adb");
   for Create_Missing_Dirs use Settings'Create_Missing_Dirs;
   package Builder is
      for Executable ("adablog-main.adb") use "adablog";
   end Builder;
   package Compiler is
      for Default_Switches ("Ada") use Settings.Compiler'Default_Switches ("Ada") & "-gnatyN";
   end Compiler;
   package Binder renames Settings.Binder;
   package Linker renames Settings.Linker;
   package Pretty_Printer renames Settings.Pretty_Printer;
end AdaBlog;