Aller au contenu

Module:Argument

De Wikidébats, l'encyclopédie des débats et des arguments « pour » et « contre »

La documentation pour ce module peut être créée à Module:Argument/doc

-- Module:Argument
-- Portage du modèle "Argument" vers Lua (Scribunto)
-- Version avec pré-expansion systématique des parser functions via frame:preprocess()

local p = {}
local i18n = mw.loadData('Module:Argument/i18n')

-- ===== Utilitaires =====
local function _(lang, key)
  local L = i18n[lang] or i18n.en or {}
  return L[key] or ('['..key..']')
end

local function param(args, ...)
  for _,k in ipairs{...} do
    local v = args[k]
    if v and v ~= '' then return v end
  end
  return ''
end

local function esc_attr(s)
  if not s then return '' end
  s = tostring(s)
  s = s:gsub('"', '"')
  return s
end

local function italics(lang, textKey)
  return "'' " .. _(lang, textKey) .. " ''"
end

local function titleData()
  local t = mw.title.getCurrentTitle()
  local full = t.prefixedText -- FULLPAGENAME
  local id = tostring(t.id or '')
  return {
    full = full,
    fullEnc = mw.uri.encode(full, 'WIKI'),
    id = id,
    url = tostring(mw.uri.fullUrl(full)),
  }
end

-- Pré-expansion d'un bloc de wikitexte/ParserFunctions
local function pf(frame, txt)
  return frame:preprocess(txt)
end

-- Ajout de catégorie via i18n (nom complet comme "Catégorie:XYZ")
local function emitCategory(lang, key)
  local name = _(lang, key)
  if not name or name == '' or name:match('^%[') then return '' end
  return string.format('[[%s]]', name)
end

-- ===== Sections =====

local function renderKeywords(frame, args, lang)
  local out = {}
  table.insert(out, '<div style="font-size:95%;margin-top:1em;"><b>' .. _(lang,'keywords') .. '</b> : ')
  local mots = param(args,'mots-clés','mots_cles','keywords')
  if mots == '' then
    table.insert(out, _(lang,'none'))
    table.insert(out, emitCategory(lang,'cat-arguments-sans-mot-cle'))
  else
    table.insert(out, pf(frame, '{{#arraymaptemplate: '..mots..' | '.._(lang,'keyword-template')..' }}'))
  end
  table.insert(out, pf(frame,
    '<span class="modifier-rubrique navigation-not-searchable">{{#formlink:'
    .. ' | link text = '.._(lang,'edit')
    .. ' | form =  '.._(lang,'form-argument-keywords')
    .. ' | target = {{FULLPAGENAMEE}}'
    .. ' | tooltip = '.._(lang,'edit-keywords-tooltip')
    .. ' }}</span>'
  ))
  table.insert(out, '<span style="display:none;">.</span></div>')
  return table.concat(out, '')
end

local function renderSummary(frame, args, lang)
  local out = {}
  table.insert(out, pf(frame, '<div style="display:none;">{{Sommaire | niveau = 1}}</div>'))
  table.insert(out, '<h2 id="Summary" class="section-modifiable">'
    .. '<span style="margin-right:0.5em;">[[Fichier:Contributions.svg | 17px | link= | alt='..esc_attr(_(lang,'summary-title'))..']]</span>'
    .. _(lang,'summary-title') .. pf(frame,
    '<span class="modifier-section navigation-not-searchable noprint">{{#formlink:'
    .. ' | link text = '.._(lang,'edit')
    .. ' | form =  '.._(lang,'form-summary')
    .. ' | target = {{FULLPAGENAMEE}}'
    .. ' | tooltip = '.._(lang,'edit-summary-tooltip')
    .. ' }}</span>'
  ) .. '</h2>')

  local resume = param(args,'résumé','summary')
  local warnings = param(args,'avertissements-résumé','warnings-summary')
  if resume ~= '' then
    if warnings ~= '' then
      table.insert(out, pf(frame, '{{#arraymap: '..warnings..' | , | x | {{Bandeau x}} | &#32; }}'))
    end
    table.insert(out, '<div>'..resume..'</div>')
    if warnings ~= '' then
      table.insert(out, pf(frame, '{{#arraymap: '..warnings..' | , | x | {{#switch: x'
        .. ' | Résumé désavantageux = '..emitCategory(lang,'cat-resume-desavantageux')
        .. ' | Résumé peu clair = '..emitCategory(lang,'cat-resume-peu-clair')
        .. ' | Résumé trop long = '..emitCategory(lang,'cat-resume-trop-long')
        .. ' | Résumé à rédiger = '..emitCategory(lang,'cat-resume-a-rediger')
        .. ' | Arguments à séparer = '..emitCategory(lang,'cat-arguments-a-separer')
        .. ' | Style à revoir = '..emitCategory(lang,'cat-style-a-revoir')
        .. ' }} | &#32; }}'))
    end
  else
    table.insert(out, '<div class="aucun-contenu navigation-not-searchable">'..italics(lang,'summary-empty')..'</div>')
    table.insert(out, emitCategory(lang,'cat-arguments-sans-resume'))
  end
  return table.concat(out, '\n')
