This tutorial was written for Callimachus 1.0 and may not work with the latest version of Callimachus.

This tutorial shows you how to create a Callimachus application that mixes RDF data and structured writing (Callimachus Articles).  An application will be created that creates, lists and edits tasks assigned to a person.  Each task will be represented by a combination of data (to track status and priority of a task) and writing (to allow for more freeform thoughts to be recorded).

You can acquire a Callimachus Archive of this application here.  All the files you need to recreate the app are contained in that file.  Simply create a new Callimachus folder and select 'Import folder contents' from the main menu to import it.  The remainder of this tutorial walks you through the creation of the app from the beginning, as if you were creating it from scratch.  You might find it useful to unzip the CAR file and use its contents to create the app step-by-step to help you learn.

The final application will allow tasks to be created, edited and viewed and will also include a listing of all tasks.  A sample task is shown below.  Note how the task is made from a combination of structured RDF data and freeform textual descriptions.

An expanded view of the files for this application are shown below, so you can see the structure of the application in its final state:

The first step is to create a new Callimachus folder to contain this application.  We called ours 'composite-app', but you may name it anything you like.  Next, create the folder structure to contain all of the application's contents.  Naturally, you could place all of these files in a single folder, but the hierarchy makes the app easier to read and easier for a new person to maintain.  You will create each folder by selecting the 'Create' menu in the upper left of a Callimachus folder view and selecting the 'Folder' option.

Now will we create each of the concepts needed for the application.  We want each task to have a priority, so we will create three concepts to represent priorities (A, B and C).  You can create these by navigating to the concepts/priorities folder and selecting 'Concept' from the Create menu.  Create all three priority concepts.  The first one should look like the image below:

We also want each task to have a status (such as "complete" or "in progress").  Navigate to the concepts/status folder and create those concepts there in the same way you created the priority concepts.

Similarly, create the CSS and media files in their respective folders.  You can get those files from the provided CAR file or create your own.  You should also create an empty folder called "tasks" to hold the tasks that will be created when using the application.  The rest of the files will be explained in more detail.

The key files for this application are:

  • A Task class
  • Callimachus create, edit and view templates for the Task class
  • Some JavaScript files that are used to associate the Article editor with the templates
  • ...and files to display a listing of all the created tasks

First let's create the templates so we can associate them with the Task class when it is created.  The task create template is just a Web page (XHTML+RDFa) that uses an HTML form to collect data about a new task.  Callimachus creates a task when the form is submitted.  RDFa is used to annotate the page so the appropriate information is created by the server.  The create template looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:skos="http://www.w3.org/2004/02/skos/core#"
    xmlns:calli="http://callimachusproject.org/rdf/2009/framework#"
    xmlns:ical="http://www.w3.org/2002/12/cal/icaltzd#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/">
<head>
    <title>New Task</title>
    <script type="text/javascript" src="js/task-create.js"></script>
    <script id="template" type="application/xhtml+xml"><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Untitled Article</title>
</head>
<body>
<h1>Untitled Article</h1>
<p>&#160;</p>
</body>
</html>]]>
    </script>
</head>
<body>
    <h1>New Task</h1>
    <form id="rdfForm" method="POST" action="" enctype="application/rdf+xml" typeof=""
            onsubmit="return calli.saveResourceAs(event,calli.slugify($('#label').val()))">
        <div class="row">
            <fieldset class="span5">
                <div class="control-group">
                    <label for="label" class="control-label">Label</label>
                    <div class="controls">
                        <input type="text" id="label" value="{rdfs:label}" class="auto-expand" required="required" autofocus="autofocus" />
                    </div>
                </div>
            </fieldset>
            <fieldset class="span5">
                <div class="control-group">
                    <label for="status" class="control-label">Status</label>
                    <div id="status" class="controls">
                        <label class="inline radio" rel="ical:status" resource="?status">
                            <input type="radio" name="status" checked="checked" />
                            <span rev="calli:hasComponent" resource="concepts/status/" property="skos:prefLabel" />
                        </label>
                    </div>
                </div>
                <div class="control-group">
                    <label for="priority" class="control-label">Priority</label>
                    <div id="priority" class="controls">
                        <label class="inline radio" rel="ical:priority" resource="?priority">
                            <input type="radio" name="priority" checked="checked" />
                            <span rev="calli:hasComponent" resource="concepts/priority/" property="skos:prefLabel" />
                        </label>
                    </div>
                </div>
            </fieldset>
        </div>
        <span id="article" rel="foaf:isPrimaryTopicOf"><span resource="?article" typeof="foaf:Document" /></span>
    </form>
    <form id="docForm" method="POST" action="?create=/callimachus/1.0/types/Article" enctype="application/xhtml+xml"
            onsubmit="calli.saveResourceAs(event, calli.slugify($('#label').val()) + '.docbook')">
        <fieldset>
            <iframe id="iframe" width="100%" height="50%" src="/callimachus/document-editor.html"
                onload="calli.initEditor(event,$('#template').text()||$('#template').html().replace(/^\s+/,''))"> </iframe>
            <div class="form-actions">
                <button type="submit" class="btn btn-success">Create</button>
            </div>
        </fieldset>
    </form>
</body>
</html>

Most of the create template is very similar to those you have seen in earlier Callimachus tutorials.  For example, the label for the task is defined like this:

<input type="text" id="label" value="{rdfs:label}" class="auto-expand" required="required" autofocus="autofocus" />

The new part of this application is the inclusion of the Callimachus Article editor in the create template.  The article editor is embedded with this line:

<span id="article" rel="foaf:isPrimaryTopicOf"><span resource="?article" typeof="foaf:Document" /></span>

Note that the article is referred to by the RDF predicate foaf:isPrimaryTopicOf.  That predicate links the task subject with an article URL in RDF.

The task edit template is very similar to the create template.  You can look at it in the CAR download.  The view template contains the same information, but just displays it instead of presenting it in a form:

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:ical="http://www.w3.org/2002/12/cal/icaltzd#"
    xmlns:skos="http://www.w3.org/2004/02/skos/core#"
    xmlns:calli="http://callimachusproject.org/rdf/2009/framework#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/">
<head>
    <title resource="?this">Task: {rdfs:label}</title>
    <link rel="edit-form" href="?edit" />
    <link rel="comments" href="?discussion" />
    <link rel="describedby" href="?describe" />
    <link rel="version-history" href="?history" />
    
    <script>
        $(document).ready(function() {
            if ($('#priority').text() == "Priority A") {
                $('#priLogo').append('<img id="priImage" src="media/PriorityA.png" />')
                $('#priority').css({visibility: "hidden"})
            } else if ($('#priority').text() == "Priority B") {
                $('#priLogo').append('<img id="priImage" src="media/PriorityB.png" />')
                $('#priority').css({visibility: "hidden"})
            } else if ($('#priority').text() == "Priority C") {
                $('#priLogo').append('<img id="priImage" src="media/PriorityC.png" />')
                $('#priority').css({visibility: "hidden"})
            }
        });
    </script>
</head>
<body resource="?this">
    <h1 id="label">{rdfs:label}</h1>
    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span10">
                <!--Body content-->
                <p><a href="task-listing.xhtml?view">Return to task listing.</a></p>
                <iframe seamless="seamless" class="flex" id="iframe" src="{foaf:isPrimaryTopicOf}?view"></iframe>
            </div>
            <div class="span2">
                <!--Sidebar content-->
                <h2>Status:</h2>
                <p><span id="status" rel="ical:status">{skos:prefLabel}</span></p>
                <br/>
                <h2>Priority:</h2>
                <p><div id="priLogo"></div><span id="priority" rel="ical:priority">{skos:prefLabel}</span></p>
            </div>
        </div>
    </div>
</body>
</html>

You will see the Article view in an iFrame embedded in the view template.  The line for that is:

<iframe seamless="seamless" class="flex" id="iframe" src="{foaf:isPrimaryTopicOf}?view"></iframe>

Next let's create the Task class.  Each task that we create will be an instance of this class.  Navigate to the top of the application's folder hierarchy and select 'Class' from the Create menu.  That will allow you to create a class that will look like this:

Don't forget to associate the three templates (create, edit and view) with the Task class when you create it.  You can do that by dragging and dropping the URL for each template onto the appropriate template dropzones in the Task editor.

The Task class view already gives you a link to create a new task or view existing tasks.  Those links are shown in the upper right of the image above.  However, we might wish to create a more functional listing and better control how tasks are displayed.  The task listing we will create will use a JQuery DataTable so a user can sort tasks by name, priority and status.  It will look like this:

The HTML for the task listing is very simple.  The magic is in the Callimachus named SPARQL query that fills the DataTable.  The HTML is:

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<head>
<title>Task Listing</title>
<link rel="edit-form" href="?edit" />
<link rel="comments" href="?discussion" />
<link rel="describedby" href="?describe" />
<link rel="version-history" href="?history" />
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="js/datatables.js"></script>
<script type="text/javascript" src="js/task-listing.js"></script>
<link rel="stylesheet" type="text/css" href="css/datatables.css" />
</head>
<body>
<h1>Task Listing</h1>
<p><a href="Task?create">Add a new task</a></p>
<div id="listing"></div>
</body>
</html>

The purpose of the query is to return four components of each task: A URL to the task itself, the name of the task, the priority of the task and the status of the task.  The RDF that we are querying is the RDF that is created by the task create template each time a new task is created.  The query is saved in queries/tasks.rq and looks like this:

#
# @Cache-Control: 
# @infer true
# @view 
#
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ical: <http://www.w3.org/2002/12/cal/icaltzd#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
 
SELECT ?taskLink ?name ?priorityLabel ?statusLabel {
    ?taskLink a <../Task>
        ; rdfs:label ?name
        ; ical:priority ?priority
        ; ical:status ?status .
    ?priority skos:prefLabel ?priorityLabel .
    ?status skos:prefLabel ?statusLabel .     
}

Some JavaScript is necessary to draw the task listing.  The file js/task-listing.js contains the code that calls the SPARQL query and inserts the results into a DataTable.  The DataTable itself is defined in js/datatables.js and styled via css/datatables.css.

Your task listing will be initially empty until you create some tasks, like in the image below.  Just click on the "Add a new task" link to create a new task.  Tasks will be added automatically to the listing since the SPARQL query is called each time the page is reloaded.

When you create a task, you will be asked to save two different files (one for the RDF and the other for the Article).  Make sure to save them into the tasks/ folder to keep them straight.  You can safely use the default names for the files, which are drawn from the task label you provided.

That's all there is to it!  Have fun making other composite applications.