| <?php
    /*
        * SQLite Code Vault :: SQLite Snippets Manager :: Example Admin Page
        * 
        * @package SQLite Snippets Manager :: SQLiteCodeVault
        * @version 1.1
        * @author https://www.phpclasses.org/browse/author/144301.html
        * @link https://www.phpclasses.org/package/12863-PHP-SQLite-Code-Vault-is-a-PHP-SQLite-snippets-manager.html
        * @license BSD License
        * @filename sqlite-snippets-admin.php
        * 
        * please leave this comment block intact so others can find the original source.
        * 
        * description: An example admin page for SQLiteCodeVault class to manage code snippets in a SQLite database.
   
        // fixed up listing rows a bit for the add section update
        // added some classes to db for json
        // one day I will have to get in to clean this beast, but today isn't that day. Neither is tomorrow.
        // v1.1 has a json export/import feature
        // currently broken: using not in the search field (and/or work)
        // added copy button to copy the code to the clipboard
        // added syntax highlighting and theme dropdown for syntax highlighting
        // added copy json button to copy the json to the clipboard
        // added cookie storing ability to remember the last used theme
        // created a cookie management javascript class for the ace.js code editor
        // created a jquery plugin to:
        // - handle the cookie management for combo boxes
        // - attach the ace.js code editor to the code textarea
        // - this was not fun :( but hey it works.
        // -- adds all sorts of cool ways to edit your code with syntax highlighting, error checking, autoindent, etc. 
        // -- so using highlight.js for the listings and ace.js for the code editor. Note: only currently attached to update code section, but easy enough to add to add section which I will do if everything runs smooth in the update section, which I highly doubt, but hey, fingers crossed.        
        
        // fixed some width issues with the page.
    */
    ob_start();
    session_start();
    // Include SQLiteCodeVault class
    require_once 'sqlite-snippets-manager.php';
    // Initialize the class
    $snippets = new PHPSQLiteCodeVault();
    function get_snippet_data_html($snippet_row)
    {
        global $snippets;
        $html = "";
        
        // create a page anchor
        $html .= "<a name='" . $snippet_row['id'] . "'></a>";
        $html .= "<div class='title'>" . $snippet_row['title'] . "</div>";
        $html .= "<div class='subcontent' style='display:none'>";
            $html .= "<div class='code-snippet' data-id='" . $snippet_row['id'] . "'>" . $snippet_row['code'] . "</div>";
            $html .= "<div class='json-row'>";
                $html .= "<div class=' json-title'>JSON Export:</div>";
                $html .= "<div class=' json'><textarea class='json-textarea' data-id='" . $snippet_row['id'] . "'>" . $snippets->snippet_to_json_str($snippet_row) . "</textarea></div>";
            $html .= "</div><!-- end json-row -->";
            $html .= "<div class='subinfo'>";
                $html .= "<div class='language'>language: " . $snippet_row['language'] . "</div>";
                $html .= "<div class='tags'>tags: " . $snippet_row['tags'] . "</div>";
                $html .= "<div class='author'>author: " . $snippet_row['author'] . "</div>";
                $html .= "<div class='license'>license: " . $snippet_row['license'] . "</div>";
                $html .= "<div class='timestamp'>" . date('Y-m-d H:i:s', $snippet_row['timestamp']) . "</div>";
            $html .= "</div><!-- end subinfo -->";
            
            $html .= "<div class='actions'>";
                $html .= '<div><button class="copyBtn" data-id="' . $snippet_row['id'] . '">Copy</button></div>';
                $html .= '<div><button class="copyJsonBtn" data-id="' . $snippet_row['id'] . '">Copy JSON</button></div>';
                $html .= "<div><button class='editBtn' data-id='" . $snippet_row['id'] . "' data-title='" . $snippet_row['title'] . "' data-code='" . htmlentities($snippet_row['code']) . "' data-language='" . $snippet_row['language'] . "' data-tags='" . $snippet_row['tags'] . "' data-author='" . $snippet_row['author'] . "' data-license='" . $snippet_row['license'] . "'>Edit</button></div>";
                $html .= '<div><button class="deleteBtn" data-id="' . $snippet_row['id'] . '">Delete</button></div>';
            $html .= "</div>";
        $html .= "</div><!-- end subcontent -->";
        return $html;
    }
    function get_snippet_html($snippet_row, $evenodd="odd")
    {
        // make safe for html
        $snippet_row['title']       = htmlspecialchars($snippet_row['title']);
        $snippet_row['code']        = htmlspecialchars($snippet_row['code']);
        $snippet_row['language']    = htmlspecialchars($snippet_row['language']);
        $snippet_row['tags']        = htmlspecialchars($snippet_row['tags']);
        $snippet_row['author']      = htmlspecialchars($snippet_row['author']);
        $snippet_row['license']     = htmlspecialchars($snippet_row['license']);
        // Return HTML for a snippet
        $html = "";
        $html .= "<div class='snippet $evenodd' data-id='" . $snippet_row['id'] . "'>";
        $html .= "<div class='snippet-data' data-id='" . $snippet_row['id'] . "'>";
        $html .= get_snippet_data_html($snippet_row);
        $html .= "</div>";
        $html .= "</div>";
        return $html;
    }
    function get_snippets_html()
    {
        global $snippets;
        // Return HTML for all snippets to go in .snippets div
        $html = "";
        /*
            $evenodd = 'odd';
            foreach ($snippetsList as $snippet) { 
                echo get_snippet_html($snippet, $evenodd);
                if ($evenodd == 'odd') 
                    $evenodd = 'even';
                else 
                    $evenodd = 'odd';
            } 
        */
        // if $_SESSION['search'] is set, then search for snippets
        if (isset($_SESSION['search']) && !empty(trim($_SESSION['search']))) {
            $snippetsList = $snippets->fuzzySearch($_SESSION['search']);
        } else {
            // If no search is submitted, get all snippets from database
            $snippetsList = $snippets->getAllSnippets();
        }
        $evenodd = "odd";
        foreach ($snippetsList as $snippet) {
            $html .= get_snippet_html($snippet, $evenodd);
            if ($evenodd == "odd") {
                $evenodd = "even";
            } else {
                $evenodd = "odd";
            }
        }
        return $html;
    }
        // If the form is submitted to add a new snippet
        if (isset($_POST['addSnippet'])) {
            // Get form data and add snippet to database
            $snippets->addSnippet($_POST['title'], $_POST['code'], $_POST['language'], $_POST['tags'], $_POST['author'], $_POST['license'], time());
        }
        // If the form is submitted to update a snippet
        if (isset($_POST['updateSnippet'])) {
            // Get form data and update snippet in database
            $snippets->saveSnippet($_POST['id'], $_POST['title'], $_POST['code'], $_POST['language'], $_POST['tags'], $_POST['author'], $_POST['license'], time());
        }
        // If the form is submitted to search for snippets
        if (isset($_POST['searchSnippet'])&& !empty(trim($_POST['search']))) {
            // Get form data and search for snippets in database
            # $snippetsList = $snippets->getSnippetsBySearch($_POST['search']);
            
            // $snippetsList = $snippets->fuzzySearch($_POST['search']);
            $_SESSION['search'] = $_POST['search'];
        } else 
        if (isset($_POST['searchSnippet']) && empty(trim($_POST['search']))) {
            $_SESSION['search'] = '%';
        }
        
        // else {
        //     // If no search is submitted, get all snippets from database
        //     // $snippetsList = $snippets->getAllSnippets();
        //     $_SESSION['search'] = '';
        // }
    if (isset($_GET['cmd']) && $_GET['cmd'] == 'ajax') {
        // If the request is an AJAX request, return the snippets list and quit
        # echo $snippetsList;
        // $evenodd = "odd";
        // foreach ($snippetsList as $snippet) {
        //     echo get_snippet_html($snippet, $evenodd);
        //     if ($evenodd == "odd") {
        //         $evenodd = "even";
        //     } else {
        //         $evenodd = "odd";
        //     }
        // }
        echo get_snippets_html();
        exit;
    } // end if ajax