end

local function renderQuotes(frame, args, lang)
  local out = {}
  table.insert(out, '<h2 id="Quotes" class="section-modifiable">'
    .. '<span style="margin-right:0.5em;">[[Fichier:Citation.svg | 17px | link= | alt='..esc_attr(_(lang,'quotes-title'))..']]</span>'
    .. _(lang,'quotes-title') .. pf(frame,
    '<span class="modifier-section navigation-not-searchable noprint">{{#formlink:'
    .. ' | link text = '.._(lang,'edit')
    .. ' | form =  '.._(lang,'form-quotes')
    .. ' | target = {{FULLPAGENAMEE}}'
    .. ' | tooltip = '.._(lang,'edit-quotes-tooltip')
    .. ' }}</span>'
  ) .. '</h2>')

  local quotes = param(args,'citations','quotes')
  if quotes == '' then
    table.insert(out, '<div class="aucun-contenu navigation-not-searchable">'..italics(lang,'quotes-empty')..'</div>')
    table.insert(out, emitCategory(lang,'cat-arguments-sans-citation'))
  else
    table.insert(out, quotes)
  end
  return table.concat(out, '\n')
end

local function renderDetailedDebate(frame, args, lang)
  local debate = param(args,'débat-détaillé','debat-detaille','detailed-debate')
  if debate == '' then return '' end
  local out = {}
  table.insert(out, emitCategory(lang,'cat-arg-debat-detaille'))
  table.insert(out, pf(frame, '{{#set: '.._(lang,'prop-debat-detaille')..' = '..debate..' }}'))

  table.insert(out,
    '<h2 id="Debate" class="section-modifiable">'
    .. '<span style="margin-right:0.5em; position:relative; bottom:1px;">[[Fichier:Parcourir.svg | 17px | link= | alt='..esc_attr(_(lang,'detailed-debate'))..']]</span>'
    .. _(lang,'detailed-debate')
    .. pf(frame,
      '<span class="modifier-section navigation-not-searchable noprint">{{#formlink:'
      .. ' | link text = '.._(lang,'edit')
      .. ' | form =  '.._(lang,'form-detailed-debate')
      .. ' | target = {{FULLPAGENAMEE}}'
      .. ' | tooltip = '.._(lang,'edit-detailed-debate-tooltip')
      .. ' }}</span>'
    )
    .. '</h2>'
  )

  table.insert(out,
    '<div style="border-style:solid; border-width:0 0 0 6px; margin:1em 0; padding:2px 10px; border-color:#02a68f;">\n'
    .. '<table style="background-color:transparent"><tr><td style="font-weight:bold;">'
    .. _(lang,'debate-banner-1') .. ' <span style="font-weight:normal;">{{FULLPAGENAME}}</span> ' .. _(lang,'debate-banner-2')
    .. '</td></tr><tr><td><div class="bandeau-section navigation-not-searchable onglet-externe" style="margin:0.25em 0; padding-right:0.25em; position:inherit;">'
    .. '<span style="margin:0 0.5em 0 0.25em">[[Fichier: Loupe.svg | 13px | lien= | class=mw-no-invert]]</span>'
    .. _(lang,'detailed-debate') .. ' : [[' .. debate .. ']]</div></td></tr></table></div>'
  )

  table.insert(out,
    '<div style="color:black; background-color:#f9f9f9; font-size:95%; width:100%; padding:5px;" class="onglet-externe">'
    .. '<div style="font-weight:bold; font-size:150%; font-family:\'Linux Libertine\',\'Georgia\',\'Times\',serif; line-height:1.25; margin-bottom:0.25em;">'
    .. debate .. '</div>'
    .. pf(frame, '{{#vardefine: Carte-arguments | {{#show: '..debate..' | ?'.._(lang,'prop-carte-arguments')..'}} }}{{#var: Carte-arguments}}')
    .. '</div>'
  )

  return table.concat(out, '\n')
