├── public └── assets │ ├── js │ ├── admin.js │ └── retina.js │ ├── img │ ├── logo-login.png │ └── logo-login@2x.png │ └── css │ ├── icons │ ├── flaticons-stroke.eot │ ├── flaticons-stroke.ttf │ └── flaticons-stroke.woff │ ├── animations.less │ └── styles.less ├── readme.md ├── tests ├── cases │ └── posts.test.php ├── phpunit.xml └── bootstrap.php ├── views ├── pages │ ├── create.phtml │ ├── edit.phtml │ └── index.phtml ├── users │ └── index.phtml ├── categories │ └── index.phtml ├── layout.phtml ├── posts │ ├── index.phtml │ ├── edit.phtml │ └── create.phtml ├── login.phtml └── partials │ └── menu.phtml ├── src └── Anchor │ ├── Mappers │ ├── Menu.php │ ├── Comments.php │ ├── Users.php │ ├── Categories.php │ ├── Themes.php │ ├── Meta.php │ ├── Templates.php │ ├── Base.php │ ├── Pages.php │ └── Posts.php │ ├── Services │ ├── Registry.php │ ├── Validator │ │ └── Rule.php │ ├── Contracts │ │ └── Validatable.php │ ├── I18n.php │ ├── Csrf.php │ ├── Validator.php │ ├── Nav.php │ ├── Auth.php │ ├── Date.php │ ├── Assets.php │ └── Messages.php │ ├── Exceptions │ └── HttpNotFound.php │ ├── Controllers │ ├── Feeds.php │ ├── Page.php │ ├── Admin │ │ ├── Categories.php │ │ ├── Backend.php │ │ ├── Users.php │ │ ├── Pages.php │ │ └── Posts.php │ ├── Posts.php │ ├── Controller.php │ ├── Article.php │ └── Frontend.php │ ├── Models │ ├── Category.php │ ├── Comment.php │ ├── User.php │ ├── Page.php │ └── Post.php │ ├── Forms │ ├── Fields │ │ ├── Textarea.php │ │ ├── Password.php │ │ ├── Button.php │ │ ├── Hidden.php │ │ ├── Text.php │ │ ├── Select.php │ │ └── Field.php │ ├── Login.php │ ├── Post.php │ └── Form.php │ └── Providers │ └── ShipServiceProvider.php ├── functions ├── metadata.php ├── old │ ├── config.php │ ├── metadata.php │ ├── author.php │ ├── users.php │ ├── posts.php │ ├── search.php │ ├── categories.php │ ├── pages.php │ ├── menus.php │ ├── comments.php │ ├── helpers.php │ └── articles.php ├── author.php ├── pages.php ├── posts.php ├── search.php ├── categories.php ├── menus.php ├── helpers.php ├── articles.php ├── comments.php └── depreciated.php ├── routes ├── categories.php ├── menu.php ├── themes.php ├── pages.php ├── admin.php ├── posts.php ├── plugins.php ├── metadata.php ├── site.php ├── fields.php ├── variables.php ├── comments.php └── users.php ├── routes.php └── composer.json /public/assets/js/admin.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Anchor Core 2 | 3 | Core library for Anchor. -------------------------------------------------------------------------------- /public/assets/img/logo-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drFabio/anchor-core/master/public/assets/img/logo-login.png -------------------------------------------------------------------------------- /public/assets/img/logo-login@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drFabio/anchor-core/master/public/assets/img/logo-login@2x.png -------------------------------------------------------------------------------- /public/assets/css/icons/flaticons-stroke.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drFabio/anchor-core/master/public/assets/css/icons/flaticons-stroke.eot -------------------------------------------------------------------------------- /public/assets/css/icons/flaticons-stroke.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drFabio/anchor-core/master/public/assets/css/icons/flaticons-stroke.ttf -------------------------------------------------------------------------------- /public/assets/css/icons/flaticons-stroke.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drFabio/anchor-core/master/public/assets/css/icons/flaticons-stroke.woff -------------------------------------------------------------------------------- /tests/cases/posts.test.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | 7 |
8 |
9 |

10 |
11 |
12 | -------------------------------------------------------------------------------- /views/pages/edit.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | 7 |
8 |
9 |

10 |
11 |
12 | -------------------------------------------------------------------------------- /tests/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./cases/ 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Anchor/Mappers/Menu.php: -------------------------------------------------------------------------------- 1 | Site Variables 7 | * @param string 8 | * @param string 9 | * @return string 10 | */ 11 | function site_meta($key, $default = '') { 12 | global $app; 13 | 14 | return $app['meta']->get($key, $default); 15 | } -------------------------------------------------------------------------------- /routes/categories.php: -------------------------------------------------------------------------------- 1 | add(new Route('admin/categories', array( 9 | 'conditions' => array($auth, $csrf), 10 | 'requirements' => array('method' => 'GET'), 11 | 'controller' => array($app['adminCategoriesController'], 'index') 12 | ))); -------------------------------------------------------------------------------- /src/Anchor/Exceptions/HttpNotFound.php: -------------------------------------------------------------------------------- 1 | setLang($lang); 14 | $this->path = $path; 15 | } 16 | 17 | public function setLang($lang) { 18 | $this->lang = $lang; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/Anchor/Mappers/Categories.php: -------------------------------------------------------------------------------- 1 | getCurrentPage(); 14 | 15 | $this->registry->put('page', $page); 16 | 17 | return $this->renderTemplate('page', $page->slug); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anchorcms/anchor-core", 3 | "description": "Library", 4 | "license": "GPL-3.0", 5 | "version": "0.1.0", 6 | "type": "library", 7 | "authors": [ 8 | { 9 | "name": "Kieron", 10 | "email": "hello@madebykieron.co.uk", 11 | "homepage": "http://madebykieron.co.uk", 12 | "role": "Developer" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.3" 17 | }, 18 | "autoload": { 19 | "psr-0": { 20 | "Anchor": "src/" 21 | }, 22 | "files": [] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /views/pages/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Pages

5 | 15 |
16 | 17 |
18 |
19 |

20 |
21 |
22 | -------------------------------------------------------------------------------- /views/users/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Users

5 | 15 |
16 | 17 |
18 |
19 |

20 |
21 |
22 | -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Textarea.php: -------------------------------------------------------------------------------- 1 | %s'; 13 | 14 | public function getHtml() { 15 | $this->attr['name'] = $this->name; 16 | 17 | return sprintf($this->prototype, $this->getAttrString($this->attr), $this->getValue()); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Password.php: -------------------------------------------------------------------------------- 1 | '; 13 | 14 | public function getHtml() { 15 | $this->attr['name'] = $this->name; 16 | $this->attr['type'] = 'password'; 17 | 18 | return sprintf($this->prototype, $this->getAttrString($this->attr)); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/Anchor/Models/User.php: -------------------------------------------------------------------------------- 1 | meta = $meta; 16 | } 17 | 18 | public function active() { 19 | $active = $this->meta->select('value') 20 | ->where('key', '=', 'theme') 21 | ->column(); 22 | 23 | return realpath('themes/' . $active); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /views/categories/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Categories

5 | 15 |
16 | 17 |
18 |
19 |

20 |
21 |
22 | -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Button.php: -------------------------------------------------------------------------------- 1 | %s'; 13 | 14 | public function getHtml() { 15 | if( ! isset($this->attr['type'])) { 16 | $this->attr['type'] = 'submit'; 17 | } 18 | 19 | return sprintf($this->prototype, $this->getAttrString($this->attr), $this->getLabel()); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Hidden.php: -------------------------------------------------------------------------------- 1 | '; 13 | 14 | public function getHtml() { 15 | $this->attr['name'] = $this->name; 16 | $this->attr['type'] = 'hidden'; 17 | $this->attr['value'] = $this->getValue(); 18 | 19 | return sprintf($this->prototype, $this->getAttrString($this->attr)); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/Anchor/Mappers/Meta.php: -------------------------------------------------------------------------------- 1 | cached[$key])) { 18 | return $this->cached[$key]; 19 | } 20 | 21 | return $this->cached[$key] = $this->query()->select('value')->where('key', '=', $key)->column(); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/Anchor/Mappers/Templates.php: -------------------------------------------------------------------------------- 1 | theme = $theme; 16 | } 17 | 18 | public function find($name) { 19 | return $this->theme . '/' . $name . '.php'; 20 | } 21 | 22 | public function exists($name) { 23 | return file_exists($this->theme . '/' . $name . '.php'); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /views/layout.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <?php echo $title; ?> 7 | 8 | 9 | 10 | 11 | 12 | ', $class); ?> 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Anchor/Controllers/Admin/Categories.php: -------------------------------------------------------------------------------- 1 | categories->all(); 15 | 16 | $vars['messages'] = $this->messages->render(); 17 | $vars['token'] = $this->csrf->token(); 18 | 19 | return $this->getCommonView('categories/index.phtml', $vars)->render(); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Text.php: -------------------------------------------------------------------------------- 1 | '; 13 | 14 | public function getHtml() { 15 | $this->attr['name'] = $this->name; 16 | $this->attr['type'] = 'text'; 17 | $this->attr['value'] = $this->getValue() ? $this->getValue() : $this->getOption('default'); 18 | 19 | return sprintf($this->prototype, $this->getAttrString($this->attr)); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/Anchor/Controllers/Posts.php: -------------------------------------------------------------------------------- 1 | getCurrentPage(); 14 | 15 | $this->registry->put('page', $page); 16 | 17 | return $this->renderTemplate('posts', $page->slug); 18 | } 19 | 20 | public function category() { 21 | $page = $this->getCurrentPage(); 22 | 23 | $this->registry->put('page', $page); 24 | 25 | return $this->renderTemplate('posts', $page->slug); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/Anchor/Models/Page.php: -------------------------------------------------------------------------------- 1 | slug; 30 | } 31 | 32 | public function content() { 33 | return $this->html; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /views/posts/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Latest posts

5 | 15 |
16 | 17 |
18 | New post 19 | Click a post on the left to edit, or add a post at the top-right. 20 |
-------------------------------------------------------------------------------- /functions/old/metadata.php: -------------------------------------------------------------------------------- 1 | Site Metadata > Site Name 7 | * @return string 8 | */ 9 | function site_name() { 10 | return site_meta('sitename'); 11 | } 12 | 13 | /** 14 | * Returns the site description 15 | * 16 | * @see Extend > Site Metadata > Site Description 17 | * @return string 18 | */ 19 | function site_description() { 20 | return site_meta('description'); 21 | } 22 | 23 | /** 24 | * Returns the value of a custom site variable 25 | * 26 | * @see Extend > Site Variables 27 | * @param string 28 | * @param string 29 | * @return string 30 | */ 31 | function site_meta($key, $default = '') { 32 | global $app; 33 | 34 | return $app['meta']->get($key, $default); 35 | } -------------------------------------------------------------------------------- /routes/menu.php: -------------------------------------------------------------------------------- 1 | 'auth'), function() { 4 | 5 | /* 6 | List Menu Items 7 | */ 8 | Route::get('admin/menu', function() { 9 | $vars['messages'] = Notify::read(); 10 | $vars['pages'] = Page::where('show_in_menu', '=', 1)->sort('menu_order')->get(); 11 | 12 | return View::create('menu/index', $vars) 13 | ->partial('header', 'partials/header') 14 | ->partial('footer', 'partials/footer'); 15 | }); 16 | 17 | /* 18 | Update order 19 | */ 20 | Route::post('admin/menu/update', function() { 21 | $sort = Input::get('sort'); 22 | 23 | foreach($sort as $index => $id) { 24 | Page::where('id', '=', $id)->update(array('menu_order' => $index)); 25 | } 26 | 27 | return Response::json(array('result' => true)); 28 | }); 29 | 30 | }); -------------------------------------------------------------------------------- /views/login.phtml: -------------------------------------------------------------------------------- 1 | open(); ?> 2 | getElement('token')->getHtml(); ?> 3 | 4 | 5 | 6 | 7 | 8 |

9 | getElement('user')->getHtml(); ?> 10 | 11 |

12 | 13 |

14 | getElement('pass')->getHtml(); ?> 15 | 16 |

17 | 18 |

getElement('login')->getHtml(); ?>

19 | close(); ?> -------------------------------------------------------------------------------- /functions/author.php: -------------------------------------------------------------------------------- 1 | getAuthor(); 10 | } 11 | 12 | /** 13 | * Returns the article author ID (user ID) 14 | * 15 | * @return string 16 | */ 17 | function author_id() { 18 | return author()->id; 19 | } 20 | 21 | /** 22 | * Returns the article author Name 23 | * 24 | * @return string 25 | */ 26 | function author_name() { 27 | return author()->real_name; 28 | } 29 | 30 | /** 31 | * Returns the article author email 32 | * 33 | * @return string 34 | */ 35 | function author_email() { 36 | return author()->email; 37 | } 38 | 39 | /** 40 | * Returns the article author bio (user bio) 41 | * 42 | * @return string 43 | */ 44 | function author_bio() { 45 | return author()->bio; 46 | } -------------------------------------------------------------------------------- /functions/old/author.php: -------------------------------------------------------------------------------- 1 | author; 10 | } 11 | 12 | /** 13 | * Returns the article author ID (user ID) 14 | * 15 | * @return string 16 | */ 17 | function author_id() { 18 | return author()->id; 19 | } 20 | 21 | /** 22 | * Returns the article author Name 23 | * 24 | * @return string 25 | */ 26 | function author_name() { 27 | return author()->real_name; 28 | } 29 | 30 | /** 31 | * Returns the article author email 32 | * 33 | * @return string 34 | */ 35 | function author_email() { 36 | return author()->email; 37 | } 38 | 39 | /** 40 | * Returns the article author bio (user bio) 41 | * 42 | * @return string 43 | */ 44 | function author_bio() { 45 | return author()->bio; 46 | } -------------------------------------------------------------------------------- /public/assets/css/animations.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Keyframes 3 | */ 4 | 5 | @-webkit-keyframes 'fade' { 6 | from { opacity: 0; } to { opacity: 1; } 7 | } 8 | @keyframes 'fade' { 9 | from { opacity: 0; } to { opacity: 1; } 10 | } 11 | 12 | @-webkit-keyframes 'fade-down' { 13 | from { opacity: 0; top: -20px; } to { opacity: 1; top: 0; } 14 | } 15 | @keyframes 'fade-down' { 16 | from { opacity: 0; top: -20px; } to { opacity: 1; top: 0; } 17 | } 18 | 19 | /** 20 | * Animations 21 | */ 22 | 23 | * { 24 | -webkit-transition: opacity .25s, color .25s, background .25s; 25 | } 26 | 27 | body.login { 28 | -webkit-animation: fade .5s 1 ease-in; 29 | animation: fade .5s 1 ease-in; 30 | } 31 | body.login .warning, body.login .error { 32 | -webkit-animation: fade-down .5s 1 ease-in-out; 33 | animation: fade-down .5s 1 ease-in-out; 34 | } -------------------------------------------------------------------------------- /views/partials/menu.phtml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Select.php: -------------------------------------------------------------------------------- 1 | %s'; 13 | 14 | public function getHtml() { 15 | $this->attr['name'] = $this->name; 16 | 17 | return sprintf($this->prototype, $this->getAttrString($this->attr), $this->getOptions()); 18 | } 19 | 20 | protected function getOptions() { 21 | $options = isset($this->options['options']) ? $this->options['options'] : array(); 22 | $html = ''; 23 | 24 | foreach($options as $key => $value) { 25 | $selected = ($this->getValue() == $key) ? ' selected' : ''; 26 | $html .= ''; 27 | } 28 | 29 | return $html; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/Anchor/Mappers/Base.php: -------------------------------------------------------------------------------- 1 | results = $results; 21 | } 22 | 23 | public function loop(Closure $callback) { 24 | if(null === $this->results) { 25 | $this->results = new \ArrayIterator($this->all()); 26 | } 27 | 28 | if($this->results->valid()) { 29 | $callback($this->results->current()); 30 | 31 | $this->results->next(); 32 | 33 | return true; 34 | } 35 | 36 | $this->results->rewind(); 37 | 38 | return false; 39 | } 40 | 41 | public function create($row) { 42 | return $row; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/Anchor/Services/Csrf.php: -------------------------------------------------------------------------------- 1 | session = $session; 16 | } 17 | 18 | public function token() { 19 | $tokens = $this->session->get('tokens', array()); 20 | 21 | $token = uniqid(); 22 | $tokens[] = $token; 23 | 24 | $this->session->put('tokens', $tokens); 25 | 26 | return $token; 27 | } 28 | 29 | public function verify($token) { 30 | $tokens = $this->session->get('tokens', array()); 31 | $offset = array_search($token, $tokens); 32 | 33 | if(false !== $offset) { 34 | unset($tokens[$offset]); 35 | 36 | $this->session->put('tokens', $tokens); 37 | 38 | return true; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /functions/old/users.php: -------------------------------------------------------------------------------- 1 | append(new Hidden('token')); 19 | 20 | $this->append(new Text('user', 21 | array( 22 | 'label' => 'Username' 23 | ), array( 24 | 'placeholder' => 'Username', 25 | 'autofocus' => 'autofocus', 26 | ) 27 | )); 28 | 29 | $this->append(new Password('pass', 30 | array( 31 | 'label' => 'Password' 32 | ), array( 33 | 'placeholder' => 'Password' 34 | ) 35 | )); 36 | 37 | $this->append(new Button('login', 38 | array( 39 | 'label' => 'Log In' 40 | ), array( 41 | 'class' => 'btn', 42 | 'type' => 'submit' 43 | ) 44 | )); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/Anchor/Mappers/Pages.php: -------------------------------------------------------------------------------- 1 | query = $query; 22 | $this->meta = $meta; 23 | } 24 | 25 | public function home() { 26 | $id = $this->meta->get('home_page'); 27 | 28 | if(isset($this->cached[$id])) { 29 | return $this->cached[$id]; 30 | } 31 | 32 | return $this->cached[$id] = $this->find($id); 33 | } 34 | 35 | public function posts() { 36 | $id = $this->meta->get('posts_page'); 37 | 38 | if(isset($this->cached[$id])) { 39 | return $this->cached[$id]; 40 | } 41 | 42 | return $this->cached[$id] = $this->find($id); 43 | } 44 | 45 | public function create($row) { 46 | return new Page($row); 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/Anchor/Services/Validator.php: -------------------------------------------------------------------------------- 1 | getValidationRules($this); 23 | 24 | foreach($this->rules as $field => $callback) { 25 | $value = isset($entity->$field) ? $entity->$field : null; 26 | $message = ''; 27 | 28 | if( ! $callback($value, $message)) { 29 | $this->valid = false; 30 | $this->messages[$field] = $message; 31 | } 32 | } 33 | } 34 | 35 | public function isValid() { 36 | return $this->valid; 37 | } 38 | 39 | public function addRule($field, Closure $rule) { 40 | $this->rules[$field] = $rule; 41 | } 42 | 43 | public function getMessages() { 44 | return $this->messages; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/Anchor/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | container[$property])) { 21 | return $this->container[$property]; 22 | } 23 | 24 | // try dependencies if any are set 25 | if(isset($this->dependencies[$property])) { 26 | return $this->dependencies[$property]; 27 | } 28 | 29 | throw new RuntimeException(sprintf('Undefined property "%s"', $property)); 30 | } 31 | 32 | public function setDependency($property, $value) { 33 | $this->dependencies[$property] = $value; 34 | } 35 | 36 | public function setContainer($container) { 37 | $this->container = $container; 38 | } 39 | 40 | public function getContainer() { 41 | return $this->container; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/Anchor/Services/Nav.php: -------------------------------------------------------------------------------- 1 | uri = $uri; 25 | } 26 | 27 | public function add($title, $uri, $class = '') { 28 | $item = new \StdClass; 29 | $item->title = $title; 30 | $item->class = $class; 31 | $item->uri = $this->uri->to($this->prefix.'/'.$uri); 32 | $item->active = preg_match('#' . $this->prefix.'/'.$uri . '#', $this->active) > 0; 33 | $this->items[] = $item; 34 | } 35 | 36 | public function getIterator() { 37 | return new ArrayIterator($this->items); 38 | } 39 | 40 | public function setPrefix($prefix) { 41 | $this->prefix = '/' . trim($prefix, '/'); 42 | 43 | return $this; 44 | } 45 | 46 | public function setActive($uri) { 47 | $this->active = $uri; 48 | 49 | return $this; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /views/posts/edit.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Latest posts

