JOE主题替换后台编辑器

6个月前 / 1 评论 / 6669 阅读 / 正在检测是否收录...

Test
以前也做过一次替换,但是那一次好像是不能自动保存,这次修复了一下,需要改动两个文件(admin/views/article_write.php 和 admin/views/js/common.js)
直接替换即可,pro 1.0.8版本,其他版本暂未测试

article_write.php

<?php if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<div id="msg" class="fixed-top alert" style="display: none"></div>
<h1 class="h3 mb-4 text-gray-800"><?php echo $containertitle; ?></h1>
<form action="article_save.php?action=add" method="post" enctype="multipart/form-data" id="addlog" name="addlog">
    <div class="row">
        <div class="col-xl-12">
            <div id="post" class="form-group">
                <div>
                    <input type="text" name="title" id="title" value="<?php echo $title; ?>" class="form-control" placeholder="文章标题" autofocus required/>
                </div>
                <div id="post_bar">
                    <a href="#mediaModal" class="text-muted small my-3" data-remote="./media.php?action=lib" data-toggle="modal" data-target="#mediaModal"><i
                                class="icofont-plus"></i> 插入图文资源</a>
                    <?php doAction('adm_writelog_head'); ?>
                </div>
                <textarea id="text" name="logcontent"><?php echo $content; ?></textarea>
            </div>
            <div class="form-group">
                <label>文章摘要:</label>
                <div id="logexcerpt"><textarea><?php echo $excerpt; ?></textarea></div>
            </div>
            <div class="form-group">
                <label>文章封面:</label>
                <div class="row m-3">
                    <div class="col-md-4">
                        <label for="upload_img">
                            <img src="<?php echo $cover ?: './views/images/cover.svg'; ?>" id="cover_image" class="rounded"/>
                            <input type="file" name="upload_img" class="image" id="upload_img" style="display:none"/>
                            <input type="hidden" name="cover" id="cover" value="<?php echo $cover; ?>"/>
                            <button type="button" id="cover_rm" class="btn-sm btn btn-link" <?php if (!$cover): ?>style="display:none"<?php endif; ?>>x</button>
                        </label>
                    </div>
                </div>
            </div>
            <div class="show_advset" id="displayToggle" onclick="displayToggle('advset', 1);">更多选项<i class="icofont-simple-right"></i></div>
            <div id="advset" class="shadow-sm p-3 mb-2 bg-white rounded">
                <div class="form-group">
                    <label>分类:</label>
                    <select name="sort" id="sort" class="form-control">
                        <option value="-1">选择分类...</option>
                        <?php
                        foreach ($sorts as $key => $value):
                            if ($value['pid'] != 0) {
                                continue;
                            }
                            $flg = $value['sid'] == $sortid ? 'selected' : '';
                            ?>
                            <option value="<?php echo $value['sid']; ?>" <?php echo $flg; ?>><?php echo $value['sortname']; ?></option>
                            <?php
                            $children = $value['children'];
                            foreach ($children as $key):
                                $value = $sorts[$key];
                                $flg = $value['sid'] == $sortid ? 'selected' : '';
                                ?>
                                <option value="<?php echo $value['sid']; ?>" <?php echo $flg; ?>>&nbsp; &nbsp; &nbsp; <?php echo $value['sortname']; ?></option>
                            <?php
                            endforeach;
                        endforeach;
                        ?>
                    </select>
                </div>
                <div class="form-group">
                    <label>标签:</label>
                    <input name="tag" id="tag" class="form-control" value="<?php echo $tagStr; ?>" placeholder="文章标签,使用逗号分隔"/>
                </div>
                <div class="form-group">
                    <label>发布时间:</label>
                    <input maxlength="200" name="postdate" id="postdate" value="<?php echo $postDate; ?>" class="form-control"/>
                </div>
                <div class="form-group">
                    <label>链接别名:(用于seo设置 <a href="./seo.php">&rarr;</a>)</label>
                    <input name="alias" id="alias" class="form-control" value="<?php echo $alias; ?>"/>
                </div>
                <div class="form-group">
                    <label>访问密码:</label>
                    <input type="text" name="password" id="password" class="form-control" value="<?php echo $password; ?>"/>
                </div>
                <div class="form-group">
                    <input type="checkbox" value="y" name="allow_remark" id="allow_remark" <?php echo $is_allow_remark; ?> />
                    <label for="allow_remark">允许评论</label>
                </div>
            </div>
            <div id="post_button">
                <input name="token" id="token" value="<?php echo LoginAuth::genToken(); ?>" type="hidden"/>
                <input type="hidden" name="ishide" id="ishide" value="<?php echo $hide; ?>"/>
                <input type="hidden" name="as_logid" id="as_logid" value="<?php echo $logid; ?>">
                <input type="hidden" name="gid" value=<?php echo $logid; ?>/>
                <input type="hidden" name="author" id="author" value=<?php echo $author; ?>/>
                <?php if ($logid < 0): ?>
                    <input type="submit" value="发布文章" onclick="return checkform();" class="btn btn-success"/>
                    <input type="button" name="savedf" id="savedf" value="保存草稿" onclick="autosave(2);" class="btn btn-primary"/>
                <?php else: ?>
                    <input type="submit" value="保存并返回" onclick="return checkform();" class="btn btn-success"/>
                    <input type="button" name="savedf" id="savedf" value="保存" onclick="autosave(2);" class="btn btn-primary"/>
                    <?php if ($isdraft) : ?>
                        <input type="submit" name="pubdf" id="pubdf" value="发布" onclick="return checkform();" class="btn btn-success"/>
                    <?php endif; ?>
                <?php endif; ?>
                <span id="save_info"></span>
            </div>
        </div>
    </div>