end

local function renderReferences(frame, args, lang)
  local out = {}
  table.insert(out, '<h2 id="References" class="section-modifiable">'
    .. '<span style="margin-right:0.5em;">[[Fichier:Bibliographie.svg | 15px | link= | alt='..esc_attr(_(lang,'references'))..']]</span>'
    .. _(lang,'references') .. pf(frame,
    '<span class="modifier-section navigation-not-searchable noprint">{{#formlink:'
    .. ' | link text = '.._(lang,'edit')
    .. ' | form =  '.._(lang,'form-references')
    .. ' | target = {{FULLPAGENAMEE}}'
    .. ' | tooltip = '.._(lang,'edit-references-tooltip')
    .. ' }}</span>'
  ) .. '</h2>')

  local warns = param(args,'avertissements-références','warnings-references')
  local biblio = param(args,'références-bibliographiques','references-bibliographiques','ref-biblio')
  local sito = param(args,'références-sitographiques','ref-sito')
  local video = param(args,'références-vidéographiques','ref-video')

  if warns ~= '' then
    table.insert(out, pf(frame, '{{#arraymap: '..warns..' | , | x | {{Bandeau x}} | &#32; }}'))
  end

  if (biblio ~= '' or sito ~= '' or video ~= '') then
    table.insert(out, pf(frame, '{{#vardefine: References-argument | }}'))
    table.insert(out, pf(frame, '{{#vardefine: References-argument | {{#var: References-argument}}<ul class="references-argument">'..biblio..sito..video..'</ul> }}'))
    table.insert(out, pf(frame, '{{#var: References-argument}}'))
  else
    table.insert(out, '<div class="aucun-contenu navigation-not-searchable">'..italics(lang,'references-empty')..'</div>')
    table.insert(out, emitCategory(lang,'cat-arguments-sans-reference'))
  end
  return table.concat(out, '\n')
end

local function renderList(titleId, icon, labelKey, formKey, paramName, warnParam, emptyCatKey, addButton)
  return function(frame, args, lang)
    local out = {}
    table.insert(out, '<h2 id="'..titleId..'" class="section-modifiable">'
      .. '<span style="margin-right:0.5em; position:relative; bottom:1px;">[[Fichier:'..icon..' | 22px | link= | alt='..esc_attr(_(lang,labelKey))..']]</span>'
      .. _(lang,labelKey) .. pf(frame,
      '<span class="modifier-section navigation-not-searchable noprint">{{#formlink:'
      .. ' | link text = '.._(lang,'edit')
      .. ' | form =  '.._(lang,formKey)
      .. ' | target = {{FULLPAGENAMEE}}'
      .. ' | tooltip = '.._(lang,'edit-list-tooltip')
      .. ' }}</span>'
    ) .. '</h2>')

    local warns = param(args, warnParam)
    if warns ~= '' then
      table.insert(out, pf(frame, '{{#arraymap: '..warns..' | , | x | {{Bandeau x}} | &#32; }}'))
    end

    local items = param(args, paramName)
    table.insert(out, '<ul class="liste-arguments">')
    if items == '' then
      table.insert(out, '<div class="aucun-contenu navigation-not-searchable">'..italics(lang,'list-empty')..'</div>')
      table.insert(out, emitCategory(lang, emptyCatKey))
    else
      table.insert(out, items)
    end
    table.insert(out, '</ul>')

    if addButton then
      table.insert(out, pf(frame,
        '{{#queryformlink:'
        .. ' | form = '.._(lang,'form-new-argument-title')
        .. ' | query string = '..addButton..'={{PAGEID}}&_run'
        .. ' | link type = post button'
        .. ' | link text = '.._(lang,'add-argument')
        .. ' | tooltip = '.._(lang,'add-argument-tooltip')..' : {{FULLPAGENAME}}'
        .. ' }}'
      ))
    end

    return table.concat(out, '\n')
  end
