前段时间给博客改了PJAX,过了一段时间觉得好久没人评论过了,才发现无法评论的Bug,为什么没人告诉我QAQ,访问量不应该这么小的呀!然后我就开始找原因,但我是业余选手,找不到原因就去找学霸帮忙了。在学霸的帮助下也算解决了这个问题,现在记录一下帮助其他人。

首先说一下无法评论的的原因,Typecho 有一段 Javascript 是用来给评论表单添加 token 认证的,位于 /var/Widget/Archive.php 中 1800 行附近,代码如下:

    document[event.add](event.load, function () {
        var r = document.getElementById('{$this->respondId}');

        if (null != r) {
            var forms = r.getElementsByTagName('form');
            if (forms.length > 0) {
                var f = forms[0], textarea = f.getElementsByTagName('textarea')[0], added = false;

                if (null != textarea && 'text' == textarea.name) {
                    textarea[event.add](event.focus, function () {
                        if (!added) {
                            var input = document.createElement('input');
                            input.type = 'hidden';
                            input.name = '_';
                            input.value = " . Typecho_Common::shuffleScriptVar(
                                $this->security->getToken($this->request->getRequestUrl())) . "

                            f.appendChild(input);
                            added = true;
                        }
                    });
                }
            }
        }
    });

学霸告诉我是因为 PJAX 加载导致 event 丢失,我们把 document 的写法改成如下所示即可:

$(document).ready(function(){

我修改玩之后发现还是不可行,于是继续找问题,发现我 AJAX 评论的绑定函数在 AJAX 执行之后并没有重新执行,绑定函数如下所示:

  function click_bind() { // 绑定
    $(comment_reply + ' a').click(function() { // 回复
      //$body.animate({scrollTop: $(respond).offset().top - 180}, 400);
      parent_id = $(this).parent().parent().attr("id");
      $(textarea).focus();
    });
    $('#cancel-comment-reply-link').click(function() { // 取消
      parent_id = '';
    });
  }

鄙人不才,没有找到比较优雅的方式,我在主题模板里面引用 ajaxcomment.js 的代码里面增加了一个小标别:

<script type="text/javascript" src="<?php $this->options->themeUrl('js/ajaxcomment.js');?>" pjaxjs="true"></script>

然后在 jquery.pjax.js 中对这个 JS 文件进行重新加载:

$('foot').find('script').each(function() {
	if ($(this).attr('pjaxjs')) {
		$.getScript($(this).attr('src'));
		$(this).remove();
	}
});

现在评论按钮可以正常点击了,但是评论还是没有正确提交上去。我又检查了一遍 token 验证,发现 token 验证能够正常添加到表单中,但是生成的 token 却是错误的。我又在上文提到的 Archive.php 文件中查看代码,调试之后,发现问题所在。我博客提交的请求链接都包含了 ?pjax=true 字段,导致生成的 token 和验证所需的 token 不同,最后我用一段正则表达式替换掉了这个字段,源码也被我修改成下面这样子:

    $(document).ready(function(){
        var r = document.getElementById('{$this->respondId}');

        if (null != r) {
            var forms = r.getElementsByTagName('form');
            if (forms.length > 0) {
                var f = forms[0], textarea = f.getElementsByTagName('textarea')[0], added = false;

                if (null != textarea && 'text' == textarea.name) {
                    textarea[event.add](event.focus, function () {
                        if (!added) {
                            var input = document.createElement('input');
                            input.type = 'hidden';
                            input.name = '_';
                            input.value = " . Typecho_Common::shuffleScriptVar(
                                $this->security->getToken(
                                    preg_replace('/\?pjax=true/', '', $this->request->getRequestUrl())
                                    )
                                ) . "

                            f.appendChild(input);
                            added = true;
                        }
                    });
                }
            }
        }
    });

更新一下这篇博文,在帮 chasonma 调试的时候,发现了另一个问题,上面的修改只能支持ajax评论,不支持非ajax评论的主题。对于非ajax评论的,即使用 $this->commentUrl() 来获得token的,还需要修改 /var/Widget/Security.php 文件,在50行左右,修改为如下代码:

    /**
     * 生成带token的路径
     *
     * @param $path
     * @return string
     */
    public function getTokenUrl($path)
    {
        $parts = parse_url($path);
        $params = array();

        if (!empty($parts['query'])) {
            parse_str($parts['query'], $params);
        }

        $params['_'] = $this->getToken(preg_replace('/\?pjax=true/', '', $this->request->getRequestUrl()));
        $parts['query'] = http_build_query($params);

        return Typecho_Common::buildUrl($parts);
    }

最后,建议直接使用我 Github 上的 PJAX,这样子就不用修改正则表达式部分的代码了。

转载保留版权:http://haipz.com/blog/i/6504 - 海胖博客