通过编辑 link 使用 Scribunto 创建部分

Creating sections with Scribunto with edit link

我正在尝试创建一个 Scribunto 模块,除其他外,它可以在其输出中创建一个部分 header。

如果返回的字符串包含 == Hello World == 等,生成的页面会正确显示该部分,甚至会在 TOC 中包含该部分。但是,该部分没有编辑部分 link.

某种程度上,这是可以理解的;该部分实际上并不存在于页面的源代码中。但我希望能够对该部分内容的来源进行编辑 link。我尝试了 buildHeader 函数的两个不同版本:

-- version 1:
function p.buildHeader(level, title, page)
    local open = '<span class="mw-editsection-bracket">[</span>'
    local close = '<span class="mw-editsection-bracket">]</span>'
    local link = '<a href="/w/index.php?title='..p.urlsafe(page)..'&action=edit" title="Edit section: '..title..'">edit</a>'
    local edit = '<span class="mw-editsection">'..open..link..close..'</span>'
    local text = '<span id="'..p.urlsafe(title)..'" class="mw-headline">'..title..'</span>'
    return '<h'..level..'>'..title..edit..'</h'..level..'>'
end

-- version 2:
function p.buildHeader(level, title, page)
    local result = mw.html.create('h'..level)
    result:tag('span')
            :attr({id=p.urlsafe(title), class='mw-headline'})
            :wikitext(title)
            :done()
        :tag('span')
            :attr('class', 'mw-editsection'):tag('span')
                :attr('class', 'mw-editsection-bracket')
                :wikitext('[')
                :done()
            :tag('a')
                :attr({href='/w/index.php?title='..p.urlsafe(page)..'&action=edit', title='Edit section: '..title})
                :wikitext('edit')
                :done()
            :tag('span')
                :attr('class', 'mw-editsection-bracket')
                :wikitext(']')
                :allDone()

    return tostring(result)
end

在这两种情况下,锚标记的 HTML 都被转义了(例如,<span class="mw-editsection">...&lt;a href="..." title="..."&gt;edit&lt;/a&gt;</span>),并且整个 mw-editsection 范围都包含在目录文本中。

有什么方法可以让我在其中进行任意编辑 link,还是我必须忍受 editsection-less Scribunto 部分?

我的工作解决方案(但不是我的首选解决方案)是插入 link 和 JavaScript。 buildHeader 函数变为:

function p.buildHeader(level, title, page)
    local result = mw.html.create('h'..level)
    result:attr('data-source', page):wikitext(title)
    return tostring(result)
end

然后,在 MediaWiki:Common.js 中,我添加:

$('h1[data-source],h2[data-source],h3[data-source],h4[data-source],h5[data-source],h6[data-source]').append(function() {
    var source = $(this).data('source'),
        title = $(this).text(),
        $editsection = $('<span>').attr('class', 'mw-editsection'),
        $open = $('<span>').attr('class', 'mw-editsection-bracket').text('['),
        $close = $('<span>').attr('class', 'mw-editsection-bracket').text(']'),
        $link = $('<a>').attr('title', 'Edit section: ' + title)
                        .attr('href', '/w/index.php?title=' + source + '&action=edit')
                        .text('edit');
    $editsection.append($open).append($link).append($close);
    return $editsection;
});

您尝试做的事情 几乎 在没有 JavaScript 的情况下是可能的,但不完全是。

尝试 #1:正常标题

首先,直接 == Hello World == 在 Scribunto 中不起作用的原因是您在 Scribunto 中生成的 wiki 文本不会被 MediaWiki 解析器自动预处理。来自 the Scribunto docs:

The module function should usually return a single string; whatever values are returned will be passed through tostring() and then concatenated with no separator. This string is incorporated into the wikitext as the result of the {{#invoke:}}.

At this point in the page parse, templates have already been expanded, parser functions and extension tags have already been processed, and pre-save transforms (e.g. signature tilde expansion and the pipe trick) have already happened. Therefore the module cannot use these features in its output text. For example, if a module returns "Hello, [[world]]! {{welcome}}", the page will read "Hello, world! {{welcome}}".

要解决这个问题,您可以在标题前使用 Scribunto 的 frame:preprocess method to preprocess strings using the MediaWiki parser before you output them. For example, preprocessing == Hello World == will register the heading with the parser, and add a strip marker。然后在稍后的解析过程中,解析器删除条带标记并添加编辑部分 link.

您可以使用以下模块代码执行此操作:

local p = {}

function p.main(frame)
    return frame:preprocess("== Hello World ==")
end

return p

在 wiki 页面上调用时,此代码将为您提供合法的 MediaWiki 编辑 link。不幸的是,它是模块页面第一部分的 link,单击它会出现 "section editing not supported" 错误。

您可以通过使用不同的框架 object 进行预处理来解决这个问题。如果您希望编辑部分 link 指向您调用模块的页面,您可以使用 parent frame:

local p = {}

function p.main(frame)
    return frame:getParent():preprocess("== Hello World ==")
end

return p

如果你想让 link 指向任意页面,你可以创建一个新的 child frame:

local p = {}

function p.main(frame)
    local childFrame = frame:newChild{title = "Your page here"}
    return childFrame:preprocess("== Hello World ==")
end

return p

以上两个示例的问题在于它们都指向页面上的第一部分 - 通过#invoke 添加的部分标题不计入部分计数。因此,除非您知道第一部分是您需要编辑的部分,否则这些 link 对您不起作用。不幸的是,我不知道有什么方法可以更改以这种方式生成的编辑 link 的节号。

尝试 #2:假标题

您实际上非常接近于模仿标题 HTML。您遇到的问题是 MediaWiki 不允许在 wiki 文本中使用 <a> 标签来防止 cross-site 脚本攻击。您可以使用 MediWiki 的外部 link 语法轻松解决此问题 ([http://www.example.com Example]).

这里有一些更接近您的目标:

local p = {}

function p.makeHeading(title, page)
    local result = mw.html.create('h2')
    result
        :tag('span')
            :attr({id = title, class='mw-headline'})
            :wikitext(title)
            :done()
        :tag('span')
            :addClass('mw-editsection')
            :addClass('plainlinks')
            :tag('span')
                :attr('class', 'mw-editsection-bracket')
                :wikitext('[')
                :done()
            :wikitext(string.format(
                '[%s %s]',
                tostring(mw.uri.fullUrl(page, {action = 'edit'})),
                'edit'
            ))
            :tag('span')
                :attr('class', 'mw-editsection-bracket')
                :wikitext(']')
    return tostring(result)
end

return p

这将为您提供一个 link 到正确位置并且看起来几乎与原始标题完全一样的标题。只有两个问题:

  1. link颜色有点不对。在 MediaWiki 中,外部 link 的颜色与内部 link 的颜色略有不同。这里我们使用 "external" link 到页面的 edit-mode URL,但是 MediaWiki 生成的编辑 link 被赋予内部 link 颜色.可以通过明智地使用样式来解决这个问题,但这会留下第二个问题:
  2. “[编辑]”文本包含在 table 目录中。

不幸的是,我不知道有什么方法可以在不使用 JavaScript 的情况下将“[edit]”文本保留在 table 内容之外。因此,唯一能够可靠工作并使一切看起来正确的解决方案是像您所做的那样使用 JavaScript。