Simplify and add lightness

This commit is contained in:
Timothy Warren 2015-06-04 14:30:42 -04:00
parent c37c050548
commit 140fef2cda
50 changed files with 824 additions and 1890 deletions

4
.gitignore vendored Normal file → Executable file
View File

@ -1,3 +1,5 @@
sys/*.sqlite
docs/*
assets/js/cache/*
assets/js/cache/*
vendor/*
composer.lock

0
README.md Normal file → Executable file
View File

34
app/classes/controller.php Normal file → Executable file
View File

@ -29,37 +29,9 @@ abstract class Controller extends \miniMVC\Controller {
{
parent::__construct();
$this->load_model('meta\data_model');
$this->load_model('meta\user_model');
$this->session =& \miniMVC\Session::get_instance();
// Check if user is logged in
$this->check_login_status();
$this->page->build_header();
}
/**
* Require user login for access
*/
private function check_login_status()
{
if ( ! isset($this->session->uid))
{
// Redirect to login
}
return;
}
/**
* Destruct controller and build page footer
*/
public function __destruct()
{
$this->page->set_foot_js_group('js');
$this->page->build_footer();
$db = \miniMVC\db::get_instance();
$this->page->queries =& $db->queries;
}
}

9
app/config/config.php Normal file → Executable file
View File