?><?php
/*
            // Cancel page reload on form submit for update snippet form
            $('#updateSnippetForm form').submit(function(e) {
                // Get form data
                var id = $('#updateSnippetForm').find('input[name="id"]').val();
                var title = $('#updateSnippetForm').find('input[name="title"]').val();
                var code = $('#updateSnippetForm').find('textarea[name="code"]').val();
                var language = $('#updateSnippetForm').find('input[name="language"]').val();
                var tags = $('#updateSnippetForm').find('input[name="tags"]').val();
                var author = $('#updateSnippetForm').find('input[name="author"]').val();
                var license = $('#updateSnippetForm').find('input[name="license"]').val();
                
                // Update snippet in database
                $.ajax({
                    url: 'sqlite-snippets-admin.php?cmd=ajax',
                    type: 'post',
                    data: {
                        updateSnippet: true,
                        id: id,
                        title: title,
                        code: code,
                        language: language,
                        tags: tags,
                        author: author,
                        license: license
                    },
                    success: function(response) {
                        // If snippet is updated successfully, reload the snippet list
                        $('#snippetsList').html(response);
                        alert('Snippet updated successfully!');
                    }
                });
            
                e.preventDefault();
                
            }); // end -- update snippet form submit
*/
// --- BEGIN --- PHP SIDE OF COMMAND PROCESSOR
if(!empty($_GET['ajax']))
{        
    switch($_GET['ajax'])
    {
        case 'add-from-json':
            $json = $_POST['flds']['json'];
            $snippets->snippet_from_json_str_to_db($json);
            $return_arr[] = array(
                "command" 	=> 'alert',
                "process" 	=> "add-from-json",
                "msg" 		=> "added from json"
            );
            // update snippet list
            $return_arr[] = array(
                "command" 	=> 'html',
                "selector" 	=> ".snippets",
                "msg" 		=> get_snippets_html()
            );
            $return_arr[] = array(
                "command" 	=> 'html',
                "selector" 	=> "#snippetCount",
                "msg" 		=> $snippets->getSnippetCount()." Snippets in DB"
            );
        
            break;
        case 'update':
            $id             = $_POST['flds']['id'];
            $title          = $_POST['flds']['title'];
            $code           = $_POST['flds']['code'];
            $language       = $_POST['flds']['language'];
            $tags           = $_POST['flds']['tags'];
            $author         = $_POST['flds']['author'];
            $license        = $_POST['flds']['license'];
            if(empty($id))
            {
                $return_arr[] = array(
                    "command" 	=> 'alert',
                    "process" 	=> "update",
                    "msg" 		=> "id is empty for update"
                );
            }
            else
            {
                // update ( saveSnippet($id, $title, $code, $language, $tags, $author, $license, $timestamp) )
                $snippets->saveSnippet($id, $title, $code, $language, $tags, $author, $license, time());
                $return_arr[] = array(
                    "command" 	=> 'alert',
                    "process" 	=> "update",
                    "msg" 		=> "updated id: $id"
                );
                $snippet = $snippets->getSnippetById($id);
                ## print_r($snippet['code']);
                // for sending back to a <pre></pre> fix the stripping of <html> tags
                $snippet['code'] = htmlspecialchars($snippet['code']);
                $return_arr[] = array(
                    "command" 	=> 'html',
                    "selector" 	=> ".snippet-data[data-id='$id']",
                    "msg" 		=> get_snippet_data_html($snippet)
                    // "msg" 		=> get_snippet_data_html($snippets->getSnippetById($id))
                );
                // $return_array[] = array(
                //     "command" 	=> 'html',
                //     "selector" 	=> '.snippet12',
                //     // "msg" 		=> get_snippet_html($snippets->getSnippetById($id))
                //     "msg" 		=> '....'
                // );
                // print_r($return_array);
            }
            break; // end -- update snippet
        case 'delete':
            $id = $_POST['flds']['id'];
            if(empty($id))
            {
                $return_arr[] = array(
                    "command" 	=> 'alert',
                    "process" 	=> "delete",
                    "msg" 		=> "id is empty for delete"
                );
            }
            else
            {
                // delete ( deleteSnippet($id) )
                $snippets->deleteSnippet($id);
                $return_arr[] = array(
                    "command" 	=> 'alert',
                    "process" 	=> "delete",
                    "msg" 		=> "deleted id: $id"
                );
                $return_arr[] = array(
                    "command" 	=> 'html',
                    "selector" 	=> "#snippetCount",
                    "msg" 		=> $snippets->getSnippetCount()." Snippets in DB"
                );
    
            }
            break; // end -- delete snippet
        
        
    }
    if(!empty($return_arr) && is_array($return_arr))
    die(json_encode($return_arr));
    die(); // ajax request, so just quit instead of showing a page
}
// --- END --- PHP SIDE OF COMMAND PROCESSOR
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Snippet Manager</title>
    <link rel="stylesheet" href="style.css">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function() {
            // Show add snippet form when add button is clicked
            $('#addBtn').click(function() {
                $('#addSnippetForm').toggle();
            });
            // Hide add snippet form when cancel button is clicked
            $('#cancelBtn').click(function() {
                $('#addSnippetForm').hide();
            });
            // Cancel page reload on form submit for add snippet form
            $('#addSnippetForm form').submit(function(e) {
                // Get form data
                var title = $('#addSnippetForm').find('input[name="title"]').val();
                var code = $('#addSnippetForm').find('textarea[name="code"]').val();
                var language = $('#addSnippetForm').find('input[name="language"]').val();
                var tags = $('#addSnippetForm').find('input[name="tags"]').val();
                var author = $('#addSnippetForm').find('input[name="author"]').val();
                var license = $('#addSnippetForm').find('input[name="license"]').val();
                
                // Add snippet to database
                $.ajax({
                    url: 'sqlite-snippets-admin.php?cmd=ajax',
                    type: 'post',
                    data: {
                        addSnippet: true,
                        title: title,
                        code: code,
                        language: language,
                        tags: tags,
                        author: author,
                        license: license
                    },
                    success: function(response) {
                        // If snippet is added successfully, reload the snippet list
                        $('#snippetsList').html(response);
                        alert('Snippet added successfully!');
                    }
                
                });
                e.preventDefault();
            });
            
            // Cancel page reload on form submit for update snippet form
            // OBSOLETE.. Now using command processor
            $('#updateSnippetForm form').submit(function(e) {
                // Get form data
                var id = $('#updateSnippetForm').find('input[name="id"]').val();
                var title = $('#updateSnippetForm').find('input[name="title"]').val();
                var code = $('#updateSnippetForm').find('textarea[name="code"]').val();
                var language = $('#updateSnippetForm').find('input[name="language"]').val();
                var tags = $('#updateSnippetForm').find('input[name="tags"]').val();
                var author = $('#updateSnippetForm').find('input[name="author"]').val();
                var license = $('#updateSnippetForm').find('input[name="license"]').val();
                
                // Update snippet in database
                $.ajax({
                    url: 'sqlite-snippets-admin.php?cmd=ajax',
                    type: 'post',
                    data: {
                        updateSnippet: true,
                        id: id,
                        title: title,
                        code: code,
                        language: language,
                        tags: tags,
                        author: author,
                        license: license
                    },
                    success: function(response) {
                        // If snippet is updated successfully, reload the snippet list
                        $('#snippetsList').html(response);
                        alert('Snippet updated successfully!');
                    }
                });
            
                e.preventDefault();
                
            }); // end -- update snippet form submit
            // Show edit snippet form when edit button is clicked (handle dynamically created edit buttons too)
            // $('.editBtn').click(function() { // old way
            $(document).on('click', '.editBtn', function() {
                var id = $(this).data('id');
                var title = $(this).data('title');
                var code = $(this).data('code');
                var language = $(this).data('language');
                var tags = $(this).data('tags');
                var author = $(this).data('author');
                var license = $(this).data('license');
                
                // code is escaped so unescape it
                const parser = new DOMParser();
                const doc = parser.parseFromString(code, 'text/html');
                code = doc.documentElement.textContent;
                $('#updateSnippetForm').find('input[name="id"]').val(id);
                $('#updateSnippetForm').find('input[name="title"]').val(title);
                $('#updateSnippetForm').find('textarea[name="code"]').val(code);
                $('#updateSnippetForm').find('input[name="language"]').val(language);
                $('#updateSnippetForm').find('input[name="tags"]').val(tags);
                $('#updateSnippetForm').find('input[name="author"]').val(author);
                $('#updateSnippetForm').find('input[name="license"]').val(license);
                $('#updateSnippetForm').show();
                // scroll to #updateSnippetForm
                $('html, body').animate({
                    scrollTop: $("#updateSnippetForm").offset().top
                }, 1000);
            });
            // Hide edit snippet form when cancel button is clicked
            $('#cancelBtn').click(function() {
                $('#updateSnippetForm').hide();
            });
        });
    </script>