end

local renderJustifications = renderList('Pros', 'Argument-pour.svg', 'justifications-title', 'form-justifications', 'justifications', 'avertissements-justifications', 'cat-arguments-sans-justification', 'Nouveau titre d\'argument[type]=Justification&Nouveau titre d\'argument[ID]')
local renderObjections    = renderList('Cons', 'Argument-contre.svg', 'objections-title', 'form-objections', 'objections', 'avertissements-objections', 'cat-arguments-sans-objection', 'Nouveau titre d\'argument[type]=Objection&Nouveau titre d\'argument[ID]')

local function renderParents(frame, args, lang)
  -- On génère le wikitexte SMW et Arrays puis on le pré-expanse en un bloc
  local wt = table.concat({
    '{{#vardefine: Debats-parents | }}',
    '{{#vardefine: Debats-parents-argupour | {{#ask: [[Argument pour::{{FULLPAGENAME}}]] | sep = -;- | link = none }} }}',
    '{{#vardefine: Debats-parents-argucontre | {{#ask: [[Argument contre::{{FULLPAGENAME}}]] | sep = -;- | link = none }} }}',
    '{{#vardefine: Debats-parents | {{#var: Debats-parents-argupour}} -;- {{#var: Debats-parents-argucontre}} }}',
    '{{#arraydefine: Debats-parents | {{#var: Debats-parents}} | -;- }}',
    '{{#arrayunique: Debats-parents}}',
    '{{#vardefine: Nombre-debats-parents | {{#arraysize: Debats-parents}} }}',
    '{{#switch: {{#var: Nombre-debats-parents}}'
      .. ' | 0 = '
      .. ' | 1 = <h2 id="Parent_debates"><span style="margin-right:0.45em;">[[Fichier:Fleche-haut.svg | 20px | link= | alt='..esc_attr(_(lang,'parent-debate'))..']]</span>'.._(lang,'parent-debate')..'</h2>'
      .. ' <ul class="navigation-not-searchable"><li style="position: relative;">{{Carte des arguments | {{#arrayprint: Debats-parents | -;-}} | {{FULLPAGENAME}} | hover-top | débat}}</li></ul>'
      .. ' | #default = <h2 id="Parent_debates"><span style="margin-right:0.45em;">[[Fichier:Fleche-haut.svg | 20px | link= | alt='..esc_attr(_(lang,'parent-debates'))..']]</span>'.._(lang,'parent-debates')..'</h2>'
      .. ' <ul class="navigation-not-searchable">{{#arraymap: {{#arrayprint: Debats-parents | -;-}} | -;- | x | <li style="position: relative;">{{Carte des arguments | x | {{FULLPAGENAME}} | hover-top | débat}}</li> | }}</ul>'
      .. ' }}'
  }, '\\n')
  return pf(frame, wt)
end

local function renderSEO(frame, args, lang, t)
  return pf(frame, '{{#seo:'
    .. ' | title = '.._(lang,'seo-title-prefix')..' {{FULLPAGENAME}} '.._(lang,'seo-title-suffix')
    .. ' | title_mode = '.._(lang,'seo-title-mode-prefix')..' {{FULLPAGENAME}}'
    .. ' | title_separator = –'
    .. ' | description = '.._(lang,'seo-description-prefix')..' {{#if: {{{mots-clés|}}} | {{{mots-clés|}}} | {{FULLPAGENAME}} }}. '
    .. _(lang,'seo-description-suffix')
    .. ' | keywords = '.._(lang,'seo-keywords')..', {{{mots-clés|}}}, {{{rubriques|}}}, débat, objection, thèse, wiki, encyclopédie, opinion'
    .. ' | image = '.._(lang,'seo-image')
    .. ' | image_alt = '.._(lang,'seo-image-alt')
    .. ' | type = article'
    .. ' | section = '.._(lang,'seo-section')
    .. ' | site_name = '.._(lang,'seo-site-name')
    .. ' | twitter_site = '.._(lang,'seo-twitter')
    .. ' | google-site-verification = 76d1055d3ec815c'
    .. ' | locale = '.._(lang,'seo-locale')
    .. ' | hreflang_de-de = https://de.wikidebates.org/'
    .. ' | hreflang_en-us = https://en.wikidebates.org/'
    .. ' | hreflang_es-es = https://es.wikidebates.org/'
    .. ' | hreflang_it-it = https://it.wikidebates.org/'
    .. ' | hreflang_pt-pt = https://pt.wikidebates.org/'
    .. ' | og:url = '..t.url
    .. ' }}')