</form>
<div class="modal" id="mediaModal" tabindex="-1" role="dialog">
    <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">图文资源</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <a href="#" id="mediaAdd" class="btn btn-sm btn-success shadow-sm mb-3">上传图片/文件</a>
                <form action="media.php?action=operate_media" method="post" name="form_media" id="form_media">
                    <div class="card-columns">
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
<div class="dropzone-previews" style="display: none;"></div>
<script src="./views/js/dropzone.min.js?t=<?php echo Option::EMLOG_VERSION_TIMESTAMP; ?>"></script>
<script>
    // 上传资源
    Dropzone.autoDiscover = false;
    var myDropzone = new Dropzone("#mediaAdd", {
        url: "./media.php?action=upload",
        addRemoveLinks: false,
        method: 'post',
        maxFilesize: 2048,//M
        filesizeBase: 1024,
        previewsContainer: ".dropzone-previews",
        sending: function (file, xhr, formData) {
            formData.append("filesize", file.size);
            $('#mediaAdd').html("上传中……");
        },
        init: function () {
            this.on("error", function (file, response) {
                alert(response);
            });
            this.on("queuecomplete", function (file) {
                $('#mediaModal').find('.modal-body .card-columns').load("./media.php?action=lib");
                $('#mediaAdd').html("上传图片/文件");
            });
        }
    });
    // 载入资源列表
    $('#mediaModal').on('show.bs.modal', function (e) {
        var button = $(e.relatedTarget);
        var modal = $(this);
        modal.find('.modal-body .card-columns').load(button.data("remote"));
    });
</script>
<!-- 封面图裁剪 -->
<div class="modal fade" id="modal" tabindex="-2" role="dialog" aria-labelledby="modalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">裁剪并上传</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">×</span>
                </button>
            </div>
            <div class="modal-body">
                <div class="img-container">
                    <div class="row">
                        <div class="col-md-11">
                            <img src="" id="sample_image"/>
                        </div>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="bt btn-sm btn-secondary" data-dismiss="modal">取消</button>
                <button type="button" id="crop" class="btn btn-sm btn-success">保存</button>
            </div>
        </div>
    </div>
</div>
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/prism-theme-one-light-dark@1.0.4/prism-onedark.min.css">
<link rel="stylesheet" href="https://img.su1018.cn/yonghu/dist/joe.write.min.css">
<script>
    window.JoeConfig = {
        emojiAPI: '<?php echo TEMPLATE_URL; ?>write/json/emoji.json',
        expressionAPI: '<?php echo TEMPLATE_URL; ?>write/json/expression.json',
        characterAPI: '<?php echo TEMPLATE_URL; ?>write/json/character.json',
        playerAPI: '<?php echo TEMPLATE_URL; ?>write/library/player.php?url=',
        autoSave: 0,
        themeURL: '<?php echo TEMPLATE_URL; ?>',
        canPreview: false
    }