</head>
<body>
<div class='row'>
    <div class='col'><h1 id='pageTtl'>Snippet Manager</h1></div>
    <div class='col'><button id="addBtn">Show/Hide Add Snippet</button></div>
    </div>
    <style>
        body {
            font-family:arial;
        }
        .row {
            display:flex;
            flex-direction:row;
            justify-content:space-between;
            align-items:center;
            margin:2vw;
        }
        .col {
            flex:1;
        }
        
        #pageTtl {
            margin-top:12px;
            font-size:2min;
        }
        
        #addBtn {
            float:right;
            margin-top:0;
        }
        #snippetCount {
            position:fixed;
            /* top:0; */
            bottom:0px;
            /* right:10px; */
            left:50%;
            transform:translateX(-50%);
            background-color: #fff;
            padding: 10px 20px;
            margin-top:0px;
            z-index:9999;
            border:1px solid #ccc;
            cursor:pointer;
        }
    </style>
    <div id="snippetCount"><?php echo $snippets->getSnippetCount(); ?> Snippets in DB</div>
    <div id="addSnippetForm" style="display:none;">
        <style>
            #addSnippetFromJson {
                margin: 20px 0;
            }
            #addSnippetFromJson .fld {
                margin: 5px 0;
            }
            #addSnippetFromJson .fld input {
                width: 100%;
                padding-top:1em;
                padding-bottom:1em;
            }
        </style>
        <div id="addSnippetFromJson">
            <div class='title'><h2>Add Snippet From JSON</h2></div>
            <div class='fld'><input type="text" name="json" placeholder="JSON" required></div>
            <div class='fld'><input type="button" class="addJsonBtn" name="addSnippetFromJson" value="Add Snippet From JSON"></div>
        </div>
        <h2>Add Snippet</h2>
        <form>
            <input type="text" name="title" placeholder="Title" required>
            <textarea class='code-textarea' name="code" placeholder="Code" required></textarea>
            <input type="text" name="language" placeholder="Language" required>
            <input type="text" name="tags" placeholder="Tags" required>
            <input type="text" name="author" placeholder="Author" required>
            <input type="text" name="license" placeholder="License" required>
            <input type="submit" name="addSnippet" value="Add Snippet">
        </form>
    </div>
    <br />
    <div id="updateSnippetForm" style="display:none;">
        <h2>Edit Snippet</h2>
        <!-- just have action cancel page reload -->
        <form action="return false;">
            <input type="hidden" name="id">
            <input type="text" name="title" placeholder="Title" required>
            <textarea class='code-textarea use_ace_edit' name="code" placeholder="Code" required></textarea>
            <input type="text" name="language" placeholder="Language" required>
            <input type="text" name="tags" placeholder="Tags" required>
            <input type="text" name="author" placeholder="Author" required>
            <input type="text" name="license" placeholder="License" required>
            <!-- <input type="submit" name="updateSnippet" value="Update Snippet"> -->
            <input type="button" id="updateBtn" value="Update">
            <input type="button" id="cancelBtn" value="Cancel">
        </form>
    </div>
    <form method="post">
        <input type="text" name="search" placeholder="Search Snippets">
        <input type="submit" name="searchSnippet" value="Search">
    </form>
    
    <h2>Snippets List:<?php if(!empty($_SESSION['search'])) echo ' (Search: ' . $_SESSION['search']. ')'; ?></h2>
    <div id="snippetsList">
        <div class='snippets'>
            <?php 
            echo get_snippets_html();
            // $evenodd = 'odd';
            // foreach ($snippetsList as $snippet) { 
            //     echo get_snippet_html($snippet, $evenodd);
            //     if ($evenodd == 'odd') 
            //         $evenodd = 'even';
            //     else 
            //         $evenodd = 'odd';
            // } 
            ?>
        </div>
            
    </div>
    <script>