5 | 15 |
16 | 17 | open(); ?> 18 | 19 |
20 |
21 |

getElement('title')->getHtml(); ?>

22 |

getElement('save')->getHtml(); ?>

23 | Custom Fields 24 |
25 | 26 |

getElement('markdown')->getHtml(); ?>

27 |
28 | 29 |
30 | getElementsExcept(array('title', 'markdown', 'save')) as $field): ?> 31 |


32 | getHtml(); ?>

33 | 34 |
35 | 36 | close(); ?> -------------------------------------------------------------------------------- /src/Anchor/Services/Auth.php: -------------------------------------------------------------------------------- 1 | session = $session; 16 | $this->users = $users; 17 | } 18 | 19 | public function guest() { 20 | return $this->session->has('user') === false; 21 | } 22 | 23 | public function user() { 24 | if($this->session->has('user')) { 25 | return $this->users->find($this->session->get('user')); 26 | } 27 | } 28 | 29 | public function logout() { 30 | $this->session->remove('user'); 31 | } 32 | 33 | public function attempt($user, $pass) { 34 | // look up user by username 35 | $user = $this->users->fetch($this->users->where('username', '=', $user)); 36 | 37 | if(null !== $user) { 38 | // check password hash 39 | if(password_verify($pass, $user->password)) { 40 | $this->session->regenerate(true); 41 | $this->session->put('user', $user->id); 42 | return true; 43 | } 44 | } 45 | 46 | return false; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/Anchor/Controllers/Article.php: -------------------------------------------------------------------------------- 1 | getParams(); 16 | $id = $params[0]; 17 | 18 | if($article = $this->posts->find($id)) { 19 | $uri = $this->uri->to($this->pages->posts()->uri() . '/' . $article->uri()); 20 | 21 | return $this->response->setStatusCode(302)->setHeader('location', $uri); 22 | } 23 | 24 | throw new HttpNotFound('Post ID not found'); 25 | } 26 | 27 | public function view($request, $route) { 28 | $page = $this->pages->posts(); 29 | 30 | $params = $route->getParams(); 31 | $slug = $params[0]; 32 | 33 | $article = $this->posts->fetch($this->posts->where('slug', '=', $slug)); 34 | 35 | if($article) { 36 | $this->registry->put('article', $article); 37 | $this->registry->put('page', $page); 38 | 39 | return $this->renderTemplate('article', $article->slug); 40 | } 41 | 42 | throw new HttpNotFound('Post not found'); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /views/posts/create.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Latest posts

5 | 15 |
16 | 17 | open(); ?> 18 | 19 | 20 | 21 |
22 |
23 |

getElement('title')->getHtml(); ?>

24 |

getElement('save')->getHtml(); ?>

25 | Custom Fields 26 |
27 | 28 |

getElement('markdown')->getHtml(); ?>

29 |
30 | 31 |
32 | getElementsExcept(array('title', 'markdown', 'save')) as $field): ?> 33 |


34 | getHtml(); ?>

