Site Skins
Creating skins (templates) for a SkyBlueCanvas site could not be easier. There is no PHP code to write and no complicated templating scripts. Simply build your HTML and CSS with the tool of your choice, and add simple tokens where the content will be placed. This approach to templating means you can very easily migrate your existing site design to SkyBlueCanvas.
Below is an example of a 3-column layout skin for SkyBlueCanvas.
<div id="wrapper" class="[class]">
<div id="header">
<h1>
<a href="{const:url}">{const:sitename}</a>
</h1>
</div>
<div id="top">
{content:top}
</div>
<div id="left">
{content:left}
</div>
<div id="main">
{content:main}
</div>
<div id="right">
{content:right}
</div>
<div id="footer">
{content:footer}
</div>
</div>
You will notice that the skin above does not contain the DOCTYPE, HTML, HEAD or BODY tags. This is because SkyBlueCanvas knows every HTML document has to have these elements, so it intelligently adds them for you. That means there is less code for you to write. You only create the basic structure for everything that appears between the BODY tags.
In fact, SkyBlueCanvas does not care at all about your HTML. When a page is displayed using your skin, SkyBlueCanvas really only cares about the tokens that tell it where to put the content. What is more, SkyBlueCanvas does not even dictate what the tokens are, only that they be properly formed. You can name your tokens whatever you like as long as they follow this basic format: {content:name}. That's it.
Extensions
The code below is the actual code for the Events manager for SkyBlueCanvas. As you can see, the code is short and simple. Most of the heavy lifting is handled by the Manager superclass. The HTML code that follows the sample PHP code is the input form for editing Events items.
<?php
defined('SKYBLUE') or die(basename(__FILE__));
class events extends manager
{
function events()
{
$this->Init();
}
function AddEventHandlers()
{
$this->AddEventHandler('OnBeforeSave', 'PrepareForSave');
}
function PrepareForSave()
{
$this->AddFieldValidation('name', 'notnull');
$this->SaveDescription();
}
function InitProps()
{
$this->SetProp('headings', array('Name', 'Date', 'Tasks'));
$this->SetProp('tasks', array('edit', 'delete'));
$this->SetProp('cols', array('name', 'date' ));
}
function SaveDescription()
{
global $Core;
$this->SaveStory(
$Core->GetVar($_POST,'story', $this->GetStoryFileName()),
stripslashes(urldecode($_POST['description'])));
$_POST['description'] =
base64_encode(stripslashes(urldecode($_POST['description'])));
}
function InitEditor()
{
global $Core;
// Set the form message
$this->SetFormMessage('Event');
// Initialize the object properties to empty strings or
// the properties of the object being edited
$_OBJ = $this->InitObjProps($this->skin, $this->obj);
// This step creates a $form array to pass to buildForm().
// buildForm() merges the $obj properites with the form HTML.
$form['ID'] = $this->GetItemID($_OBJ);
$form['NAME'] = $this->GetObjProp($_OBJ,'name');
$form['DATE'] = $this->GetObjProp($_OBJ,'date');
$form['TIME'] = $this->GetObjProp($_OBJ,'time');
$form['MERIDIAN'] = $Core->MeridianSelector($_OBJ['meridian']);
$form['VENUE'] = $this->GetObjProp($_OBJ,'venue');
$form['ADDRESS'] = $this->GetObjProp($_OBJ,'address');
$form['CITY'] = $this->GetObjProp($_OBJ,'city');
$form['STATE'] = $Core->StateSelector($_OBJ['state']);
$form['ZIP'] = $this->GetObjProp($_OBJ,'zip');
$form['ADMISSION'] = $this->GetObjProp($_OBJ,'admission');
$form['PHONE'] = $this->GetObjProp($_OBJ,'phone');
$form['URL'] = $this->GetObjProp($_OBJ,'url');
$form['DESCRIPTION'] = null;
$form['STORY'] = $this->GetStoryFileName();
$form['STYLESELECTOR'] = $this->GetObjProp($_OBJ,'styleselector');
$form['ORDER'] =
$Core->OrderSelector2($this->objs, 'name', $_OBJ['name']);
$this->BuildForm($form);
}
}
?>
The code below is the HTML for building the form for adding Events items in the SkyBlueCanvas admin control panel.
<input id="id"
type="hidden"
name="id"
value="{OBJ:ID}"
/>
<input id="objtype"
type="hidden"
name="objtype"
value="events"
/>
<label for="name">[TERM:NAME]:</label>
<input type="text"
name="name"
value="{OBJ:NAME}"
size="45"
/>
<label for="date">[TERM:DATE]:</label>
<input type="text"
name="date"
value="{OBJ:DATE}"
size="45"
/>
<label for="time">[TERM:TIME]:</label>
<input type="text"
name="time"
value="{OBJ:TIME}"
size="10"
/>
{OBJ:MERIDIAN}
<label for="admission">[TERM:ADMISSION]:</label>
<input type="text"
name="admission"
value="{OBJ:ADMISSION}"
size="45"
/>
<label for="venue">[TERM:VENUE]:</label>
<input type="text"
name="venue"
value="{OBJ:VENUE}"
size="45"
/>
<label for="phone">[TERM:PHONE]:</label>
<input type="text"
name="phone"
value="{OBJ:PHONE}"
size="45"
/>
<label for="address">[TERM:ADDRESS]:</label>
<input type="text"
name="address"
value="{OBJ:ADDRESS}"
size="45"
/>
<label for="city">[TERM:CITY]:</label>
<input type="text"
name="city"
value="{OBJ:CITY}"
size="45"
/>
<label for="state">[TERM:STATE]:</label>
{OBJ:STATE}
<td valign="top">[TERM:ZIP]:</label>
<input type="text"
name="zip"
value="{OBJ:ZIP}"
size="45"
/>
<label for="url">[TERM:URL]:</label>
<input type="text"
name="url"
value="{OBJ:URL}"
size="45"
/>
<label for="description">[TERM:DESCRIPTION]:</label>
<div id="editoranchor"></div>
<textarea id="story_content"
name="description"
cols="55"
rows="22"></textarea>
<input id="storyfile"
type="hidden"
name="story"
value="{OBJ:STORY}"
/>
<label for="order">[TERM:ORDER]:</label>
{OBJ:ORDER}