Модуль:Навигация-мини

Материал из Викитеки — свободной библиотеки
Перейти к навигации Перейти к поиску
Документация Документация

Подгружает данные из Викиданных и интерпретирует их, показывая в шапках статей. Используется в Модуль:Отексте, Шаблон:Отексте, Модуль:Обавторе, Шаблон:Обавторе.

local p = {};
local wd = require("Module:WD");

-- will be appended to project code
local localLanguage = 'ru';
local localProject = 'wikisource';
local argSearch = 'ПОИСК';

local preferredLanguages = { localLanguage }

-- Mapping from local arguments to 
local projects = {
	{ arg = 'ВИКИТЕКА',	name = 'Викитека',	project='wikisource',		code='s',		logo='Wikisource-logo.svg',	title='Викитека',		titlePRS='Викитека'},
	{ arg = 'ВИКИПЕДИЯ',	name = 'Википедия',	project='wiki',			code='w',		logo='Wikipedia-logo.png',	title='Википедия',		titlePRS='Википедія' },
	{ arg = 'ВИКИСКЛАД',	name = 'Викисклад',	project='commons',		code='commons',		logo='Commons-logo.svg',	title='Фото, аудио и видео',	titlePRS='Фото, аудіо и видео',	monolanguage = true },
	{ arg = 'ВИКИНОВОСТИ',	name = 'Викиновости',	project='wikinews',		code='n',		logo='Wikinews-logo.svg',	title='Новости',		titlePRS='Новости' },
	{ arg = 'ВИКИГИД',	name = 'Викигид',	project='wikivoyage',		code='voy',		logo='wikivoyage-logo.svg',	title='Гид',			titlePRS='Гидъ' },
	{ arg = 'ВИКИВИДЫ',	name = 'Викивиды',	project='specieswiki',		code='species',		logo='Wikispecies-logo.svg',	title='Виды',			titlePRS='Виды',		monolanguage = true },
	{ arg = 'ВИКИДАННЫЕ',	name = 'Викиданные',	project='wikidata',		code='d',		logo='Wikidata-logo.svg',	title='Данные',			titlePRS='Данныя',		monolanguage = true },
	{ arg = 'ВИКИСЛОВАРЬ',	name = 'Викисловарь',	project='wikidictionary',	code='wikt:',		logo='Wiktionary-logo-ru.png',	title='Словарь',		titlePRS='Словарь' },
	{ arg = 'ВИКИУЧЕБНИК',	name = 'Викиучебник',	project='wikibooks',		code='b',		logo='Wikibooks-logo.svg',	title='Учебник',		titlePRS='Учебникъ' },
	{ arg = 'ВИКИВЕРСИТЕТ',	name = 'Викиверситет',	project='wikiversity',		code='v',		logo='Wikiversity-logo.svg',	title='Викиверситет',		titlePRS='Викиверситетъ' },
	{ arg = 'ВИКИЦИТАТНИК',	name = 'Викицитатник',	project='wikiquote',		code='q',		logo='Wikiquote-logo.svg',	title='Цитаты и афоризмы',	titlePRS='Цитаты и афоризмы' },
	{ arg = 'ВИКИЛИВР',		name = 'Викиливр',		project='wikilivres',		code='wikilivres', logo='Wikilivres logo.png', title='Викиливр', titlePRS='Викиливр'},
	{ arg = 'ВИКИЛИВРУ',	name = 'Викиливру',	project='wikilivres_ru',	code='wikilivresru', logo='Wlru-logo.png', title='Викилив.ру', titlePRS='Викилив.ру'}
}

local parentProperties = {
--	'P921', -- main topic link
	'P910'  -- main category
	-- 'P629', -- edition or translation of
	-- 'P361', -- part of
}

-- local currentTitleFull = mw.title.getCurrentTitle().fullText;