end

local function renderInterlang(frame, args)
  local out = {}
  local inter = param(args,'interlangue','interlanguage')
  if inter ~= '' then table.insert(out, inter) end
  local interwiki = param(args,'interwiki')
  if interwiki ~= '' then
    table.insert(out, pf(frame, '{{#arraymap: '..interwiki..' | ; | <page> | [[<page>]] | }}'))
  end
  return table.concat(out, '\n')
end

local function titleChecks(frame, lang, t)
  local out = {}

  if mw.ustring.len(t.full) < 3 then
    table.insert(out,
      '<div class="warningbox navigation-not-searchable">\n<b>' ..
      _(lang,'title-warning-short') ..
      '</b></div>'
    )
    table.insert(out, emitCategory(lang,'cat-titres-tres-courts'))
  end

  if mw.ustring.sub(t.full, -1) == '.' then
    if mw.ustring.sub(t.full, -4) ~= 'etc.' then
      table.insert(out,
        '<div class="warningbox navigation-not-searchable">\n<b>' ..
        _(lang,'title-warning-dot') ..
        '</b></div>'
      )
      table.insert(out, emitCategory(lang,'cat-titres-terminant-point'))
    end
  end

  -- Catégories par préfixes (éventuellement paramétrées via i18n.title_prefix_categories)
  local prefixes = i18n.title_prefix_categories or {}
  for n, list in pairs(prefixes) do
    local nnum = tonumber(n) or 0
    if nnum > 0 then
      local sub = mw.ustring.sub(t.full, 1, nnum)
      local cats = list[sub]
      if cats then
        for _, catKey in ipairs(cats) do
          table.insert(out, emitCategory(lang, catKey))
        end
      end
    end
  end

  return table.concat(out, '\n')
end

local function renderEndCatsAndProps(frame, args, lang)
  local out = {}
  table.insert(out, emitCategory(lang,'cat-arguments'))

  table.insert(out, pf(frame, '{{#set: '
    .. 'Nom de page d\'argument = {{FULLPAGENAME}}'
    .. ' | Carte des arguments = {{#var: Carte-arguments}}'
    .. ' | Contenu d\'argument = {{#var: Contenu-argument}}'
    .. ' }}'))

  table.insert(out, pf(frame, '{{#if: {{{rubriques|}}} | {{#arraymap: {{{rubriques|}}} | , | x | [[Catégorie:x]][[Rubrique::x| ]] | }} | '..emitCategory(lang,'cat-arguments-sans-rubrique')..' }}'))

  table.insert(out, pf(frame, '{{#arraymap: {{{mots-clés|}}} | , | x | {{#set: Mot-clé = x}} | }}'))

  return table.concat(out, '\n')
end