// BEGIN --> JAVASCRIPT COMMAND PROCESSOR //
            function do_cmd_post(url, send_data)
            {
                $.post( url, { 
                    flds: send_data /* in php will appear as $_POST['flds']  */ }, 
                    function( return_data ) { 
                    do_cmd_process(return_data); 
                    }, "json" ); // punt any returned data to processor
                    
            }
            // ---
            function do_cmd_process(data) // handle data coming back from ajax
            {
                if (data instanceof Array) {
                    data.forEach(function(entry) {
                        console.log(entry.command);
                        
                        //console.log(entry.message);
                        // handle returned commands //
                        switch(entry.command)
                        {
                            // generic commands //
                            case 'alert':
                                alert(entry.msg);
                                break;
                            case 'log':
                                console.log(entry.msg);
                                break;
                            case 'append':
                                $(entry.selector).append(entry.msg);
                                break;
                            case 'prepend':
                                $(entry.selector).prepend(entry.msg);
                                break;
                            case 'html':
                                $(entry.selector).html(entry.msg);
                                break;
                            case 'val':
                                $(entry.selector).val(entry.msg);
                                break;
                            case 'focus':
                                $(entry.selector).focus();
                                break;
                            case 'blur':
                                $(entry.selector).blur();
                                break;
                            case 'clear':
                                $(entry.selector).val('');
                                break;
                            case 'js':
                                eval(entry.msg);
                                break;
                            case 'resize_textarea_to_fit_contents':
                                $(entry.selector).height(0);
                                $(entry.selector).height($(entry.selector)[0].scrollHeight);
                                break;
                            case 'disable_input':
                                $(entry.selector).prop('disabled', true);
                                break;
                            case 'enable_input':
                                $(entry.selector).prop('disabled', false);
                                break;
                            case 'resize_textareas':
                                $(".message_content textarea").each(function(){
                                    $(this).css("height", ($(this).prop("scrollHeight")) + "px");
                                });
                                break;
                        } // end switch
                    });
                }
            }
