summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README32
-rw-r--r--TODO4
-rw-r--r--code/admin/add.php55
-rw-r--r--code/admin/admin.css15
-rw-r--r--code/admin/admin.js123
-rw-r--r--code/admin/ajax.php63
-rw-r--r--code/admin/auth.php53
-rw-r--r--code/admin/editor-bind-code.html71
-rw-r--r--code/admin/index.php111
-rw-r--r--code/admin/render.php59
-rw-r--r--code/admin/utils.php179
-rw-r--r--code/index.php9
-rwxr-xr-xdist/build_all.sh2
-rw-r--r--dist/debian/TODO0
-rw-r--r--dist/out/.builds-goes-here1
-rwxr-xr-xdist/scripts/po2mo.sh9
-rw-r--r--libs/microajax/microajax.minified.js1
-rw-r--r--libs/treeview/treeview.css121
-rw-r--r--libs/treeview/treeview_icons.pngbin0 -> 762 bytes
-rw-r--r--locale/en_US.po110
-rw-r--r--locale/fr_FR.po110
-rw-r--r--samplefiles/content/en/start/div-content.html27
-rw-r--r--samplefiles/content/en/start/div-teaser.html3
-rw-r--r--samplefiles/content/en/start/props.ini5
-rw-r--r--samplefiles/content/fr/accueil/div-content.html27
-rw-r--r--samplefiles/content/fr/accueil/div-teaser.html3
-rw-r--r--samplefiles/content/fr/accueil/props.ini5
-rw-r--r--samplefiles/content/site_conf.ini3
-rw-r--r--samplefiles/templates/aloha/images/background.pngbin0 -> 251 bytes
-rw-r--r--samplefiles/templates/aloha/images/external-link-ltr-icon.pngbin0 -> 279 bytes
-rw-r--r--samplefiles/templates/aloha/layout-article.php15
-rw-r--r--samplefiles/templates/aloha/screen.css79
-rw-r--r--samplefiles/templates/default/layout-article.php12
-rw-r--r--samplefiles/templates/default/screen.css0
34 files changed, 1307 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..fdedf5b
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+
+Open-Source or public-domain components reused in this project
+ * TreeView (http://acidmartin.wordpress.com/tag/html5-treeview/)
+ * MicroAJAX (http://code.google.com/p/microajax/)
+ * Aloha Editor
+ * PlUpload
+
+
+MicroAJAX Copyright Notice :
+
+/*
+Copyright (c) 2008 Stefan Lange-Hegermann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..cbaeb35
--- /dev/null
+++ b/TODO
@@ -0,0 +1,4 @@
+
+S'intéresser à http://pico.dev7studios.com/docs.html
+
+Ecrire un writer pour sauver les modifs faites avec aloha
diff --git a/code/admin/add.php b/code/admin/add.php
new file mode 100644
index 0000000..c839e0a
--- /dev/null
+++ b/code/admin/add.php
@@ -0,0 +1,55 @@
+<?php
+ require_once('utils.php');
+ need_auth();
+
+ // Config loading
+ $site_conf = load_ini_site_conf("content/site_conf.ini");
+ if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR);
+
+ // Localization Init
+ l10n_init($site_conf['site_admin_lang']);
+
+ $kind=sanitize($_GET, 'kind', '/[^a-z_]+/', 'page'); /* Could be : page, media */
+?>
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<link rel="stylesheet" href="treeview.css">
+<link rel="stylesheet" href="admin.css">
+<script type="text/javascript" src="admin.js"></script>
+<title><?=($kind=='media')?_('Add media'):_('Add page')?></title>
+</head>
+<body>
+<form>
+
+<fieldset>
+<legend><?=($kind=='media')?_('Media tree'):_('Page tree')?></legend>
+<div class="css-treeview">
+<?php
+ if ($kind=='media') {
+ $tree=find_all('../media', 'media');
+ } else {
+ $tree=find_all('./content', 'page');
+ }
+ php_array_to_tree($tree, 'select_fold');
+?>
+</div>
+</fieldset>
+
+<fieldset>
+<legend><?=($kind=='media')?_('Media folder'):_('Page folder')?></legend>
+<label for="fold_path"><?=_('Folder path')?></label>
+<input id="fold_path" name="fold_path" readonly="readonly" value="<?=_('(choose a folder in the tree)')?>"><br>
+
+<label for="fold_add_name"><?=_('New item name')?></label>
+<input id="fold_add_name" type="text" value="">
+
+<label for="fold_add_fold"><?=_('Actions')?></label>
+<input id="fold_add_fold" type="button" value="<?=_('Add folder')?>" onclick="go_add('<?=$kind?>','fold');">
+<input id="fold_add_item" type="button" value="<?=_('Add page')?>" onclick="go_add('<?=$kind?>','item');">
+</fieldset>
+
+</form>
+</body>
+</html>
diff --git a/code/admin/admin.css b/code/admin/admin.css
new file mode 100644
index 0000000..f01a35d
--- /dev/null
+++ b/code/admin/admin.css
@@ -0,0 +1,15 @@
+fieldset {
+ display:inline-block;
+ vertical-align: top;
+ margin: 0.5em;
+ width:45%;
+}
+fieldset>label {
+ display:inline-block;
+ text-align:right;
+ width: 12em;
+}
+.tree_add {
+ display:block;
+ float:right;
+}
diff --git a/code/admin/admin.js b/code/admin/admin.js
new file mode 100644
index 0000000..3d0125d
--- /dev/null
+++ b/code/admin/admin.js
@@ -0,0 +1,123 @@
+// Helpers
+function gEBId(id) { return document.getElementById(id) };
+
+function microAjaxJSON(query,callback) {
+ microAjax(query,function (res) {
+ var parsed_json;
+ try {
+ parsed_json = JSON.parse(res);
+ } catch(err) {
+ alert(res);
+ return;
+ }
+ callback(parsed_json);
+ });
+}
+
+// Admin simple actions
+function select_fold(path) {
+ gEBId("fold_path").value=path;
+}
+
+// Admin AJAX actions
+function load_page_props(path) {
+ gEBId("page_path").value=path;
+ var url = "ajax.php?action=load_page_props&path=" + encodeURIComponent(path);
+ microAjaxJSON(url, function (parsed_json) {
+ gEBId("page_title").value = parsed_json.page_title;
+ gEBId("page_description").value = parsed_json.page_description;
+ gEBId("page_keywords").value = parsed_json.page_keywords;
+ });
+}
+
+function load_media_props(path) {
+ gEBId("media_path").value=path;
+ var url = "ajax.php?action=load_media_props&path=" + encodeURIComponent(path);
+ microAjaxJSON(url, function (parsed_json) {
+ gEBId("media_title").value = parsed_json.media_title;
+ gEBId("media_description").value = parsed_json.media_description;
+ //gEBId("media_keywords").value = parsed_json.media_keywords;
+ });
+}
+
+function save_page_props() {
+ var path = gEBId("page_path").value;
+ var page_title = gEBId("page_title").value;
+ var page_description = gEBId("page_description").value;
+ var page_keywords = gEBId("page_keywords").value;
+
+ //TODO : check against regex
+
+ var url = "ajax.php?action=save_page_props"
+ + "&path=" + encodeURIComponent(path)
+ + "&page_title=" + encodeURIComponent(page_title)
+ + "&page_description=" + encodeURIComponent(page_description)
+ + "&page_keywords=" + encodeURIComponent(page_keywords);
+
+ microAjaxJSON(url, function (parsed_json) {
+ if ( parsed_json.result != "OK" ) {
+ alert("Error\nResult: " + parsed_json.result + "\nRequest: " + url);
+ return;
+ }
+ //TODO : says to user that the work is done
+ });
+}
+
+function save_media_props() {
+ var path = gEBId("media_path").value;
+ var title = gEBId("media_title").value;
+ var description = gEBId("media_description").value;
+ //var keywords = gEBId("media_keywords").value;
+
+ //TODO : check against regex
+
+ var url = "ajax.php?action=save_media_props"
+ + "&path=" + encodeURIComponent(path)
+ + "&title=" + encodeURIComponent(title)
+ + "&description=" + encodeURIComponent(description);
+ // + "&keywords=" + encodeURIComponent(keywords);
+
+ microAjaxJSON(url, function (parsed_json) {
+ if ( parsed_json.result != "OK" ) {
+ alert("Error\nResult: " + parsed_json.result + "\nRequest: " + url);
+ return;
+ }
+ //TODO : says to user that the work is done
+ });
+}
+
+function save_site_props() {
+ //TODO
+}
+
+// Admin other actions (with page change or refresh)
+function go_add_form(kind) {
+ document.location = 'add.php?kind=' + encodeURIComponent(kind);
+}
+
+function go_add(kind,type) {
+ var path = gEBId("fold_path").value;
+ var name = gEBId("fold_add_name").value;
+ // TODO : check name and path against regex
+ var url = 'add.php?kind=' + encodeURIComponent(kind)
+ + '&action=add_' + encodeURIComponent(type)
+ + '&path=' + encodeURIComponent(path)
+ + '&name=' + encodeURIComponent(name);
+ document.location = url;
+}
+
+function go_edit_page() {
+ var path = gEBId("page_path").value;
+ document.location = 'render.php?action=edit&page=' + encodeURIComponent(path);
+}
+
+function go_delete_page() {
+ var path = gEBId("page_path").value;
+ //TODO : confirmation, ajax query, if OK, confirm then refresh
+}
+
+function go_delete_media() {
+ var path = gEBId("page_path").value;
+ //TODO : confirmation, ajax query, if OK, confirm then refresh
+}
+
diff --git a/code/admin/ajax.php b/code/admin/ajax.php
new file mode 100644
index 0000000..0893843
--- /dev/null
+++ b/code/admin/ajax.php
@@ -0,0 +1,63 @@
+<?php
+ require_once('utils.php');
+ need_auth();
+
+ function load_page_props($path) {
+ return load_ini_page_props($path);
+ }
+
+ function load_media_props($path) {
+ return array(
+ 'media_title' => 'test title',
+ 'media_description' => 'test descr',
+ 'media_keywords' => 'test, keyword',
+ );
+ }
+
+ function save_page_props($path) {
+ //TODO : Should validate props here also...
+ $props=load_page_props($path);
+
+ foreach ( array('page_title', 'page_description', 'page_keywords') as $k ) {
+ if ( array_key_exists($k,$_GET) ) $props[$k]=$_GET[$k];
+ }
+
+ $ini_path="content/$path/props.ini";
+ return write_ini_file($props, $ini_path, false);
+ }
+
+ function save_media_props($path) {
+ return FALSE;
+ }
+
+ // URL params clean-up
+ $action=sanitize($_GET, 'action', '/[^a-z_]+/', 'none'); /* Could be : load_page_props, load_media_props... */
+ $path=sanitize($_GET, 'path', '/[^a-z0-9\/]+/', ''); // Never put \. in this regex
+
+ switch($action) {
+ case 'load_page_props':
+ $res = load_page_props($path);
+ break;
+ case 'load_media_props':
+ $res = load_media_props($path);
+ break;
+ case 'save_page_props':
+ if ( save_page_props($path) ) {
+ $res=array('result' => 'OK');
+ } else {
+ $res=array('result' => 'FAILED');
+ }
+ break;
+ case 'save_media_props':
+ if ( save_media_props($path) ) {
+ $res=array('result' => 'OK');
+ } else {
+ $res=array('result' => 'FAILED');
+ }
+ break;
+ default:
+ $res = array('result' => 'ERROR', 'error'=>'invalid action');
+ break;
+ }
+ echo json_encode($res);
+?>
diff --git a/code/admin/auth.php b/code/admin/auth.php
new file mode 100644
index 0000000..f4afee0
--- /dev/null
+++ b/code/admin/auth.php
@@ -0,0 +1,53 @@
+<?php
+ // Edit secrets here
+ $configured_user = 'admin';
+ $configured_pass = 'admin';
+
+ // Auth validation
+ $auth_fail=FALSE;
+ if ( array_key_exists('u', $_POST) && array_key_exists('p', $_POST) ) {
+ if ( $_POST['u'] === $configured_user && $_POST['p'] === $configured_pass ) {
+ // Auth success
+ session_start();
+ $_SESSION['auth_user'] = TRUE;
+ // Auto-redirect to previous page
+ if ( array_key_exists('auth_return', $_SESSION) && (strlen($_SESSION['auth_return']) > 0) ) {
+ header('Location: ' . $_SESSION['auth_return']);
+ }
+ echo "Authenticated\n";
+ exit();
+ } else {
+ $auth_fail=TRUE;
+ }
+ }
+?>
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Authentification</title>
+</head>
+<body>
+<form method="post">
+ <fieldset style="float:left">
+ <legend>Authentification</legend>
+ <table>
+ <tr>
+ <td><label>User</label></td>
+ <td><input type="text" name="u" value="admin"></td>
+ </tr>
+ <tr>
+ <td><label>Pass</label></td>
+ <td><input type="password" name="p" value="admin"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right">
+ <span><?php if ($auth_fail) echo "Login failed";?></span>
+ <input type="submit" value="Login">
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</form>
+</body>
+</html>
diff --git a/code/admin/editor-bind-code.html b/code/admin/editor-bind-code.html
new file mode 100644
index 0000000..d6a9825
--- /dev/null
+++ b/code/admin/editor-bind-code.html
@@ -0,0 +1,71 @@
+<!-- Editor deffered loading -->
+<link href="http://cdn.aloha-editor.org/latest/css/aloha.css" type="text/css" rel="stylesheet">
+<script type="text/javascript" src="http://cdn.aloha-editor.org/latest/lib/vendor/jquery-1.7.1.js"></script>
+<script type="text/javascript" src="http://cdn.aloha-editor.org/latest/lib/require.js"></script>
+<script>
+ var Aloha = window.Aloha || ( window.Aloha = {} );
+
+ Aloha.settings = {
+ locale: 'fr',
+ plugins: {
+ format: {
+ config : [ 'b', 'i','sub','sup'],
+ editables : {
+ // no formatting allowed for title
+ '#title' : [ ],
+ // formatting for all editable DIVs
+ 'div' : [ 'b', 'i', 'del', 'sub', 'sup' ],
+ // content is a DIV and has class .article so it gets both buttons
+ '.article' : [ 'b', 'i', 'p', 'title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'removeFormat']
+ }
+ },
+ list: {
+ // all elements with no specific configuration get an UL, just for fun :)
+ config : [ 'ul' ],
+ editables : {
+ // Even if this is configured it is not set because OL and UL are not allowed in H1.
+ '#title' : [ 'ol' ],
+ // all divs get OL
+ 'div' : [ 'ol' ],
+ // content is a DIV. It would get only OL but with class .article it also gets UL.
+ '.article' : [ 'ul' ]
+ }
+ },
+ link: {
+ config : [ 'a' ],
+ editables : {
+ // No links in the title.
+ '#title' : [ ]
+ }
+ }
+ },
+ sidebar: {
+ disabled: false
+ }
+ };
+</script>
+
+<script type="text/javascript" src="http://cdn.aloha-editor.org/latest/lib/aloha.js"
+ data-aloha-plugins="common/ui,
+ common/format,
+ common/table,
+ common/list,
+ common/link,
+ common/highlighteditables,
+ common/block,
+ common/undo,
+ common/image,
+ common/contenthandler,
+ common/paste,
+ common/commands,
+ common/abbr"></script>
+
+<script type="text/javascript">
+Aloha.ready(function() {
+ // mark the editable parts
+ $('#title').aloha();
+ $('#teaser').aloha();
+ $('#content').aloha();
+});
+
+</script>
diff --git a/code/admin/index.php b/code/admin/index.php
new file mode 100644
index 0000000..ddb95b3
--- /dev/null
+++ b/code/admin/index.php
@@ -0,0 +1,111 @@
+<?php
+ require_once('utils.php');
+ need_auth();
+
+ // Config loading
+ $site_conf = load_ini_site_conf("content/site_conf.ini");
+ if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR);
+
+ // Localization Init
+ l10n_init($site_conf['site_admin_lang']);
+?>
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<link rel="stylesheet" href="treeview.css">
+<link rel="stylesheet" href="admin.css">
+<script type="text/javascript" src="microajax.minified.js"></script>
+<script type="text/javascript" src="admin.js"></script>
+<title><?=_('Admin')?></title>
+</head>
+<body>
+<form>
+
+<fieldset>
+<legend><?=_('Page tree')?></legend>
+<input id="page_add" class="tree_add" type="button" value="<?=_('Add page')?>" onclick="go_add_form('page');">
+<div class="css-treeview">
+<?php
+ $page_tree=find_all('./content', 'page');
+ //echo '<pre>' . print_r($page_tree,true) . '</pre>' . "\n";
+ php_array_to_tree($page_tree, '', 'load_page_props', '', 'pagedir-0');
+?>
+</div>
+</fieldset>
+
+<fieldset>
+<legend><?=_('Selected page')?></legend>
+<label for="page_path"><?=_('Page path')?></label>
+<input id="page_path" name="page_path" readonly="readonly" value="<?=_('(choose a page in the tree)')?>"><br>
+
+<label for="page_edit"><?=_('Actions')?></label>
+<input id="page_edit" type="button" value="<?=_('Edit page')?>" onclick="go_edit_page();">
+<input id="page_delete" type="button" value="<?=_('Delete page')?>" onclick="go_delete_page();">
+
+<br><br>
+
+<label for="page_title"><?=_('Page title')?></label>
+<input id="page_title" name="page_title" value=""><br>
+
+<label for="page_description"><?=_('Page description')?></label>
+<input id="page_description" name="page_description" value=""><br>
+
+<label for="page_keywords"><?=_('Page keywords')?></label>
+<input id="page_keywords" name="page_keywords" value=""><br>
+
+<label for="page_submit"></label>
+<input id="page_submit" type="button" value="<?=_('Save properties')?>" onclick="save_page_props();"><br>
+</fieldset>
+
+<fieldset>
+<legend><?=_('Media tree')?></legend>
+<input id="media_add" class="tree_add" type="button" value="<?=_('Add media')?>" onclick="go_add_form('media');">
+<div class="css-treeview">
+<?php
+ $media_tree=find_all('../media', 'media');
+ //echo '<pre>' . print_r($media_tree,true) . '</pre>' . "\n";
+ php_array_to_tree($media_tree, '', 'load_media_props', '', 'mediadir-0');
+?>
+</div>
+</fieldset>
+
+<fieldset>
+<legend><?=_('Selected Media')?></legend>
+<label for="media_path"><?=_('Media path')?></label>
+<input id="media_path" name="media_path" readonly="readonly" value="<?=_('(choose a media in the tree)')?>"><br>
+
+<label for="media_edit"><?=_('Actions')?></label>
+<!--<input id="media_edit" type="button" value="Edit media">-->
+<input id="media_delete" type="button" value="<?=_('Delete media')?>" onclick="go_delete_media();">
+
+<br><br>
+
+<label for="media_title"><?=_('Media title')?></label>
+<input id="media_title" name="media_title" value=""><br>
+
+<label for="media_description"><?=_('Media description')?></label>
+<input id="media_description" name="media_description" value=""><br>
+<!--
+<label for="media_keywords">Media keywords</label>
+<input id="media_keywords" name="media_keywords" value=""><br>
+-->
+<label for="media_submit"></label>
+<input id="media_submit" type="button" value="<?=_('Save properties')?>" onclick="save_media_props();"><br>
+</fieldset>
+
+<fieldset>
+<legend><?=_('Site properties')?></legend>
+<label for="site_admin_lang"><?=_('Admin lang')?></label>
+<input id="site_admin_lang" name="site_admin_lang" value="<?=$site_conf['site_admin_lang']?>"><br>
+
+<label for="site_default_page"><?=_('Default page')?></label>
+<input id="site_default_page" name="site_default_page" value="<?=$site_conf['site_default_page']?>"><br>
+
+<label for="site_submit"></label>
+<input id="site_submit" type="button" value="<?=_('Save properties')?>" onclick="save_site_props();"><br>
+</fieldset>
+
+</form>
+</body>
+</html>
diff --git a/code/admin/render.php b/code/admin/render.php
new file mode 100644
index 0000000..9d4175e
--- /dev/null
+++ b/code/admin/render.php
@@ -0,0 +1,59 @@
+<?php
+ require_once('utils.php');
+ need_auth();
+
+ // Config loading
+ $site_conf = load_ini_site_conf("content/site_conf.ini");
+ if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR);
+
+ // URL params clean-up
+ $action=sanitize($_GET, 'action', '/[^a-z_]+/', 'preview'); /* Could be : preview, edit, publish */
+ $page=sanitize($_GET, 'page', '/[^a-z0-9\/]+/', $site_conf['site_default_page']); // Never put \. in this regex
+
+ // Template vars init ($page, $page_path, $page_props, $page_tpl_url)
+ $page_path = "content/$page";
+ if ( ! is_dir($page_path) ) trigger_error("Error : page does not exists ($page)", E_USER_ERROR);
+ $page_props = load_ini_page_props($page);
+ if ( ! is_array($page_props) ) trigger_error("Error parsing page properties ($page/props.ini)", E_USER_ERROR);
+ $page_tpl_url = str_repeat('../', substr_count($page, '/')) . "admin/templates/" . $page_props['page_template'] . '/';
+
+ if ($action === 'publish') ob_start(); /* Buffering for redirecting to file instead of browser */
+
+ // Basic HTML5 skeleton + page props insertion + template call
+?>
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title><?=$page_props['page_title']?></title>
+<meta name="description" content="<?=$page_props['page_description']?>">
+<meta name="keywords" content="<?=$page_props['page_keywords']?>">
+<link rel="stylesheet" href="<?="$page_tpl_url" /*FIXME*/?>screen.css">
+</head>
+<body>
+<?php
+ require("templates/" . $page_props['page_template'] . '/layout-' . $page_props['page_layout'] . '.php');
+ if ( $action === 'edit') require('editor-bind-code.html');
+?>
+</body>
+</html>
+<?php
+ // If publishing, write resulting HTML page on a .html file
+ if ($action === 'publish') {
+ $out=ob_get_contents();
+ ob_end_clean();
+ $dest="../$page.html";
+ $destfold=dirname($dest);
+ if ( ! is_dir($destfold) ) {
+ if ( ! mkdir($destfold,0777,true) ) {
+ trigger_error("Error : Can't create '$destfold'", E_USER_ERROR);
+ }
+ }
+ $size=file_put_contents($dest, $out);
+ if ( $size === FALSE ) {
+ trigger_error("Error : Can't write " . strlen($out) . " bytes to '$dest'", E_USER_ERROR);
+ } else {
+ echo json_encode(array('result'=>'ok', 'size' => $size));
+ }
+ }
+?>
diff --git a/code/admin/utils.php b/code/admin/utils.php
new file mode 100644
index 0000000..f02146a
--- /dev/null
+++ b/code/admin/utils.php
@@ -0,0 +1,179 @@
+<?php
+ function sanitize($arg_array, $arg_key, $replace_chars_re, $default_value) {
+ //FIXME : should check string type and strlen !
+ if ( ! array_key_exists($arg_key, $arg_array) ) return $default_value;
+ return preg_replace($replace_chars_re, '_', $arg_array[$arg_key]);
+ }
+
+ function sanitize_ini($ini_path, $array_entry_props) {
+ $array_ini = parse_ini_file($ini_path);
+ if ( is_array($array_ini) ) {
+ // Sanitize any existing ini entries. Destroy unwanted ones.
+ foreach ( $array_ini as $k => $v ) {
+ if ( array_key_exists($k, $array_entry_props)
+ && array_key_exists('replace_chars_re', $array_entry_props[$k])
+ && array_key_exists('default_value', $array_entry_props[$k])
+ ) {
+ $array_ini[$k] = sanitize($array_ini, $k,
+ $array_entry_props[$k]['replace_chars_re'],
+ $array_entry_props[$k]['default_value'] );
+ } else {
+ unset($array_ini[$k]);
+ }
+ }
+ // Set default value for all missing ini entries (if default value exists)
+ foreach ( $array_entry_props as $k => $v ) {
+ if ( !array_key_exists($k, $array_ini) && array_key_exists('default_value', $array_entry_props[$k]) ) {
+ $array_ini[$k] = $array_entry_props[$k]['default_value'];
+ }
+ }
+ }
+ return $array_ini;
+ }
+
+ function load_ini_site_conf($ini_path) {
+ $sanitize_site_conf = array(
+ 'site_admin_lang' => array( 'replace_chars_re' => '/[^a-zA-Z\/\_-]+/', 'default_value' => 'C' ),
+ 'site_default_page' => array( 'replace_chars_re' => '/[^a-z0-9\/]+/', 'default_value' => 'en/index' ),
+ );
+ return sanitize_ini($ini_path, $sanitize_site_conf);
+ }
+
+ function load_ini_page_props($page) {
+ $sanitize_page_props = array(
+ //FIXME : title regex : all but html special chars ?
+ 'page_title' => array( 'replace_chars_re' => '/[^\w !_,.-]+/', 'default_value' => '(missing title in props.ini)' ),
+ 'page_template' => array( 'replace_chars_re' => '/[^a-z0-9]+/', 'default_value' => 'default' ),
+ 'page_layout' => array( 'replace_chars_re' => '/[^a-z0-9]+/', 'default_value' => 'article' ),
+ 'page_description' => array( 'replace_chars_re' => '/[^\w !_,.-]+/', 'default_value' => '(missing description in props.ini)' ),
+ 'page_keywords' => array( 'replace_chars_re' => '/[^\w !_,.-]+/', 'default_value' => '(missing keywords in props.ini)' ),
+ );
+ $ini_path="content/$page/props.ini";
+ return sanitize_ini($ini_path, $sanitize_page_props);
+ }
+
+ function l10n_init($lang) {
+ setlocale(LC_MESSAGES, "$lang.utf8");
+ $base = bindtextdomain('editablesite', './locale');
+ $domain = textdomain('editablesite');
+ bind_textdomain_codeset('editablesite', 'UTF-8');
+ //echo "<pre>l10n file is '$base/$lang.utf8/LC_MESSAGES/$domain.mo'</pre>\n";
+ }
+
+ function need_auth() {
+ session_start();
+ if ( ! array_key_exists('auth_user', $_SESSION) || $_SESSION['auth_user'] !== TRUE ) {
+ $_SESSION['auth_return'] = $_SERVER['REQUEST_URI'];
+ header('Location: auth.php');
+ exit();
+ }
+ }
+
+ function is_ress($kind, $path) {
+ switch ($kind) {
+ case 'page': return is_file($path.'/props.ini');
+ case 'media': return substr($path, -4)=='.jpg' && is_file($path);
+ default : return FALSE;
+ }
+ }
+
+ function strcmp_tree($a,$b) {
+ if (is_array($a) || is_array($b) ) return 0;
+ return strnatcasecmp($a,$b);
+ }
+
+ function find_all($path, $kind) {
+ $result=array();
+ if ( $handle = opendir($path) ) {
+ while (FALSE !== ($entry = readdir($handle))) {
+ if ( array_search($entry, array('.','..')) !== FALSE ) continue;
+ $childpath=$path.'/'.$entry;
+ if ( is_ress($kind, $childpath) ) $result[] = $entry;
+ else if ( is_dir($childpath) ) $result[$entry]=find_all($childpath,$kind);
+ }
+ closedir($handle);
+ }
+ uasort($result, 'strcmp_tree');
+ return $result;
+ }
+
+ function php_array_to_tree($page_tree, $node_cb, $leaf_cb='', $path='', $itemid="item-0") {
+ if ( ! is_array($page_tree) ) return;
+ echo "<ul>\n";
+ foreach ($page_tree as $k => $v) {
+ if ( is_numeric($k) ) {
+ // Leaf
+ if ( strlen($leaf_cb) > 0 ) {
+ echo '<li><a href="javascript:' . $leaf_cb . "('$path$v');" . '">' . $v . '</a></li>' . "\n";
+ } else {
+ echo "<li>$v</li>\n";
+ }
+ } else {
+ // Node
+ // Increment $itemid last component
+ // "1-1-2-1" will come "1-1-2-2"
+ $tmp = explode('-', $itemid);
+ array_push($tmp, array_pop($tmp) + 1);
+ $itemid = implode('-', $tmp);
+ $tmp=null;
+ /// Write the node
+ echo "<li>\n";
+ echo '<input type="checkbox" checked="checked" id="' . $itemid . '">' . "\n";
+ echo '<label for="' . $itemid . '">';
+ if ( strlen($node_cb) > 0 ) {
+ echo '<a href="javascript:' . $node_cb . "('$path$k');" . '">' . $k . '</a>';
+ } else {
+ echo $k;
+ }
+ echo "</label>\n";
+ // Recursively build the tree below the node
+ php_array_to_tree($v, $node_cb, $leaf_cb, $path.$k.'/', $itemid."-0");
+ echo "</li>\n";
+ }
+ }
+ echo "</ul>\n";
+ }
+
+ function safe_put_file($path, $content) {
+ //FIXME : if exists, then mktemp, put in it then rm and mv. Right preservation problems ?
+ if ($handle = fopen($path, 'w')) {
+ $res = fwrite($handle, $content);
+ fclose($handle);
+ }
+ }
+
+ function _write_ini_file_r(&$content, $assoc_arr, $has_sections)
+ {
+ foreach ($assoc_arr as $key => $val) {
+ if (is_array($val)) {
+ if($has_sections) {
+ $content .= "[$key]\n";
+ _write_ini_file_r($content, $val, false);
+ } else {
+ foreach($val as $iKey => $iVal) {
+ if (is_int($iKey))
+ $content .= $key ."[] = $iVal\n";
+ else
+ $content .= $key ."[$iKey] = $iVal\n";
+ }
+ }
+ } else {
+ if ( preg_match('/^\w+$/',$val)===1 )
+ $content .= "$key = $val\n";
+ else
+ $content .= "$key = \"" . str_replace('"', '\"', $val) . "\"\n";
+ }
+ }
+ }
+
+ function write_ini_file($assoc_arr, $path, $has_sections) {
+ $res=FALSE;
+ $content = '';
+ _write_ini_file_r($content, $assoc_arr, $has_sections);
+ if (is_string($content) && strlen($content) > 0) {
+ safe_put_file($path, $content);
+ }
+
+ return $res;
+ }
+
diff --git a/code/index.php b/code/index.php
new file mode 100644
index 0000000..b07f778
--- /dev/null
+++ b/code/index.php
@@ -0,0 +1,9 @@
+<?php
+ chdir('admin/');
+ require_once('utils.php');
+
+ // Config loading
+ $site_conf = load_ini_site_conf("content/site_conf.ini");
+ if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR);
+
+ header('Location: ' . $site_conf['site_default_page'].'.html');
diff --git a/dist/build_all.sh b/dist/build_all.sh
new file mode 100755
index 0000000..05a7907
--- /dev/null
+++ b/dist/build_all.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+
diff --git a/dist/debian/TODO b/dist/debian/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dist/debian/TODO
diff --git a/dist/out/.builds-goes-here b/dist/out/.builds-goes-here
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/dist/out/.builds-goes-here
@@ -0,0 +1 @@
+
diff --git a/dist/scripts/po2mo.sh b/dist/scripts/po2mo.sh
new file mode 100755
index 0000000..7be049b
--- /dev/null
+++ b/dist/scripts/po2mo.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+for f in *.po
+do
+ mo_dir=${f%%.po}.utf8/LC_MESSAGES/
+ [ -d "$mo_dir" ] || mkdir -p "$mo_dir"
+
+ echo msgfmt -o "$mo_dir/editablesite.mo" "$f"
+ msgfmt -o "$mo_dir/editablesite.mo" "$f"
+done
diff --git a/libs/microajax/microajax.minified.js b/libs/microajax/microajax.minified.js
new file mode 100644
index 0000000..5ccdc8f
--- /dev/null
+++ b/libs/microajax/microajax.minified.js
@@ -0,0 +1 @@
+function microAjax(B,A){this.bindFunction=function(E,D){return function(){return E.apply(D,[D])}};this.stateChange=function(D){if(this.request.readyState==4){this.callbackFunction(this.request.responseText)}};this.getRequest=function(){if(window.ActiveXObject){return new ActiveXObject("Microsoft.XMLHTTP")}else{if(window.XMLHttpRequest){return new XMLHttpRequest()}}return false};this.postBody=(arguments[2]||"");this.callbackFunction=A;this.url=B;this.request=this.getRequest();if(this.request){var C=this.request;C.onreadystatechange=this.bindFunction(this.stateChange,this);if(this.postBody!==""){C.open("POST",B,true);C.setRequestHeader("X-Requested-With","XMLHttpRequest");C.setRequestHeader("Content-type","application/x-www-form-urlencoded");C.setRequestHeader("Connection","close")}else{C.open("GET",B,true)}C.send(this.postBody)}}; \ No newline at end of file
diff --git a/libs/treeview/treeview.css b/libs/treeview/treeview.css
new file mode 100644
index 0000000..2c14f1a
--- /dev/null
+++ b/libs/treeview/treeview.css
@@ -0,0 +1,121 @@
+.css-treeview ul,
+.css-treeview li
+{
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.css-treeview input
+{
+ position: absolute;
+ opacity: 0;
+}
+
+.css-treeview
+{
+ font: normal 11px Arial, Sans-serif;
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+
+.css-treeview a
+{
+ color: #00f;
+ text-decoration: none;
+}
+
+.css-treeview a:hover
+{
+ text-decoration: underline;
+}
+
+.css-treeview input + label + ul
+{
+ margin: 0 0 0 22px;
+}
+
+.css-treeview input ~ ul
+{
+ display: none;
+}
+
+.css-treeview label,
+.css-treeview label::before
+{
+ cursor: pointer;
+}
+
+.css-treeview input:disabled + label
+{
+ cursor: default;
+ opacity: .6;
+}
+
+.css-treeview input:checked:not(:disabled) ~ ul
+{
+ display: block;
+}
+
+.css-treeview label,
+.css-treeview label::before
+{
+ background: url("treeview_icons.png") no-repeat;
+}
+
+.css-treeview label,
+.css-treeview a,
+.css-treeview label::before
+{
+ display: inline-block;
+ height: 16px;
+ line-height: 16px;,
+ vertical-align: middle;
+}
+
+.css-treeview label
+{
+ background-position: 18px 0;
+}
+
+.css-treeview label::before
+{
+ content: "";
+ width: 16px;
+ margin: 0 22px 0 0;
+ vertical-align: middle;
+ background-position: 0 -32px;
+}
+
+.css-treeview input:checked + label::before
+{
+ background-position: 0 -16px;
+}
+
+.css-treeview input.new + label::before
+{
+ background-position: 0 -48px;
+}
+
+/* webkit adjacent element selector bugfix */
+@media screen and (-webkit-min-device-pixel-ratio:0)
+{
+ .css-treeview
+ {
+ -webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
+ }
+
+ @-webkit-keyframes webkit-adjacent-element-selector-bugfix
+ {
+ from
+ {
+ padding: 0;
+ }
+ to
+ {
+ padding: 0;
+ }
+ }
+}
+
diff --git a/libs/treeview/treeview_icons.png b/libs/treeview/treeview_icons.png
new file mode 100644
index 0000000..924cd5b
--- /dev/null
+++ b/libs/treeview/treeview_icons.png
Binary files differ
diff --git a/locale/en_US.po b/locale/en_US.po
new file mode 100644
index 0000000..2ab1692
--- /dev/null
+++ b/locale/en_US.po
@@ -0,0 +1,110 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: EditableSite\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-10-28 18:16+0100\n"
+"PO-Revision-Date: 2013-10-28 18:16+0100\n"
+"Last-Translator: Ludovic Pouzenc <lpouzenc@gmail.com>\n"
+"Language-Team: \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
+"X-Poedit-Basepath: /var/www/EditableSite\n"
+"X-Poedit-Language: French\n"
+"X-Poedit-Country: FRANCE\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-SearchPath-0: admin\n"
+
+#: admin/index.php:57
+msgid "Admin"
+msgstr "Admin"
+
+#: admin/index.php:63
+msgid "Page Tree"
+msgstr "Page Tree"
+
+#: admin/index.php:72
+msgid "Selected page"
+msgstr "Selected page"
+
+#: admin/index.php:73
+msgid "Page path"
+msgstr "Page path"
+
+#: admin/index.php:74
+msgid "(choose a page in the tree)"
+msgstr "(choose a page in the tree)"
+
+#: admin/index.php:76
+#: admin/index.php:109
+msgid "Actions"
+msgstr "Actions"
+
+#: admin/index.php:77
+msgid "Edit page"
+msgstr "Edit page"
+
+#: admin/index.php:78
+msgid "Delete page"
+msgstr "Delete page"
+
+#: admin/index.php:82
+msgid "Page title"
+msgstr "Page title"
+
+#: admin/index.php:85
+msgid "Page description"
+msgstr "Page description"
+
+#: admin/index.php:88
+msgid "Page keywords"
+msgstr "Page keywords"
+
+#: admin/index.php:92
+#: admin/index.php:125
+#: admin/index.php:137
+msgid "Save properties"
+msgstr "Save properties"
+
+#: admin/index.php:96
+msgid "Media Tree"
+msgstr "Media Tree"
+
+#: admin/index.php:105
+msgid "Selected Media"
+msgstr "Selected Media"
+
+#: admin/index.php:106
+msgid "Media path"
+msgstr "Media path"
+
+#: admin/index.php:107
+msgid "(choose a media in the tree)"
+msgstr "(choose a media in the tree)"
+
+#: admin/index.php:111
+msgid "Delete media"
+msgstr "Delete media"
+
+#: admin/index.php:115
+msgid "Media title"
+msgstr "Media title"
+
+#: admin/index.php:118
+msgid "Media description"
+msgstr "Media description"
+
+#: admin/index.php:129
+msgid "Site properties"
+msgstr "Site properties"
+
+#: admin/index.php:130
+msgid "Admin lang"
+msgstr "Admin lang"
+
+#: admin/index.php:133
+msgid "Default page"
+msgstr "Default page"
+
diff --git a/locale/fr_FR.po b/locale/fr_FR.po
new file mode 100644
index 0000000..665eb43
--- /dev/null
+++ b/locale/fr_FR.po
@@ -0,0 +1,110 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: EditableSite\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-10-28 18:15+0100\n"
+"PO-Revision-Date: 2013-10-28 20:11+0100\n"
+"Last-Translator: Ludovic Pouzenc <lpouzenc@gmail.com>\n"
+"Language-Team: \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
+"X-Poedit-Basepath: /var/www/EditableSite\n"
+"X-Poedit-Language: French\n"
+"X-Poedit-Country: FRANCE\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-SearchPath-0: admin\n"
+
+#: admin/index.php:57
+msgid "Admin"
+msgstr "Admin"
+
+#: admin/index.php:63
+msgid "Page Tree"
+msgstr "Arborescence des pages"
+
+#: admin/index.php:72
+msgid "Selected page"
+msgstr "Page sélectionnée"
+
+#: admin/index.php:73
+msgid "Page path"
+msgstr "Chemin de la page"
+
+#: admin/index.php:74
+msgid "(choose a page in the tree)"
+msgstr "(choisir une page de l'arbre)"
+
+#: admin/index.php:76
+#: admin/index.php:109
+msgid "Actions"
+msgstr "Actions"
+
+#: admin/index.php:77
+msgid "Edit page"
+msgstr "Éditer"
+
+#: admin/index.php:78
+msgid "Delete page"
+msgstr "Supprimer"
+
+#: admin/index.php:82
+msgid "Page title"
+msgstr "Titre"
+
+#: admin/index.php:85
+msgid "Page description"
+msgstr "Description"
+
+#: admin/index.php:88
+msgid "Page keywords"
+msgstr "Mots-clés"
+
+#: admin/index.php:92
+#: admin/index.php:125
+#: admin/index.php:137
+msgid "Save properties"
+msgstr "Sauver les propriétés"
+
+#: admin/index.php:96
+msgid "Media Tree"
+msgstr "Arborescence des médias"
+
+#: admin/index.php:105
+msgid "Selected Media"
+msgstr "Média sélectionné"
+
+#: admin/index.php:106
+msgid "Media path"
+msgstr "Chemin du media"
+
+#: admin/index.php:107
+msgid "(choose a media in the tree)"
+msgstr "(choisir un media de l'arbre)"
+
+#: admin/index.php:111
+msgid "Delete media"
+msgstr "Supprimer"
+
+#: admin/index.php:115
+msgid "Media title"
+msgstr "Titre"
+
+#: admin/index.php:118
+msgid "Media description"
+msgstr "Description"
+
+#: admin/index.php:129
+msgid "Site properties"
+msgstr "Propriétés du site"
+
+#: admin/index.php:130
+msgid "Admin lang"
+msgstr "Langue outil admin"
+
+#: admin/index.php:133
+msgid "Default page"
+msgstr "Page par défaut"
+
diff --git a/samplefiles/content/en/start/div-content.html b/samplefiles/content/en/start/div-content.html
new file mode 100644
index 0000000..2aea644
--- /dev/null
+++ b/samplefiles/content/en/start/div-content.html
@@ -0,0 +1,27 @@
+<h2>Etymology</h2>
+<p>The word <a href="http://en.wikipedia.org/wiki/Aloha-invalid" target="_blank">aloha</a> derives from the Proto-Polynesian root <i>*qalofa</i>. It has cognates in other Polynesian languages, such as Samoan alofa
+and Māori aroha, also meaning "love."</p>
+<table>
+<caption>with a caption.</caption>
+<tr><td>This</td><td>is</td></tr>
+<tr><td>a</td><td>table.</td></tr>
+</table>
+<p>A folk etymology claims that it derives from a compound of the <a href="http://en.wikipedia.org/wiki/Hawaii" target="_blank">Hawaiian</a> words alo meaning "presence", "front", "face", or "share"; and
+ha, meaning "breath of life" or "essence of life." Although alo does indeed mean "presence" etc., the word for breath is spelled with a macron
+or kahakō over the a (hā) whereas the word aloha does not have a long a.</p>
+<h2>Usage</h2>
+<p>Before contact with the West, the words used for greeting were welina and anoai. Today, "aloha kakahiaka" is the phrase for "good
+morning." "Aloha ʻauinalā" means "good afternoon" and "aloha ahiahi" means "good evening." "Aloha kākou" is a common form of "welcome to all."</p>
+<p>In modern Hawaiʻi, numerous businesses have aloha in their names, with more than 3 pages of listings in the Oʻahu phone book alone.</p>
+<h2>Trends</h2>
+<p>Recent trends are popularizing the term elsewhere in the United States. Popular entertainer, Broadway star and Hollywood actress Bette
+Midler, born in Honolulu, uses the greeting frequently in national appearances. The word was also used frequently in the hit television drama
+Hawaii Five-O. In the influential 1982 film comedy Fast Times at Ridgemont High, the eccentric teacher Mr. Hand makes use of the greeting. The
+Aloha Spirit is a major concept in Lilo and Stitch, a very popular Disney series of movies and TV shows, set in Hawaiʻi. The drama series Lost,
+shot in Hawaiʻi, has a thank you note at the end of the credits saying "We thank the people of Hawaiʻi and their Aloha Spirit". Aloha is a term
+also used in the Nickelodeon program Rocket Power.</p>
+<ul>
+ <li>Arguably the most famous historical Hawaiian song, "Aloha ʻOe" was written by the last queen of Hawaii, Liliʻuokalani.</li>
+ <li>The term inspired the name of the ALOHA Protocol introduced in the 1970s by the University of Hawaii.</li>
+ <li>In Hawaii someone can be said to have or show aloha in the way they treat others; whether family, friend, neighbor or stranger.</li>
+</ul>
diff --git a/samplefiles/content/en/start/div-teaser.html b/samplefiles/content/en/start/div-teaser.html
new file mode 100644
index 0000000..414f783
--- /dev/null
+++ b/samplefiles/content/en/start/div-teaser.html
@@ -0,0 +1,3 @@
+<p><b>Aloha</b> in the Hawaiian language means affection, love, peace, compassion and mercy. Since the middle of the 19th century, it also
+has come to be used as an English greeting to say <i>goodbye</i> and <i>hello</i>. Currently, it is mostly used in the sense of hello; however,
+it is used as the above.</p>
diff --git a/samplefiles/content/en/start/props.ini b/samplefiles/content/en/start/props.ini
new file mode 100644
index 0000000..63546c0
--- /dev/null
+++ b/samplefiles/content/en/start/props.ini
@@ -0,0 +1,5 @@
+page_template = default
+page_layout = article
+page_title = "Aloha, World!"
+page_description = "Hello world for the mini site creator tool"
+page_keywords = "Hello, world"
diff --git a/samplefiles/content/fr/accueil/div-content.html b/samplefiles/content/fr/accueil/div-content.html
new file mode 100644
index 0000000..2aea644
--- /dev/null
+++ b/samplefiles/content/fr/accueil/div-content.html
@@ -0,0 +1,27 @@
+<h2>Etymology</h2>
+<p>The word <a href="http://en.wikipedia.org/wiki/Aloha-invalid" target="_blank">aloha</a> derives from the Proto-Polynesian root <i>*qalofa</i>. It has cognates in other Polynesian languages, such as Samoan alofa
+and Māori aroha, also meaning "love."</p>
+<table>
+<caption>with a caption.</caption>
+<tr><td>This</td><td>is</td></tr>
+<tr><td>a</td><td>table.</td></tr>
+</table>
+<p>A folk etymology claims that it derives from a compound of the <a href="http://en.wikipedia.org/wiki/Hawaii" target="_blank">Hawaiian</a> words alo meaning "presence", "front", "face", or "share"; and
+ha, meaning "breath of life" or "essence of life." Although alo does indeed mean "presence" etc., the word for breath is spelled with a macron
+or kahakō over the a (hā) whereas the word aloha does not have a long a.</p>
+<h2>Usage</h2>
+<p>Before contact with the West, the words used for greeting were welina and anoai. Today, "aloha kakahiaka" is the phrase for "good
+morning." "Aloha ʻauinalā" means "good afternoon" and "aloha ahiahi" means "good evening." "Aloha kākou" is a common form of "welcome to all."</p>
+<p>In modern Hawaiʻi, numerous businesses have aloha in their names, with more than 3 pages of listings in the Oʻahu phone book alone.</p>
+<h2>Trends</h2>
+<p>Recent trends are popularizing the term elsewhere in the United States. Popular entertainer, Broadway star and Hollywood actress Bette
+Midler, born in Honolulu, uses the greeting frequently in national appearances. The word was also used frequently in the hit television drama
+Hawaii Five-O. In the influential 1982 film comedy Fast Times at Ridgemont High, the eccentric teacher Mr. Hand makes use of the greeting. The
+Aloha Spirit is a major concept in Lilo and Stitch, a very popular Disney series of movies and TV shows, set in Hawaiʻi. The drama series Lost,
+shot in Hawaiʻi, has a thank you note at the end of the credits saying "We thank the people of Hawaiʻi and their Aloha Spirit". Aloha is a term
+also used in the Nickelodeon program Rocket Power.</p>
+<ul>
+ <li>Arguably the most famous historical Hawaiian song, "Aloha ʻOe" was written by the last queen of Hawaii, Liliʻuokalani.</li>
+ <li>The term inspired the name of the ALOHA Protocol introduced in the 1970s by the University of Hawaii.</li>
+ <li>In Hawaii someone can be said to have or show aloha in the way they treat others; whether family, friend, neighbor or stranger.</li>
+</ul>
diff --git a/samplefiles/content/fr/accueil/div-teaser.html b/samplefiles/content/fr/accueil/div-teaser.html
new file mode 100644
index 0000000..414f783
--- /dev/null
+++ b/samplefiles/content/fr/accueil/div-teaser.html
@@ -0,0 +1,3 @@
+<p><b>Aloha</b> in the Hawaiian language means affection, love, peace, compassion and mercy. Since the middle of the 19th century, it also
+has come to be used as an English greeting to say <i>goodbye</i> and <i>hello</i>. Currently, it is mostly used in the sense of hello; however,
+it is used as the above.</p>
diff --git a/samplefiles/content/fr/accueil/props.ini b/samplefiles/content/fr/accueil/props.ini
new file mode 100644
index 0000000..c833c34
--- /dev/null
+++ b/samplefiles/content/fr/accueil/props.ini
@@ -0,0 +1,5 @@
+page_template = default
+page_layout = article
+page_title = "Démonstration Aloha"
+page_description = "Cette page reprends la démonstration de l'éditeur Aloha"
+page_keywords = "Hello, world, démo"
diff --git a/samplefiles/content/site_conf.ini b/samplefiles/content/site_conf.ini
new file mode 100644
index 0000000..69ad74a
--- /dev/null
+++ b/samplefiles/content/site_conf.ini
@@ -0,0 +1,3 @@
+site_admin_lang = "fr_FR"
+;site_admin_lang = "en_US"
+site_default_page = "fr/accueil"
diff --git a/samplefiles/templates/aloha/images/background.png b/samplefiles/templates/aloha/images/background.png
new file mode 100644
index 0000000..64ece57
--- /dev/null
+++ b/samplefiles/templates/aloha/images/background.png
Binary files differ
diff --git a/samplefiles/templates/aloha/images/external-link-ltr-icon.png b/samplefiles/templates/aloha/images/external-link-ltr-icon.png
new file mode 100644
index 0000000..4b710b0
--- /dev/null
+++ b/samplefiles/templates/aloha/images/external-link-ltr-icon.png
Binary files differ
diff --git a/samplefiles/templates/aloha/layout-article.php b/samplefiles/templates/aloha/layout-article.php
new file mode 100644
index 0000000..86a65a7
--- /dev/null
+++ b/samplefiles/templates/aloha/layout-article.php
@@ -0,0 +1,15 @@
+<div id="main">
+<!--<div id="tree-div"></div>-->
+<h1 id="title"><?=$page_props['page_title']?></h1>
+<div id="bodyContent">
+
+<div id="teaser" class="shorttext">
+<?php include("$page_path/div-teaser.html"); ?>
+</div>
+
+<div id="content" class="article">
+<?php include("$page_path/div-content.html"); ?>
+</div>
+
+</div>
+</div>
diff --git a/samplefiles/templates/aloha/screen.css b/samplefiles/templates/aloha/screen.css
new file mode 100644
index 0000000..cec5b0a
--- /dev/null
+++ b/samplefiles/templates/aloha/screen.css
@@ -0,0 +1,79 @@
+body {
+ font-family: sans-serif;
+}
+
+body {
+ background-image: url("images/background.png");
+}
+
+#bodyContent {
+ font-size:0.8em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: sans-serif;
+ color: #1c94c4;
+ border-bottom:1px solid #AAAAAA;
+ padding-bottom:0.17em;
+ padding-top:0.5em;
+}
+
+h1 { font-size: 188%; }
+h2 { font-size: 150%; }
+h3 { font-size: 132%; }
+h4 { font-size: 116%; }
+h5 { font-size: 100%; }
+h6 { font-size: 80%; }
+
+#main {
+ width: 50%;
+ position: absolute;
+ top: 10%;
+ left: 25%;
+ padding: 30px;
+ background-color: white;
+ border-radius: 10px;
+ color: #444444;
+ -moz-border-radius: 10px;
+ box-shadow: 5px 5px rgba(0,0,0,0.3);
+ -webkit-box-shadow: 5px 5px rgba(0,0,0,0.3);
+ -moz-box-shadow: 5px 5px rgba(0,0,0,0.3);
+}
+
+a.aloha {
+ background: url(images/external-link-ltr-icon.png) no-repeat 100% 50%;
+ padding: 0px 13px 0px 0px;
+}
+
+/* Abbreviation styling */
+abbr, acronym
+{
+ border-bottom: .1em dotted;
+ cursor: help;
+}
+
+/* A basic table styling */
+table
+{
+ padding: 0;
+ margin: 0;
+ border-collapse: collapse;
+ border: 1px solid #333;
+ color: #000;
+}
+
+table caption
+{
+ caption-side: bottom;
+ font-size: 0.8em;
+ font-style: italic;
+ text-align: right;
+ padding: 0.5em 0;
+}
+
+table th, table td
+{
+ border: 1px solid #666;
+ padding: 0.5em;
+ text-align: left;
+} \ No newline at end of file
diff --git a/samplefiles/templates/default/layout-article.php b/samplefiles/templates/default/layout-article.php
new file mode 100644
index 0000000..36e6e6c
--- /dev/null
+++ b/samplefiles/templates/default/layout-article.php
@@ -0,0 +1,12 @@
+<div id="main">
+ <h1 id="title"><?=$page_props['page_title']?></h1>
+ <div id="body">
+ <div id="teaser" class="shorttext">
+<?php include("$page_path/div-teaser.html"); ?>
+ </div>
+
+ <div id="content" class="article">
+<?php include("$page_path/div-content.html"); ?>
+ </div>
+ </div>
+</div>
diff --git a/samplefiles/templates/default/screen.css b/samplefiles/templates/default/screen.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samplefiles/templates/default/screen.css