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
-
更簡潔,沒有像 Bootstrap 那樣雜亂的樣式名稱(如:.m-l-1, .p-x-2, .p-a-3)
-
以意義為樣式命名的主要精神
-
以支援行動裝置為優先
-
更加彈性的格線系統,並達到 16 格線
-
具有回饋力的動畫
-
元件之間可交互使用
-
模塊不需要 jQuery(耶!)
editormd
- Support Standard Markdown / CommonMark and GFM (GitHub Flavored Markdown)
- Real-time Preview, Preformatted text/Code blocks/Tables insert, Code syntax highlighting...;
- Support ToC (Table of Contents), Emoji, Task lists, @Links...;
- Support decode & fliter of the HTML tags & attributes;
- Support TeX (LaTeX expressions, Based on KaTeX), Flowchart and Sequence Diagram of Markdown extended syntax;
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
- 301