// END --> JAVASCRIPT COMMAND PROCESSOR //
    $(document).ready(function() {
            // handle copy json button
            $(document).on('click', '.copyJsonBtn', function() {
                // get id from attr on button called data-id
                var id = $(this).attr('data-id');
                // get text from a dynamic element .code-snippet with a data-id of id
                var text_fld = $('.json-textarea[data-id="' + id + '"]').val();
                // now copy text_fld to clipboard
                // create a temporary input element
                var $temp = $("<input>");
                // add it to the document
                $("body").append($temp);
                // set the value of the input to the text_fld
                $temp.val(text_fld).select();
                // copy the text to the clipboard
                document.execCommand("copy");
                // remove the temporary input
                $temp.remove();
                alert('copied json to clipboard');
                
            }); // end -- handle copy json button
            // handle copy button
            $(document).on('click', '.copyBtn', function() {
                // get id from attr on button called data-id
                var id = $(this).attr('data-id');
                // get text from a dynamic element .code-snippet with a data-id of id
                var text_fld = $('.code-snippet[data-id="' + id + '"]').text();
                // now copy text_fld to clipboard
                // create a temporary input element
                var $temp = $("<input>");
                // add it to the document
                $("body").append($temp);
                // set the value of the input to the text_fld
                $temp.val(text_fld).select();
                // copy the text to the clipboard
                document.execCommand("copy");
                // remove the temporary input
                $temp.remove();
                alert('copied source code to clipboard');
                
            }); // end -- handle copy button
            // on click a dynamically created .addJsonBtn
            // add snippet from json
            $(document).on('click', '.addJsonBtn', function() {
                // get json from input
                var json = $('input[name="json"]').val();
                var send_data   = {
                    //"file": $('select[name="conversation_combobox"]').val()
                    "json": json
                };
                do_cmd_post('sqlite-snippets-admin.php?ajax=add-from-json', send_data);
            }); // end -- add snippet from json
            //  on click a dynamically created .deleteBtn 
            // delete button will alert ('hi')
            $(document).on('click', '.deleteBtn', function() {
                // confirm delete
                if(!confirm('Are you sure you want to delete this snippet?'))
                    return;
                // get id from attr on button called data-id
                var id = $(this).attr('data-id');
                var send_data   = {
                    //"file": $('select[name="conversation_combobox"]').val()
                    "id": id
                };
                // hide .snippet with data-id = id
                $('.snippet[data-id="' + id + '"]').hide();
                do_cmd_post('sqlite-snippets-admin.php?ajax=delete', send_data);
            }); // end -- delete snippet
            // updateBtn
            $(document).on('click', '#updateBtn', function() {
                // get id from attr on button called data-id
                var id = $('#updateSnippetForm').find('input[name="id"]').val();
                var send_data   = {
                    //"file": $('select[name="conversation_combobox"]').val()
                    "id": id,
                    "title": $('#updateSnippetForm').find('input[name="title"]').val(),
                    "code": $('#updateSnippetForm').find('textarea[name="code"]').val(),
                    "language": $('#updateSnippetForm').find('input[name="language"]').val(),
                    "tags": $('#updateSnippetForm').find('input[name="tags"]').val(),
                    "author": $('#updateSnippetForm').find('input[name="author"]').val(),
                    "license": $('#updateSnippetForm').find('input[name="license"]').val()
                };
                do_cmd_post('sqlite-snippets-admin.php?ajax=update', send_data);
            }); // end -- update snippet
    });
</script>
<style>
    .snippet {
        position:relative;
        display:block;
        border: 1px solid #ccc;
    }
    .snippet-data {
        position:relative;
        display:block;
    }
    
    .snippet .actions {
        position:relative;
        display:block;
        text-align:right;
        
    }
    .snippet .actions div,
    .snippet-data div  {
        display:inline-block;
        padding:1vw;
    }
    .snippet .actions div {
        cursor:pointer;
    }
    .snippet.even {
        background-color:#bbb;
    }
    .snippet.odd {
        background-color:#ddd;
    }