35 | 36 |
37 | 38 | close(); ?> -------------------------------------------------------------------------------- /routes/themes.php: -------------------------------------------------------------------------------- 1 | 'auth'), function() { 4 | 5 | /* 6 | List all themes 7 | */ 8 | Route::get('admin/extend/themes', function($page = 1) { 9 | $vars['messages'] = Notify::read(); 10 | $vars['token'] = Csrf::token(); 11 | 12 | $vars['themes'] = Themes::all(); 13 | 14 | return View::create('extend/themes/index', $vars) 15 | ->partial('nav', 'extend/nav') 16 | ->partial('header', 'partials/header') 17 | ->partial('footer', 'partials/footer'); 18 | }); 19 | 20 | /* 21 | theme overview 22 | */ 23 | Route::get('admin/extend/themes/(:any)', function($slug) { 24 | $vars['messages'] = Notify::read(); 25 | $vars['token'] = Csrf::token(); 26 | 27 | return View::create('extend/themes/overview', $vars) 28 | ->partial('nav', 'extend/nav') 29 | ->partial('header', 'partials/header') 30 | ->partial('footer', 'partials/footer'); 31 | }); 32 | 33 | /* 34 | theme install 35 | */ 36 | Route::get('admin/extend/themes/(:any)/install', function($slug) { 37 | return Response::redirect('admin/extend/themes'); 38 | }); 39 | 40 | /* 41 | theme uninstall 42 | */ 43 | Route::get('admin/extend/themes/(:any)/uninstall', function($slug) { 44 | return Response::redirect('admin/extend/themes'); 45 | }); 46 | 47 | }); -------------------------------------------------------------------------------- /src/Anchor/Services/Date.php: -------------------------------------------------------------------------------- 1 | tz = $tz; 38 | $this->format = $format; 39 | } 40 | 41 | /** 42 | * Format a date from the database as UTC to users current timezone 43 | * 44 | * @param string 45 | */ 46 | public function format($date, $format = null) { 47 | $date = new DateTime($date, new DateTimeZone('UTC')); 48 | $date->setTimezone($this->tz); 49 | 50 | return $date->format($format ?: $this->format); 51 | } 52 | 53 | /** 54 | * Format a date from the users current timezone to the database as UTC 55 | * 56 | * @param string 57 | */ 58 | public function mysql($date) { 59 | $date = new DateTime($date, $this->tz); 60 | $date->setTimezone(new DateTimeZone('UTC')); 61 | 62 | return $date->format('Y-m-d H:i:s'); 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /src/Anchor/Models/Post.php: -------------------------------------------------------------------------------- 1 | slug; 35 | } 36 | 37 | public function content() { 38 | return $this->html; 39 | } 40 | 41 | public function setCategory($category) { 42 | $this->categoryModel = $category; 43 | } 44 | 45 | public function getCategory() { 46 | return $this->categoryModel; 47 | } 48 | 49 | public function setAuthor($user) { 50 | $this->userModel = $user; 51 | } 52 | 53 | public function getAuthor() { 54 | return $this->userModel; 55 | } 56 | 57 | public function getValidationRules(Validator $validator) { 58 | $validator->addRule('title', function($value, &$message) { 59 | if('' === $value) { 60 | $message = 'Please enter a title'; 61 | return false; 62 | } 63 | 64 | return true; 65 | }); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /src/Anchor/Services/Assets.php: -------------------------------------------------------------------------------- 1 | lessc = $lessc; 19 | } 20 | 21 | public function copy($src, $dest) { 22 | foreach(new FilesystemIterator($src, FilesystemIterator::SKIP_DOTS) as $fileinfo) { 23 | $fn = $fileinfo->getFilename(); 24 | 25 | if($fileinfo->isFile()) { 26 | copy($fileinfo->getPathname(), $dest . '/' . $fileinfo->getFilename()); 27 | } 28 | elseif($fileinfo->isDir()) { 29 | if( ! is_dir($dest.'/'.$fn)) mkdir($dest.'/'.$fn); 30 | 31 | $this->copy($fileinfo->getPathname(), $dest.'/'.$fn); 32 | } 33 | } 34 | } 35 | 36 | public function compile($src) { 37 | foreach(new FilesystemIterator($src, FilesystemIterator::SKIP_DOTS) as $fileinfo) { 38 | if($fileinfo->isFile()) { 39 | $ext = pathinfo($fileinfo->getPathname(), PATHINFO_EXTENSION); 40 | 41 | if($ext == 'less') { 42 | $this->lessc->checkedCompile($fileinfo->getPathname(), 43 | $fileinfo->getPath() . '/' . $fileinfo->getBasename('.less') . '.css'); 44 | } 45 | } 46 | elseif($fileinfo->isDir()) { 47 | $this->compile($fileinfo->getPathname()); 48 | } 49 | } 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/Anchor/Services/Messages.php: -------------------------------------------------------------------------------- 1 | {message}

'; 17 | 18 | public function __construct(SessionInterface $session) { 19 | $this->session = $session; 20 | } 21 | 22 | public function __call($method, $args) { 23 | $this->add($method, $args[0]); 24 | } 25 | 26 | public function setFormat($format) { 27 | $thi->format = $format; 28 | } 29 | 30 | public function add($type, $message) { 31 | $messages = $this->session->get('messages'); 32 | 33 | if( ! is_array($message)) { 34 | $message = array($message); 35 | } 36 | 37 | if( ! isset($messages[$type])) { 38 | $messages[$type] = array(); 39 | } 40 | 41 | $messages[$type] = array_merge($messages[$type], $message); 42 | 43 | $this->session->put('messages', $messages); 44 | } 45 | 46 | public function render($format = null) { 47 | $messages = $this->session->get('messages', array()); 48 | $html = ''; 49 | 50 | foreach($messages as $type => $group) { 51 | foreach($group as $message) { 52 | $html .= str_replace(array('{type}', '{message}'), array($type, $message), $this->format); 53 | } 54 | } 55 | 56 | $this->session->remove('messages'); 57 | 58 | return $html; 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/Anchor/Forms/Fields/Field.php: -------------------------------------------------------------------------------- 1 | name = $name; 24 | $this->options = $options; 25 | $this->attr = $attr; 26 | } 27 | 28 | protected function getAttrString(array $options) { 29 | $attr = array(); 30 | 31 | foreach($options as $key => $value) { 32 | $attr[] = $key.'="'.$value.'"'; 33 | } 34 | 35 | return implode(' ', $attr); 36 | } 37 | 38 | abstract public function getHtml(); 39 | 40 | public function getName() { 41 | return $this->name; 42 | } 43 | 44 | public function setForm($form) { 45 | return $this->form = $form; 46 | } 47 | 48 | public function getOption($name, $default = '') { 49 | return isset($this->options[$name]) ? $this->options[$name] : $default; 50 | } 51 | 52 | public function getLabel() { 53 | return $this->getOption('label', $this->name); 54 | } 55 | 56 | public function getValue($default = '') { 57 | return $this->form->getValue($this->name, $default); 58 | } 59 | 60 | public function setValue($value) { 61 | return $this->form->setValue($this->name, $value); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /functions/pages.php: -------------------------------------------------------------------------------- 1 | get('page'); 12 | } 13 | 14 | /** 15 | * Returns the page ID 16 | * 17 | * @return string 18 | */ 19 | function page_id() { 20 | return page()->id; 21 | } 22 | 23 | /** 24 | * Returns the page url (including nested pages) 25 | * 26 | * @return string 27 | */ 28 | function page_url() { 29 | global $app; 30 | 31 | return $app['uri']->to(page()->uri()); 32 | } 33 | 34 | /** 35 | * Returns the page slug 36 | * 37 | * @return string 38 | */ 39 | function page_slug() { 40 | return page()->slug; 41 | } 42 | 43 | /** 44 | * Returns the page name (short title to be used in menus) 45 | * 46 | * @return string 47 | */ 48 | function page_name() { 49 | return page()->name; 50 | } 51 | 52 | /** 53 | * Returns the page title 54 | * 55 | * @param string 56 | * @return string 57 | */ 58 | function page_title() { 59 | return page()->title; 60 | } 61 | 62 | /** 63 | * Returns the page content 64 | * 65 | * @return string 66 | */ 67 | function page_content() { 68 | return page()->content(); 69 | } 70 | 71 | /** 72 | * Returns the page status (published, draft, archived) 73 | * 74 | * @return string 75 | */ 76 | function page_status() { 77 | return page()->status; 78 | } 79 | 80 | /** 81 | * Returns the value of a custom field for a page 82 | * 83 | * @param string 84 | * @param mixed 85 | * @return string 86 | */ 87 | function page_custom_field($key, $default = '') { 88 | return; 89 | } -------------------------------------------------------------------------------- /functions/posts.php: -------------------------------------------------------------------------------- 1 | 0; 10 | } 11 | 12 | /** 13 | * Returns true while there are still items in the array. 14 | * 15 | * Updates the current article object in the Registry on each call. 16 | * 17 | * @return bool 18 | */ 19 | function posts() { 20 | global $app; 21 | 22 | return $app['posts']->loop(function($post) use($app) { 23 | $app['registry']->put('article', $post); 24 | }); 25 | } 26 | 27 | /** 28 | * Returns a html link to the next page of posts 29 | * 30 | * @return string 31 | */ 32 | function posts_next($text = 'Next →', $default = '') { 33 | return; 34 | } 35 | 36 | /** 37 | * Returns a html link to the previous page of posts 38 | * 39 | * @return string 40 | */ 41 | function posts_prev($text = '← Previous', $default = '') { 42 | return; 43 | } 44 | 45 | /** 46 | * Returns the total of published posts 47 | * 48 | * @return string 49 | */ 50 | function total_posts() { 51 | global $app; 52 | 53 | return $app['posts']->count(); 54 | } 55 | 56 | /** 57 | * Returns true if there is more posts than the posts per page causing 58 | * pagination to be generated 59 | * 60 | * @return bool 61 | */ 62 | function has_pagination() { 63 | return; 64 | } 65 | 66 | /** 67 | * Returns the number of posts per page, if the total number of posts is less 68 | * than the number of posts per page value then the total posts is returned 69 | * 70 | * @return string 71 | */ 72 | function posts_per_page() { 73 | return; 74 | } -------------------------------------------------------------------------------- /routes/pages.php: -------------------------------------------------------------------------------- 1 | add(new Route('admin/pages/:id/edit', [ 9 | 'conditions' => array($auth, $csrf), 10 | 'requirements' => array('method' => 'GET'), 11 | 'controller' => array($app['adminPagesController'], 'edit') 12 | ])); 13 | 14 | $app['router']->add(new Route('admin/pages/:id/update', [ 15 | 'conditions' => array($auth, $csrf), 16 | 'requirements' => array('method' => 'POST'), 17 | 'controller' => array($app['adminPagesController'], 'update') 18 | ])); 19 | 20 | /* 21 | * Create post 22 | */ 23 | $app['router']->add(new Route('admin/pages/create', array( 24 | 'conditions' => array($auth, $csrf), 25 | 'requirements' => array('method' => 'GET'), 26 | 'controller' => array($app['adminPagesController'], 'create') 27 | ))); 28 | 29 | $app['router']->add(new Route('admin/pages/save', array( 30 | 'conditions' => array($auth, $csrf), 31 | 'requirements' => array('method' => 'POST'), 32 | 'controller' => array($app['adminPagesController'], 'store') 33 | ))); 34 | 35 | /* 36 | * Delete post 37 | */ 38 | $app['router']->add(new Route('admin/pages/:id/delete', array( 39 | 'conditions' => array($auth, $csrf), 40 | 'requirements' => array('method' => 'POST'), 41 | 'controller' => array($app['adminPagesController'], 'destroy') 42 | ))); 43 | 44 | /* 45 | * List all pages and paginate through them 46 | */ 47 | $app['router']->add(new Route('admin/pages', array( 48 | 'conditions' => array($auth, $csrf), 49 | 'requirements' => array('method' => 'GET'), 50 | 'controller' => array($app['adminPagesController'], 'index') 51 | ))); -------------------------------------------------------------------------------- /functions/search.php: -------------------------------------------------------------------------------- 1 | guest()) { 8 | $app['messages']->warning('Invalid Session'); 9 | 10 | return $app['response']->redirect($app['uri']->to('admin/login')); 11 | } 12 | }); 13 | 14 | $csrf = new Condition(function() use($app) { 15 | if($app['input']->has('token')) { 16 | if( ! $app['csrf']->verify($app['input']->get('token'))) { 17 | $app['messages']->warning('Invalid Token'); 18 | 19 | return $app['response']->redirect($app['uri']->to('admin/login')); 20 | } 21 | } 22 | }); 23 | 24 | /** 25 | * Admin routing 26 | */ 27 | $app['router']->add(new Route('admin', [ 28 | 'controller' => function() use($app) { 29 | $uri = $app['auth']->guest() ? 'admin/login' : 'admin/posts'; 30 | 31 | return $app['response']->redirect($app['uri']->to($uri)); 32 | } 33 | ])); 34 | 35 | /* 36 | * Log in 37 | */ 38 | $app['router']->add(new Route('admin/login', [ 39 | 'conditions' => [$csrf], 40 | 'requirements' => ['method' => 'GET'], 41 | 'controller' => array($app['adminUsersController'], 'login') 42 | ])); 43 | 44 | $app['router']->add(new Route('admin/login/attempt', [ 45 | 'conditions' => [$csrf], 46 | 'requirements' => ['method' => 'POST'], 47 | 'controller' => array($app['adminUsersController'], 'attempt') 48 | ])); 49 | 50 | /* 51 | * Log out 52 | */ 53 | $app['router']->add(new Route('admin/logout', [ 54 | 'controller' => function() use($app) { 55 | $app['auth']->logout(); 56 | 57 | return $app['response']->redirect($app['uri']->to('admin/login')); 58 | } 59 | ])); -------------------------------------------------------------------------------- /routes/posts.php: -------------------------------------------------------------------------------- 1 | add(new Route('admin/posts/:id/edit', array( 9 | 'conditions' => array($auth, $csrf), 10 | 'requirements' => array('method' => 'GET'), 11 | 'controller' => array($app['adminPostsController'], 'edit') 12 | ))); 13 | 14 | $app['router']->add(new Route('admin/posts/:id/update', array( 15 | 'conditions' => array($auth, $csrf), 16 | 'requirements' => array('method' => 'POST'), 17 | 'controller' => array($app['adminPostsController'], 'update') 18 | ))); 19 | 20 | /* 21 | * Create post 22 | */ 23 | $app['router']->add(new Route('admin/posts/create', array( 24 | 'conditions' => array($auth, $csrf), 25 | 'requirements' => array('method' => 'GET'), 26 | 'controller' => array($app['adminPostsController'], 'create') 27 | ))); 28 | 29 | $app['router']->add(new Route('admin/posts/store', array( 30 | 'conditions' => array($auth, $csrf), 31 | 'requirements' => array('method' => 'POST'), 32 | 'controller' => array($app['adminPostsController'], 'store') 33 | ))); 34 | 35 | /* 36 | * Delete post 37 | */ 38 | $app['router']->add(new Route('admin/posts/:id/delete', array( 39 | 'conditions' => array($auth, $csrf), 40 | 'requirements' => array('method' => 'POST'), 41 | 'controller' => array($app['adminPostsController'], 'destroy') 42 | ))); 43 | 44 | /* 45 | * List all posts and paginate through them 46 | */ 47 | $app['router']->add(new Route('admin/posts', array( 48 | 'conditions' => array($auth, $csrf), 49 | 'requirements' => array('method' => 'GET'), 50 | 'controller' => array($app['adminPostsController'], 'index') 51 | ))); -------------------------------------------------------------------------------- /functions/old/posts.php: -------------------------------------------------------------------------------- 1 | 0; 12 | } 13 | 14 | /** 15 | * Returns true while there are still items in the array. 16 | * 17 | * Updates the current article object in the Registry on each call. 18 | * 19 | * @return bool 20 | */ 21 | function posts() { 22 | global $app; 23 | 24 | return $app['posts']->loop(function($post) use($app) { 25 | $app['registry']->put('article', $post); 26 | }); 27 | } 28 | 29 | /** 30 | * Returns a html link to the next page of posts 31 | * 32 | * @return string 33 | */ 34 | function posts_next($text = 'Next →', $default = '') { 35 | return; 36 | } 37 | 38 | /** 39 | * Returns a html link to the previous page of posts 40 | * 41 | * @return string 42 | */ 43 | function posts_prev($text = '← Previous', $default = '') { 44 | return; 45 | } 46 | 47 | /** 48 | * Returns the total of published posts 49 | * 50 | * @return string 51 | */ 52 | function total_posts() { 53 | global $app; 54 | 55 | return $app['posts']->count(); 56 | } 57 | 58 | /** 59 | * Returns true if there is more posts than the posts per page causing 60 | * pagination to be generated 61 | * 62 | * @return bool 63 | */ 64 | function has_pagination() { 65 | return; 66 | } 67 | 68 | /** 69 | * Returns the number of posts per page, if the total number of posts is less 70 | * than the number of posts per page value then the total posts is returned 71 | * 72 | * @return string 73 | */ 74 | function posts_per_page() { 75 | return; 76 | } -------------------------------------------------------------------------------- /functions/old/search.php: -------------------------------------------------------------------------------- 1 | viewpath; 20 | } 21 | 22 | public function setViewPath($path) { 23 | $this->viewpath = realpath($path); 24 | } 25 | 26 | protected function getView($template, array $vars = array()) { 27 | $view = new View($this->getViewPath() . '/' . ltrim($template, '/'), $vars); 28 | $view->setHelper('lang', $this->lang); 29 | $view->setHelper('uri', $this->uri); 30 | 31 | return $view; 32 | } 33 | 34 | protected function getLayout(array $vars = array()) { 35 | return $this->getView('layout.phtml', $vars); 36 | } 37 | 38 | protected function getPartial($template, array $vars = array()) { 39 | return $this->getView('partials/' . $template, $vars); 40 | } 41 | 42 | protected function getCommonView($template, array $vars = array()) { 43 | if( ! isset($vars['title'])) { 44 | $vars['title'] = 'Untitled'; 45 | } 46 | 47 | if( ! isset($vars['class'])) { 48 | $vars['class'] = 'default'; 49 | } 50 | 51 | $menu = $this->getPartial('menu.phtml'); 52 | $menu->assign('nav', $this->nav); 53 | 54 | $main = $this->getView($template, $vars); 55 | $main->nest('menu', $menu); 56 | 57 | return $this->getLayout($vars)->nest('body', $main); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /functions/categories.php: -------------------------------------------------------------------------------- 1 | has('category')) { 33 | return $app['registry']->get('category'); 34 | } 35 | 36 | if($article = article()) { 37 | return $article->getCategory(); 38 | } 39 | } 40 | 41 | /** 42 | * Returns the category ID 43 | * 44 | * @return string 45 | */ 46 | function category_id() { 47 | return category()->id; 48 | } 49 | 50 | /** 51 | * Returns the category title 52 | * 53 | * @return string 54 | */ 55 | function category_title() { 56 | return category()->title; 57 | } 58 | 59 | /** 60 | * Returns the category slug 61 | * 62 | * @return string 63 | */ 64 | function category_slug() { 65 | return category()->slug; 66 | } 67 | 68 | /** 69 | * Returns the category description 70 | * 71 | * @return string 72 | */ 73 | function category_description() { 74 | return category()->description; 75 | } 76 | 77 | /** 78 | * Returns the category url 79 | * 80 | * @return string 81 | */ 82 | function category_url() { 83 | return full_url(page_slug().'/'.category_slug()); 84 | } 85 | 86 | /** 87 | * Returns the number of published posts in the current category 88 | * 89 | * @return string 90 | */ 91 | function category_count() { 92 | return category()->total_posts; 93 | } -------------------------------------------------------------------------------- /functions/old/categories.php: -------------------------------------------------------------------------------- 1 | has('category')) { 33 | return $app['registry']->get('category'); 34 | } 35 | 36 | if($article = article()) { 37 | return $article->category; 38 | } 39 | } 40 | 41 | /** 42 | * Returns the category ID 43 | * 44 | * @return string 45 | */ 46 | function category_id() { 47 | return category()->id; 48 | } 49 | 50 | /** 51 | * Returns the category title 52 | * 53 | * @return string 54 | */ 55 | function category_title() { 56 | return category()->title; 57 | } 58 | 59 | /** 60 | * Returns the category slug 61 | * 62 | * @return string 63 | */ 64 | function category_slug() { 65 | return category()->slug; 66 | } 67 | 68 | /** 69 | * Returns the category description 70 | * 71 | * @return string 72 | */ 73 | function category_description() { 74 | return category()->description; 75 | } 76 | 77 | /** 78 | * Returns the category url 79 | * 80 | * @return string 81 | */ 82 | function category_url() { 83 | return full_url(page_slug().'/'.category_slug()); 84 | } 85 | 86 | /** 87 | * Returns the number of published posts in the current category 88 | * 89 | * @return string 90 | */ 91 | function category_count() { 92 | return category()->total_posts; 93 | } -------------------------------------------------------------------------------- /src/Anchor/Forms/Post.php: -------------------------------------------------------------------------------- 1 | append(new Text('title', 20 | array( 21 | 'label' => 'Title' 22 | ), array( 23 | 'placeholder' => 'Title' 24 | ) 25 | )); 26 | 27 | $this->append(new Text('slug', 28 | array( 29 | 'label' => 'Slug' 30 | ), array( 31 | 'placeholder' => 'Slug' 32 | ) 33 | )); 34 | 35 | $this->append(new Textarea('markdown', 36 | array( 37 | 'label' => 'Markdown' 38 | ), array( 39 | 'spell' => 'off', 40 | 'placeholder' => 'Your pearls of wisdom ...' 41 | ) 42 | )); 43 | 44 | $this->append(new Text('created', 45 | array( 46 | 'label' => 'Created', 47 | 'default' => date('Y-m-d H:i:s') 48 | ) 49 | )); 50 | 51 | $this->append(new Select('status', 52 | array( 53 | 'label' => 'Status', 54 | 'options' => array_combine( 55 | array('published', 'draft', 'archived'), 56 | array('Published', 'Draft', 'Archived') 57 | ), 58 | ) 59 | )); 60 | 61 | $this->append(new Select('category', 62 | array( 63 | 'label' => 'Status', 64 | 'options' => array('Empty'), 65 | ) 66 | )); 67 | 68 | $this->append(new Select('comments', 69 | array( 70 | 'label' => 'Allow Comments', 71 | 'options' => array_combine( 72 | array(0, 1), 73 | array('Yes', 'No') 74 | ), 75 | ) 76 | )); 77 | 78 | $this->append(new Button('save', 79 | array( 80 | 'label' => 'Save Changes' 81 | ) 82 | )); 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /functions/old/pages.php: -------------------------------------------------------------------------------- 1 | get('page'); 12 | } 13 | 14 | /** 15 | * Returns the page ID 16 | * 17 | * @return string 18 | */ 19 | function page_id() { 20 | return page()->id; 21 | } 22 | 23 | /** 24 | * Returns the page url (including nested pages) 25 | * 26 | * @return string 27 | */ 28 | function page_url() { 29 | global $app; 30 | 31 | return $app['uri']->to(page()->uri()); 32 | } 33 | 34 | /** 35 | * Returns the page slug 36 | * 37 | * @return string 38 | */ 39 | function page_slug() { 40 | return page()->slug; 41 | } 42 | 43 | /** 44 | * Returns the page name (short title to be used in menus) 45 | * 46 | * @return string 47 | */ 48 | function page_name() { 49 | return page()->name; 50 | } 51 | 52 | /** 53 | * Returns the page title 54 | * 55 | * @param string 56 | * @return string 57 | */ 58 | function page_title() { 59 | return page()->title; 60 | } 61 | 62 | /** 63 | * Alias page content 64 | * 65 | * @return string 66 | */ 67 | function page_html() { 68 | return page_content(); 69 | } 70 | 71 | /** 72 | * Alias page content 73 | * 74 | * @return string 75 | */ 76 | function page_markdown() { 77 | return page_content(); 78 | } 79 | 80 | /** 81 | * Returns the page content 82 | * 83 | * @return string 84 | */ 85 | function page_content() { 86 | return page()->content(); 87 | } 88 | 89 | /** 90 | * Returns the page status (published, draft, archived) 91 | * 92 | * @return string 93 | */ 94 | function page_status() { 95 | return; 96 | } 97 | 98 | /** 99 | * Returns the value of a custom field for a page 100 | * 101 | * @param string 102 | * @param mixed 103 | * @return string 104 | */ 105 | function page_custom_field($key, $default = '') { 106 | return; 107 | } -------------------------------------------------------------------------------- /routes/plugins.php: -------------------------------------------------------------------------------- 1 | 'auth'), function() { 4 | 5 | /* 6 | List all plugins 7 | */ 8 | Route::get('admin/extend/plugins', function($page = 1) { 9 | $vars['messages'] = Notify::read(); 10 | $vars['token'] = Csrf::token(); 11 | 12 | $vars['plugins'] = Plugin::available(); 13 | 14 | return View::create('extend/plugins/index', $vars) 15 | ->partial('header', 'partials/header') 16 | ->partial('footer', 'partials/footer'); 17 | }); 18 | 19 | /* 20 | Plugin overview 21 | */ 22 | Route::get('admin/extend/plugins/(:any)', function($slug) { 23 | $vars['messages'] = Notify::read(); 24 | $vars['token'] = Csrf::token(); 25 | 26 | $vars['info'] = Plugin::about($slug); 27 | $vars['plugin'] = Plugin::where('path', '=', $slug)->fetch(); 28 | 29 | $action = ($vars['plugin']) ? '/uninstall' : '/install'; 30 | $vars['url'] = 'admin/extend/plugins/' . $vars['info']['path'] . '/' . $action; 31 | 32 | return View::create('extend/plugins/overview', $vars) 33 | ->partial('header', 'partials/header') 34 | ->partial('footer', 'partials/footer'); 35 | }); 36 | 37 | /* 38 | Plugin install 39 | */ 40 | Route::get('admin/extend/plugins/(:any)/install', function($slug) { 41 | $about = Plugin::about($slug); 42 | 43 | $plugin = Plugin::create($about); 44 | 45 | // run the plugin installer 46 | $plugin->instance()->install(); 47 | 48 | Notify::success(__('plugins.installed', $plugin->name)); 49 | 50 | return Response::redirect('admin/extend/plugins'); 51 | }); 52 | 53 | /* 54 | Plugin uninstall 55 | */ 56 | Route::get('admin/extend/plugins/(:any)/uninstall', function($slug) { 57 | $plugin = Plugin::where('path', '=', $slug)->fetch(); 58 | 59 | // run the plugin uninstaller 60 | $plugin->instance()->uninstall(); 61 | 62 | Notify::notice(__('plugins.uninstalled', $plugin->name)); 63 | 64 | // remove from the database 65 | $plugin->delete(); 66 | 67 | return Response::redirect('admin/extend/plugins'); 68 | }); 69 | 70 | }); -------------------------------------------------------------------------------- /src/Anchor/Controllers/Admin/Users.php: -------------------------------------------------------------------------------- 1 | users->all(); 17 | 18 | $vars['messages'] = $this->messages->render(); 19 | $vars['token'] = $this->csrf->token(); 20 | 21 | return $this->getCommonView('users/index.phtml', $vars)->render(); 22 | } 23 | 24 | public function login() { 25 | // redirect valid sessions 26 | if( ! $this->auth->guest()) { 27 | return $this->response->redirect($this->uri->to('admin/posts')); 28 | } 29 | 30 | $form = new LoginForm; 31 | $form->setAttr('method', 'post'); 32 | $form->setAttr('action', $this->uri->to('admin/login/attempt')); 33 | 34 | $form->setValue('token', $this->csrf->token()); 35 | 36 | if($this->session->has('_prev_input')) { 37 | $form->setValues($this->session->get('_prev_input')); 38 | $this->session->remove('_prev_input'); 39 | } 40 | 41 | $vars['messages'] = $this->messages->render(); 42 | $vars['title'] = 'Login'; 43 | $vars['class'] = 'login'; 44 | $vars['form'] = $form; 45 | 46 | return $this->getCommonView('login.phtml', $vars)->render(); 47 | } 48 | 49 | public function attempt() { 50 | $attempt = $this->auth->attempt( 51 | $this->input->filter('user', '', FILTER_SANITIZE_STRING), 52 | $this->input->get('pass') 53 | ); 54 | 55 | if( ! $attempt) { 56 | $this->messages->error('Invalid Login Details'); 57 | 58 | $this->session->put('_prev_input', array( 59 | 'user' => $this->input->filter('user', '', FILTER_SANITIZE_STRING) 60 | )); 61 | 62 | return $this->response->redirect($this->uri->to('admin/login')); 63 | } 64 | 65 | return $this->response->redirect($this->uri->to('admin/posts')); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /routes/metadata.php: -------------------------------------------------------------------------------- 1 | 'auth'), function() { 4 | 5 | /* 6 | List Metadata 7 | */ 8 | Route::get('admin/extend/metadata', function() { 9 | $vars['messages'] = Notify::read(); 10 | $vars['token'] = Csrf::token(); 11 | 12 | $vars['meta'] = Config::get('meta'); 13 | $vars['pages'] = Page::dropdown(); 14 | $vars['themes'] = Themes::all(); 15 | 16 | return View::create('extend/metadata/edit', $vars) 17 | ->partial('header', 'partials/header') 18 | ->partial('footer', 'partials/footer'); 19 | }); 20 | 21 | /* 22 | Update Metadata 23 | */ 24 | Route::post('admin/extend/metadata', function() { 25 | $input = Input::get(array('sitename', 'description', 'home_page', 'posts_page', 26 | 'posts_per_page', 'admin_posts_per_page', 'auto_published_comments', 'theme', 'comment_notifications', 'comment_moderation_keys')); 27 | 28 | $validator = new Validator($input); 29 | 30 | $validator->check('sitename') 31 | ->is_max(3, __('metadata.sitename_missing')); 32 | 33 | $validator->check('description') 34 | ->is_max(3, __('metadata.sitedescription_missing')); 35 | 36 | $validator->check('posts_per_page') 37 | ->is_regex('#^[0-9]+$#', __('metadata.missing_posts_per_page', 'Please enter a number for posts per page')); 38 | 39 | if($errors = $validator->errors()) { 40 | Input::flash(); 41 | 42 | Notify::error($errors); 43 | 44 | return Response::redirect('admin/extend/metadata'); 45 | } 46 | 47 | // convert double quotes so we dont break html 48 | $input['sitename'] = htmlspecialchars($input['sitename'], ENT_COMPAT, Config::app('encoding'), false); 49 | $input['description'] = htmlspecialchars($input['description'], ENT_COMPAT, Config::app('encoding'), false); 50 | 51 | foreach($input as $key => $value) { 52 | Query::table('meta')->where('key', '=', $key)->update(array('value' => $value)); 53 | } 54 | 55 | Notify::success(__('metadata.updated')); 56 | 57 | return Response::redirect('admin/extend/metadata'); 58 | }); 59 | 60 | }); 61 | -------------------------------------------------------------------------------- /functions/menus.php: -------------------------------------------------------------------------------- 1 | loop(function($page) use($app) { 23 | $app['registry']->put('item', $page); 24 | }); 25 | } 26 | 27 | /** 28 | * Returns the menu_item 29 | * 30 | * @return string 31 | */ 32 | function menu_item() { 33 | global $app; 34 | 35 | return $app['registry']->get('item'); 36 | } 37 | 38 | /** 39 | * Returns the menu_item ID 40 | * 41 | * @return string 42 | */ 43 | function menu_id() { 44 | return menu_item()->id; 45 | } 46 | 47 | /** 48 | * Returns the menu_item url 49 | * 50 | * @return string 51 | */ 52 | function menu_url() { 53 | global $app; 54 | 55 | return $app['uri']->to(menu_item()->uri()); 56 | } 57 | 58 | /** 59 | * Returns the menu_item relative url (slug and parent slugs) 60 | * 61 | * @return string 62 | */ 63 | function menu_relative_url() { 64 | return menu_url(); 65 | } 66 | 67 | /** 68 | * Returns the menu_item name (short title) 69 | * 70 | * @return string 71 | */ 72 | function menu_name() { 73 | return menu_item()->name; 74 | } 75 | 76 | /** 77 | * Returns the menu_item title 78 | * 79 | * @return string 80 | */ 81 | function menu_title() { 82 | return menu_item()->title; 83 | } 84 | 85 | /** 86 | * Returns true if the current slug matches the menu_item slug 87 | * 88 | * @return bool 89 | */ 90 | function menu_active() { 91 | return; 92 | } 93 | 94 | /** 95 | * Returns the menu_item parent ID 96 | * 97 | * @return string 98 | */ 99 | function menu_parent() { 100 | return; 101 | } 102 | 103 | /** 104 | * Renders a unodered list as a menu including any sub menus 105 | * 106 | * @param array array('parent' => 0, 'class' => '') 107 | * @return string 108 | */ 109 | function menu_render($params = array()) { 110 | return; 111 | } -------------------------------------------------------------------------------- /functions/old/menus.php: -------------------------------------------------------------------------------- 1 | loop(function($page) use($app) { 23 | $app['registry']->put('item', $page); 24 | }); 25 | } 26 | 27 | /** 28 | * Returns the menu_item 29 | * 30 | * @return string 31 | */ 32 | function menu_item() { 33 | global $app; 34 | 35 | return $app['registry']->get('item'); 36 | } 37 | 38 | /** 39 | * Returns the menu_item ID 40 | * 41 | * @return string 42 | */ 43 | function menu_id() { 44 | return menu_item()->id; 45 | } 46 | 47 | /** 48 | * Returns the menu_item url 49 | * 50 | * @return string 51 | */ 52 | function menu_url() { 53 | global $app; 54 | 55 | return $app['uri']->to(menu_item()->uri()); 56 | } 57 | 58 | /** 59 | * Returns the menu_item relative url (slug and parent slugs) 60 | * 61 | * @return string 62 | */ 63 | function menu_relative_url() { 64 | return menu_url(); 65 | } 66 | 67 | /** 68 | * Returns the menu_item name (short title) 69 | * 70 | * @return string 71 | */ 72 | function menu_name() { 73 | return menu_item()->name; 74 | } 75 | 76 | /** 77 | * Returns the menu_item title 78 | * 79 | * @return string 80 | */ 81 | function menu_title() { 82 | return menu_item()->title; 83 | } 84 | 85 | /** 86 | * Returns true if the current slug matches the menu_item slug 87 | * 88 | * @return bool 89 | */ 90 | function menu_active() { 91 | return; 92 | } 93 | 94 | /** 95 | * Returns the menu_item parent ID 96 | * 97 | * @return string 98 | */ 99 | function menu_parent() { 100 | return; 101 | } 102 | 103 | /** 104 | * Renders a unodered list as a menu including any sub menus 105 | * 106 | * @param array array('parent' => 0, 'class' => '') 107 | * @return string 108 | */ 109 | function menu_render($params = array()) { 110 | return; 111 | } -------------------------------------------------------------------------------- /src/Anchor/Controllers/Frontend.php: -------------------------------------------------------------------------------- 1 | request->getUri(), '/'), 1); 19 | } 20 | 21 | protected function getCurrentPage() { 22 | if($this->request->getUri() == '/') { 23 | return $this->pages->home(); 24 | } 25 | 26 | $slug = $this->getSlug(); 27 | $query = $this->pages->where('slug', '=', $slug); 28 | 29 | if($page = $this->pages->fetch($query)) { 30 | return $page; 31 | } 32 | 33 | throw new HttpNotFound('Page not found'); 34 | } 35 | 36 | protected function getTemplate($name, $slug = '') { 37 | if(strlen($slug) and $this->templates->exists($name . '-' . $slug)) { 38 | return $this->templates->find($name . '-' . $slug); 39 | } 40 | 41 | if($this->templates->exists($name)) { 42 | return $this->templates->find($name); 43 | } 44 | 45 | throw new ErrorException('Template not found'); 46 | } 47 | 48 | protected function getLayout($name) { 49 | if($this->templates->exists('layout-' . $name)) { 50 | return $this->templates->find('layout-' . $name); 51 | } 52 | 53 | if($this->templates->exists('layout')) { 54 | return $this->templates->find('layout'); 55 | } 56 | } 57 | 58 | protected function renderTemplate($name, $slug = '', $vars = array()) { 59 | // custom template 60 | $template = $this->getTemplate($name, $slug); 61 | 62 | // use layout wrapper 63 | if($layout = $this->getLayout($name)) { 64 | $view = new View($layout, $vars); 65 | $view->nest('body', new View($template, $vars)); 66 | } 67 | // normal template 68 | else { 69 | $view = new View($template, $vars); 70 | } 71 | 72 | return $view->render(); 73 | } 74 | 75 | public function notFound($title = 'Not Found') { 76 | $page = $this->pages->home(); 77 | $this->registry->put('page', $page); 78 | 79 | $html = $this->renderTemplate('404', '', array('message' => $title)); 80 | 81 | return $this->response->setStatusCode(404)->setBody($html); 82 | } 83 | 84 | } -------------------------------------------------------------------------------- /functions/helpers.php: -------------------------------------------------------------------------------- 1 | to($url); 13 | } 14 | 15 | /** 16 | * Returns a uri relative to the current theme 17 | * 18 | * @param string 19 | * @return string 20 | */ 21 | function theme_url($file = '') { 22 | global $app; 23 | 24 | $theme = $app['meta']->get('theme'); 25 | return $app['uri']->to('themes/'.$theme.'/'.$file); 26 | } 27 | 28 | /** 29 | * Include a theme file is the file exists and readable 30 | * 31 | * Returns true if the file was included 32 | * 33 | * @param string 34 | * @return bool 35 | */ 36 | function theme_include($file) { 37 | global $app; 38 | 39 | $theme = $app['meta']->get('theme'); 40 | $path = 'themes/'.$theme.'/'.$file; 41 | 42 | if(is_file($path)) { 43 | return require $path; 44 | } 45 | } 46 | 47 | /** 48 | * Returns true if the current page ID match the home page ID 49 | * 50 | * @return bool 51 | */ 52 | function is_homepage() { 53 | global $app; 54 | 55 | return $app['pages']->home()->id == page_id(); 56 | } 57 | 58 | /** 59 | * Returns true if the current page ID match the posts listing page ID 60 | * 61 | * @return bool 62 | */ 63 | function is_postspage() { 64 | global $app; 65 | 66 | return $app['pages']->posts()->id == page_id(); 67 | } 68 | 69 | /** 70 | * Returns true if a article object has been set in the Registry 71 | * 72 | * @return bool 73 | */ 74 | function is_article() { 75 | global $app; 76 | 77 | return $app['registry']->has('article'); 78 | } 79 | 80 | /** 81 | * Returns true if a post_category object has been set in the Registry 82 | * 83 | * @return bool 84 | */ 85 | function is_category() { 86 | global $app; 87 | 88 | return $app['registry']->has('category'); 89 | } 90 | 91 | /** 92 | * Returns true if a page object has been set in the Registry 93 | * 94 | * @return bool 95 | */ 96 | function is_page() { 97 | global $app; 98 | 99 | return $app['registry']->has('page'); 100 | } 101 | 102 | /** 103 | * Gettext fallback 104 | * 105 | * @return string 106 | */ 107 | if( ! function_exists('_')) { 108 | function _($text) { 109 | return $text; 110 | } 111 | } -------------------------------------------------------------------------------- /src/Anchor/Mappers/Posts.php: -------------------------------------------------------------------------------- 1 | query() 34 | ->where('id', '>', $post->id) 35 | ->where('status', '=', 'published'); 36 | 37 | return $this->fetch($query); 38 | } 39 | 40 | /** 41 | * Returns the previous post 42 | * 43 | * @param object Post 44 | * @return object/null 45 | */ 46 | public function previous(Post $post) { 47 | $query = $this->query() 48 | ->where('id', '<', $post->id) 49 | ->where('status', '=', 'published') 50 | ->order('id', 'desc'); 51 | 52 | return $this->fetch($query); 53 | } 54 | 55 | /** 56 | * Creates a new Post object 57 | * 58 | * @param object 59 | */ 60 | public function create($row) { 61 | $post = new Post($row); 62 | 63 | $categories = new Categories($this->query); 64 | 65 | if($category = $categories->find($post->category)) { 66 | $post->setCategory($category); 67 | } 68 | else { 69 | $post->setCategory($categories->fetch()); 70 | } 71 | 72 | //$comments = new Comments($this->query); 73 | //$post->total_comments = $comments->where('status', '=', 'published')->count(); 74 | 75 | $users = new Users($this->query); 76 | $post->setAuthor($users->find($post->author)); 77 | 78 | return $post; 79 | } 80 | 81 | /** 82 | * Fetch a buffered array of published posts 83 | * 84 | * @return object ArrayObject 85 | */ 86 | public function published() { 87 | return $this->all($this->query() 88 | ->where('status', '=', 'published') 89 | ->order('created', 'desc')); 90 | } 91 | 92 | /** 93 | * Fetch a buffered array of latest posts 94 | * 95 | * @return object ArrayObject 96 | */ 97 | public function latest() { 98 | return $this->all($this->query() 99 | ->order('created', 'desc')); 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /routes/site.php: -------------------------------------------------------------------------------- 1 | home()->id == $app['pages']->posts()->id) ? 'posts': 'page'; 5 | 6 | /** 7 | * The Default page 8 | */ 9 | $default = new Ship\Routing\Route('/'); 10 | //$default->setController(array($app[$controller.'Controller'], 'index')); 11 | $default->setController(function() use($app) { 12 | return $app['response']->redirect($app['uri']->to($app['pages']->home()->uri()), 301); 13 | }); 14 | $app['router']->add($default); 15 | 16 | /** 17 | * The Home page 18 | */ 19 | $home = new Ship\Routing\Route($app['pages']->home()->uri()); 20 | $home->setController(array($app[$controller.'Controller'], 'index')); 21 | $app['router']->add($home); 22 | 23 | /** 24 | * Listing page 25 | */ 26 | $posts = new Ship\Routing\Route($app['pages']->posts()->uri()); 27 | $posts->setController(array($app['postsController'], 'index')); 28 | $app['router']->add($posts); 29 | 30 | /** 31 | * List posts by category 32 | */ 33 | $category = new Ship\Routing\Route($app['pages']->posts()->uri() . '/category/:any'); 34 | $category->setController(array($app['postsController'], 'category')); 35 | $app['router']->add($category); 36 | 37 | /** 38 | * Rss feed 39 | */ 40 | $rss = new Ship\Routing\Route('feeds/rss'); 41 | $rss->setController(array($app['feedController'], 'rss')); 42 | $app['router']->add($rss); 43 | 44 | /** 45 | * Json feed 46 | */ 47 | $json = new Ship\Routing\Route('feeds/json'); 48 | $json->setController(array($app['feedController'], 'json')); 49 | $app['router']->add($json); 50 | 51 | /** 52 | * Redirect by article ID 53 | */ 54 | $redirect = new Ship\Routing\Route('[0-9]+'); 55 | $redirect->setController(array($app['articleController'], 'redirect')); 56 | $app['router']->add($redirect); 57 | 58 | /** 59 | * View article 60 | */ 61 | $article = new Ship\Routing\Route($app['pages']->posts()->uri() . '/:any'); 62 | $article->setController(array($app['articleController'], 'view')); 63 | $app['router']->add($article); 64 | 65 | /** 66 | * Post a comment 67 | */ 68 | $comment = new Ship\Routing\Route($app['pages']->posts()->uri() . '/:any'); 69 | $comment->setRequirement('method', 'POST')->setController(array($app['articleController'], 'comment')); 70 | $app['router']->add($comment); 71 | 72 | /** 73 | * Search 74 | */ 75 | $search = new Ship\Routing\Route('search'); 76 | $search->setController(array($app['pageController'], 'search')); 77 | $app['router']->add($search); 78 | 79 | /** 80 | * View pages 81 | */ 82 | $page = new Ship\Routing\Route(':any'); 83 | $page->setController(array($app['pageController'], 'index')); 84 | $app['router']->add($page); -------------------------------------------------------------------------------- /functions/articles.php: -------------------------------------------------------------------------------- 1 | get('article'); 12 | } 13 | 14 | /** 15 | * Returns the article ID 16 | * 17 | * @return string 18 | */ 19 | function article_id() { 20 | return article()->id; 21 | } 22 | 23 | /** 24 | * Returns the article title 25 | * 26 | * @return string 27 | */ 28 | function article_title() { 29 | return article()->title; 30 | } 31 | 32 | /** 33 | * Returns the article slug 34 | * 35 | * @return string 36 | */ 37 | function article_slug() { 38 | return article()->slug; 39 | } 40 | 41 | /** 42 | * Returns the previous article url 43 | * 44 | * @return string 45 | */ 46 | function article_previous_url() { 47 | global $app; 48 | 49 | $previous = $app['posts']->previous(article()); 50 | 51 | if($previous) { 52 | return full_url(page_slug() . '/' . $previous->uri()); 53 | } 54 | } 55 | 56 | /** 57 | * Returns the next article url 58 | * 59 | * @return string 60 | */ 61 | function article_next_url() { 62 | global $app; 63 | 64 | $next = $app['posts']->next(article()); 65 | 66 | if($next) { 67 | return full_url(page_slug() . '/' . $next->uri()); 68 | } 69 | } 70 | 71 | /** 72 | * Returns the article url 73 | * 74 | * @return string 75 | */ 76 | function article_url() { 77 | return full_url(page_slug() . '/' . article_slug()); 78 | } 79 | 80 | /** 81 | * Returns the article description 82 | * 83 | * @return string 84 | */ 85 | function article_description() { 86 | return article()->description; 87 | } 88 | 89 | /** 90 | * Returns the article content 91 | * 92 | * @return string 93 | */ 94 | function article_content() { 95 | return article()->content(); 96 | } 97 | 98 | /** 99 | * Returns the article created date as a unix time stamp 100 | * 101 | * @return string 102 | */ 103 | function article_time() { 104 | global $app; 105 | 106 | return $app['date']->format(article()->created, 'U'); 107 | } 108 | 109 | /** 110 | * Returns the article created date formatted 111 | * 112 | * @return string 113 | */ 114 | function article_date() { 115 | global $app; 116 | 117 | return $app['date']->format(article()->created); 118 | } 119 | 120 | /** 121 | * Returns the article status (published, draft, archived) 122 | * 123 | * @return string 124 | */ 125 | function article_status() { 126 | return article()->status; 127 | } 128 | 129 | /** 130 | * Returns the value of a custom field for a post (article) 131 | * 132 | * @param string 133 | * @param mixed 134 | * @return string 135 | */ 136 | function article_custom_field($key, $default = '') { 137 | return; 138 | } -------------------------------------------------------------------------------- /public/assets/js/retina.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Retina.js v1.1.0 3 | * 4 | * Copyright 2013 Imulus, LLC 5 | * Released under the MIT license 6 | * 7 | * Retina.js is an open source script that makes it easy to serve 8 | * high-resolution images to devices with retina displays. 9 | */ 10 | (function(){var root=typeof exports=="undefined"?window:exports;var config={check_mime_type:true};root.Retina=Retina;function Retina(){}Retina.configure=function(options){if(options==null)options={};for(var prop in options)config[prop]=options[prop]};Retina.init=function(context){if(context==null)context=root;var existing_onload=context.onload||new Function;context.onload=function(){var images=document.getElementsByTagName("img"),retinaImages=[],i,image;for(i=0;i1)return true;if(root.matchMedia&&root.matchMedia(mediaQuery).matches)return true;return false};root.RetinaImagePath=RetinaImagePath;function RetinaImagePath(path,at_2x_path){this.path=path;if(typeof at_2x_path!=="undefined"&&at_2x_path!==null){this.at_2x_path=at_2x_path;this.perform_check=false}else{this.at_2x_path=path.replace(/\.\w+$/,function(match){return"@2x"+match});this.perform_check=true}}RetinaImagePath.confirmed_paths=[];RetinaImagePath.prototype.is_external=function(){return!!(this.path.match(/^https?\:/i)&&!this.path.match("//"+document.domain))};RetinaImagePath.prototype.check_2x_variant=function(callback){var http,that=this;if(this.is_external()){return callback(false)}else if(!this.perform_check&&typeof this.at_2x_path!=="undefined"&&this.at_2x_path!==null){return callback(true)}else if(this.at_2x_path in RetinaImagePath.confirmed_paths){return callback(true)}else{http=new XMLHttpRequest;http.open("HEAD",this.at_2x_path);http.onreadystatechange=function(){if(http.readyState!=4){return callback(false)}if(http.status>=200&&http.status<=399){if(config.check_mime_type){var type=http.getResponseHeader("Content-Type");if(type==null||!type.match(/^image/i)){return callback(false)}}RetinaImagePath.confirmed_paths.push(that.at_2x_path);return callback(true)}else{return callback(false)}};http.send()}};function RetinaImage(el){this.el=el;this.path=new RetinaImagePath(this.el.getAttribute("src"),this.el.getAttribute("data-at2x"));var that=this;this.path.check_2x_variant(function(hasVariant){if(hasVariant)that.swap()})}root.RetinaImage=RetinaImage;RetinaImage.prototype.swap=function(path){if(typeof path=="undefined")path=this.path.at_2x_path;var that=this;function load(){if(!that.el.complete){setTimeout(load,5)}else{that.el.setAttribute("width",that.el.offsetWidth);that.el.setAttribute("height",that.el.offsetHeight);that.el.setAttribute("src",path)}}load()};if(Retina.isRetina()){Retina.init(root)}})(); -------------------------------------------------------------------------------- /routes/fields.php: -------------------------------------------------------------------------------- 1 | 'auth,csrf'), function() { 4 | 5 | /* 6 | List Fields 7 | */ 8 | Route::get(array('admin/extend/fields', 'admin/extend/fields/(:num)'), function($page = 1) { 9 | $vars['messages'] = Notify::read(); 10 | $vars['token'] = Csrf::token(); 11 | 12 | $perpage = Config::meta('admin_posts_per_page', 6); 13 | $vars['extend'] = Extend::paginate($page, $perpage); 14 | 15 | return View::create('extend/fields/index', $vars) 16 | ->partial('header', 'partials/header') 17 | ->partial('footer', 'partials/footer'); 18 | }); 19 | 20 | /* 21 | Add Field 22 | */ 23 | Route::get('admin/extend/fields/add', function() { 24 | $vars['messages'] = Notify::read(); 25 | $vars['token'] = Csrf::token(); 26 | 27 | return View::create('extend/fields/add', $vars) 28 | ->partial('header', 'partials/header') 29 | ->partial('footer', 'partials/footer'); 30 | }); 31 | 32 | Route::post('admin/extend/fields/add', function() { 33 | $input = Input::get(array('data_type', 'field_type', 'key', 'label', 'attributes')); 34 | 35 | if($errors = Extend::validate($input)) { 36 | Input::flash(); 37 | 38 | Notify::error($errors); 39 | 40 | return Response::redirect('admin/extend/fields/add'); 41 | } 42 | 43 | Extend::create($input); 44 | 45 | Notify::success(__('extend.field_created')); 46 | 47 | return Response::redirect('admin/extend/fields'); 48 | }); 49 | 50 | /* 51 | Edit Field 52 | */ 53 | Route::get('admin/extend/fields/edit/(:num)', function($id) { 54 | $vars['messages'] = Notify::read(); 55 | $vars['token'] = Csrf::token(); 56 | 57 | $extend = Extend::find($id); 58 | 59 | if($extend->attributes) { 60 | $extend->attributes = Json::decode($extend->attributes); 61 | } 62 | 63 | $vars['field'] = $extend; 64 | 65 | return View::create('extend/fields/edit', $vars) 66 | ->partial('header', 'partials/header') 67 | ->partial('footer', 'partials/footer'); 68 | }); 69 | 70 | Route::post('admin/extend/fields/edit/(:num)', function($id) { 71 | $input = Input::get(array('data_type', 'field_type', 'key', 'label', 'attributes')); 72 | 73 | if($errors = Extend::validate($input, $id)) { 74 | Input::flash(); 75 | 76 | Notify::error($errors); 77 | 78 | return Response::redirect('admin/extend/fields/add'); 79 | } 80 | 81 | Extend::update($id, $input); 82 | 83 | Notify::success(__('extend.field_updated')); 84 | 85 | return Response::redirect('admin/extend/fields/edit/' . $id); 86 | }); 87 | 88 | /* 89 | Delete Field 90 | */ 91 | Route::get('admin/extend/fields/delete/(:num)', function($id) { 92 | $field = Extend::find($id); 93 | 94 | Query::table($field->data_type . '_meta')->where('extend', '=', $field->id)->delete(); 95 | 96 | $field->delete(); 97 | 98 | Notify::success(__('extend.field_deleted')); 99 | 100 | return Response::redirect('admin/extend/fields'); 101 | }); 102 | 103 | }); 104 | -------------------------------------------------------------------------------- /functions/comments.php: -------------------------------------------------------------------------------- 1 | input->filter('page', 1, FILTER_SANITIZE_NUMBER_INT); 17 | $offset = ($page - 1) * $perpage; 18 | 19 | // @todo: check for page overflow 20 | // @todo: check if category exists 21 | 22 | $vars['pages'] = $this->pages->all($this->pages->skip($offset)->take($perpage)); 23 | $vars['title'] = 'Pages'; 24 | 25 | $vars['messages'] = $this->messages->render(); 26 | $vars['token'] = $this->csrf->token(); 27 | 28 | return $this->getCommonView('pages/index.phtml', $vars)->render(); 29 | } 30 | 31 | public function create() { 32 | $vars['messages'] = $this->messages->render(); 33 | $vars['token'] = $this->csrf->token(); 34 | 35 | $vars['title'] = 'Create Page'; 36 | $vars['statuses'] = array('published', 'draft', 'archived'); 37 | 38 | return $this->getCommonView('pages/create.phtml', $vars)->render(); 39 | } 40 | 41 | public function store() { 42 | $page = new Page; 43 | 44 | // filter and validate 45 | $values = array(); 46 | 47 | $page->exchangeArray($values); 48 | 49 | $this->pages->save($page); 50 | 51 | return $this->response->redirect($this->uri->to('admin/pages')); 52 | } 53 | 54 | public function show() {} 55 | 56 | public function edit($request, $route) { 57 | // post ID 58 | $params = $route->getParams(); 59 | $id = $params[0]; 60 | 61 | // find post 62 | $page = $this->pages->where('id', '=', $id)->fetch(); 63 | 64 | if(null === $page) { 65 | $this->messages->error('Page not found'); 66 | 67 | return $this->response->redirect($this->uri->to('admin/pages')); 68 | } 69 | 70 | $vars['messages'] = $this->messages->render(); 71 | $vars['token'] = $this->csrf->token(); 72 | 73 | $vars['title'] = 'Editing “' . $page->title . '”'; 74 | $vars['page'] = $page; 75 | $vars['statuses'] = array('published', 'draft', 'archived'); 76 | 77 | return $this->getCommonView('pages/edit.phtml', $vars)->render(); 78 | } 79 | 80 | public function update($request, $route) { 81 | // post ID 82 | $params = $route->getParams(); 83 | $id = $params[0]; 84 | 85 | // find post 86 | $page = $this->pages->where('id', '=', $id)->fetch(); 87 | 88 | if(null === $page) { 89 | $this->messages->error('Page not found'); 90 | 91 | return $this->response->redirect($this->uri->to('admin/pages')); 92 | } 93 | 94 | $this->messages->info('Page updated'); 95 | 96 | return $this->response->redirect($this->uri->to('admin/pages')); 97 | } 98 | 99 | public function destroy() { 100 | // post ID 101 | $params = $route->getParams(); 102 | $id = $params[0]; 103 | 104 | $this->messages->info('Page deleted'); 105 | 106 | return $this->response->redirect($this->uri->to('admin/pages')); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /src/Anchor/Forms/Form.php: -------------------------------------------------------------------------------- 1 | 'POST' 21 | ); 22 | 23 | protected $values = array(); 24 | 25 | protected function getAttrString(array $options) { 26 | $attr = array(); 27 | 28 | foreach($options as $key => $value) { 29 | $attr[] = $key.'="'.$value.'"'; 30 | } 31 | 32 | return implode(' ', $attr); 33 | } 34 | 35 | public function append($field) { 36 | $field->setForm($this); 37 | 38 | $this->fields[$field->getName()] = $field; 39 | } 40 | 41 | public function setAttr($name, $value) { 42 | $this->attr[$name] = $value; 43 | } 44 | 45 | public function getAttr($name, $default = '') { 46 | return isset($this->attr[$name]) ? $this->attr[$name] : $default; 47 | } 48 | 49 | public function getIterator() { 50 | return new ArrayIterator($this->fields); 51 | } 52 | 53 | public function open(array $options = array()) { 54 | $options = array_merge($this->attr, $options); 55 | 56 | if( ! isset($options['accept-charset'])) { 57 | $options['accept-charset'] = 'utf-8'; 58 | } 59 | 60 | return sprintf('
', $this->getAttrString($options)); 61 | } 62 | 63 | public function close() { 64 | return '
'; 65 | } 66 | 67 | public function removeElements() { 68 | $this->fields = array(); 69 | } 70 | 71 | public function getElement($name) { 72 | foreach($this->fields as $field) { 73 | if($field->getName() == $name) { 74 | return $field; 75 | } 76 | } 77 | } 78 | 79 | public function getElements(array $elements) { 80 | $form = clone $this; 81 | $form->removeElements(); 82 | 83 | foreach($this->fields as $field) { 84 | if(in_array($field->getName(), $elements)) { 85 | $form->append($field); 86 | } 87 | } 88 | 89 | return $form; 90 | } 91 | 92 | public function getElementsExcept(array $elements) { 93 | $form = clone $this; 94 | $form->removeElements(); 95 | 96 | foreach($this->fields as $field) { 97 | if( ! in_array($field->getName(), $elements)) { 98 | $form->append($field); 99 | } 100 | } 101 | 102 | return $form; 103 | } 104 | 105 | public function setValues(array $values) { 106 | foreach($values as $key => $value) { 107 | if(isset($this->fields[$key])) { 108 | $this->values[$key] = $value; 109 | } 110 | } 111 | } 112 | 113 | public function getValues() { 114 | return $this->values; 115 | } 116 | 117 | public function setValue($name, $value) { 118 | $this->values[$name] = $value; 119 | } 120 | 121 | public function getValue($name, $default = null) { 122 | return isset($this->values[$name]) ? $this->values[$name] : $default; 123 | } 124 | 125 | public function getMessages() { 126 | return array(array('title' => 'Please enetr a post title')); 127 | } 128 | 129 | } -------------------------------------------------------------------------------- /functions/old/helpers.php: -------------------------------------------------------------------------------- 1 | to($url); 13 | } 14 | 15 | /** 16 | * Returns a uri 17 | * 18 | * @param string 19 | * @return string 20 | */ 21 | function base_url($url = '') { 22 | return full_url($url); 23 | } 24 | 25 | /** 26 | * Returns a uri relative to the current theme 27 | * 28 | * @param string 29 | * @return string 30 | */ 31 | function theme_url($file = '') { 32 | global $app; 33 | 34 | $theme = $app['meta']->get('theme'); 35 | return $app['uri']->to('themes/'.$theme.'/'.$file); 36 | } 37 | 38 | /** 39 | * Include a theme file is the file exists and readable 40 | * 41 | * Returns true if the file was included 42 | * 43 | * @param string 44 | * @return bool 45 | */ 46 | function theme_include($file) { 47 | global $app; 48 | 49 | $theme = $app['meta']->get('theme'); 50 | $path = 'themes/'.$theme.'/'.$file; 51 | 52 | if(is_file($path)) { 53 | return require $path; 54 | } 55 | } 56 | 57 | /** 58 | * Returns a uri relative to anchor admin 59 | * 60 | * @param string 61 | * @return string 62 | */ 63 | function asset_url($extra = '') { 64 | return; 65 | } 66 | 67 | /** 68 | * Returns the current uri 69 | * 70 | * @return string 71 | */ 72 | function current_url() { 73 | return; 74 | } 75 | 76 | /** 77 | * Returns the rss uri 78 | * 79 | * @return string 80 | */ 81 | function rss_url() { 82 | global $app; 83 | 84 | return $app['uri']->to('feeds/rss'); 85 | } 86 | 87 | /** 88 | * Stores a function to be called in other template files 89 | * 90 | * Usage: 91 | * 92 | * 93 | * @param function Closure 94 | * @param string 95 | * @return string 96 | */ 97 | function bind($page, $fn) { 98 | return; 99 | } 100 | 101 | /** 102 | * Invokes a stored function 103 | * 104 | * Usage: 105 | * 106 | * 107 | * @param string 108 | * @return string 109 | */ 110 | function receive($name = '') { 111 | return; 112 | } 113 | 114 | /** 115 | * Returns a CSS class of page types and current uri 116 | * 117 | * @return string 118 | */ 119 | function body_class() { 120 | return; 121 | } 122 | 123 | /** 124 | * Returns true if the current page ID match the home page ID 125 | * 126 | * @return bool 127 | */ 128 | function is_homepage() { 129 | return; 130 | } 131 | 132 | /** 133 | * Returns true if the current page ID match the posts listing page ID 134 | * 135 | * @return bool 136 | */ 137 | function is_postspage() { 138 | return; 139 | } 140 | 141 | /** 142 | * Returns true if a article object has been set in the Registry 143 | * 144 | * @return bool 145 | */ 146 | function is_article() { 147 | global $app; 148 | 149 | return $app['registry']->had('article'); 150 | } 151 | 152 | /** 153 | * Returns true if a post_category object has been set in the Registry 154 | * 155 | * @return bool 156 | */ 157 | function is_category() { 158 | global $app; 159 | 160 | return $app['registry']->had('category'); 161 | } 162 | 163 | /** 164 | * Returns true if a page object has been set in the Registry 165 | * 166 | * @return bool 167 | */ 168 | function is_page() { 169 | global $app; 170 | 171 | return $app['registry']->had('page'); 172 | } -------------------------------------------------------------------------------- /routes/variables.php: -------------------------------------------------------------------------------- 1 | 'auth'), function() { 4 | 5 | /* 6 | List Vars 7 | */ 8 | Route::get('admin/extend/variables', function() { 9 | $vars['messages'] = Notify::read(); 10 | $vars['token'] = Csrf::token(); 11 | 12 | $variables = array(); 13 | 14 | foreach(Query::table('meta')->sort('key')->get() as $meta) { 15 | if(strpos($meta->key, 'custom_') === 0) $variables[] = $meta; 16 | } 17 | 18 | $vars['variables'] = $variables; 19 | 20 | return View::create('extend/variables/index', $vars) 21 | ->partial('header', 'partials/header') 22 | ->partial('footer', 'partials/footer'); 23 | }); 24 | 25 | /* 26 | Add Var 27 | */ 28 | Route::get('admin/extend/variables/add', function() { 29 | $vars['messages'] = Notify::read(); 30 | $vars['token'] = Csrf::token(); 31 | 32 | return View::create('extend/variables/add', $vars) 33 | ->partial('header', 'partials/header') 34 | ->partial('footer', 'partials/footer'); 35 | }); 36 | 37 | Route::post('admin/extend/variables/add', function() { 38 | $input = Input::get(array('key', 'value')); 39 | 40 | $input['key'] = 'custom_' . slug($input['key'], '_'); 41 | 42 | $validator = new Validator($input); 43 | 44 | $validator->add('valid_key', function($str) { 45 | if(strlen($str) > 7) { 46 | return Query::table('meta') 47 | ->where('key', '=', $str) 48 | ->count() == 0; 49 | } 50 | 51 | return true; 52 | }); 53 | 54 | $validator->check('key') 55 | // include prefix length 'custom_' 56 | ->is_max(7, __('extend.name_missing')) 57 | ->is_valid_key(__('extend.name_exists')); 58 | 59 | if($errors = $validator->errors()) { 60 | Input::flash(); 61 | 62 | Notify::error($errors); 63 | 64 | return Response::redirect('admin/extend/variables/add'); 65 | } 66 | 67 | Query::table('meta')->insert($input); 68 | 69 | Notify::success(__('extend.variable_created')); 70 | 71 | return Response::redirect('admin/extend/variables'); 72 | }); 73 | 74 | /* 75 | Edit Var 76 | */ 77 | Route::get('admin/extend/variables/edit/(:any)', function($key) { 78 | $vars['messages'] = Notify::read(); 79 | $vars['token'] = Csrf::token(); 80 | $vars['variable'] = Query::table('meta')->where('key', '=', $key)->fetch(); 81 | 82 | // remove prefix 83 | $vars['variable']->user_key = substr($vars['variable']->key, strlen('custom_')); 84 | 85 | return View::create('extend/variables/edit', $vars) 86 | ->partial('header', 'partials/header') 87 | ->partial('footer', 'partials/footer'); 88 | }); 89 | 90 | Route::post('admin/extend/variables/edit/(:any)', function($key) { 91 | $input = Input::get(array('key', 'value')); 92 | 93 | $input['key'] = 'custom_' . slug($input['key'], '_'); 94 | 95 | $validator = new Validator($input); 96 | 97 | $validator->add('valid_key', function($str) use($key) { 98 | // no change 99 | if($str == $key) return true; 100 | 101 | // check the new key $str is available 102 | return Query::table('meta')->where('key', '=', $str)->count() == 0; 103 | }); 104 | 105 | $validator->check('key') 106 | // include prefix length 'custom_' 107 | ->is_max(7, __('extend.name_missing')) 108 | ->is_valid_key(__('extend.name_exists')); 109 | 110 | if($errors = $validator->errors()) { 111 | Input::flash(); 112 | 113 | Notify::error($errors); 114 | 115 | return Response::redirect('admin/extend/variables/edit/' . $key); 116 | } 117 | 118 | Query::table('meta')->where('key', '=', $key)->update($input); 119 | 120 | Notify::success(__('extend.variable_updated')); 121 | 122 | return Response::redirect('admin/extend/variables'); 123 | }); 124 | 125 | /* 126 | Delete Var 127 | */ 128 | Route::get('admin/extend/variables/delete/(:any)', function($key) { 129 | Query::table('meta')->where('key', '=', $key)->delete(); 130 | 131 | Notify::success(__('extend.variable_deleted')); 132 | 133 | return Response::redirect('admin/extend/variables'); 134 | }); 135 | 136 | }); -------------------------------------------------------------------------------- /routes/comments.php: -------------------------------------------------------------------------------- 1 | 'auth'), function() { 4 | 5 | /* 6 | List Comments 7 | */ 8 | Route::get(array('admin/comments', 'admin/comments/(:num)'), function($page = 1) { 9 | $perpage = Config::meta('posts_per_page'); 10 | 11 | $count = Comment::count(); 12 | $results = Comment::take($perpage)->skip(($page - 1) * $perpage)->sort('date', 'desc')->get(); 13 | 14 | $vars['comments'] = new Paginator($results, $count, $page, $perpage, Uri::to('admin/comments')); 15 | $vars['messages'] = Notify::read(); 16 | 17 | $vars['status'] = 'all'; 18 | $vars['statuses'] = array( 19 | array('url' => '', 'lang' => 'global.all', 'class' => 'active'), 20 | array('url' => 'pending', 'lang' => 'global.pending', 'class' => 'pending'), 21 | array('url' => 'approved', 'lang' => 'global.approved', 'class' => 'approved'), 22 | array('url' => 'spam', 'lang' => 'global.spam', 'class' => 'spam') 23 | ); 24 | 25 | return View::create('comments/index', $vars) 26 | ->partial('header', 'partials/header') 27 | ->partial('footer', 'partials/footer'); 28 | }); 29 | 30 | /* 31 | List Comments by status 32 | */ 33 | Route::get(array( 34 | 'admin/comments/(pending|approved|spam)', 35 | 'admin/comments/(pending|approved|spam)/(:num)'), function($status = '', $page = 1) { 36 | 37 | $query = Comment::begin(); 38 | $perpage = Config::meta('posts_per_page'); 39 | 40 | if(in_array($status, array('pending', 'approved', 'spam'))) { 41 | $query->where('status', '=', $status); 42 | } 43 | 44 | $count = $query->count(); 45 | $results = $query->take($perpage)->skip(($page - 1) * $perpage)->sort('date', 'desc')->get(); 46 | 47 | $vars['comments'] = new Paginator($results, $count, $page, $perpage, Uri::to('admin/comments/' . $status)); 48 | $vars['messages'] = Notify::read(); 49 | 50 | $vars['status'] = $status; 51 | $vars['statuses'] = array( 52 | array('url' => '', 'lang' => 'global.all', 'class' => ''), 53 | array('url' => 'pending', 'lang' => 'global.pending', 'class' => 'pending'), 54 | array('url' => 'approved', 'lang' => 'global.approved', 'class' => 'approved'), 55 | array('url' => 'spam', 'lang' => 'global.spam', 'class' => 'spam') 56 | ); 57 | 58 | return View::create('comments/index', $vars) 59 | ->partial('header', 'partials/header') 60 | ->partial('footer', 'partials/footer'); 61 | }); 62 | 63 | /* 64 | Edit Comment 65 | */ 66 | Route::get('admin/comments/edit/(:num)', function($id) { 67 | $vars['messages'] = Notify::read(); 68 | $vars['token'] = Csrf::token(); 69 | $vars['comment'] = Comment::find($id); 70 | 71 | $vars['statuses'] = array( 72 | 'approved' => __('global.approved'), 73 | 'pending' => __('global.pending'), 74 | 'spam' => __('global.spam') 75 | ); 76 | 77 | return View::create('comments/edit', $vars) 78 | ->partial('header', 'partials/header') 79 | ->partial('footer', 'partials/footer'); 80 | }); 81 | 82 | Route::post('admin/comments/edit/(:num)', function($id) { 83 | $input = Input::get(array('name', 'email', 'text', 'status')); 84 | 85 | $validator = new Validator($input); 86 | 87 | $validator->check('name') 88 | ->is_max(3, __('comments.name_missing')); 89 | 90 | $validator->check('text') 91 | ->is_max(3, __('comments.text_missing')); 92 | 93 | if($errors = $validator->errors()) { 94 | Input::flash(); 95 | 96 | Notify::error($errors); 97 | 98 | return Response::redirect('admin/comments/edit/' . $id); 99 | } 100 | 101 | Comment::update($id, $input); 102 | 103 | Notify::success(__('comments.updated')); 104 | 105 | return Response::redirect('admin/comments/' . $input['status']); 106 | }); 107 | 108 | /* 109 | Delete Comment 110 | */ 111 | Route::get('admin/comments/delete/(:num)', function($id) { 112 | $comment = Comment::find($id); 113 | $status = $comment->status; 114 | 115 | $comment->delete(); 116 | 117 | Notify::success(__('comments.deleted')); 118 | 119 | return Response::redirect('admin/comments/' . $status); 120 | }); 121 | 122 | }); -------------------------------------------------------------------------------- /routes/users.php: -------------------------------------------------------------------------------- 1 | add(new Route('admin/users', array( 9 | 'conditions' => array($auth, $csrf), 10 | 'requirements' => array('method' => 'GET'), 11 | 'controller' => array($app['adminUsersController'], 'index') 12 | ))); 13 | 14 | 15 | 16 | /* 17 | $app['router']->register('GET', 'admin/amnesia', array('before' => 'guest', 'main' => function() { 18 | $vars['messages'] = Notify::read(); 19 | $vars['token'] = Csrf::token(); 20 | 21 | return View::create('users/amnesia', $vars) 22 | ->partial('header', 'partials/header') 23 | ->partial('footer', 'partials/footer'); 24 | })); 25 | 26 | $app['router']->register('POST', 'admin/amnesia', array('before' => 'csrf', 'main' => function() { 27 | $email = Input::get('email'); 28 | 29 | $validator = new Validator(array('email' => $email)); 30 | $query = User::where('email', '=', $email); 31 | 32 | $validator->add('valid', function($email) use($query) { 33 | return $query->count(); 34 | }); 35 | 36 | $validator->check('email') 37 | ->is_email(__('users.email_missing')) 38 | ->is_valid(__('users.email_not_found')); 39 | 40 | if($errors = $validator->errors()) { 41 | Input::flash(); 42 | 43 | Notify::error($errors); 44 | 45 | return Response::redirect('admin/amnesia'); 46 | } 47 | 48 | $user = $query->fetch(); 49 | Session::put('user', $user->id); 50 | 51 | $token = noise(8); 52 | Session::put('token', $token); 53 | 54 | $uri = Uri::full('admin/reset/' . $token); 55 | $subject = __('users.recovery_subject'); 56 | $msg = __('users.recovery_message', $uri); 57 | 58 | mail($user->email, $subject, $msg); 59 | 60 | Notify::success(__('users.recovery_sent')); 61 | 62 | return Response::redirect('admin/login'); 63 | })); 64 | 65 | $app['router']->register('GET', 'admin/reset/(:any)', array('before' => 'guest', 'main' => function($key) { 66 | $vars['messages'] = Notify::read(); 67 | $vars['token'] = Csrf::token(); 68 | $vars['key'] = ($token = Session::get('token')); 69 | 70 | if($token != $key) { 71 | Notify::error(__('users.recovery_expired')); 72 | 73 | return Response::redirect('admin/login'); 74 | } 75 | 76 | return View::create('users/reset', $vars) 77 | ->partial('header', 'partials/header') 78 | ->partial('footer', 'partials/footer'); 79 | })); 80 | 81 | $app['router']->register('POST', 'admin/reset/(:any)', array('before' => 'csrf', 'main' => function($key) { 82 | $password = Input::get('pass'); 83 | $token = Session::get('token'); 84 | $user = Session::get('user'); 85 | 86 | if($token != $key) { 87 | Notify::error(__('users.recovery_expired')); 88 | 89 | return Response::redirect('admin/login'); 90 | } 91 | 92 | $validator = new Validator(array('password' => $password)); 93 | 94 | $validator->check('password') 95 | ->is_max(6, __('users.password_too_short', 6)); 96 | 97 | if($errors = $validator->errors()) { 98 | Input::flash(); 99 | 100 | Notify::error($errors); 101 | 102 | return Response::redirect('admin/reset/' . $key); 103 | } 104 | 105 | User::update($user, array( 106 | 'password' => password_hash($password, PASSWORD_BCRYPT) 107 | )); 108 | 109 | Session::erase('user'); 110 | Session::erase('token'); 111 | 112 | Notify::success(__('users.password_reset')); 113 | 114 | return Response::redirect('admin/login'); 115 | })); 116 | 117 | $app['router']->register('GET', 'admin/upgrade', function() { 118 | $vars['messages'] = Notify::read(); 119 | $vars['token'] = Csrf::token(); 120 | 121 | $version = Config::meta('update_version'); 122 | $url = 'https://github.com/anchorcms/anchor-cms/archive/%s.zip'; 123 | 124 | $vars['version'] = $version; 125 | $vars['url'] = sprintf($url, $version); 126 | 127 | return View::create('upgrade', $vars) 128 | ->partial('header', 'partials/header') 129 | ->partial('footer', 'partials/footer'); 130 | }); 131 | 132 | $app['router']->register('GET', 'admin/extend', array('before' => 'auth', 'main' => function($page = 1) { 133 | $vars['messages'] = Notify::read(); 134 | $vars['token'] = Csrf::token(); 135 | 136 | return View::create('extend/index', $vars) 137 | ->partial('nav', 'extend/nav') 138 | ->partial('header', 'partials/header') 139 | ->partial('footer', 'partials/footer'); 140 | })); 141 | 142 | */ -------------------------------------------------------------------------------- /functions/old/articles.php: -------------------------------------------------------------------------------- 1 | get('article'); 12 | } 13 | 14 | /** 15 | * Returns the article ID 16 | * 17 | * @return string 18 | */ 19 | function article_id() { 20 | return article()->id; 21 | } 22 | 23 | /** 24 | * Returns the article title 25 | * 26 | * @return string 27 | */ 28 | function article_title() { 29 | return article()->title; 30 | } 31 | 32 | /** 33 | * Returns the article slug 34 | * 35 | * @return string 36 | */ 37 | function article_slug() { 38 | return article()->slug; 39 | } 40 | 41 | /** 42 | * Returns the previous article url 43 | * 44 | * @return string 45 | */ 46 | function article_previous_url() { 47 | global $app; 48 | 49 | $previous = $app['posts']->previous(article()); 50 | 51 | if($previous) { 52 | return full_url(page_slug() . '/' . $previous->uri()); 53 | } 54 | } 55 | 56 | /** 57 | * Returns the next article url 58 | * 59 | * @return string 60 | */ 61 | function article_next_url() { 62 | global $app; 63 | 64 | $next = $app['posts']->next(article()); 65 | 66 | if($next) { 67 | return full_url(page_slug() . '/' . $next->uri()); 68 | } 69 | } 70 | 71 | /** 72 | * Returns the article url 73 | * 74 | * @return string 75 | */ 76 | function article_url() { 77 | return full_url(page_slug() . '/' . article_slug()); 78 | } 79 | 80 | /** 81 | * Returns the article description 82 | * 83 | * @return string 84 | */ 85 | function article_description() { 86 | return article()->description; 87 | } 88 | 89 | /** 90 | * Returns the article description or the first n characters on the content 91 | * if there is no description 92 | * 93 | * @param int 94 | * @param string 95 | * @return string 96 | */ 97 | function article_excerpt($word_length = 50, $elips = '...') { 98 | return article_description(); 99 | } 100 | 101 | /** 102 | * Alias article content 103 | * 104 | * @return string 105 | */ 106 | function article_html() { 107 | return article_content(); 108 | } 109 | 110 | /** 111 | * Alias article content 112 | * 113 | * @return string 114 | */ 115 | function article_markdown() { 116 | return article_content(); 117 | } 118 | 119 | /** 120 | * Returns the article content 121 | * 122 | * @return string 123 | */ 124 | function article_content() { 125 | return article()->content(); 126 | } 127 | 128 | /** 129 | * Returns the article css 130 | * 131 | * @return string 132 | */ 133 | function article_css() { 134 | return article_custom_field('css'); 135 | } 136 | 137 | /** 138 | * Returns the article js 139 | * 140 | * @return string 141 | */ 142 | function article_js() { 143 | return article_custom_field('js'); 144 | } 145 | 146 | /** 147 | * Returns the article created date as a unix time stamp 148 | * 149 | * @return string 150 | */ 151 | function article_time() { 152 | global $app; 153 | 154 | return $app['date']->format(article()->created, 'U'); 155 | } 156 | 157 | /** 158 | * Returns the article created date formatted 159 | * 160 | * @return string 161 | */ 162 | function article_date() { 163 | global $app; 164 | 165 | return $app['date']->format(article()->created); 166 | } 167 | 168 | /** 169 | * Returns the article status (published, draft, archived) 170 | * 171 | * @return string 172 | */ 173 | function article_status() { 174 | return article()->status; 175 | } 176 | 177 | /** 178 | * Returns the article category title 179 | * 180 | * @return string 181 | */ 182 | function article_category() { 183 | return category_title(); 184 | } 185 | 186 | /** 187 | * Returns the article category slug 188 | * 189 | * @return string 190 | */ 191 | function article_category_slug() { 192 | return category_slug(); 193 | } 194 | 195 | /** 196 | * Returns the article category url 197 | * 198 | * @return string 199 | */ 200 | function article_category_url() { 201 | return category_url(); 202 | } 203 | 204 | /** 205 | * Returns the article total comments 206 | * 207 | * @return string 208 | */ 209 | function article_total_comments() { 210 | return article()->total_comments; 211 | } 212 | 213 | /** 214 | * Returns the article author username 215 | * 216 | * @return string 217 | */ 218 | function article_author() { 219 | return article()->author->real_name; 220 | } 221 | 222 | /** 223 | * Returns the article author ID (user ID) 224 | * 225 | * @return string 226 | */ 227 | function article_author_id() { 228 | return article()->author->id; 229 | } 230 | 231 | /** 232 | * Returns the article author bio (user bio) 233 | * 234 | * @return string 235 | */ 236 | function article_author_bio() { 237 | return article()->author->bio; 238 | } 239 | 240 | /** 241 | * Returns the value of a custom field for a post (article) 242 | * 243 | * @param string 244 | * @param mixed 245 | * @return string 246 | */ 247 | function article_custom_field($key, $default = '') { 248 | return; 249 | } 250 | 251 | /** 252 | * Returns true if the article contents custom css or js code 253 | * 254 | * @return bool 255 | */ 256 | function customised() { 257 | return article_css() or article_js(); 258 | } -------------------------------------------------------------------------------- /src/Anchor/Controllers/Admin/Posts.php: -------------------------------------------------------------------------------- 1 | input->filter('page', 1, FILTER_SANITIZE_NUMBER_INT); 19 | $category = $this->input->filter('category', 0, FILTER_SANITIZE_NUMBER_INT); 20 | $offset = ($page - 1) * $perpage; 21 | 22 | // @todo: check for page overflow 23 | // @todo: check if category exists 24 | 25 | if($category) { 26 | $vars['posts'] = $this->posts->all( 27 | $this->posts->where('category', '=', $category) 28 | ->order('created', 'desc') 29 | ->skip($offset) 30 | ->take($perpage) 31 | ); 32 | } 33 | else { 34 | $vars['posts'] = $this->posts->all( 35 | $this->posts->order('created', 'desc') 36 | ->skip($offset) 37 | ->take($perpage) 38 | ); 39 | } 40 | 41 | $vars['title'] = 'Posts'; 42 | $vars['categories'] = $this->categories->all(); 43 | 44 | $vars['messages'] = $this->messages->render(); 45 | $vars['token'] = $this->csrf->token(); 46 | 47 | return $this->getCommonView('posts/index.phtml', $vars)->render(); 48 | } 49 | 50 | public function create() { 51 | $post = new PostModel; 52 | 53 | $form = new PostForm; 54 | $form->setAttr('action', $this->uri->to('admin/posts/store')); 55 | $form->setAttr('method', 'POST'); 56 | 57 | $vars['messages'] = $this->messages->render(); 58 | $vars['token'] = $this->csrf->token(); 59 | 60 | $vars['title'] = 'Creating a new post'; 61 | 62 | $vars['form'] = $form; 63 | $vars['post'] = $post; 64 | 65 | $vars['categories'] = $this->categories->all(); 66 | $vars['posts'] = $this->posts->latest(); 67 | 68 | return $this->getCommonView('posts/create.phtml', $vars)->render(); 69 | } 70 | 71 | public function store() { 72 | $post = new PostModel; 73 | $validator = new Validator; 74 | 75 | $post->hydrate($this->input->getArrayCopy()); 76 | 77 | $validator->validate($post); 78 | 79 | if( ! $validator->isValid()) { 80 | //$this->session->flash($this->input->getArrayCopy()); 81 | 82 | $this->messages->add('error', $validator->getMessages()); 83 | 84 | return $this->response->redirect($this->uri->to('admin/posts/create')); 85 | } 86 | 87 | if('' === $post->slug) { 88 | $post->slug = $this->slugify->slugify($post->title); 89 | } 90 | 91 | $post->html = $this->markdown->parse($post->markdown); 92 | 93 | $user = $this->auth->user(); 94 | $post->author = $user->id; 95 | 96 | $this->posts->save($post); 97 | 98 | $this->messages->info('Post created'); 99 | 100 | return $this->response->redirect($this->uri->to('admin/posts/'.$post->id.'/edit')); 101 | } 102 | 103 | public function edit($request, $route) { 104 | // post ID 105 | $params = $route->getParams(); 106 | $id = $params[0]; 107 | 108 | // find post 109 | $post = $this->posts->find($id); 110 | 111 | if(null === $post) { 112 | $this->messages->error('Post not found'); 113 | 114 | return $this->response->redirect($this->uri->to('admin/posts')); 115 | } 116 | 117 | $form = new PostForm; 118 | $form->setAttr('action', $this->uri->to('admin/posts/'.$post->id.'/update')); 119 | $form->setAttr('method', 'POST'); 120 | $form->setValues($post->toArray()); 121 | 122 | $vars['messages'] = $this->messages->render(); 123 | $vars['token'] = $this->csrf->token(); 124 | 125 | $vars['title'] = 'Editing “' . $post->title . '”'; 126 | $vars['post'] = $post; 127 | $vars['categories'] = $this->categories->all(); 128 | $vars['posts'] = $this->posts->latest(); 129 | $vars['form'] = $form; 130 | 131 | return $this->getCommonView('posts/edit.phtml', $vars)->render(); 132 | } 133 | 134 | public function update($request, $route) { 135 | // post ID 136 | $params = $route->getParams(); 137 | $id = $params[0]; 138 | 139 | // find post 140 | $post = $this->posts->find($id); 141 | 142 | if(null === $post) { 143 | $this->messages->error('Post not found'); 144 | 145 | return $this->response->redirect($uri->to('admin/posts')); 146 | } 147 | 148 | // validate form input 149 | $validator = new Validator; 150 | 151 | $post->hydrate($this->input->getArrayCopy()); 152 | 153 | $validator->validate($post); 154 | 155 | if( ! $validator->isValid()) { 156 | //$this->session->flash($this->input->getArrayCopy()); 157 | 158 | $this->messages->add('error', $validator->getMessages()); 159 | 160 | return $this->response->redirect($this->uri->to('admin/posts/'.$post->id.'/edit')); 161 | } 162 | 163 | if('' === $post->slug) { 164 | $post->slug = $this->slugify->slugify($post->title); 165 | } 166 | 167 | $post->html = $this->markdown->parse($post->markdown); 168 | 169 | $user = $this->auth->user(); 170 | $post->author = $user->id; 171 | 172 | $this->posts->save($post); 173 | 174 | $this->messages->info('Post updated'); 175 | 176 | return $this->response->redirect($this->uri->to('admin/posts/'.$post->id.'/edit')); 177 | } 178 | 179 | public function destroy() { 180 | // post ID 181 | $params = $route->getParams(); 182 | $id = $params[0]; 183 | 184 | $this->messages->info('Post deleted'); 185 | 186 | return $this->response->redirect($this->uri->to('admin/posts')); 187 | } 188 | 189 | } -------------------------------------------------------------------------------- /src/Anchor/Providers/ShipServiceProvider.php: -------------------------------------------------------------------------------- 1 | active()); 25 | }; 26 | 27 | $app['pages'] = function($app) { 28 | return new \Anchor\Mappers\Pages($app['query'], $app['meta']); 29 | }; 30 | 31 | $app['posts'] = function($app) { 32 | return new \Anchor\Mappers\Posts($app['query']); 33 | }; 34 | 35 | $app['categories'] = function($app) { 36 | return new \Anchor\Mappers\Categories($app['query']); 37 | }; 38 | 39 | $app['users'] = function($app) { 40 | return new \Anchor\Mappers\Users($app['query']); 41 | }; 42 | 43 | $app['meta'] = function($app) { 44 | return new \Anchor\Mappers\Meta($app['query']); 45 | }; 46 | } 47 | 48 | protected function registerServices(Container $app) { 49 | /** 50 | * Services 51 | */ 52 | $app['auth'] = function($app) { 53 | return new \Anchor\Services\Auth($app['session'], $app['users']); 54 | }; 55 | 56 | $app['date'] = function($app) { 57 | $format = $app['meta']->get('date_format'); 58 | 59 | return new \Anchor\Services\Date($app['timezone'], $format); 60 | }; 61 | 62 | $app['messages'] = function($app) { 63 | return new \Anchor\Services\Messages($app['session']); 64 | }; 65 | 66 | $app['csrf'] = function($app) { 67 | return new \Anchor\Services\Csrf($app['session']); 68 | }; 69 | 70 | $app['registry'] = function() { 71 | return new \Anchor\Services\Registry; 72 | }; 73 | 74 | $app['nav'] = function($app) { 75 | $nav = new \Anchor\Services\Nav($app['uri']); 76 | 77 | $nav->setPrefix('admin')->setActive($app['request']->getUri()); 78 | 79 | $nav->add('Posts', 'posts', 'flaticon feather-1'); 80 | //$nav->add('Comments', 'comments', 'flaticon writing-comment-2'); 81 | $nav->add('Pages', 'pages', 'flaticon multiple-documents-1'); 82 | //$nav->add('Menu', 'menu', 'flaticon menu-list-4'); 83 | $nav->add('Categories', 'categories', 'flaticon tag-1'); 84 | $nav->add('Users', 'users', 'flaticon user-1'); 85 | //$nav->add('Extend', 'extend', 'flaticon cube-1'); 86 | 87 | return $nav; 88 | }; 89 | 90 | $app['lang'] = function($app) { 91 | $lang = $app['config']->get('app.language', 'en_GB'); 92 | 93 | return new \Anchor\Services\I18n($lang); 94 | }; 95 | } 96 | 97 | protected function registerControllers(Container $app) { 98 | /** 99 | * Controllers 100 | */ 101 | $app['articleController'] = function($app) { 102 | $controller = new \Anchor\Controllers\Article; 103 | 104 | $controller->setContainer($app); 105 | 106 | return $controller; 107 | }; 108 | 109 | $app['pageController'] = function($app) { 110 | $controller = new \Anchor\Controllers\Page; 111 | 112 | $controller->setContainer($app); 113 | 114 | return $controller; 115 | }; 116 | 117 | $app['postsController'] = function($app) { 118 | $controller = new \Anchor\Controllers\Posts; 119 | 120 | $controller->setContainer($app); 121 | 122 | return $controller; 123 | }; 124 | 125 | $app['feedController'] = function($app) { 126 | $controller = new \Anchor\Controllers\Feeds; 127 | 128 | $controller->setContainer($app); 129 | 130 | return $controller; 131 | }; 132 | 133 | /** 134 | * Admin Controllers 135 | */ 136 | $app['anchorViewsPath'] = function() { 137 | return __DIR__ . '/../../../views'; 138 | }; 139 | 140 | $app['adminPostsController'] = function($app) { 141 | $controller = new \Anchor\Controllers\Admin\Posts; 142 | 143 | $controller->setContainer($app); 144 | 145 | $controller->setViewPath($app['anchorViewsPath']); 146 | 147 | return $controller; 148 | }; 149 | 150 | $app['adminPagesController'] = function($app) { 151 | $controller = new \Anchor\Controllers\Admin\Pages; 152 | 153 | $controller->setContainer($app); 154 | 155 | $controller->setViewPath($app['anchorViewsPath']); 156 | 157 | return $controller; 158 | }; 159 | 160 | $app['adminCategoriesController'] = function($app) { 161 | $controller = new \Anchor\Controllers\Admin\Categories; 162 | 163 | $controller->setContainer($app); 164 | 165 | $controller->setViewPath($app['anchorViewsPath']); 166 | 167 | return $controller; 168 | }; 169 | 170 | $app['adminUsersController'] = function($app) { 171 | $controller = new \Anchor\Controllers\Admin\Users; 172 | 173 | $controller->setContainer($app); 174 | 175 | $controller->setViewPath($app['anchorViewsPath']); 176 | 177 | return $controller; 178 | }; 179 | } 180 | 181 | public function register(Container $app) { 182 | 183 | $app['events']->attach('beforeDispatch', function() { 184 | // load theme functions before processing the request 185 | foreach(glob(__DIR__ . '/../../../functions/*.php') as $functions) { 186 | require $functions; 187 | } 188 | }); 189 | 190 | $app['error']->handler(function(\Anchor\Exceptions\HttpNotFound $e) { 191 | echo '404'; 192 | }); 193 | 194 | $app['admin'] = strpos($app['request']->getUri(), '/admin') === 0; 195 | 196 | $this->registerMappers($app); 197 | $this->registerServices($app); 198 | $this->registerControllers($app); 199 | 200 | require __DIR__ . '/../../../routes.php'; 201 | } 202 | 203 | } -------------------------------------------------------------------------------- /functions/depreciated.php: -------------------------------------------------------------------------------- 1 | uri(); 36 | } 37 | 38 | /** 39 | * Returns the rss uri 40 | * 41 | * @return string 42 | */ 43 | function rss_url() { 44 | global $app; 45 | 46 | return $app['uri']->to('feeds/rss'); 47 | } 48 | 49 | /** 50 | * Stores a function to be called in other template files 51 | * 52 | * Usage: 53 | * 54 | * 55 | * @param function Closure 56 | * @param string 57 | * @return string 58 | */ 59 | function bind($page, $fn) { 60 | return; 61 | } 62 | 63 | /** 64 | * Invokes a stored function 65 | * 66 | * Usage: 67 | * 68 | * 69 | * @param string 70 | * @return string 71 | */ 72 | function receive($name = '') { 73 | return; 74 | } 75 | 76 | /** 77 | * Returns a CSS class of page types and current uri 78 | * 79 | * @return string 80 | */ 81 | function body_class() { 82 | return; 83 | } 84 | 85 | /** 86 | * Sets a theme value in the config class 87 | * 88 | * @param string 89 | * @param string 90 | */ 91 | function set_theme_options($options, $value = null) { 92 | return; 93 | } 94 | 95 | /** 96 | * Retrieves a theme value in the config class 97 | * 98 | * @param string 99 | * @param string 100 | * @return string 101 | */ 102 | function theme_option($option, $default = '') { 103 | return; 104 | } 105 | 106 | /** 107 | * Returns the article description or the first n characters on the content 108 | * if there is no description 109 | * 110 | * @param int 111 | * @param string 112 | * @return string 113 | */ 114 | function article_excerpt($word_length = 50, $elips = '...') { 115 | return article_description(); 116 | } 117 | 118 | 119 | /** 120 | * Returns the article category title 121 | * 122 | * @return string 123 | */ 124 | function article_category() { 125 | return category_title(); 126 | } 127 | 128 | /** 129 | * Returns the article category slug 130 | * 131 | * @return string 132 | */ 133 | function article_category_slug() { 134 | return category_slug(); 135 | } 136 | 137 | /** 138 | * Returns the article category url 139 | * 140 | * @return string 141 | */ 142 | function article_category_url() { 143 | return category_url(); 144 | } 145 | 146 | /** 147 | * Returns the article total comments 148 | * 149 | * @return string 150 | */ 151 | function article_total_comments() { 152 | return article()->total_comments; 153 | } 154 | 155 | /** 156 | * Returns the article author username 157 | * 158 | * @return string 159 | */ 160 | function article_author() { 161 | return article()->author->real_name; 162 | } 163 | 164 | /** 165 | * Returns the article author ID (user ID) 166 | * 167 | * @return string 168 | */ 169 | function article_author_id() { 170 | return article()->author->id; 171 | } 172 | 173 | /** 174 | * Returns the article author bio (user bio) 175 | * 176 | * @return string 177 | */ 178 | function article_author_bio() { 179 | return article()->author->bio; 180 | } 181 | 182 | /** 183 | * Alias article content 184 | * 185 | * @return string 186 | */ 187 | function article_html() { 188 | return article_content(); 189 | } 190 | 191 | /** 192 | * Alias article content 193 | * 194 | * @return string 195 | */ 196 | function article_markdown() { 197 | return article_content(); 198 | } 199 | 200 | /** 201 | * Returns the article css 202 | * 203 | * @return string 204 | */ 205 | function article_css() { 206 | return article_custom_field('css'); 207 | } 208 | 209 | /** 210 | * Returns the article js 211 | * 212 | * @return string 213 | */ 214 | function article_js() { 215 | return article_custom_field('js'); 216 | } 217 | 218 | /** 219 | * Returns true if the article contents custom css or js code 220 | * 221 | * @return bool 222 | */ 223 | function customised() { 224 | return article_css() or article_js(); 225 | } 226 | 227 | /** 228 | * Returns the site name 229 | * 230 | * @see Extend > Site Metadata > Site Name 231 | * @return string 232 | */ 233 | function site_name() { 234 | return site_meta('sitename'); 235 | } 236 | 237 | /** 238 | * Returns the site description 239 | * 240 | * @see Extend > Site Metadata > Site Description 241 | * @return string 242 | */ 243 | function site_description() { 244 | return site_meta('description'); 245 | } 246 | 247 | 248 | /** 249 | * Alias page content 250 | * 251 | * @return string 252 | */ 253 | function page_html() { 254 | return page_content(); 255 | } 256 | 257 | /** 258 | * Alias page content 259 | * 260 | * @return string 261 | */ 262 | function page_markdown() { 263 | return page_content(); 264 | } 265 | 266 | /** 267 | * Returns true if the current user is logged in. 268 | * 269 | * Sets the current user in the Registry 270 | * 271 | * @return bool 272 | */ 273 | function user_authed() { 274 | return; 275 | } 276 | 277 | /** 278 | * Returns the authed user ID 279 | * 280 | * @return string 281 | */ 282 | function user_authed_id() { 283 | return; 284 | } 285 | 286 | /** 287 | * Returns the authed user name 288 | * 289 | * @return string 290 | */ 291 | function user_authed_name() { 292 | return; 293 | } 294 | 295 | 296 | /** 297 | * Returns the authed user email 298 | * 299 | * @return string 300 | */ 301 | function user_authed_email() { 302 | return; 303 | } 304 | 305 | /** 306 | * Returns the authed user role (administrator, editor, user) 307 | * 308 | * @return string 309 | */ 310 | function user_authed_role() { 311 | return; 312 | } 313 | 314 | /** 315 | * Returns the authed user real name (display name) 316 | * 317 | * @return string 318 | */ 319 | function user_authed_real_name() { 320 | return; 321 | } -------------------------------------------------------------------------------- /public/assets/css/styles.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Define variables 3 | */ 4 | 5 | // Main colours 6 | @primary: #448ed8; 7 | @secondary: #35cc6e; 8 | @negative: #cc5635; 9 | 10 | // Grey body colours 11 | @light: #f5f7f9; 12 | @dark: #272a2d; 13 | @mid: #787e85; 14 | 15 | // Type choices 16 | @sans: "Fira Sans OT", sans-serif; 17 | @serif: Scala, Garamond, serif; 18 | @monospace: "Fira Mono OT", "Anonymous Pro", "Source Code Pro", monospace; 19 | 20 | /** 21 | * File imports 22 | */ 23 | @import 'icons/stroke.css'; 24 | @import 'animations.css'; 25 | 26 | /** 27 | * Main reset 28 | */ 29 | * { 30 | margin: 0; 31 | padding: 0; 32 | 33 | -webkit-box-sizing: border-box; 34 | -moz-box-sizing: border-box; 35 | box-sizing: border-box; 36 | 37 | -webkit-font-smoothing: antialiased; 38 | 39 | text-rendering: optimizeLegibility; 40 | } 41 | 42 | body, input, textarea, button { 43 | font: 16px/24px @sans; 44 | } 45 | textarea { 46 | font-family: @serif; 47 | } 48 | 49 | h1 { 50 | font-weight: 100; 51 | font-size: 32px; 52 | line-height: 50px; 53 | 54 | color: darken(@mid, 10%); 55 | } 56 | h2 { 57 | font-weight: 300; 58 | font-size: 32px; 59 | line-height: 40px; 60 | } 61 | 62 | body, html { 63 | overflow: hidden; 64 | height: 100%; 65 | } 66 | body { 67 | background: #fff; 68 | color: @mid; 69 | } 70 | 71 | input, textarea, .warning, .error, button, .btn { 72 | padding: 14px 16px 12px; 73 | border-radius: 5px; 74 | } 75 | 76 | input, textarea { 77 | border: none; 78 | outline: none; 79 | 80 | color: darken(@mid, 15%); 81 | } 82 | ::-webkit-input-placeholder { 83 | color: lighten(@mid, 25%); 84 | } 85 | ::placeholder { 86 | color: lighten(@mid, 25%); 87 | } 88 | 89 | button, .btn { 90 | display: inline-block; 91 | border: none; 92 | 93 | background: @primary; 94 | color: #fff; 95 | 96 | text-decoration: none; 97 | 98 | cursor: pointer; 99 | outline: none; 100 | 101 | &:hover, &:active { 102 | background: darken(@primary, 10%); 103 | } 104 | 105 | &:active { 106 | box-shadow: inset 0 2px 2px rgba(0,0,0,.2); 107 | } 108 | 109 | &.subdued { 110 | background: darken(@light, 15%); 111 | 112 | &:hover { 113 | background: darken(@light, 20%); 114 | } 115 | } 116 | 117 | &.secondary, &[type=submit] { 118 | background: @secondary; 119 | 120 | &:hover { 121 | background: darken(@secondary, 5%); 122 | } 123 | } 124 | } 125 | 126 | .warning, .error { 127 | display: block; 128 | position: relative; 129 | 130 | background: @negative; 131 | color: #fff; 132 | 133 | font-size: 15px; 134 | } 135 | .warning:after, .error:after { 136 | content: ''; 137 | position: absolute; 138 | left: 16px; 139 | bottom: -5px; 140 | 141 | display: block; 142 | 143 | border-left: 8px solid transparent; 144 | border-right: 8px solid transparent; 145 | border-top: 6px solid @negative; 146 | } 147 | 148 | 149 | /** 150 | * Login page 151 | */ 152 | body.login { 153 | width: 400px; 154 | margin: 0 auto; 155 | 156 | background: @dark; 157 | } 158 | body.login .logo { 159 | display: block; 160 | margin: 0 0 40px; 161 | } 162 | body.login .warning + .logo, body.login .error + .logo { 163 | display: none; 164 | } 165 | body.login form { 166 | position: absolute; 167 | top: 50%; 168 | 169 | width: 400px; 170 | margin-top: -82px; /* Form height */ 171 | } 172 | body.login p { 173 | position: relative; 174 | margin-bottom: 20px; 175 | } 176 | body.login label { 177 | position: absolute; 178 | left: 0; 179 | right: 0; 180 | top: 0; 181 | 182 | display: block; 183 | width: 40px; 184 | height: 100%; 185 | 186 | color: lighten(@dark, 20%); 187 | background: rgba(0,0,0,.1); 188 | 189 | font-size: 0; 190 | text-align: center; 191 | line-height: 65px; /* wut */ 192 | 193 | cursor: pointer; 194 | border-radius: 5px 0 0 5px; 195 | } 196 | body.login label:before { 197 | display: block; 198 | line-height: 50px; 199 | } 200 | body.login input:focus + label { 201 | color: lighten(@dark, 50%); 202 | } 203 | body.login input { 204 | display: block; 205 | width: 100%; 206 | padding-left: 56px; /* 40 + 16 */ 207 | 208 | background: lighten(@dark, 5%); 209 | color: #fff; 210 | } 211 | body.login input:focus { 212 | background: lighten(@dark, 8%); 213 | } 214 | body.login input:focus::-webkit-input-placeholder { 215 | color: lighten(@dark, 33.5%); 216 | } 217 | body.login input::-webkit-input-placeholder { 218 | color: lighten(@dark, 25%); 219 | } 220 | body.login button { 221 | position: relative; 222 | top: 20px; 223 | 224 | width: 100%; 225 | } 226 | 227 | /** 228 | * Main admin 229 | */ 230 | .menu { 231 | position: relative; 232 | float: left; 233 | width: 100px; 234 | height: 100%; 235 | 236 | background: @dark; 237 | box-shadow: inset -1px 0 2px rgba(0,0,0,.25); 238 | } 239 | .menu nav { 240 | position: relative; 241 | } 242 | .menu nav li { 243 | list-style: none; 244 | } 245 | .menu nav a { 246 | display: block; 247 | padding: 25px 0; 248 | 249 | color: lighten(@dark, 15%); 250 | 251 | font-size: 14px; 252 | line-height: 18px; 253 | text-align: center; 254 | text-decoration: none; 255 | 256 | box-shadow: inset 0 -1px 0 rgba(255,255,255,.05); 257 | } 258 | .menu nav a:before { 259 | display: block; 260 | margin-bottom: 8px; 261 | 262 | position: relative; 263 | top: 2px; 264 | } 265 | .menu nav a:hover { 266 | color: @mid; 267 | background: rgba(255,255,255,.02); 268 | } 269 | .menu nav .active a { 270 | color: #fff; 271 | background: @primary; 272 | 273 | box-shadow: inset -1px 0 2px rgba(0,0,0,.1), inset 0 -1px 0 rgba(255,255,255,.08); 274 | } 275 | .menu .bottom { 276 | position: absolute; 277 | bottom: 0; 278 | left: 0; 279 | right: 0; 280 | } 281 | .menu .bottom a { 282 | float: left; 283 | width: 50%; 284 | padding-bottom: 15px; 285 | 286 | font-size: 0; 287 | 288 | box-shadow: inset 0 1px 0 rgba(255,255,255,.06); 289 | } 290 | .menu .bottom a:first-child { 291 | box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 1px 0 0 rgba(255,255,255,.04); 292 | } 293 | 294 | .list { 295 | float: left; 296 | width: 250px; 297 | height: 100%; 298 | 299 | background: darken(@light, 4%); 300 | 301 | box-shadow: inset -1px 0 2px rgba(0,0,0,.05); 302 | } 303 | .list li { 304 | list-style: none; 305 | } 306 | .list .intro { 307 | padding: 34px 30px 33px; 308 | 309 | color: saturate(lighten(@mid, 25%), 7%); 310 | background: rgba(0,0,0,.025); 311 | 312 | font-size: 12px; 313 | font-weight: bold; 314 | text-transform: uppercase; 315 | letter-spacing: 2px; 316 | 317 | border-bottom: 1px solid rgba(0,0,0,.05); 318 | } 319 | .list li a { 320 | display: block; 321 | padding: 15px 30px; 322 | 323 | border-bottom: 1px solid rgba(0,0,0,.05); 324 | 325 | color: darken(@mid, 15%); 326 | text-decoration: none; 327 | } 328 | .list li a:hover { 329 | background: rgba(255,255,255,.3); 330 | } 331 | .list li.active a { 332 | background: #fff; 333 | border-bottom: 1px solid rgba(0,0,0,.1); 334 | } 335 | .list li time, .list li span { 336 | display: block; 337 | 338 | font-size: 12px; 339 | font-weight: normal; 340 | 341 | opacity: .5; 342 | } 343 | 344 | .content { 345 | position: relative; 346 | float: left; 347 | 348 | width: 70%; 349 | width: calc(~"100% - 350px"); 350 | height: 100%; 351 | } 352 | body > form { 353 | height: 100%; 354 | } 355 | .content .markdown { 356 | height: 100%; 357 | height: calc(~"100% - 92px"); 358 | } 359 | .content .markdown textarea { 360 | width: 100%; 361 | height: 100%; 362 | 363 | padding: 30px 40px; 364 | 365 | font-size: 21px; 366 | line-height: 32px; 367 | 368 | resize: none; 369 | } 370 | .content hgroup { 371 | overflow: hidden; 372 | padding: 21px 40px 20px; 373 | 374 | background: @light; 375 | border-bottom: 1px solid darken(@light, 5%); 376 | } 377 | .content hgroup h1 { 378 | float: left; 379 | font-size: 30px; 380 | 381 | position: relative; 382 | 383 | width: 60%; 384 | width: calc(~"100% - 240px"); 385 | 386 | &:after { 387 | content: ''; 388 | position: absolute; 389 | right: 0; 390 | top: 0; 391 | bottom: 0; 392 | 393 | display: block; 394 | width: 40px; 395 | 396 | background-image: linear-gradient(to right, fade(@light, 0%) 0%, @light 100%); 397 | 398 | pointer-events: none; 399 | 400 | opacity: 1; 401 | -webkit-transition: opacity .2s, background .2s; 402 | } 403 | &.focus:after { 404 | opacity: 0; 405 | } 406 | &.focus.long:after { 407 | opacity: 1; 408 | background-image: linear-gradient(to right, fade(darken(@light, 1%), 0%) 0%, darken(@light, 1%) 100%); 409 | } 410 | 411 | input { 412 | display: block; 413 | padding: 0; 414 | width: 100%; 415 | 416 | background: transparent; 417 | 418 | font-size: 30px; 419 | line-height: 50px; 420 | font-weight: 100; 421 | } 422 | } 423 | .content button, .content .btn { 424 | float: right; 425 | padding: 12px 22px 10px; 426 | 427 | position: relative; 428 | top: 4px; 429 | } 430 | .content hgroup .custom-fields { 431 | float: right; 432 | width: 50px; 433 | margin-right: 20px; 434 | 435 | font-size: 0; 436 | line-height: 6px; 437 | text-decoration: none; 438 | 439 | padding: 12px 16px 10px; 440 | } 441 | .content hgroup .custom-fields:before { 442 | position: relative; 443 | top: 3px; 444 | } 445 | .content .top-right { 446 | margin: 21px 40px 0 0; 447 | } 448 | .content .empty-state { 449 | position: absolute; 450 | left: 50%; 451 | top: 50%; 452 | 453 | display: block; 454 | width: 440px; 455 | margin: -38px 0 0 -220px; 456 | 457 | font-size: 15px; 458 | text-align: center; 459 | 460 | color: darken(@light, 15%); 461 | } 462 | .content .empty-state:before { 463 | display: block; 464 | margin-bottom: 20px; 465 | 466 | font-size: 32px; 467 | } 468 | 469 | #opts { 470 | display: none; 471 | } --------------------------------------------------------------------------------