ich hatte mitbekommen, das viele auf der Suche nach einer lauffähigen Version des "DynTable"-Moduls sind. Bis 4.2 war diese lauffähig, danach ging es nicht mehr; bis jetzt
Ich hab das komplette Modul noch mal überarbeitet - zwar immer noch nicht mit jQuery umgesetzt, jedoch viele Fehler behoben und das Ding einfach mal etwas aufgeräumt. Auch sind die JS-Fehler raus.
- Bugs behoben
- auf short_open_tags verzichtet
- Stylings angepasst
- noHover ist zurück
Redaxo 4.3 arbeitet anscheinend etwas anders mit den "Aktionen", deswegen hier der wichtige Hinweis: Die Aktion "rexname" bitte als JEDE Aktion mit JEDEM Event einfügen - dann funktioniert auch alles ordentlich. (siehe Screenshot)
Modul Eingabe
- Code: Alles auswählen
<style type="text/css">
.tableImgs {
float: left;
width: 40px;
margin-bottom: 5px;
margin-top: 5px;
}
table#tabelle,
#tabelle td,
#tabelle tr,
#tabelle th {
vertical-align: middle;
}
table#tabelle input {
margin-right: 5px;
}
</style>
<?php
$rexname = explode("~~","REX_VALUE[1]");
$GLOBALS['rexname'] = $rexname;
/**
* --------------------------------------------------------------------
*
* Redaxo Modul: DynTable
*
* Version: 1.3.1, 22.08.2011 // Hirbod Mirjavadi // info@nightstomp.com
*
*
* --------------------------------------------------------------------
* - Neu:
*
* - REX 4.3 lauffähig
* - short_open_tags entfernt
*
*/
/**
* -----------------------------------------------------------------------------
* Aktionen für das Modul setzen:
*
* ALLE EVENTS UND ALLE ACTIONS SETZEN, DAMIT ES BEI REDAXO 4.3 LÄUFT
*
*
*
* OPTIONEN:
*
* $maxSize:
* Maximal zulässige Breite "eines" Inputfeldes, wenn sich dieses über
* den zulässigen Bildschirmbereich erstrecken würde.
*
* $headline:
* Mögliche Tabellenüberschrift
*
* $colChooserAllowed:
* true:eingeschaltet; false:ausgeschaltet
* Anzeigeoption für Selectelement zur Einstellung der Tabellenspalten
*
* $maxColChooserValues:
* Maximal einstellbare Anzahl an Spalten
*
* $colChooserInfo:
* true: einschalten; false: ausschalten
* Einschalten des Infotextes wie die Spaltenzahl verändert wird.
*
* $maxCols:
* Ist aktiv, wenn $colChooserAllowed=false; ist !
* Voreinstellung der maximalen Anzahl an Spalten.
*
* $tableIdChooserAllowed:
* Schaltet das Inputfeld zur Eingabe der Tabel id ein / aus
* Für $tableIdChooserAllowed=false wird stets table id="dyntable" gesetzt !
* ------------------------------------------------------------------------------
*/
// OPTIONEN
$maxSize = 120;
$headline = '';
$colChooserAllowed = true;
$maxColChooserValues = 100;
$maxCols = 100;
$colChooserInfo = true;
$tableIdChooserAllowed = true;
$colChooserInfo=true;
if($maxColChooserValues<=1)
{
$colChooserAllowed = false;
$colChooserInfo=false;
}
if(!$colChooserAllowed) $rexname[1] = $maxCols;
if(!isset($rexname[1]) OR ($rexname[1]==''))
{
$rexname[1] = 1;
$sizeArr = array($maxSize);
} else {
$size = floor($maxSize / $rexname[1]);
for($i=0;$i<$rexname[1];$i++) $sizeArr[] = $size;
}
$tableID = (isset($rexname[3])&&($rexname[3]!=''))?$rexname[3]:'dyntable';
?>
<?php
$jsSizeArr = "new Array('".implode("','",$sizeArr)."')";
$script=<<<EOD
<script language="javascript">
function numRows(table_id) {
var rows = document.getElementById(table_id).getElementsByTagName('tr');
return rows.length;
}
function numCols(table_id) {
var cols = document.getElementById(table_id).getElementsByTagName('input');
return cols.length;
}
function createInput(pRow, pCellNum, psize )
{
var row_value = '';
var cell = pRow.insertCell(pCellNum);
var el = document.createElement('input');
el.setAttribute('type', 'text');
el.setAttribute('value', row_value);
el.setAttribute('name', '');
el.setAttribute('size', psize);
cell.appendChild(el);
}
function addRow(r, table_id){
if (!document.getElementById || !document.createElement || !document.createTextNode)
{
alert ("Ihr Browser unterst&tzt die Funktion leider nicht !"); return;
}
var rowIndex;
if(r)
rowIndex = r.parentNode.parentNode.rowIndex + 1;
else
rowIndex = numRows(table_id);
//alert(rowIndex);
var sizeArr = $jsSizeArr;
var table = document.getElementById(table_id);
var lastRow = numRows(table_id);
var rowNum = lastRow+1;
var lastCol = numCols(table_id);
var colCount = lastCol / lastRow;
if (navigator.platform == "MacPPC")
{
rowIndex = rowIndex * 2;
}
var row = table.insertRow(rowIndex);
for(var i=0;i<colCount;i++) createInput(row, i, sizeArr[i]);
createButtons(row, table_id);
setRowColHidden(rowNum, colCount);
updateRexname(table_id);
}
function setRowColHidden( rowNum, colCount )
{
document.getElementById('REX_FORM').elements['rexname[0]'].value = rowNum + ':' + colCount;
}
function createButtons(row, table_id)
{
var cell = row.insertCell(0);
cell.className = "tableImgs";
cell.innerHTML = '<a href="#row" onclick="addRow(this, \'' + table_id + '\')";><img src="./media/file_add.gif" /></a>' +
'<a href="#row" onclick="moveUp(this, \'' + table_id + '\')";><img src="./media/file_up.gif" /></a>' +
'<a href="#row" onclick="deleteRow(this, \'' + table_id + '\')";><img src="./media/file_del.gif" /></a>' +
'<a href="#row" onclick="moveDown(this, \'' + table_id + '\')";><img src="./media/file_down.gif" /></a>';
}
function moveUp(link, table_id){
var row = link.parentNode.parentNode;
if (0 == row.rowIndex) {
alert('Die erste Zeile kann nicht weiter nach oben verschoben werden!');
} else {
var prevRow = row.previousSibling;
row.parentNode.removeChild(row);
prevRow.parentNode.insertBefore(row, prevRow);
updateRexname(table_id);
}
}
function moveDown(link, table_id){
var row = link.parentNode.parentNode;
if (numRows(table_id) == row.rowIndex + 1) {
alert('Die letze Zeile kann nicht weiter nach unten verschoben werden!');
} else {
var nextRow = row.nextSibling;
row.parentNode.removeChild(nextRow);
row.parentNode.insertBefore(nextRow, row);
updateRexname(table_id);
}
}
function setCol(p)
{
var rowcol = document.getElementById('REX_FORM').elements['rexname[0]'].value;
var rowcol = document.getElementById('REX_FORM').elements['rexname[0]'].value;
var rowcolArr = rowcol.split(":");
document.getElementById('REX_FORM').elements['rexname[0]'].value = rowcolArr[0] + ':' + p;
}
function deleteRow(r, table_id)
{
var i;
if(r)
i = r.parentNode.parentNode.rowIndex;
else
i = numRows(table_id)-1;
if (i == 0) {
alert('Die erste Zeile kann nicht gelöscht werden');
} else {
document.getElementById(table_id).deleteRow(i);
var lastCol = numCols(table_id);
lastRow = numRows(table_id);
var colCount = lastCol / lastRow;
setRowColHidden( lastRow, colCount );
updateRexname(table_id);
}
}
function updateRexname(table_id)
{
var inputWert = document.getElementById(table_id).getElementsByTagName('input');
for (var k = 0; k < inputWert.length; k++)
{
inputWert[k].name = "rexname[" + (k+4) + "]";
}
}
function setHdl()
{
var hdlValue = document.getElementById('REX_FORM').elements['rexname[2]'].value;
if(hdlValue==1)
{
document.getElementById('REX_FORM').elements['rexname[2]'].value=0;
} else {
document.getElementById('REX_FORM').elements['rexname[2]'].value=1;
}
}
</script>
EOD;
// Script im Backend einfügen
if(!$REX['GG']) {
echo $script;
}
echo $headline;
/*
* -----------------------------------------------------------------------------
* Vorgabe der Tabellenkonstruktion mit 1 Zeile
* -----------------------------------------------------------------------------
*/
$rexname_col = (isset($rexname[1])&&($rexname[1]!=''))?$rexname[1]:1;
$table_id = 'tabelle';
$colChooser = true;
// Jetzt generieren wir die erste Spalte mit X Cols, falls noch keine zusätzlichen Spalten angelegt wurden
if( isset($rexname[0]) && ($rexname[0]==''))
{
$colChooser=true;
$rexname_rowcol = '1:'.$rexname[1];
$table = '<table id="'.$table_id.'">';
$table .= '<tr>';
$k=4;
for($i=0;$i<$rexname_col;$i++)
{
$rexname_value = isset($rexname[$k])?$rexname[$k]:'';
$table .= '<td><input type="text" name="rexname['.($k).']" value="'.$rexname_value.'" size="'.$sizeArr[$i].'" /></td>';
$k++;
}
$table .= '</tr>';
$table .= '</table>';
}
// stripslashes
$rexname[$k] = stripslashes($rexname[$k]);
// Ende
/*
* -----------------------------------------------------------------------------
* Jetzt werden die restlich angelegten Felder dynamisch generiert
* -----------------------------------------------------------------------------*/
if( isset($rexname[0])&& ereg(':',$rexname[0]) )
{
list($rows, $cols) = split(':',$rexname[0]);
$colChooser = ($rows==1)?true:false;
$rexname_rowcol = ( isset($rexname[0]) && ($rexname[0]!='') ) ? $rows.':'.$rexname_col : '1:'.$rexname_col;
$table = '<table id="'.$table_id.'">';
$k=4;
for($i=0;$i<$rows;$i++)
{
$table .= '<tr><td class="tableImgs">
<a href="#row" onclick="addRow(this, \''.$table_id.'\')";><img src="./media/file_add.gif" /></a>
<a href="#row" onclick="moveUp(this, \''.$table_id.'\')";><img src="./media/file_up.gif" /></a>
<a href="#row" onclick="deleteRow(this, \''.$table_id.'\')";><img src="./media/file_del.gif" /></a>
<a href="#row" onclick="moveDown(this, \''.$table_id.'\')";><img src="./media/file_down.gif" /></a>
</td> ';
for($j=0;$j<$cols;$j++)
{
// stripslashes
$rexname[$k] = stripslashes($rexname[$k]);
$rexname_value = (isset( $rexname[$k] ) ) ? $rexname[$k] : '';
$table .= '<td><input type="text" name="rexname['.$k.']" value="'.$rexname_value.'" size="'.$sizeArr[$j].'" /></td>';
$k++;
}
$table .= '</tr>';
}
$table .= '</table>';
}
echo $table;
?>
<input name="rexname[0]" type="hidden" value="<?php echo $rexname_rowcol; ?>" />
<input name="rexname[1]" type="hidden" value="<?php echo $rexname_col; ?>" />
<input name="rexname[2]" type="hidden" value="<?php echo $rexname[2]; ?>" />
<br />
<a name="row"></a>
<fieldset style="color:#ff0000">
<a href="#row" onClick="addRow(null, '<?php echo $table_id;?>')"><img src="./media/file_add.gif" /></a>
<a href="#row" onClick="deleteRow(null, '<?php echo $table_id;?>')"><img src="./media/file_del.gif" /></a><br />
</fieldset>
<br />
<div>
Spaltenanzahl:<br />
<select name="rexname[1]" onchange="setCol( this[selectedIndex].value ); document.getElementById('REX_FORM').update.value=1; submit();">
<?php
foreach( range(1,$maxColChooserValues) as $value) {
echo '<option value="'.$value.'"';
if ( $rexname[1]=="$value" ) {
echo 'selected="selected" ';
}
echo '>'.$value.'</option>';
}
?>
</select>
</div>
<br />
<div>
Zeile 1 als Tabellenüberschrift (th) auszeichen?
<div>
Ja <input type="radio" name="rexname[2]" value="1" <?php if ($rexname[2] == '1') echo 'checked'; ?> /> | Nein <input type="radio" name="rexname[2]" value="0" <?php if ($rexname[2] == '0') echo 'checked'; ?> />
</div>
</div>
<br />
<div>
noHover aktivieren? (nur wenn Zeile 1 Darstellungsprobleme beim Hovern hat)
<div>
Ja <input type="radio" name="VALUE[5]" value="1" <?php if ("REX_VALUE[5]" == '1') echo 'checked'; ?> /> | Nein <input type="radio" name="VALUE[5]" value="0" <?php if ("REX_VALUE[5]" == '0') echo 'checked'; ?> />
</div>
</div>
<br />
<?php if($tableIdChooserAllowed):?>
<fieldset>
<legend>
Der Tabelle eine Klasse vergeben (class=).<br />
Keine Eingabe = dyntable
</legend>
<input type="text" name="rexname[3]" value="<?php echo (isset($rexname[3])&&($rexname[3]!=''))?$rexname[3]:'dyntable';?>">
</fieldset>
<br />
<?php endif ;?>
<?php if($colChooserInfo) { ?>
<div>
Information<br />
- Textile-Formatierung kann in jeder Zelle angewandt werden.<br />
</div>
<?php } ?>
</table>
</table>
Modul Ausgabe
- Code: Alles auswählen
<?php
$rexname = explode("~~","REX_VALUE[1]");
$GLOBALS['rexname'] = $rexname;
$styleInfoVisible = true;
$table_id = ( isset($rexname[3]) && ($rexname[3]!='') )?$rexname[3]:'dyntable';
if( isset($rexname[0])&&(ereg(':',$rexname[0])) )
{
list($rows,$cols) = split(':', $rexname[0]);
$k=4;
$c=0;
if ("REX_VALUE[5]" == "1")
{
$activeNoHover = $this->getValue('article_id');
}
$tdStyleArr = array();
$thStyleArr = array();
$table = '<table class="'.$table_id.'">';
for($i=0;$i<$rows;$i++)
{
if ($i == 0 or $i == 1 && $this->getValue('article_id') != $activeNoHover)
{
$table .= '<tr class="noHover">';
} else {
$table .= '<tr>';
}
$tdi=1;
for($j=0;$j<$cols;$j++)
{
$c .= ($rexname[$k]!='')?1:0;
//$rexname[$k] = str_replace(""", "\"", $rexname[$k]);
$rexname[$k] = str_replace(""", '"', $rexname[$k]);
$rexname[$k] = str_replace("<", "<", $rexname[$k]);
$rexname[$k] = str_replace(">", ">", $rexname[$k]);
if (empty($rexname[$k]))
{
$rexname[$k] = " ";
}
$rexname[$k] = stripslashes($rexname[$k]);
// Inputfelder mit Textile formatieren
//(php-code nicht eingerückt, weil das sonst EOT-Fehler verursacht.)
$input =<<< EOT
$rexname[$k]
EOT;
$textile = new Textile;
if ("$rexname[$k]" != "")
$rexname[$k] = $textile->TextileThis($input);
$rexname[$k] = str_replace("###"," ",$rexname[$k]);
// die erste Zeile als Tabellenüberschrift
if( isset($rexname[2]) && ($rexname[2]==1) && ($i==0) ) {
$table .= '<th class="th'.$tdi.'">'.$rexname[$k].'</th>';
#$thStyleArr[] = '#dyntable .th'.$tdi;
$thStyleArr[] = '#'.$table_id.' .th'.$tdi;
$k++; $tdi++;
} else {
//$pos1 = stripos($rexname[$k], ".2008");
//echo $pos1;
//if ($pos1 != false) continue;
$table .= '<td class="td'.$tdi.'">'.$rexname[$k].'</td>';
#$tdStyleArr[] = '#dyntable .td'.$tdi;
$tdStyleArr[] = '#'.$table_id.' .td'.$tdi;
$k++; $tdi++;
}
}
$table .= '</tr>';
}
$table .= '</table>';
// Nur Backendformatierung
if(!$REX['REDAXO'])
{
echo <<<EOD
<style type="text/css">
$tableStyle
$thStyleStr
$tdStyleStr
</style>
EOD;
}
// Nur Backend
if(!$REX['REDAXO']) {
if($c>0) echo $table; else {
echo '<fieldset><legend>Info</legend>';
echo 'Sämtliche Tabellenzellen sind leer !';
echo '</fieldset>';
}
}
// Nur Frontend
if($REX['REDAXO']) {
if($c>0) echo '<!-- colsplit -->'.$table;
}
// StyleInfo: Nur Backend
if((!$REX['REDAXO'])&&($styleInfoVisible))
{
echo '<br /><br />';
$info = '<fieldset>';
$info .= '<legend>Styleangaben</legend>';
$info .= 'Die Anzeige der Styleangaben wird in der Backendausgabe dieses Moduls abgeschaltet durch: $styleInfoVisible = false;';
$info .= '<br /><br />';
$info .= '<b>Tabelle:</b><br />id="'.$table_id.'"<br />';
// CSS Tabellenüberschrift
if(count($thStyleArr)>0) {
$info .= '<br />';
$info .= '<b>Überschrift:</b>';
$info .= '<br />';
$tdi=1;
for($j=0; $j<$cols; $j++) {
$info .= $tdi.'.Spalte: class="th'.$tdi.'"' . '<br />'; $tdi++;
}
$info .= '<br /><b>Andere Zellen:</b><br />';
} else $info .= '<br /><b>Zellen:</b><br />';
// CSS andere Zellen
$tdi=1;
for($j=0; $j<$cols; $j++) {
$info .= $tdi.'.Spalte: class="td'.$tdi.'"' . '<br />'; $tdi++;
}
$info .= '</fieldset>';
}
}
unset($tdStyleArr);
unset($thStyleArr);
?>
rexname Aktion (bitte dem Modul "DynTable" dann hinzufügen)
- Preview-Action
- Presave-Action
- Postsave-Action
mit allen Events! Am besten unter jeder Textarea den "Haken" setzen (nur Rex 4.3.*)
- Code: Alles auswählen
<?php
$rexname = rex_request("rexname","array");
$newname = "";
for ( $c = 0; $c < 999; $c++ ) {
if (isset($rexname[$c])) { $newname .= $rexname[$c] . '~~'; }
else { $newname .= '~~'; }
}
if ( isset($REX_ACTION['VALUE'][1]) and $REX_ACTION['VALUE'][1] != '') {
$rexname = split('~~', $REX_ACTION['VALUE'][1]);
} else {
$REX_ACTION['VALUE'][1] = $newname;
}
?>
Letzter Hinweis: Die Rexname unterstützt maximal 999 Einträge. Dieser Wert kann vergrößert / verkleinert werden. Je größer der Wert, desto langsamer wird alles. Deswegen nur anpassen, wenn es notwendig ist. Eventuell sind sogar 999 schon zuviel - das muss jeder für sich selbst entscheiden. Geändert werden kann es in der "rexname Action" in der Zeile:
- Code: Alles auswählen
for ( $c = 0; $c < 999; $c++ ) {
Bekannte Probleme
Redaxo hat Standardmäßg "accesskeys" fürs Backend aktiviert. Im Ordner /redaxo/media/ liegt die Datei "standard.js". Diese hat eigentlich einen Ausschluss von Textarea, Input-Forms etc. Da DynTable im DOM die neuen Eingabefelder generiert, bekommt der "listener" davon nichts mit. Die Eingabe von "L" in einem Inputfeld führt z.B. zu einem Logout aus Redaxo.
Die beste Lösung wäre es, den Listener upzudaten, sobald ein neues Feld hinzugefügt wurde, da es jetzt aber schnell werden muss, folgendes:
Öffne die "standard.js" und scrolle komplett bis zum Ende; Zeile 669-677
Ersetze den unteren Teil mit:
- Code: Alles auswählen
$(function() {
$("input,button,textarea,select,option")
.focus(function(event) {
ENABLE_KEY_NAV = false;
})
.blur(function(event) {
ENABLE_KEY_NAV = false;
});
});
Das wars. Ich hab nur an die .blur generel ENABLE_KEY_NAV auf false gestellt.
Dadurch läuft es im DynTable gescheit, da der Listener nie ausm "focus" zurück kommt. Quick, auch ein bisschen Dirty, aber es sollte den Zweck erfüllen.
LG
Hirbod
Achtung: Der Code-Blog von Redaxo rückt nach dem Kopieren den Text ein. Simples Copy & Paste funktioniert wg EOT/EOD nicht. Vorher unbedingt den kompletten Code mit einem anständigen Editor makieren und nach links einziehen, damit die Leerzeichen entfernt werden!


