[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare - eTemplates - XUL/XML Import & Export * 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.xul_io.inc.php 20839 2006-03-27 12:23:49Z ralfbecker $ */ 14 15 if (!function_exists('var2xml')) 16 { 17 if (file_exists(EGW_API_INC.'class.xmltool.inc.php')) 18 { 19 include_once (EGW_API_INC.'class.xmltool.inc.php'); 20 } 21 else 22 { 23 include_once ('class.xmltool.inc.php'); 24 } 25 } 26 27 /** 28 * XUL/XML Import & Export for eTemplates 29 * 30 * used only internaly 31 * 32 * @package etemplate 33 * @subpackage api 34 * @author RalfBecker-AT-outdoor-training.de 35 * @license GPL 36 */ 37 class xul_io 38 { 39 var $widget2xul; 40 var $attr2xul; 41 var $xul2widget; 42 43 function xul_io() 44 { 45 /** 46 * @var array $attr2xul how to translate attr, common to all widgets 47 */ 48 $this->attr2xul = array( 49 'name' => 'id', 50 'help' => 'statustext', 51 'span' => 'span,class', 52 'type' => '', // this is the widget-name => dont write as attr 53 'disabled' => 'disabled=true', 54 'readonly' => 'readonly=true', 55 'size' => 'options' 56 ); 57 /** 58 * @var array $widget2xul how to widget-names and widget-spec. attr., not set ones are identical 59 */ 60 $this->widget2xul = array( 61 'label' => array( 62 '.name' => 'description', 63 'label' => 'value' 64 ), 65 'text' => array( 66 '.name' => 'textbox', 67 'size' => 'size,maxlength,validator' 68 ), 69 'textarea' => array( 70 '.name' => 'textbox', 71 '.set' => 'multiline=true', 72 'size' => 'rows,cols' 73 ), 74 'integer' => array( 75 '.name' => 'textbox', 76 '.set' => 'type=integer', 77 'size' => 'min,max,size' 78 ), 79 'float' => array( 80 '.name' => 'textbox', 81 '.set' => 'type=float', 82 'size' => 'min,max,size,precision' 83 ), 84 'select' => array( 85 '.name' => 'menulist,menupopup', 86 ), 87 'select-multi' => array( // multiselection, if size > 0 88 '.name' => 'listbox', 89 'size' => 'rows,options' 90 ), 91 'template' => array( 92 '.name' => 'template', 93 'size' => 'content' 94 ), 95 'image' => array( 96 '.name' => 'image', 97 'name' => 'src' 98 ), 99 'tab' => array( 100 '.name' => 'tabbox,tabs,tabpanels' 101 ), 102 'button' => array( 103 '.name' => 'button', 104 'size' => 'image,ro_image' 105 ), 106 'htmlarea' => array( 107 'size' => 'style,plugins', 108 ), 109 ); 110 /** 111 * @var array $xul2widget how to xul-widget names to our internal ones, not set ones are identical 112 */ 113 $this->xul2widget = array( 114 'menulist' => 'select', 115 'listbox' => 'select', 116 'menupopup' => 'select', 117 'description' => 'label' 118 ); 119 } 120 121 /** 122 * sets an attribute in the xml object representing a widget 123 * 124 * @param object &$widget widget to set the attribute in 125 * @param string $attr comma delimited attr = default-value pairs, eg. "type=int,min=0" 126 * @param array $val array with values to set 127 */ 128 function set_attributes(&$widget,$attr,$val) 129 { 130 if ($attr != '' && !is_numeric($attr)) 131 { 132 $attrs = explode(',',$attr); 133 134 if (count($attrs)) 135 { 136 $vals = count($attrs) > 1 ? explode(',',$val,count($attrs)) : array($val); 137 foreach($attrs as $n => $attr) 138 { 139 if (($val = $vals[$n]) != '') 140 { 141 list($attr,$set) = explode('=',$attr); 142 $widget->set_attribute($attr,$set != '' ? $set : $val); 143 } 144 } 145 } 146 } 147 } 148 149 /** 150 * add a widget to a parent 151 * 152 * @param object &$parent parten to add the widget 153 * @param array $cell widget to add 154 * @param array &$embeded_too already embeded eTemplates 155 * @return object reference (!) the the xml object representing the widget, so other children can be added 156 */ 157 function &add_widget(&$parent,$cell,&$embeded_too) 158 { 159 $type = $cell['type']; 160 if (is_array($type)) 161 { 162 list(,$type) = each($type); 163 } 164 if (!$type) $cell['type'] = $type = 'hugo'; 165 if (substr($type,0,6) == 'select') 166 { 167 $type = $cell['size'] > 1 ? 'select-multi' : 'select'; 168 } 169 $widgetattr2xul = isset($this->widget2xul[$type]) ? $this->widget2xul[$type] : array(); 170 $type = isset($widgetattr2xul['.name']) ? $widgetattr2xul['.name'] : $type; 171 list($type,$child,$child2) = explode(',',$type); 172 $widget =& new xmlnode($type); 173 $attr_widget = &$widget; 174 if ($child) 175 { 176 $child =& new xmlnode($child); 177 if ($type != 'tabbox') $attr_widget = &$child; 178 } 179 if ($child2) 180 { 181 $child2 =& new xmlnode($child2); 182 } 183 if (isset($widgetattr2xul['.set'])) // set default-attr for type 184 { 185 $attrs = explode(',',$widgetattr2xul['.set']); 186 foreach($attrs as $attr) 187 { 188 list($attr,$val) = explode('=',$attr); 189 $widget->set_attribute($attr,$val); 190 } 191 } 192 switch ($type) 193 { 194 case 'nextmatch': 195 list($tpl) = explode(',',$cell['size']); 196 $embeded =& new etemplate($tpl,$this->load_via); 197 if ($embeded_too) 198 { 199 $this->add_etempl($embeded,$embeded_too); 200 } 201 $cell['size'] = $embeded->name; 202 unset($embeded); 203 break; 204 case 'tabbox': 205 $labels = explode('|',$cell['label']); unset($cell['label']); 206 $helps = explode('|',$cell['help']); unset($cell['help']); 207 $names = explode('|',$cell['name']); unset($cell['name']); 208 for ($n = 0; $n < count($labels); ++$n) 209 { 210 $tab =& new xmlnode('tab'); 211 $tab->set_attribute('label',$labels[$n]); 212 $tab->set_attribute('statustext',$helps[$n]); 213 $child->add_node($tab); 214 215 $embeded =& new etemplate($names[$n],$this->load_via); 216 if ($embeded_too) 217 { 218 $this->add_etempl($embeded,$embeded_too); 219 } 220 $template =& new xmlnode('template'); 221 $template->set_attribute('id',$embeded->name); 222 $child2->add_node($template); 223 unset($embeded); 224 unset($template); 225 } 226 break; 227 case 'menulist': // id,options belongs to the 'menupopup' child 228 if ($cell['span']) 229 { 230 $widget->set_attribute('span',$cell['span']); 231 unset($cell['span']); 232 } 233 // fall-trought 234 case 'listbox': 235 if ($cell['type'] != 'select') // one of the sub-types 236 { 237 $attr_widget->set_attribute('type',$cell['type']); 238 } 239 break; 240 case 'groupbox': 241 if ($cell['label']) 242 { 243 $caption =& new xmlnode('caption'); 244 $caption->set_attribute('label',$cell['label']); 245 $widget->add_node($caption); 246 unset($cell['label']); 247 } 248 // fall-through 249 case 'vbox': 250 case 'hbox': 251 case 'box': 252 case 'deck': 253 list($anz,$orient,$options) = split(',',$cell['size'],2); 254 for ($n = 1; $n <= $anz; ++$n) 255 { 256 $this->add_widget($widget,$cell[$n],$embeded_too); 257 unset($cell[$n]); 258 } 259 $cell['orient'] = $orient; 260 $cell['size'] = $options; 261 break; 262 263 case 'template': 264 if ($cell['name'][0] != '@' && $embeded_too) 265 { 266 $templ =& new etemplate(); 267 if ($templ->read(boetemplate::expand_name($cell['name'],0,0),'default','default',0,'',$this->load_via)) 268 { 269 $this->add_etempl($templ,$embeded_too); 270 } 271 $cell['name'] = $templ->name; 272 unset($templ); 273 } 274 break; 275 276 case 'grid': 277 $this->add_grid($parent,$cell,$embeded_too); 278 return; // grid is already added 279 } 280 foreach($cell as $attr => $val) 281 { 282 if (is_array($val)) // correct old buggy etemplates 283 { 284 list(,$val) = each($val); 285 } 286 if (isset($widgetattr2xul[$attr])) 287 { 288 $attr = $widgetattr2xul[$attr]; 289 } 290 elseif (isset($this->attr2xul[$attr])) 291 { 292 $attr = $this->attr2xul[$attr]; 293 } 294 $this->set_attributes($attr_widget,$attr,$val); 295 } 296 if ($child) 297 { 298 $widget->add_node($child); 299 } 300 if ($child2) 301 { 302 $widget->add_node($child2); 303 } 304 $parent->add_node($widget); 305 } 306 307 /** 308 * add a grid to $parent (xml object) 309 * 310 * @param object &$parent where to add the grid 311 * @param array $grid grid to add 312 * @param array &embeded_too array with already embeded eTemplates 313 */ 314 function add_grid(&$parent,$grid,&$embeded_too) 315 { 316 $xul_grid =& new xmlnode('grid'); 317 $this->set_attributes($xul_grid,'width,height,border,class,spacing,padding,overflow',$grid['size']); 318 319 $xul_columns =& new xmlnode('columns'); 320 $xul_rows =& new xmlnode('rows'); 321 322 reset($grid['data']); 323 list(,$opts) = each ($grid['data']); // read over options-row 324 while (list($r,$row) = each ($grid['data'])) 325 { 326 $xul_row =& new xmlnode('row'); 327 $this->set_attributes($xul_row,'class,valign',$opts["c$r"]); 328 $this->set_attributes($xul_row,'height,disabled',$opts["h$r"]); 329 330 $spanned = 0; 331 foreach($row as $c => $cell) 332 { 333 if ($r == '1') // write columns only once in the first row 334 { 335 $xul_column =& new xmlnode('column'); 336 $this->set_attributes($xul_column,'width,disabled',$opts[$c]); 337 $xul_columns->add_node($xul_column); 338 } 339 if ($spanned-- > 1) 340 { 341 continue; // spanned cells are not written 342 } 343 $this->add_widget($xul_row,$cell,$embeded_too); 344 345 $spanned = $cell['span'] == 'all' ? 999 : $cell['span']; 346 } 347 $xul_rows->add_node($xul_row); 348 } 349 $xul_grid->add_node($xul_columns); 350 $xul_grid->add_node($xul_rows); 351 352 $parent->add_node($xul_grid); 353 } 354 355 /** 356 * add / embed an eTemplate into the global $xul_overlay object (used by export) 357 * 358 * @param object &$etempl eTemplate to embed 359 * @param array &embeded_too array with already embeded templates 360 */ 361 function add_etempl(&$etempl,&$embeded_too) 362 { 363 if (is_array($embeded_too)) 364 { 365 if (isset($embeded_too[$etempl->name])) 366 { 367 return; // allready embeded 368 } 369 } 370 else 371 { 372 $embeded_too = array(); 373 } 374 $embeded_too[$etempl->name] = True; 375 376 $template =& new xmlnode('template'); 377 $template->set_attribute('id',$etempl->name); 378 $template->set_attribute('template',$etempl->template); 379 $template->set_attribute('lang',$etempl->lang); 380 $template->set_attribute('group',$etempl->group); 381 $template->set_attribute('version',$etempl->version); 382 383 foreach($etempl->children as $child) 384 { 385 $this->add_widget($template,$child,$embeded_too); 386 } 387 if ($etempl->style != '') 388 { 389 $styles =& new xmlnode('styles'); 390 $styles->set_value($etempl->style); 391 $template->add_node($styles); 392 } 393 $this->xul_overlay->add_node($template); 394 } 395 396 /** 397 * create an XML representation of an eTemplate 398 * 399 * @param object $etempl eTemplate object to export 400 * @return string the XML 401 */ 402 function export($etempl) 403 { 404 if ($this->debug) 405 { 406 echo "<p>etempl->data = "; _debug_array($etempl->data); 407 } 408 $doc =& new xmldoc(); 409 $doc->add_comment('$'.'Id$'); 410 411 $this->xul_overlay =& new xmlnode('overlay'); // global for all add_etempl calls 412 $this->load_via = $etempl->as_array(); 413 414 $embeded_too = True; 415 $this->add_etempl($etempl,$embeded_too); 416 417 $doc->add_root($this->xul_overlay); 418 $xml = $doc->export_xml(); 419 420 if ($this->debug) 421 { 422 echo "<pre>\n" . htmlentities($xml) . "\n</pre>\n"; 423 } 424 return $xml; 425 } 426 427 /** 428 * create an eTemplate from it's XML representation 429 * 430 * @param object &$etempl eTemplate object to set 431 * @param string $data the XML 432 * @param array/string array with names of imported templates or error-message 433 */ 434 function import(&$etempl,$data) 435 { 436 if ($this->debug) 437 { 438 echo "<pre>\n" . htmlentities($data) . "\n</pre><p>\n"; 439 } 440 $parser = xml_parser_create(); 441 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 442 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 443 $vals = $index = ''; 444 $ok = xml_parse_into_struct($parser, $data, $vals, $index); 445 446 if (!$ok || !is_array($vals)) 447 { 448 $err = 'Error Line '.xml_get_current_line_number($parser).', Column '.xml_get_current_column_number($parser). 449 ': '.xml_error_string(xml_get_error_code($parser)); 450 } 451 xml_parser_free($parser); 452 453 if ($err != '') 454 { 455 return $err; 456 } 457 $parents = array(); 458 $parent = null; 459 foreach($vals as $n => $node) 460 { 461 if ($this->debug) 462 { 463 echo "<h1>$n</h1><pre>".print_r($node,true)."</pre>"; 464 } 465 $type = $node['type']; 466 $tag = $node['tag']; 467 $attr = is_array($node['attributes']) ? $node['attributes'] : array(); 468 if ($attr['id']) 469 { 470 $attr['name'] = $attr['id']; unset($attr['id']); 471 } 472 if (isset($attr['options']) && $attr['options'] != '') 473 { 474 $attr['size'] = $attr['options']; unset($attr['options']); 475 } 476 if ($tag != 'textbox' && !isset($attr['type'])) 477 { 478 $attr['type'] = $this->xul2widget[$tag] ? $this->xul2widget[$tag] : $tag; 479 } 480 if ($this->debug) 481 { 482 echo "<p>$node[level]: $tag/$type: value='$node[value]' attr=\n"; _debug_array($attr); 483 } 484 switch ($tag) 485 { 486 case 'overlay': 487 break; 488 case 'template': 489 case 'grid': 490 if ($type != 'open' && is_array($tab_attr)) // templates/grids in a tabpanel 491 { 492 $tab_names[] = $attr['name']; 493 break; 494 } 495 if ($tag == 'template' && $type != 'complete' && $node['level'] > 2) // level 1 is the overlay 496 { 497 return "Can't import nested $tag's !!!"; 498 } 499 switch ($type) 500 { 501 case 'close': 502 if (!count($parents) || $parent['.is_root']) // templ import complet => save it 503 { 504 unset($parent['.is_root']); 505 unset($parent); $parents = array(); 506 $etempl->fix_old_template_format(); // set the depricated compat vars 507 // save tmpl to the cache, as the file may contain more then one tmpl 508 $cname = ($etempl->template == '' ? 'default' : $etempl->template).'/'.$etempl->name. 509 ($etempl->lang == '' ? '' : '.'.$etempl->lang); 510 $GLOBALS['egw_info']['etemplate']['cache'][$cname] = $etempl->as_array(1); 511 if ($this->debug) 512 { 513 $etempl->echo_tmpl(); 514 } 515 $imported[] = $etempl->name; 516 } 517 else 518 { 519 // poping the last used parent from the end of the parents array (array_pop does not work with references) 520 $parent = &$parents[count($parents)-1]; 521 unset($parents[count($parents)-1]); 522 } 523 break; 524 case 'open': 525 if (($is_root = is_null($parent))) // starting a new templ 526 { 527 $etempl->init($attr); 528 $etempl->children = array(); // init adds one grid by default 529 $parent = &$etempl->children; 530 } 531 if ($tag == 'grid') 532 { 533 $size = ''; 534 foreach(array('overflow','padding','spacing','class','border','height','width') as $opt) 535 { 536 $size = $attr[$opt] . ($size != '' ? ",$size" : ''); 537 } 538 $grid = array( // empty grid 539 'type' => 'grid', 540 'data' => array(), 541 'cols' => 0, 542 'rows' => 0, 543 'size' => $size, 544 ); 545 if ($is_root) $grid['.is_root'] = true; // we need to remember we have no template as parent 546 soetemplate::add_child($parent,$grid); 547 $parents[count($parents)] = &$parent; 548 $parent = &$grid; 549 unset($grid); 550 } 551 break; 552 case 'complete': // reference to an other template 553 $attr['type'] = 'template'; // might be grid in old xet-files 554 soetemplate::add_child($parent,$attr); 555 unset($attr); 556 break; 557 } 558 break; 559 case 'columns': 560 case 'rows': 561 break; 562 case 'column': 563 if ($type != 'complete') 564 { 565 return 'place widgets in <row> and not in <column> !!!'; 566 } 567 $parent['data'][0][$etempl->num2chrs($parent['cols']++)] = $attr['width'] . 568 ($attr['disabled'] ? ','.$attr['disabled'] : ''); 569 break; 570 case 'row': 571 if ($type != 'open') 572 { 573 break; 574 } 575 $nul = null; soetemplate::add_child($parent,$nul); // null =& new row 576 $parent['data'][0]['c'.$parent['rows']] = $attr['class'] . ($attr['valign'] ? ','.$attr['valign'] : ''); 577 $parent['data'][0]['h'.$parent['rows']] = $attr['height'] . 578 ($attr['disabled'] ? ','.$attr['disabled'] : ''); 579 break; 580 case 'styles': 581 $etempl->style = trim($node['value']); 582 break; 583 case 'tabbox': 584 if ($type == 'open') 585 { 586 $tab_labels = $tab_helps = $tab_names = array(); 587 $tab_attr = $attr; 588 } 589 else 590 { 591 $tab_attr['type'] = 'tab'; 592 $tab_attr['label'] = implode('|',$tab_labels); 593 $tab_attr['name'] = implode('|',$tab_names); 594 $tab_attr['help'] = implode('|',$tab_helps); 595 $tab_attr['span'] .= $tab_attr['class'] ? ','.$tab_attr['class'] : ''; 596 unset($tab_attr['class']); 597 598 soetemplate::add_child($parent,$tab_attr); 599 unset($tab_attr); 600 } 601 break; 602 case 'tabs': 603 case 'tabpanels': 604 break; 605 case 'tab': 606 if ($type != 'close') 607 { 608 $tab_labels[] = $attr['label']; 609 $tab_helps[] = $attr['statustext']; 610 } 611 break; 612 case 'menupopup': 613 if (is_array($menulist_attr)) 614 { 615 $attr['help'] = $attr['statustext']; unset($attr['statustext']); 616 unset($menulist_attr['type']); 617 $menulist_attr += $attr; 618 } 619 break; 620 case 'menulist': 621 if ($type == 'open') 622 { 623 $menulist_attr = $attr; 624 } 625 else 626 { 627 soetemplate::add_child($parent,$menulist_attr); 628 unset($menulist_attr); 629 } 630 break; 631 case 'vbox': 632 case 'hbox': 633 case 'deck': 634 case 'groupbox': 635 case 'box': 636 if ($type != 'close') // open or complete 637 { 638 $attr['size'] = '0'.($attr['orient'] || $attr['size'] ? ','.$attr['orient']. 639 ($attr['size'] ? ','.$attr['size'] : '') : ''); 640 soetemplate::add_child($parent,$attr); 641 $parents[count($parents)] = &$parent; // $parents[] does not always the same - strange 642 $parent = &$attr; 643 unset($attr); 644 } 645 if ($type != 'open') // close or complete 646 { 647 // poping the last used parent from the end of the parents array (array_pop does not work with references) 648 $parent = &$parents[count($parents)-1]; 649 unset($parents[count($parents)-1]); 650 } 651 break; 652 case 'caption': // caption of (group)box 653 if ($parent['type'] == 'groupbox') 654 { 655 $parent['label'] = $attr['label']; 656 } 657 break; 658 // the following labels create automaticaly a child-entry in their parent 659 case 'textbox': 660 if ($attr['multiline']) 661 { 662 unset($attr['multiline']); 663 $attr['type'] = 'textarea'; 664 $attr['size'] = $attr['rows'] . ($attr['cols'] ? ','.$attr['cols'] : ''); 665 unset($attr['cols']); 666 unset($attr['rows']); 667 } 668 elseif ($attr['type']) // integer,float 669 { 670 $attr['size'] = $attr['min'] . ($attr['max'] ? ','.$attr['max'] : ($attr['size'] ? ',':'')) . ','.$attr['size']; 671 unset($attr['min']); 672 unset($attr['max']); 673 } 674 else // input 675 { 676 $attr['type'] = 'text'; 677 $attr['size'] .= $attr['maxlength']!='' ? ','.$attr['maxlength'] : ''; 678 unset($attr['maxlength']); 679 } 680 // fall-through 681 default: 682 switch ($tag) 683 { 684 case 'description': 685 case 'label': 686 $attr['label'] = $attr['value']; 687 unset($attr['value']); 688 break; 689 case 'template': 690 $attr['size'] = $attr['content']; 691 unset($attr['content']); 692 break; 693 case 'image': 694 $attr['name'] = $attr['src']; 695 unset($attr['src']); 696 break; 697 case 'listbox': 698 $attr['size'] = ereg_replace(',*$','',$attr['rows'].','.$attr['size']); 699 unset($attr['rows']); 700 break; 701 case 'button': 702 if ($attr['image'] || $attr['ro_image']) 703 { 704 $attr['size'] = $attr['image'] . ($attr['ro_image'] ? ','.$attr['ro_image'] : ''); 705 unset($attr['image']); unset($attr['ro_image']); 706 } 707 break; 708 } 709 $attr['help'] = $attr['statustext']; unset($attr['statustext']); 710 $attr['span'] .= $attr['class'] ? ','.$attr['class'] : ''; unset($attr['class']); 711 if ($type == 'close') 712 { 713 break; 714 } 715 soetemplate::add_child($parent,$attr); 716 unset($attr); 717 break; 718 } 719 if ($this->debug) 720 { 721 echo "<b>parent</b><pre>".print_r($parent,true)."</pre>"; 722 echo "<b>parents</b><pre>".print_r($parents,true)."</pre>"; 723 echo "<b>children</b><pre>".print_r($etempl->children,true)."</pre>"; 724 } 725 } 726 return $imported; 727 } 728 }
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 |