Typecho 全站 pjax 方案

其实最早添加 pjax 的时候就发现了评论会有问题,只是一直不知道怎么去解决,后来就放弃了。最近想出一种办法,使得全站 pjax 生效。
(可能不具有通用性,因为我使用的 Ajax 评论不是 willin kan 的那款

搜索引擎搜到的有关 Typecho&pjax 的内容主要有如下几篇:

其中基本都要修改 Typecho 的内核代码,主要是 header 中的评论 js 输出,或者是用修改版 pjax.js。

引入 js 文件

<script src="//cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
<script src="//cdn.bootcss.com/jquery.pjax/1.9.6/jquery.pjax.min.js"></script>

pjax 初始化

function pjaxInit() {
    var pjaxContainer = '#pjax-container',
        pjaxSearchForm = '#search-form',
        pjaxTimeout = 30000;

    $(document).pjax('a[target!=_blank]', pjaxContainer, {
        fragment: pjaxContainer,
        timeout: pjaxTimeout
    });
    $(document).on('submit', 'pjaxSearchForm', function(event) {
        $.pjax.submit(event, pjaxContainer, {
            fragment: pjaxContainer,
            timeout: pjaxTimeout
        });
    });
    $(document).on('pjax:send', function() {
        //载入动画
    });
    $(document).on('pjax:complete', function() {
        //需要重载的插件
        //载入动画结束
        ajaxCommentRewrite();
    });
}

干掉 TypechoComment

在 bindCommentReplyButton () 方法中加入

ajaxCommentRewrite();

ajaxCommentRewrite () 方法的具体代码

$(selector.commentReplyButton + ' a').prop('onclick', null).attr('href', 'javascript:;');
$(selector.commentCancelReplyLink).prop('onclick', null).attr('href', 'javascript:;');

原 Ajax 评论代码中需要修改的地方

TypechoComment.cancelReply();

替换为

cancelReply();

ajaxComments () 添加

removeTextareaEvent();

cancelReply () 方法的具体代码

function cancelReply() {
    var response = $(selector.respondContainer)[0],
        holder = $('#comment-form-place-holder')[0],
        input = $('#comment-parent')[0];
    if (null != input) {
        input.parentNode.removeChild(input);
    }
    if (null == holder) {
        return true;
    }
    $(selector.commentCancelReplyLink)[0].style.display = 'none';
    holder.parentNode.insertBefore(response, holder);
    return false;
}

removeTextarea () 方法的具体代码

function removeTextareaEvent() {
    $(document).on('click', selector.submitTextarea, function() {
        $(selector.submitForm + ' input[name="_"]:not(#comment_)').remove();
    });
}

使用 jQuery 重新绑定回复按钮和取消回复按钮事件

 $(document).on('click', selector.commentReplyButton, function() {
     var cid = $(this).attr('data-cid'),
         coid = $(this).attr('data-coid');
     var comment = $('#' + cid)[0],
         parent = comment.parentNode,
         response = $(selector.respondContainer)[0],
         input = $('#comment-parent')[0],
         form = 'form' == response.tagName ? response : response.getElementsByTagName('form')[0],
         textarea = response.getElementsByTagName('textarea')[0];
     if (null == input) {
         input = createElement('input', {
             'type': 'hidden',
             'name': 'parent',
             'id': 'comment-parent'
         });
         form.appendChild(input);
     }
     input.setAttribute('value', coid);
     if (null == document.getElementById('comment-form-place-holder')) {
         var holder = createElement('div', {
             'id': 'comment-form-place-holder'
         });
         response.parentNode.insertBefore(holder, response);
     }
     comment.appendChild(response);
     $(selector.commentCancelReplyLink)[0].style.display = '';
     if (null != textarea && 'text' == textarea.name) {
         textarea.focus();
     }
     return false;
 });

$(document).on('click', selector.commentCancelReplyLink, function() {
    cancelReply();
});

createElement () 方法具体代码

function createElement(tag, attr) {
    var el = document.createElement(tag);
    for (var key in attr) {
        el.setAttribute(key, attr[key]);
    }
    return el;
}

修改 comments.php
form 中添加 (注意把 wrap 修改为你对应的 pjaxContainer)

<input name="_" type="hidden" id="comment_" value="<?php echo Helper::security()->getToken(str_replace(array('?_pjax=%23wrap', '&_pjax=%23wrap'), '', Typecho_Request::getInstance()->getRequestUrl()));?>"/>

回复楼层按钮改为

<span class="reply" data-cid="comment-<?php $comments->coid();?>" data-coid="<?php $comments->coid();?>">

别忘了修改公共模板部分,通过添加 is_pjax () 方法来判断

function is_pjax()
{
    return (isset($_SERVER['HTTP_X_PJAX']) && $_SERVER['HTTP_X_PJAX'] == 'true');
}

至此 Ajax 评论的问题基本解决

重载统计代码

在 pjax:success 中添加

if (window.ga) {
    var location = window.location.pathname + window.location.search;
    ga('send', 'pageview', {
        'page': location,
        'title': document.title
    });
}

同时移除原来的

ga('send', 'pageview');