-- ===== Orchestration =====
function p.render(frame)
  local parent = frame:getParent()
  local args = parent and parent.args or frame.args
  local lang = args.lang or mw.getContentLanguage():getCode()
  local t = titleData()

  local out = {}

  -- SHORTDESC + default form (pré-expansion)
  table.insert(out, pf(frame, '{{SHORTDESC: '.._(lang,'shortdesc')..' }}'))
  table.insert(out, pf(frame, '{{#default_form: '.._(lang,'default-form-argument')..' }}'))

  -- Numéro d'argument (catégorie SMW)
  table.insert(out, '[[Numéro d\'argument:: '..t.id..'| ]]')

  -- Vérifs et catégories liées au titre
  table.insert(out, titleChecks(frame, lang, t))

  -- Bandeaux avertissements de titre/argument (pré-expansion)
  local avTitre = param(args, 'avertissements-titre')
  local avArg = param(args, 'avertissements-argument')
  if avTitre ~= '' or avArg ~= '' then
    local list = (avTitre ~= '' and avArg ~= '') and (avTitre..','..avArg) or (avTitre ~= '' and avTitre or avArg)
    table.insert(out, pf(frame, '{{#arraymap: '..list..' | , | x | {{Bandeau x}} | &#32; }}'))
  end

  -- Mots-clés
  table.insert(out, renderKeywords(frame, args, lang))

  -- Résumé
  table.insert(out, renderSummary(frame, args, lang))

  -- Citations
  table.insert(out, renderQuotes(frame, args, lang))

  -- Débat détaillé
  table.insert(out, renderDetailedDebate(frame, args, lang))

  -- Références
  table.insert(out, renderReferences(frame, args, lang))

  -- Justifications & Objections
  table.insert(out, renderJustifications(frame, args, lang))
  table.insert(out, renderObjections(frame, args, lang))

  -- Carte arguments (résumé des colonnes) — bloc pré-expansé avec variables
  table.insert(out, pf(frame, '{{#vardefine: Carte-arguments | <table style="background-color:transparent; width:100%;" class="navigation-not-searchable">'
    .. '<tr><th style="text-align:left;">'.._(lang,'justifications-title')..'</th>'
    .. '<th style="text-align:left; padding-left:1em;">'.._(lang,'objections-title')..'</th></tr>'
    .. "<tr style=\"vertical-align:top;\"><td><div>{{#var: Carte-justifications | <div style=\"font-size:95%\">'' " .. _(lang,'none-entered') .. " ''</div> }}</div></td>"
	.. "<td style=\"padding-left:1em;\"><div>{{#var: Carte-objections | <div style=\"font-size:95%\">'' " .. _(lang,'none-entered-fem') .. " ''</div> }}</div></td>"
    .. '</tr></table> }}'))

  -- Débats parents (liste + cartes)
  table.insert(out, renderParents(frame, args, lang))

  -- Interlang / interwiki
  table.insert(out, renderInterlang(frame, args))

  -- Catégorie "sans contenu" si tout vide
  table.insert(out, pf(frame, '{{#if: {{{résumé|}}}{{{citations|}}}{{{références-bibliographiques|}}}{{{références-sitographiques|}}}{{{références-vidéographiques|}}} | | '..emitCategory(lang,'cat-arguments-sans-contenu')..' }}'))

  -- Catégories & propriétés finales
  table.insert(out, renderEndCatsAndProps(frame, args, lang))

  -- SEO
  table.insert(out, renderSEO(frame, args, lang, t))

  -- Boutons masqués (pré-expansion)
  table.insert(out, pf(frame, '<span id="bouton-renommer" class="modifier-rubrique navigation-not-searchable" style="display:none;">[[Spécial:Renommage/{{FULLPAGENAME}}| '.._(lang,'rename')..']]</span>'))
  table.insert(out, pf(frame, '<span id="bouton-modifier-categories" class="modifier-rubrique navigation-not-searchable noprint" style="display:none;">{{#formlink:'
    .. ' | link text = '.._(lang,'edit')
    .. ' | form =  '.._(lang,'form-argument-rubriques')
    .. ' | target = {{FULLPAGENAMEE}}'
    .. ' | tooltip = '.._(lang,'edit-rubriques-tooltip')
    .. ' }}</span>'))
  table.insert(out, pf(frame, '<span id="bouton-modifier-interlangue" class="modifier-rubrique navigation-not-searchable noprint" style="display:none;">{{#formlink:'
    .. ' | link text = '.._(lang,'edit')
    .. ' | form =  '.._(lang,'form-argument-interlang')
    .. ' | target = {{FULLPAGENAMEE}}'
    .. ' | tooltip = '.._(lang,'edit-interlang-tooltip')
    .. ' }}</span>'))

  -- NOCACHE (comme l'original)
  table.insert(out, '__NOCACHE__')

  return table.concat(out, '\n')
end

return p