Создание разделов с помощью Scribunto со ссылкой для редактирования

Я пытаюсь создать модуль Scribunto, который, помимо прочего, может создавать заголовок раздела в своем выводе.

Если возвращаемая строка содержит, например, == Hello World ==, результирующая страница правильно отображает раздел и даже включает его в оглавление. Однако в разделе нет ссылки на editsection.

В какой-то степени это понятно; раздела на самом деле не существует в исходном коде страницы. Но я хотел бы иметь возможность поместить ссылку на редактирование, откуда берется содержимое раздела. Я пробовал две разные версии функции 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 был включен в текст оглавления.

Есть ли способ получить там мою произвольную ссылку на редактирование, или мне придется жить с разделами Scribunto без раздела редактирования?


person Brian S    schedule 12.07.2016    source источник


Ответы (2)


То, что вы пытаетесь сделать, почти возможно без JavaScript, но не совсем.

Попытка №1: обычные заголовки

Во-первых, причина, по которой простой == Hello World == не работает в Scribunto, заключается в том, что вики-текст, который вы создаете в Scribunto, не обрабатывается автоматически синтаксическим анализатором MediaWiki. Из документации Scribunto:

Функция модуля обычно должна возвращать одну строку; любые возвращенные значения будут переданы через tostring(), а затем объединены без разделителя. Эта строка включена в викитекст как результат {{#invoke:}}.

На этом этапе синтаксического анализа страницы шаблоны уже развернуты, функции анализатора и теги расширения уже обработаны, а преобразования перед сохранением (например, расширение подписи с помощью тильды и трюк с трубой) уже выполнены. Поэтому модуль не может использовать эти функции в своем выходном тексте. Например, если модуль возвращает "Hello, [[world]]! {{welcome}}", страница будет выглядеть так: «Привет, мир! {{ добро пожаловать}}".

Чтобы обойти это, вы можете использовать метод Scribunto frame:preprocess. для предварительной обработки строк с помощью синтаксического анализатора MediaWiki перед их выводом. Например, предварительная обработка == Hello World == зарегистрирует заголовок в синтаксическом анализаторе и добавит маркер полосы перед заголовок заголовка. Затем в процессе синтаксического анализа синтаксический анализатор удаляет маркер полосы и добавляет ссылку на раздел редактирования.

Вы можете сделать это с помощью следующего кода модуля:

local p = {}

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

return p

При вызове на вики-странице этот код даст вам законную ссылку для редактирования MediaWiki. К сожалению, это ссылка на первый раздел страницы модуля, и нажатие на нее приведет к ошибке «Редактирование раздела не поддерживается».

Вы можете обойти это, используя другой объект фрейма для предварительной обработки. Если вы хотите, чтобы ссылка раздела редактирования указывала на страницу, с которой вы вызвали модуль, вы можете использовать родительский фрейм:

local p = {}

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

return p

А если вы хотите, чтобы ссылка указывала на произвольную страницу, вы можете создать новый дочерний кадр:

local p = {}

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

return p

Проблема с двумя приведенными выше примерами заключается в том, что они оба указывают на первый раздел на странице, а заголовки разделов, добавленные с помощью #invoke, не учитываются при подсчете разделов. Поэтому, если вы не знаете, что вам нужно отредактировать первый раздел, эти ссылки не будут работать для вас. К сожалению, я не знаю, как изменить номер раздела ссылок редактирования, сгенерированных таким образом.

Попытка №2: поддельные заголовки

На самом деле вы были очень близки в своей попытке подражать заголовку HTML. Проблема, с которой вы столкнулись, заключается в том, что MediaWiki не разрешает использовать теги <a> в викитексте для предотвращения атак межсайтового скриптинга. Вы можете легко обойти это, используя синтаксис внешних ссылок MediWiki ([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

Это даст вам заголовок, который ссылается на нужное место и выглядит почти так же, как оригинал. Есть только две проблемы:

  1. Цвет ссылки немного не тот. В MediaWiki внешние ссылки имеют немного другой цвет, чем внутренние ссылки. Здесь мы используем «внешнюю» ссылку на URL-адрес режима редактирования страницы, но ссылкам редактирования, сгенерированным MediaWiki, присваивается цвет внутренней ссылки. Это можно обойти с помощью разумного использования стилей, но остается проблема номер два:
  2. Текст «[править]» включен в оглавление.

К сожалению, я не знаю, как убрать текст «[edit]» из оглавления без использования JavaScript. Таким образом, единственное решение, которое будет надежно работать и все будет выглядеть правильно, — это использовать JavaScript, как это сделали вы.

person Jack Taylor    schedule 02.05.2017

Мое рабочее решение (но не мое предпочтительное решение) - вставить ссылку с помощью 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;
});
person Brian S    schedule 12.07.2016