// controllers/front/post.js
import config from '../../config.js'
import post from '../../views/front/post.jsx'
import postdb from '../../models/postdb.ts'
class Post{
async getOneItem(req, res){
this.config = await config()
this.config.pageTitle = 'ទំព័រការផ្សាយ'
this.config.route = '/'
let {item} = await postdb.getItem(req, 0)
this.config.post = item
const html = await post(this.config)
res.send(html)
}
}
export default new Post()
// models/postdb.js
interface PostSchema {
_id: ObjectId;
id: string;
title: string;
content: string;
categories: string[];
thumb: string;
postdate: string;
video: string;
userid: string;
}
class Postdb{
async count(req, query={}){
const posts = req.mydb.collection<PostSchema>("posts")
return await posts.countDocuments(query)
}
async insertPost(req){
const id = Date.now() + Math.round(Math.random() * 1E9).toString()
if(req.body.categories.includes(',')){
var categories: string[] = req.body.categories.split(',')
}else{
var categories: string[] = [req.body.categories]
}
const user_id = await req.session.get('user-id')
let newPost = {
id: id,
title: req.body.title,
content: req.body.content,
categories: categories,
thumb: req.body.thumb,
postdate: req.body.datetime,
video: req.body.video,
userid: user_id,
}
const posts = req.mydb.collection<PostSchema>("posts")
await posts.insertOne(newPost)
}
async getItem(req, amount, query={}){
const posts = req.mydb.collection<PostSchema>("posts")
let item = null
let items = null
if(req.params.id){
item = await posts.findOne({id: req.params.id})
}
if(amount){
items = await posts.find(query).sort({date:-1,_id:-1}).limit(amount).toArray()
}
return {item:item, items:items}
}
async editPost(req){
if(req.body.categories.includes(',')){
var categories: string[] = req.body.categories.split(',')
}else{
var categories: string[] = [req.body.categories]
}
let editPost = {$set:{
title: req.body.title,
content: req.body.content,
categories: categories,
thumb: req.body.thumb,
postdate: req.body.datetime,
video: req.body.video,
}}
const posts = req.mydb.collection<PostSchema>("posts")
await posts.updateOne({id: req.params.id}, editPost)
}
async deletePost(req){
const posts = req.mydb.collection<PostSchema>("posts")
if(req.params.id){
var item = await posts.findOne({id: req.params.id})
}
const user_id = await req.session.get('user-id')
const user_role = await req.session.get('user-role')
if(user_role in {'Admin':1,'Editor':1,'Author':1}){
if((user_role === 'Admin') || (user_id === item.userid)){
await posts.deleteOne({id: req.params.id})
}
}
}
}
export default new Postdb
// views/front/post.jsx
/** @jsx h */
import { h, renderSSR } from "../../deps.ts"
function PostJsx(props){
return(
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{props.config.siteTitle} | {props.config.pageTitle}</title>
<link href="/images/siteLogo.png" rel="icon" />
<link href="/styles/base.css" rel="stylesheet" />
<link href="/fonts/setup.css" rel="stylesheet" />
<script src="/scripts/jquery.js"></script>
<link rel="stylesheet" href="/styles/front/home.css" />
<link rel="stylesheet" href="/styles/front/menu.css" />
<link rel="stylesheet" href="/styles/front/single.css" />
<script src="/scripts/setPlayer.js"></script>
</head>
<body>
<section class="Home">
<header>
<div class="inner region">
<div class="title"><a href="/">{props.config.siteTitle}</a></div>
<form action="/search" method="post">
<select name='category'>
<option>ការផ្សាយ</option>
</select>
<input type="text" name="q" required placeholder="Search" />
<input type="submit" value="ស្វែងរក" />
</form>
<div class="login"><a href="/login">ចូលក្នុង</a> | <a href="#register">ចុះឈ្មោះ</a></div>
</div>
</header>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
<div class="menu">
<div class="innner region">
<div class="topnav" id="myTopnav">
<a href="/" class="active">Home</a>
<a href="#news">News</a>
<a href="#contact">Contact</a>
<a href="#about">About</a>
<span dangerouslySetInnerHTML={{__html: `
<a href="javascript:void(0);" class="icon" onclick='myFunction()'>
<i class="fa fa-bars"></i>
</a>
`}}/>
</div>
</div>
</div>
<script dangerouslySetInnerHTML={{__html: `
function myFunction() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive";
} else {
x.className = "topnav";
}
}
`}}/>
<div class="main region">
<div class="content">
<div class="Post">
<div class="title">{props.config.post.title}</div>
<div class="date">
{(new Date(props.config.post.postdate)).toLocaleDateString('it-IT')}
</div>
<div class="category">ជំពូកៈ {(props.config.post.categories).toString()}</div>
<div class="video">
<div class="screen"></div>
<div class="playlist"></div>
</div>
<script dangerouslySetInnerHTML={{__html: `
const videos = JSON.parse('${ props.config.post.video }')
videos.reverse()
let clicked = 0
for(let index in videos){
let ending = ''
if(index == videos.length-1){
ending = videos[index].status
}
let title = videos[index].title
let html = '<div id="part'+index+'" class="part" onClick="setScreen(videos['+index+'],'+index+',true)">${ props.config.post.title } ភាគ '+(++index)+' '+ending+'</div>'
$('.playlist').append(html)
}
setScreen(videos[0],0,false)
`}}/>
<div class="text-content" dangerouslySetInnerHTML={{__html: `
${props.config.post.content}
`}}/>
</div>
</div>
<div class="sidebar">Sidebar</div>
</div>
</section>
</body>
</html>
)
}
function Post(config){
const str = renderSSR(<PostJsx config={config} />)
const html = `<!DOCTYPE html>${str}`
return html
}
export default Post
//asset/js/setPlayer.js
function setScreen(entry,id,click){
if(entry['type'] == 'OK'){
var url = `//ok.ru/videoembed/${entry['id']}`
}else if(entry['type'] == 'YouTube'){
var url = `https://www.youtube.com/embed/${entry['id']}`
}else if(entry['type'] == 'YouTubePlaylist'){
var url = `https://www.youtube.com/embed/videoseries?list=${entry['id']}`
}else if(entry['type'] === "Facebook"){
var url = `https://www.facebook.com/watch/?v=${entry['id']}`
}else if(entry['type'] === "GoogleDrive"){
var url = `https://docs.google.com/file/d/${entry['id']}/preview`
}else if(entry['type'] === "Vimeo"){
var url = `https://player.vimeo.com/video/${entry['id']}`
}else if(entry['type'] === "Dailymotion"){
var url = `https://www.dailymotion.com/embed/video/${entry['id']}`
}
if(entry['type'] !== 'Facebook'){
var iframe = `<div>
<iframe id="video-player" src="${url}" frameborder="0" allowfullscreen></iframe>
</div>`;
}else{
var iframe = `<div class="fb-video" data-href="${url}" data-width="auto" data-show-captions="true"></div>`;
}
if(click){
$('.Post .video .playlist #part'+clicked)
.css({'background':'var(--background-light)','color':'black'})
}
$('.Post .video .playlist #part'+id)
.css({'background':'var(--background)','color':'white'})
$('.Post .video .screen').html(iframe)
if((entry['type'] === "Facebook")&&(fb_api)){
FB.XFBML.parse()
}
clicked = id
}
/* static/styles/front/single.css */
.Post .title{
font: 25px/1.5 Oswald, Limonf3;
padding-bottom: 20px;
}
.Post .category{
padding-bottom: 30px;
}
.Post .video{
padding-bottom: 20px;
}
.Post .video .screen{
position: relative;
padding-top: 56.25%;
}
.Post .video .screen iframe{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.Post .video .playlist{
max-height: 361px;
overflow: auto;
}
.Post .video .playlist .part{
padding: 10px;
font: bold 16px/1.5 Courgette, HandWriting;
background: lightgrey;
border: 1px solid grey;
border-top: none;
color: rgb(71, 71, 71);
}
.Post .video .playlist .part:first-child{
border-top: 1px solid grey;
}
.Post .video .playlist .part:hover{
cursor: pointer;
opacity: .7;
}
GitHub: https://github.com/Sokhavuth/khmerweb-deno
Deno Deploy: https://khmerweb-blog.deno.dev