Merge branch 'bluditv2' of github.com:dignajar/bludit into bluditv2
This commit is contained in:
commit
48a4077ebb
|
@ -91,7 +91,7 @@ function checkGet($args)
|
|||
}
|
||||
|
||||
// Bruteforce protection, add IP to blacklist.
|
||||
$Security->addLoginFail();
|
||||
$Security->addToBlacklist();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,27 +8,26 @@
|
|||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
function checkPost($args)
|
||||
function checkLogin($args)
|
||||
{
|
||||
global $Security;
|
||||
global $Login;
|
||||
global $Language;
|
||||
|
||||
if($Security->isBlocked()) {
|
||||
if ($Security->isBlocked()) {
|
||||
Alert::set($Language->g('IP address has been blocked').'<br>'.$Language->g('Try again in a few minutes'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify User sanitize the input
|
||||
if( $Login->verifyUser($_POST['username'], $_POST['password']) ) {
|
||||
if ($Login->verifyUser($_POST['username'], $_POST['password'])) {
|
||||
// Renew the token. This token will be the same inside the session for multiple forms.
|
||||
$Security->generateTokenCSRF();
|
||||
Redirect::page('dashboard');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bruteforce protection, add IP to blacklist.
|
||||
$Security->addLoginFail();
|
||||
// Bruteforce protection, add IP to the blacklist
|
||||
$Security->addToBlacklist();
|
||||
|
||||
// Create alert
|
||||
Alert::set($Language->g('Username or password incorrect'));
|
||||
|
@ -44,9 +43,9 @@ function checkPost($args)
|
|||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||
if ($_SERVER['REQUEST_METHOD']=='POST')
|
||||
{
|
||||
checkPost($_POST);
|
||||
checkLogin($_POST);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
@ -83,7 +83,7 @@ if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
|||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
$allPublishedPages = buildAllpages(false);
|
||||
$allPublishedPages = buildAllpages(true);
|
||||
|
||||
// Homepage select options
|
||||
$homepageOptions = array();
|
||||
|
|
|
@ -217,6 +217,11 @@ div.dashboard-links h4 {
|
|||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#dashboard-hello {
|
||||
background-color: #FBDF6B;
|
||||
padding: 20px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* FORM
|
||||
---------------------------------------------------------------- */
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -18,6 +18,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="<?php echo HTML_PATH_ADMIN_THEME.'css/uikit/progress.almost-flat.min.css?version='.BLUDIT_VERSION ?>">
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo HTML_PATH_ADMIN_THEME.'css/default.css?version='.BLUDIT_VERSION ?>">
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo HTML_PATH_ADMIN_THEME.'css/jquery.datetimepicker.css?version='.BLUDIT_VERSION ?>">
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo DOMAIN_CORE_CSS.'font-awesome/font-awesome.min.css?version='.BLUDIT_VERSION ?>">
|
||||
|
||||
<!-- Javascript -->
|
||||
<script charset="utf-8" src="<?php echo HTML_PATH_CORE_JS.'jquery.min.js?version='.BLUDIT_VERSION ?>"></script>
|
||||
|
@ -144,6 +145,9 @@ $(document).ready(function() {
|
|||
<?php
|
||||
if( Sanitize::pathFile(PATH_ADMIN_VIEWS, $layout['view'].'.php') ) {
|
||||
include(PATH_ADMIN_VIEWS.$layout['view'].'.php');
|
||||
} else {
|
||||
echo '<h1 style="width:100%; text-align:center">Hey!</h1>';
|
||||
echo '<h2 style="width:100%; text-align:center">Have you seen my ball?</h2>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
<!-- CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo HTML_PATH_ADMIN_THEME.'css/uikit/uikit.almost-flat.min.css?version='.BLUDIT_VERSION ?>">
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo HTML_PATH_ADMIN_THEME.'css/login.css?version='.BLUDIT_VERSION ?>">
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo HTML_PATH_CORE_CSS.'font-awesome/font-awesome.min.css?version='.BLUDIT_VERSION ?>">
|
||||
|
||||
<!-- Javascript -->
|
||||
<script charset="utf-8" src="<?php echo HTML_PATH_ADMIN_THEME.'js/jquery.min.js?version='.BLUDIT_VERSION ?>"></script>
|
||||
<script charset="utf-8" src="<?php echo HTML_PATH_CORE_JS.'jquery.min.js?version='.BLUDIT_VERSION ?>"></script>
|
||||
<script charset="utf-8" src="<?php echo HTML_PATH_ADMIN_THEME.'js/uikit/uikit.min.js?version='.BLUDIT_VERSION ?>"></script>
|
||||
|
||||
<!-- Plugins -->
|
||||
|
|
|
@ -148,6 +148,4 @@
|
|||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<form method="post" action="" class="uk-form" autocomplete="off">
|
||||
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php $Security->printTokenCSRF() ?>">
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php echo $Security->getTokenCSRF() ?>">
|
||||
|
||||
<div class="uk-form-row">
|
||||
<input name="email" class="uk-width-1-1 uk-form-large" placeholder="<?php $L->p('Email') ?>" type="text">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<form method="post" action="" class="uk-form" autocomplete="off">
|
||||
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php $Security->printTokenCSRF() ?>">
|
||||
<input type="hidden" id="jstoken" name="tokenCSRF" value="<?php echo $Security->getTokenCSRF() ?>">
|
||||
|
||||
<div class="uk-form-row">
|
||||
<input name="username" class="uk-width-1-1 uk-form-large" placeholder="<?php $L->p('Username') ?>" type="text">
|
||||
|
|
|
@ -50,14 +50,12 @@ else
|
|||
// User not logged.
|
||||
// Slug is login.
|
||||
// Slug is login-email.
|
||||
if($Url->notFound() || !$Login->isLogged() || ($Url->slug()==='login') || ($Url->slug()==='login-email') )
|
||||
{
|
||||
if($Url->notFound() || !$Login->isLogged() || ($Url->slug()==='login') || ($Url->slug()==='login-email') ) {
|
||||
$layout['controller'] = 'login';
|
||||
$layout['view'] = 'login';
|
||||
$layout['template'] = 'login.php';
|
||||
|
||||
if($Url->slug()==='login-email')
|
||||
{
|
||||
if ($Url->slug()==='login-email') {
|
||||
$layout['controller'] = 'login-email';
|
||||
$layout['view'] = 'login-email';
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ define('DB_CATEGORIES', PATH_DATABASES.'categories.php');
|
|||
define('DB_TAGS', PATH_DATABASES.'tags.php');
|
||||
define('DB_SYSLOG', PATH_DATABASES.'syslog.php');
|
||||
define('DB_USERS', PATH_DATABASES.'users.php');
|
||||
define('DB_SECURITY', PATH_DATABASES.'security.php');
|
||||
|
||||
// Log separator
|
||||
define('LOG_SEP', ' | ');
|
||||
|
@ -110,7 +111,7 @@ define('CLI_STATUS', 'published');
|
|||
define('CLI_USERNAME', 'admin');
|
||||
|
||||
// Filename
|
||||
define('FILENAME', 'index.md');
|
||||
define('FILENAME', 'index.txt');
|
||||
|
||||
// Database date format
|
||||
define('DB_DATE_FORMAT', 'Y-m-d H:i:s');
|
||||
|
|
|
@ -100,7 +100,7 @@ if( $dbPages->scheduler() ) {
|
|||
}
|
||||
|
||||
// Generate pages parent tree, only published pages
|
||||
buildPagesByParent(false);
|
||||
//buildPagesByParent(true);
|
||||
|
||||
// Set home page is the user defined one
|
||||
if( $Site->homepage() && $Url->whereAmI()==='home' ) {
|
||||
|
|
|
@ -72,10 +72,9 @@ class dbPages extends dbJSON
|
|||
}
|
||||
|
||||
// Where the data is stored
|
||||
if($options['inFile']) {
|
||||
$dataForFile[$field] = Text::firstCharUp($field).': '.$value;
|
||||
}
|
||||
else {
|
||||
if ($options['inFile']) {
|
||||
$dataForFile[$field] = $this->stylingFieldsForFile($field, $value);
|
||||
} else {
|
||||
// Set type
|
||||
settype($value, gettype($options['value']));
|
||||
|
||||
|
@ -84,7 +83,7 @@ class dbPages extends dbJSON
|
|||
}
|
||||
}
|
||||
|
||||
if( $climode===false ) {
|
||||
if ($climode===false) {
|
||||
// Create the directory
|
||||
if( Filesystem::mkdir(PATH_PAGES.$key, true) === false ) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to create the directory '.PATH_PAGES.$key);
|
||||
|
@ -92,7 +91,7 @@ class dbPages extends dbJSON
|
|||
}
|
||||
|
||||
// Make the index.txt and save the file.
|
||||
$data = implode("\n", $dataForFile);
|
||||
$data = implode(PHP_EOL, $dataForFile);
|
||||
if( file_put_contents(PATH_PAGES.$key.DS.FILENAME, $data) === false ) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to put the content in the file '.FILENAME);
|
||||
return false;
|
||||
|
@ -155,11 +154,9 @@ class dbPages extends dbJSON
|
|||
$value = $options['value'];
|
||||
}
|
||||
|
||||
// Where the data is stored
|
||||
if($options['inFile']) {
|
||||
$dataForFile[$field] = Text::firstCharUp($field).': '.$value;
|
||||
}
|
||||
else {
|
||||
if ($options['inFile']) {
|
||||
$dataForFile[$field] = $this->stylingFieldsForFile($field, $value);
|
||||
} else {
|
||||
// Set type
|
||||
settype($value, gettype($options['value']));
|
||||
|
||||
|
@ -309,7 +306,7 @@ class dbPages extends dbJSON
|
|||
// Returns an array with a list of pages
|
||||
// The database is sorted by date or by position
|
||||
// (int) $pageNumber, the page number
|
||||
// (int) $amountOfItems, amount of items to return
|
||||
// (int) $amountOfItems, amount of items to return, if -1 returns all the items
|
||||
// (boolean) $onlyPublished, TRUE to return only published pages
|
||||
public function getList($pageNumber, $amountOfItems, $onlyPublished=true)
|
||||
{
|
||||
|
@ -322,6 +319,10 @@ class dbPages extends dbJSON
|
|||
// Remove Error page from the list
|
||||
unset($db['error']);
|
||||
|
||||
if($amountOfItems==-1) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
// The first page number is 1, so the real is 0
|
||||
$realPageNumber = $pageNumber - 1;
|
||||
|
||||
|
@ -583,6 +584,25 @@ class dbPages extends dbJSON
|
|||
}
|
||||
}
|
||||
|
||||
private function stylingFieldsForFile($field, $value)
|
||||
{
|
||||
// Support for Markdown files, good approach for Github
|
||||
if (FILENAME==='index.md') {
|
||||
if ($field==='title') {
|
||||
return '#Title: '.$value;
|
||||
} elseif ($field==='content') {
|
||||
return '---'.PHP_EOL.$value;
|
||||
} else {
|
||||
return '<!-- '.Text::firstCharUp($field).': '.$value.' -->';
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy style of Bludit with index.txt
|
||||
if ($field==='content') {
|
||||
return 'Content:'.PHP_EOL.$value;
|
||||
}
|
||||
return Text::firstCharUp($field).': '.$value;
|
||||
}
|
||||
|
||||
// ----- OLD
|
||||
|
||||
|
|
|
@ -185,19 +185,18 @@ class dbUsers extends dbJSON
|
|||
return $token;
|
||||
}
|
||||
|
||||
// ---- OLD
|
||||
// Returns array with the username databases filtered by username, FALSE otherwise
|
||||
public function getDb($username)
|
||||
public function getDB($username)
|
||||
{
|
||||
if($this->exists($username)) {
|
||||
$user = $this->db[$username];
|
||||
|
||||
return $user;
|
||||
if ($this->exists($username)) {
|
||||
return $this->db[$username];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---- OLD
|
||||
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
return $this->db;
|
||||
|
|
|
@ -149,16 +149,21 @@ function buildPagesFor($for, $categoryKey=false, $tagKey=false)
|
|||
|
||||
// Generate the global variable $pagesByParent, defined on 69.pages.php
|
||||
// (boolean) $allPages, TRUE include all status, FALSE only include published status
|
||||
function buildPagesByParent($allPages=true) {
|
||||
function buildPagesByParent($onlyPublished=true) {
|
||||
global $dbPages;
|
||||
global $pagesByParent;
|
||||
global $pagesByParentByKey;
|
||||
|
||||
$keys = array_keys($dbPages->db);
|
||||
// Get DB
|
||||
$pageNumber = 1;
|
||||
$amountOfItems = -1;
|
||||
$db = $dbPages->getList($pageNumber, $amountOfItems, $onlyPublished);
|
||||
|
||||
// Get Keys
|
||||
$keys = array_keys($db);
|
||||
foreach($keys as $pageKey) {
|
||||
$page = buildPage($pageKey);
|
||||
if($page!==false) {
|
||||
if($allPages || $page->published()) {
|
||||
$parentKey = $page->parentKey();
|
||||
// FALSE if the page is parent
|
||||
if($parentKey===false) {
|
||||
|
@ -173,7 +178,6 @@ function buildPagesByParent($allPages=true) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an Array with all pages existing on the system
|
||||
|
@ -186,19 +190,22 @@ function buildPagesByParent($allPages=true) {
|
|||
pageKeyN => Page object,
|
||||
)
|
||||
*/
|
||||
function buildAllpages($allPages=true) {
|
||||
function buildAllpages($onlyPublished=true) {
|
||||
global $dbPages;
|
||||
|
||||
// Get DB
|
||||
$pageNumber = 1;
|
||||
$amountOfItems = -1;
|
||||
$db = $dbPages->getList($pageNumber, $amountOfItems, $onlyPublished);
|
||||
|
||||
$tmp = array();
|
||||
$keys = array_keys($dbPages->db);
|
||||
$keys = array_keys($db);
|
||||
foreach($keys as $pageKey) {
|
||||
$page = buildPage($pageKey);
|
||||
if($page!==false) {
|
||||
if($allPages || $page->published()) {
|
||||
$tmp[$page->key()] = $page;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,16 @@ class Log {
|
|||
|
||||
public static function set($text, $type=0)
|
||||
{
|
||||
error_log('('.BLUDIT_VERSION.')'.$text, $type);
|
||||
if (is_array($text) ) {
|
||||
error_log('------------------------', $type);
|
||||
error_log('Array', $type);
|
||||
error_log('------------------------', $type);
|
||||
foreach ($text as $key=>$value) {
|
||||
error_log($key.'=>'.$value, $type);
|
||||
}
|
||||
error_log('------------------------', $type);
|
||||
}
|
||||
error_log('('.BLUDIT_VERSION.') ('.$_SERVER['REQUEST_URI'].') '.$text, $type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,13 +55,9 @@
|
|||
public static function destroy()
|
||||
{
|
||||
session_destroy();
|
||||
|
||||
unset($_SESSION);
|
||||
|
||||
self::$started = false;
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'Session destroyed.');
|
||||
|
||||
return !isset($_SESSION);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,26 @@ class Login {
|
|||
return Session::get('role');
|
||||
}
|
||||
|
||||
// Returns TRUE if the user is logged, FALSE otherwise
|
||||
public function isLogged()
|
||||
{
|
||||
if (Session::get('fingerPrint')===$this->fingerPrint()) {
|
||||
$username = Session::get('username');
|
||||
if (!empty($username)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log::set(__METHOD__.LOG_SEP.'Session username empty, destroy the session.');
|
||||
Session::destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'FingerPrint are differents. Current fingerPrint: '.Session::get('fingerPrint').' !== Current fingerPrint: '.$this->fingerPrint());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the session for the user logged
|
||||
public function setLogin($username, $role)
|
||||
{
|
||||
Session::set('username', $username);
|
||||
|
@ -26,30 +46,12 @@ class Login {
|
|||
Session::set('fingerPrint', $this->fingerPrint());
|
||||
Session::set('sessionTime', time());
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'Set fingerPrint: '.$this->fingerPrint());
|
||||
}
|
||||
|
||||
public function isLogged()
|
||||
{
|
||||
if(Session::get('fingerPrint')===$this->fingerPrint())
|
||||
{
|
||||
$username = Session::get('username');
|
||||
|
||||
if(!empty($username)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log::set(__METHOD__.LOG_SEP.'Session username empty: '.$username);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::set(__METHOD__.LOG_SEP.'FingerPrint are differents. Session fingerPrint: '.Session::get('fingerPrint').' !== Current fingerPrint: '.$this->fingerPrint());
|
||||
}
|
||||
|
||||
return false;
|
||||
Log::set(__METHOD__.LOG_SEP.'User logged, fingerprint: '.$this->fingerPrint());
|
||||
}
|
||||
|
||||
// Check if the username and the password are valid
|
||||
// Returns TRUE if valid and set the session
|
||||
// Returns FALSE for invalid username or password
|
||||
public function verifyUser($username, $password)
|
||||
{
|
||||
$username = Sanitize::html($username);
|
||||
|
@ -58,25 +60,21 @@ class Login {
|
|||
$username = trim($username);
|
||||
$password = trim($password);
|
||||
|
||||
if(empty($username) || empty($password)) {
|
||||
if (empty($username) || empty($password)) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Username or password empty. Username: '.$username.' - Password: '.$password);
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->dbUsers->getDb($username);
|
||||
$user = $this->dbUsers->getDB($username);
|
||||
if($user==false) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Username does not exist: '.$username);
|
||||
return false;
|
||||
}
|
||||
|
||||
$passwordHash = sha1($password.$user['salt']);
|
||||
|
||||
if($passwordHash === $user['password'])
|
||||
{
|
||||
$passwordHash = $this->dbUsers->generatePasswordHash($password, $user['salt']);
|
||||
if ($passwordHash===$user['password']) {
|
||||
$this->setLogin($username, $user['role']);
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'User logged succeeded by username and password - Username: '.$username);
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -130,27 +128,14 @@ class Login {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function fingerPrint($random=false)
|
||||
public function fingerPrint()
|
||||
{
|
||||
// User agent
|
||||
$agent = getenv('HTTP_USER_AGENT');
|
||||
if(empty($agent)) {
|
||||
$agent = 'Bludit/1.0 (Mr Nibbler Protocol)';
|
||||
if (empty($agent)) {
|
||||
$agent = 'Bludit/2.0 (Mr Nibbler Protocol)';
|
||||
}
|
||||
|
||||
// User IP
|
||||
if(getenv('HTTP_X_FORWARDED_FOR'))
|
||||
$ip = getenv('HTTP_X_FORWARDED_FOR');
|
||||
elseif(getenv('HTTP_CLIENT_IP'))
|
||||
$ip = getenv('HTTP_CLIENT_IP');
|
||||
else
|
||||
$ip = getenv('REMOTE_ADDR');
|
||||
|
||||
if($random) {
|
||||
return sha1(mt_rand().$agent.$ip);
|
||||
}
|
||||
|
||||
// DEBUG: Ver CLIENT IP, hay veces que retorna la ip ::1 y otras 127.0.0.1
|
||||
return sha1($agent);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ class Page {
|
|||
}
|
||||
|
||||
$tmp = 0;
|
||||
$lines = file($filePath);
|
||||
foreach($lines as $lineNumber=>$line) {
|
||||
$file = file($filePath);
|
||||
foreach($file as $lineNumber=>$line) {
|
||||
// Split the line in 2 parts, limiter by :
|
||||
$parts = explode(':', $line, 2);
|
||||
|
||||
|
@ -60,20 +60,15 @@ class Page {
|
|||
}
|
||||
|
||||
// Process the content
|
||||
if($tmp!==0) {
|
||||
if ($tmp!==0) {
|
||||
// Next line after "Content:" or "---"
|
||||
$tmp++;
|
||||
|
||||
// Remove lines after Content
|
||||
$output = array_slice($lines, $tmp);
|
||||
// Get all lines after "Content:" or "---"
|
||||
$content = array_slice($file, $tmp);
|
||||
|
||||
if( !empty($parts[1]) ) {
|
||||
array_unshift($output, "\n");
|
||||
array_unshift($output, $parts[1]);
|
||||
}
|
||||
|
||||
$implode = implode($output);
|
||||
$this->vars['contentRaw'] = $implode;
|
||||
// Join lines in one variable, this is RAW content from file
|
||||
$this->vars['contentRaw'] = implode($content);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
<?php defined('BLUDIT') or die('Bludit Badass CMS.');
|
||||
|
||||
class Security extends dbJSON
|
||||
{
|
||||
private $dbFields = array(
|
||||
'key1'=>'Where we go we dont need roads',
|
||||
'minutesBlocked'=>5,
|
||||
'numberFailuresAllowed'=>10,
|
||||
'blackList'=>array()
|
||||
|
@ -11,51 +10,34 @@ class Security extends dbJSON
|
|||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct(PATH_DATABASES.'security.php');
|
||||
parent::__construct(DB_SECURITY);
|
||||
}
|
||||
|
||||
// Authentication key
|
||||
// --------------------------------------------------------------------
|
||||
public function key1()
|
||||
{
|
||||
return $this->db['key1'];
|
||||
}
|
||||
|
||||
|
||||
// ====================================================
|
||||
// TOKEN FOR CSRF
|
||||
// ====================================================
|
||||
|
||||
// Generate and save the token in Session.
|
||||
// Generate and save the token in Session
|
||||
public function generateTokenCSRF()
|
||||
{
|
||||
$token = Text::randomText(8);
|
||||
$token = sha1($token);
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'New tokenCSRF was generated '.$token);
|
||||
|
||||
$token = sha1( uniqid().time() );
|
||||
Session::set('tokenCSRF', $token);
|
||||
Log::set('New Token CSRF: '.$token);
|
||||
}
|
||||
|
||||
// Validate the token.
|
||||
// Validate the token
|
||||
public function validateTokenCSRF($token)
|
||||
{
|
||||
$sessionToken = Session::get('tokenCSRF');
|
||||
|
||||
$sessionToken = $this->getTokenCSRF();
|
||||
return ( !empty($sessionToken) && ($sessionToken===$token) );
|
||||
}
|
||||
|
||||
// Returns the token.
|
||||
// Returns the token
|
||||
public function getTokenCSRF()
|
||||
{
|
||||
return Session::get('tokenCSRF');
|
||||
}
|
||||
|
||||
public function printTokenCSRF()
|
||||
{
|
||||
echo Session::get('tokenCSRF');
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// BRUTE FORCE PROTECTION
|
||||
// ====================================================
|
||||
|
@ -64,7 +46,7 @@ class Security extends dbJSON
|
|||
{
|
||||
$ip = $this->getUserIp();
|
||||
|
||||
if(!isset($this->db['blackList'][$ip])) {
|
||||
if (!isset($this->db['blackList'][$ip])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -73,51 +55,42 @@ class Security extends dbJSON
|
|||
$numberFailures = $userBlack['numberFailures'];
|
||||
$lastFailure = $userBlack['lastFailure'];
|
||||
|
||||
// Check if the IP is expired, then is not blocked.
|
||||
if($currentTime > $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||
// Check if the IP is expired, then is not blocked
|
||||
if ($currentTime > $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The IP has more failures than number of failures, then the IP is blocked.
|
||||
if($numberFailures >= $this->db['numberFailuresAllowed']) {
|
||||
// The IP has more failures than number of failures, then the IP is blocked
|
||||
if ($numberFailures >= $this->db['numberFailuresAllowed']) {
|
||||
Log::set(__METHOD__.LOG_SEP.'IP Blocked:'.$ip);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise the IP is not blocked.
|
||||
// Otherwise the IP is not blocked
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addLoginFail()
|
||||
// Add or update the current client IP on the blacklist
|
||||
public function addToBlacklist()
|
||||
{
|
||||
$ip = $this->getUserIp();
|
||||
$currentTime = time();
|
||||
$numberFailures = 1;
|
||||
|
||||
if(isset($this->db['blackList'][$ip]))
|
||||
{
|
||||
if (isset($this->db['blackList'][$ip])) {
|
||||
$userBlack = $this->db['blackList'][$ip];
|
||||
$lastFailure = $userBlack['lastFailure'];
|
||||
|
||||
// Check if the IP is expired, then renew the number of failures.
|
||||
if($currentTime <= $lastFailure + ($this->db['minutesBlocked']*60))
|
||||
{
|
||||
// Check if the IP is expired, then renew the number of failures
|
||||
if($currentTime <= $lastFailure + ($this->db['minutesBlocked']*60)) {
|
||||
$numberFailures = $userBlack['numberFailures'];
|
||||
$numberFailures = $numberFailures + 1;
|
||||
}
|
||||
}
|
||||
|
||||
$this->db['blackList'][$ip] = array('lastFailure'=>$currentTime, 'numberFailures'=>$numberFailures);
|
||||
|
||||
Log::set(__METHOD__.LOG_SEP.'Blacklist, IP:'.$ip.', Number of failures:'.$numberFailures);
|
||||
|
||||
// Save the database
|
||||
if( $this->save() === false ) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to save the database file.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function getNumberFailures($ip=null)
|
||||
|
@ -134,14 +107,13 @@ class Security extends dbJSON
|
|||
|
||||
public function getUserIp()
|
||||
{
|
||||
// User IP
|
||||
if(getenv('HTTP_X_FORWARDED_FOR'))
|
||||
if (getenv('HTTP_X_FORWARDED_FOR')) {
|
||||
$ip = getenv('HTTP_X_FORWARDED_FOR');
|
||||
elseif(getenv('HTTP_CLIENT_IP'))
|
||||
} elseif (getenv('HTTP_CLIENT_IP')) {
|
||||
$ip = getenv('HTTP_CLIENT_IP');
|
||||
else
|
||||
} else {
|
||||
$ip = getenv('REMOTE_ADDR');
|
||||
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{
|
||||
"native": "Deutsch (Schweiz)",
|
||||
"english-name": "German",
|
||||
"last-update": "2016-09-28",
|
||||
"last-update": "2017-07-10",
|
||||
"author": "Clickwork",
|
||||
"email": "egoetschel@clickwork.ch",
|
||||
"website": "https://clickwork.ch"
|
||||
|
@ -236,5 +236,21 @@
|
|||
"сurrent-status" : "Status",
|
||||
"disable-the-user" : "Benutzer deaktivieren",
|
||||
"add-a-new-page": "Eine neue Seite hinzufügen",
|
||||
"add-a-new-post": "Einen neuen Beitrag hinzufügen"
|
||||
"add-a-new-post": "Einen neuen Beitrag hinzufügen",
|
||||
"save-as-draft": "Als Entwurf speichern",
|
||||
"categories": "Kategorien",
|
||||
"add-a-new-category": "Eine neue Kategorie hinzufügen",
|
||||
"new-category": "Neue Katgeorie",
|
||||
"slug": "slug",
|
||||
"edit-category": "Kategorie bearbeiten",
|
||||
"new-theme-configured": "New theme configured",
|
||||
"plugin-configured": "Plugin configured",
|
||||
"new-category-created": "New category created",
|
||||
"new-page-created": "New page created",
|
||||
"page-deleted": "Page deleted",
|
||||
"page-edited": "Page edited",
|
||||
"user-edited": "User edited",
|
||||
"changes-on-settings": "Changes on settings",
|
||||
"plugin-installed": "Plugin installed",
|
||||
"user-password-changed": "User password changed"
|
||||
}
|
||||
|
|
|
@ -9,6 +9,12 @@
|
|||
"website": ""
|
||||
},
|
||||
|
||||
"installer-page-about-content": "The about page is an important and powerful tool for potential clients and partners. For those who wonder who is behind the website, your About page is the first source of information. \n Change this page's content on the admin panel, manage, pages and click on the about page.",
|
||||
"installer-page-error-content": "Opps, page not found, sorry!",
|
||||
"page-not-found": "Page not found",
|
||||
"about-your-site-or-yourself": "About your site or yourself",
|
||||
"welcome-to-bludit": "Welcome to Bludit",
|
||||
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"confirm-password": "Confirm Password",
|
||||
|
@ -215,7 +221,7 @@
|
|||
"the-about-page-is-very-important": "The about page is an important and powerful tool for potential clients and partners. For those who wonder who is behind the website, your About page is the first source of information.",
|
||||
"change-this-pages-content-on-the-admin-panel": "Change this page's content on the admin panel, manage, pages and click on the about page.",
|
||||
"about-your-site-or-yourself": "About your site or yourself",
|
||||
"welcome-to-bludit": "Welcome to Bludit",
|
||||
|
||||
|
||||
"site-information": "Site information",
|
||||
"date-and-time-formats": "Date and time formats",
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
"plugin-data":
|
||||
{
|
||||
"name": "About",
|
||||
"description": "Little description about your site or yourself."
|
||||
"description": "Shows a little description about your site or yourself."
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
"email": "",
|
||||
"website": "https://plugins.bludit.com",
|
||||
"version": "2.0",
|
||||
"releaseDate": "2017-05-26",
|
||||
"releaseDate": "2017-06-15",
|
||||
"license": "MIT",
|
||||
"compatible": "2.0",
|
||||
"notes": ""
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"email": "",
|
||||
"website": "https://plugins.bludit.com",
|
||||
"version": "2.0",
|
||||
"releaseDate": "2017-07-07",
|
||||
"releaseDate": "2017-06-15",
|
||||
"license": "MIT",
|
||||
"compatible": "2.0",
|
||||
"notes": ""
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"email": "",
|
||||
"website": "https://plugins.bludit.com",
|
||||
"version": "2.0",
|
||||
"releaseDate": "2017-05-26",
|
||||
"releaseDate": "2017-06-15",
|
||||
"license": "MIT",
|
||||
"compatible": "2.0",
|
||||
"notes": ""
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"email": "",
|
||||
"website": "https://plugins.bludit.com",
|
||||
"version": "2.0",
|
||||
"releaseDate": "2017-05-26",
|
||||
"releaseDate": "2017-06-15",
|
||||
"license": "MIT",
|
||||
"compatible": "2.0",
|
||||
"notes": ""
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"email": "",
|
||||
"website": "https://plugins.bludit.com",
|
||||
"version": "2.0",
|
||||
"releaseDate": "2017-05-26",
|
||||
"releaseDate": "2017-06-15",
|
||||
"license": "MIT",
|
||||
"compatible": "2.0",
|
||||
"notes": ""
|
||||
|
|
|
@ -6,7 +6,7 @@ class pluginLinks extends Plugin {
|
|||
{
|
||||
// JSON database
|
||||
$jsondb = json_encode(array(
|
||||
'Bludit'=>'https://bludit.com',
|
||||
'Bludit'=>'https://www.bludit.com',
|
||||
'Donate'=>'https://paypal.me/bludit'
|
||||
));
|
||||
|
||||
|
|
|
@ -14,11 +14,13 @@ class pluginSitemap extends Plugin {
|
|||
$xml .= '<loc>'.$Site->url().'</loc>';
|
||||
$xml .= '</url>';
|
||||
|
||||
// Get keys of pages
|
||||
$keys = $dbPages->db;
|
||||
unset($keys['error']);
|
||||
$keys = array_keys($keys);
|
||||
// Get DB
|
||||
$pageNumber = 1;
|
||||
$amountOfItems = -1;
|
||||
$onlyPublished = true;
|
||||
$db = $dbPages->getList($pageNumber, $amountOfItems, $onlyPublished);
|
||||
|
||||
$keys = array_keys($db);
|
||||
foreach($keys as $pageKey) {
|
||||
// Create the page object from the page key
|
||||
$page = buildPage($pageKey);
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
body {
|
||||
padding-top: 0;
|
||||
background: #F7F7F7;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
a {
|
||||
border: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
border-bottom: 1px dotted rgba(160, 160, 160, 0.65)
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
text-transform: none;
|
||||
letter-spacing: 0;
|
||||
font-weight: normal;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 1.3em;
|
||||
}
|
||||
|
||||
code {
|
||||
border: 0;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pre code {
|
||||
border: 1px solid #ffcb94;
|
||||
font-weight: normal !important;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#main {
|
||||
max-width: 980px;
|
||||
}
|
||||
|
||||
#header {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 1.4em;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
#header .links {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#header .main ul li {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#header .main ul li > a {
|
||||
color: #2672ec;
|
||||
}
|
||||
|
||||
header p {
|
||||
text-transform: none;
|
||||
letter-spacing: 0;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#menu .links > li a h3 {
|
||||
font-size: 1em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#intro header h2 {
|
||||
font-weight: lighter;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#intro header p {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.post {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.post a {
|
||||
color: #2672ec;
|
||||
}
|
||||
|
||||
.post > header {
|
||||
border-bottom-color: #F7F7F7;
|
||||
margin-bottom: 1.3em;
|
||||
}
|
||||
|
||||
.post > header .meta {
|
||||
padding: 0.5em 3em 0.3em;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.post > header .title {
|
||||
padding: 0.5em 3em 0.3em;
|
||||
}
|
||||
|
||||
.post > header .title h1 {
|
||||
font-size: 2em;
|
||||
font-weight: normal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.post > header .title h1 a {
|
||||
color: #3c3b3b;
|
||||
}
|
||||
|
||||
.post > footer .stats {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.post > footer .actions {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.author .name {
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
margin-top: 2.2em;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.plugin > h2 {
|
||||
font-weight: normal !important;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.plugin ul {
|
||||
list-style: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.plugin li {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.plugin-pages ul.children {
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.plugin-pages li.parent {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
/* Only for Plugin tags */
|
||||
.plugin-tags li {
|
||||
text-transform: capitalize;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Future Imperfect by HTML5 UP
|
||||
html5up.net | @n33co
|
||||
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
|
||||
*/
|
||||
|
||||
/* Button */
|
||||
|
||||
input[type="submit"],
|
||||
input[type="reset"],
|
||||
input[type="button"],
|
||||
button,
|
||||
.button {
|
||||
border: solid 1px #dedede;
|
||||
}
|
||||
|
||||
/* Form */
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
input[type="email"],
|
||||
input[type="tel"],
|
||||
select,
|
||||
textarea {
|
||||
border: solid 1px #dedede;
|
||||
}
|
||||
|
||||
/* Post */
|
||||
|
||||
.post {
|
||||
border: solid 1px #dedede;
|
||||
}
|
||||
|
||||
.post > header {
|
||||
border-bottom: solid 1px #dedede;
|
||||
}
|
||||
|
||||
/* Mini Post */
|
||||
|
||||
.mini-post {
|
||||
border: solid 1px #dedede;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
#header {
|
||||
border-bottom: solid 1px #dedede;
|
||||
}
|
||||
|
||||
#header .links {
|
||||
border-left: solid 1px #dedede;
|
||||
}
|
||||
|
||||
#header .main ul li {
|
||||
border-left: solid 1px #dedede;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
|
||||
#sidebar > * {
|
||||
border-top: solid 1px #dedede;
|
||||
}
|
||||
|
||||
/* Menu */
|
||||
|
||||
#menu {
|
||||
border-left: solid 1px #dedede;
|
||||
}
|
||||
|
||||
#menu > * {
|
||||
border-top: solid 1px #dedede;
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Future Imperfect by HTML5 UP
|
||||
html5up.net | @n33co
|
||||
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
|
||||
*/
|
||||
|
||||
/* List */
|
||||
|
||||
ul.posts article:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.posts article .image {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
ul.posts article header {
|
||||
display: table-cell;
|
||||
padding-right: 1em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* Author */
|
||||
|
||||
.author .name {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.author img {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Post */
|
||||
|
||||
.post:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
|
||||
.post > header:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
|
||||
.post > header .title {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
.post > header .meta {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.post > footer:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
|
||||
.post > footer .actions {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.post > footer .stats {
|
||||
display: inline-block;
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
/* Mini Post */
|
||||
|
||||
.mini-post .image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
#header:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#header .links {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#header .main {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/* Wrapper */
|
||||
|
||||
/* Sidebar */
|
||||
|
||||
#sidebar {
|
||||
display: table-cell;
|
||||
margin-right: 0;
|
||||
padding-right: 3em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* Main */
|
||||
|
||||
#main {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
|
||||
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
|
||||
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
|
||||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
|
||||
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
|
|
@ -0,0 +1,6 @@
|
|||
/*! Respond.js v1.4.2: min/max-width media query polyfill
|
||||
* Copyright 2014 Scott Jehl
|
||||
* Licensed under MIT
|
||||
* http://j.mp/respondjs */
|
||||
|
||||
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b<t.length;b++){var c=t[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!p[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(w(c.styleSheet.rawCssText,e,f),p[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!s||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}x()};y(),c.update=y,c.getEmValue=u,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Future Imperfect by HTML5 UP
|
||||
html5up.net | @n33co
|
||||
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
skel.breakpoints({
|
||||
xlarge: '(max-width: 1680px)',
|
||||
large: '(max-width: 1280px)',
|
||||
medium: '(max-width: 980px)',
|
||||
small: '(max-width: 736px)',
|
||||
xsmall: '(max-width: 480px)'
|
||||
});
|
||||
|
||||
$(function() {
|
||||
|
||||
var $window = $(window),
|
||||
$body = $('body'),
|
||||
$menu = $('#menu'),
|
||||
$sidebar = $('#sidebar'),
|
||||
$main = $('#main');
|
||||
|
||||
// Disable animations/transitions until the page has loaded.
|
||||
$body.addClass('is-loading');
|
||||
|
||||
$window.on('load', function() {
|
||||
window.setTimeout(function() {
|
||||
$body.removeClass('is-loading');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Fix: Placeholder polyfill.
|
||||
$('form').placeholder();
|
||||
|
||||
// Prioritize "important" elements on medium.
|
||||
skel.on('+medium -medium', function() {
|
||||
$.prioritize(
|
||||
'.important\\28 medium\\29',
|
||||
skel.breakpoint('medium').active
|
||||
);
|
||||
});
|
||||
|
||||
// IE<=9: Reverse order of main and sidebar.
|
||||
if (skel.vars.IEVersion <= 9)
|
||||
$main.insertAfter($sidebar);
|
||||
|
||||
// Menu.
|
||||
$menu
|
||||
.appendTo($body)
|
||||
.panel({
|
||||
delay: 500,
|
||||
hideOnClick: true,
|
||||
hideOnSwipe: true,
|
||||
resetScroll: true,
|
||||
resetForms: true,
|
||||
side: 'right',
|
||||
target: $body,
|
||||
visibleClass: 'is-menu-visible'
|
||||
});
|
||||
|
||||
// Search (header).
|
||||
var $search = $('#search'),
|
||||
$search_input = $search.find('input');
|
||||
|
||||
$body
|
||||
.on('click', '[href="#search"]', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
// Not visible?
|
||||
if (!$search.hasClass('visible')) {
|
||||
|
||||
// Reset form.
|
||||
$search[0].reset();
|
||||
|
||||
// Show.
|
||||
$search.addClass('visible');
|
||||
|
||||
// Focus input.
|
||||
$search_input.focus();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$search_input
|
||||
.on('keydown', function(event) {
|
||||
|
||||
if (event.keyCode == 27)
|
||||
$search_input.blur();
|
||||
|
||||
})
|
||||
.on('blur', function() {
|
||||
window.setTimeout(function() {
|
||||
$search.removeClass('visible');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Intro.
|
||||
var $intro = $('#intro');
|
||||
|
||||
// Move to main on <=large, back to sidebar on >large.
|
||||
skel
|
||||
.on('+large', function() {
|
||||
$intro.prependTo($main);
|
||||
})
|
||||
.on('-large', function() {
|
||||
$intro.prependTo($sidebar);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,587 @@
|
|||
(function($) {
|
||||
|
||||
/**
|
||||
* Generate an indented list of links from a nav. Meant for use with panel().
|
||||
* @return {jQuery} jQuery object.
|
||||
*/
|
||||
$.fn.navList = function() {
|
||||
|
||||
var $this = $(this);
|
||||
$a = $this.find('a'),
|
||||
b = [];
|
||||
|
||||
$a.each(function() {
|
||||
|
||||
var $this = $(this),
|
||||
indent = Math.max(0, $this.parents('li').length - 1),
|
||||
href = $this.attr('href'),
|
||||
target = $this.attr('target');
|
||||
|
||||
b.push(
|
||||
'<a ' +
|
||||
'class="link depth-' + indent + '"' +
|
||||
( (typeof target !== 'undefined' && target != '') ? ' target="' + target + '"' : '') +
|
||||
( (typeof href !== 'undefined' && href != '') ? ' href="' + href + '"' : '') +
|
||||
'>' +
|
||||
'<span class="indent-' + indent + '"></span>' +
|
||||
$this.text() +
|
||||
'</a>'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
return b.join('');
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Panel-ify an element.
|
||||
* @param {object} userConfig User config.
|
||||
* @return {jQuery} jQuery object.
|
||||
*/
|
||||
$.fn.panel = function(userConfig) {
|
||||
|
||||
// No elements?
|
||||
if (this.length == 0)
|
||||
return $this;
|
||||
|
||||
// Multiple elements?
|
||||
if (this.length > 1) {
|
||||
|
||||
for (var i=0; i < this.length; i++)
|
||||
$(this[i]).panel(userConfig);
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
// Vars.
|
||||
var $this = $(this),
|
||||
$body = $('body'),
|
||||
$window = $(window),
|
||||
id = $this.attr('id'),
|
||||
config;
|
||||
|
||||
// Config.
|
||||
config = $.extend({
|
||||
|
||||
// Delay.
|
||||
delay: 0,
|
||||
|
||||
// Hide panel on link click.
|
||||
hideOnClick: false,
|
||||
|
||||
// Hide panel on escape keypress.
|
||||
hideOnEscape: false,
|
||||
|
||||
// Hide panel on swipe.
|
||||
hideOnSwipe: false,
|
||||
|
||||
// Reset scroll position on hide.
|
||||
resetScroll: false,
|
||||
|
||||
// Reset forms on hide.
|
||||
resetForms: false,
|
||||
|
||||
// Side of viewport the panel will appear.
|
||||
side: null,
|
||||
|
||||
// Target element for "class".
|
||||
target: $this,
|
||||
|
||||
// Class to toggle.
|
||||
visibleClass: 'visible'
|
||||
|
||||
}, userConfig);
|
||||
|
||||
// Expand "target" if it's not a jQuery object already.
|
||||
if (typeof config.target != 'jQuery')
|
||||
config.target = $(config.target);
|
||||
|
||||
// Panel.
|
||||
|
||||
// Methods.
|
||||
$this._hide = function(event) {
|
||||
|
||||
// Already hidden? Bail.
|
||||
if (!config.target.hasClass(config.visibleClass))
|
||||
return;
|
||||
|
||||
// If an event was provided, cancel it.
|
||||
if (event) {
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
}
|
||||
|
||||
// Hide.
|
||||
config.target.removeClass(config.visibleClass);
|
||||
|
||||
// Post-hide stuff.
|
||||
window.setTimeout(function() {
|
||||
|
||||
// Reset scroll position.
|
||||
if (config.resetScroll)
|
||||
$this.scrollTop(0);
|
||||
|
||||
// Reset forms.
|
||||
if (config.resetForms)
|
||||
$this.find('form').each(function() {
|
||||
this.reset();
|
||||
});
|
||||
|
||||
}, config.delay);
|
||||
|
||||
};
|
||||
|
||||
// Vendor fixes.
|
||||
$this
|
||||
.css('-ms-overflow-style', '-ms-autohiding-scrollbar')
|
||||
.css('-webkit-overflow-scrolling', 'touch');
|
||||
|
||||
// Hide on click.
|
||||
if (config.hideOnClick) {
|
||||
|
||||
$this.find('a')
|
||||
.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
|
||||
|
||||
$this
|
||||
.on('click', 'a', function(event) {
|
||||
|
||||
var $a = $(this),
|
||||
href = $a.attr('href'),
|
||||
target = $a.attr('target');
|
||||
|
||||
if (!href || href == '#' || href == '' || href == '#' + id)
|
||||
return;
|
||||
|
||||
// Cancel original event.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Hide panel.
|
||||
$this._hide();
|
||||
|
||||
// Redirect to href.
|
||||
window.setTimeout(function() {
|
||||
|
||||
if (target == '_blank')
|
||||
window.open(href);
|
||||
else
|
||||
window.location.href = href;
|
||||
|
||||
}, config.delay + 10);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Event: Touch stuff.
|
||||
$this.on('touchstart', function(event) {
|
||||
|
||||
$this.touchPosX = event.originalEvent.touches[0].pageX;
|
||||
$this.touchPosY = event.originalEvent.touches[0].pageY;
|
||||
|
||||
})
|
||||
|
||||
$this.on('touchmove', function(event) {
|
||||
|
||||
if ($this.touchPosX === null
|
||||
|| $this.touchPosY === null)
|
||||
return;
|
||||
|
||||
var diffX = $this.touchPosX - event.originalEvent.touches[0].pageX,
|
||||
diffY = $this.touchPosY - event.originalEvent.touches[0].pageY,
|
||||
th = $this.outerHeight(),
|
||||
ts = ($this.get(0).scrollHeight - $this.scrollTop());
|
||||
|
||||
// Hide on swipe?
|
||||
if (config.hideOnSwipe) {
|
||||
|
||||
var result = false,
|
||||
boundary = 20,
|
||||
delta = 50;
|
||||
|
||||
switch (config.side) {
|
||||
|
||||
case 'left':
|
||||
result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta);
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta));
|
||||
break;
|
||||
|
||||
case 'top':
|
||||
result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta);
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (result) {
|
||||
|
||||
$this.touchPosX = null;
|
||||
$this.touchPosY = null;
|
||||
$this._hide();
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Prevent vertical scrolling past the top or bottom.
|
||||
if (($this.scrollTop() < 0 && diffY < 0)
|
||||
|| (ts > (th - 2) && ts < (th + 2) && diffY > 0)) {
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Event: Prevent certain events inside the panel from bubbling.
|
||||
$this.on('click touchend touchstart touchmove', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Event: Hide panel if a child anchor tag pointing to its ID is clicked.
|
||||
$this.on('click', 'a[href="#' + id + '"]', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
config.target.removeClass(config.visibleClass);
|
||||
|
||||
});
|
||||
|
||||
// Body.
|
||||
|
||||
// Event: Hide panel on body click/tap.
|
||||
$body.on('click touchend', function(event) {
|
||||
$this._hide(event);
|
||||
});
|
||||
|
||||
// Event: Toggle.
|
||||
$body.on('click', 'a[href="#' + id + '"]', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
config.target.toggleClass(config.visibleClass);
|
||||
|
||||
});
|
||||
|
||||
// Window.
|
||||
|
||||
// Event: Hide on ESC.
|
||||
if (config.hideOnEscape)
|
||||
$window.on('keydown', function(event) {
|
||||
|
||||
if (event.keyCode == 27)
|
||||
$this._hide(event);
|
||||
|
||||
});
|
||||
|
||||
return $this;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply "placeholder" attribute polyfill to one or more forms.
|
||||
* @return {jQuery} jQuery object.
|
||||
*/
|
||||
$.fn.placeholder = function() {
|
||||
|
||||
// Browser natively supports placeholders? Bail.
|
||||
if (typeof (document.createElement('input')).placeholder != 'undefined')
|
||||
return $(this);
|
||||
|
||||
// No elements?
|
||||
if (this.length == 0)
|
||||
return $this;
|
||||
|
||||
// Multiple elements?
|
||||
if (this.length > 1) {
|
||||
|
||||
for (var i=0; i < this.length; i++)
|
||||
$(this[i]).placeholder();
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
// Vars.
|
||||
var $this = $(this);
|
||||
|
||||
// Text, TextArea.
|
||||
$this.find('input[type=text],textarea')
|
||||
.each(function() {
|
||||
|
||||
var i = $(this);
|
||||
|
||||
if (i.val() == ''
|
||||
|| i.val() == i.attr('placeholder'))
|
||||
i
|
||||
.addClass('polyfill-placeholder')
|
||||
.val(i.attr('placeholder'));
|
||||
|
||||
})
|
||||
.on('blur', function() {
|
||||
|
||||
var i = $(this);
|
||||
|
||||
if (i.attr('name').match(/-polyfill-field$/))
|
||||
return;
|
||||
|
||||
if (i.val() == '')
|
||||
i
|
||||
.addClass('polyfill-placeholder')
|
||||
.val(i.attr('placeholder'));
|
||||
|
||||
})
|
||||
.on('focus', function() {
|
||||
|
||||
var i = $(this);
|
||||
|
||||
if (i.attr('name').match(/-polyfill-field$/))
|
||||
return;
|
||||
|
||||
if (i.val() == i.attr('placeholder'))
|
||||
i
|
||||
.removeClass('polyfill-placeholder')
|
||||
.val('');
|
||||
|
||||
});
|
||||
|
||||
// Password.
|
||||
$this.find('input[type=password]')
|
||||
.each(function() {
|
||||
|
||||
var i = $(this);
|
||||
var x = $(
|
||||
$('<div>')
|
||||
.append(i.clone())
|
||||
.remove()
|
||||
.html()
|
||||
.replace(/type="password"/i, 'type="text"')
|
||||
.replace(/type=password/i, 'type=text')
|
||||
);
|
||||
|
||||
if (i.attr('id') != '')
|
||||
x.attr('id', i.attr('id') + '-polyfill-field');
|
||||
|
||||
if (i.attr('name') != '')
|
||||
x.attr('name', i.attr('name') + '-polyfill-field');
|
||||
|
||||
x.addClass('polyfill-placeholder')
|
||||
.val(x.attr('placeholder')).insertAfter(i);
|
||||
|
||||
if (i.val() == '')
|
||||
i.hide();
|
||||
else
|
||||
x.hide();
|
||||
|
||||
i
|
||||
.on('blur', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
|
||||
|
||||
if (i.val() == '') {
|
||||
|
||||
i.hide();
|
||||
x.show();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
x
|
||||
.on('focus', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']');
|
||||
|
||||
x.hide();
|
||||
|
||||
i
|
||||
.show()
|
||||
.focus();
|
||||
|
||||
})
|
||||
.on('keypress', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
x.val('');
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Events.
|
||||
$this
|
||||
.on('submit', function() {
|
||||
|
||||
$this.find('input[type=text],input[type=password],textarea')
|
||||
.each(function(event) {
|
||||
|
||||
var i = $(this);
|
||||
|
||||
if (i.attr('name').match(/-polyfill-field$/))
|
||||
i.attr('name', '');
|
||||
|
||||
if (i.val() == i.attr('placeholder')) {
|
||||
|
||||
i.removeClass('polyfill-placeholder');
|
||||
i.val('');
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
.on('reset', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
$this.find('select')
|
||||
.val($('option:first').val());
|
||||
|
||||
$this.find('input,textarea')
|
||||
.each(function() {
|
||||
|
||||
var i = $(this),
|
||||
x;
|
||||
|
||||
i.removeClass('polyfill-placeholder');
|
||||
|
||||
switch (this.type) {
|
||||
|
||||
case 'submit':
|
||||
case 'reset':
|
||||
break;
|
||||
|
||||
case 'password':
|
||||
i.val(i.attr('defaultValue'));
|
||||
|
||||
x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
|
||||
|
||||
if (i.val() == '') {
|
||||
i.hide();
|
||||
x.show();
|
||||
}
|
||||
else {
|
||||
i.show();
|
||||
x.hide();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
case 'radio':
|
||||
i.attr('checked', i.attr('defaultValue'));
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
i.val(i.attr('defaultValue'));
|
||||
|
||||
if (i.val() == '') {
|
||||
i.addClass('polyfill-placeholder');
|
||||
i.val(i.attr('placeholder'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
i.val(i.attr('defaultValue'));
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return $this;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves elements to/from the first positions of their respective parents.
|
||||
* @param {jQuery} $elements Elements (or selector) to move.
|
||||
* @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations.
|
||||
*/
|
||||
$.prioritize = function($elements, condition) {
|
||||
|
||||
var key = '__prioritize';
|
||||
|
||||
// Expand $elements if it's not already a jQuery object.
|
||||
if (typeof $elements != 'jQuery')
|
||||
$elements = $($elements);
|
||||
|
||||
// Step through elements.
|
||||
$elements.each(function() {
|
||||
|
||||
var $e = $(this), $p,
|
||||
$parent = $e.parent();
|
||||
|
||||
// No parent? Bail.
|
||||
if ($parent.length == 0)
|
||||
return;
|
||||
|
||||
// Not moved? Move it.
|
||||
if (!$e.data(key)) {
|
||||
|
||||
// Condition is false? Bail.
|
||||
if (!condition)
|
||||
return;
|
||||
|
||||
// Get placeholder (which will serve as our point of reference for when this element needs to move back).
|
||||
$p = $e.prev();
|
||||
|
||||
// Couldn't find anything? Means this element's already at the top, so bail.
|
||||
if ($p.length == 0)
|
||||
return;
|
||||
|
||||
// Move element to top of parent.
|
||||
$e.prependTo($parent);
|
||||
|
||||
// Mark element as moved.
|
||||
$e.data(key, $p);
|
||||
|
||||
}
|
||||
|
||||
// Moved already?
|
||||
else {
|
||||
|
||||
// Condition is true? Bail.
|
||||
if (condition)
|
||||
return;
|
||||
|
||||
$p = $e.data(key);
|
||||
|
||||
// Move element back to its original location (using our placeholder).
|
||||
$e.insertAfter($p);
|
||||
|
||||
// Unmark element as moved.
|
||||
$e.removeData(key);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
})(jQuery);
|
Binary file not shown.
After Width: | Height: | Size: 1005 B |
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Include HTML meta tags -->
|
||||
<?php include(THEME_DIR_PHP.'head.php') ?>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
|
||||
<div id="main">
|
||||
|
||||
<?php
|
||||
if( ($Url->whereAmI()=='home') || ($Url->whereAmI()=='tag') || ($Url->whereAmI()=='blog') )
|
||||
{
|
||||
include(THEME_DIR_PHP.'home.php');
|
||||
}
|
||||
elseif($Url->whereAmI()=='post')
|
||||
{
|
||||
include(THEME_DIR_PHP.'post.php');
|
||||
}
|
||||
elseif($Url->whereAmI()=='page')
|
||||
{
|
||||
include(THEME_DIR_PHP.'page.php');
|
||||
}
|
||||
?>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<section id="sidebar">
|
||||
<?php include(THEME_DIR_PHP.'sidebar.php') ?>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<?php Theme::jquery() ?>
|
||||
<script src="<?php echo HTML_PATH_THEME ?>assets/js/skel.min.js"></script>
|
||||
<script src="<?php echo HTML_PATH_THEME ?>assets/js/util.js"></script>
|
||||
<!--[if lte IE 8]><script src="<?php echo HTML_PATH_THEME ?>assets/js/ie/respond.min.js"></script><![endif]-->
|
||||
<script src="<?php echo HTML_PATH_THEME ?>assets/js/main.js"></script>
|
||||
|
||||
<!-- Plugins Site Body End -->
|
||||
<?php Theme::plugins('siteBodyEnd') ?>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"theme-data":
|
||||
{
|
||||
"name": "diego",
|
||||
"description": "Minimalist and very responsive theme, developed by @n33co, adapted and modified for Bludit."
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"theme-data":
|
||||
{
|
||||
"name": "diego",
|
||||
"description": "Minimalista y a su vez altamente adaptable para todo tipo de pantallas, desarrollado por @n33co, adaptado y modificado para Bludit."
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"author": "n33co",
|
||||
"email": "",
|
||||
"website": "http://html5up.net",
|
||||
"version": "1.4",
|
||||
"releaseDate": "2016-05-20",
|
||||
"license": "CCA 3.0",
|
||||
"compatible": "1.5beta",
|
||||
"notes": ""
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
Theme::charset('utf-8');
|
||||
Theme::viewport('width=device-width, initial-scale=1');
|
||||
|
||||
Theme::title();
|
||||
Theme::description();
|
||||
|
||||
Theme::favicon('favicon.png');
|
||||
?>
|
||||
|
||||
<!--[if lte IE 8]><script src="<?php echo HTML_PATH_THEME ?>assets/js/ie/html5shiv.js"></script><![endif]-->
|
||||
<link rel="stylesheet" href="<?php echo HTML_PATH_THEME ?>assets/css/main.css">
|
||||
<!--[if lte IE 9]><link rel="stylesheet" href="<?php echo HTML_PATH_THEME ?>assets/css/ie9.css" /><![endif]-->
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="<?php echo HTML_PATH_THEME ?>assets/css/ie8.css" /><![endif]-->
|
||||
<link rel="stylesheet" href="<?php echo HTML_PATH_THEME ?>assets/css/bludit.css">
|
||||
|
||||
<?php
|
||||
|
||||
// Add local Fonts Awesome
|
||||
Theme::fontAwesome();
|
||||
|
||||
// Load plugins, hook: Site head
|
||||
Theme::plugins('siteHead');
|
||||
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/styles/default.min.css">
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/highlight.min.js"></script>
|
|
@ -0,0 +1,83 @@
|
|||
<!-- Show each post on this page -->
|
||||
<?php foreach ($posts as $Post): ?>
|
||||
|
||||
<article class="post">
|
||||
|
||||
<!-- Show plugins, Hook: Post Begin -->
|
||||
<?php Theme::plugins('postBegin') ?>
|
||||
|
||||
<!-- Post's header -->
|
||||
<header>
|
||||
<div class="title">
|
||||
<h1><a href="<?php echo $Post->permalink() ?>"><?php echo $Post->title() ?></a></h1>
|
||||
<p><?php echo $Post->description() ?></p>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<?php
|
||||
// Get the user who created the post.
|
||||
$User = $Post->user();
|
||||
|
||||
// Default author is the username.
|
||||
$author = $User->username();
|
||||
|
||||
// If the user complete the first name or last name this will be the author.
|
||||
if( Text::isNotEmpty($User->firstName()) || Text::isNotEmpty($User->lastName()) ) {
|
||||
$author = $User->firstName().' '.$User->lastName();
|
||||
}
|
||||
?>
|
||||
<time class="published" datetime="2015-11-01"><?php echo $Post->date() ?></time>
|
||||
<div class="author"><span class="name"><?php echo $author ?></span><img src="<?php echo $User->profilePicture() ?>" alt=""></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<?php
|
||||
if($Post->coverImage()) {
|
||||
echo '<a href="'.$Post->permalink().'" class="image featured"><img src="'.$Post->coverImage().'" alt="Cover Image"></a>';
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Post's content, the first part if has pagebrake -->
|
||||
<?php echo $Post->content(false) ?>
|
||||
|
||||
<!-- Post's footer -->
|
||||
<footer>
|
||||
|
||||
<!-- Read more button -->
|
||||
<?php if($Post->readMore()) { ?>
|
||||
<ul class="actions">
|
||||
<li><a href="<?php echo $Post->permalink() ?>" class="button"><?php $Language->p('Read more') ?></a></li>
|
||||
</ul>
|
||||
<?php } ?>
|
||||
|
||||
<!-- Post's tags -->
|
||||
<ul class="stats">
|
||||
<?php
|
||||
$tags = $Post->tags(true);
|
||||
|
||||
foreach($tags as $tagKey=>$tagName) {
|
||||
echo '<li><a href="'.HTML_PATH_ROOT.$Url->filters('tag').'/'.$tagKey.'">'.$tagName.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
<!-- Plugins Post End -->
|
||||
<?php Theme::plugins('postEnd') ?>
|
||||
|
||||
</article>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
<!-- Pagination -->
|
||||
<ul class="actions pagination">
|
||||
<?php
|
||||
if( Paginator::get('showNewer') ) {
|
||||
echo '<li><a href="'.Paginator::urlPrevPage().'" class="button big previous">'.$Language->get('Prev page').'</a></li>';
|
||||
}
|
||||
|
||||
if( Paginator::get('showOlder') ) {
|
||||
echo '<li><a href="'.Paginator::urlNextPage().'" class="button big next">'.$Language->get('Next page').'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
|
@ -0,0 +1,27 @@
|
|||
<article class="post">
|
||||
|
||||
<!-- Plugins Page Begin -->
|
||||
<?php Theme::plugins('pageBegin') ?>
|
||||
|
||||
<!-- Post's header -->
|
||||
<header>
|
||||
<div class="title">
|
||||
<h1><a href="<?php echo $Page->permalink() ?>"><?php echo $Page->title() ?></a></h1>
|
||||
<p><?php echo $Page->description() ?></p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<?php
|
||||
if($Page->coverImage()) {
|
||||
echo '<a href="'.$Page->permalink().'" class="image featured"><img src="'.$Page->coverImage().'" alt="Cover Image"></a>';
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Post's content, the first part if has pagebrake -->
|
||||
<?php echo $Page->content() ?>
|
||||
|
||||
<!-- Plugins Page End -->
|
||||
<?php Theme::plugins('pageEnd') ?>
|
||||
|
||||
</article>
|
|
@ -0,0 +1,57 @@
|
|||
<article class="post">
|
||||
|
||||
<!-- Show plugins, Hook: Post Begin -->
|
||||
<?php Theme::plugins('postBegin') ?>
|
||||
|
||||
<!-- Post's header -->
|
||||
<header>
|
||||
<div class="title">
|
||||
<h1><a href="<?php echo $Post->permalink() ?>"><?php echo $Post->title() ?></a></h1>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<?php
|
||||
// Get the user who created the post.
|
||||
$User = $Post->user();
|
||||
|
||||
// Default author is the username.
|
||||
$author = $User->username();
|
||||
|
||||
// If the user complete the first name or last name this will be the author.
|
||||
if( Text::isNotEmpty($User->firstName()) || Text::isNotEmpty($User->lastName()) ) {
|
||||
$author = $User->firstName().' '.$User->lastName();
|
||||
}
|
||||
?>
|
||||
<time class="published" datetime="2015-11-01"><?php echo $Post->date() ?></time>
|
||||
<div class="author"><span class="name"><?php echo $author ?></span><img src="<?php echo $User->profilePicture() ?>" alt=""></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<?php
|
||||
if($Post->coverImage()) {
|
||||
echo '<a href="'.$Post->permalink().'" class="image featured"><img src="'.$Post->coverImage().'" alt="Cover Image"></a>';
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Post's content, the first part if has pagebrake -->
|
||||
<?php echo $Post->content() ?>
|
||||
|
||||
<!-- Post's footer -->
|
||||
<footer>
|
||||
|
||||
<!-- Post's tags -->
|
||||
<ul class="stats">
|
||||
<?php
|
||||
$tags = $Post->tags(true);
|
||||
|
||||
foreach($tags as $tagKey=>$tagName) {
|
||||
echo '<li><a href="'.HTML_PATH_ROOT.$Url->filters('tag').'/'.$tagKey.'">'.$tagName.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
<!-- Show plugins, Hook: Post End -->
|
||||
<?php Theme::plugins('postEnd') ?>
|
||||
|
||||
</article>
|
|
@ -0,0 +1,41 @@
|
|||
<!-- Intro -->
|
||||
<section id="intro">
|
||||
<header>
|
||||
<h2><a href="<?php echo $Site->url() ?>"><?php echo $Site->title() ?></a></h2>
|
||||
<p><?php echo $Site->slogan() ?></p>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
<?php Theme::plugins('siteSidebar') ?>
|
||||
|
||||
<!-- Footer -->
|
||||
<section id="footer">
|
||||
<ul class="icons">
|
||||
<?php
|
||||
if($Site->twitter()) {
|
||||
echo '<li><a href="'.$Site->twitter().'" class="fa-twitter"><span class="label">Twitter</span></a></li>';
|
||||
}
|
||||
|
||||
if($Site->facebook()) {
|
||||
echo '<li><a href="'.$Site->facebook().'" class="fa-facebook"><span class="label">Facebook</span></a></li>';
|
||||
}
|
||||
|
||||
if($Site->instagram()) {
|
||||
echo '<li><a href="'.$Site->instagram().'" class="fa-instagram"><span class="label">Instagram</span></a></li>';
|
||||
}
|
||||
|
||||
if($Site->github()) {
|
||||
echo '<li><a href="'.$Site->github().'" class="fa-github"><span class="label">Github</span></a></li>';
|
||||
}
|
||||
|
||||
if( $plugins['all']['pluginRSS']->installed() ) {
|
||||
echo '<li><a href="'.DOMAIN_BASE.'rss.xml'.'" class="fa-rss"><span class="label">RSS</span></a></li>';
|
||||
}
|
||||
|
||||
if( $plugins['all']['pluginSitemap']->installed() ) {
|
||||
echo '<li><a href="'.DOMAIN_BASE.'sitemap.xml'.'" class="fa-sitemap"><span class="label">Sitemap</span></a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<p class="copyright"><?php echo $Site->footer() ?> | <a href="http://www.bludit.com">BLUDIT</a></p>
|
||||
</section>
|
|
@ -8,6 +8,33 @@ a.home-title {
|
|||
color: #222;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
ul li {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
table thead {
|
||||
background: #555555;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
table td,
|
||||
table th {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
}
|
||||
/* PAGES */
|
||||
|
||||
article.page:not(:last-child) {
|
||||
|
@ -32,8 +59,17 @@ div.plugin:not(:last-child) {
|
|||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
div.plugin h2.plugin-label {
|
||||
div.plugin > h1,
|
||||
div.plugin > h2,
|
||||
div.plugin > h3,
|
||||
div.plugin > h4,
|
||||
div.plugin > h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.plugin h2.plugin-label {
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
padding-bottom: 5px;
|
||||
text-transform: uppercase;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
@ -43,6 +79,8 @@ div.plugin ul {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
/* PLUGIN MENU */
|
||||
|
||||
div.plugin-menu li.menu:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
@ -50,3 +88,14 @@ div.plugin-menu li.menu:not(:last-child) {
|
|||
div.plugin-menu ul.submenu {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* PLUGIN PAGES */
|
||||
|
||||
div.plugin-pages li.parent h3 {
|
||||
margin-bottom: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.plugin-pages ul.child {
|
||||
margin-left: 5px;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -11,9 +11,15 @@
|
|||
<img src="<?php echo $page->coverImage() ?>" alt="<?php echo $page->slug() ?>">
|
||||
<?php } ?>
|
||||
</header>
|
||||
<?php echo $page->content() ?>
|
||||
<?php echo $page->contentBreak() ?>
|
||||
<footer>
|
||||
<div class="category"><i class="icon-price-tag"></i> <?php echo $page->category() ?></div>
|
||||
<?php if ($page->readMore() ) { ?>
|
||||
<div class="readmore">
|
||||
<a href="<?php echo $page->permalink() ?>">
|
||||
<i class="icon-arrow-down"></i> <?php echo $Language->get('Read more') ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</footer>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
|
|
20
install.php
20
install.php
|
@ -57,7 +57,7 @@ define('PATH_ABSTRACT', PATH_KERNEL.'abstract'.DS);
|
|||
define('CHECK_SYMBOLIC_LINKS', TRUE);
|
||||
|
||||
// Filename for posts and pages
|
||||
define('FILENAME', 'index.md');
|
||||
define('FILENAME', 'index.txt');
|
||||
|
||||
// Domain and protocol
|
||||
define('DOMAIN', $_SERVER['HTTP_HOST']);
|
||||
|
@ -321,7 +321,7 @@ function install($adminPassword, $email, $timezone)
|
|||
'description'=>$Language->get('About your site or yourself'),
|
||||
'username'=>'admin',
|
||||
'tags'=>array(),
|
||||
'status'=>'published',
|
||||
'status'=>'fixed',
|
||||
'date'=>$currentDate,
|
||||
'dateModified'=>'',
|
||||
'allowComments'=>true,
|
||||
|
@ -342,7 +342,7 @@ function install($adminPassword, $email, $timezone)
|
|||
'position'=>1,
|
||||
'coverImage'=>'',
|
||||
'md5file'=>'',
|
||||
'category'=>'',
|
||||
'category'=>'general',
|
||||
'uuid'=>md5(uniqid())
|
||||
)
|
||||
);
|
||||
|
@ -367,7 +367,7 @@ function install($adminPassword, $email, $timezone)
|
|||
'language'=>$Language->getCurrentLocale(),
|
||||
'locale'=>$Language->getCurrentLocale(),
|
||||
'timezone'=>$timezone,
|
||||
'theme'=>'editorial',
|
||||
'theme'=>'kernel-panic',
|
||||
'adminTheme'=>'default',
|
||||
'homepage'=>'',
|
||||
'itemsPerPage'=>6,
|
||||
|
@ -418,10 +418,7 @@ function install($adminPassword, $email, $timezone)
|
|||
file_put_contents(PATH_DATABASES.'syslog.php', $dataHead.json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||
|
||||
// File security.php
|
||||
$randomKey = sha1( uniqid() );
|
||||
|
||||
$data = array(
|
||||
'key1'=>$randomKey,
|
||||
'minutesBlocked'=>5,
|
||||
'numberFailuresAllowed'=>10,
|
||||
'blackList'=>array()
|
||||
|
@ -431,8 +428,9 @@ function install($adminPassword, $email, $timezone)
|
|||
|
||||
// File categories.php
|
||||
$data = array(
|
||||
'videos'=>array('name'=>'Videos', 'list'=>array()),
|
||||
'music'=>array('name'=>'Music', 'list'=>array())
|
||||
'general'=>array('name'=>'General', 'list'=>array()),
|
||||
'music'=>array('name'=>'Music', 'list'=>array()),
|
||||
'videos'=>array('name'=>'Videos', 'list'=>array())
|
||||
);
|
||||
file_put_contents(PATH_DATABASES.'categories.php', $dataHead.json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||
|
||||
|
@ -497,11 +495,11 @@ function install($adminPassword, $email, $timezone)
|
|||
);
|
||||
|
||||
// File for error page
|
||||
$data = 'Title: '.$Language->get('Error').PHP_EOL.'Content: '.$Language->get('The page has not been found');
|
||||
$data = 'Title: '.$Language->get('Error').PHP_EOL.'Content: '.PHP_EOL.$Language->get('installer-page-error-content');
|
||||
file_put_contents(PATH_PAGES.'error'.DS.FILENAME, $data, LOCK_EX);
|
||||
|
||||
// File for about page
|
||||
$data = 'Title: '.$Language->get('About').PHP_EOL.'Content: '.$Language->get('the-about-page-is-very-important').' '.$Language->get('change-this-pages-content-on-the-admin-panel');
|
||||
$data = 'Title: '.$Language->get('About').PHP_EOL.'Content: '.PHP_EOL.$Language->get('installer-page-about-content');
|
||||
file_put_contents(PATH_PAGES.'about'.DS.FILENAME, $data, LOCK_EX);
|
||||
|
||||
// File for welcome page
|
||||
|
|
Loading…
Reference in New Issue