--[[
Функция возвращает массив значений свойства propertyId из элемента entity
Возвращаются значения "preferred", если они есть, иначе значения "normal".
]]
local function getClaimValues( entity, propertyId )
    local result = {};
    local claim = nil;
    if (entity ~= nil) and (entity.claims ~= nil) then
      claim = entity.claims[ propertyId ];
    end
    if (claim ~= nil) then
      local b_prefered_mode = false;
      for key, value in pairs(claim) do
        local snak = nil;
        if value.rank == "preferred" then          -- предпочтительный ранг
          if not b_prefered_mode then
            result = {};
            b_prefered_mode = true;
          end
          snak = value.mainsnak;
        elseif (value.rank == "normal") and (not b_prefered_mode) then    -- обычный ранг
          snak = value.mainsnak;
        end
        if (snak ~= nil) and (snak.snaktype == "value") then
          if snak.datavalue.type == "wikibase-entityid" then
            result[#result+1] = "Q" .. snak.datavalue.value["numeric-id"];
          else
            result[#result+1] = snak.datavalue.value;
          end
        end
      end
    end
    return result;
end

--[[
-- функция для тестирования
-- {{#invoke:Навигация-мини|test_getClaimValues|Q20646238|P921}}
function p.test_getClaimValues (frame)
    local s_item = frame.args[1];
    local s_property = frame.args[2];
    local entity = mw.wikibase.getEntity(s_item);
    local data = getClaimValues(entity, s_property);
    local s_result = ""
    for key, value in pairs(data) do
      s_result = s_result .. "[" .. key .. "]: " .. tostring(value) .. "<br/>"
    end
    return s_result;
end
]]
--[[
function p.populateInterwikiByEntityId( entityId, result )
    if ( result == nil ) then
        result = {};
    end
    if ( entityId == nil ) then
        return result;
    end
    local entity = mw.wikibase.getEntity( entityId );
    if ( entity == nil ) then
        return result;
    end
    return p.populateInterwikiByEntity( entity, result );
end
]]
function p.populateInterwikiByEntity(entity, result)
	-- populate from entity interwiki
	local sitelinks = entity.sitelinks;
	if sitelinks ~= nil then
		for sitecode, sitelink in pairs( sitelinks ) do
			-- mw.log("  "..sitecode.." = "..sitelink.title);
			if result[sitecode] == nil then
				result[sitecode] = sitelink.title;
			end;
		end;
	end;
    -- check if entity have main topic item
    for _, propertyCode in pairs( parentProperties ) do
	    local parentEntityIds = getClaimValues( entity, propertyCode );
	    for _, parentEntityId in pairs( parentEntityIds ) do
              local entity2 = mw.wikibase.getEntity(parentEntityId);
--	        if propertyCode == 'P921' and result['wikidata'] == nil then
--	            result['wikidata'] = entity2.id; -- entity itself is a wikidata link
--	        end
	        p.populateInterwikiByEntity(entity2, result);
	    end;
	end;
	if result['commons'] == nil then
	    local commonsCategories = getClaimValues( entity, 'P373' );
	    for _, commonsCategory in pairs( commonsCategories ) do
	    	 result[ 'commons' ] = 'Category:' .. commonsCategory;
	    	 break;
	    end;
	end;
    return result;
end

-- сбор данных 
function scrape_data( frame, scrape_manual_and_wd_links )
	local scrape_manual_and_wd_links = true
	local args = frame:getParent().args;
	local entity = mw.wikibase.getEntity();
	local wikidataInterwiki = {};
	-- Работа с Викиданными
	if entity ~= nil then
		-- для энциклопедических и словарных статей (P31 = Q17329259/Q1580166) просматриваем P921 ("основная тема произведения")
    	if wd.has_valid_item_value (entity, "P31", 17329259) or wd.has_valid_item_value (entity, "P31", 1580166) then
    		local topics = getClaimValues(entity, "P921")
    		for key, s_item_id in pairs(topics) do
    			-- mw.log("просматриваем: "..s_item_id)
    			if wikidataInterwiki['wikidata'] == nil then
   					wikidataInterwiki['wikidata'] = s_item_id
   				end
	    		wikidataInterwiki = p.populateInterwikiByEntity(mw.wikibase.getEntity(s_item_id), wikidataInterwiki)
			end
		else
   			-- mw.log("это не энциклопедическая статья");
   			wikidataInterwiki['wikidata'] = entity.id
			wikidataInterwiki = p.populateInterwikiByEntity(entity, wikidataInterwiki)
			if wikidataInterwiki['ruwikisource'] == mw.title.getCurrentTitle().fullText then
				wikidataInterwiki['ruwikisource'] = nil
			end;
		end;
	end;
	--
	
    local result = { 
    	wlinks_data={}, -- формат: {project, s_link, manual_link, wd_link}
		categories={}, categories_raw={},
    	IS_PRS = require( "Module:Header" ).parse_title( mw.title.getCurrentTitle().text , "isPRS" ),  -- isDO = isCurrentPageDO()
    }
    function result:add(project, manual_link, wd_link) 
    	local s_link; if manual_link then s_link = manual_link elseif wd_link then s_link = wd_link end
    	table.insert(self.wlinks_data, {project, s_link, manual_link, wd_link} )
    end
    function result:add_cat(s)
    	table.insert(self.categories, '[[Категория:'..s..']]')
    	table.insert(self.categories_raw, s)
    end
	
	for _, project in pairs( projects ) do
                local s_arg = project.arg;
                local s_code = project.code;
                local s_name = project.name;
                local manual_link, wd_link
		repeat 
			-- do we have value provided as template argument?
			-- поиск ссылки в параметре шаблона
			local provided = args[s_arg];
			if ( provided and #provided > 0 ) then
				-- keyword to locally suppress Wikidata output
				if provided ~= '__NULL__' then
					if ( project.project == localProject ) then
						manual_link = provided
						result:add_cat('Викитека:Ручная ссылка:' .. s_name);
					else
						if ( mw.ustring.sub( provided , 1, 1 ) == ':' ) then
							provided = mw.ustring.sub( provided , 2 );
						end
						manual_link = s_code .. ':' .. provided
						result:add_cat('Викитека:Ручная ссылка:' .. s_name)
					end
				end
				-- break; -- continue to next project
			end
	
			-- поиск ссылки в Викиданных
			-- При projectCode == "wikidata":
			--    для энциклопедический статей категория "Ссылка из Викиданных" ставится по property P921 ("основная тема")
			--    для других страниц если Викитека указана в списке проектов 
			if ( project.monolanguage ) then
				local projectCode = project.project;
				local title = wikidataInterwiki[ projectCode ]
				if ( title ) then
					wd_link = s_code .. ':' .. title
					result:add_cat('Викитека:Ссылка из Викиданных:' .. s_name)
					break
				end
			else
				--TODO: handle native/official language 
				local foundProjectLink = false;
				for _, lang in pairs( preferredLanguages ) do
					local projectCode = lang .. project.project;
					local title = wikidataInterwiki[ projectCode ];
					if ( title ) then
						if ( project.project == localProject ) then
							if ( lang == localLanguage ) then
								wd_link = ':' .. title
							else
								wd_link = ':' .. lang .. ':' .. title
							end
						else
							if ( lang == localLanguage ) then
								wd_link = s_code .. ':' .. title
							else
								wd_link = s_code .. ':' .. lang .. ':' .. title
							end
						end;
						result:add_cat('Викитека:Ссылка из Викиданных:' .. s_name)
						foundProjectLink = true;
						break;
					end
				end
				if ( foundProjectLink ) then
					break;
				end
			end

			-- still no link to wiki
			if ( project.project == 'wiki' and not manual_link ) then
				local searchString = args[ argSearch ] or frame.args.search;
				if ( searchString and #searchString > 0 ) then
					manual_link = s_code .. ':Special:Search/' .. searchString
					break; -- continue to next project
				end
			end

			break;
		until true;
  	
  		if manual_link and wd_link then
  			if manual_link == wd_link then 
				result:add_cat('Викитека:Ручная ссылка совпадает со ссылкой из Викиданных:'..s_name)
			else
				result:add_cat('Викитека:Ручная ссылка отличается от ссылки из Викиданных')
			end
		end
		-- Для страниц авторов категории дальше меняются в Модуль:Обавторе в change_wd_categories()
		
		result:add( project, manual_link, wd_link )
	end
	
	-- mw.logObject(result, "result")
	return result
end
function p.scrape_data( frame ) return scrape_data( frame ) end

-- оформление строки для {{отексте}} и Модуль:Отексте
function p.render( frame )
	local dataset = scrape_data( frame )
	if #dataset.wlinks_data > 0 then 
		local links = {}
		for _, v in pairs(dataset.wlinks_data) do
			local project, s_link = v[1], v[2]
			if s_link then
				local s_title = "";	if ( dataset.IS_PRS ) then s_title = project.titlePRS else s_title = project.title end
				table.insert(links, "[[Файл:"..project.logo.."|13px|link="..s_link .."]]&nbsp;[["..s_link.."|"..s_title.."]]")
			end
		end
		
		local result
		if #links > 0 then 
			links = table.concat(links, '&nbsp;')
			result = "&nbsp;<span style=\"float:right;\">'''Википроекты:'''&nbsp;"..links..'</span>'
		end
		if #dataset.categories > 0 then result = result .. table.concat(dataset.categories) end
		return result
	end
end

return p;