مودول:بطاقة

من ويكيپيديا

لماذا هذا الأسلوب ؟[بدل لكود]

هذه الوحدة تعمل على جعل عملية استحداث قوالب البطاقات (أو قوالب معلومات أو Infobox) أسهل/أبسط ما يمكن من خلال تعريفات بسيطة في وحدات فرعية.

المميزات
  • استحداث القوالب يندرج ضمن عملية البرمجة واستعمال وحدات فرعية بلغة لوا (Lua) يضبط المكتوب لضمان غياب الأخطاء.
  • عملية ترتيب البيانات المعروضة بسيطة ولا تستدعي تغيير الأرقام (مثلما هو الحال مع module:InfoBox).
  • توفر مكتبات لجلب البيانات الأكثر استعمالا لاقتصاد الوقت والكود.
  • الجمع في مكان واحد للمبرمج/المطور لتوفير التعليمات والشروح.
  • توفر أدوات مساعدة لتحيين صفحة الشرح بصورة آنية وآلية أو نصف آلية (مثل : الصيغة وبيانات القالب ..) بعد تحيين الوحدة أو أحد المكتبات المساعدة.

الاستخدام[بدل لكود]

هذه الوحدة تستعمل لعرض قالب معلومات (Infobox) أو بطاقة بالاعتماد على وحدة فرعية تحتوي على بيانات حول مضمون هذا القالب. تسمح هذه الوحدة بإجراء استجوابات بصورة مبسطة لويكي بيانات لجلب ما توفر من البيانات.

