| [ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
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'=>'←','up'=>' ↑ ','down'=>' ↓ ', 684 'right'=>'→','previous'=>'←↑','next'=>'↓→','in'=>'×') 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 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |