[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/etemplate/inc/ -> class.editor.inc.php (source)

   1  <?php
   2      /**************************************************************************\
   3      * eGroupWare - eTemplates - Editor                                         *
   4      * http://www.eGroupWare.org                                                *
   5      * Written by Ralf Becker <RalfBecker@outdoor-training.de>                  *
   6      * --------------------------------------------                             *
   7      *  This program is free software; you can redistribute it and/or modify it *
   8      *  under the terms of the GNU General Public License as published by the   *
   9      *  Free Software Foundation; either version 2 of the License, or (at your  *
  10      *  option) any later version.                                              *
  11      \**************************************************************************/
  12  
  13      /* $Id: class.editor.inc.php 20458 2006-03-07 23:47:59Z ralfbecker $ */
  14  
  15      /**
  16       * template editor of the eTemplate package
  17       *
  18       * @package etemplate
  19       * @subpackage tools
  20       * @author RalfBecker-AT-outdoor-training.de
  21       * @license GPL
  22       */
  23      class editor
  24      {
  25          var $debug;
  26          var $etemplate; // eTemplate we edit
  27          var $editor;    // editor eTemplate
  28          var $aligns = array(
  29              '' => 'Left',
  30              'right' => 'Right',
  31              'center' => 'Center',
  32          );
  33          var $valigns = array(
  34              '' => 'Middle',
  35              'top' => 'Top',
  36              'bottom' => 'Bottom',
  37              'baseline' => 'Baseline',
  38          );
  39          var $edit_menu = array(
  40              'delete' => 'delete',
  41              'cut' => 'cut',
  42              'copy' => 'copy',
  43              'paste' => 'paste',
  44              'swap' => 'swap',
  45          );
  46          var $row_menu = array(
  47              'row_delete' => 'delete this row',
  48              'row_insert_above' => 'insert a row above',
  49              'row_insert_below' => 'insert a row below',
  50              'row_swap_next' => 'swap with next row',
  51          );
  52          var $column_menu = array(
  53              'column_delete' => 'delete this column',
  54              'column_insert_before' => 'insert a column before',
  55              'column_insert_behind' => 'insert a column behind',
  56              'column_swap_next' => 'swap with next column',
  57          );
  58          var $box_menu = array(
  59              'box_insert_before' => 'insert a widget before',
  60              'box_insert_behind' => 'insert a widget behind',
  61              'box_swap_next' => 'swap widget with next one',
  62          );
  63          var $options = array(
  64              'width',
  65              'height',
  66              'border',
  67              'class',
  68              'spacing',
  69              'padding',
  70              'overflow'
  71          );
  72          var $overflows = array(
  73              '' => 'visible',
  74              'hidden' => 'hidden',
  75              'scroll' => 'scroll',
  76              'auto' => 'auto'
  77          );
  78          var $onclick_types = array(
  79              ''        => 'nothing',
  80              'confirm' => 'confirm',
  81              'popup'   => 'popup',
  82              'custom'  => 'custom',
  83          );
  84          var $onchange_types = array(
  85              ''        => 'nothing',
  86              'submit'  => 'submit form',
  87              'custom'  => 'custom',
  88          );
  89          var $extensions = '';
  90  
  91          var $public_functions = array
  92          (
  93              'edit'         => True,
  94              'widget'       => True,
  95              'styles'       => True,
  96          );
  97  
  98  		function editor()
  99          {
 100              $this->etemplate =& CreateObject('etemplate.etemplate');
 101  
 102              $this->extensions = $GLOBALS['egw']->session->appsession('extensions','etemplate');
 103          }
 104  
 105  		function export_xml(&$xml,&$xml_label)
 106          {
 107              $name = $this->etemplate->name;
 108              $template = $this->etemplate->template != '' ? $this->etemplate->template : 'default';
 109  
 110              list($app) = explode('.',$name);
 111  
 112              if (!is_object($this->etemplate->xul_io))
 113              {
 114                  $this->etemplate->xul_io =& CreateObject('etemplate.xul_io');
 115              }
 116              $xml = $this->etemplate->xul_io->export($this->etemplate);
 117  
 118              $dir = EGW_SERVER_ROOT . "/$app/templates/$template";
 119              if (($create_it = !is_dir($dir)))
 120              {
 121                  $dir = EGW_SERVER_ROOT . "/$app/templates";
 122              }
 123              if (!is_writeable($dir))
 124              {
 125                  return lang("Error: webserver is not allowed to write into '%1' !!!",$dir);
 126              }
 127              if ($create_it)
 128              {
 129                  mkdir($dir .= "/$template");
 130              }
 131              $file = $dir . '/' . substr($name,strlen($app)+1);
 132              if ($this->etemplate->lang)
 133              {
 134                  $file .= '.' . $this->etemplate->lang;
 135              }
 136              $old_file = $file . '.old.xet';
 137              $file .= '.xet';
 138              if (file_exists($file))
 139              {
 140                  if (file_exists($old_file))
 141                  {
 142                      unlink($old_file);
 143                  }
 144                  rename($file,$old_file);
 145              }
 146  
 147              if (!($f = fopen($xml_label=$file,'w')))
 148              {
 149                  return 0;
 150              }
 151              if (!is_object($this->etemplate->xul_io))
 152              {
 153                  $this->etemplate->xul_io =& CreateObject('etemplate.xul_io');
 154              }
 155              $xml = $this->etemplate->xul_io->export($this->etemplate);
 156  
 157              fwrite($f,$xml);
 158              fclose($f);
 159  
 160              return lang("eTemplate '%1' written to '%2'",$name,$file);
 161          }
 162  
 163  		function import_xml($file,&$xml)
 164          {
 165              if ($file == 'none' || $file == '' || !($f = fopen($file,'r')))
 166              {
 167                  return lang('no filename given or selected via Browse...')."file='$file'";
 168              }
 169              $xml = fread ($f, filesize ($file));
 170              fclose($f);
 171  
 172              if (!is_object($this->etemplate->xul_io))
 173              {
 174                  $this->etemplate->xul_io =& CreateObject('etemplate.xul_io');
 175              }
 176              $imported = $this->etemplate->xul_io->import($this->etemplate,$xml);
 177              $this->etemplate->modified = @filemtime($f);
 178              $this->etemplate->modified_set = 'xul-import';
 179  
 180              if (is_array($imported))
 181              {
 182                  if (count($imported) == 1)
 183                  {
 184                      $imported = lang("eTemplate '%1' imported, use Save to put it in the database",$this->etemplate->name);
 185                  }
 186                  else
 187                  {
 188                      $imported = lang('File contains more than one eTemplate, last one is shown !!!');
 189                  }
 190              }
 191              return $imported;
 192          }
 193  
 194  		function list_result($cont='',$msg='')
 195          {
 196              if ($this->debug)
 197              {
 198                  echo "<p>etemplate.editor.list_result: cont="; _debug_array($cont);
 199              }
 200              if (!$cont || !is_array($cont))
 201              {
 202                  return $this->edit('error');
 203              }
 204              if (!isset($cont['result']) || isset($cont['search']))
 205              {
 206                  $cont['result'] = $this->etemplate->search($cont);
 207              }
 208              $result = $cont['result'];
 209  
 210              if (isset($cont['delete']))
 211              {
 212                  list($delete) = each($cont['delete']);
 213                  $this->etemplate->init($result[$delete-1]);
 214                  if ($this->etemplate->delete())
 215                  {
 216                      $msg = lang('Template deleted');
 217                      unset($result[$delete-1]);
 218                      $result = array_values($result);
 219                  }
 220                  else
 221                  {
 222                      $msg = lang('Error: Template not found !!!');
 223                  }
 224              }
 225              if (isset($cont['delete_selected']))
 226              {
 227                  foreach($cont['selected'] as $row => $sel)
 228                  {
 229                      if ($sel)
 230                      {
 231                          $this->etemplate->init($result[$row-1]);
 232                          if ($this->etemplate->delete())
 233                          {
 234                              unset($result[$row-1]);
 235                              ++$n;
 236                          }
 237                      }
 238                  }
 239                  if ($n)
 240                  {
 241                      $msg = lang('%1 eTemplates deleted',$n);
 242                  }
 243                  unset($cont['selected']);
 244                  unset($cont['delete_selected']);
 245                  $result = array_values($result);
 246              }
 247              if (isset($cont['read']))
 248              {
 249                  list($read) = each($cont['read']);
 250                  $this->etemplate->read($result[$read-1]);
 251                  $this->edit();
 252                  return;
 253              }
 254              if (!$msg)
 255              {
 256                  $msg = lang('%1 eTemplates found',count($result));
 257              }
 258              unset($cont['result']);
 259              if (!isset($cont['name']))
 260              {
 261                  $cont += $this->etemplate->as_array();
 262              }
 263              $content = $cont + array('msg' => $msg);
 264  
 265              reset($result);
 266              for ($row=1; list(,$param) = each($result); ++$row)
 267              {
 268                  $content[$row] = $param;
 269              }
 270              $list_result =& new etemplate('etemplate.editor.list_result');
 271              $GLOBALS['egw_info']['flags']['app_header'] = lang('Editable Templates - Search');
 272              $list_result->exec('etemplate.editor.list_result',$content,'','',array(
 273                  'result' => $result,
 274              ),'');
 275          }
 276  
 277          /**
 278           * new eTemplate editor, which edits widgets in a popup
 279           *
 280           * @param array $content content from the process_exec call
 281           * @param string $msg message to show
 282           */
 283  		function edit($content=null,$msg = '')
 284          {
 285              if ($this->debug)
 286              {
 287                  echo "<p>etemplate.editor.show: content="; _debug_array($content);
 288              }
 289              if (!is_array($content)) $content = array();
 290              $preserv = array();
 291  
 292              if ($content['import_xml'])
 293              {
 294                  $msg .= $this->import_xml($content['file']['tmp_name'],$xml);
 295                  //$this->etemplate->echo_tmpl();
 296                  $xml_label = $content['file']['name'];
 297                  $preserv['import'] = $this->etemplate->as_array(1);
 298              }
 299              elseif (is_array($content['import']) && !$content['read'])    // imported not yet saved tmpl
 300              {
 301                  $this->etemplate->init($content['import']);
 302                  $preserv['import'] = $content['import'];
 303              }
 304              if ($content['save'])
 305              {
 306                  if (!is_array($content['import'])) $this->etemplate->read($content['old_keys']);
 307  
 308                  if (!$this->etemplate->modified_set || !$this->etemplate->modified)
 309                  {
 310                      $this->etemplate->modified = time();
 311                  }
 312                  $ok = $this->etemplate->save(trim($content['name']),trim($content['template']),trim($content['lang']),(int) $content['group'],trim($content['version']));
 313                  $msg = $ok ? lang('Template saved') : lang('Error: while saving !!!');
 314                  if ($ok) unset($preserv['import']);
 315              }
 316              elseif (isset($_GET['name']) || isset($content['name']))
 317              {
 318                  if ($_GET['name'])
 319                  {
 320                      foreach($this->etemplate->db_key_cols as $var)
 321                      {
 322                          $content[$var] = $_GET[$var];
 323                      }
 324                  }
 325                  if ($content['version'] != '')
 326                  {
 327                      $save_version = $content['version'];
 328                      unset($content['version']);
 329                      $this->etemplate->read($content);
 330                      $newest_version = $this->etemplate->version;
 331                      $content['version'] = $save_version;
 332                  }
 333                  if (!$this->etemplate->read($content))
 334                  {
 335                      if (isset($content['name']))
 336                      {
 337                          $version_backup = $content['version'];
 338                          $content['version'] = '';    // trying it without version
 339                          if ($this->etemplate->read($content))
 340                          {
 341                              $msg = lang('only an other Version found !!!');
 342                          }
 343                          else
 344                          {
 345                              $result = $this->etemplate->search($content);
 346                              if (count($result) > 1)
 347                              {
 348                                  return $this->list_result(array('result' => $result));
 349                              }
 350                              elseif (!count($result) || !$this->etemplate->read($result[0]))
 351                              {
 352                                  $msg = lang('Error: Template not found !!!');
 353                                  $this->etemplate->version = $content['version'] = $version_backup;
 354                              }
 355                              elseif ($content['name'] == $result[0]['name'])
 356                              {
 357                                  $msg = lang('only an other Version found !!!');
 358                              }
 359                          }
 360                      }
 361                      else
 362                      {
 363                          $msg = lang('Error: Template not found !!!');
 364                      }
 365                  }
 366                  elseif ($newest_version != '' && $this->etemplate->version != $newest_version)
 367                  {
 368                      $link = $this->etemplate->as_array(-1);
 369                      $link['menuaction'] = 'etemplate.editor.edit';
 370                      $link['version'] = $newest_version;
 371                      $msg = lang("newer version '%1' exists !!!",$this->etemplate->html->a_href($newest_version,$link));
 372                  }
 373              }
 374              if (!is_array($this->extensions))
 375              {
 376                  if (($extensions = $this->scan_for_extensions()))
 377                  {
 378                      $msg .= lang('Extensions loaded:') . ' ' . $extensions;
 379                      $msg_ext_loaded = True;
 380                  }
 381              }
 382              list($app) = explode('.',$this->etemplate->name);
 383              if ($app && $app != 'etemplate')
 384              {
 385                  $GLOBALS['egw']->translation->add_app($app);    // load translations for app
 386  
 387                  if (($extensions = $this->scan_for_extensions($app)))
 388                  {
 389                      $msg .= (!$msg_ext_loaded?lang('Extensions loaded:').' ':', ') . $extensions;
 390                  }
 391              }
 392              if (!$msg && $content['delete'])
 393              {
 394                  if (!$content['version'] && $this->etemplate->version)
 395                  {
 396                      $this->etemplate->version = '';    // else the newest would get deleted and not the one without version
 397                  }
 398                  $ok = $this->etemplate->delete();
 399                  $msg = $ok ? lang('Template deleted') : lang('Error: Template not found !!!');
 400                  $preserv['import'] = $this->etemplate->as_array(1);    // that way the content can be saved again
 401              }
 402              elseif ($content['dump'])
 403              {
 404                  if (empty($app) || !@is_dir(EGW_SERVER_ROOT.'/'.$app))
 405                  {
 406                      $msg .= lang('Application name needed to write a langfile or dump the eTemplates !!!');
 407                  }
 408                  else
 409                  {
 410                      $msg .= $this->etemplate->dump4setup($app);
 411                  }
 412              }
 413              elseif ($content['langfile'])
 414              {
 415                  if (empty($app) || !@is_dir(EGW_SERVER_ROOT.'/'.$app))
 416                  {
 417                      $msg = lang('Application name needed to write a langfile or dump the eTemplates !!!');
 418                  }
 419                  else
 420                  {
 421                      $additional = array();
 422                      if ($app == 'etemplate')
 423                      {
 424                          $additional = $this->etemplate->types + $this->extensions + $this->aligns + $this->valigns +
 425                              $this->edit_menu + $this->box_menu + $this->row_menu + $this->column_menu + $this->onclick_types + $this->onchange_types;
 426                      }
 427                      else    // try to call the writeLangFile function of the app's ui-layer
 428                      {
 429                          foreach(array('ui'.$name,'ui',$name,'bo'.$name) as $class)
 430                          {
 431                              if (file_exists(EGW_INCLUDE_ROOT.'/'.$name.'/inc/class.'.$class.'.inc.php') &&
 432                                  ($ui =& CreateObject($name.'.'.$class)) && is_object($ui))
 433                              {
 434                                  break;
 435                              }
 436                          }
 437                          if (is_object($ui) && @$ui->public_functions['writeLangFile'])
 438                          {
 439                              $msg = "$class::writeLangFile: ".$ui->writeLangFile();
 440                          }
 441                          unset($ui);
 442                      }
 443                      //if (empty($msg))
 444                      {
 445                          $msg = $this->etemplate->writeLangFile($app,'en',$additional);
 446                      }
 447                  }
 448              }
 449              elseif ($content['export_xml'])
 450              {
 451                  $msg .= $this->export_xml($xml,$xml_label);
 452              }
 453              $new_content = $this->etemplate->as_array() + array(
 454                  'msg' => $msg,
 455                  'xml_label' => $xml_label,
 456                  'xml' => $xml ? '<pre>'.$this->etemplate->html->htmlspecialchars($xml)."</pre>\n" : '',
 457              );
 458  
 459              $editor =& new etemplate('etemplate.editor.new');
 460              if (!$msg && isset($content['values']) && !isset($content['vals']))
 461              {
 462                  $r = 1;
 463                  foreach((array)$content['cont'] as $key => $val)
 464                  {
 465                      $vals["@$r"] = $key;
 466                      $vals["A$r"] = is_array($val) ? htmlspecialchars(serialize($val)).'#SeR#' : $val;
 467                      ++$r;
 468                  }
 469                  $editor->data[$editor->rows]['A']['name'] = 'etemplate.editor.values';
 470                  $editor->data[$editor->rows]['A']['size'] = 'vals';
 471                  $new_content['vals'] = $vals;
 472              }
 473              else
 474              {
 475                  // set onclick handler
 476                  $this->etemplate->onclick_handler = "edit_widget('%p');";
 477                  // setting the javascript via the content, allows looping too
 478                  $new_content['onclick'] = '
 479                  <script language="javascript">
 480  					function edit_widget(path)
 481                      {
 482                          var url = "'.$GLOBALS['egw']->link('/index.php',$this->etemplate->as_array(-1)+array(
 483                              'menuaction' => 'etemplate.editor.widget',
 484                          )).'";
 485                          url = url.replace(/index.php\\?/,"index.php?path="+path+"&");
 486                          window.open(url,"etemplate_editor_widget","dependent=yes,width=640,height=480,location=no,menubar=no,toolbar=no,scrollbars=yes,status=yes");
 487                      }
 488                  </script>';
 489                  if ($app != 'etemplate' && file_exists(EGW_SERVER_ROOT.'/'.$app.'/templates/default/app.css'))
 490                  {
 491                      $new_content['onclick'] .= $editor->html->style('@import url('.$GLOBALS['egw_info']['server']['webserver_url'].'/'.$app.'/templates/default/app.css);');
 492                  }
 493                  $editor->data[$editor->rows]['A']['obj'] = &$this->etemplate;
 494                  $vals = $content['vals'];
 495                  $olds = $content['olds'];
 496  
 497                  for ($r = 1; isset($vals["A$r"]); ++$r)
 498                  {
 499                      $new_content['cont'][$olds["@$r"]] = substr($vals["A$r"],-5)=='#SeR#' ?
 500                          unserialize(substr($vals["A$r"],0,-5)) : $vals["A$r"];
 501                  }
 502              }
 503              $preserv['olds'] = $vals;
 504              $preserv['old_keys'] = $this->etemplate->as_array(-1);    // in case we do a save as
 505  
 506              $GLOBALS['egw_info']['flags']['app_header'] = lang('Editable Templates - Show Template');
 507              $editor->exec('etemplate.editor.edit',$new_content,array(),'',$preserv,0,'/^cont/');
 508          }
 509  
 510          /**
 511           * initialises the children arrays for the new widget type, converts boxes <--> grids
 512           *
 513           * @internal 
 514           * @param array &$widget reference to the new widget data
 515           * @param array $old the old widget data
 516           */
 517  		function change_widget_type(&$widget,$old)
 518          {
 519              //echo "<p>editor::change_widget_type($widget[type]=$old[type])</p>\n";
 520              $old_type = $old['type'];
 521              $old_had_children = isset($this->etemplate->widgets_with_children[$old_type]);
 522  
 523              if (!isset($this->etemplate->widgets_with_children[$widget['type']]) ||
 524                  ($old_type == 'grid') == ($widget['type'] == 'grid'))
 525              {
 526                  if ($this->etemplate->widgets_with_children[$widget['type']] == 'box')    // box
 527                  {
 528                      if ((int) $widget['size'] < 1)    // min. 1 child
 529                      {
 530                          list(,$options) = explode(',',$widget['size'],2);
 531                          $widget['size'] = '1'.($options ? ','.$options : '');
 532                      }
 533                      // create the needed cells, if they dont exist
 534                      for ($n = 1; $n <= (int) $widget['size']; ++$n)
 535                      {
 536                          if (!is_array($widget[$n])) $widget[$n] = $n == 1 ? $old : soetemplate::empty_cell();
 537                      }
 538                      unset($widget['onclick']);    // not valid for a box
 539                  }
 540                  return; // no change necessary, eg. between different box-types
 541              }
 542              switch ($this->etemplate->widgets_with_children[$widget['type']])
 543              {
 544                  case 'grid':
 545                      $widget['data'] = array(array());
 546                      $widget['cols'] = $widget['rows'] = 0;
 547      
 548                      if ($old_had_children)    // box --> grid: hbox --> 1 row, other boxes --> 1 column
 549                      {
 550                          list($num) = explode(',',$old['size']);
 551                          for ($n = 1; is_array($old[$n]) && $n <= $num; ++$n)
 552                          {
 553                              $new_line = null;
 554                              if ($old_type != 'hbox') soetemplate::add_child($widget,$new_line);
 555                              soetemplate::add_child($widget,$old[$n]);
 556                              unset($widget[$n]);
 557                          }
 558                          $widget['size'] = '';
 559                      }
 560                      else    // 1 row with 1 column/child
 561                      {
 562                          soetemplate::add_child($widget,soetemplate::empty_cell());
 563                      }
 564                      break;
 565  
 566                  case 'box':
 567                      $widget['size'] = 0;
 568                      
 569                      if ($old_type == 'grid')
 570                      {
 571                          if (preg_match('/,(vertical|horizontal)/',$widget['size'],$matches))
 572                          {
 573                              $orient = $matches[1];
 574                          }
 575                          else
 576                          {
 577                              $orient = $widget['type'] == 'hbox' ? 'horizontal' : 'vertical';
 578                          }
 579                          if ($orient == 'horizontal')    // ==> use first row
 580                          {
 581                              $row =& $old['data'][1];
 582                              for ($n = 0; $n < $old['cols']; ++$n)
 583                              {
 584                                  $cell =& $row[soetemplate::num2chrs($n)];
 585                                  soetemplate::add_child($widget,$cell);
 586                                  list($span) = (int)explode(',',$cell['span']);
 587                                  if ($span == 'all') break;
 588                                  while ($span-- > 1) ++$n;
 589                              }
 590                          }
 591                          else    // vertical ==> use 1 column
 592                          {
 593                              for ($n = 1; $n <= $old['rows']; ++$n)
 594                              {
 595                                  soetemplate::add_child($widget,$old['data'][$n][soetemplate::num2chrs(0)]);
 596                              }
 597                          }
 598                      }
 599                      if (!$widget['size']) // minimum one child
 600                      {
 601                          soetemplate::add_child($widget,soetemplate::empty_cell());
 602                      }
 603                      break;
 604              }
 605              //_debug_array($widget);
 606          }
 607          
 608          /**
 609           * returns array with path => type pairs for each parent of $path
 610           *
 611           * @param string $path path to the widget not the parent!
 612           * @return array 
 613           */
 614  		function path_components($path)
 615          {
 616              $path_parts = explode('/',$path);
 617              array_pop($path_parts);        // removed the widget itself
 618              array_shift($path_parts);    // removed the leading empty string
 619  
 620              $components = array();
 621              $part_path = '';
 622              foreach($path_parts as $part)
 623              {
 624                  $part_path .= '/'.$part;
 625                  $parent =& $this->etemplate->get_widget_by_path($part_path);
 626                  $components[$part_path] = $parent['type'];
 627              }
 628              return $components;
 629          }
 630  
 631          /**
 632           * returns array with path => type pairs for each parent of $path
 633           *
 634           * @param array $parent the parent
 635           * @param string $child_id id of child
 636           * @param string $parent_path path of the parent
 637           * @return array with keys left, right, up and down and their pathes set (if applicable)
 638           */
 639  		function parent_navigation($parent,$parent_path,$child_id,$widget)
 640          {
 641              if ($parent['type'] == 'grid' && preg_match('/^([0-9]+)([A-Z]+)$/',$child_id,$matches))
 642              {
 643                  list(,$r,$c) = $matches;
 644                  // find the column-number (base 0) for $c (A, B, C, ...)
 645                  for($col = 0; soetemplate::num2chrs($col) != $c && $col < 100; ++$col) ;
 646                  
 647                  if ($col > 0) $left = $parent_path.'/'.$r.soetemplate::num2chrs($col-1);
 648                  
 649                  if ($col < $parent['cols']-1) $right = $parent_path.'/'.$r.soetemplate::num2chrs($col+1);
 650                  
 651                  if ($r > 1) $up = $parent_path.'/'.($r-1).$c;
 652                  
 653                  if ($r < $parent['rows']) $down = $parent_path.'/'.($r+1).$c;
 654              }
 655              elseif ($parent['type']) // any box
 656              {
 657                  if ($child_id > 1) $previous = $parent_path.'/'.($child_id-1);
 658                  
 659                  if ($child_id < (int) $parent['size'])  $next = $parent_path.'/'.($child_id+1);
 660              }
 661              else // template
 662              {
 663                  if ($child_id > 0) $previous = '/'.($child_id-1);
 664                  
 665                  if ($child_id < count($this->etemplate->children)-1)  $next = '/'.($child_id+1);
 666              }
 667              if ($widget['type'] == 'grid')
 668              {
 669                  $in = $parent_path.'/'.$child_id.'/1A';
 670              }
 671              elseif (isset($this->etemplate->widgets_with_children[$widget['type']]) && $widget['type'] != 'template')
 672              {
 673                  if ($widget['type'])    // box
 674                  {
 675                      $in = $parent_path.'/'.$child_id.'/1';
 676                  }
 677                  else
 678                  {
 679                      $in = '/0';
 680                  }
 681              }
 682              $navi = array();
 683              foreach(array('left'=>'&larr;','up'=>'&nbsp;&uarr;&nbsp;','down'=>'&nbsp;&darr;&nbsp;',
 684                  'right'=>'&rarr;','previous'=>'&larr;&uarr;','next'=>'&darr;&rarr;','in'=>'&times;') as $var => $dir)
 685              {
 686                  if ($$var) $navi[$$var] = $dir;
 687              }
 688              return $navi;
 689          }
 690  
 691          /**
 692           * functions of the edit-menu: paste, swap, cut, delete, copy
 693           *
 694           * @internal 
 695           * @param string &$action row_delete, row_insert_above, row_insert_below, row_swap, row_prefs
 696           * @param array &$parent referece to the parent
 697           * @param array &$content reference to the content-array
 698           * @param string $child_id id of a cell
 699           * @return string msg to display
 700           */
 701  		function edit_actions(&$action,&$parent,&$content,$child_id)
 702          {
 703              switch ($action)
 704              {
 705                  case 'paste':
 706                  case 'swap':
 707                      $clipboard = $GLOBALS['egw']->session->appsession('clipboard','etemplate');
 708                      if (!is_array($clipboard))
 709                      {
 710                          return lang('nothing in clipboard to paste !!!');
 711                      }
 712                      if ($action == 'swap')
 713                      {
 714                          $GLOBALS['egw']->session->appsession('clipboard','etemplate',$content['cell']);
 715                      }
 716                      $content['cell'] = $clipboard;
 717                      break;
 718  
 719                  case 'copy':
 720                  case 'cut':
 721                      $GLOBALS['egw']->session->appsession('clipboard','etemplate',$content['cell']);
 722                      if ($action != 'cut')
 723                      {
 724                          return lang('widget copied into clipboard');
 725                      }
 726                      // fall-through
 727                  case 'delete':
 728                      if ($parent['type'] != 'grid')
 729                      {
 730                          // delete widget from parent
 731                          if ($parent['type'])    // box
 732                          {
 733                              list($num,$options) = explode(',',$parent['size'],2);
 734                              if ($num <= 1)    // cant delete last child --> only empty it
 735                              {
 736                                  $parent[$num=1] = soetemplate::empty_cell();
 737                              }
 738                              else
 739                              {
 740                                  for($n = $child_id; $n < $num; ++$n)
 741                                  {
 742                                      $parent[$n] = $parent[1+$n];
 743                                  }
 744                                  unset($parent[$num--]);
 745                              }
 746                              $parent['size'] = $num . ($options ? ','.$options : '');
 747                          }
 748                          else    // template itself
 749                          {
 750                              if (count($this->etemplate->children) <= 1)    // cant delete last child
 751                              {
 752                                  $this->etemplate->children[0] = soetemplate::empty_cell();
 753                              }
 754                              else
 755                              {
 756                                  unset($parent[$child_id]);
 757                                  $this->etemplate->children = array_values($this->etemplate->children);
 758                              }
 759                          }
 760                          $action = 'save-no-merge';
 761                      }
 762                      else
 763                      {
 764                          $content['cell'] = soetemplate::empty_cell();
 765                          return lang('cant delete a single widget from a grid !!!');
 766                      }
 767                      break;
 768              }
 769              return '';
 770          }
 771  
 772          /**
 773           * functions of the box-menu: insert-before, -behind und swap
 774           *
 775           * @internal 
 776           * @param string &$action row_delete, row_insert_above, row_insert_below, row_swap, row_prefs
 777           * @param array &$parent referece to the parent
 778           * @param array &$content reference to the content-array
 779           * @param string &$child_id id of a cell, may change to the next cell if inserting behind
 780           * @param string $parent_path path of parent
 781           * @return string msg to display
 782           */
 783  		function box_actions(&$action,&$parent,&$content,&$child_id,$parent_path)
 784          {
 785              switch ($action)
 786              {
 787                  case 'box_insert_before':
 788                  case 'box_insert_behind':
 789                      $n = $child_id + (int)($action == 'box_insert_behind');
 790                      if (!$parent['type'])    // template
 791                      {
 792                          $num = count($parent)-1;    // 0..count()-1
 793                      }
 794                      else // boxes
 795                      {
 796                          list($num,$options) = explode(',',$parent['size'],2);
 797                      }
 798                      for($i = $num; $i >= $n; --$i)
 799                      {
 800                          $parent[1+$i] = $parent[$i];
 801                      }
 802                      $parent[$n] = $content['cell'] = soetemplate::empty_cell();
 803                      $child_id = $n;
 804                      if ($parent['type']) $parent['size'] = (1+$num) . ($options ? ','.$options : '');
 805                      break;
 806                      
 807                  case 'box_swap_next':
 808                      if (!$parent['type'])    // template
 809                      {
 810                          $num = count($parent)-1;    // 0..count()-1
 811                      }
 812                      else // boxes
 813                      {
 814                          list($num) = explode(',',$parent['size'],2);
 815                      }
 816                      if ($child_id == $num)    // if on last cell, swap with the one before
 817                      {
 818                          $this->swap($parent[$child_id],$parent[$child_id-1]);
 819                          --$child_id;
 820                      }
 821                      else
 822                      {
 823                          $this->swap($parent[$child_id],$parent[$child_id+1]);
 824                          ++$child_id;
 825                      }
 826                      break;
 827              }
 828              $action = 'apply-no-merge';
 829  
 830              return '';
 831          }
 832                          
 833          /**
 834           * functions of the row-menu: insert, deleting & swaping of rows
 835           *
 836           * @internal 
 837           * @param string &$action row_delete, row_insert_above, row_insert_below, row_swap_next, row_prefs
 838           * @param array &$grid grid
 839           * @param string $child_id id of a cell
 840           * @return string msg to display
 841           */
 842  		function row_actions(&$action,&$grid,$child_id)
 843          {
 844              $data =& $grid['data'];
 845              $rows =& $grid['rows'];
 846              $cols =& $grid['cols'];
 847              $opts =& $data[0];
 848  
 849              if (preg_match('/^([0-9]+)([A-Z]+)$/',$child_id,$matches)) list(,$r,$c) = $matches;
 850  
 851              if (!$c || !$r || $r > $rows) return "wrong child_id='$child_id' => r='$r', c='$c'";
 852  
 853              switch($action)
 854              {
 855                  case 'row_swap_next':
 856                      if ($r > $rows-1)
 857                      {
 858                          if ($r != $rows) return lang('no row to swap with !!!');
 859                          --$r;    // in last row swap with row above
 860                      }
 861                      $this->swap($data[$r],$data[1+$r]);
 862                      $this->swap($opts['c'.$r],$opts['c'.(1+$r)]);
 863                      $this->swap($opts['h'.$r],$opts['h'.(1+$r)]);
 864                      break;
 865                      
 866                  case 'row_delete':
 867                      if ($rows <= 1)    // one row only => delete whole grid
 868                      {
 869                          return lang('cant delete the only row in a grid !!!');
 870                          // todo: delete whole grid instead
 871                      }
 872                      for($i = $r; $i < $rows; ++$i)
 873                      {
 874                          $opts['c'.$i] = $opts['c'.(1+$i)]; 
 875                          $opts['h'.$i] = $opts['h'.(1+$i)]; 
 876                          $data[$i] = $data[1+$i];
 877                      }
 878                      unset($opts['c'.$rows]);
 879                      unset($opts['h'.$rows]);
 880                      unset($data[$rows--]);
 881                      break;
 882                      
 883                  case 'row_insert_above':
 884                      --$r;
 885                      // fall-through
 886                  case 'row_insert_below':
 887                      //echo "row_insert_below($r) rows=$rows, cols=$cols"; _debug_array($grid);
 888                      // move height + class options of rows
 889                      for($i = $rows; $i > $r; --$i)
 890                      {
 891                          echo ($i+1)."=$i<br>\n";
 892                          $data[1+$i] = $data[$i]; 
 893                          $opts['c'.(1+$i)] = $opts['c'.$i]; 
 894                          $opts['h'.(1+$i)] = $opts['h'.$i]; 
 895                      }
 896                      for($i = 0; $i < $cols; ++$i)
 897                      {
 898                          echo (1+$r).":$i=".soetemplate::num2chrs($i)."=empty_cell()<br>\n";
 899                          $data[1+$r][soetemplate::num2chrs($i)] = soetemplate::empty_cell();
 900                      }
 901                      $opts['c'.(1+$r)] = $opts['h'.(1+$r)] = '';
 902                      ++$rows;
 903                      //_debug_array($grid); return '';
 904                      break;
 905              }
 906              $action = 'save-no-merge';
 907  
 908              return '';
 909          }
 910  
 911          /**
 912           * functions of the column-menu: insert, deleting & swaping of columns
 913           *
 914           * @internal 
 915           * @param string &$action column_delete, column_insert_before, column_insert_behind, column_swap_next, column_prefs
 916           * @param array &$grid grid
 917           * @param string $child_id id of a cell
 918           * @return string msg to display
 919           */
 920  		function column_actions(&$action,&$grid,$child_id)
 921          {
 922              $data =& $grid['data'];
 923              $rows =& $grid['rows'];
 924              $cols =& $grid['cols'];
 925              $opts =& $data[0];
 926              
 927              if (preg_match('/^([0-9]+)([A-Z]+)$/',$child_id,$matches)) list(,$r,$c) = $matches;
 928              // find the column-number (base 0) for $c (A, B, C, ...)
 929              for($col = 0; soetemplate::num2chrs($col) != $c && $col < 100; ++$col) ;
 930  
 931              if (!$c || !$r || $r > $rows || $col >= $cols) return "wrong child_id='$child_id' => r='$r', c='$c', col=$col";
 932  
 933              switch($action)
 934              {
 935                  case 'column_swap_next':
 936                      if ($col >= $cols-1)
 937                      {
 938                          if ($col != $cols-1) return lang('no column to swap with !!!');
 939                          $c = soetemplate::num2chrs(--$col); // in last column swap with the one before
 940                      }
 941                      $c_next = soetemplate::num2chrs(1+$col);
 942                      for($row = 1; $row <= $rows; ++$row)
 943                      {
 944                          $this->swap($data[$row][$c],$data[$row][$c_next]);
 945                      }
 946                      $this->swap($opts[$c],$opts[$c_next]);
 947                      //_debug_array($grid); return '';
 948                      break;
 949                      
 950                  case 'column_insert_behind':
 951                      ++$col;
 952                  case 'column_insert_before':
 953                      //echo "<p>column_insert_before: col=$col</p>\n";
 954                      // $col is where the new column data goes
 955                      for ($row = 1; $row <= $rows; ++$row)
 956                      {
 957                          for ($i = $cols; $i > $col; --$i)
 958                          {
 959                              $data[$row][soetemplate::num2chrs($i)] = $data[$row][soetemplate::num2chrs($i-1)];
 960                          }
 961                          $data[$row][soetemplate::num2chrs($col)] = soetemplate::empty_cell();
 962                      }
 963                      for ($i = $cols; $i > $col; --$i)
 964                      {
 965                          $opts[soetemplate::num2chrs($i)] = $opts[soetemplate::num2chrs($i-1)];
 966                      }
 967                      unset($opts[soetemplate::num2chrs($col)]);
 968                      ++$cols;
 969                      //_debug_array($grid); return '';
 970                      break;
 971                      
 972                  case 'column_delete':
 973                      if ($cols <= 1)
 974                      {
 975                          return lang('cant delete the only column of a grid !!!');
 976                          // todo: delete whole grid instead
 977                      }
 978                      for ($row = 1; $row <= $rows; ++$row)
 979                      {
 980                          for ($i = $col; $i < $cols-1; ++$i)
 981                          {
 982                              $data[$row][soetemplate::num2chrs($i)] = $data[$row][soetemplate::num2chrs($i+1)];
 983                          }
 984                          unset($data[$row][soetemplate::num2chrs($cols-1)]);
 985                      }
 986                      for ($i = $col; $i < $cols-1; ++$i)
 987                      {
 988                          $opts[soetemplate::num2chrs($i)] = $opts[soetemplate::num2chrs($i+1)];
 989                      }
 990                      unset($opts[soetemplate::num2chrs(--$cols)]);
 991                      break;        
 992              }
 993              $action = 'save-no-merge';
 994  
 995              return '';
 996          }
 997  
 998          /**
 999           * converts onclick selectbox and onclick text to one javascript call
1000           *
1001           * @param array &$widget reference into the widget-tree
1002           * @param array &$cell_content cell array in content
1003           * @param boolean $widget2content=true copy from widget to content or other direction
1004           */
1005  		function fix_set_onclick(&$widget,&$cell_content,$widget2content=true)
1006          {
1007              if ($widget2content)
1008              {
1009                  if (preg_match('/^return confirm\(["\']{1}?(.*)["\']{1}\);?$/',$widget['onclick'],$matches))
1010                  {
1011                      $cell_content['onclick'] = $matches[1];
1012                      $cell_content['onclick_type'] = 'confirm';
1013                  }
1014                  elseif (preg_match('/^window.open\(egw::link\(\'\/index.php\',\'([^\']+)\'\)(\+values2url\(.*\))?,\'([^\']+)\',\'dependent=yes,width=([0-9]+),height=([0-9]+),scrollbars=yes,status=yes\'\); return false;$/',$widget['onclick'],$matches))
1015                  {
1016                      $cell_content['onclick'] = $matches[1].($matches[2] ? str_replace('+values2url(this.form,','&values2url(',$matches[2]) : '');
1017                      if ($matches[3] != '_blank')
1018                      {
1019                          $cell_content['onclick'] .= ','.$matches[3];
1020                      }
1021                      if ($matches[4] != '600')
1022                      {
1023                          $cell_content['onclick'] .= ($matches[3]=='_blank' ? ',':'').','.$matches[4];
1024                      }
1025                      if ($matches[5] != '450')
1026                      {
1027                          $cell_content['onclick'] .= ($matches[4]=='600' ? ','.($matches[3]=='_blank' ? ',':'') : '').
1028                              ','.$matches[5];
1029                      }
1030                      $cell_content['onclick_type'] = 'popup';
1031                  }
1032                  else
1033                  {
1034                      $cell_content['onclick_type'] = !$widget['onclick'] ? '' : 'custom';
1035                  }
1036              }
1037              else    // content --> widget
1038              {
1039                  if (preg_match('/^return confirm\(["\']{1}?(.*)["\']{1}\);?$/',$cell_content['onclick'],$matches) ||
1040                      $cell_content['onclick_type'] == 'confirm' && $cell_content['onclick'])
1041                  {
1042                      $cell_content['onclick_type'] = 'confirm';
1043                      $cell_content['onclick'] = is_array($matches) && $matches[1] ? $matches[1] : $cell_content['onclick'];
1044                      $widget['onclick'] = "return confirm('".$cell_content['onclick']."');";
1045                  }
1046                  elseif ($cell_content['onclick_type'] == 'popup' && $cell_content['onclick'])
1047                  {
1048                      // eg: menuaction=calendar.uiforms.freetimesearch&values2url('start,end,participants'),ft_search,700,500
1049                      if  (($values2url = preg_match('/&values2url\((\'[^\']+\')\)/',$cell_content['onclick'],$matches)))
1050                      {
1051                          $values2url = $matches[1];
1052                          $onclick = str_replace('&values2url('.$values2url.')','',$cell_content['onclick']);
1053                      }
1054                      list($get,$target,$width,$height) = explode(',',$values2url ? $onclick : $cell_content['onclick']);
1055                      if (!$target) $target = '_blank';
1056                      if (!$width)  $width  = 600;
1057                      if (!$height) $height = 450;
1058                      $widget['onclick'] = "window.open(egw::link('/index.php','$get')".($values2url ? "+values2url(this.form,$values2url)" : '').
1059                          ",'$target','dependent=yes,width=$width,height=$height,scrollbars=yes,status=yes'); return false;";
1060                  }
1061                  elseif ($cell_content['onclick'])
1062                  {
1063                      $wiget['onclick'] = $cell_content['onclick'];
1064                      $cell_content['onclick_type'] = 'custom';
1065                  }
1066                  else
1067                  {
1068                      $cell_content['onclick_type'] = '';
1069                  }
1070                  unset($widget['onclick_type']);
1071              }
1072              //echo "<p>editor::fix_set_onclick(,,widget2content=".(int)$widget2content.") widget="; _debug_array($widget); echo "content="; _debug_array($cell_content);
1073          }
1074  
1075          /**
1076           * converts onchange selectbox and onchange text to one javascript call
1077           *
1078           * @param array &$widget reference into the widget-tree
1079           * @param array &$cell_content cell array in content
1080           * @param boolean $widget2content=true copy from widget to content or other direction
1081           */
1082  		function fix_set_onchange(&$widget,&$cell_content,$widget2content=true)
1083          {
1084              if ($widget2content)
1085              {
1086                  if (!$widget['onchange'])
1087                  {
1088                      $cell_content['onchange_type'] = $cell_content['onchange'] = '';
1089                  }
1090                  elseif ($widget['onchange'] == 1 || $widget['onchange'] == 'this.form.submit();')
1091                  {
1092                      $cell_content['onchange'] = '';
1093                      $cell_content['onchange_type'] = 'submit';
1094                  }
1095                  else
1096                  {
1097                      $cell_content['onchange_type'] = 'custom';
1098                  }
1099              }
1100              else    // content --> widget
1101              {
1102                  if ($cell_content['onchange_type'] == 'submit' || $cell_content['onchange'] == 'this.form.submit();')
1103                  {
1104                      $widget['onchange'] = 1;
1105                  }
1106                  elseif(!$cell_content['onchange'])
1107                  {
1108                      $widget['onchange'] = 0;
1109                  }
1110                  unset($widget['onchange_type']);
1111              }
1112              //echo "<p>editor::fix_set_onchange(,,widget2content=".(int)$widget2content.") widget="; _debug_array($widget); echo "content="; _debug_array($cell_content);
1113          }
1114  
1115          /**
1116           * edit dialog for a widget
1117           *
1118           * @param array $content the submitted content of the etemplate::exec function, default null
1119           * @param string $msg msg to display, default ''
1120           */
1121  		function widget($content=null,$msg='')
1122          {
1123              if (is_array($content))
1124              {
1125                  $path = $content['goto'] ? $content['goto'] : ($content['goto2'] ? $content['goto2'] : $content['path']);
1126                  $Ok = $this->etemplate->read($content['name'],$content['template'],$content['lang'],0,$content['goto'] || $content['goto2'] ? $content['version'] : $content['old_version']);
1127                  
1128                  // build size from options array, if applicable
1129                  if (is_array($content['cell']['options']))
1130                  {
1131                      $size = '';
1132                      for ($n = max(array_keys($content['cell']['options'])); $n >= 0; --$n)
1133                      {
1134                          if (strlen($content['cell']['options'][$n]) || strlen($size))
1135                          {
1136                              $size = $content['cell']['options'][$n].(strlen($size) ? ','.$size : '');
1137                          }
1138                      }
1139                      $content['cell']['size'] = $size;
1140                  }
1141              }
1142              else
1143              {
1144                  //echo "<p><b>".($_GET['path']).":</b></p>\n";
1145                  list($name,$version,$path) = explode(':',$_GET['path'],3);    // <name>:<version>:<path>
1146                  $Ok = $this->etemplate->read(array(
1147                      'name'    => $name,
1148                      'version' => $version,
1149                  ));
1150              }
1151              if (!$Ok && !$content['cancel'])
1152              {
1153                  $msg .= lang('Error: Template not found !!!');
1154              }
1155              $path_parts = explode('/',$path);
1156              $child_id = array_pop($path_parts);
1157              $parent_path = implode('/',$path_parts);
1158              //echo "<p>path='$path': child_id='$child_id', parent_path='$parent_path'</p>\n";
1159              $parent =& $this->etemplate->get_widget_by_path($parent_path);
1160              
1161              if (is_array($content))
1162              {
1163                  foreach(array('save','apply','cancel','goto','goto2','edit_menu','box_menu','row_menu','column_menu') as $n => $name)
1164                  {
1165                      if (($action = $content[$name] ? ($n < 5 ? $name : $content[$name]) : false)) break;
1166                      $name = '';
1167                  }
1168                  unset($content[$name]);
1169                  
1170                  //echo "<p>name='$name', parent-type='$parent[type]', action='$action'</p>\n";
1171                  if (($name == 'row_menu' || $name == 'column_menu') && $parent['type'] != 'grid' ||
1172                      $name == 'box_menu' && $parent['type'] == 'grid')
1173                  {
1174                      $msg .= lang("parent is a '%1' !!!",lang($parent['type'] ? $parent['type'] : 'template'));
1175                      $action = false;
1176                  }
1177                  switch($name)
1178                  {
1179                      case 'edit_menu':
1180                          $msg .= $this->edit_actions($action,$parent,$content,$child_id);
1181                          break;
1182                          
1183                      case 'box_menu':
1184                          $msg .= $this->box_actions($action,$parent,$content,$child_id,$parent_path);
1185                          break;
1186  
1187                      case 'row_menu':
1188                          $msg .= $this->row_actions($action,$parent,$child_id);
1189                          break;
1190                          
1191                      case 'column_menu':
1192                          $msg .= $this->column_actions($action,$parent,$child_id);
1193                          break;
1194                          
1195                      default: 
1196                          // all menu's are (only) working on the parent, referencing widget is unnecessary 
1197                          // and gives unexpected results, if parent is changed (eg. content gets copied)
1198                          $widget =& $this->etemplate->get_widget_by_path($path);
1199                          break;
1200                  }
1201                  switch ($action)
1202                  {
1203                      case 'goto':
1204                      case 'goto2':
1205                          $content['cell'] = $widget;
1206                          $this->fix_set_onclick($widget,$content['cell'],true);
1207                          $this->fix_set_onchange($widget,$content['cell'],true);
1208                          break;
1209  
1210                      case '':
1211                      case 'save': case 'apply': 
1212                          // initialise the children arrays if type is changed to a widget with children
1213                          //echo "<p>$content[path]: $widget[type] --> ".$content['cell']['type']."</p>\n";
1214                          if (isset($this->etemplate->widgets_with_children[$content['cell']['type']]))
1215                          {
1216                              $this->change_widget_type($content['cell'],$widget);
1217                          }
1218                          if (!$action) break;
1219                          // save+apply only
1220                          $widget = $content['cell'];
1221                          if ($content['cell']['onclick_type'] || $content['cell']['onclick'])
1222                          {
1223                              $this->fix_set_onclick($widget,$content['cell'],false);
1224                          }
1225                          if ($content['cell']['onchange_type'] || $content['cell']['onchange'])
1226                          {
1227                              $this->fix_set_onchange($widget,$content['cell'],false);
1228                          }
1229                          // row- and column-attr for a grid
1230                          if ($parent['type'] == 'grid' && preg_match('/^([0-9]+)([A-Z]+)$/',$child_id,$matches))
1231                          {
1232                              list(,$row,$col) = $matches;
1233                              $parent['data'][0]['h'.$row] = $content['grid_row']['height'].
1234                                  ($content['grid_row']['disabled']?','.$content['grid_row']['disabled']:'');
1235                              $parent['data'][0]['c'.$row] = $content['grid_row']['class'].
1236                                  ($content['grid_row']['valign']?','.$content['grid_row']['valign']:'');
1237                              $parent['data'][0][$col] = $content['grid_column']['width'].
1238                                  ($content['grid_column']['disabled']?','.$content['grid_column']['disabled']:'');
1239                          }
1240                          // fall-through
1241                      case 'save-no-merge':
1242                      case 'apply-no-merge':
1243                          //$this->etemplate->echo_tmpl();
1244                          $ok = $this->etemplate->save($content);
1245                          $msg .= $ok ? lang('Template saved') : lang('Error: while saving !!!');
1246      
1247                          // if necessary fix the version of our opener
1248                          if ($content['opener']['name'] == $content['name'] &&
1249                              $content['opener']['template'] == $content['template'] &&
1250                              $content['opener']['group'] == $content['group'] &&
1251                              $content['opener']['lang'] == $content['lang'])
1252                          {
1253                              $content['opener']['version'] = $content['version'];
1254                          }
1255                          $js = "opener.location.href='".$GLOBALS['egw']->link('/index.php',array(
1256                                  'menuaction' => 'etemplate.editor.edit',
1257                              )+$content['opener'])."';";
1258                          if ($action == 'apply' || $action == 'apply-no-merge') break;
1259                          // fall through
1260                      case 'cancel':
1261                          $js .= 'window.close();';
1262                          echo "<html><body><script>$js</script></body></html>\n";
1263                          $GLOBALS['egw']->common->egw_exit();
1264                          break;
1265                  }                
1266                  if ($js)
1267                  {
1268                      $content['java_script'] = "<script>$js</script>";
1269                  }
1270              }
1271              else
1272              {
1273                  $widget =& $this->etemplate->get_widget_by_path($path);
1274                  
1275                  $content = $this->etemplate->as_array(-1);
1276                  $content['cell'] = $widget;
1277                  $this->fix_set_onclick($widget,$content['cell'],true);
1278                  $this->fix_set_onchange($widget,$content['cell'],true);
1279                  
1280                  foreach($this->etemplate->db_key_cols as $var)
1281                  {
1282                      if (isset($_GET[$var]))
1283                      {
1284                          $content['opener'][$var] = $_GET[$var];
1285                      }
1286                  }
1287              }
1288              unset($content['cell']['obj']);    // just in case it contains a template-object
1289              
1290              if ($parent['type'] == 'grid' && preg_match('/^([0-9]+)([A-Z]+)$/',$child_id,$matches))
1291              {
1292                  list(,$row,$col) = $matches;
1293  
1294                  $grid_row =& $content['grid_row'];
1295                  list($grid_row['height'],$grid_row['disabled']) = explode(',',$parent['data'][0]['h'.$row]);
1296                  list($grid_row['class'],$grid_row['valign']) = explode(',',$parent['data'][0]['c'.$row]);
1297                  
1298                  $grid_column =& $content['grid_column'];
1299                  list($grid_column['width'],$grid_column['disabled']) = explode(',',$parent['data'][0][$col]);
1300                  //echo "<p>grid_row($row)=".print_r($grid_row,true).", grid_column($col)=".print_r($grid_column,true)."</p>\n";
1301              }
1302              else
1303              {
1304                  unset($content['grid_row']);
1305                  unset($content['grid_column']);
1306              }
1307              $content['path'] = ($parent_path!='/'?$parent_path:'').'/'.$child_id;
1308              $content['msg'] = $msg;
1309              $content['goto'] = $this->path_components($content['path']);
1310              $content['goto2'] = $this->parent_navigation($parent,$parent_path,$child_id,$widget);
1311              
1312              $content['cell']['options'] = explode(',',$content['cell']['size']);
1313  
1314              $editor =& new etemplate('etemplate.editor.widget');
1315              $type_tmpl =& new etemplate;
1316              if ($type_tmpl->read('etemplate.editor.widget.'.$widget['type']))
1317              {
1318                  $editor->set_cell_attribute('etemplate.editor.widget.generic','obj',$type_tmpl);
1319              }
1320              if ($parent['type'] == 'grid')
1321              {
1322                  $editor->disable_cells('box_menu');
1323              }
1324              else
1325              {
1326                  $editor->disable_cells('row_menu');
1327                  $editor->disable_cells('column_menu');
1328              }
1329              $preserv = $this->etemplate->as_array()+array(
1330                  'path'        => $content['path'],
1331                  'old_version' => $this->etemplate->version,
1332                  'opener'      => $content['opener'],
1333                  'cell'        => $content['cell'],
1334                  'goto'        => $content['goto'],
1335              );
1336              unset($preserv['cell']['options']);    // otherwise we never know if content is returned via options array or size
1337              
1338              $GLOBALS['egw_info']['flags']['java_script'] = "<script>window.focus();</script>\n";
1339              $GLOBALS['egw_info']['flags']['app_header'] = lang('Editable Templates - Editor');
1340              $editor->exec('etemplate.editor.widget',$content,array(
1341                      'type'       => array_merge($this->etemplate->types,$this->extensions),
1342                      'align'      => &$this->aligns,
1343                      'valign'     => &$this->valigns,
1344                      'edit_menu'  => &$this->edit_menu,
1345                      'box_menu'   => &$this->box_menu,
1346                      'row_menu'   => &$this->row_menu,
1347                      'column_menu'=> &$this->column_menu,
1348                      'onclick_type'=>&$this->onclick_types,
1349                      'onchange_type'=>&$this->onchange_types,
1350                      'options[6]' => &$this->overflows,
1351                  ),'',$preserv,2);
1352          }
1353  
1354          /**
1355           * edit dialog for the styles of a templat or app
1356           *
1357           * @param array $content the submitted content of the etemplate::exec function, default null
1358           * @param string $msg msg to display, default ''
1359           */
1360  		function styles($content=null,$msg='')
1361          {
1362              if (!is_array($content))
1363              {
1364                  foreach($this->etemplate->db_key_cols as $var)
1365                  {
1366                      if (isset($_GET[$var])) $content[$var] = $_GET[$var];
1367                  }
1368              }
1369              //_debug_array($content);
1370              // security check for content[from]
1371              if ($content['from'] && !preg_match('/^[A-Za-z0-9_-]+\/templates\/[A-Za-z0-9_-]+\/app.css$/',$content['from']))
1372              {
1373                  $content['from'] = '';    // someone tried to trick us reading a file we are not suppost to read
1374              }
1375              if (!$this->etemplate->read($content))
1376              {
1377                  $msg .= lang('Error: Template not found !!!');
1378              }
1379              if ($content['save'] || $content['apply'])
1380              {
1381                  if ($content['from'])
1382                  {
1383                      $path = EGW_SERVER_ROOT.'/'.$content['from'];
1384                      if (is_writable(dirname($path)) && file_exists($path))
1385                      {
1386                          rename($path,str_replace('.css','.old.css',$path));
1387                      }
1388                      if (file_exists($path) && !is_writable(dirname($path)))
1389                      {
1390                          $msg .= lang("Error: webserver is not allowed to write into '%1' !!!",dirname($path));
1391                      }
1392                      else
1393                      {
1394                          $fp = fopen($path,'w');
1395                          if (!$fp || !fwrite($fp,$content['styles']))
1396                          {
1397                              $msg .= lang('Error: while saving !!!');
1398                          }
1399                          else
1400                          {
1401                              $msg .= lang("File writen",$path);
1402                          }
1403                          @fclose($fp);
1404                      }
1405                  }                    
1406                  else    // the templates own embeded styles;
1407                  {
1408                      $this->etemplate->style = $content['styles'];
1409                      $ok = $this->etemplate->save();
1410                      $msg = $ok ? lang('Template saved') : lang('Error: while saving !!!');
1411                  }
1412                  $js = "opener.location.href='".$GLOBALS['egw']->link('/index.php',array(
1413                          'menuaction' => 'etemplate.editor.edit',
1414                      )+$this->etemplate->as_array(-1))."';";
1415              }
1416              if ($content['save'] || $content['cancel'])
1417              {
1418                  $js .= 'window.close();';
1419                  echo "<html><body><script>$js</script></body></html>\n";
1420                  $GLOBALS['egw']->common->egw_exit();
1421              }
1422              $content = array(
1423                  'from' => $content['from'],
1424                  'java_script' => $js ? '<script>'.$js.'</script>' : '',
1425                  'msg' => $msg
1426              );
1427              $tmpl =& new etemplate('etemplate.editor.styles');
1428  
1429              if ($content['from'])
1430              {
1431                  $path = EGW_SERVER_ROOT.'/'.$content['from'];
1432                  $content['styles'] = file_exists($path) && is_readable($path) ? implode('',file($path)) : '';
1433                  if (!is_writable(dirname($path)) && (!file_exists($path) || !is_writable($path)))
1434                  { 
1435                      $tmpl->set_cell_attribute('styles','readonly',true);
1436                  }
1437              }
1438              else
1439              {
1440                  $content['styles'] = $this->etemplate->style;
1441              }
1442              // generate list of style-sources
1443              $keys = $this->etemplate->as_array(-1); unset($keys['group']);
1444              $sources[''] = lang('eTemplate').': '.implode(':',$keys);
1445              list($app) = explode('.',$this->etemplate->name);
1446              $app_templates = @opendir(EGW_SERVER_ROOT.'/'.$app.'/templates');
1447              while (($template = @readdir($app_templates)) !== false)
1448              {
1449                  $dir = EGW_SERVER_ROOT.'/'.$app.'/templates/'.$template;
1450                  if ($template[0] == '.' || $template == 'CVS' || !is_dir($dir.'/images')) continue;    // not a template-dir
1451                  $exists = file_exists($dir.'/app.css');
1452                  $writable = is_writable($dir) || $exists && is_writable($dir.'/app.css');
1453                  if (!$exists && !$writable) continue;    // nothing to show
1454                  $rel_path = $app.'/templates/'.$template.'/app.css';
1455                  $sources[$rel_path] = lang('file').': '.$rel_path.($exists && !$writable ? ' ('.lang('readonly').')' : '');
1456              }
1457              $GLOBALS['egw_info']['flags']['java_script'] = "<script>window.focus();</script>\n";
1458              $GLOBALS['egw_info']['flags']['app_header'] = lang('etemplate').' - '.lang('CSS-styles');
1459              $tmpl->exec('etemplate.editor.styles',$content,array('from'=>$sources),'',$keys,2);
1460          }
1461  
1462          /**
1463           * search the inc-dirs of etemplate and the app whichs template is edited for extensions / custom widgets
1464           *
1465           * extensions are class-files in $app/inc/class.${name}_widget.inc.php
1466           * the extensions found will be saved in a class-var and in the session
1467           *
1468           * @param string $app='etemplate' app to scan
1469           * @return string comma delimited list of new found extensions
1470           */
1471  		function scan_for_extensions($app='etemplate')
1472          {
1473              if (!is_array($this->extensions)) $this->extensions = array();
1474              
1475              if (isset($this->extensions['**loaded**'][$app])) return '';    // already loaded
1476              
1477              $labels = array();
1478              $dir = @opendir(EGW_SERVER_ROOT.'/'.$app.'/inc');
1479              while ($dir && ($file = readdir($dir)))
1480              {
1481                  if (ereg('class\\.([a-zA-Z0-9_]*)_widget.inc.php',$file,$regs) &&
1482                      ($regs[1] != 'xslt' || $this->etemplate->xslt) &&
1483                      ($ext = $this->etemplate->loadExtension($regs[1].'.'.$app,$this->etemplate)))
1484                  {
1485                      if (is_array($ext))
1486                      {
1487                          $this->extensions += $ext;
1488                          $labels += $ext;
1489                      }
1490                      else
1491                      {
1492                          $this->extensions[$regs[1]] = $ext;
1493                          $labels[] = $ext;
1494                      }
1495                  }
1496              }
1497              // store the information in the session, our constructor loads it from there
1498              $GLOBALS['egw']->session->appsession('extensions','etemplate',$this->extensions);
1499              $apps_loaded = $GLOBALS['egw']->session->appsession('apps_loaded','etemplate');
1500              $apps_loaded[$app] = true;
1501              $GLOBALS['egw']->session->appsession('apps_loaded','etemplate',$apps_loaded);
1502              //_debug_array($this->extensions); _debug_array($apps_loaded);
1503              
1504              return implode(', ',$labels);
1505          }
1506          
1507          /**
1508           * swap the values of $a and $b
1509           *
1510           * @param mixed &$a
1511           * @param mixed &$b
1512           */
1513  		function swap(&$a,&$b)
1514          {
1515              $h = $a;
1516              $a = $b;
1517              $b = $h;
1518          }
1519      }


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7