Cavern

INFOR 31st

Tony Yang | t510599

> Explore those deep inside the cave.

Origin

▲ INFOR 31st Web Development 考幹題

then

▲ A buggy version

It's time to rewrite!

TOCASUI

  1. 更簡潔,沒有像 Bootstrap 那樣雜亂的樣式名稱(如:.m-l-1, .p-x-2, .p-a-3)

  2. 意義為樣式命名的主要精神

  3. 以支援行動裝置為優先

  4. 更加彈性的格線系統,並達到 16 格線

  5. 具有回饋力的動畫

  6. 元件之間可交互使用

  7. 模塊不需要 jQuery(耶!)

editormd

IMPLEMENTATION

front end

position: sticky

.comment.header {
   position: sticky;
   position: -webkit-sticky; /* Safari */
   top: 0;
}

REGEX

message.replace(regex, function (_match, name, id, _offset, _string) {
    return `<a href="user.php?username=${id}">${name}</a>`;
});
名稱 內容
match 匹配到的整段字串
p1, p2... 依照分組,依序填入的字串
offset 位置
string 將被替換的完整原始字串

參數

event delegation

bUBBLING AND CAPTURING

event delegation

WHY?

Example:

  • 1000 <tr> in a table
  • click event for every row

 

Normally we...

-> Create eventListener for each element.

 

It leads to:

-> 1000 eventListener

=> lag website

event delegation

$('tr').each((i, ele) => {
    $(ele).on('click', function(e) {
        let el = this;
        // do something
    });
});
$('table').on('click', 'tr', function(e) {
    let el = e.currentTarget;
    // do something
});

NORMAL

Delegation

Table

Table

tr

tr

tr

tr

tr

tr

IMPLEMENTATION

back end

PHP

\PHP 是世界上最棒的語言/

ob_start(), ob_flush(), ob_get_contents()
  • ob_start()
    • create new output buffer
  • ob_flush()
    • flush output buffer
  • ob_get_contents()
    • get output buffer content
include/view.php
class View {
    private $master_content;
    // some private attribute...

    public function __construct($master, $nav, $sidebar, $title, $part) {
        $this->load($master,$nav,$sidebar);
        ob_start();
    }

    private function load($master, $nav, $sidebar) {
        ob_start();
        include($master);
        $this->master_content = ob_get_contents();
        ob_end_clean();
        // load navbar and sidebar...
    }
    
    public function render() {
        $content = ob_get_contents();
        ob_end_clean();
        
        echo strtr($this->master_content, array(
            // ...
            '{content}' => $content
        ));
        @ob_flush();
        flush();
    }
};
filter_var()

You can validate or sanatize specific data.

filter_var($variable [, $filter = FILTER_DEFAULT [, $options ]])
Validate filters FILTER_VALIDATE_EMAIL
FILTER_VALIDATE_IP
FILTER_VALIDATE_URL
Sanatize filters FILTER_SANITIZE_EMAIL
FILTER_SANITIZE_URL

return sanatized value if pass

or otherwise return false

WAIT

SOME PHP NAMING

MySQL

inner join

SELECT `post`.*, `user`.name FROM `post` INNER JOIN `user`
ON `post`.username = `user`.username

Polling

flow

setInterval(() => {
    axios.request({
        url: "ajax/notification.php?fetch",
        method: "GET"
    }).done((res) => {
        setNotificationCounter(res.data);
    }).catch((err) => {
        console.error(err);
    });
});

CSRF

Login

SESSION_ID

example.blog

<img src="example.blog/post?del=1">

SESSION_ID

another.site

Post deleted!

concept

GET example.blog/post?del=1

SESSION & No Token

another.site

CSRF!

SOL:

DOUBLE SUBMIT COOKIE

GET example.blog/post?del=1

TOKEN

example.blog

Post deleted!

& X-CSRF-TOKEN

SOL:

DOUBLE SUBMIT COOKIE

axios.defaults.withCredentials = true;

axios.interceptors.request.use(function (config) {
    var crypto = window.crypto || window.msCrypto;
    let csrfToken = btoa(String(crypto.getRandomValues(new Uint32Array(1))[0]));
    document.cookie = `${axios.defaults.xsrfCookieName}=${csrfToken}; max-age=10; path=/`;
    return config;
}, function (error) {
    return Promise.reject(error);
});

Navigo

Create router

var root = "./";
var useHash = true;
var hash = "#";
let router = new Navigo(root, useHash, hash);

router.on({
    '/post': function () {
        render('post');
    },
    '/post/:id': function () {
        render('post', params.id);
    },
    '/user/:username': function () {
        render('user', params.username)
    }
}).resolve();

ROUTE HOOK

router.hooks({
    before: (done, params) => {
        resetMenu();
        done();
    },
    after: params => {
        scrollTop();
    }
});

navigo links

<a href="/post" data-navigo>文章列表</a>

Use data-navigo attribute

router.navigate("/post")

router.navigate()

router.updatePageLinks()

router.updatePageLinks()

final product

php project?

JavaScript 68.4% : PHP 27.3%

Libraries

Cavern is inspired by, and used code of secret-blog by gdsecret, which is licensed under AGPL v3.

  • TocasUI
  • edtiormd
  • jQuery
  • axios
  • navigo
  • sweetalert2
  • css.js (jotform/css.js)

FuTURE

  • get rid of secret-blog code
  • functional search bar
  • topic system
  • customize sidebar

Live demo

thanks for listening

Cavern

By Tony Yang

Cavern

Resonance - INFOR 31st x 32nd -- Cavern: A simple blog

  • 308