@ -31,12 +31,7 @@
| slash.
|
*/
// Determine the default site url
$ri = $_SERVER['REQUEST_URI'];
$ind_pos = stripos($ri, "index.php");
$default_path = ($ind_pos !== FALSE) ? substr($ri, 0, $ind_pos) : $ri;
$default_baseurl = "//" . str_replace("//", "/", $_SERVER['HTTP_HOST']. $default_path);
define('BASE_URL', $default_baseurl);
define('BASE_URL', '//' . $_SERVER['HTTP_HOST'] . '/');
/*
|--------------------------------------------------------------------------
@ -46,7 +41,7 @@ define('BASE_URL', $default_baseurl);
| This determines whether "index.php" is in generated urls
|
*/
define('URL_INDEX_FILE', 'index.php/');
define('URL_INDEX_FILE', '');
/*
|--------------------------------------------------------------------------

28
app/config/routes.php Normal file → Executable file
View File

@ -29,20 +29,22 @@
// --------------------------------------------------------------------------
return array(
$routes = [
// Default Paths
'default_controller' => 'welcome',
'default_module' => 'meta',
'delete' => 'meta/welcome/delete',
'update' => 'meta/welcome/update_item',
'genre' => 'meta/genre/index',
'genre/add' => 'meta/genre/add',
'genre/add_category' => 'meta/genre/add_category',
'category' => 'meta/category/index',
'category/add_section' => 'meta/category/add_section',
'section' => 'meta/section/index',
'section/add_data' => 'meta/section/add_data',
'default_controller' => 'genre',
'404_route' => '',
);
];
// Add default routes
$router->add('home', '/');
$router->add(null, '/{controller}/{action}/{id}');
$router->add('no_id', '/{controller}/{action}');
// Custom routes
$router->add('outline', '/outline');
$router->add('edit', '/edit');
$router->add('delete', '/delete');
$router->addPost('data_add', '/section/add_data');
$router->addPost('update', '/update');
// End of routes.php

6
app/modules/meta/controllers/category.php Normal file → Executable file
View File

@ -31,7 +31,7 @@ class category extends meta\controller {
/**
* Returns the sections / editing options for a category
*/
public function index($id = 0)
public function detail($id = 0)
{
if ($id === 0)
{
@ -50,7 +50,7 @@ class category extends meta\controller {
'category_id' => $id
);
$this->load_view('category_detail', $data);
$this->render('category_detail', $data);
}
/**
@ -74,7 +74,7 @@ class category extends meta\controller {
$this->page->set_message('error', 'Section already exists for this category');
}
$this->index($id);
$this->detail($id);
}
}

139
app/modules/meta/controllers/genre.php Normal file → Executable file
View File

@ -20,39 +20,20 @@
*/
class genre extends meta\controller {
/**
* Initialize the Controller
*/
public function __construct()
{
parent::__construct();
}
/**
* Default controller method
*/
public function index($id = 0)
public function index()
{
if ($id === 0)
{
// Re-route to detail page if the last segment
// is a valid integer
$id = (int) miniMVC\get_last_segment();
}
$data = array();
$data['genres'] = $this->data_model->get_genres();
if ($id === 0)
{
// Otherwise, display list of genres
$data = array();
$data['genres'] = $this->data_model->get_genres();
$this->render('genres', $data);
$this->load_view('genres', $data);
return;
}
return $this->detail($id);
return;
}
// --------------------------------------------------------------------------
/**
* Adds a new genre
@ -77,14 +58,23 @@ class genre extends meta\controller {
// Render the basic page
$this->index();
}
// --------------------------------------------------------------------------
/**
* Returns the categories / editing options for a genre
*
* @param int
*/
public function detail($id)
public function detail($id = 0)
{
if ($id === 0)
{
// Re-route to detail page if the last segment
// is a valid integer
$id = (int) miniMVC\get_last_segment();
}
$genre = $this->data_model->get_genre_by_id($id);
$categories = $this->data_model->get_categories($id);
@ -94,8 +84,10 @@ class genre extends meta\controller {
'genre_id' => $id
);
$this->load_view('genre_detail', $data);
$this->render('genre_detail', $data);
}
// --------------------------------------------------------------------------
/**
* Adds a category to the current genre
@ -120,6 +112,97 @@ class genre extends meta\controller {
$this->detail($id);
}
// --------------------------------------------------------------------------
/**
* Display an outline of the data for a table of contents
*/
public function outline()
{
$outline_data = $this->data_model->get_outline_data();
$this->render('outline', array('outline' => $outline_data));
}
// --------------------------------------------------------------------------
/**
* Get a message for ajax insertion
*/
public function message()
{
$type = strip_tags($_GET['type']);
$message = $_GET['message'];
$this->page->set_output(
$this->page->set_message($type, $message, TRUE)
);
}
// --------------------------------------------------------------------------
public function delete()
{
$type = strip_tags($_POST['type']);
$valid_types = ['genre', 'category', 'section', 'data'];
$res = (in_array($type, $valid_types))
? $this->data_model->delete($type, (int) $_POST['id'])
: 0;
exit(mb_trim($res));
}
// --------------------------------------------------------------------------
public function edit()
{
$type = strip_tags($_GET['type']);
$id = (int) $_GET['id'];
if ($this->data_model->is_valid_type($type))
{
$data = call_user_func(array($this->data_model, "get_{$type}_by_id"), $id);
$form_array = array(
'name' => is_array($data) ? $data['key'] : "",
'val' => is_array($data) ? $data['value'] : $data,
'type' => $type,
'id' => $id
);
exit($this->load_view('edit_form', $form_array, TRUE));
}
}
// --------------------------------------------------------------------------
public function update()
{
$id = (int) $_POST['id'];
$type = strip_tags($_POST['type']);
$name = strip_tags($_POST['name']);
$val = (isset($_POST['val'])) ? $_POST['val'] : NULL;
if ($this->data_model->is_valid_type($type))
{
if ($type != 'data')
{
$res = $this->data_model->update($type, $id, $name);
}
else
{
$res = $this->data_model->update_data($id, $name, $val);
}
$res = (int) $res;
exit(mb_trim($res));
}
exit(0);
}
}
// End of genre.php

6
app/modules/meta/controllers/section.php Normal file → Executable file
View File

@ -31,7 +31,7 @@ class section extends meta\controller {
/**
* Default controller method
*/
public function index($id=0)
public function detail($id=0)
{
if ($id === 0)
{
@ -50,7 +50,7 @@ class section extends meta\controller {
'section_id' => $id
);
$this->load_view('section_detail', $data);
$this->render('section_detail', $data);
}
/**
@ -77,7 +77,7 @@ class section extends meta\controller {
? $this->page->set_message('success', 'Added data')
: $this->page->set_message('error', 'Data already exists');
$this->index($section_id);
$this->detail($section_id);
}
}

View File

@ -1,167 +0,0 @@
<?php
/**
* meta
*
* Hierarchial data tool
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Default Controller class
*
* @package meta
*/
class welcome extends \meta\controller {
/**
* Initialize the constructor
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
// --------------------------------------------------------------------------
/**
* Default route for the controller
*
* @return void
*/
public function index()
{
$data = array();
$data['genres'] = $this->data_model->get_genres();
$this->load_view('genres', $data);
}
// --------------------------------------------------------------------------
/**
* Authenticate a user
*/
public function login()
{
$this->load_view('login');
}
// --------------------------------------------------------------------------
/**
* Logout
*/
public function logout()
{
}
// --------------------------------------------------------------------------
/**
* Display an outline of the data for a table of contents
*/
public function outline()
{
$outline_data = $this->data_model->get_outline_data();
$this->load_view('outline', array('outline' => $outline_data));
}
// --------------------------------------------------------------------------
/**
* Get a message for ajax insertion
*/
public function message()
{
$type = strip_tags($_GET['type']);
$message = $_GET['message'];
$this->page->set_output(
$this->page->set_message($type, $message, TRUE)
);
}
// --------------------------------------------------------------------------
public function delete()
{
$type = strip_tags($_POST['type']);
switch($type)
{
case "genre":
case "category":
case "section":
case "data":
$res = (int) $this->data_model->delete($type, (int) $_POST['id']);
break;
default:
$res = 0;
break;
}
die(trim($res));
}
// --------------------------------------------------------------------------
public function edit()
{
$type = strip_tags($_GET['type']);
$id = (int) $_GET['id'];
if ($this->data_model->is_valid_type($type))
{
$data = call_user_func(array($this->data_model, "get_{$type}_by_id"), $id);
$form_array = array(
'name' => is_array($data) ? $data['key'] : "",
'val' => is_array($data) ? $data['value'] : $data,
'type' => $type,
'id' => $id
);
exit($this->load_view('edit_form', $form_array, TRUE));
}
}
// --------------------------------------------------------------------------
public function update_item()
{
$id = (int) $_POST['id'];
$type = strip_tags($_POST['type']);
$name = strip_tags($_POST['name']);
$val = (isset($_POST['val'])) ? $_POST['val'] : NULL;
if ($this->data_model->is_valid_type($type))
{
if ($type != 'data')
{
$res = $this->data_model->update($type, $id, $name);
}
else
{
$res = $this->data_model->update_data($id, $name, $val);
}
$res = (int) $res;
exit(trim($res));
}
exit(0);
}
}
// End of welcome.php

216
app/modules/meta/models/data_model.php Normal file → Executable file
View File

@ -15,6 +15,8 @@
namespace meta;
use \miniMVC\db;
/**
* Main Model for database interaction
*
@ -42,9 +44,7 @@ class data_model extends \miniMVC\Model {
public function __construct()
{
parent::__construct();
$this->session =& \miniMVC\Session::get_instance();
$this->db =& \miniMVC\db::get_instance();
$this->db = db::get_instance();
}
// --------------------------------------------------------------------------
@ -113,7 +113,7 @@ class data_model extends \miniMVC\Model {
->where('id', (int) $id)
->update($type);
return ( ! empty($query)) ;
return (bool) $query;
}
// --------------------------------------------------------------------------
@ -128,19 +128,13 @@ class data_model extends \miniMVC\Model {
*/
public function update_data($data_id, $key, $val)
{
try{
// Save the data
$this->db->set('key', $key)
->set('value', $val)
->where('id', (int) $data_id)
->update('data');
}
catch(\PDOException $e)
{
return FALSE;
}
// Save the data
$query = $this->db->set('key', $key)
->set('value', $val)
->where('id', (int) $data_id)
->update('data');
return TRUE;
return (bool) $query;
}
// --------------------------------------------------------------------------
@ -161,13 +155,13 @@ class data_model extends \miniMVC\Model {
->limit(1)
->get();
// Fetch the data as a workaround
// for databases that do not support
// grabbing result counts (SQLite / Firebird)
$array = $query->fetchAll(\PDO::FETCH_ASSOC);
if (count($array) < 1)
$res = $query->fetch();
if (count($res) < 1)
{
$this->db->set('genre', $genre)
$id = $this->get_next_id("genre");
$this->db->set('id', $id)
->set('genre', $genre)
->insert('genre');
return TRUE;
@ -195,13 +189,13 @@ class data_model extends \miniMVC\Model {
->limit(1)
->get();
// Fetch the data as a workaround
// for databases that do not support
// grabbing result counts (SQLite / Firebird)
$array = $query->fetchAll();
if (count($array)< 1)
$res = $query->fetch();
if (count($res) < 1)
{
$this->db->set('category', $cat)
$id = $this->get_next_id('category');
$this->db->set('id', $id)
->set('category', $cat)
->set('genre_id', $genre_id)
->insert('category');
@ -234,7 +228,9 @@ class data_model extends \miniMVC\Model {
$array = $q->fetchAll();
if (count($array) < 1)
{
$this->db->set('section', $section)
$id = $this->get_next_id('section');
$this->db->set('id', $id)
->set('section', $section)
->set('category_id', (int) $category_id)
->insert('section');
@ -262,10 +258,14 @@ class data_model extends \miniMVC\Model {
->where('key', $key)
->get();
if ($this->db->num_rows() > 0) return FALSE;
$res = $q->fetch();
if (count($res) > 0) return FALSE;
// Save the data
$this->db->set('key', $key)
$id = $this->get_next_id('data');
$this->db->set('id', $id)
->set('key', $key)
->set('value', $val)
->set('section_id', (int) $section_id)
->insert('data');
@ -274,8 +274,6 @@ class data_model extends \miniMVC\Model {
return TRUE;
}
// --------------------------------------------------------------------------
// ! Data Retrieval
// --------------------------------------------------------------------------
@ -290,8 +288,8 @@ class data_model extends \miniMVC\Model {
{
$query = $this->db->select('genre, genre_id, category, category_id')
->from('section s')
->join('category c', 'c.id=s.category_id')
->join('genre g', 'g.id=c.genre_id')
->join('category c', 'c.id=s.category_id', 'inner')
->join('genre g', 'g.id=c.genre_id', 'inner')
->where('s.id', $section_id)
->get();
@ -310,7 +308,7 @@ class data_model extends \miniMVC\Model {
$genres = array();
$query = $this->db->select('id, genre')
->from('genre')
->order_by('genre', 'asc')
->orderBy('genre', 'asc')
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
@ -377,6 +375,7 @@ class data_model extends \miniMVC\Model {
$query = $this->db->select('id, category')
->from('category')
->where('genre_id', (int) $genre_id)
->orderBy('category', 'asc')
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
@ -422,6 +421,7 @@ class data_model extends \miniMVC\Model {
$query = $this->db->select('id, section')
->from('section')
->where('category_id', (int) $category_id)
->orderBy('section', 'asc')
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
@ -467,6 +467,7 @@ class data_model extends \miniMVC\Model {
$query = $this->db->select('id, key, value')
->from('data')
->where('section_id', (int) $section_id)
->orderBy('key', 'asc')
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
@ -510,6 +511,7 @@ class data_model extends \miniMVC\Model {
// Get the sections
$s_query = $this->db->from('section')
->where('category_id', (int) $category_id)
->orderBy('section', 'asc')
->get();
$sections = array();
@ -525,7 +527,8 @@ class data_model extends \miniMVC\Model {
if ( ! empty($sections))
{
$d_query = $this->db->from('data')
->where_in('section_id', array_keys($sections))
->whereIn('section_id', array_keys($sections))
->orderBy('key', 'asc')
->get();
while($row = $d_query->fetch(\PDO::FETCH_ASSOC))
@ -557,62 +560,24 @@ class data_model extends \miniMVC\Model {
public function get_outline_data()
{
// Get the genres
$g_query = $this->db->from('genre')
$query = $this->db->select('g.id, genre,
c.id AS cat_id, category,
s.id AS section_id, section')
->from('genre g')
->join('category c', 'c.genre_id=g.id', 'inner')
->join('section s', 's.category_id=c.id', 'inner')
->orderBy('genre', 'asc')
->orderBy('category', 'asc')
->orderBy('section', 'asc')
->get();
$genres = array();
$return = array();
while ($row = $g_query->fetch(\PDO::FETCH_ASSOC))
// Create the nested array
while ($row = $query->fetch(\PDO::FETCH_ASSOC))
{
$genres[$row['id']] = $row['genre'];
}
// Get the categories
$c_query = $this->db->from('category')
->get();
$categories = array();
while($row = $c_query->fetch(\PDO::FETCH_ASSOC))
{
$categories[$row['genre_id']][$row['id']] = $row['category'];
}
// Get the sections
$s_query = $this->db->from('section')
->get();
$sections = array();
while($row = $s_query->fetch(\PDO::FETCH_ASSOC))
{
$sections[$row['category_id']][$row['id']] = $row['section'];
}
// Organize into a nested array
foreach($genres as $genre_id => $genre)
{
$return[$genre_id][$genre] = array();
$g =& $return[$genre_id][$genre];
// Categories for this genre
if (isset($categories[$genre_id]))
{
$g = $categories[$genre_id];
foreach($categories[$genre_id] as $category_id => $category)
{
$g[$category_id] = array($category => array());
$c =& $g[$category_id][$category];
// Sections for this category
if (isset($sections[$category_id]))
{
$c = $sections[$category_id];
}
}
}
extract($row);
$return[$id][$genre][$cat_id][$category][$section_id] = $section;
}
return $return;
@ -649,7 +614,7 @@ class data_model extends \miniMVC\Model {
{
$query = $this->db->select('id')
->from($type)
->order_by('id', 'DESC')
->orderBy('id', 'DESC')
->limit(1)
->get();
@ -660,6 +625,77 @@ class data_model extends \miniMVC\Model {
// --------------------------------------------------------------------------
/**
* Get the next id for database insertion
*
* @param string $table_name
* @param string $field
* @return int
*/
public function get_next_id($table_name, $field="id")
{
$query = $this->db->select("MAX($field) as last_id")
->from($table_name)
->limit(1)
->get();
$row = $query->fetch(\PDO::FETCH_ASSOC);
if (empty($row))
{
$id = 1;
}
else
{
$id = intval($row['last_id']) + 1;
}
return $id;
}
// --------------------------------------------------------------------------
public function create_tables()
{
$tables = [
'genre' => $this->db->util->create_table('genre', [
'id' => 'INT NOT NULL PRIMARY KEY',
'genre' => 'VARCHAR(255)'
]),
'category' => $this->db->util->create_table('category', [
'id' => 'INT NOT NULL PRIMARY KEY',
'genre_id' => 'INT NOT NULL',
'category' => 'VARCHAR(255)'
],[
'genre_id' => ' REFERENCES "genre" '
]),
'section' => $this->db->util->create_table('section', [
'id' => 'INT NOT NULL PRIMARY KEY',
'category_id' => 'INT NOT NULL',
'section' => 'VARCHAR(255)'
],[
'category_id' => ' REFERENCES "category" '
]),
'data' => $this->db->util->create_table('data', [
'id' => 'INT NOT NULL PRIMARY KEY',
'section_id' => 'INT NOT NULL',
'key' => 'VARCHAR(255)',
'value' => 'BLOB SUB_TYPE TEXT'
],[
'section_id' => ' REFERENCES "section"'
])
];
foreach($tables as $table => $sql)
{
// Add the table
$this->db->query($sql);
echo "{$sql};<br />";
}
}
}
// End of data_model.php

View File

@ -1,120 +0,0 @@
<?php
/**
* meta
*
* Simple hierarchial data management
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace meta;
/**
* Model for dealing with user logins / permissions
*
* @package meta
*/
class user_model extends \miniMVC\Model {
/**
* Reference to database connection
*
* @var Query_Builder
*/
protected $db;
/**
* Reference to bcrypt object
*
* @var Bcrypt
*/
protected $bcrypt;
/**
* Reference to session
*
* @var Session
*/
protected $session;
/**
* Initialize the User model
*/
public function __construct()
{
parent::__construct();
$this->bcrypt = new \Bcrypt(15);
$this->db =& \miniMVC\db::get_instance();
$this->session =& \miniMVC\Session::get_instance();
}
// --------------------------------------------------------------------------
/**
* Add a user for access
*
* @param string
* @param string
* @param string
*/
public function add_user($username, $pass1, $pass2)
{
// Check for the existing username
$query = $this->db->select('username')
->from('user')
->where('username', $username)
->get();
$res = $query->fetch(\PDO::FETCH_ASSOC);
if (empty($res)) return FALSE;
// Verify that passwords match
if ($pass1 !== $pass2) return FALSE;
// Add user
$hashed = $this->bcrypt->hash($pass1);
$this->db->set('username', $username)
->set('hash', $hashed)
->insert('user');
return TRUE;
}
// --------------------------------------------------------------------------
/**
* Check and see if the login is valid
*
* @param string
* @param string
* @return bool
*/
public function check_login($username, $pass)
{
$query = $this->db->from('user')
->where('username', $username)
->get();
$row = $query->fetch(\PDO::FETCH_ASSOC);
// The user does not exist
if (empty($row))
{
return FALSE;
}
return $this->bcrypt->verify($pass, $row['hash']);
}
}
// End of user_model.php

26
app/modules/meta/views/category_detail.php Normal file → Executable file
View File

@ -1,5 +1,5 @@
<p class="breadcrumbs">
<a href="<?= miniMVC\site_url('') ?>">Genres</a> > <a href="<?= miniMVC\site_url('genres/detail/'.$genre['id']) ?>"><?= $genre['genre'] ?></a> > <?= $category ?>
<a href="<?= miniMVC\site_url('') ?>">Genres</a> > <a href="<?= miniMVC\site_url('genre/detail/'.$genre['id']) ?>"><?= $genre['genre'] ?></a> > <?= $category ?>
</p>
<form class="add" action="<?= miniMVC\site_url("category/add_section") ?>" method="post">
@ -22,27 +22,23 @@
<?php if (is_array($section)) list($section, $d) = $section ?>
<li>
<h4><a href="<?= miniMVC\site_url("section/detail/{$id}") ?>"><?= $section ?></a></h4>
<span class="modify" id="section_<?=$id ?>">
<span class="modify" data-id="<?= $id ?>" data-type="section" data-parent="<?= $category_id ?>">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</span>
<?php if ( ! empty($d)): ?>
<?php foreach($d as $did => $dd): ?>
<?php foreach($dd as $k => $v): ?>
<?php $class = (strpos($v, "<br />") !== FALSE) ? 'multiline' : 'pair' ?>
<dl class="<?= $class ?>">
<dt><?= $k ?></dt>
<dd>
<?= $v ?>
</dd>
</dl>
<?php foreach($dd as $k => $v): ?>
<?php $class = (strpos($v, "<ul>") !== FALSE || strpos($v, "<br />") !== FALSE) ? 'multiline' : 'pair' ?>
<dl class="<?= $class ?>">
<dt><?= $k ?></dt>
<dd>
<?= $v ?>
</dd>
</dl>
<?php endforeach ?>
<?php endforeach ?>
<?php endforeach ?>
<?php endif ?>
<?php $d = array(); // Don't let data linger ?>

0
app/modules/meta/views/edit_form.php Normal file → Executable file
View File

16
app/modules/meta/views/genre_detail.php Normal file → Executable file
View File

@ -19,23 +19,11 @@
<ul class="list">
<?php foreach($categories as $id => $cat): ?>
<li>
<a href="<?= miniMVC\site_url("category/{$id}") ?>"><?= $cat ?></a>
<span class="modify" id="category_<?=$id ?>">
<a href="<?= miniMVC\site_url("category/detail/{$id}") ?>"><?= $cat ?></a>
<span class="modify" data-type="category" data-id="<?=$id ?>" data-parent="<?=$genre_id ?>">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</span>
<ul>
<?php /* $sarray = $this->data_model->get_sections($id); ?>
<?php foreach($sarray as $sid => $section): ?>
<li>
<a href="<?= miniMVC\site_url("section/{$sid}") ?>"><?= $section ?></a>
<span class="modify" id="section_<?=$id ?>">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</span>
</li>
<?php endforeach */ ?>
</ul>
</li>
<?php endforeach ?>
</ul>

4
app/modules/meta/views/genres.php Normal file → Executable file
View File

@ -18,10 +18,10 @@
<ul class="list">
<?php foreach($genres as $id => $name): ?>
<li>
<a href="<?= miniMVC\site_url("genre/{$id}") ?>">
<a href="<?= miniMVC\site_url("genre/detail/{$id}") ?>">
<?= $name ?>
</a>
<span class="modify" id="genre_<?=$id ?>">
<span class="modify" data-id="<?= $id ?>" data-type="genre" data-parent="<?=$id ?>">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</span>

View File

@ -1,14 +0,0 @@
<h3>Login</h3>
<form action="<?= miniMVC\site_url('welcome/login') ?>" method="post">
<dl>
<dt><label for="user">Username:</label></dt>
<dd><input type="text" id="user" name="user" /></dd>
<dt><label for="pass">Password:</label></dt>
<dd><input type="password" id="pass" name="pass" /></dd>
<dt>&nbsp;</dt>
<dd><button type="submit">Login</button></dd>
</dl>
</form>

6
app/modules/meta/views/outline.php Normal file → Executable file
View File

@ -20,7 +20,7 @@
<!-- Genres -->
<?php foreach($genre_array as $genre => $cat_array): ?>
<dt>
<a href="<?= \miniMVC\site_url("genre/{$genre_id}") ?>"><?= $genre ?></a>
<a href="<?= \miniMVC\site_url("genre/detail/{$genre_id}") ?>"><?= $genre ?></a>
</dt>
<dd>
@ -29,14 +29,14 @@
<!-- Categories -->
<?php foreach($cname_array as $category => $sect_array): ?>
<li>
<a href="<?= \miniMVC\site_url("category/{$cat_id}") ?>"><?= $category ?></a>
<a href="<?= \miniMVC\site_url("category/detail/{$cat_id}") ?>"><?= $category ?></a>
<?php if ( ! empty($sect_array)): ?>
<ul>
<!-- Sections -->
<?php foreach($sect_array as $section_id => $section): ?>
<li>
<a href="<?= \miniMVC\site_url("section/{$section_id}") ?>">
<a href="<?= \miniMVC\site_url("section/detail/{$section_id}") ?>">
<?= $section ?>
</a>
</li>

44
app/modules/meta/views/section_detail.php Normal file → Executable file
View File

@ -4,8 +4,8 @@
<a href="<?= miniMVC\site_url('category/detail/'.$p['category_id']) ?>"><?= $p['category'] ?></a> >
<?= $section ?>
</p>
<form class="add" action="<?= miniMVC\site_url("section/add_data") ?>" method="post">
<script src="<?= SCRIPT_PATH.'wysiwyg'; ?>"></script>
<form class="add" action="<?= miniMVC\site_url("section/add_data") ?>" method="post" onsubmit="window.edit_wysiwyg.toggle()">
<fieldset>
<legend>Add Data</legend>
<dl>
@ -21,56 +21,22 @@
</dl>
</fieldset>
</form>
<script src="<?= SCRIPT_PATH.'wysiwyg'; ?>"></script>
<script type="text/javascript">
// WYSIWYG
new TINY.editor.edit('editor',
{
id:'input',
width:450,
height:175,
cssclass:'te',
controlclass:'tecontrol',
rowclass:'teheader',
dividerclass:'tedivider',
controls:['bold','italic','underline','strikethrough','|','subscript','superscript','|',
'orderedlist','unorderedlist','|','leftalign',
'centeralign','rightalign','blockjustify','|','unformat','n','undo','redo','|',
'image','hr','link','unlink','|'],
footer:true,
fonts:['Verdana','Arial','Georgia','Trebuchet MS'],
xhtml:true,
cssfile:ASSET_URL+'css.php/g/css',
bodyid:'editor',
footerclass:'tefooter',
toggle:{text:'source',activetext:'wysiwyg',cssclass:'toggle'},
resize:{cssclass:'resize'}
});
// Make sure the WYSIWYG submits the text
// This just copies the text from the WYSIWYG into the textbox
document.querySelector('form').onsubmit = function(e) {
window.editor.toggle();
};
</script>
<h3>Data</h3>
<?php if ( ! empty($sdata)): ?>
<?php foreach($sdata as $d_id => $d): ?>
<?php foreach($d as $k => $v): ?>
<?php $class = (strpos($v, "<br />") !== FALSE) ? 'multiline' : 'pair' ?>
<?php $class = (strpos($v, "<ul>") !== FALSE || strpos($v, "<br />") !== FALSE) ? 'multiline' : 'pair' ?>
<dl class="<?= $class ?>">
<dt>
<?= $k ?>
<span class="modify" id="data_<?=$d_id ?>">
<span class="modify" data-type="data" data-id="<?=$d_id ?>" data-parent="<?= $section_id ?>">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</span>
</dt>
<dd><?= $v ?></dd>
</dl>
<?php endforeach ?>
<?php endforeach ?>
<?php endif ?>

View File

@ -1,33 +0,0 @@
<?php
/**
* meta
*
* Hierarchial data tool
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Setup Controller
*
* @package meta
*/
class setup extends \meta\controller {
/**
* Constuctor
*/
public function __construct()
{
}
}
// End of setup.php

0
app/views/errors/error_404.php Normal file → Executable file
View File

0
app/views/errors/error_db.php Normal file → Executable file
View File

0
app/views/errors/error_general.php Normal file → Executable file
View File

0
app/views/errors/error_php_exception.php Normal file → Executable file
View File

2
app/views/footer.php Normal file → Executable file
View File

@ -1,4 +1,4 @@
<?php $this->load_view('theme_footer'); ?>
<?= $this->load_view('theme_footer', ['queries' => $this->queries], TRUE); ?>
<?php if ($foot_js != ""): ?>
<?= $foot_js ?>
<?php endif ?>

5
app/views/header.php Normal file → Executable file
View File

@ -1,12 +1,13 @@
<head>
<?= $meta ?>
<title><?= $title ?></title>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<?= $css ?>
<?= $head_tags ?>
<title><?= $title ?></title>
<?php if (!empty($base)) { ?><base href="<?=$base ?>" /><?php } ?>
<?= $head_tags ?>
<?= $head_js ?>
</head>
<body<?= (!empty($body_class)) ? "class=\"" . $body_class . "\"" : ""; ?><?= (!empty($body_id)) ? " id=\"" . $body_id . "\"" : ""; ?>>
<?php $this->load_view('theme_header'); ?>
<?= $this->load_view('theme_header', [], TRUE); ?>

0
app/views/message.php Normal file → Executable file
View File

7
app/views/theme_footer.php Normal file → Executable file
View File

@ -1,2 +1,7 @@
<div id="overlay_bg"></div>
<div id="overlay"></div>
<div id="overlay"></div>
<h5>Queries:</h5>
<?php unset($queries['total_time']); ?>
<?php foreach($queries as $q): ?>
<pre><code class="language-sql"><?= $q['sql'] ?></code></pre><br />
<?php endforeach ?>

4
app/views/theme_header.php Normal file → Executable file
View File

@ -1,6 +1,6 @@
<script type="text/javascript">
var APP_URL = '<?= \miniMVC\site_url(); ?>';
var ASSET_URL = APP_URL.replace('index.php/', '') + 'assets/';
var APP_URL = '<?= \miniMVC\site_url(''); ?>';
var ASSET_URL = APP_URL.replace('index.php/', '') + '/assets/';
</script>
<h1><a href="<?= miniMVC\site_url('') ?>">Meta</a></h1>
<span id="outline">[<a href="<?= miniMVC\site_url('outline')?>">Data Outline</a>]</span>

3
assets/config/css_groups.php Normal file → Executable file
View File

@ -24,7 +24,8 @@ return array(
'normalize.css',
'message.css',
'theme.css',
'tinyeditor.css'
'tinyeditor.css',
'prism.css'
)
);
// End of css_groups.php

View File

@ -27,6 +27,7 @@ return array(
*/
'js' => array(
'prism.js',
'kis-lite-dom.js',
'meta.js'
),

0
assets/css/message.css Normal file → Executable file
View File

0
assets/css/normalize.css vendored Normal file → Executable file
View File

127
assets/css/prism.css Executable file
View File

@ -0,0 +1,127 @@
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"],
.token {
color: black;
text-shadow: 0 1px white;
font-family: 'Anonymous Pro', Consolas, Monaco, 'Andale Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.builtin {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #a67f59;
background: hsla(0,0%,100%,.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.regex,
.token.important {
color: #e90;
}
.token.important {
font-weight: bold;
}
.token.entity {
cursor: help;
}

6
assets/css/theme.css Normal file → Executable file
View File

@ -217,7 +217,7 @@ dl.outline dd:last-child {
list-style:square inside;
}
.list li {
.list > li {
list-style:none;
}
@ -231,6 +231,10 @@ dl.multiline, dl.pair {
border-bottom:1px dotted #312;
}
li dl.multiline:last-of-type {
border-bottom:0;
}
dl.multiline dt {
font-weight:bold;
line-height:1.5;

840
assets/js/kis-lite-dom.js Executable file → Normal file

File diff suppressed because it is too large Load Diff

156
assets/js/meta.js Normal file → Executable file
View File

@ -27,39 +27,71 @@ $_.ext('center', function (sel){
sel.style.left = left + "px";
});
(function() {
(function(w, $_) {
"use strict";
"use strict";
var TINY = window.TINY || {};
var $_ = window.$_ || {};
var TINY = w.TINY || {};
var $_ = w.$_ || {};
var parent_map = {
"data":"section",
"section":"category",
"category":"genre",
"genre":"genre"
};
// ! Show/hide forms based on use
$_("fieldset dl").dom.hide();
$_("fieldset legend").event.add('click', function(e){
var form = $_("fieldset dl").dom;
(form.css('display').trim() == 'none')
? form.show()
: form.hide();
($_("fieldset dl").dom.css('display').trim() == 'none')
? $_("fieldset dl").dom.show()
: $_("fieldset dl").dom.hide();
});
var meta = {};
window.meta = meta;
w.meta = meta;
/**
* Create the WYSIWYG editor box
*/
meta.initTINY = function(id) {
// WYSIWYG
new TINY.editor.edit('edit_wysiwyg',
{
id:id,
width:450,
height:175,
cssclass:'te',
controlclass:'tecontrol',
rowclass:'teheader',
dividerclass:'tedivider',
controls:['bold','italic','underline','strikethrough','|','subscript','superscript','|',
'orderedlist','unorderedlist','|','leftalign',
'centeralign','rightalign','blockjustify','|','unformat','n','undo','redo','|',
'image','hr','link','unlink','|'],
footer:true,
fonts:['Verdana','Arial','Georgia','Trebuchet MS'],
xhtml:true,
cssfile:ASSET_URL+'css.php/g/css',
bodyid:'editor',
footerclass:'tefooter',
toggle:{text:'source',activetext:'wysiwyg',cssclass:'toggle'},
resize:{cssclass:'resize'}
});
},
/**
* Deletes a genre/category/section/data item
* based on the current page context
*/
meta.delete_item = function(e) {
var item_id, id, type;
var id, type, parent_id;
// Get the type/id of the item
item_id = this.parentNode.id;
item_id = item_id.split('_');
id = item_id[1];
type = item_id[0];
id = this.parentNode.dataset['id'];
type = this.parentNode.dataset.type;
parent_id = this.parentNode.dataset.parent;
// Confirm deletion
var confirm_string = "Are you sure you want to delete this "+type+"? Deleting this item will delete all items under it. There is no undo.";
@ -70,34 +102,25 @@ $_.ext('center', function (sel){
if (do_delete)
{
// Call the appropriate deletion method
switch(type)
{
case "genre":
case "category":
case "section":
case "data":
$_.post(APP_URL+'delete', {'id':id, 'type':type}, function(res){
if (res == 1)
{
// Reload the page
window.location = window.location;
}
else
{
$_.get(APP_URL+'message', {
type: 'error',
message: 'There was an error deleting that item'
}, function(h) {
$_('body').dom.prepend(h);
});
}
$_.post(APP_URL+'delete', {'id':id, 'type':type}, function(res){
if (res == 1)
{
// Redirect to previous page
var redir_url = APP_URL+parent_map[type]+'/detail/'+parent_id;
w.location = (type !== 'genre')
? redir_url
: APP_URL;
}
else
{
$_.get(APP_URL+'message', {
type: 'error',
message: 'There was an error deleting that item'
}, function(h) {
$_('body').dom.prepend(h);
});
break;
default:
break;
}
}
});
}
};
@ -106,14 +129,10 @@ $_.ext('center', function (sel){
* being edited
*/
meta.get_edit_form = function(e) {
var item_id, id, type;
var id, type;
// Get the type/id of the item
item_id = this.parentNode.id;
item_id = item_id.split('_');
id = item_id[1];
type = item_id[0];
id = this.parentNode.dataset['id'];
type = this.parentNode.dataset.type;
$_('#overlay_bg, #overlay').dom.show();
@ -126,29 +145,7 @@ $_.ext('center', function (sel){
if (type == 'data')
{
// WYSIWYG
new TINY.editor.edit('edit_wysiwyg',
{
id:'val',
width:450,
height:175,
cssclass:'te',
controlclass:'tecontrol',
rowclass:'teheader',
dividerclass:'tedivider',
controls:['bold','italic','underline','strikethrough','|','subscript','superscript','|',
'orderedlist','unorderedlist','|','leftalign',
'centeralign','rightalign','blockjustify','|','unformat','n','undo','redo','|',
'image','hr','link','unlink','|'],
footer:true,
fonts:['Verdana','Arial','Georgia','Trebuchet MS'],
xhtml:true,
cssfile:ASSET_URL+'css.php/g/css',
bodyid:'editor',
footerclass:'tefooter',
toggle:{text:'source',activetext:'wysiwyg',cssclass:'toggle'},
resize:{cssclass:'resize'}
});
meta.initTINY('val');
//Do it again, so it's correct this time!
$_('#overlay').center();
@ -190,7 +187,7 @@ $_.ext('center', function (sel){
if (res == 1)
{
// Reload the page
window.location = window.location;
w.location = w.location;
}
else
{
@ -217,12 +214,17 @@ $_.ext('center', function (sel){
// Overlay close
$_("#overlay_bg").event.add('click', function(e) {
$_('#overlay_bg').dom.css('display', '');
$_('#overlay_bg').dom.css('display', 'none');
$_('#overlay').dom.html('');
$_('#overlay').dom.hide();
});
// Edit form submission
$_.event.live('#edit_form', 'submit', meta.update_item);
}());
// WYSIWYG on section/data pages
if (document.getElementById('textarea') != null)
{
meta.initTINY('textarea');
}
}(window, $_));

12
assets/js/prism.js Executable file
View File

@ -0,0 +1,12 @@
/**
* Prism: Lightweight, robust, elegant syntax highlighting
* MIT license http://www.opensource.org/licenses/mit-license.php/
* @author Lea Verou http://lea.verou.me
*/(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data),o);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar,l.language);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r,i){return n.stringify(t.tokenize(e,r),i)},tokenize:function(e,n,r){var i=t.Token,s=[e],o=n.rest;if(o){for(var u in o)n[u]=o[u];delete n.rest}e:for(var u in n){if(!n.hasOwnProperty(u)||!n[u])continue;var a=n[u],f=a.inside,l=!!a.lookbehind,c=0;a=a.pattern||a;for(var h=0;h<s.length;h++){var p=s[h];if(s.length>e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+"</"+s.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();;
Prism.languages.markup={comment:/&lt;!--[\w\W]*?-->/g,prolog:/&lt;\?.+?\?>/,doctype:/&lt;!DOCTYPE.+?>/,cdata:/&lt;!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/&lt;\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^&lt;\/?[\w:-]+/i,inside:{punctuation:/^&lt;\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&amp;#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&amp;/,"&"))});;
Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*{))/gi,inside:{punctuation:/[;:]/g}},url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/g,property:/(\b|\B)[\w-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[\{\};:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/(&lt;|<)style[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/style(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)style[\w\W]*?(>|&gt;)|(&lt;|<)\/style(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});;
Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}}, number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|&lt;=?|>=?|={1,3}|(&amp;){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};
;
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|throw|catch|finally|null|break|continue)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/script(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)|(&lt;|<)\/script(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});
;
Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)).*?(\r?\n|$))/g,lookbehind:!0},string: /("|')(\\?.)*?\1/g,keyword:/\b(ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMPORARY|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/gi,boolean:/\b(TRUE|FALSE|NULL)\b/gi,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/\b(ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]{1}|!|=?&lt;|=?&gt;|={1}|(&amp;){1,2}|\|?\||\?|\*|\//gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[;[\]()`,.]/g};;

5
composer.json Normal file
View File

@ -0,0 +1,5 @@
{
"require": {
"aura/router": "2.0.*@dev"
}
}

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

8
index.php Normal file → Executable file
View File

@ -32,12 +32,18 @@ define('MM_SYS_PATH', __DIR__.'/sys/');
define('MM_APP_PATH', __DIR__.'/app/');
define('MM_MOD_PATH', MM_APP_PATH.'modules/');
// Autoload vendors
require(MM_BASE_PATH . '/vendor/autoload.php');
// Require the basic configuration file
require(MM_APP_PATH .'config/config.php');
require(MM_APP_PATH . 'config/config.php');
// Require the most important files
require(MM_SYS_PATH . 'common.php');
// Start the autoloader
spl_autoload_register('miniMVC\autoload');
// And away we go!
init();

7
phpdoc.dist.xml Normal file → Executable file
View File

@ -12,13 +12,10 @@
</transformations>
<files>
<directory>.</directory>
<directory>tests</directory>
<directory>assets</directory>
<directory>app/config</directory>
<directory>app/views</directory>
<directory>sys/db</directory>
<directory>app/modules/</directory>
<ignore>tests/*</ignore>
<ignore>assets/*</ignore>
<ignore>vendor/*</ignore>
<ignore>sys/db/*</ignore>
<ignore>app/config/*</ignore>
<ignore>app/views/*</ignore>

143
sys/common.php Normal file → Executable file
View File

@ -21,6 +21,7 @@
*/
namespace miniMVC;
use \Aura\Router\RouterFactory;
// --------------------------------------------------------------------------
// ! Autoloading
@ -59,9 +60,6 @@ function autoload($name)
}
}
// Start the autoloader
spl_autoload_register('miniMVC\autoload');
// --------------------------------------------------------------------------
// ! Error handling / messages
// --------------------------------------------------------------------------
@ -362,107 +360,50 @@ function get_segments()
*/
function route()
{
$router_factory = new RouterFactory;
$router = $router_factory->newInstance();
// Get the path info
$pi = $_SERVER['PATH_INFO'];
$ru = $_SERVER['REQUEST_URI'];
$sn = $_SERVER['SCRIPT_NAME'];
$qs = $_SERVER['QUERY_STRING'];
// Load the routes config file to add additional routes
$routes = [];
require_once(MM_APP_PATH . 'config/routes.php');
// Make sure the home page works when in a sub_directory
if (strlen($sn) > strlen($ru))
{
$pi = '/';
}
// get the incoming request URL path
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// Load the routes config file
$routes = require_once(MM_APP_PATH . 'config/routes.php');
// get the route based on the path and server
$route = $router->match($path, $_SERVER);
// Set the default route
$module = $routes['default_module'];
// Set default controller/function
$controller = $routes['default_controller'];
$func = "index";
$route_set = FALSE;
$action = 'index';
// If it isn't the index page
if ( ! empty($pi) && $pi !== "/")
// 404 Condition
if (empty($route))
{
//Remove trailing slash and begining slash
$pi = trim($pi, '/');
$segments = explode("/", $pi);
show_404();
return;
}
// URL matches the route exactly? Cool, that was easy
if (isset($routes[$pi]))
// Home
if (isset($route->name) && $route->name === 'home')
{
run($controller, $action);
return;
}
// Gather route parts
foreach(array('controller', 'action', 'id') as $param)
{
if (isset($route->params[$param]))
{
list($module, $controller, $func) = explode("/", $routes[$pi]);
run($module, $controller, $func);
return;
}
else
{
$custom_routes = $routes;
// Skip required routes
unset($custom_routes['default_module']);
unset($custom_routes['default_controller']);
unset($custom_routes['404_handler']);
foreach($custom_routes as $uri => $map)
{
if (preg_match("`{$uri}`i", $pi))
{
list($module, $controller, $func) = explode("/", $map);
run($module, $controller, $func);
return;
}
}
}
// Doesn't match a predefined route?
// Match on module/controller/method, module/controller, controller/method, or method
if ( ! $route_set)
{
$num_segments = 0;
if (strpos($pi, '/') === FALSE && ! empty($pi))
{
$num_segments = 1;
}
else
{
$segments = explode('/', $pi);
$num_segments = count($segments);
}
// Determine route based on uri segments
if ($num_segments === 1)
{
$func = $pi;
}
elseif ($num_segments === 2)
{
list($module, $controller) = $segments;
// If it's just controller/function
if ($controller == 'index')
{
$controller = $module;
$module = $routes['default_module'];
$func = 'index';
}
}
else
{
list($module, $controller, $func) = $segments;
}
$$param = $route->params[$param];
}
}
run($module, $controller, $func);
if ( ! isset($id)) $id = array();
return;
// Dispatch to the appropriate controller
run($controller, $action, array($id));
}
// --------------------------------------------------------------------------
@ -470,14 +411,14 @@ function route()
/**
* Instantiate the appropriate controller
*
* @param string
* @param string
* @param string
* @param array
* @param string $controller
* @param string $func
* @param array $args
* @return void
*/
function run($module, $controller, $func, $args = array())
function run($controller, $func, $args = array())
{
$path = MM_MOD_PATH . "{$module}/controllers/{$controller}.php";
$path = MM_MOD_PATH . "meta/controllers/{$controller}.php";
if (is_file($path))
{
@ -492,7 +433,7 @@ function run($module, $controller, $func, $args = array())
// Define the name of the current module for file loading
if ( ! defined('MM_MOD'))
{
define('MM_MOD', $module);
define('MM_MOD', 'meta');
}
if (class_exists($controller))
@ -500,11 +441,9 @@ function run($module, $controller, $func, $args = array())
$class = new $controller();
}
//show_error(to_string(get_declared_classes()));
return call_user_func_array(array($class, $func), $args);
call_user_func_array(array($class, $func), $args);
return;
}
show_404();
}
// Function doesn't exist...404

15
sys/core/Controller.php Normal file → Executable file
View File

@ -92,6 +92,21 @@ class Controller {
{
return $this->page->load_view($file, $data, $return);
}
// --------------------------------------------------------------------------
/**
* Automate loading of header and footer
*
* @param string $file
* @param array $data
* @param bool $return
* @return mixed
*/
public function render($file, array $data=array(), $return=FALSE)
{
return $this->page->render($file, $data, $return);
}
}
// End of controller.php

0
sys/core/Model.php Normal file → Executable file
View File

11
sys/core/Page.php Normal file → Executable file
View File

@ -166,12 +166,6 @@ class Page {
{
ob_end_flush();
}
}
else
{
echo 'No content';
}
}
@ -452,7 +446,7 @@ class Page {
$this->_headers($html5);
//Output Header
$this->load_view('header', $data);
$this->append_output($this->load_view('header', $data, TRUE));
return $this;
}
@ -468,7 +462,7 @@ class Page {
$data['foot_js'] = ($this->foot_js != "") ? $this->foot_js : '';
$this->load_view('footer', $data);
$this->append_output($this->load_view('footer', $data, TRUE));
}
// --------------------------------------------------------------------------
@ -543,6 +537,7 @@ class Page {
{
$this->build_header();
$this->load_view($view, $data);
$this->set_foot_js_group('js');
$this->build_footer();
}

10
sys/core/db.php Normal file → Executable file
View File

@ -21,7 +21,7 @@ namespace miniMVC;
* @package miniMVC
* @subpackage System
*/
class db extends \Query_Builder {
class db extends \Query\Query_Builder {
/**
* DB connection instances
@ -56,7 +56,7 @@ class db extends \Query_Builder {
}
//echo 'Creating new instance of db class.';
self::$instance[$dbname] = new DB($db_conf[$dbname]);
self::$instance[$dbname] = Query($db_conf[$dbname]);
}
return self::$instance[$dbname];
@ -81,10 +81,8 @@ class db extends \Query_Builder {
{
$error = $this->errorInfo();
}
$code = $error[0];
$driver_code = $error[1];
$message = $error[2];
list($code, $driver_code, $message) = $error;
// Contain the content for buffering
ob_start();

1
sys/db

@ -1 +0,0 @@
Subproject commit 27318506d05a1ce0d7e7c8b891a23ab558b512a5

1
sys/db Symbolic link
View File

@ -0,0 +1 @@
/var/www/htdocs/dev.timshomepage.net/github/Query/

View File

@ -1,201 +0,0 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Class to simplify dealing with bcrypt for password handling
*
* @see
* @package miniMVC
* @subpackage libraries
*/
class Bcrypt {
/**
* Number of times to recurse
*
* @var int
*/
private $rounds;
/**
* Stores random seed
*
* @var mixed
*/
private $randomState;
/**
* Create a new Bcrypt object
*
* @param int $rounds
*/
public function __construct($rounds = 12)
{
if (CRYPT_BLOWFISH != 1)
{
throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
}
$this->rounds = $rounds;
}
// --------------------------------------------------------------------------
/**
* Returns a has for the input string
*
* @param string
* @return string
*/
public function hash($input)
{
$hash = crypt($input, $this->getSalt());
if (strlen($hash) > 13)
return $hash;
return false;
}
// --------------------------------------------------------------------------
/**
* Check if a password hash is valid
*
* @param string
* @param string
* @return bool
*/
public function verify($input, $existingHash)
{
$hash = crypt($input, $existingHash);
return $hash === $existingHash;
}
// --------------------------------------------------------------------------
/**
* Private function to generate the random salt
*
* @return string
*/
private function getSalt()
{
$salt = sprintf('$2a$%02d$', $this->rounds);
$bytes = $this->getRandomBytes(16);
$salt .= $this->encodeBytes($bytes);
return $salt;
}
// --------------------------------------------------------------------------
/**
* Private method to generate random characters for salt
*
* @param int
* @return string
*/
private function getRandomBytes($count)
{
$bytes = '';
if (function_exists('openssl_random_pseudo_bytes') && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) // OpenSSL slow on Win
{
$bytes = openssl_random_pseudo_bytes($count);
}
if ($bytes === '' && is_readable('/dev/urandom') && ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE)
{
$bytes = fread($hRand, $count);
fclose($hRand);
}
if (strlen($bytes) < $count)
{
$bytes = '';
if ($this->randomState === null)
{
$this->randomState = microtime();
if (function_exists('getmypid'))
{
$this->randomState .= getmypid();
}
}
for ($i = 0; $i < $count; $i += 16)
{
$this->randomState = md5(microtime() . $this->randomState);
if (PHP_VERSION >= '5')
{
$bytes .= md5($this->randomState, true);
}
else
{
$bytes .= pack('H*', md5($this->randomState));
}
}
$bytes = substr($bytes, 0, $count);
}
return $bytes;
}
// --------------------------------------------------------------------------
/**
* Further randomizes salt?
*
* @param string
* @return string
*/
private function encodeBytes($input)
{
// The following is code from the PHP Password Hashing Framework
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '';
$i = 0;
do
{
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16)
{
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
}

View File

@ -1,153 +0,0 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class for using JSON as a key->value data store
*
* @package miniMVC
* @subpackage Libraries
*/
class Data_Store {
/**
* Settings object represented by the currently loaded JSON file
*/
private $current;
/**
* Singleton instance
*/
private static $instance;
/**
* Create and/or load json file
*/
protected function __construct()
{
$path = MM_APP_PATH .'config/data_store.json';
if ( ! is_file($path))
{
touch($path);
$this->current = (object)[];
}
else
{
// Load the file
$json = file_get_contents($path);
// Load the object into the class
$this->current = json_decode($json);
}
}
// --------------------------------------------------------------------------
/**
* Output the data on destruct
*/
public function __destruct()
{
$file_string = json_encode($this->current, JSON_PRETTY_PRINT);
file_put_contents(MM_APP_PATH . 'config/data_store.json', $file_string);
}
// --------------------------------------------------------------------------
/**
* Magic function called when cloning an object
*/
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
// --------------------------------------------------------------------------
/**
* Magic method to simplify isset checking for config options
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return (isset($this->current->{$key}))
? $this->current->{$key}
: NULL;
}
// --------------------------------------------------------------------------
/**
* Magic method to simplify setting config options
*
* @param string $key
* @param mixed
*/
public function __set($key, $val)
{
return $this->current->{$key} = $val;
}
// --------------------------------------------------------------------------
/**
* Static method to retreive current instance
* of the singleton
*
* @return self
*/
public static function &get_instance()
{
if( ! isset(self::$instance))
{
$name = __CLASS__;
self::$instance = new $name();
}
return self::$instance;
}
// --------------------------------------------------------------------------
/**
* Removes a key from the data store
*
* @param string $key
* @return void
*/
public function del($key)
{
unset($this->current->{$key});
}
// --------------------------------------------------------------------------
/**
* Return the entire data store object
*
* @return object
*/
public function get_all()
{
return $this->current;
}
}
// End of data store.php

View File

@ -1,124 +0,0 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class to improve handling of PHP sessions
*
* @package miniMVC
* @subpackage Libraries
*/
class Session {
/**
* Reference to session superglobal
*
* @var array
*/
protected $sess = array();
/**
* Reference to current instance
*
* @var Session
*/
protected static $instance;
/**
* Start a session
*/
protected function __construct()
{
session_start();
// Create a re-generatable id using a hash of the user's ip address and user agent
$session_id = sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
// Save a reference to the session for later access
$_SESSION[$session_id] = (isset($_SESSION[$session_id])) ?: array();
$this->sess =& $_SESSION[$session_id];
}
// --------------------------------------------------------------------------
/**
* Set a session value
*
* @param string $key
* @param mixed $val
* @return void
*/
public function __set($key, $val)
{
$this->sess[$key] = $val;
}
// --------------------------------------------------------------------------
/**
* Retreive a session value
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->sess[$key];
}
// --------------------------------------------------------------------------
/**
* Destroy a session
*
* @return void
*/
public function destroy()
{
sess_destroy();
}
// --------------------------------------------------------------------------
/**
* Singleton getter function
*
* @return self
*/
public static function &get_instance()
{
if ( ! isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
// --------------------------------------------------------------------------
/**
* Magic function called when cloning an object
*/
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
// End of session.php