Jump to content
 







Main menu
   


Navigation  



Main page
Contents
Current events
Random article
About Wikipedia
Contact us
Donate
 




Contribute  



Help
Learn to edit
Community portal
Recent changes
Upload file
 








Search  

































Create account

Log in
 









Create account
 Log in
 




Pages for logged out editors learn more  



Contributions
Talk
 



















Contents

   



(Top)
 


1 Usage  





2 Submodules  














Module:External links






Алтай тил
Аԥсшәа
العربية
Արեւմտահայերէն
Авар
Azərbaycanca

Башҡортса
Беларуская
Беларуская (тарашкевіца)
Буряад
Català
Чӑвашла
Cebuano
Cymraeg
Dansk
الدارجة
Ελληνικά
Эрзянь
فارسی
ГӀалгӀай

Հայերեն
ि
Bahasa Indonesia
Italiano
Jawa

Қазақша
Лакку
Лезги
Magyar
ि
Македонски

مصرى
Мокшень
Монгол


Нохчийн
Norsk bokmål
Oʻzbekcha / ўзбекча

Qaraqalpaqsha
Română
Русский
Саха тыла
Simple English
Slovenščina
کوردی
Српски / srpski
Srpskohrvatski / српскохрватски
ி
Tarandíne
Татарча / tatarça

Тоҷикӣ
Türkçe
Удмурт
Українська
اردو
Vèneto
Tiếng Vit


 
 

Edit links
 









Module
Talk
 

















Read
View source
View history
 








Tools
   


Actions  



Read
View source
View history
 




General  



What links here
Related changes
Upload file
Special pages
Permanent link
Page information
Get shortened URL
Download QR code
Wikidata item
 




Print/export  



Download as PDF
Printable version
 
















Appearance
   

 





Permanently protected module

From Wikipedia, the free encyclopedia
 


This module is designed for implementing templates to display external links in an English Wikipedia article, using the properties defined in that article's Wikidata item. It was based on the Norwegian Wikipedia module no:Modul:External links.

The first test implementation is Template:Sports links (based on no:Mal:Sportslenker). The sports-related link properties and formats are specified in Module:External links/conf/Sports (based on no:Modul:External links/conf/Sport).

Other subject-based implementations at the Norwegian Wikipedia include:

Usage

