TV Channel Website: Admin Post Page
Tags: webdev, tutorial, python, bottle
Published: 2022-08-26 11:42:00

GitHub: [https://github.com/Sokhavuth/TV-Channel](https://github.com/Sokhavuth/TV-Channel)
Vercel: [https://khmerweb-tv-channel.vercel.app/login](https://khmerweb-tv-channel.vercel.app/login)
<br/>

<p>In the dashboard, post page is a place where we can prepare to publish video(s) with or without text. So we need a rich text editor to write text content and to embed pictures into the text.</p>

<p>Among rich text editor, we can use CKEditor 5 for free. It is a very good text editor; we can build and download it at <a href="https://ckeditor.com/ckeditor-5/online-builder/">https://ckeditor.com/ckeditor-5/online-builder/ </a></p>

<p>If we include CKEditor in a form with other input gadgets, the CKEDitor content will be automatically sent to the sever with other contents. And we can easily copy these contents to insert into our database.</p>

<p>However, we need to write some JavaScipt code to create video content or video playlist and to create a list of categories to be sent to the server.</p>

```html
<!--views/backend/index.tpl-->

<link rel="stylesheet" href="/static/styles/backend/index.css" />

<section class="Index">
    <header>
        <div class="inner region">
            <div class="page-title">{{ data["pageTitle"] }}</div>
            <form action="/admin/search" method="post">
                <select name="searchtype">
                    <option>Post</option>
                    <option>Category</option>
                    <option>User</option>
                </select>
                <input type="text" name="q" required />
                <input type="submit" value="Search" />
            </form>
            <div class="logout">
                {{ data["username"]}} | <a href="/">Home</a> | <a href="/login/logout">Logout</a>
            </div>
        </div>
    </header>

    <div class="main region">
        <div class="sidebar">
            <div class="inner">
                <a href="/admin/post"><img src="/static/images/movie.png" /></a>
                <a href="/admin/post">Post</a>

                <a href="/admin/category"><img src="/static/images/category.png" /></a>
                <a href="/admin/category">Category</a>

                <a href="/admin/upload"><img src="/static/images/upload.png" /></a>
                <a href="/admin/upload">Upload</a>

                <a href="/admin/user"><img src="/static/images/users.png" /></a>
                <a href="/admin/user">User</a>

                <a href="/admin/setting"><img src="/static/images/setting.png" /></a>
                <a href="/admin/setting">Settings</a>
            </div>
        </div>
        <div class="content">
            <%
            if("/post" in data["route"]):
                include("backend/post.tpl")
            end
            %>
        </div>
    </div>

    <div class="footer region">
        <div class="info">Total number of items:</div>
        <ul></ul>
        <div class="pagination">
            <img onclick="paginate(`{{ data['route'] }}`)" src="/static/images/load.png" />
        </div>

        <div class="credit">
            <a href="https://khmerweb.vercel.app/">&copy Khmer Web 2022</a>
        </div>
    </div>
</section>
```

```html
<!--views/backend/post.tpl-->

<link rel="stylesheet" href="/static/styles/backend/post.css" />
<script src="/static/scripts/ckeditor/ckeditor.js"></script>
<script src="/static/scripts/video.js"></script>
<script src="/static/scripts/addCategory.js"></script>

<section class="Post">
    <form action="/admin/post" method="post" name="form" onSubmit="submitForm(event)">
        <input type="text" name="tilte" required placeholder="Post title" />
        <textarea name="content" id="editor"></textarea>
        <input type="text" name="categories" required placeholder="Categories" />
        <div class="wrapper">
            <select id="category" onChange="getCategory()">
                <option>Slect a category</option>
                <option>News</option>
                <option>Entertainment</option>
                <option>Movie</option>
            </select>
            <input type="text" name="thumb" required placeholder="Thumbnail" />
            <input type="datetime-local" name="datetime" required />
            <input type="submit" value="Publish" />
        </div>
        <input name='videos' value='' type='hidden' />
    </form>
    <div class="video-wrapper" >
        <select name="type">
          <option>YouTube</option>
          <option>YouTubePL</option>
          <option>Facebook</option>
          <option>OK</option>
        </select>
        <input type="text" name="videoid" required placeholder="Video id" />
        <select name="status">
          <option>End</option>
          <option>Continue</option>
          <option>~ End</option>
        </select>
        <input onclick="genJson()" type="submit" value="Insert video" />
    </div>

    <div class='viddata'>
        <div></div>
    </div>

</section>
<script src="/static/scripts/ckeditor/config.js"></script>
```

```css
/* public/styles/backend/post.css */

.Post form .ck-editor__editable{
    min-height: 300px;
    color: black;
}

.Post input, .Post select{
    font: var(--body-font);
    padding: 2px 5px;
}

.Post input{
    width: 100%;
}

.Post form .wrapper, 
.Post .video-wrapper,
.Post .viddata div{
    display: grid;
    grid-template-columns: 20% 40% auto 15%;
}

.Post .viddata div{
    width: 100%;
}

.Post .viddata div p:hover{
    cursor: pointer;
    color: red;
}

.Post .viddata b,
.Post .viddata input,
.Post .viddata p{
    font: var(--body-font);
    padding: 3px 5px;
    background: rgb(208, 216, 228);
    border: 1px solid grey;
    text-align: center;
    color: black;
}

.Post .viddata input{
    background: white;
}
```

```js
// static/scripts/video.js

let episode = 0

const genJson = () => {
    let json = $('input[name="videos"]').val()
    if((json !== '')&&(json !== '[]')){
        json = JSON.parse(json)
        episode = json.length
    }else{
        episode = 0
    }

    const type = $('select[name="type"').val()
    const id = $('input[name="videoid"').val()
    const status = $('select[name="status"').val()
            
    let video = {
        type: type,
        id: id,
        status: status,
    }
        
    let success = false
    
    for(let v in video){
        if(video[v] === ''){
            alert('You need to fill the required field '+v)
            success = false
            break
        }else{
            success = true
        }
    }

    if(success){
        let json = $('input[name="videos"]').val()
        video = {
            type: type,
            id: id,
            status: status,
        }
        if((json === '')){
            json = JSON.stringify([video])
            $('input[name="videos"]').val(json)
        }else{
            json = JSON.parse(json)
            json.push(video)
            json = JSON.stringify(json)
            $('input[name="videos"').val(json)
        }

        let html =``

        for(let v in video){
            html += `<input value="${video[v]}" required />`
        }

        html += `<p title="Delete" onClick="deleteRow(event)" class="episode">${++episode}</p>`
        html = `<div>${html}</div>`
        
        if($('.viddata div').html() === ''){
            $('.viddata div').append('<b>Type​</b>')
            $('.viddata div').append('<b>Video id​</b>')
            $('.viddata div').append('<b>Status</b>')
            $('.viddata div').append('<b>Part/Delete</b>')
        }
        
        $('.viddata div:eq(0)' ).after(html)
    }
}

function submitForm(e){
    e.preventDefault()
    
    const is_video = $('input[name="videos"').val()

    if((is_video !== '') && (is_video !== '[]')){
        episode = JSON.parse(is_video).length
        let videos = []
        let part = {}
        let key = {0:'type', 1:'id', 2:'status'}

        for(let v=1; v<=episode; v++){
            for(let j=0; j<3; j++){
                part[key[j]] = $(`.viddata div:eq(${v}) input:eq(${j})`).val()
            }

            videos.push({...part})
        }
    
        const json = JSON.stringify(videos)
        $('input[name="videos"').val(json)
    }
    
    document.forms["form"].submit()
}

function deleteRow(e) {
    e.target.parentElement.remove()
    
    let index = parseInt(e.target.innerHTML)
    index = index - 1
    let json = $('input[name="videos"]').val()
    json = JSON.parse(json)
    json.splice(index, 1)
    episode = json.length
    json = JSON.stringify(json)
    $('input[name="videos"').val(json)

    for(let v=episode; v>-1; v--){
        $('.episode').eq(v).html(episode-v)
    }
}
```

```js
// static/scripts/addCategory.js 

function getCategory(){
    const category = $('#category option:selected').text()
    $('select').prop('selectedIndex',0)
    let categories = $('[name=categories]').val()
    if(categories === ''){
        categories += category
    }else{
        categories += (`, ${category}`)
    }
    
    $('[name=categories]').val(categories)
}
```