</script>
<script src="//cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/typecho-joe-next@6.2.4/plugin/prism/prism.min.js"></script>
<script src="<?php echo TEMPLATE_URL; ?>write/parse/parse.min.js"></script>
<script src="https://img.su1018.cn/yonghu/dist/wancheng.js"></script>
<script src="<?php echo TEMPLATE_URL; ?>assets/js/joe.short.min.js"></script>
<script src="./editor.md/editormd.js?t=<?php echo Option::EMLOG_VERSION_TIMESTAMP; ?>"></script>
<script>
    var icon_tog;//如果值为true,则“更多选项”箭头向右
    $("#alias").keyup(function () {
        checkalias();
    });
    setTimeout("autosave(1)", 30000);
    $("#menu_category_content").addClass('active');
    $("#menu_content").addClass('show');
    $("#menu_write").addClass('active');
    icon_tog = false;
    if (Cookies.get('em_advset') == "hidden") {
        displayToggle('advset', 1);
    } else {
        $(".icofont-simple-right").attr("class", "icofont-simple-down");
    }
    // 编辑器
    var Editor, Editor_summary;
    $(function () {
        Editor_summary = editormd("logexcerpt", {
            width: "100%",
            height: 300,
            toolbarIcons: function () {
                return ["undo", "redo", "|", "bold", "del", "italic", "quote", "|", "h1", "h2", "h3", "|", "list-ul", "list-ol", "hr", "|", "link", "image", "|", "watch"]
            },
            path: "editor.md/lib/",
            tex: false,
            watch: false,
            htmlDecode: true,
            flowChart: false,
            autoFocus: false,
            sequenceDiagram: false,
            placeholder: "如果留空,则使用文章内容作为摘要...",
            onload: function () {
                hooks.doAction("sum_loaded", this);
            }
        });
        Editor.setToolbarAutoFixed(false);
        Editor_summary.setToolbarAutoFixed(false);
    });
    // 封面图
    $(document).ready(function () {
        var $modal = $('#modal');
        var image = document.getElementById('sample_image');
        var cropper;
        $('#upload_img').change(function (event) {
            var files = event.target.files;
            var done = function (url) {
                image.src = url;
                $modal.modal('show');
            };
            if (files && files.length > 0) {
                reader = new FileReader();
                reader.onload = function (event) {
                    done(reader.result);
                };
                reader.readAsDataURL(files[0]);
            }
        });
        $modal.on('shown.bs.modal', function () {
            cropper = new Cropper(image, {
                aspectRatio: 16 / 9,
                viewMode: 1
            });
        }).on('hidden.bs.modal', function () {
            cropper.destroy();
            cropper = null;
        });
        $('#crop').click(function () {
            canvas = cropper.getCroppedCanvas({
                width: 650,
                height: 366
            });
            canvas.toBlob(function (blob) {
                var formData = new FormData();
                formData.append('image', blob, 'cover.jpg');
                $.ajax('./article.php?action=upload_cover', {
                    method: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function (data) {
                        $modal.modal('hide');
                        if (data != "error") {
                            $('#cover_image').attr('src', data);
                            $('#cover').val(data);
                            $('#cover_rm').show();
                        }
                    }
                });
            });
        });
        $('#cover_rm').click(function () {
            $('#cover_image').attr('src', "./views/images/cover.svg");
            $('#cover').val("");
            $('#cover_rm').hide();
        });
    });
</script>

common.js

