Модул:Isomer
Этот модуль оценён как готовый к использованию. Предпологается, что все баги устранены и он готов для широкого использования. Его можно указывать на справочных страницах и рекомендовать к использованию новым участникам. Для его изменения и тестирования, пожалуйста, используйте песочницу.Категория:Модули:Стабильные |
Функции
[вироиши манбаъ]Section
[вироиши манбаъ]{{#invoke:Isomer|Section|full-width|half-width|title-background|desc-background|data-background|border-color|shortnames|title|mandatory-title|wide-column|collapsed|nocat|1|2|3|…}} — отображает несколько строк (секцию) таблицы. Перед первым вызовом функции в тексте должно быть начало таблицы ({|) или начало новой строки (|-), после последнего — окончание таблицы (|}) или следующая строка. Параметры вызова:
- half-width
- Ширина блока, расположенного в правой ячейке.
- full-width
- Ширина блока, занимающего две объединённые ячейки.
- title-background
- Цвет фона заголовка секции.
- desc-background
- Цвет фона левой ячейки.
- data-background
- Цвет фона правой ячейки.
- border-color
- Цвет границы заголовка секции.
- shortnames
- Краткое имя, список, элементы которого идентифицируют отображаемое значение как относящееся к определённому изомеру.
- title
- Текст заголовка секции, при отсутствии заголовок не отображается.
- mandatory-title
- Заголовок отображается даже для пустой секции (любое непустое значение).
- wide-column
- Таблица должна иметь три столбца (см. например {{drugbox}}), если параметр равен 1 — объединяются первый и второй столбец, если 2 — второй и третий.
- collapsed
- Секция свёрнута (любое непустое значение).
- nocat
- Автоматическая категоризация (см. ниже category) отключена (любое непустое значение).
Далее идут тройки безымянных параметров:
- 1
- Описание параметра, текст левой ячейки. При пустом значении ячейки объединяются.
- 2
- Величина параметра, текст правой ячейки. Если все параметры 2 в секции пустые, секция не отображается.
- 3
- Дополнительные параметры.
Строка может иметь несколько дополнительных параметров, которые отделяются друг от друга точкой с запятой. Значения параметра, если они имеются, отделяются от его имени двоеточием. Значение параметра не должно содержать точку с запятой, знаки равенства должны экранироваться. Дополнительные параметры:
- unit:единица\минимальная степень\максимальная степень\используемая степень
- Отображается физическая величина с нормализацией значения.
- единица — единица физической величины, обычно используется без приставок, например «г»;
- минимальная и максимальная степень — степени десятичных множителей, используемые для данной величины, например «г\-6\3» указывает, что могут использоваться микрограммы, миллиграммы, граммы, килограммы, но не мегаграммы («0\0» запрещает модификацию значения, в этом случае можно указывать величину с приставкой, например «нм\0\0»);
- используемая степень — множитель, применяющийся для величины, например «Дж\\\3» означает, что энергия указывается в килоджоулях.
- Параметр 2 может быть диапазоном значений.
- link:ссылка
- Отображается указанная ссылка, параметр 2 добавляется к ссылке и используется как её заголовок.
- columns:колонки
- Указывает число колонок, используется для вывода изображений. Параметр 2 интерпретируется как имя файла, если файл не найден, то значение параметра выводится без изменений.
- templates:шаблон
- Параметр 2 передаётся в указанный шаблон.
- word-wrap
- Длинные слова могут разбиваться для переноса.
- image-width:ширина
- Ограничивает ширину изображения по сравнению с расчётной по ширине поля или колонки.
- category:категория
- Если параметр 2 пустой, страница включается в указанную категорию.
- multivalue-separator:входной\выходной
- Разделитель нескольких значений параметров внутри изомера, по умолчанию «; \<br />». Входной используется для разделения входных значений, выходной добавляется к обработанным строкам. Если указан пустой входной разделитель, строка будет обрабатываться целиком, без разделения.
- extension:расширение
- Используется дополнительная обработка значения параметра 2.
- GHS — коды разделённые произвольным, но одинаковым для всей строки символом передаются в шаблон {{H-фраза}} или {{P-фраза}}.
- NFPA704 — четыре значения, разделённые запятыми, используются в качестве соответствующих параметров шаблона {{NFPA 704}}.
- ICD10 — каждое значение из списка, разделённого запятыми, используется в шаблоне {{ICD10}} (с необходимым разделением на части).
- capitalise — заменяет первый символ на заглавный.
IsomerButtons
[вироиши манбаъ]{{#invoke:Isomer|IsomerButtons|1}} — отображает строку — список изомеров. Параметры вызова:
- title-background
- Цвет фона заголовка.
- border-color
- Цвет границы заголовка.
- dark-color
- Цвет тёмного фона.
- light-color
- Цвет светлого фона.
- title
- Текст заголовка, см. выше.
- 1
- Краткое имя, см. shortnames выше.
Isomers
[вироиши манбаъ]{{#invoke:Isomer|Isomers|1|2|unit|link|columns|width}} — отображает значения параметра для каждого изомера. Функция в шаблоне {{Изомеры}} непосредственно больше не используется (заменена на Section) и будет исключена из модуля. Параметры вызова:
- 1
- Краткое имя, см. выше.
- 2
- Отображаемая величина, ссылка, файл.
- unit
- Отображается физическая величина с нормализацией значения, см. выше.
- link
- Отображается указанная ссылка, см. выше.
- columns
- Указывает число колонок, см. выше.
- width
- Ширина поля или общая ширина всех колонок.
local I={}
-- Формирует содержимое ячейки для шаблона Изомеры
local IsDigit
IsDigit=function(char)
return mw.ustring.find('0123456789⁰¹²³⁴⁵⁶⁷⁸⁹',char,1,true)
end
local IsExclus
IsExclus=function(char)
return mw.ustring.find('%°℃K',char,1,true)
end
local physval
physval=function(text,physunit)
local s=mw.text.trim(text);
local lastchar=mw.ustring.sub(s,-1);
if (IsDigit(lastchar)) then
local prefs={
[-24]='и',
[-21]='з',
[-18]='а',
[-15]='ф',
[-12]='п',
[-9]='н',
[-6]='мк',
[-3]='м',
[0]='',
[3]='к',
[6]='М',
[9]='Г',
[12]='Т',
[15]='П',
[18]='Э',
[21]='З',
[24]='И'
}
local p=mw.text.split(physunit,'\\',true); -- например: г\-6\3\0
local punit=p[1]; -- граммы (г)
local pmin=tonumber(p[2]) or -24; -- допустимые приставки и множители: аз мк (10⁻⁶)
local pmax=tonumber(p[3]) or 24; -- то ба (10³)
local pval=tonumber(p[4]) or 0; -- текущее значение: граммы (10⁰)
local v=mw.text.split(s,'[—…]',false); -- если диапазон значений
local vmin=v[1];
local vmax=v[2];
local firstchar=mw.ustring.sub(vmin,1,1); -- знаки <, > и т. д. перед числом, но не минус
if ((firstchar~='-') and (firstchar~='−') and not IsDigit(firstchar)) then
vmin=mw.ustring.sub(vmin,2);
else
firstchar=nil;
end
local lang=mw.language.new('ru');
vmin=lang:parseFormattedNumber(vmin);
vmax=lang:parseFormattedNumber(vmax);
if ((vmin) and (not v[2] or vmax)) then -- распознаны оба числа диапазона или единственное
local pow, p;
if (not IsExclus(mw.ustring.sub(punit,1,1))) then
if (vmax and ((math.abs(math.floor(math.log10(math.abs(vmax)))) % 3) < (math.abs(math.floor(math.log10(math.abs(vmin)))) % 3))) then
p=math.log10(math.abs(vmax)); -- напр.: 120—1400 Ед → 0,12—1,4 кЕд
else
p=math.log10(math.abs(vmin));
if ((p<0) and (p>=-1)) then
p=0; -- напр.: 120 мЕд → 0,12 Ед
end;
end;
pow=math.floor(p / 3) * 3 +pval;
pow=math.max(pow,pmin);
pow=math.min(pow,pmax);
else
pow=0 -- к указанным ед. приставки не применяем
end
vmin=vmin/(10^(pow-pval));
s=firstchar or ''; -- начало форматирования
if (firstchar and (vmin<0)) then
s=s..' ';
end
s=s..lang:formatNum(vmin);
if (vmax) then
vmax=vmax/(10^(pow-pval));
if (vmin<0) then
s=s..'…';
else
s=s..'—';
end
if (vmax<0) then
s=s..' ';
else
if (vmin<0) then
s=s..'+';
end
end
s=s..lang:formatNum(vmax);
end
punit=prefs[pow]..punit;
else
punit=prefs[pval]..punit; -- похоже на число, но не обработано
end
if (punit~='°') then
s=s..' ';
end
s=s..punit;
end
return s
end
local formatimg
formatimg=function(text,width)
local s=text;
if (mw.ustring.sub(text,1,1)~='[') then
local o=mw.title.new(text,'Media');
if (o) and (o.exists) then
s='[[File:'..text..'|'..tostring(width)..'px]]';
end
end
return s
end
local splitPrefValSuff
splitPrefValSuff=function(text)
local p,s;
local pref='';
local val;
local suff='';
p=mw.ustring.find(text,':');
s=mw.ustring.find(text,'(',p or 2,true);
if (p) then
pref=mw.ustring.sub(text,1,p)..' ';
p=p+1;
end
if (s) then
suff=' '..mw.ustring.sub(text,s,-1);
s=s-1;
end
val=mw.ustring.sub(text,p or 1,s);
return pref,val,suff
end
local extGHS
extGHS=function(text)
local s='';
local v={};
local firstchar=mw.ustring.sub(text,1,1);
if ((firstchar=='P') or (firstchar=='H')) then
local f=mw.getCurrentFrame();
local pos=1;
local delimiter;
repeat -- разделитель может быть любой, но + используется внутри фразы
pos=mw.ustring.find(text,firstchar,pos+1,true);
if (pos) then
delimiter=mw.ustring.sub(text,pos-1,pos-1);
end
until ((not pos) or (delimiter~='+'))
if (pos) then
v=mw.text.split(text,delimiter,true);
else
v={text};
end
for i=1,#v do
if (firstchar=='P') then
s=s..f:expandTemplate{title='P-фраза',args={v[i]}};
else
s=s..f:expandTemplate{title='H-фраза',args={v[i]}};
end
if (i<#v) then
s=s..', ';
end
end
else
s=text;
end
return s
end
local extNFPA
extNFPA=function(text)
local s='';
local v={};
local f=mw.getCurrentFrame();
if (mw.ustring.find(text,',',1,true)) then
v=mw.text.split(text,',',true);
else -- викиданные без разд. дабы не вывод. пустое поле)
v[1]=mw.ustring.sub(text,1,1);
v[2]=mw.ustring.sub(text,2,2);
v[3]=mw.ustring.sub(text,3,3);
v[4]=mw.ustring.sub(text,4,-1);
end
s=f:expandTemplate{title='NFPA 704',args={['опасность для здоровья'] = v[1], ['огнеопасность'] = v[2], ['реакционоспособность'] = v[3], ['прочее'] = v[4]}}
return s
end
local extICD10
extICD10=function(text)
local s='';
if (mw.ustring.find(text,']]',1,true)) then
s=text; -- есть викификация, не трогаем
else
local v=mw.text.split(text,',',true);
local str,sA,sB;
local f=mw.getCurrentFrame();
for i=1,#v do
str=mw.text.trim(v[i]);
sA=mw.ustring.sub(str,1,1);
sB=mw.ustring.sub(str,2,-1);
s=s..f:expandTemplate{title='ICD10',args={sA,sB}};
if (i<#v) then
s=s..', ';
end
end
end
return s
end
local capitalise
capitalise=function(text)
local pos=(mw.ustring.find(text,'|') or 0) + 1; -- если викифицированно
local s=mw.ustring.sub(text,1,pos-1)..mw.ustring.upper(mw.ustring.sub(text,pos,pos))..mw.ustring.sub(text,pos+1,-1);
return s
end
local processvalue
processvalue=function(text,opt)
local s;
if (opt.ext=='GHS') then --extensions
text=extGHS(text);
elseif (opt.ext=='NFPA704') then
text=extNFPA(text);
elseif (opt.ext=='ICD10') then
text=extICD10(text);
end
if (opt.physunit) then
s=physval(text,opt.physunit);
elseif (opt.link) then
s=[[<span class="reflink plainlinksneverexpand">[]]..opt.link..text..' '..text..[[]</span>]];
elseif (opt.columns) then
s=formatimg(text,opt.imgwidth);
elseif (opt.temps) then
local f=mw.getCurrentFrame();
s=f:expandTemplate{title=opt.temps,args={text}};
else
s=text;
end
return s
end
local getmultivalues
getmultivalues=function(text,opt)
local multivalues={};
local prefvalsuff={};
local strsepin='; ';
if (opt.mvsep) then -- разделители множественных значений (на входе и на выходе)
local sep=mw.text.split(opt.mvsep,'\\',true)
strsepin=sep[1];
end
local pref,val,suff;
local hasHtml = mw.ustring.find(text,'<%a.->');
-- ((mw.ustring.sub(text,1,1)=='<') and (mw.ustring.sub(text,2,2)~=' ') and (not IsDigit(mw.ustring.sub(text,2,2))))
if (hasHtml or (#strsepin==0)) then
if (hasHtml) then
opt.ext=nil; --на входе html, ничего не трогаем
end
prefvalsuff={
pref='',
val=text,
suff=''
}
table.insert(multivalues,prefvalsuff);
else
local v=mw.text.split(text,strsepin,true); -- значения можно разделять '; '
for i=1,#v do
if (opt.columns) then
pref,val,suff='',v[i],''; --имя файла, не трогаем
else
pref,val,suff=splitPrefValSuff(v[i]); -- с собственными пояснениями
end
val=mw.text.trim(val);
prefvalsuff={
pref=pref,
val=val,
suff=suff
}
table.insert(multivalues,prefvalsuff);
end
end
return multivalues
end
local processmultivalues
processmultivalues=function(values,opt)
local s='';
local strsepout=[[<br />]];
if (opt.mvsep) then -- разделители множественных значений (на входе и на выходе)
local sep=mw.text.split(opt.mvsep,'\\',true)
if (sep[2]) then
strsepout=sep[2];
end
end
if (opt.capitalise) then
values[1].val=capitalise(values[1].val);
end
for i=1, #values do
s=s..values[i].pref..processvalue(values[i].val,opt)..values[i].suff;
if (i<#values) then
s=s..strsepout;
end
end
return s
end
local getlocalisomers
getlocalisomers=function(shortnamelist,textlist,opt)
local isomers={};
local shortnames, text;
if ((#shortnamelist>0) and (mw.ustring.find(textlist,'\\'))) then
shortnames=mw.text.split(shortnamelist,'\\');
text=mw.text.split(textlist,'\\');
n=#shortnames;
else
shortnames={};
text={textlist};
n=1;
end
for i=1,n do
if (text[i]) and (#text[i]~=0) then
local isomer={
shortname = shortnames[i],
values = getmultivalues(text[i],opt)
}
table.insert(isomers,isomer);
end
end
return isomers
end
local getproperty
getproperty=function(property,firstonly)
local propertyvalues={};
local entity=mw.wikibase.getEntityObject();
if (entity and entity.claims and entity.claims[string.upper(property)]) then
local rank = 'normal'
for i, statement in pairs( entity.claims[string.upper(property)] ) do
if (statement.rank == 'preferred') then
rank = 'preferred'
break
end
end
for i, statement in pairs( entity.claims[string.upper(property)] ) do
if (statement.rank == rank) then
if (statement.mainsnak.snaktype == 'value') then
local val;
if (statement.mainsnak.datavalue.type == 'wikibase-entityid') then
local id = 'Q'..statement.mainsnak.datavalue.value['numeric-id'];
local link = mw.wikibase.sitelink(id)
local label = mw.wikibase.label(id);
if link then
if label then
val='[['..link..'|'..label..']]';
else
val='[['..link..']]';
end
else
if label then
val=label;
else
val='[[d:'..id..'|'..id..']]';
end
end
elseif statement.mainsnak.datavalue.type == 'quantity' then
val=statement.mainsnak.datavalue.value['amount'];
else
val=statement.mainsnak.datavalue.value;
end
table.insert(propertyvalues,val);
if (firstonly) then
break;
end
end
end
end
end
return propertyvalues
end
local getwikidataisomers
getwikidataisomers=function(shortnamelist,textlist,opt)
local isomers={};
local multivalues={};
local prefvalsuff={};
local val={};
if (mw.ustring.find(opt.property,'\\')) then
local s=''; --several prop. in one cell (NFPA 704)
local properties=mw.text.split(opt.property,'\\');
for i=1, #properties do
s = s..(getproperty(properties[i],true)[1] or '');
end
if (#s>0) then
val={s};
end
else
val = getproperty(opt.property,false);
end
for i=1, #val do
prefvalsuff={
pref='',
val=val[i],
suff=''
}
table.insert(multivalues,prefvalsuff);
end
if (#multivalues > 0) then
local isomer={
shortname = nil,
values = multivalues
}
table.insert(isomers,isomer);
end
return isomers
end
local processisomers
processisomers=function(row)
local s='';
local str, str2, colwidth;
if (row.options.columns) then
colwidth=math.floor(row.options.width/row.options.columns);
else
colwidth=row.options.width;
end
if ((not row.options.imgwidth) or (row.options.imgwidth > colwidth)) then
row.options.imgwidth=colwidth;
end
if (row.options.width and row.isomers[1].shortname) then
row.options.imgwidth=row.options.imgwidth-20;
end
for i=1,#row.isomers do
-- if (text[i]) and (#text[i]~=0) then
if ((row.isomers[i].shortname) or row.options.width) then -- оборачиваем рез-т в div и (или) подписываем кратким названием
str='<div';
if (row.isomers[i].shortname) then
str=str..[[ class="mw-collapsible" id="mw-customcollapsible-isomer]]..tostring(i)..[=["]=];
end
if (row.options.width) then
str=str..[[ style="width:]]..tostring(colwidth)..[=[px; word-wrap:break-word;]=];
if (row.options.columns) then
str=str..' display:inline-block; vertical-align:top';
end
str=str..[["]]; --end style
end
str=str..'>'; --end div
if (row.isomers[i].shortname) then
if (row.options.columns) then
str=str..[[<span style="vertical-align:top; letter-spacing:normal;">]];
end
str=str..[[''']]..row.isomers[i].shortname..[=[''': ]=];
if (row.options.columns) then
str=str..[[</span>]];
end
end
str2=[[</div>]];
else
str='';
str2='';
end
s=s..str..processmultivalues(row.isomers[i].values,row.options)..str2;
-- end
end
if (row.options.columns) then
s=string.format([[<div style="width:%ipx; text-align:center; letter-spacing:-5px; margin: 0 auto">%s</div>]],row.options.width,s);
end
return s
end
--[=[function I.Isomers(frame)
local shortnamelist=frame.args[1];
local textlist=frame.args[2];
local opt={};
opt.physunit=frame.args['unit'];
opt.link=frame.args['link'];
opt.width=tonumber(frame.args['width']);
opt.columns=tonumber(frame.args['columns']);
return isomers(shortnamelist,textlist,opt)
end]=]
local getrow
getrow=function(shortnames,desc,value,opt)
local row;
local isomers={};
if (opt.property) then
isomers=getwikidataisomers(shortnames,value,opt);
end
if (#isomers == 0) then
opt.property = nil; --данные получены не из викиданных
isomers=getlocalisomers(shortnames,value,opt);
end
if (#isomers > 0) then
row={
isomers = isomers,
description = desc,
options = opt
}
end
return row
end
-- Формирует строку - список изомеров
function I.IsomerButtons(frame)
local titlebg=frame.args['title-background'] or '#F8EABA';
local bordercolor=frame.args['border-color'] or '#C0C090';
local darkcolor=frame.args['dark-color'] or '#F0F0C0';
local lightcolor=frame.args['light-color'] or '#F8F8C8';
local title=frame.args['title'];
local shortnamelist=frame.args[1];
local s='';
local bgcolor;
if (#shortnamelist>0) then
if ((title) and (#title>0)) then
s=s..string.format([[!colspan="2" align="center" cellspacing="3" style="border:1px solid %s;background:%s;margin-bottom:3px"|%s]],bordercolor,titlebg,title);
s=s..'\n|-\n|colspan="2" style="padding:0"|\n';
end;
local shortname=mw.text.split(shortnamelist,'\\');
local n=#shortname;
local width=math.floor(100 / n + 0.5);
s=s..[[{| style="border: 0px; border-collapse:collapse; text-align:center; width:100%"]]..'\n';
for i=1,n do
if ((i % 2) ==0) then
bgcolor=darkcolor;
else
bgcolor=lightcolor;
end
s=s..string.format([[|bgcolor="%s" width="%i%%"|<div class="mw-customtoggle-isomer%i">%s</div>]],bgcolor,width,i,shortname[i])..'\n';
end
s=s..'|}';
if ((title) and (#title>0)) then
s=s..'\n|-\n';
end
end
return s
end
-- Формирует секцию: заголовок и поля
local hash
hash=function(text)
local h={0,0,0,0,0,0}
local s=''
for i = 1, mw.ustring.len(text) do
h[(i % 6) + 1]=h[(i % 6) + 1]+mw.ustring.codepoint(text,i);
end
for i = 1, 6 do
s=s..mw.ustring.char((h[i] % 26)+mw.ustring.codepoint('a',1));
end
return s
end
local splitfirst
splitfirst=function(s,pattern,plain)
local s1,s2;
local i=mw.ustring.find(s,pattern,1,plain);
if (i) then
s1=mw.ustring.sub(s,1,i-1);
s2=mw.ustring.sub(s,i+1,-1);
else
s1=s;
s2='';
end
return s1,s2
end
function I.Section(frame)
local fullwidth=tonumber(frame.args['full-width']) or 225;
local halfwidth=tonumber(frame.args['half-width']) or math.floor(fullwidth * 0.6);
local titlebg=frame.args['title-background'] or '#F8EABA';
local bordercolor=frame.args['border-color'] or '#C0C090';
local descbg=frame.args['desc-background'] or '#F0F0C0';
local databg=frame.args['data-background'] or '#FFFFFF';
local shortnames=frame.args['shortnames'] or '';
local title=frame.args['title'];
local mand=frame.args['mandatory-title'];
local widecol=tonumber(frame.args['wide-column']) or 0;
local strcolspan1='';
local strcolspan2='';
local strcolspan3='colspan="2"';
if (widecol > 0) then
strcolspan3='colspan="3"';
if (widecol == 1) then
strcolspan1='colspan="2"';
else
strcolspan2='colspan="2"';
end
end
local strcollapsed='';
if (frame.args['collapsed']) then
strcollapsed='mw-collapsed';
end
local nocat=frame.args['nocat'];
local rows={};
local s='';
local r=2;
local strid='';
local desc,value,options;
local physunit,link,width,columns,ext;
local w,optname,optval;
r=1;
while (frame.args[r]) do
desc=mw.text.trim(frame.args[r]);
value=mw.text.trim(frame.args[r+1] or '');
options=mw.text.trim(frame.args[r+2]);
r=r+3;
if (#desc>0) then
w=halfwidth;
else
w=fullwidth;
end
opt={};
if (options) then
for j,u in ipairs(mw.text.split(options,';',true)) do
optname,optval=splitfirst(u,'[:=]',false);
optname=mw.ustring.lower(mw.text.trim(optname));
optval=optval or '';
optval=mw.ustring.gsub(optval,'&sem&',';')
if (optname=='unit') then
opt.physunit=optval;
elseif (optname=='link') then
opt.link=optval;
elseif (optname=='capitalise') then
opt.capitalise=true;
elseif (optname=='word-wrap') then
opt.width=w;
elseif (optname=='columns') then
opt.columns=optval;
opt.width=w;
elseif (optname=='image-width') then
opt.imgwidth=tonumber(optval);
opt.width=w;
elseif (optname=='extension') then
opt.ext=optval;
elseif (optname=='templates') then
opt.temps=optval;
elseif (optname=='multivalue-separator') then
opt.mvsep=optval;
elseif (optname=='category') then
if ((#value==0) and not nocat) then
local o=mw.title.getCurrentTitle();
if (o.namespace==0) then
s=s..string.format('[[Category:%s]]\n',optval);
end
end
elseif (optname=='property') then
opt.property=optval;
end
end
end
table.insert(rows,getrow(shortnames,desc,value,opt));
end
if ((title) and (#title>0)) then
if ((#rows>0) or mand) then
local h=hash(title);
strid=string.format([[id="mw-customcollapsible-%s" class="mw-collapsible %s"]],h,strcollapsed)
s=string.format([[!%s align="center" cellspacing="3" style="border:1px solid %s;background:%s;margin-bottom:3px"|<div class="mw-customtoggle-%s">%s</div>]],strcolspan3,bordercolor,titlebg,h,title)..'\n';
end
end
for i=1, #rows do
if (#rows[i].isomers > 0) then
s=s..string.format('|-%s\n',strid);
if ((rows[i].description) and (#rows[i].description>0)) then
s=s..string.format([[|%s bgcolor="%s"|%s||%s bgcolor="%s"|]],strcolspan1,descbg,rows[i].description,strcolspan2,databg);
else
s=s..string.format([[|%s bgcolor="%s"|]],strcolspan3,databg);
end
s=s..processisomers(rows[i])..'\n';
end
end
s=s..'|-\n';
return s
end
return I