استحداث قالب معلومة (أو بطاقة) يمر بخطوتين :

  1. إنشاء وحدة فرعية بعنوان من الشاكلة : وحدة:بطاقة/قالب/اسم_قالب
    • مثال : وحدة:بطاقة/قالب/لعبة
  2. إنشاء قالب يستعمل لاحقا في المقالات. محتوى هذا القالب سيكون : {{#استدعاء:بطاقة|تركيب|وحدة=اسم_الوحدة_الفرعية}}
    • مثال :{{#استدعاء:بطاقة|تركيب|وحدة=لعبة}}

محتوى الوحدة الفرعية[بدل لكود]

محتوى فارغ
return 	{
 maincolor = '#DDDDDD' -- اللون المستعمل لعنوان البطاقة
 ,parts = {} -- محتويات البطاقة
}
محتوى نموذجي
local generic = require( 'وحدة:بطاقة/أدوات' )

return 	{
 -- اللون المستعمل لعنوان البطاقة
 maincolor = '#DDDDDD', 
 -- محتويات البطاقة
 parts = { 
	  generic.title(),
	  {type = 'subtitle', value = {'الاسم_الأصلي'}},
	  generic.logo(),
	  generic.mainimage(),
	  {type = 'table', title = 'معلومات عامة', rows = {
		{type = 'row', 
			label = 'الصانع',
			value ={'صانع','manufacturer'},
			wikidata = {property='P176'}
		},
		{type = 'row',
			label = 'أسماء أخرى',
			value ={'أسماء_أخرى','aka'},
		},
		{type = 'row',
			label = '[[شركة أم]]',
			value ={'شركة_أم','parent_company'},
		},
	  }},
	}
}
محتوى متقدم يجمع التعليمات بالشروح
return 	{
 -- شرح مختصر عن وظيفة البطاقة
 description = "بطاقة تعريفية عن ...",
 -- اللون المستعمل لعنوان البطاقة
 maincolor = '#DDDDDD', 
 -- محتويات البطاقة
 parts = { 
	  generic.title(),
	  {type = 'subtitle', value = {'الاسم_الأصلي'}},
	  generic.logo(),
	  generic.mainimage(),
	  {type = 'table', title = 'معلومات عامة', rows = {
		{type = 'row', 
			label = 'الصانع',
			value ={'صانع','manufacturer'},
			wikidata = {property='P176'},
			metadata = {
				description = "تسمية صانع المنتج",
				option = "required", -- تظهر عند التحرير المرئي على أنها معلومة ضرورية يجب توفيرها
				type = "string", 
			}
		},
		{type = 'row',
			label = 'أسماء أخرى',
			value ={'أسماء_أخرى','aka'},
			metadata = {
				description = "أسماء أخرى متداولة",
				option = "suggested", 
				type = "string", 
			}
		},
		{type = 'row',
				label = 'تاريخ التأسيس',
				value ={'تأسيس','founded'},
				metadata = {
					description = "تاريخ التأسيس الشركة",
					option = "suggested", 
                  -- تظهر عند التحرير المرئي على أنها معلومة تمثل تاريخا لذا وجب كتابة بنسق التواريخ.
					type = "date" 
				}
		},
	  }},
	}
}

إحصائيات[بدل لكود]

الأيقونات المتوفرة[بدل لكود]

خطأ: لا توجد وحدة بهذا الاسم "بطاقة/مساعدة".


local p = {}
local lang = 'ar' -- اللغة

local item = nil -- l'élément Wikidata lié
local localdata = {}-- بيانات مضمنة في القالب
local page = { -- بيانات حول الصفحة التي ستعرض عليها البطاقة 
	name = mw.title.getCurrentTitle().prefixedText,
	namespace =  mw.title.getCurrentTitle().namespace
}

local maincolor, secondcolor, thirdcolor = '#E1E1E1', '#E1E1E1', '#000000'
-- النتيجة النهائية
local infobox = mw.html.create('table')

-- نتائج ثانوية
local maintenance = '' -- chaîne retournée avec le module : cats de maintenance
local externaltext = '' -- par exemple coordonnées en titre

local valueexpl = 'activate-query' --wd.translate("activate-query")
local mapmod = require "Module:Location map" --"Module:Carte"

local i18n = {
	['see doc'] = 'حول القالب',
	['edit'] = 'تعديل',
	['edit code'] = 'تعديل مصدري',
	['edit item'] = 'تعديل ويكي بيانات',
	['tracking cat'] = "صفحات بها بيانات ويكي بيانات",
	['invalid block type'] = "لبنة بيانات غير صحيحة في القالب", --"Bloc de données invalide dans le module d'infobox",
	['default cat'] = "صيانة بطاقات",
}

local function addWikidataCat(prop)
	-- if page.namespace 
	if type(prop) == 'table' then prop = prop[1] end
	if page.namespace == 0 then
	  maintenance = maintenance .. '[[تصنيف:صفحات_تستخدم_خاصية_' .. prop .. ']]'
	end
end

local function expandQuery(query)
	local value, number -- نتيجة ، عدد النتائج للضبط الصرفي للعنوان
	if(type(query) ~= 'table') then return nil end
-- الوحدات المستعملة
	local wikimod = query.wikimod or localdata.wikimod or 'Wikidata2'
	
	local wdexpandQuery = require("وحدة:بطاقة/ويكي.بيانات").expandQuery


	return wdexpandQuery(localdata.item ,wikimod,query)	

end

local function getWikidataValue(params, wikidataparam)
	-- Récupère la valeur Wikidata pour la valeur, soit dans le paramètre "wikidata" soit dans le paramètre "property"
	if not localdata.item then
		return nil
	end

	if params.blockers then -- blockers are local parameters that disable the wikidata query
		local blockers = params.blockers
		if (type(blockers) == 'string') then
			blockers = {blockers}
		end
		for i, blocker in ipairs(blockers) do
			if localdata[blocker] then
				return nil
			end
		end
	end

	local v, valnum -- la valeur à retourner, et le nombre de de valeurs (pour l'accord grammatical)
	
	if not wikidataparam then -- par défaut la valeur wikidata est dans le paramètre "wikidata" mais dans les structures composées comme "title", il y a plusieurs paramètres wikidata
		wikidataparam = 'wikidata'
	end

	if params[wikidataparam] then
		if type(params[wikidataparam]) == 'function' then
			v, valnum = params[wikidataparam](localdata.item)
		elseif type(params[wikidataparam]) == 'table' then
			v, valnum = expandQuery(params[wikidataparam])
		else
			v, valnum = params[wikidataparam]
		end
	end
	if not v then
		return nil
	end
	-- v = linguistic.ucfirst(v)
	return v, valnum
end

local function getValue(val, params)
	if type(val) == 'string' then
		return localdata[val]
	elseif type(val) == 'function' then
		return val(localdata, localdata.item, params)
	elseif type(val) == 'table' then
		for i, j in pairs(val) do -- si plusieurs paramètres possibles (legacy de vieux code), prendre le premier non vide
			if localdata[j] then
				return localdata[j]
			end
		end
	end
end

local function addMaintenanceCat(cat, sortkey)
	if page.namespace ~= 0 then
		return ''
	end
	if cat then
		maintenance = maintenance .. '[[Category:' .. cat .. '|' .. (sortkey or page.name) .. ']]'
	end
end

function p.separator(params)
	local style = params['separator style'] or {}
	style.height = style.height or '2px'
	style['background-color'] = style['background-color'] or maincolor
	
	return mw.html.create('hr'):css( style )	
end

function p.buildtitle(params)
	local text = getValue(params.value, params) or params.textdefaultvalue or  getWikidataValue(params) or mw.title.getCurrentTitle().text
	local subtext = getValue(params.subtitle) or  getWikidataValue(params, 'wikidatasubtitle') or params.subtitledefaultvalue
	if subtext and (subtext ~= text) then
		text = text .. '<br /><small>' .. subtext .. '</small>'
	end

	local icon = params.icon or ''
	if icon ~= '' and icon ~= 'defaut' then
		text = text .. mw.getCurrentFrame():extensionTag('templatestyles', '', {src = 'ب.ص.م/أيقونة/' .. mw.text.trim(icon) .. '.css'})
		if not params.large then
			icon = 'icon ' .. icon
		end
	end
	local class = 'entete ' .. icon
	
	-- overwrites with those provided in the module
	local style = {}
	style['background-color'] = maincolor
	style['color'] = thirdcolor
	if params.style then
		for i, j in pairs(params.style) do
			style[i] = j
		end
	end
	local title = mw.html.create('tr')
		:tag('th')
			:wikitext(text)
			:addClass(class)
			:css(style)
		:allDone()
	return title
end
p.buildTitle = p.buildtitle

function p.buildnavbox(params)
	
	-- ajustement des paramètres de données
	params.previousval = params.previousval or params.previousparameter -- nom de paramètre obsolète
	params.nextval = params.nextval or params.nextparameter
	
	if params.previousproperty then
		params.previouswikidata = {property = params.previousproperty, numval = 3 , conjtype = 'new line'}
	end
	if params.nextproperty then
		params.nextwikidata = {property = params.nextproperty, numval = 3, conjtype = 'new line'}
	end

	local previousval = getValue(params.previousval, params) or getWikidataValue(params, 'previouswikidata')
	local nextval = getValue(params.nextval, params) or getWikidataValue(params, 'nextwikidata')
	
	if not previousval and not nextval then return nil end

	-- définition du style
	local class = "overflow nav " .. (params.class or '')
	local style = params.style or {}

	if params.separated then -- options pour ajouter une ligne de séparation au dessus
		class = class .. ' bordered'
		style['border-top'] = '1px solid' .. maincolor
	end
	
	local navbox
	--if params.inner then -- pour celles qui sont à l'intérieur d'une table
		navbox = mw.html.create('tr'):tag('td'):attr('colspan', 2)
		style['font-weight'] = style['font-weight'] or 'normal'
	--else
		--navbox = mw.html.create('div')
	--end
	
	local style2 = {}
	style2["background-color"] = '#E6E6E6' --maincolor
	
	local navboxN, navboxP
	if(previousval) then
		navboxP = mw.html.create('div')
			:addClass('prev_bloc')
			:css(style2)
			:wikitext(previousval)
			:done()	
	end
	if(nextval) then
		navboxN = mw.html.create('div')
			:addClass('next_bloc')
			:css(style2)
			:wikitext(nextval)
			:done()	
	end
	navbox
		:addClass(class)
		:css(style)
		:node(navboxP)
		:node(navboxN)
		:allDone()
	return navbox
end
p.buildNavbox = p.buildnavbox

local function getwdImage(Q, property)
	property = property or 'P18'
	local QID
	if type(Q) == 'table' and Q.id and Q.id ~= '-' 
	    then QID = Q.id
		else return
	end	
	local wdata 
	if (Q.claims and Q.claims[property]) then wdata = Q.claims[property]
		else 	wdata = mw.wikibase.getBestStatements(QID, property or 'P18') -- P18 is 'image'
	end
	local first
	for _, image in pairs(wdata) do
		if image.mainsnak.snaktype == 'value' then
			if not first then
				first = image.mainsnak.datavalue.value
			end
			local q = image.qualifiers
			if q and q.P2096 then
				for _, caption in pairs(q.P2096) do -- P2096 is 'caption'
					if caption.snaktype == 'value' and caption.datavalue.value.language == lang then
						return image.mainsnak.datavalue.value, caption.datavalue.value.text
					end
				end
			end
		end
	end
	return first
end

function p.buildimages(params)
	local images = {}
	local upright, link, caption, captionfromwd, alt, size  -- size is deprecated
	if type(params.imageparameters) == 'string' then
		params.imageparameters = {params.imageparameters}
	end
	if not params.imageparameters then -- s'il n'y a pas de paramètre image, continuer, peut-être y a-t-il une image par défaut définie dans le module d'infobox
		params.imageparameters = {}
	end
	for j, k in ipairs(params.imageparameters) do
		table.insert(images, localdata[k])
	end
	-- Images de Wikidata 
	if #images == 0 and localdata.item then
		if params.property then
			params.wikidata = {entity = localdata.item, property = params.property}
		end
		if params.wikidata then
			local wdq = params.wikidata
			
			wdq.excludespecial = true
			if type(wdq) == 'table' then
				--mw.log(">>>entity:"..mw.dumpObject(localdata.item))
				if type(params.wikidata.property) == 'table' then
					for i,improp in pairs(params.wikidata.property) do
						images,captionfromwd = getwdImage(localdata.item, improp)
						if images ~= nil then break end
					end
				else
					images,captionfromwd = getwdImage(localdata.item, params.wikidata.property)
				end
			end
			if type(wdq) == 'function' then
				images = params.wikidata()
				if type(images) == 'string' then
					return images
				end --c'est probablement une erreur dans la requête => afficher le message
			end
			if type(images) == 'string' then
				images = {images}
			end
			if (not images) then
				images = {}
			end
			if (#images > 0) and (params.wikidata.property) then
				addWikidataCat(params.wikidata.property)
			end

		end
	end

	-- Images par défaut
	if #images == 0 then
		if params.maintenancecat then
			addMaintenanceCat(params.maintenancecat, params.sortkey)
		end
		if params.defaultimages then
			images = params.defaultimages
			if type(images) == 'string' then
				images = {images}
			end
			upright = params.defaultimageupright
			caption = params.defaultimagecaption
			link = params.defaultimagelink
			alt = params.defaultimagealt
			if not alt and ( images[1] == 'DefautAr.svg' or images[1] == 'Defaut 2.svg' ) then
				alt = 'نحتاج صورة تكون من الأفضل حرة'
			end
		end
	end
	if #images == 0 then
		return nil
	end
	
	upright = upright or getValue(params.uprightparameter) or params.defaultupright or "1.2"
	link = link or getValue(params.linkparameter) or params.defaultlink
	caption = captionfromwd or caption or getValue(params.captionparameter) or params.defaultcaption
	alt = alt or getValue( params.altparameter) or params.defaultalt
	
	if captionfromwd then
		addMaintenanceCat("صفحات تستخدم خاصية P2096")
	end

	-- taille avec "size" (obsolète)
	size = size or getValue(params.sizeparameter) or params.defaultsize -- deprecated
	if size then
		local numsize = size:gsub('px', '')
		numsize = size:gsub('بك', '')
		numsize = mw.ustring.gsub(numsize, 'x.*', '')
		numsize = tonumber(numsize)
		if type(numsize) ~= 'number' or numsize > 280 then
			addMaintenanceCat("مقالات تسيء استعمال حجم الصورة")
		end
		if tonumber(size) then
			size = size .. 'px'
		end
		size = '|' .. size
	else
		size = ''
	end
	
	if tonumber(upright) then
		upright = tostring(tonumber(upright) ) / #images
	end
	if tonumber(size) then
		size = tostring(tonumber(size) ) / #images
	end

	local style = params.style or {padding ='2px 0',}

	-- تحضير عرض الصورة

	local imagesString = ''
	for i,image in pairs(images) do
		if image == '-' then
			return
		end
		
		--image = string.match(image, '%[%[[^:]*:([^|%]]*)') or image
		--image = string.gsub(image ,'^([^:]+:)','')
		image = string.match(image, '[^:]*:([^|%]]*)') or image
		imagesString = imagesString ..  '[[file:' .. image .. size .. '|frameless'
		-- [[
		if alt then
			imagesString = imagesString .. '|alt=' .. alt
		end
		if link then
			imagesString = imagesString .. '|link=' .. link
		end
		if upright then
			imagesString = imagesString .. '|upright=' .. upright
		elseif #images > 1 then
			imagesString = imagesString .. '|upright=' .. ( 1 / #images )
		end

		imagesString = imagesString .. ']]'
		
	end

	local image = mw.html.create('div')
		:addClass("images")
		:css(style)
		:wikitext(imagesString)

	-- التعليق
	local captionobj
	if caption then
		captionobj = mw.html.create('div')
			:wikitext(caption)
			:css(params.legendstyle or {})
			:addClass("legend")
			:done()
	end
	
	-- الفاصل
	local separator
	if params.separator then
		separator = separator(params)
	end
	return mw.html.create('tr'):tag('td') --mw.html.create('div')
		:css({	border="unset",padding="unset"})
		:node(image)
		:node(captionobj)
		:node(separator)
		:done()
end
p.buildImages = p.buildimages

function p.buildtext(params)
	local class = params.class or ''
	local style = {
		['text-align'] = 'center',
		['font-weight'] = 'bold'
	}
	if params.style then
		for i, j in pairs(params.style) do
			style[i] = j
		end
	end
	local text = getValue(params.value, params) or getWikidataValue(params) or params.defaultvalue
	if text == '-' then
		return
	end
	if not text then
		addMaintenanceCat(params.maintenancecat, params.sortkey)
		return nil
	end
	local formattedtext = mw.html.create('tr'):tag('td') --mw.html.create('p')
		:addClass(class)
		:css(style)
		:wikitext(text)
		:done()
	return formattedtext
end
p.buildText = p.buildtext

function p.buildrow(params)
	local class = params.class or ''
	local style = params.style or {}
	local value, number =  getValue(params.value, params)
	if (value == valueexpl) then
		value = nil
		params.wikidata.expl = false
	end
	if (not value) then
		value, number =  getWikidataValue(params, 'wikidata')
	end
	if (not value) and (params.property) then
		value, number = expandQuery{ property = params.property, ucfirst = params.ucfirst }
	end
	if not value then
		value = params.defaultvalue
	end
	if value == '-' then
		return nil
	end
	if not number then
		number = 0 -- == indéfini
	end

	if not value then
		if params.maintenancecat then
			local maintenancecat = getValue(params.maintenancecat, params)
			addMaintenanceCat(maintenancecat, params.sortkey)
		end
		return nil
	end

	local label = params.label
	if number > 1 and (params.plurallabel) then
		label = params.plurallabel
	elseif number == 1 and (params.singularlabel) then
		label = params.singularlabel
	end
	if number > 4 then   --- اخفاء النتيجة في حال تجاوز عددها 4
		params.hidden = true
	end
	
	if type(label) == 'function' then
			label = label(localdata, localdata.item)
	elseif type(label) == 'table' then
			label = getValue(label, params)    -- في حال وجود عدة تسميات
			if not label then label = params.defaultlabel end
	end

	-- format
	local formattedvalue = mw.html.create('div')
		:wikitext('\n' .. value) -- رمز '\n' مطلوب عندما تكون value قائمة تبدأ بـ '*' ou '#'
		
	if (params.hidden == true)then
		formattedvalue = mw.html.create('div')
			:attr({class="NavContent", style=""}) --display: none; text-align: center; 
			:node(formattedvalue)
		local divNavHead = mw.html.create('div')
			:attr({class="NavHead nomobile", style="text-align:left;border: none; padding: 0; background:none; font-size: 75%;"})			
			:wikitext("&nbsp;[[file:Incomplete list.svg|20x20px|link=]]") --[عرض]/[إخفاء]
		formattedvalue = mw.html.create('div')
			:attr({class="NavFrame collapsed", style="border: none; padding: 0;"})
			:node(divNavHead)
			:node(formattedvalue)
	end
	formattedvalue =  mw.html.create('td')
			:node(formattedvalue)
			:allDone()
	
	local formattedlabel
	if label then
		formattedlabel = mw.html.create('th')
			:attr('scope', 'row')
			:wikitext(label)
			:done()
	end
	local row = mw.html.create('tr')
		:addClass(class)
		:css(style)
		:node(formattedlabel)
		:node(formattedvalue)
		:done()
	
	return row
end
p.buildRow = p.buildrow

function p.buildsuccession(params)
	if not params.value then
		--return nil
		params.value = {}
	end
		
	--local style = params.style or {}
	--style['text-align'] = style['text-align'] or 'center'
	--style['color'] = style['color'] or '#000000'
	--style['background-color'] = style['background-color'] or '#F9F9F9'
	
	local rowI = mw.html.create('tr'):tag('td'):tag('table'):tag('tr') --mw.html.create('tr')
	
	local colspan = '2'
	cellI = mw.html.create('td')
			:attr({colspan = colspan})
			:attr({align = 'center'})
	
	local styleT = {display='table',margin='5px',width= '100%'}
	styleT['background-color'] = 'transparent'
	styleT['border-spacing'] = '0'
    styleT['border-collapse'] = 'collapse'

	tabC = mw.html.create('table')
			--:attr({cellspacing = '0'})
			:addClass('navigation-not-searchable')
			:css(styleT)
	
	local row = mw.html.create('tr')

	local color = params.color or 'default'

	local style = {}
	local arrowLeft
	local arrowRight
	
	if color == 'default' then
		style['background-color'] = '#E6E6E6'
		arrowLeft = '[[file:Fleche-defaut-droite.png|13px|alt=سابق|link=]]'
		arrowRight = '[[file:Fleche-defaut-gauche.png|13px|alt=سابق|link=]]'
	else
		style['background-color'] = color
		arrowLeft = '[[file:Fleche-defaut-droite-gris-32.png|13px|alt=لاحق|link=]]'
		arrowRight = '[[file:Fleche-defaut-gauche-gris-32.png|13px|alt=لاحق|link=]]'
	end
	
	local styleTrans = {}
	styleTrans['background-color'] = '#F9F9F9'
	
	style['vertical-align'] = "middle"

	-- ajustement des paramètres de données
	params.previousval = params.previousval or params.previousparameter -- nom de paramètre obsolète
	params.nextval = params.nextval or params.nextparameter
	
	if params.previousproperty then
		params.previouswikidata = {property = params.previousproperty , numval=3}
	end
	if params.nextproperty then
		params.nextwikidata = {property = params.nextproperty , numval=3}
	end
	if params.actualproperty then
		params.actualwikidata = {property = params.actualproperty , numval=3}
	end
	
	local values = params.value
        params.numval = 3
	local before = values['before'] or getValue(params.previousval, params) or getWikidataValue(params, 'previouswikidata')
	local center = values['center'] or getValue(params.actualval, params) or getWikidataValue(params, 'actualwikidata')
	local after = values['after'] or getValue(params.nextval, params) or getWikidataValue(params, 'nextwikidata')

	if not before and not center and not after then
		return nil
	end	
	
	local widthCell = '44%'
	if center then
		widthCenter = '28%'
		widthCell = '29%'
	end
	
	local formattedbefore
	if before then
		formattedbefore = mw.html.create('td')
			:attr({valign = 'middle'})
			:attr({align = 'right'})
			:attr({width = '5%'})
			:css(style)
			:wikitext(arrowLeft)
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(style)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({align = 'right'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(style)
			:wikitext(before)
			:done()
		row:node(formattedbefore)
	else
		formattedbefore = mw.html.create('td')
			:attr({valign = 'middle'})
			:attr({align = 'right'})
			:attr({width = '5%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({align = 'right'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
	end
	
	local formattedcenter
	formattedcenter = mw.html.create('td')
		:attr({width = '1%'})
		:css(styleTrans)
		:wikitext('')
		:done()
	row:node(formattedcenter)
	
	if center then
		formattedcenter = mw.html.create('td')
			:attr({align = 'center'})
			:attr({valign = 'middle'})
			:attr({width = widthCenter})
			:css(style)
			:wikitext(center)
			:done()
		row:node(formattedcenter)
		formattedcenter = mw.html.create('td')
			:attr({width = '1%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedcenter)
	end
	
	local formattedafter
	if after then
		formattedafter = mw.html.create('td')
			:attr({align = 'left'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(style)
			:wikitext(after)
			:done()
		row:node(formattedafter)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(style)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedafter = mw.html.create('td')
			:attr({align = 'left'})
			:attr({valign = 'middle'})
			:attr({width = '5%'})
			:css(style)
			:wikitext(arrowRight)
			:done()
		row:node(formattedafter)
	else
		formattedafter = mw.html.create('td')
			:attr({align = 'left'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedafter)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedafter = mw.html.create('td')
			:attr({align = 'left'})
			:attr({valign = 'middle'})
			:attr({width = '5%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedafter)
	end
	
	row:done()
	tabC:node(row)
	tabC:done()
	cellI:node(tabC)
	cellI:done()
	rowI:node(cellI)
	rowI:allDone()
	
	return rowI
end
p.buildSuccession = p.buildsuccession

function p.buildrow1col(params)
	
	if not params.value then
		return nil
	end
		
	--local style = params.style or {}
	--style['text-align'] = style['text-align'] or 'center'
	--style['color'] = style['color'] or '#000000'
	--style['background-color'] = style['background-color'] or '#F9F9F9'
	local class = params.class
	local rowcolor
	if params.color == 'secondcolor' then
		rowcolor = secondcolor
	else
		rowcolor = params.color
	end
	
	local style = {}
	style['padding'] = '4px'
	style['text-align'] = 'center'
	style['background-color'] = rowcolor or '#F9F9F9'
	style['color'] = '#000000'
	
	local text = params.value

	local colspan ='2'

	local formattedlabel
	formattedlabel = mw.html.create('th')
		:attr({colspan = colspan})
		:css(style)
		:wikitext(text)
		:done()

	local row = mw.html.create('tr')
		:addClass(class)
		:css(style)
		:node(formattedlabel)
		:done()
	
	return row
end
p.buildRow1Col = p.buildrow1col

function p.build1cell(params)
	mw.log(">>>"..mw.dumpObject(params))
	local value = params[1] or params.data
	if type(value) == 'table' then
		value = mw.dumpObject(value)
	end
	if value == '-' or not value then
		value = ''
	end

	--mw.log(">>>Value = "..(value))
	
	local fCell = mw.html.create('td')
		:addClass(params.class)
		:css(params.style or {})
		:wikitext(value)
		:done()

	if params.colspan then
	  fCell:attr({colspan = params.colspan})
	end

	fCell:allDone()
	return fCell
end
p.build1Cell = p.build1cell

function p.build1row(params)
	local cols = params.cols

	-- expand parameters so that we have a list of tables
	local i = 1

	while (i <= #cols) do 
		local l = cols[i]
		if type(l) == 'function' then 
			l = l(localdata, localdata.item)
		end
		if (type(l) == 'table') and (l.type == 'multi') then
			table.remove(cols, i)  
			for j, col in ipairs(l.cols) do
				table.insert(cols, i + j - 1, col) 
			end
		elseif type(l) == 'nil' then
			table.remove(cols, i)
		elseif type(l) ~= 'table' then 
			return error('نوع غير معروف : ' .. type(l))
		else
			i = i + 1
		end
	end 
	-- CREATE ROW
	local expandedcols = {}
	for k, col in ipairs(cols) do
		if col.data then
			local v = p.buildblock(col.data) or ''
			col.data = v
			table.insert(expandedcols, col)
		end
	end
	if (#expandedcols == 0) then
		return nil
	end
	cols = expandedcols	

	local tabtr = mw.html.create('tr')
		:css(params.style or {})
		:addClass(params.class)
		:done()
	
	for i, j in pairs (cols) do
		tabtr:node(p.build1cell(j))
	end	
	tabtr:allDone()
	return tabtr	
end
p.build1Row = p.build1row

function p.buildsubtitle(params)

	local class = params.class or ''
	local style = {
		['text-align'] = 'center',
		['font-size'] = '90%',
		['background-color'] = maincolor,
		['color'] = thirdcolor
	}
	if params.style then
		for i, j in pairs(params.style) do
			style[i] = j
		end
	end
	
	local text = getValue(params.value, params) or getWikidataValue(params) or params.defaultvalue
	if text == '-' then
		return
	end
	if not text then
		addMaintenanceCat(params.maintenancecat, params.sortkey)
		return nil
	end

	local title = mw.html.create('tr'):tag('td')--mw.html.create('div')
		:addClass(class)
		:css(style)
		:tag('div')
		:wikitext(text)
		:allDone()
	return title
end

p.buildSubTitle = p.buildsubtitle

function p.buildtable(params)
	
	local rows = params.rows
	
	-- expand parameters so that we have a list of tables
	local i = 1

	while (i <= #rows) do 
		local l = rows[i]
		if type(l) == 'function' then 
			l = l(localdata, localdata.item)
		end
		if (type(l) == 'table') and (l.type == 'multi') then
			table.remove(rows, i)  
			for j, row in ipairs(l.rows) do
				table.insert(rows, i + j - 1, row) 
			end
		elseif type(l) == 'nil' then
			table.remove(rows, i)
		elseif type(l) ~= 'table' then 
			return error('أسطر قالب البطاقة ("rows") على شكل جداول (table), وليست ' .. type(l))
		else
			i = i + 1
		end
	end 

	-- CREATE ROW
	local expandedrows = {}
	for k, row in ipairs(rows) do
		local v = p.buildblock(row)
		if v then
			table.insert(expandedrows, v)
		end
	end
	if (#expandedrows == 0) then
		return nil
	end
	rows = expandedrows

	-- ADD TITLE
	local title
	if params.title or params.singulartitle or params.pluraltitle then
		local text
		if #rows > 1 and params.pluraltitle then
			text = params.pluraltitle
		elseif #rows == 1 and params.singulartitle then
			text = params.singulartitle
		else
			text = params.title
		end

		local style = params.titlestyle or {display='table-caption',border='unset'}
		style['text-align'] = style['text-align'] or 'center'
		style['color'] = style['color'] or thirdcolor
		style['background-color'] = style['background-color'] or secondcolor

		local colspan ='2'
		title = mw.html.create('caption')
			:attr({colspan = colspan})
			:css(style)
			:wikitext(text)
			:done()
	end
	
	local tabstyle =params.style or {width='100%',display='table'}
	tabstyle['border']= 'unset'
	tabstyle['margin']= 'unset'
	tabstyle['border-collapse']= 'separate'
	
	local tab = mw.html.create('table'):css(tabstyle)
	if #rows > 12 then
		tab = tab 
			:addClass('mw-collapsible mw-collapsed')
	end
	if title then
		tab:node(title)
	end
	
	for i, j in pairs (rows) do
		tab:node(j)
	end
	
	if params.separator then
		local separator = p.separator(params)
		tab:node(separator)
	end
	tab:allDone()
	return mw.html.create('tr'):tag('td')
		:node(tab) --:addClass('infobox_v3'))
		:css({border='unset'})
		:done()
end
p.buildTable = p.buildtable

function p.buildinvalidblock(args)
	defaultcat = i18n['default cat'];
	
	addMaintenanceCat(defaultcat)
	local text = ''
	if type(args) ~= 'table' then
		text = "لبنات قالب بطاقة يجب أن تكتب على شكل جداول (table)"
	else
		text = i18n["invalid block type"] .. ' : ' .. (args.type or '??')
	end
	return text
end
p.buildInvalidBlock = p.buildinvalidblock

function p.buildmap(params)
	if true then		return nil;		end
	
	-- paramètre d'affichage 
	local maplist = getValue(params.maps)
	local pointtype = params.pointtype
	local maptype = params.maptype -- choisit le type de carte le plus approprié (relief, administratif, etc.)	
	if type(maplist) == 'function' then
		maplist = maplist(localdata, localdata.item)
	end
	local width = tonumber(params.width) or 280
	if width > 280 then
		addMaintenanceCat("أخطاء في استعمال ب.ص.م/صورة كبيرة جدا")
		return 'صورة كبيرة جدا، العرض لا يجب أن يتجاوز 280بك'
	end

	-- récupération des données locales
	local pointtable = {}
	local globe = params.globe
	if params.latitude then
		local lat, long
		if type(params.latitude) == 'function' then
			lat, long = params.latitude(localdata, localdata.item), params.longitude(localdata, localdata.item)
		else
			lat = getValue(params.latitude, params) 
			long = getValue(params.longitude, params) 
		end
		if lat then
			table.insert(pointtable, {latitude = lat, longitude = long})
		end
	end

	-- récupération des données wikidata
	local function processWDval(claim, displayformat)
		if not claim then
			return nil
		end
		local val = wd.formatSnak( claim.mainsnak )
		return {latitude = val.latitude, longitude = val.longitude, globe = val.globe, marker = displayformat.marker}
	end
	
	local function getWDvals(query)
		query.excludespecial = true
		query.numval = query.numval or 1
		query.entity = query.entity or localdata.item
		local claims = wd.getClaims(query)
		if (not claims) then
			return
		end
		for i, claim in ipairs(claims) do
			claim = processWDval(claim, query)
			table.insert(pointtable, claim)
		end
	end
	
	if (#pointtable == 0) and localdata.item and params.wikidata and (params.wikidata ~= '-') then
		for i, query in ipairs(params.wikidata) do
			if type(query) == 'function' then
				query = query()
			end
			if query then
				getWDvals(query)
			end
		end
	end
	
	if (not pointtable) or (#pointtable == 0) then
		return nil
	end
	

	local geojson = {}
	table.insert(geojson, {
			['type'] = 'Feature',
			['geometry'] = {
				['type'] = "Point",
				['coordinates'] = { pointtable[1].longitude, pointtable[1].latitude }
			},
			['properties'] = {
				--['title'] = point.text or '',
				--['marker-symbol'] = point.marker,
				['marker-color'] =   "#224422", -- or point.markercolor
			}
    })	
	local margs = {
    		['height'] = width,
    		['width'] = width,
    		['frameless'] = 'frameless',
    		['align'] = 'center',
    		['latitude'] = pointtable[1].latitude,
    		['longitude'] = pointtable[1].longitude,
    		['zoom'] = params.default_zoom  or 13
    	}
	return mw.getCurrentFrame():extensionTag('mapframe', mw.text.jsonEncode(geojson), margs);


end
p.buildMap = p.buildmap

function p.buildexternaltext(params)
	local value = getValue(params.value)
	if value and (type(value) == 'string') then
		externaltext = externaltext .. value
	end
end
p.buildExternalText = p.buildexternaltext

function p.buildfooter(params)
	if not params then
		params = {}
	end
	
	local class = 'navbar noprint bordered ' .. (params.class or '')
	local style = params.style or {}
	style['border-top'] = style['border-top'] or '2px dotted ' .. maincolor
	style['display'] =  'block'
	
	local backlinkstr = '[' .. tostring( mw.uri.fullUrl( page.name, 'veaction=edit&section=0' ) ) .. ' ' .. i18n['edit'] .. ']'
		.. ' - [' .. tostring( mw.uri.fullUrl( page.name, 'action=edit&section=0' ) ) .. ' ' .. i18n['edit code'] .. ']'

	local itemlinkstr
	if localdata.item then
		itemlinkstr = '[[d:' .. localdata.item.id .. '|' .. i18n['edit item'] .. ']]'
	end
	local editstr = backlinkstr
	if itemlinkstr then
		editstr = editstr .. ' - ' .. itemlinkstr
	end
	local editlinkspan =  mw.html.create('span')
		:css({['text-align'] = "right"})
		:addClass('plainlinks')
		:wikitext(editstr)
		:done()
	local doclinkstr = '[[File:Info Simple.svg|12px|link=' .. localdata.templatename .. '|' .. i18n['see doc'] .. ']]'
	-- si ce lien ne marche pas toujours, il faut ajouter un variable pour le nom de l'infobox récupéré par le frame
	local doclinkspan = mw.html.create('span')
		:css({['text-align'] = "left",['float'] = "left"})
		:wikitext(doclinkstr)
		:done()
	
	local footer = mw.html.create('tr'):tag('td'):tag('p') --mw.html.create('p')
		:addClass(class)
		:css(style)
		:node(editlinkspan)
		:node(doclinkspan)
		:done()
	return footer
end
p.buildFooter = p.buildfooter

function p.buildblock(block)
	if type(block) == 'function' then
		block = block( localdata )
	end

	local blocktypes = { -- list of functions for block buildings
		['invalid'] = p.buildinvalidblock,
		['external text'] = p.buildexternaltext,
		['footer'] = p.buildfooter,
		['images'] = p.buildimages,
		['map']= p.buildmap,
		['mixed'] = p.buildrow,
		['navbox'] = p.buildnavbox,
		['table'] = p.buildtable,
		['row'] = p.buildrow,
		['row1col'] = p.buildrow1col,
		['succession'] = p.buildnavbox, --,p.buildsuccession
		['text'] = p.buildtext,
		['title'] = p.buildtitle,
		['subtitle'] = p.buildsubtitle,
		['1row'] = p.build1row,
	}
	if type(block) ~= 'table' or (not block.type) or (not blocktypes[block.type]) then
		return blocktypes['invalid'](block)
	end
	return blocktypes[block.type](block) 
end
p.buildBlock = p.buildblock

function p.build()
	
	localdata = require( 'وحدة:بطاقة/بيانات')
	item = localdata.item

	-- assign rank to the infobox, "secondary" means special formatting like no displaytitle for coordinates
	local infoboxrank = 'main' -- main infobox of the page, with coordinates displayed in title etc.
	if page.namespace ~= 0 then
		infoboxrank = 'secondary'
	end
	-- if infobox is linked to another item: rank = secondary
	if localdata.item then
		local itemlink = mw.wikibase.sitelink(localdata.item.id)
		local pagetitle = mw.title.getCurrentTitle().text
		if (itemlink or '') ~= pagetitle then
			infoboxrank = 'secondary'
		end
	end
	localdata.infoboxrank = infoboxrank

	-- load infobox module page
	local moduledata = require('وحدة:بطاقة/قالب/' .. localdata.modulename)
	moduledata.name = localdata.modulename
	localdata.wikimod = moduledata.wikimod 
	
	-- defines main color
	maincolor = localdata['لون الخلفية'] or moduledata.maincolor or maincolor
	secondcolor =  moduledata.secondcolor or secondcolor
	thirdcolor = localdata['لون الكتابة'] or moduledata.thirdcolor or thirdcolor
	if maincolor:match( '^%x%x%x%x%x%x$' ) or maincolor:match( '^%x%x%x$' ) then
		maincolor = '#' .. maincolor
	end
	
	-- class
	local class = 'infobox_v2b mainTable infobox'
	if moduledata.class then
		class = class .. ' ' .. moduledata.class
	end
	
	-- style
	local style = moduledata.style or {}
	--if not style['max-width'] then
	--	style['max-width'] = 'none'
	--end
	
	-- build infobox
	infobox	:addClass(class)
			:css(style)
	for i, j in pairs( moduledata.parts ) do
		infobox:node(p.buildblock(j))
	end
	infobox
		:node(p.buildfooter(moduledata.footer))
		:allDone()

	templatestyles = mw.getCurrentFrame():extensionTag( 'templatestyles', '', { src = "ب.ص.م/infobox_v2b/styles.css" } );
	return templatestyles .. tostring(infobox) .. externaltext, maintenance
end

return p