function getChecked(node) {
    var re = false;
    $('input.' + node).each(function (i) {
        if (this.checked) {
            re = true;
        }
    });
    return re;
}
function timestamp() {
    return new Date().getTime();
}
function em_confirm(id, property, token) {
    switch (property) {
        case 'tw':
            var urlreturn = "twitter.php?action=del&id=" + id;
            var msg = "确定要删除该笔记吗?";
            break;
        case 'comment':
            var urlreturn = "comment.php?action=del&id=" + id;
            var msg = "确定要删除该评论吗?";
            break;
        case 'commentbyip':
            var urlreturn = "comment.php?action=delbyip&ip=" + id;
            var msg = "确定要删除来自该IP的所有评论吗?";
            break;
        case 'link':
            var urlreturn = "link.php?action=dellink&linkid=" + id;
            var msg = "确定要删除该链接吗?";
            break;
        case 'navi':
            var urlreturn = "navbar.php?action=del&id=" + id;
            var msg = "确定要删除该导航吗?";
            break;
        case 'media':
            var urlreturn = "media.php?action=delete&aid=" + id;
            var msg = "确定要删除该媒体文件吗?";
            break;
        case 'avatar':
            var urlreturn = "blogger.php?action=delicon";
            var msg = "确定要删除头像吗?";
            break;
        case 'sort':
            var urlreturn = "sort.php?action=del&sid=" + id;
            var msg = "确定要删除该分类吗?";
            break;
        case 'user':
            var urlreturn = "user.php?action=del&uid=" + id;
            var msg = "确定要删除该用户吗?";
            break;
        case 'tpl':
            var urlreturn = "template.php?action=del&tpl=" + id;
            var msg = "确定要删除该模板吗?";
            break;
        case 'reset_widget':
            var urlreturn = "widgets.php?action=reset";
            var msg = "确定要恢复组件设置到初始状态吗?这样会丢失你自定义的组件。";
            break;
        case 'plu':
            var urlreturn = "plugin.php?action=del&plugin=" + id;
            var msg = "确定要删除该插件吗?";
            break;
    }
    if (confirm(msg)) {
        window.location = urlreturn + "&token=" + token;
    } else {
        return;
    }
}
function focusEle(id) {
    try {
        document.getElementById(id).focus();
    } catch (e) {
    }
}
function hideActived() {
    $(".alert-success").hide();
    $(".alert-danger").hide();
}
function displayToggle(id, keep) {
    $("#" + id).toggleClass(id + "_hidden");
    icon_tog ? $(".icofont-simple-right").attr("class", "icofont-simple-down") : $(".icofont-simple-down").attr("class", "icofont-simple-right");
    icon_tog = !icon_tog;
    if (keep == 1) {
        Cookies.set('em_' + id, $("#" + id).css('visibility'), {expires: 365})
    }
    if (keep == 2) {
        Cookies.set('em_' + id, $("#" + id).css('visibility'))
    }
}
function isalias(a) {
    var reg1 = /^[\u4e00-\u9fa5\w-]*$/;
    var reg2 = /^[\d]+$/;
    var reg3 = /^post(-\d+)?$/;
    if (!reg1.test(a)) {
        return 1;
    } else if (reg2.test(a)) {
        return 2;
    } else if (reg3.test(a)) {
        return 3;
    } else if (a == 't' || a == 'm' || a == 'admin') {
        return 4;
    } else {
        return 0;
    }
}
function checkform() {
    var a = $.trim($("#alias").val());
    var t = $.trim($("#title").val());
    if (0 == isalias(a)) {
        return true;
    } else {
        alert("链接别名错误");
        $("#alias").focus();
        return false;
    }
}
function checkalias() {
    var a = $.trim($("#alias").val());
    if (1 == isalias(a)) {
        $("#alias_msg_hook").html('<span id="input_error">别名错误,应由字母、数字、下划线、短横线组成</span>');
    } else if (2 == isalias(a)) {
        $("#alias_msg_hook").html('<span id="input_error">别名错误,不能为纯数字</span>');
    } else if (3 == isalias(a)) {
        $("#alias_msg_hook").html('<span id="input_error">别名错误,不能为\'post\'或\'post-数字\'</span>');
    } else if (4 == isalias(a)) {
        $("#alias_msg_hook").html('<span id="input_error">别名错误,与系统链接冲突</span>');
    } else {
        $("#alias_msg_hook").html('');
        $("#msg").html('');
    }
}
function insert_media_img(fileurl, imgsrc) {
    var ds = document.getElementsByClassName("cm-content");
    for (var i = 0; i < ds.length; i++) {
        ds[i].append('[#图片;
    }
}
function insert_media_video(fileurl) {
    var ds = document.getElementsByClassName("cm-content");
    for (var i = 0; i < ds.length; i++) {
        ds[i].append('<video class=\"video-js\" controls preload=\"auto\" width=\"100%\" data-setup=\'{"aspectRatio":"16:9"}\'> <source src="' + fileurl + '" type=\'video/mp4\' > </video>');
    }
}
function insert_media(fileurl, filename) {
    var ds = document.getElementsByClassName("cm-content");
    for (var i = 0; i < ds.length; i++) {
        ds[i].append('[' + filename + '](' + fileurl + ')\n\n');
    }
}
// act: 1 auto save, 2 manual save:click save button to save,
function autosave(act) {
    var nodeid = "as_logid";
    var timeout = 30000;
    var url = "article_save.php?action=autosave";
    var title = $.trim($("#title").val());
    var cover = $.trim($("#cover").val());
    var alias = $.trim($("#alias").val());
    var sort = $.trim($("#sort").val());
    var postdate = $.trim($("#postdate").val());
    var date = $.trim($("#date").val());
    var logid = $("#as_logid").val();
    var author = $("#author").val();
    var demo = document.getElementsByClassName("cm-content");
    var content=demo[0].innerText;
    var excerpt = Editor_summary.getMarkdown();
    var tag = $.trim($("#tag").val());
    var top = $("#top").is(":checked") ? 'y' : 'n';
    var sortop = $("#sortop").is(":checked") ? 'y' : 'n';
    var allow_remark = $("#allow_remark").is(":checked") ? 'y' : 'n';
    var password = $.trim($("#password").val());
    var ishide = $.trim($("#ishide").val());
    var token = $.trim($("#token").val());
    var ishide = ishide == "" ? "y" : ishide;
    var querystr = "logcontent=" + encodeURIComponent(content)
        + "&logexcerpt=" + encodeURIComponent(excerpt)
        + "&title=" + encodeURIComponent(title)
        + "&cover=" + encodeURIComponent(cover)
        + "&alias=" + encodeURIComponent(alias)
        + "&author=" + author
        + "&sort=" + sort
        + "&postdate=" + postdate
        + "&date=" + date
        + "&tag=" + encodeURIComponent(tag)
        + "&top=" + top
        + "&sortop=" + sortop
        + "&allow_remark=" + allow_remark
        + "&password=" + password
        + "&token=" + token
        + "&ishide=" + ishide
        + "&as_logid=" + logid;
    // 检查别名
    if (alias != '' && 0 != isalias(alias)) {
        $("#msg").show().html("链接别名错误,自动保存失败");
        if (act == 0) {
            setTimeout("autosave(1)", timeout);
        }
        return;
    }
    // 编辑发布状态的文章时不自动保存
    if (act == 1 && ishide == 'n') {
        return;
    }
    // 内容为空时不自动保存
    if (act == 1 && content == "") {
        setTimeout("autosave(1)", timeout);
        return;
    }
    var btname = $("#savedf").val();
    $("#savedf").val("正在保存中...");
    $("#savedf").attr("disabled", "disabled");
    $.post(url, querystr, function (data) {
        data = $.trim(data);
        var isresponse = /autosave\_gid\:\d+\_df\:\d*\_/;
        if (isresponse.test(data)) {
            var getvar = data.match(/\_gid\:([\d]+)\_df\:([\d]*)\_/);
            var logid = getvar[1];
            var d = new Date();
            var h = d.getHours();
            var m = d.getMinutes();
            var s = d.getSeconds();
            var tm = (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s);
            $("#save_info").html("保存于:" + tm);
            $("#" + nodeid).val(logid);
            $("#savedf").attr("disabled", false).val(btname);
        } else {
            $("#savedf").attr("disabled", false).val(btname);
            $("#msg").html("网络或系统出现异常...保存可能失败").addClass("alert-danger");
        }
    });
    if (act == 1) {
        setTimeout("autosave(1)", timeout);
    }
}
// toggle plugin
$.fn.toggleClick = function () {
    var functions = arguments;
    return this.click(function () {
        var iteration = $(this).data('iteration') || 0;
        functions[iteration].apply(this, arguments);
        iteration = (iteration + 1) % functions.length;
        $(this).data('iteration', iteration);
    });
};
// 过滤HTML标签
function removeHTMLTag(str) {
    str = str.replace(/<\/?[^>]*>/g, ''); //去除HTML tag
    str = str.replace(/[ | ]*\n/g, '\n'); //去除行尾空白
    str = str.replace(/ /ig, '');
    return str;
}
// 表格全选
$(function () {
    $('#checkAll').click(function (event) {
        let tr_checkbox = $('table tbody tr').find('input[type=checkbox]');
        tr_checkbox.prop('checked', $(this).prop('checked'));
        event.stopPropagation();
    });
    // 点击表格每一行的checkbox,表格所有选中的checkbox数 = 表格行数时,则将表头的‘checkAll’单选框置为选中,否则置为未选中
    $('table tbody tr').find('input[type=checkbox]').click(function (event) {
        let tbr = $('table tbody tr');
        $('#checkAll').prop('checked', tbr.find('input[type=checkbox]:checked').length == tbr.length ? true : false);
        event.stopPropagation();
    });
});
// 卡片全选
$(function () {
    $('#checkAllCard').click(function (event) {
        let card_checkbox = $('.card-body').find('input[type=checkbox]');
        card_checkbox.prop('checked', $(this).prop('checked'));
        event.stopPropagation();
    });
    $('.card-body').find('input[type=checkbox]').click(function (event) {
        let cards = $('.card-body');
        $('#checkAllCard').prop('checked', cards.find('input[type=checkbox]:checked').length == cards.length ? true : false);
        event.stopPropagation();
    });
});
// editor.md的js钩子
var queue = new Array();
var hooks = {
    addAction: function (hook, func) {
        if (typeof (queue[hook]) == "undefined" || queue[hook] == null) {
            queue[hook] = new Array();
        }
        if (typeof func == 'function') {
            queue[hook].push(func);
        }
    },
    doAction: function (hook, obj) {
        try {
            for (var i = 0; i < queue[hook].length; i++) {
                queue[hook][i](obj);
            }
        } catch (e) {
        }
    }
}

评论(1)

取消
    1. 头像
      aa123aaLv.2
      沙发
       回复