Вот так выглядит готовое поле:

Сделать несложно:
- Создаем Пространство имен gridtv и прописываем пути:
- Создаем папки core/components/gridtv/tv/input/tpl/
- В core/components/gridtv/tv/input создаем файл gridtv.class.php:
<?php if(!class_exists('GridTVRender')) { class GridTVRender extends modTemplateVarInputRender { public function getTemplate() { return $this->modx->getOption('core_path').'components/gridtv/tv/input/tpl/gridtv.tpl'; } public function process($value,array $params = array()) { } } } return 'GridTVRender';
- В core/components/gridtv/tv/input/tpl создаем файл gridtv.tpl:
<style> {literal} table.editable th { padding:5px 10px; background:#E4E9EE; font-weight:bold; height:20px; } table.editable td { background:#e9e9e9; padding:5px 10px; height:20px; } table.editable input{ width:50px; } {/literal} </style> <table id="table{$tv->id}" class="editable" > <tbody id="tbody{$tv->id}"> </tbody> </table> <input type="hidden" id="tv{$tv->id}" name="tv{$tv->id}" value="{$tv->value}"> <script type="text/javascript"> // <![CDATA[ {literal} var data=[[{"type":"TH","value":"ТИРАЖ/ШИРИНА, мм"}]]; {/literal} if(document.getElementById("tv{$tv->id}").value!=""){ data=JSON.parse(document.getElementById("tv{$tv->id}").value.replace(/\'/gi,'"')); } console.log(data); var tbody=document.getElementById("tbody{$tv->id}"); for(var r=0;r<data.length;r++){ var tr=document.createElement("tr"); if(r==0){ tr.id="frow{$tv->id}"; } for(var c=0;c<data[r].length;c++){ if(undefined!=data[r][c]){ var cell=document.createElement(data[r][c].type); var input=document.createElement("input"); input.type="text"; input.value=data[r][c].value; cell.appendChild(input); tr.appendChild(cell); } } if(r==0){ var btn=document.createElement("button"); btn.onclick=addColumn{$tv->id}; btn.textContent="+"; var btn2=document.createElement("button"); btn2.onclick=deleteColumn{$tv->id}; btn2.textContent="-"; var cth=document.createElement("th"); cth.id="cth{$tv->id}"; cth.appendChild(btn); cth.appendChild(btn2); tr.appendChild(cth); } tbody.appendChild(tr); } var btn=document.createElement("button"); btn.onclick=addRow{$tv->id}; btn.textContent="+"; var btn2=document.createElement("button"); btn2.onclick=deleteRow{$tv->id}; btn2.textContent="-"; var rth=document.createElement("th"); var tr=document.createElement("tr"); tr.id="rth{$tv->id}"; rth.appendChild(btn); rth.appendChild(btn2); tr.appendChild(rth); tbody.appendChild(tr); var inputs=document.getElementById("table{$tv->id}").getElementsByTagName("input"); for(var k=0;k<inputs.length;k++){ inputs[k].onkeyup=function(e){ document.getElementById("tv{$tv->id}").value=tableToJson{$tv->id}(); } } function addColumn{$tv->id}(){ var node = document.getElementById("frow{$tv->id}"); var input=document.createElement("input"); input.type="text"; input.onkeyup=function(e){ document.getElementById("tv{$tv->id}").value=tableToJson{$tv->id}(); } var th=document.createElement("th"); th.appendChild(input); node.insertBefore(th,document.getElementById("cth{$tv->id}")); rebuidlTable{$tv->id}(); } function addRow{$tv->id}(){ var node = document.getElementById("tbody{$tv->id}"); var tr=document.createElement("tr"); var input=document.createElement("input"); input.type="text"; var th=document.createElement("th"); th.appendChild(input); tr.appendChild(th); node.insertBefore(tr,document.getElementById("rth{$tv->id}")); rebuidlTable{$tv->id}(); } function rebuidlTable{$tv->id}(){ var frow=document.getElementById("frow{$tv->id}"); var tbody=document.getElementById("tbody{$tv->id}"); //console.log(tbody.childElementCount); var rows=tbody.childElementCount-2; var cols=frow.childElementCount-1; for(var i=1;i<=rows;i++){ var cm=cols-tbody.children[i].childElementCount; for(var j=0;j<cm;j++){ var td=document.createElement("td"); var input=document.createElement("input"); input.type="text"; td.appendChild(input); tbody.children[i].appendChild(td); } } } function deleteRow{$tv->id}(){ if(tbody.childElementCount>=3){ tbody.children[tbody.childElementCount-2].remove(); } } function deleteColumn{$tv->id}(){ for(var i=0;i<tbody.childElementCount-1;i++){ var rows=tbody.children[i].children; if((i>0)&&(rows.length>1)){ rows[rows.length-1].remove(); }else{ if(rows.length>2){ rows[rows.length-2].remove(); } } } } function tableToJson{$tv->id}(){ var arr=Array(); var rows=document.getElementById("tbody{$tv->id}").children; for(var i=0;i<rows.length;i++){ var cells=rows[i].children; arr[i]=Array(); for(var j=0;j<cells.length;j++){ if(cells[j].textContent!="+-"){ if(cells[j].getElementsByTagName("input").length>0){ var val=cells[j].getElementsByTagName("input")[0].value; }else{ var val=cells[j].textContent; } {literal} arr[i].push({"type":cells[j].tagName,"value":val}); {/literal} } } } if(arr[arr.length-1].length==0){ arr.pop(); } return JSON.stringify(arr).replace(/\"/gi,"'"); } // ]]> </script>
- Создаем новый плагин и отмечаем указанные события:
<?php $corePath = $modx->getOption('core_path',null,MODX_CORE_PATH).'components/gridtv/'; switch ($modx->event->name) { case 'OnTVInputRenderList': $modx->event->output($corePath.'tv/input/'); break; case 'OnTVOutputRenderList': $modx->event->output($corePath.'tv/output/'); break; case 'OnTVInputPropertiesList': $modx->event->output($corePath.'tv/inputoptions/'); break; case 'OnTVOutputRenderPropertiesList': $modx->event->output($corePath.'tv/properties/'); break; }
- Создаем новую TV и выбираем тип gridtv
На выходе TV дает JSON с полями «type»:«TH» или «TD» и «value» ячейки.
Обрабатывать можно, например, вот таким сниппетом:
<?php
$page = $modx->getObject('modResource', $modx->resource->id);
$data=$modx->fromJSON(str_replace("'",'"',$page->getTVValue("grid")));
if(count($data)>1){
$out='<table>
<tbody>';
$frow=true;
foreach($data as $row){
$out.="<tr>";
foreach($row as $cell){
if($frow){
$out.='<th class="first_row">'.$cell['value'].'</th>';
}else{
if($cell['type']=="TH"){
$out.='<th>'.$cell['value'].'</th>';
}else{
$out.='<td>'.$cell['value'].'</td>';
}
}
}
$out.="</tr>";
$frow=false;
}
echo $out."</tbody></table>";
}
Павел Романов 19.01.2016 10:42 #
)))
Удален 19.01.2016 11:22 #
Павел Романов 19.01.2016 11:32 #
Просто очень много решений есть уже готовых.
Удален 19.01.2016 21:28 #
Да и насчет «много решений», вы слегка погорячились — мне встречались 2 — упомянутый Павлом tvtable и громоздкая надстройка над MIGX.
Волков Николай 31.01.2016 23:48 #
Василий 17.02.2017 21:54 #