{{#invoke:External links|function_name}}

Submodules

  • External links/conf/Sports
  • External links/conf/Sports/doc
  • External links/conf/Sports/sandbox
  • External links/conf/doc
  • External links/conf/documentation page
  • External links/doc
  • External links/sandbox
  • require('strict')
    -- local genitive = require('Module:Genitive')._genitive
    local contLang = mw.language.getContentLanguage()
    
    local cmodule = {}
    local conf = require 'Module:External links/conf'(contLang:getCode())
    local hasdatafromwikidata = false
    local hasdatafromlocal = false
    local haswikidatalink = true -- we assume it's connected
    
    local p = {}
    
    local function getLabel(entity, use_genitive, pagetitle)
     local label = (pagetitle and pagetitle ~= '') and pagetitle or nil
     if not label and not entity then
      label = mw.title.getCurrentTitle().text
     elseif not label then
      label = mw.wikibase.label(entity.id) or mw.title.getCurrentTitle().text
     end
    -- return use_genitive and genitive(label, 'sitt') or label
     return use_genitive and label .. "'s" or label
    end
    
    -- @todo cleanup, this is in production, use the console
    local function dump(obj)
     return "<pre>" .. mw.dumpObject(obj) .. "</pre>"
    end
    
    
    local function stringFormatter( datavalue )
     if datavalue == nil or datavalue['type'] ~= 'string' then
      return nil
     end
     return datavalue.value
    end
    
    local pval = {}
    pval.P1793 = { -- format as a regular expression
     types = {
      snaktype = 'value',
      datatype = 'string',
     },
    }
    
    pval.P407 = { -- language of work or name
     types = {
      snaktype = 'value',
      datatype = 'wikibase-item',
      datavalue = {
       type = 'wikibase-entityid', 
      }
     },
    }
    
    pval.P364 = { -- original language of work 
     types = {
      snaktype = 'value',
      datatype = 'wikibase-item',
      datavalue = {
       type = 'wikibase-entityid', 
      }
     },
    }
    
    pval.P218 = { -- ISO 639-1 language 
     types = {
      snaktype = 'value',
      datatype = 'external-id',
      datavalue = {
       type = 'string', 
      }
     },
    }
    
    pval.P305 = { -- IETF language tag
     types = {
      snaktype = 'value',
      datatype = 'external-id',
      datavalue = {
       type = 'string', 
      }
     },
    }
    
    pval.P582 = { -- end time
     types = {
      snaktype = 'value',
      datatype = 'time',
      datavalue = {
       type = 'string', 
      }
     },
    }
    
    
    -- This is a really makeshift crappy converter, but it'll do some basic
    -- conversion from PCRE to Lua-style patterns (note that this only work
    -- in very few cases)
    local function regexConverter( regex )
     local output = regex
     output = string.gsub(output, "\\d{2}", "%%d%%d")
     output = string.gsub(output, "\\d{3}", "%%d%%d%%d")
     output = string.gsub(output, "\\d{4}", "%%d%%d%%d%%d")
     output = string.gsub(output, "\\d{5}", "%%d%%d%%d%%d%%d")
     output = string.gsub(output, "\\d{6}", "%%d%%d%%d%%d%%d%%d")
     output = string.gsub(output, "\\d{7}", "%%d%%d%%d%%d%%d%%d%%d")
     output = string.gsub(output, "\\d{8}", "%%d%%d%%d%%d%%d%%d%%d%%d")
     output = string.gsub(output, "\\d", "%%d")
     
     return output
    end
    
    
    local function getFormatterUrl( prop, value )
     local head = ""
     local tail = ""
     local entity = mw.wikibase.getEntity(prop)
     -- to avoid deep tests
     if not entity or not entity.claims then
      return head
     end
     -- get the claims for this entity
     local statements = entity.claims['P1630'] -- formatter URL
     -- to avoid deep tests
     if not statements then
      return head
     end
     local formatters = {}
     -- let's go through the claims
     for _, claim in ipairs( statements ) do
      -- to avoid deep tests
      if not claim then
       claim = {}
      end
      local valid = claim['type'] == 'statement'
       and claim['rank'] ~= 'deprecated'
      if valid then
       local mainsnak = claim.mainsnak or {}
       local preferred = claim['rank'] == 'preferred'
       -- get any qualifiers for this claim (we are interested in P1793 for
       -- indication of which claim is correct) 
       local qualifiers = claim.qualifiers or {}
       -- now let's check the qualifier we are interested in
       local qualid = 'P1793' -- format as a regular expression
       -- if the claim has this qualifier
       if qualifiers[qualid] then
        -- it's here, let's check it out!
        local items = {}
        -- traverse all snaks in this qualifier
        for _, qualsnak in ipairs( qualifiers[qualid] ) do
         if qualsnak and pval[qualid] then
          --mw.log("qualsnak = " .. dump(qualsnak))
          -- check if the snak is of the correct snaktype and datatype
          local valid = qualsnak.snaktype == pval[qualid].types.snaktype
           and qualsnak.datatype == pval[qualid].types.datatype
          if valid then
           -- we'll have to convert the regex to Lua-style
           local regex = regexConverter(qualsnak.datavalue.value)
           local test = string.match( value, '^'..regex..'$' )
           if test then
            -- it matched, this is correct and overrides any other.
            if preferred then
             head = mainsnak.datavalue.value
            else
             tail = mainsnak.datavalue.value
            end
           end
          end
         end
        end
       else
        -- we don't have any qualifier, is it preferred?
        if (head == '' and preferred) or (tail == '' and not preferred) then
         -- if we don't have any other, use this one
         if preferred and head == '' then
          head = mainsnak.datavalue.value
         elseif not preferred and tail == '' then
          tail = mainsnak.datavalue.value
         end
        end
       end
      end
     end
     return head ~= '' and head or tail
    
    end
    
    
    
    local function getLanguageData(prop, qid)
     local head = {}
     local tail = {}
     -- mw.log("getLanguageData, prop="..dump(prop).." qid="..dump(qid))
     -- get the entity we are checking
     local entity = mw.wikibase.getEntityObject(qid)
     -- to avoid deep tests
     if not entity then
      return nil
     end
     if not entity.claims then
      return {}
     end
     -- get the claims for this entity
     local statements = entity.claims[prop]
     -- to avoid deep tests
     if not statements then
      return {}
     end
     -- mw.log("getLanguageData going through claims="..dump(statements))
     -- let's go through the claims
     for _, claim in ipairs( statements ) do
      -- to avoid deep tests
      if not claim then
       claim = {}
      end
      local valid = claim['type'] == 'statement'
       and claim['rank'] ~= 'deprecated'
      if valid then
       local mainsnak = claim.mainsnak or {}
       local preferred = claim['rank'] == 'preferred'
       -- verify the item is what we expect
       local valid = mainsnak.snaktype == pval[prop].types.snaktype
        and mainsnak.datatype == pval[prop].types.datatype
        and mainsnak.datavalue.type == pval[prop].types.datavalue.type
       if valid then
        -- mw.log("getLanguageData claim is valid="..dump(claim))
        -- if this is the correct P-value, dive into it and get P218 (ISO 639-1)
        if mainsnak.property == 'P364' then -- original language of work
         if preferred then
          head[#head+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator'))
         else
          tail[#tail+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator'))
         end
        elseif mainsnak.property == 'P218' or mainsnak.property == 'P305' then -- ISO 639-1 code or IETF language tag
         if preferred then
          head[#head+1] = stringFormatter(mainsnak.datavalue)
         else
          tail[#tail+1] = stringFormatter(mainsnak.datavalue)
         end
        end
       end
      end
     end
     -- mw.log("getLanguageData returning head="..dump(head).." tail="..dump(tail))
     return #head>0 and head or tail
    end
    
    local langqvalorder = {'P407','P364'}
    local otherqvalorder = {'P582'}
    
    local function getValuesFromWikidata(props)
     local head = {}
     local tail = {}
     -- mw.log("getValuesFromWikidata, props="..dump(props))
     -- get the entity we are checking
     local entity = mw.wikibase.getEntityObject()
     -- to avoid deep tests
     if not entity then
      --mw.log("getValuesFromWikidata no entity")
      return nil
     end
     if not entity.claims or not props or not props.prop or props.prop == '' then
      --mw.log("getValuesFromWikidata no claims or no props")
      return {}
     end
     -- get the claims for this entity
     local statements = entity.claims[props.prop]
     -- to avoid deep tests
     if not statements then
      return {}
     end
     -- let's go through the claims
     for _, claim in ipairs( statements ) do
      -- to avoid deep tests
      if not claim then
       claim = {}
      end
      local valid = claim['type'] == 'statement'
       and claim['rank'] ~= 'deprecated'
      if valid then
       -- mw.log("getValuesFromWikidata valid claim="..dump(claim))
       local mainsnak = claim.mainsnak or {}
       local preferred = claim['rank'] == 'preferred'
       -- get the content of the claim (the identifier)
       local langcode = props.langcode
       local checklangcode = nil
       if props.langcode and props.langcode ~= '' then
        checklangcode = string.find(langcode, "([pP]%d+)")
       end
       if checklangcode and checklangcode ~= "" then
        -- this is a P-value for language-code, so we'll check qualifiers for languagedata
        -- first get any qualifiers
        local qualifiers = claim.qualifiers or {}
        for _, qualid in ipairs( langqvalorder ) do
         -- if the claim has this qualifier
         if qualifiers[qualid] then
          -- it's here, let's check it out!
          local items = {}
          -- traverse all snaks in this qualifier
          for _, qualsnak in ipairs( qualifiers[qualid] ) do
           if qualsnak and pval[qualid] then
            -- mw.log("qualsnak = " .. dump(qualsnak))
            -- check if the snak is of the correct snaktype and datatype
            local valid = qualsnak.snaktype == pval[qualid].types.snaktype
             and qualsnak.datatype == pval[qualid].types.datatype
            if valid then
             -- now get the actual data
             langcode = table.concat(getLanguageData('P305', 'Q'..qualsnak.datavalue.value['numeric-id']), '')
            end
           end
          end
         end
         -- mw.log("langcode is now="..dump(langcode))
        end
        if string.find(langcode, "([pP]%d+)") then
         -- we still don't have any langcode, so we default to "en"
         langcode = nil
        end
       end
       local stillvalid = true
       -- we should check a couple of other qualifiers as well
       -- first get any qualifiers
       local qualifiers = claim.qualifiers or {}
       for _, qualid in ipairs( otherqvalorder ) do
        -- if the claim has this qualifier
        if qualifiers[qualid] then
         -- it's here, let's check it out!
         local items = {}
         -- traverse all snaks in this qualifier
         for _, qualsnak in ipairs( qualifiers[qualid] ) do
          if qualsnak and pval[qualid] then
           -- mw.log("qualsnak = " .. dump(qualsnak))
           -- check if the snak is of the correct snaktype and datatype
           local valid = qualsnak.snaktype == pval[qualid].types.snaktype
            and qualsnak.datatype == pval[qualid].types.datatype
           if not valid then
            -- sorry, this is not correct
            mw.log("qualsnak = INCORRECT")
            stillvalid = false
           end
          end
         end
        end
        -- mw.log("langcode is now="..dump(langcode))
       end
       if stillvalid then
        if preferred then
         head[#head+1] = { value=stringFormatter(mainsnak.datavalue) }
         if langcode and langcode ~= '' then
          head[#head]['langcode'] = langcode
         end
        else
         tail[#tail+1] = { value=stringFormatter(mainsnak.datavalue) }
         if langcode and langcode ~= '' then
          tail[#tail]['langcode'] = langcode
         end
        end
       end
      end
     end
     -- mw.log("getValuesFromWikidata returning head="..dump(head).." tail="..dump(tail))
     return #head>0 and head or tail
    end
    
    local function findMainLinksOnWikidata(props, pagetitle, short_links)
     local output = {}
     local pid = nil
     -- get the entity we are checking
     local entity = mw.wikibase.getEntityObject()
     -- to avoid deep tests
     if not entity then
      return nil
     end
     local values = getValuesFromWikidata(props)
     for _, value in ipairs( values ) do
      local verified_value = nil
      if props.regex then
       -- we have a local defined regex, so this will have to pass first
       -- maybe we'll have to convert the regex to Lua-style
       local regex = regexConverter(props.regex)
       local test = string.match( value.value, '^'..regex..'$' )
       --mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id)
       if test then
        -- it matched, this is correct and overrides any other.
        verified_value = value.value
       end
      else
       verified_value = value.value
      end
      if verified_value then
       local url = ''
       output[#output+1] = {}
       output[#output].langcode = value.langcode
       output[#output].category = {}
       if props.url_f then
        -- we have a local defined url-formatter function, use it as first priority
        url = props.url_f(verified_value)
        if props.track and not string.find(props.langcode, "([pP]%d+)") then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
        elseif props.track then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
        end
       elseif props.url then
        -- we have a local defined url-formatter string, use it as second priority
        url = mw.message.newRawMessage(props.url, verified_value):plain()
        if props.track and not string.find(props.langcode, "([pP]%d+)") then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
        elseif props.track then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
        end
       else
        -- get the formatvalue from the property, if it exists
        local formatterUrl = getFormatterUrl(props.prop, verified_value)
        if formatterUrl ~= '' then
         url = mw.message.newRawMessage(formatterUrl, verified_value):plain()
         if props.track then 
          output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
         end
        end
       end
       if url ~= '' then
        local this_wiki = mw.getContentLanguage()
        local this_wiki_code = this_wiki:getCode()
        local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or ""
        if short_links and props.short then
         output[#output].text =
          mw.message.newRawMessage(props.short,
           getLabel(entity, props.genitive, pagetitle),
           url,
           langlink,
           verified_value,
           mw.uri.encode(verified_value, 'PATH'))
          :plain()
        else
         output[#output].text =
          mw.message.newRawMessage(props.message,
           getLabel(entity, props.genitive, pagetitle),
           url,
           langlink,
           verified_value,
           mw.uri.encode(verified_value, 'PATH'))
          :plain()
        end
       end
      end
     end
     --mw.log("findMainLinksOnWikidata returning="..dump(output))
     return output
    end
    
    local function getSitelinksFromWikidata(props, entity)
     local output = {}
     --mw.log("getSitelinksFromWikidata, props="..dump(props))
     -- to avoid deep tests
     if not entity then
      entity = mw.wikibase.getEntityObject()
      if not entity then
       --mw.log("getSitelinksFromWikidata no entity")
       return nil
      end
     end
     local requested_sitelink = string.match(props.prop, "SL(%l+)")
     local sitelinks = entity:getSitelink(requested_sitelink)
     if sitelinks and sitelinks ~= '' then
      output[#output+1] = { value = sitelinks }
     end
     --mw.log("getSitelinksFromWikidata returning output="..dump(output))
     return output
    end
    
    
    local function findSiteLinksOnWikidata(props, pagetitle, short_links)
     local output = {}
     local pid = nil
     -- get the entity we are checking
     local entity = mw.wikibase.getEntityObject()
     -- to avoid deep tests
     if not entity then
      return nil
     end
     local values = getSitelinksFromWikidata(props)
     for _, value in ipairs( values ) do
      local verified_value = nil
      if props.regex then
       -- we have a local defined regex, so this will have to pass first
       -- maybe we'll have to convert the regex to Lua-style
       local regex = regexConverter(props.regex)
       local test = string.match( value.value, '^'..regex..'$' )
       --mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id)
       if test then
        -- it matched, this is correct and overrides any other.
        verified_value = value.value
       end
      else
       verified_value = value.value
      end
      if verified_value then
       --mw.log("it's verified..")
       local url = ''
       output[#output+1] = {}
       output[#output].langcode = value.langcode
       output[#output].category = {}
       if props.url_f then
        -- we have a local defined url-formatter function, use it as first priority
        url = props.url_f(verified_value)
        if props.track and not string.find(props.langcode, "(SL%l+)") then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
        elseif props.track then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
        end
       elseif props.url then
        -- we have a local defined url-formatter string, use it as second priority
        url = mw.message.newRawMessage(props.url, verified_value):plain()
        if props.track and not string.find(props.langcode, "(SL%l+)") then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
        elseif props.track then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
        end
       else
        url = verified_value:gsub(' ','_')
        if props.track then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
        end
       end
       if url ~= '' then
        local this_wiki = mw.getContentLanguage()
        local this_wiki_code = this_wiki:getCode()
        local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or ""
        if short_links and props.short then
         output[#output].text =
          mw.message.newRawMessage(props.short,
           getLabel(entity, props.genitive, pagetitle),
           url,
           langlink,
           verified_value,
           mw.uri.encode(verified_value, 'PATH'))
          :plain()
        else
         output[#output].text =
          mw.message.newRawMessage(props.message,
           getLabel(entity, props.genitive, pagetitle),
           url,
           langlink,
           verified_value,
           mw.uri.encode(verified_value, 'PATH'))
          :plain()
        end
       end
      end
     end
     --mw.log("findSiteLinksOnWikidata returning="..dump(output))
     return output
    end
    
    
    local function findMainLinksLocal(props, pagetitle, short_links, local_value)
     local output = {}
     -- to avoid deep tests
     if not props.prop then
      return nil
     end
     if not local_value or local_value == '' then
      -- bail out if no value is present
      return output
     end
     -- get the formatvalue from the property
     local verified_value = local_value
     if props.regex and props.regex ~= '' then
      -- let's verify the id
      -- maybe we'll have to convert the regex to Lua-style
      local regex = regexConverter(props.regex)
      local test = string.match( local_value, '^'..regex..'$' )
      if test then
       -- it matched, this is correct
       verified_value = local_value
      else
       verified_value = nil
      end
      
     end
     if not verified_value then
      return output
     end
     local wikidata_property = string.find(props.prop, "([pP]%d+)")
     local wikidata_values = {}
     if wikidata_property then
      -- get any wikidata values to see if they are equal to local values
      wikidata_values = getValuesFromWikidata(props)
     end
     if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then
      output[#output+1] = {}
      output[#output].langcode = string.find(props.langcode, "([pP]%d+)") and "" or props.langcode
      --mw.log("findMainLinksLocal - props="..dump(props).." langcode="..output[#output].langcode)
      output[#output].category = {}
      local url = ''
      if props.track and wikidata_property and wikidata_values and #wikidata_values then
       local local_value_in_wikidata = false
       for _,value in ipairs( wikidata_values ) do
        if value.value == verified_value then
         local_value_in_wikidata = true
        end
       end
       output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain()
      end
      if wikidata_property and wikidata_values and #wikidata_values then
       hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim
      end
      if props.url_f then
       -- we have a local defined url-formatter function, use it as first priority
       url = props.url_f(verified_value)
       if props.track then 
        output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
       end
      elseif props.url then
       -- we have a local defined url-formatter string, use it as second priority
       url = mw.message.newRawMessage(props.url, verified_value):plain()
       if props.track then 
        output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
       end
      elseif wikidata_property then
       -- get the formatvalue from the property, if it exists
       local formatterUrl = getFormatterUrl(props.prop, verified_value)
       if formatterUrl ~= '' then
        url = mw.message.newRawMessage(formatterUrl, verified_value):plain()
        if props.track then 
         output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain()
        end
       end
      else
       -- no other choice, bail out
       return {}
      end
      local this_wiki = mw.getContentLanguage()
      local this_wiki_code = this_wiki:getCode()
      local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or ""
      if short_links and props.short then
       output[#output].text =
        mw.message.newRawMessage(props.short,
         getLabel(nil, props.genitive, pagetitle),
         url,
         langlink,
         verified_value,
         mw.uri.encode(verified_value, 'PATH'))
        :plain()
      else
       output[#output].text =
        mw.message.newRawMessage(props.message,
         getLabel(nil, props.genitive, pagetitle),
         url,
         langlink,
         verified_value,
         mw.uri.encode(verified_value, 'PATH'))
        :plain()
      end
     end
     --mw.log("findMainLinksLocal returning="..dump(output))
     return output
    end
    
    local function findSiteLinksLocal(props, pagetitle, short_links, local_value)
     local output = {}
     -- to avoid deep tests
     if not props.prop then
      return nil
     end
     if not local_value or local_value == '' then
      -- bail out if no value is present
      return output
     end
     -- get the formatvalue from the property
     local verified_value = local_value
     if props.regex and props.regex ~= '' then
      -- let's verify the id
      -- maybe we'll have to convert the regex to Lua-style
      local regex = regexConverter(props.regex)
      local test = string.match( local_value, '^'..regex..'$' )
      if test then
       -- it matched, this is correct
       verified_value = local_value
      else
       verified_value = nil
      end
      
     end
     if not verified_value then
      return output
     end
     local wikidata_property = string.find(props.prop, "(SL.+)")
     local wikidata_values = {}
     if wikidata_property then
      -- get any wikidata values to see if they are equal to local values
      wikidata_values = getSitelinksFromWikidata(props)
     end
     if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then
      output[#output+1] = {}
      output[#output].langcode = string.find(props.langcode, "(SL.+)") and "" or props.langcode
      --mw.log("findSiteLinksLocal - props="..dump(props).." langcode="..output[#output].langcode .." wikidata_values="..dump(wikidata_values))
      output[#output].category = {}
      local url = ''
      if props.track and wikidata_property and wikidata_values and #wikidata_values then
       local local_value_in_wikidata = false
       for _,value in ipairs( wikidata_values ) do
        if value.value == verified_value then
         local_value_in_wikidata = true
        end
       end
       output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain()
      end
      if wikidata_property and wikidata_values and #wikidata_values then
       hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim
      end
      if props.url_f then
       -- we have a local defined url-formatter function, use it as first priority
       url = props.url_f(verified_value)
       if props.track then 
        output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
       end
      elseif props.url then
       -- we have a local defined url-formatter string, use it as second priority
       url = mw.message.newRawMessage(props.url, verified_value):plain()
       if props.track then 
        output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
       end
      elseif wikidata_property then
       url = verified_value:gsub(' ','_')
       if props.track then 
        output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain()
       end
      else
       -- no other choice, bail out
       return {}
      end
      local this_wiki = mw.getContentLanguage()
      local this_wiki_code = this_wiki:getCode()
      local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or ""
      if short_links and props.short then
       output[#output].text =
        mw.message.newRawMessage(props.short,
         getLabel(nil, props.genitive, pagetitle),
         url,
         langlink,
         verified_value,
         mw.uri.encode(verified_value, 'PATH'))
        :plain()
      else
       output[#output].text =
        mw.message.newRawMessage(props.message,
         getLabel(nil, props.genitive, pagetitle),
         url,
         langlink,
         verified_value,
         mw.uri.encode(verified_value, 'PATH'))
        :plain()
      end
     end
     --mw.log("findSiteLinksLocal returning="..dump(output))
     return output
    end
    
    
    local function addLinkback(str, property)
     local id = mw.wikibase.getEntityObject()
     if not id then
      return str
     end
     if type(id) == 'table' then
      id = id.id
     end
     
     local class = ''
     local url = ''
     if property then
      class = 'wd_' .. string.lower(property)
      url = mw.uri.fullUrl('d:' .. id .. '#' .. property)
      url.fragment = property
     else
      url = mw.uri.fullUrl('d:' .. id )
     end
     
     local title = conf:g('wikidata-linkback-edit')
     local icon = '[%s [[File:Blue pencil.svg|%s|10px|text-top|link=]] ]'
     url = tostring(url)
     local v = mw.html.create('span')
      :addClass(class)
      :wikitext(str)
      :tag('span')
       :addClass('noprint plainlinks wikidata-linkback')
       :css('padding-left', '.3em')
       :wikitext(icon:format(url, title))
      :allDone()
     return tostring(v)
    end
    
    
    local function getArgument(frame, argument)
     local args = frame.args
     if args[1] == nil then
      local pFrame = frame:getParent();
      args = pFrame.args;
      for k,v in pairs( frame.args ) do
       args[k] = v;
      end
     end
     if args[argument] then
      return args[argument]
     end
     return nil
    end
    
    
    local function removeEntry(conf_claims, identifier, property)
     for i, props in ipairs(conf_claims) do
      if props[identifier] == property then
       table.remove(conf_claims, i)
      end
     end
     return conf_claims
    end
    
    function p.getLinks(frame)
     local configured_conf = getArgument(frame, conf:a('arg-conf'))
     if configured_conf then
      cmodule = require ('Module:External_links/conf/'..configured_conf)
     else
      error(mw.message.newRawMessage(conf:g('missing-conf'), configured_conf):plain())
     end
     local output = {}
     local category = {}
     local conf_claims = cmodule:getConfiguredClaims(contLang:getCode())
     local limits = cmodule:getLimits()
     assert(limits, mw.message.newRawMessage(conf:g('missing-limits'), configured_conf):plain())
     local links_shown = getArgument(frame, conf:a('arg-maxlink'))
     local pagetitle = getArgument(frame, conf:a('arg-title'))
     -- get a list of tracked properties from the article itself
     local requested_tracking = getArgument(frame, conf:a('arg-track'))
     if requested_tracking and requested_tracking ~= '' then
      -- the properties should be written as P1234, P2345 and other 
      -- version corresponding to the applicable property-identifiers in the config
      for track_prop in string.gmatch(requested_tracking,"([^ ,;:]+)") do
       -- get the requested properties and be able to access them
       -- like req_prop['P345'] to verify if it was requested
       local remove_track = string.match(track_prop, "^\-(.*)")
       for i,claim in ipairs ( conf_claims )  do
        if remove_track == claim.prop or remove_track == conf:a('mod-filter-all') then
         -- if a property starts with "-", then we'll simply remove that 
         -- property from the conf_claims
         conf_claims[i]['track'] = false
        elseif track_prop == claim.prop or track_prop == conf:a('mod-filter-all') then
         conf_claims[i]['track'] = true
        end
       end
      end
     end
     -- get a list of "approved" properties from the article itself
     local requested_properties = getArgument(frame, conf:a('arg-properties'))
     --mw.log("requested_properties="..dump(requested_properties))
     -- assume all properties are allowed
     local req_prop = {}
     local no_req_prop = false  -- we'll allow properties to be filtered for now 
     if requested_properties and requested_properties ~= '' then
      -- the properties should be written as P1234, P2345 and other 
      -- version corresponding to the applicable property-identifiers in the config
      for i in string.gmatch(requested_properties,"([^ ,;:]+)") do
       -- get the requested properties and be able to access them
       -- like req_prop['P345'] to verify if it was requested
       if i == conf:a('mod-filter-all') then
        -- this is a special modifier, saying we should ignore 
        -- all previous and future positive filters and remove the
        -- filter (with exception of negative filters)
        req_prop = {}
        no_req_prop = true
       end
       local remove_prop = string.match(i, "^\-(.*)")
       if remove_prop then
        -- if a property starts with "-", then we'll simply remove that 
        -- property from the conf_claims
        conf_claims = removeEntry(conf_claims, 'prop', remove_prop)
       elseif not no_req_prop then -- only if we are allowing properties to be filtered 
        req_prop[i] = 1
        -- cheat to make #req_prop indicate populated table
        req_prop[1] = 1
       end
      end
     end
     local requested_langs = getArgument(frame, conf:a('arg-languages'))
     --mw.log("requested_langs="..dump(requested_langs))
     -- assume all languages are allowed
     local req_lang = {}
     local no_req_lang = false  -- we'll allow languages to be filtered for now
     if requested_langs and requested_langs ~= '' then
      -- the languages should be written as langcodes as used in the conf_claims
      for i in string.gmatch(requested_langs,"([^ ,;:]+)") do
       -- get the requested languages and be able to access them
       if i == conf:a('mod-filter-all') then
        -- this is a special modifier, saying we should ignore 
        -- all previous and future positive filters and remove the
        -- filter (with exception of negative filters)
        req_lang = {}
        no_req_lang = true
       end
       -- like req_lang['en'] to verify if it was requested
       local remove_lang = string.match(i, "^\-(.*)")
       if remove_lang then
        -- if a language starts with "-", then we'll simply remove that 
        -- language from the conf_claims
        conf_claims = removeEntry(conf_claims, 'langcode', remove_lang)
       elseif not no_req_lang then -- only if we are allowing languages to be filtered 
        req_lang[i] = 1
        -- cheat to make #req_lang indicate populated table
        req_lang[1] = 1
       end
      end
     end
     local short_links = getArgument(frame, conf:a('arg-short'))
     if short_links and short_links ~= '' then
      short_links = true
     else
      short_links = false
     end
     local showinline = getArgument(frame, conf:a('arg-inline'))
     if showinline and showinline ~= '' then
      showinline = true
     else
      showinline = false
     end
     if not links_shown or links_shown == '' then
      links_shown = limits['links-shown'] and limits['links-shown'] or 5
     else
      links_shown = tonumber(links_shown)
     end
     local somedataonwikidata = not short_links
     --mw.log("conf_claims="..dump(conf_claims))
     --mw.log("req_prop="..dump(req_prop))
     --mw.log("req_lang="..dump(req_lang))
     --mw.log("short_links="..dump(short_links))
     for _, props in ipairs(conf_claims) do
      -- if we're called with a list of approved properties or languages, check if this one is "approved"
      if (#req_prop==0 or req_prop[props.prop]) and (#req_lang==0 or req_lang[props.langcode] or string.find(props.langcode, "([pP]%d+)")) then
       --mw.log("checking claim="..dump(props))
       local links = {}
       local checkedonwikidata = false
       -- get the any local overriding value from the call
       local wikivalue = getArgument(frame, props.prop)
       --mw.log("wikivalue="..dump(wikivalue))
       if (not wikivalue or wikivalue == "") and string.find(props.prop, "([pP]%d+)") then
        -- the property is a Pnnn type, and therefore on Wikidata
        links = findMainLinksOnWikidata(props, pagetitle, short_links)
        if links == nil then
         -- a nil-value indicated no wikidata-link
         haswikidatalink = false
         links = {}
        else
         checkedonwikidata = true
        end
       elseif (not wikivalue or wikivalue == "") and string.find(props.prop, "(SL%l+)") then
        -- this is a sitelink-type (SLspecieswiki)
        --mw.log("finding sitelinks..")
        links = findSiteLinksOnWikidata(props, pagetitle, short_links)
        if links == nil then
         -- a nil-value indicated no wikidata-link
         haswikidatalink = false
         links = {}
        else
         checkedonwikidata = true
        end
       elseif (wikivalue and wikivalue ~= "") and string.find(props.prop, "(SL%l+)") then
        -- this is a sitelink-type (SLspecieswiki)
        links = findSiteLinksLocal(props, pagetitle, short_links, wikivalue)
       elseif wikivalue and wikivalue ~= '' then
        -- the property is of another annotation, and therefore a local construct
        links = findMainLinksLocal(props, pagetitle, short_links, wikivalue)
       end
       --mw.log("links="..dump(links))
       for _,v in ipairs(links) do
        -- we'll have to check langcodes again as they may have come from wikidata
        if (#req_lang==0 or req_lang[v.langcode]) then
         if checkedonwikidata and not hasdatafromwikidata then
          -- add a general tracking category for articles with data from wikidata
          hasdatafromwikidata = true
          category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-data-cat')
         elseif not checkedonwikidata and not hasdatafromlocal then
          -- add a general tracking category for articles with data from template-calls in local articles
          hasdatafromlocal = true
          category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-local-cat')
         end
         if short_links and props.short and v.text and v.text ~= '' then
          -- if short links were requested, and a short definition exists for this property, let's use it
          if #output==0 then
           output[#output+1] = v.text
          else
           output[#output] = output[#output] .. cmodule:getMessage(contLang:getCode(),'short-list-separator') .. v.text
          end
          somedataonwikidata = true
         elseif not short_links and not showinline and v.text and v.text ~= '' then
          -- only if short links were not requested
          output[#output+1] = (#output>=1 and conf:g('msg-ul-prepend') or '')   -- if this is the first link, we won't output a list-element (msg-ul-prepend) 
           .. (checkedonwikidata and addLinkback(v.text, props.prop) or v.text) -- if the link comes from wikidata, also output a linkback.
         elseif not short_links and showinline and v.text and v.text ~= '' then
          -- only if short links were not requested
          output[#output+1] = v.text
         end
         if props.track and v.category and #v.category then
          -- add category if tracking is on for this property and a category exists in the link-result.
          for _,cats in ipairs( v.category ) do
           category[#category+1] = cats
          end
         end
         if links_shown>0 then
          links_shown = links_shown - 1
         else
          break
         end
        end
       end
       if links_shown==0 then
        break
       end
      end
     end
     local outtext = "" 
     if short_links and #output>0 then
      -- if these are short links, output the whole thing with linkback to wikidata
      --mw.log("somedataonwikidata="..dump(somedataonwikidata).." and output="..dump(output).." and #output="..dump(#output))
      outtext = (somedataonwikidata 
       and addLinkback(table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')), nil)
       or table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')))
     elseif not short_links and not showinline and #output>0 then
      outtext = table.concat(output,"\n")
     elseif not short_links and showinline and #output>0 then
      outtext = table.concat(output,conf:g('msg-inline-separator'))
     end
     if not hasdatafromwikidata then
      category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-data-cat')
      if not hasdatafromlocal and not short_links then
       outtext = cmodule:getMessage(contLang:getCode(), 'no-data-text')
      end
     end
     if not haswikidatalink then
      category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-wikilink-cat')
      if not hasdatafromlocal and not short_links then
       outtext = cmodule:getMessage(contLang:getCode(), 'no-wikilink')
      end
     end
     local nocategory = getArgument(frame, conf:a('arg-no-categories'))
     category = #category>0 and "\n" .. table.concat(category,"\n") or ""
     --mw.log("nocategory="..dump(nocategory).." and outtext="..dump(outtext).." and category="..dump(category))
     outtext = outtext .. (nocategory and '' or category)
     return outtext
    end
    
    function p.getLanguageCode(frame)
     local prop = getArgument(frame, conf:a('arg-properties'))
     local output = getLanguageData(prop)
     return table.concat(output, conf:a('mod-filter-separator'))
    end
    
    return p
    

    Retrieved from "https://en.wikipedia.org/w/index.php?title=Module:External_links&oldid=1226038006"

    Category: 
    Modules subject to page protection
    Hidden category: 
    Wikipedia template-protected modules
     



    This page was last edited on 28 May 2024, at 06:09 (UTC).

    Text is available under the Creative Commons Attribution-ShareAlike License 4.0; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization.



    Privacy policy

    About Wikipedia

    Disclaimers

    Contact Wikipedia

    Code of Conduct

    Developers

    Statistics

    Cookie statement

    Mobile view



    Wikimedia Foundation
    Powered by MediaWiki