/* ****************************************** */
/* Container */
#addSnippetForm, #updateSnippetForm {
  background-color: #f2f2f2;
  border-radius: 5px;
  padding: 20px;
  width: 80%;
  margin: 0 auto;
  box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
}
/* Form elements */
input[type=text],
input[type=submit],
textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
  resize: vertical;
  font-size: 16px;
  font-family: "Arial", sans-serif;
  margin-bottom: 12px;
}
textarea {
  min-height: 100px;
}
/* Placeholder styling */
input[type=text]::placeholder,
textarea::placeholder {
  color: #999;
  font-style: italic;
}
/* Submit button */
input[type=submit] {
  background-color: #04AA6D;
  color: white;
  cursor: pointer;
  transition: background-color 0.2s;
}
input[type=submit]:hover {
  background-color: #048458;
}
/*  button */
input[type=button] {
    background-color: #007bff;
  border: none;
  border-radius: 4px;
  color: white;
  cursor: pointer;
  font-family: 'Roboto', sans-serif;
  font-size: 0.9rem;
  padding: 0.5rem 1rem;
  text-transform: uppercase;
}
input[type=button]:hover {
    background-color: #0056b3;
}
/* Form headings */
 h2 {
  font-size: 24px;
  font-weight: bold;
  margin-bottom: 20px;
}
/* --- */
.snippets {
  display: grid;
  /* grid-template-columns: repeat(auto-fill, minmax(1400px, 1fr)); */
  grid-gap: 1rem;
  margin: 1rem;
}
.snippet {
  background-color: #f9f9f9;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  padding: 1rem;
  font-family: 'Roboto', sans-serif;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.snippet-data {
  display: flex;
  flex-direction: column;
}
.title,
.language,
.tags,
.author,
.license,
.timestamp {
  font-size: 0.9rem;
  margin-bottom: 0.5rem;
}
.title {
  font-weight: bold;
  font-size: 1.1rem;
  margin-bottom: 0.8rem;
  /* border-bottom: 1px solid #e0e0e0; */
  /* make nicer */
    padding-bottom: 0.5rem;
    cursor:pointer;
}
.code-snippet {
  background-color: #f0f0f0;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  padding: 0.5rem;
  font-family: 'Courier', monospace;
  white-space: pre-wrap;
  overflow-x: auto;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-top: 1rem;
}
button {
  background-color: #007bff;
  border: none;
  border-radius: 4px;
  color: white;
  cursor: pointer;
  font-family: 'Roboto', sans-serif;
  font-size: 0.9rem;
  padding: 0.5rem 1rem;
  text-transform: uppercase;
}
button:hover {
  background-color: #0056b3;
}
.code-snippet .subinfo {
  display: flex;
  justify-content: space-between;
  margin-top: 1rem;
}
.code-snippet .subinfo .left {
  display: flex;
  flex-direction: column;
}
.code-snippet .subinfo .right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
.code-snippet .subinfo .left .language,
.code-snippet .subinfo .left .tags,
.code-snippet .subinfo .left .author,
.code-snippet .subinfo .left .license {
  font-size: 0.9rem;
  margin-bottom: 0.5rem;
}
.code-snippet .subinfo .right .timestamp {
  font-size: 0.9rem;
  margin-bottom: 0.5rem;
}
.json-row {
    position:relative;
    display: block;
    justify-content: space-between;
    margin-top: 1rem;
    width:100%;
    
}
.json-row div 
{
    position:relative;
    display:block;
    width:97%;
    margin:0;
    padding:0;
}
.json-row textarea {
    width:100%;
}
/* --- */
</style>
<script>
    /* when snippet-data .title is clicked, toggle the code snippet (nearest .subcontent section) */
    $(document).ready(function(){
        // $(".snippet-data .title").click(function(){
        //     $(this).next(".subcontent").slideToggle("slow");
        // });
        /* handle dynamic */
        $(document).on('click', '.snippet-data .title', function(){
            $(this).next(".subcontent").slideToggle("fast");
        });
    });
</script>
            
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/default.min.css"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/monokai.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github.min.css">
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/atom-one-dark.min.css"> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<style>
    .highlight-theme {
        position:fixed;
        bottom:0px;
        left:0px;
        margin:2px;
    }
    .highlight-theme-label {
        position:fixed;
        bottom:22px;
        left:0px;
        margin:2px;
        font-size:0.8rem;
        font-weight:bold;
    }
</style>
<!-- label for select -->
<label class='highlight-theme-label' for="highlight-theme">Highlight.js theme:</label>
<select name='highlight-theme' class='highlight-theme' onchange="switch_highlight_theme(this.value)">    
    <option value='github' SELECTED>github</option>
    <!-- <option value='default'>default</option> -->
    <!-- <option value='monokai'>monokai</option> -->
    <!-- <option value='atom-one-dark'>atom-one-dark</option> -->
    <!-- <option value='nord'>nord</option> -->
    <!-- a11y-dark,a11y-light,agate,an-old-hope,androidstudio,arduino-light,arta,ascetic,atom-one-dark-reasonable,atom-one-light,brown-paper,dark,github-dark-dimmed,github-dark --> 
    <!-- <option value='github-dark'>github-dark</option> -->
    <!-- <option value='a11y-dark'>a11y-dark</option> -->
    <option value='a11y-light'>a11y-light</option>
    <!-- <option value='agate'>agate</option> -->
    <option value='arduino-light'>arduino-light</option>
    <!-- <option value='arta'>arta</option> -->
    <!-- <option value='atom-one-dark-reasonable'>atom-one-dark-reasonable</option> -->
    <option value='googlecode'>googlecode</option>
    <option value='intellij-light'>intellij-light</option>
    <!-- <option value='kimbie-light'>kimbie-light</option> -->
</select>
<script>
    function getCookie(cname) 
    {
        var name = cname + "=";
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        // console.log(ca);
        for(var i = 0; i <ca.length; i++) 
        {
            var c = ca[i];
            // console.log(c);
            while (c.charAt(0) == ' ') 
            {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) 
            {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }
    // if there is a cookie set, switch to that theme
    // on document ready
    $(document).ready(function(){
        var highlight_theme = getCookie('highlight-theme');
        if (highlight_theme != "") {
            switch_highlight_theme(highlight_theme);
        }
    });
    function switch_highlight_theme(themename)
    {
        /* save a cookie with current highlight */
        document.cookie = "highlight-theme="+themename+"; path=/; SameSite=None; Secure";
        // remove all highlight.js stylesheets
        $('link[href*="highlight.js"]').remove();
        // add the new one
        $('head').append('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/'+themename+'.min.css">');
        // update the highlights
        update_highlights();
    }
</script>
<style>
/* for highlights */
.code-snippet {
    background-color:#fff;
        /* color:#fff; */
        padding:1rem;
        border:1px solid #333;
}
</style>
<script>
    function update_highlights()
    {
        $(document).ready(function() {
            // update_highlights();
            document.querySelectorAll('#code-textarea,.code-snippet').forEach(el => {
                // if we do not already have a highlit element then..
                if (!el.classList.contains('hljs')) 
                {
                    // escape the text //
                    el.innerHTML = el.innerHTML.replace(/</g, '<').replace(/>/g, '>');
                    hljs.highlightElement(el);
                }
            });
        });
    };
    update_highlights();
    // when a .title is clicked, update_highlights
    $(document).ready(function(){
        $(document).on('click', '.snippet-data .title', function(){
            update_highlights();
        });
    });
</script>
<!-- BEGIN BEGIN BEGIN BEGIN -- ace.js code editor (my js cookie class and jq plugin) -->
                        <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> -->
                        <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ace.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-language_tools.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-beautify.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-settings_menu.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-spellcheck.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-whitespace.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-split.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-searchbox.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-statusbar.js"></script>
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.19.0/ext-textarea.js"></script>
                    <script>
  // simple cookie class in javascript
  class Cookie {
    constructor() {
      this.cookie = document.cookie;
    }
    get(name) {
      const value = this.cookie.match(`(^|;)\\s*${name}\\s*=\\s*([^;]+)`);
      return value ? value.pop() : '';
    }
    set(name, value, days) {
      let expires = '';
      if (days) {
        const date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = `; expires=${date.toUTCString()}`;
      }
      // set for SameSite=None; 
      document.cookie = `${name}=${value || ''}${expires}; path=/; SameSite=None; Secure`;
      // document.cookie = `${name}=${value || ''}${expires}; path=/`;
    }
    delete(name) {
      this.set(name, '', -1);
    }
  } // end my cookie class
  // example usage:
  // const cookie = new Cookie();
  // cookie.set('name', 'value', 7);
  // cookie.get('name');
  // cookie.delete('name');
</script>
                    <!-- the plugin -->
                    <script>
(function($) {
  $.fn.customAceEditor = function(removeyn='no', themeselect_id='#theme-selector', modeselect_id='#mode-selector') {
    // removeyn = 'destroy' to remove the editor
    // make an editors array
    var editors = [];
    if (removeyn == 'destroy') {
      return this.each(function() {
        const textarea = $(this);
        const editorDiv = textarea.prev();
        editorDiv.remove();
        textarea.show();
        textarea.removeClass('hascodearea');
      });
    }
    if (this.hasClass('hascodearea')) {
      this.customAceEditor('destroy');
    }
    this.each(function() {
      const textarea = $(this);
      const editorDiv = $('<div class="hascodearea">').insertBefore(textarea).width(textarea.width()).height(textarea.height());
      
      const textarea_content = textarea.val();
      
      textarea.addClass('hascodearea');
      textarea.hide();
      /* to autoresize the Ace editor first you need to set the height of the editor to auto and then call the resize() method on the editor instance. */
      /* example calling the resize method on the editor instance:
      var editor = ace.edit("editor");
      editor.resize();
      */
      const editor = ace.edit(editorDiv[0], {
        autoScrollEditorIntoView: false,
        width: '100%',
        height: 'auto',
        fontSize: '16px',
        tabSize: 4,
        useSoftTabs: true,
        showPrintMargin: false,
        showGutter: true,
        highlightActiveLine: true,
        wrap: true,
        enableBasicAutocompletion: true,
        enableLiveAutocompletion: true,
        enableSnippets: true,
        maxLines: Infinity,
        minLines: 5,
        maxLines: 900000,
        scrollPastEnd: 1, /* fixed line 1 disappearing */
      });
      // add to editors array
      editors.push(editor);
      /* when window resizes, resize this editor */
      editor.setAutoScrollEditorIntoView(true);
      editor.setValue(textarea_content, 1); // 1 = moves cursor to end
// localstorage
//    use themeselect_id and modeselect_id to prefix the localstorage keys
      // revamped to use cookies, however have some variables still sharing localstorage name
    
      localstorage_prefix_theme   =  themeselect_id;
      localstorage_prefix_mode    =  modeselect_id;
      // clean the . and # out of the id's
      localstorage_prefix_theme   =  localstorage_prefix_theme.replace(/\.|#/, '');
      localstorage_prefix_mode    =  localstorage_prefix_mode.replace(/\.|#/, '');
      cookie_name_theme = localstorage_prefix_theme+'_theme';
      cookie_name_mode  = localstorage_prefix_mode+'_mode';
      const cookie = new Cookie();
      console.log('cookie theme:',cookie_name_theme,"::",cookie.get(cookie_name_theme));
      console.log('cookie mode:',cookie_name_mode,"::",cookie.get(cookie_name_mode));
      const defaultTheme = cookie.get(cookie_name_theme) || 'monokai';
      const defaultMode = cookie.get(cookie_name_mode) || 'text';
// ^^ localstorage
      editor.setTheme(`ace/theme/${defaultTheme}`);
      editor.session.setMode(`ace/mode/${defaultMode}`);
    //   editor.session.on('change input', function() {
    //     textarea.val(editor.getValue());
    //   });
      const themes = [
        "monokai", 
            "ambiance", "chaos", "chrome", "clouds", "clouds_midnight", "cobalt",
            "crimson_editor", "dawn", "dracula", "dreamweaver", "eclipse", "github",
            "gob", "gruvbox", "idle_fingers", "iplastic", "katzenmilch", "kr_theme",
            "kuroir", "merbivore", "merbivore_soft", "mono_industrial", "monokai",
            "pastel_on_dark", "solarized_dark", "solarized_light", "sqlserver",
            "terminal", "textmate", "tomorrow", "tomorrow_night", "tomorrow_night_blue",
            "tomorrow_night_bright", "tomorrow_night_eighties", "twilight", "vibrant_ink",
            "xcode"
        // ... (other themes)
      ];
      const themeSelector = $(themeselect_id);
// add attr data-cookie=cookie_name_theme
      themeSelector.attr('data-cookietheme', cookie_name_theme);
      themeSelector.attr('test', 'testthemmmme');
      themes.forEach(theme => {
        themeSelector.append($('<option>').val(theme).text(theme));
      });
      themeSelector.val(defaultTheme);
      themeSelector.on('change', function() {
        editor.setTheme(`ace/theme/${this.value}`);
// localstorage
        // localStorage.setItem(localstorage_prefix_theme+'defaultTheme', this.value);
        // get cookie name from attr data-cookie
        cookie_name = $(this).attr('data-cookietheme')
        const cookie = new Cookie();
        cookie.delete(cookie_name);
        cookie.set(cookie_name, this.value, 7);
        // alert(this.value);
      });
      const modes = [
            "text",
            "javascript", "php", "python", "ruby", "html", "css", "php", "java", "c_cpp",
            "markdown", "json", "xml", "yaml", "typescript", "sql", "go", "lua",
            "swift", "perl", "csharp", "rust", "r"
        // ... (other modes)
      ];
      const modeSelector = $(modeselect_id);
// add attr data-cookie=cookie_name_mode
      modeSelector.attr('data-cookiemode', cookie_name_mode);
      modes.forEach(mode => {
        modeSelector.append($('<option>').val(mode).text(mode));
      });
      modeSelector.val(defaultMode);
      modeSelector.on('change', function() {
        editor.session.setMode(`ace/mode/${this.value}`);
// localstorage
        // localStorage.setItem(localstorage_prefix_mode+'defaultMode', this.value);
        // get cookie name from attr data-cookie
        cookie_name = $(this).attr('data-cookiemode')
        const cookie = new Cookie();
        cookie.delete(cookie_name);
        cookie.set(cookie_name, this.value, 7);
      });
    //   editor.setValue(textarea.val(), 1);
    // set editor value to textarea
    }); // end each
    return editors;
  };
})(jQuery); // end jquery plugin
                    </script>
<script>
    // use use use
    // after the .code-textarea, append a row containing two blank select boxes with a class of .theme-selector and .mode-selector
    // the code for the jquery append
    $('.use_ace_edit').after('<div class="row"><div class="col-sm-6"><select class="theme-selector"></select></div><div class="col-sm-6"><select class="mode-selector"></select></div></div>');
    // $('.code-editor-1').customAceEditor('no', '.theme-selector-1', '.mode-selector-1');
    // document ready
    
    // $('.code-textarea').customAceEditor('no', '.theme-selector', '.mode-selector');
    // document ready first
    $(document).ready(function() {
        var the_editors = [];
        $(document).on('click', '.editBtn', function() {
            // when form done showing execute this
            // show and when complete showing do $('#updateSnippetForm')
            // after showing #updateSnippetForm, execute this
            var code = $(this).data('code');
            console.log(code);
            // code is escaped so unescape it
            const parser = new DOMParser();
            const doc = parser.parseFromString(code, 'text/html');
            code = doc.documentElement.textContent;
            console.log(code);
            the_editors = $('.use_ace_edit').customAceEditor('no', '.theme-selector', '.mode-selector');
            // find ace editor kind of like
            // editor = document.querySelector('.ace_editor')
            // the_editors should contain an array of ace editors
            // loop through an set their value to code
            the_editors.forEach(editor => {
                editor.setValue(code, 1);
            });
            console.log(the_editors);
            
        });
        // when a key down is clicked while an ace code editor is focused
        // set the textarea value to the ace editor value
        $(document).on('keydown', function() {
            the_editors.forEach(editor => {
                $('.use_ace_edit').val(editor.getValue());
                console.log(editor.getValue());
            });
        });
            
    });
</script>
                    <script>
                        // get all ace.js code editors on page, and set them to 100% width (fixed an autoresize issue)
                        const editors = document.querySelectorAll('.ace_editor');
                        editors.forEach(editor => {
                            editor.style.width = '100%';
                        });
                    </script>
<!-- END END END -- ace.js code editor -->
</body>
</html>
 |