1<?php 2/* 3 * e107 website system 4 * 5 * Copyright (C) 2008-2012 e107 Inc (e107.org) 6 * Released under the terms and conditions of the 7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) 8 * 9 * Form Handler 10 * 11*/ 12 13if (!defined('e107_INIT')) { exit; } 14 15/** 16 * 17 * @package e107 18 * @subpackage e107_handlers 19 * @version $Id$ 20 * 21 * 22 * Automate Form fields creation. Produced markup is following e107 CSS/XHTML standards 23 * If options argument is omitted, default values will be used (which OK most of the time) 24 * Options are intended to handle some very special cases. 25 * 26 * Overall field options format (array or GET string like this one: var1=val1&var2=val2...): 27 * 28 * - id => (mixed) custom id attribute value 29 * if numeric value is passed it'll be just appended to the name e.g. {filed-name}-{value} 30 * if false is passed id will be not created 31 * if empty string is passed (or no 'id' option is found) 32 * in all other cases the value will be used as field id 33 * default: empty string 34 * 35 * - class => (string) field class(es) 36 * Example: 'tbox select class1 class2 class3' 37 * NOTE: this will override core classes, so you have to explicit include them! 38 * default: empty string 39 * 40 * - size => (int) size attribute value (used when needed) 41 * default: 40 42 * 43 * - title (string) title attribute 44 * default: empty string (omitted) 45 * 46 * - readonly => (bool) readonly attribute 47 * default: false 48 * 49 * - selected => (bool) selected attribute (used when needed) 50 * default: false 51 * 52 * checked => (bool) checked attribute (used when needed) 53 * default: false 54 * - disabled => (bool) disabled attribute 55 * default: false 56 * 57 * - tabindex => (int) tabindex attribute value 58 * default: inner tabindex counter 59 * 60 * - other => (string) additional data 61 * Example: 'attribute1="value1" attribute2="value2"' 62 * default: empty string 63 */ 64class e_form 65{ 66 protected $_tabindex_counter = 0; 67 protected $_tabindex_enabled = true; 68 protected $_cached_attributes = array(); 69 protected $_field_warnings = array(); 70 private $_inline_token = null; 71 72 /** 73 * @var user_class 74 */ 75 protected $_uc; 76 77 protected $_required_string; 78 79 function __construct($enable_tabindex = false) 80 { 81 e107_include_once(e_LANGUAGEDIR.e_LANGUAGE."/lan_form_handler.php"); 82 $this->_tabindex_enabled = $enable_tabindex; 83 $this->_uc = e107::getUserClass(); 84 $this->setRequiredString('<span class="required text-warning"> *</span>'); 85 } 86 87 /** 88 * @param $tmp 89 * @return array 90 * @see https://github.com/e107inc/e107/issues/3533 91 */ 92 private static function sort_get_files_output($tmp) 93 { 94 usort($tmp, function ($left, $right) { 95 $left_full_path = $left['path'] . $left['fname']; 96 $right_full_path = $right['path'] . $right['fname']; 97 return strcmp($left_full_path, $right_full_path); 98 }); 99 return $tmp; 100 } 101 102 103 public function addWarning($field) 104 { 105 $this->_field_warnings[] = $field; 106 107 } 108 109 /** 110 * Open a new form 111 * @param string name 112 * @param $method - post|get default is post 113 * @param string target - e_REQUEST_URI by default 114 * @param array $options 115 * @return string 116 */ 117 public function open($name, $method=null, $target=null, $options=null) 118 { 119 if($target == null) 120 { 121 $target = e_REQUEST_URI; 122 } 123 124 if($method == null) 125 { 126 $method = "post"; 127 } 128 129 $autoComplete = ""; 130 131 if(is_string($options)) 132 { 133 parse_str($options, $options); 134 } 135 136 if(vartrue($options['class'])) 137 { 138 $class = "class='".$options['class']."'"; 139 } 140 else // default 141 { 142 $class= "class='form-horizontal'"; 143 } 144 145 if(isset($options['autocomplete'])) // leave as isset() 146 { 147 $autoComplete = " autocomplete='".($options['autocomplete'] ? 'on' : 'off')."'"; 148 } 149 150 151 if($method == 'get' && strpos($target,'=')) 152 { 153 list($url,$qry) = explode("?",$target); 154 $text = "\n<form {$class} action='{$url}' id='".$this->name2id($name)."' method = '{$method}'{$autoComplete}>\n"; 155 156 parse_str($qry,$m); 157 foreach($m as $k=>$v) 158 { 159 $text .= $this->hidden($k, $v); 160 } 161 162 } 163 else 164 { 165 $target = str_replace("&", "&", $target); 166 $text = "\n<form {$class} action='{$target}' id='".$this->name2id($name)."' method='{$method}'{$autoComplete}>\n"; 167 } 168 return $text; 169 } 170 171 /** 172 * Close a Form 173 */ 174 public function close() 175 { 176 return "</form>"; 177 178 } 179 180 181 /** 182 * Render a country drop-down list. 183 * @param string $name 184 * @param string $value 185 * @param array $options 186 * @return string 187 */ 188 public function country($name, $value, $options=array()) 189 { 190 191 $arr = $this->getCountry(); 192 193 $placeholder = isset($options['placeholder']) ? $options['placeholder'] : ' '; 194 195 return $this->select($name, $arr, $value, $options, $placeholder); 196 } 197 198 199 /** 200 * Get a list of countries. 201 * @param null|string $iso ISO code. 202 * @return array|mixed|string 203 */ 204 public function getCountry($iso=null) // move to parser? 205 { 206 207 $c = array(); 208 209 $c['af'] = "Afghanistan"; 210 $c['al'] = "Albania"; 211 $c['dz'] = "Algeria"; 212 $c['as'] = "American Samoa"; 213 $c['ad'] = "Andorra"; 214 $c['ao'] = "Angola"; 215 $c['ai'] = "Anguilla"; 216 $c['aq'] = "Antarctica"; 217 $c['ag'] = "Antigua and Barbuda"; 218 $c['ar'] = "Argentina"; 219 $c['am'] = "Armenia"; 220 $c['aw'] = "Aruba"; 221 $c['au'] = "Australia"; 222 $c['at'] = "Austria"; 223 $c['az'] = "Azerbaijan"; 224 $c['bs'] = "Bahamas"; 225 $c['bh'] = "Bahrain"; 226 $c['bd'] = "Bangladesh"; 227 $c['bb'] = "Barbados"; 228 $c['by'] = "Belarus"; 229 $c['be'] = "Belgium"; 230 $c['bz'] = "Belize"; 231 $c['bj'] = "Benin"; 232 $c['bm'] = "Bermuda"; 233 $c['bt'] = "Bhutan"; 234 $c['bo'] = "Bolivia"; 235 $c['ba'] = "Bosnia-Herzegovina"; 236 $c['bw'] = "Botswana"; 237 $c['bv'] = "Bouvet Island"; 238 $c['br'] = "Brazil"; 239 $c['io'] = "British Indian Ocean Territory"; 240 $c['bn'] = "Brunei Darussalam"; 241 $c['bg'] = "Bulgaria"; 242 $c['bf'] = "Burkina Faso"; 243 $c['bi'] = "Burundi"; 244 $c['kh'] = "Cambodia"; 245 $c['cm'] = "Cameroon"; 246 $c['ca'] = "Canada"; 247 248 $c['cv'] = "Cape Verde"; 249 $c['ky'] = "Cayman Islands"; 250 $c['cf'] = "Central African Republic"; 251 $c['td'] = "Chad"; 252 $c['cl'] = "Chile"; 253 $c['cn'] = "China"; 254 $c['cx'] = "Christmas Island"; 255 $c['cc'] = "Cocos (Keeling) Islands"; 256 $c['co'] = "Colombia"; 257 $c['km'] = "Comoros"; 258 $c['cg'] = "Congo"; 259 $c['cd'] = "Congo (Dem.Rep)"; 260 $c['ck'] = "Cook Islands"; 261 $c['cr'] = "Costa Rica"; 262 $c['hr'] = "Croatia"; 263 $c['cu'] = "Cuba"; 264 $c['cy'] = "Cyprus"; 265 $c['cz'] = "Czech Republic"; 266 $c['dk'] = "Denmark"; 267 $c['dj'] = "Djibouti"; 268 $c['dm'] = "Dominica"; 269 $c['do'] = "Dominican Republic"; 270 $c['tp'] = "East Timor"; 271 $c['ec'] = "Ecuador"; 272 $c['eg'] = "Egypt"; 273 $c['sv'] = "El Salvador"; 274 $c['gq'] = "Equatorial Guinea"; 275 $c['er'] = "Eritrea"; 276 $c['ee'] = "Estonia"; 277 $c['et'] = "Ethiopia"; 278 $c['fk'] = "Falkland Islands"; 279 $c['fo'] = "Faroe Islands"; 280 $c['fj'] = "Fiji"; 281 $c['fi'] = "Finland"; 282 // $c['cs'] = "Former Czechoslovakia"; 283 // $c['su'] = "Former USSR"; 284 $c['fr'] = "France"; 285 // $c['fx'] = "France (European Territory)"; 286 $c['gf'] = "French Guyana"; 287 $c['tf'] = "French Southern Territories"; 288 $c['ga'] = "Gabon"; 289 $c['gm'] = "Gambia"; 290 $c['ge'] = "Georgia"; 291 $c['de'] = "Germany"; 292 $c['gh'] = "Ghana"; 293 $c['gi'] = "Gibraltar"; 294 $c['gr'] = "Greece"; 295 $c['gl'] = "Greenland"; 296 $c['gd'] = "Grenada"; 297 $c['gp'] = "Guadeloupe (French)"; 298 $c['gu'] = "Guam (USA)"; 299 $c['gt'] = "Guatemala"; 300 $c['gn'] = "Guinea"; 301 $c['gw'] = "Guinea Bissau"; 302 $c['gy'] = "Guyana"; 303 $c['ht'] = "Haiti"; 304 $c['hm'] = "Heard and McDonald Islands"; 305 $c['hn'] = "Honduras"; 306 $c['hk'] = "Hong Kong"; 307 $c['hu'] = "Hungary"; 308 $c['is'] = "Iceland"; 309 $c['in'] = "India"; 310 $c['id'] = "Indonesia"; 311 $c['ir'] = "Iran"; 312 $c['iq'] = "Iraq"; 313 $c['ie'] = "Ireland"; 314 $c['il'] = "Israel"; 315 $c['it'] = "Italy"; 316 $c['ci'] = "Ivory Coast (Cote D'Ivoire)"; 317 $c['jm'] = "Jamaica"; 318 $c['jp'] = "Japan"; 319 $c['jo'] = "Jordan"; 320 $c['kz'] = "Kazakhstan"; 321 $c['ke'] = "Kenya"; 322 $c['ki'] = "Kiribati"; 323 $c['kp'] = "Korea (North)"; 324 $c['kr'] = "Korea (South)"; 325 $c['kw'] = "Kuwait"; 326 $c['kg'] = "Kyrgyzstan"; 327 $c['la'] = "Laos"; 328 $c['lv'] = "Latvia"; 329 $c['lb'] = "Lebanon"; 330 $c['ls'] = "Lesotho"; 331 $c['lr'] = "Liberia"; 332 $c['ly'] = "Libya"; 333 $c['li'] = "Liechtenstein"; 334 $c['lt'] = "Lithuania"; 335 $c['lu'] = "Luxembourg"; 336 $c['mo'] = "Macau"; 337 $c['mk'] = "Macedonia"; 338 $c['mg'] = "Madagascar"; 339 $c['mw'] = "Malawi"; 340 $c['my'] = "Malaysia"; 341 $c['mv'] = "Maldives"; 342 $c['ml'] = "Mali"; 343 $c['mt'] = "Malta"; 344 $c['mh'] = "Marshall Islands"; 345 $c['mq'] = "Martinique (French)"; 346 $c['mr'] = "Mauritania"; 347 $c['mu'] = "Mauritius"; 348 $c['yt'] = "Mayotte"; 349 $c['mx'] = "Mexico"; 350 $c['fm'] = "Micronesia"; 351 $c['md'] = "Moldavia"; 352 $c['mc'] = "Monaco"; 353 $c['mn'] = "Mongolia"; 354 $c['me'] = "Montenegro"; 355 $c['ms'] = "Montserrat"; 356 $c['ma'] = "Morocco"; 357 $c['mz'] = "Mozambique"; 358 $c['mm'] = "Myanmar"; 359 $c['na'] = "Namibia"; 360 $c['nr'] = "Nauru"; 361 $c['np'] = "Nepal"; 362 $c['nl'] = "Netherlands"; 363 $c['an'] = "Netherlands Antilles"; 364 // $c['net'] = "Network"; 365 366 $c['nc'] = "New Caledonia (French)"; 367 $c['nz'] = "New Zealand"; 368 $c['ni'] = "Nicaragua"; 369 $c['ne'] = "Niger"; 370 $c['ng'] = "Nigeria"; 371 $c['nu'] = "Niue"; 372 $c['nf'] = "Norfolk Island"; 373 374 $c['mp'] = "Northern Mariana Islands"; 375 $c['no'] = "Norway"; 376 // $c['arpa'] = "Old style Arpanet"; 377 $c['om'] = "Oman"; 378 $c['pk'] = "Pakistan"; 379 $c['pw'] = "Palau"; 380 $c['pa'] = "Panama"; 381 $c['pg'] = "Papua New Guinea"; 382 $c['py'] = "Paraguay"; 383 $c['pe'] = "Peru"; 384 $c['ph'] = "Philippines"; 385 $c['pn'] = "Pitcairn Island"; 386 $c['pl'] = "Poland"; 387 $c['pf'] = "Polynesia (French)"; 388 $c['pt'] = "Portugal"; 389 $c['pr'] = "Puerto Rico"; 390 $c['ps'] = "Palestine"; 391 $c['qa'] = "Qatar"; 392 $c['re'] = "Reunion (French)"; 393 $c['ro'] = "Romania"; 394 $c['ru'] = "Russia"; 395 $c['rw'] = "Rwanda"; 396 $c['gs'] = "S. Georgia & S. Sandwich Isls."; 397 $c['sh'] = "Saint Helena"; 398 $c['kn'] = "Saint Kitts & Nevis"; 399 $c['lc'] = "Saint Lucia"; 400 $c['pm'] = "Saint Pierre and Miquelon"; 401 $c['st'] = "Saint Tome (Sao Tome) and Principe"; 402 $c['vc'] = "Saint Vincent & Grenadines"; 403 $c['ws'] = "Samoa"; 404 $c['sm'] = "San Marino"; 405 $c['sa'] = "Saudi Arabia"; 406 $c['sn'] = "Senegal"; 407 $c['rs'] = "Serbia"; 408 $c['sc'] = "Seychelles"; 409 $c['sl'] = "Sierra Leone"; 410 $c['sg'] = "Singapore"; 411 $c['sk'] = "Slovak Republic"; 412 $c['si'] = "Slovenia"; 413 $c['sb'] = "Solomon Islands"; 414 $c['so'] = "Somalia"; 415 $c['za'] = "South Africa"; 416 417 $c['es'] = "Spain"; 418 $c['lk'] = "Sri Lanka"; 419 $c['sd'] = "Sudan"; 420 $c['sr'] = "Suriname"; 421 $c['sj'] = "Svalbard and Jan Mayen Islands"; 422 $c['sz'] = "Swaziland"; 423 $c['se'] = "Sweden"; 424 $c['ch'] = "Switzerland"; 425 $c['sy'] = "Syria"; 426 $c['tj'] = "Tadjikistan"; 427 $c['tw'] = "Taiwan"; 428 $c['tz'] = "Tanzania"; 429 $c['th'] = "Thailand"; 430 $c['ti'] = "Tibet"; 431 $c['tg'] = "Togo"; 432 $c['tk'] = "Tokelau"; 433 $c['to'] = "Tonga"; 434 $c['tt'] = "Trinidad and Tobago"; 435 $c['tn'] = "Tunisia"; 436 $c['tr'] = "Turkey"; 437 $c['tm'] = "Turkmenistan"; 438 $c['tc'] = "Turks and Caicos Islands"; 439 $c['tv'] = "Tuvalu"; 440 $c['ug'] = "Uganda"; 441 $c['ua'] = "Ukraine"; 442 $c['ae'] = "United Arab Emirates"; 443 $c['gb'] = "United Kingdom"; 444 $c['us'] = "United States"; 445 $c['uy'] = "Uruguay"; 446 $c['um'] = "US Minor Outlying Islands"; 447 $c['uz'] = "Uzbekistan"; 448 $c['vu'] = "Vanuatu"; 449 $c['va'] = "Vatican City State"; 450 $c['ve'] = "Venezuela"; 451 $c['vn'] = "Vietnam"; 452 $c['vg'] = "Virgin Islands (British)"; 453 $c['vi'] = "Virgin Islands (USA)"; 454 $c['wf'] = "Wallis and Futuna Islands"; 455 $c['eh'] = "Western Sahara"; 456 $c['ye'] = "Yemen"; 457 458 // $c['zr'] = "(deprecated) Zaire"; 459 $c['zm'] = "Zambia"; 460 $c['zw'] = "Zimbabwe"; 461 462 463 if(!empty($iso) && !empty($c[$iso])) 464 { 465 return $c[$iso]; 466 } 467 468 469 return ($iso === null) ? $c : ''; 470 471 } 472 473 474 /** 475 * Get required field markup string 476 * @return string 477 */ 478 public function getRequiredString() 479 { 480 return $this->_required_string; 481 } 482 483 /** 484 * Set required field markup string 485 * @param string $string 486 * @return e_form 487 */ 488 public function setRequiredString($string) 489 { 490 $this->_required_string = $string; 491 return $this; 492 } 493 494 // For Comma separated keyword tags. 495 function tags($name, $value, $maxlength = 200, $options = array()) 496 { 497 if(is_string($options)) parse_str($options, $options); 498 499 $defaults['selectize'] = array( 500 'create' => true, 501 'maxItems' => vartrue($options['maxItems'], 7), 502 'mode' => 'multi', 503 'plugins' => array('remove_button'), 504 ); 505 506 $options = array_replace_recursive($defaults, $options); 507 508 return $this->text($name, $value, $maxlength, $options); 509 } 510 511 512 /** 513 * Render Bootstrap Tabs 514 * 515 * @param $array 516 * @param $options 517 * @return string 518 * @example 519 * $array = array( 520 * 'home' => array('caption' => 'Home', 'text' => 'some tab content' ), 521 * 'other' => array('caption' => 'Other', 'text' => 'second tab content' ) 522 * ); 523 */ 524 function tabs($array,$options = array()) 525 { 526 $initTab = varset($options['active'],false); 527 $id = !empty($options['id']) ? 'id="'.$options['id'].'"' : ''; 528 $text =' 529 <!-- Nav tabs --> 530 <ul '.$id.' class="nav nav-tabs">'; 531 532 $c = 0; 533 534 foreach($array as $key=>$tab) 535 { 536 537 if(is_numeric($key)) 538 { 539 $key = 'tab-'.$key; 540 } 541 542 if($c == 0 & $initTab == false) 543 { 544 $initTab = $key; 545 } 546 547 548 549 $active = ($key ==$initTab) ? ' class="nav-item active"' : ' class="nav-item"'; 550 $text .= '<li'.$active.'><a class="nav-link" href="#'.$key.'" data-toggle="tab">'.$tab['caption'].'</a></li>'; 551 $c++; 552 } 553 554 $text .= '</ul>'; 555 556 $initTab = varset($options['active'],false); 557 $tabClass = varset($options['class'],null); 558 559 $text .= ' 560 <!-- Tab panes --> 561 <div class="tab-content '.$tabClass.'">'; 562 563 $c=0; 564 foreach($array as $key=>$tab) 565 { 566 567 568 if(is_numeric($key)) 569 { 570 $key = 'tab-'.$key; 571 } 572 573 if($c == 0 & $initTab == false) 574 { 575 $initTab = $key; 576 } 577 578 $active = ($key == $initTab) ? ' active' : ''; 579 $text .= '<div class="tab-pane'.$active.'" id="'.$key.'">'.$tab['text'].'</div>'; 580 $c++; 581 } 582 583 $text .= ' 584 </div>'; 585 586 return $text; 587 588 } 589 590 591 /** 592 * Render Bootstrap Carousel 593 * @param string $name : A unique name 594 * @param array $array 595 * @param array $options : default, interval, pause, wrap, navigation, indicators 596 * @return string|array 597 * @example 598 * $array = array( 599 * 'slide1' => array('caption' => 'Slide 1', 'text' => 'first slide content' ), 600 * 'slide2' => array('caption' => 'Slide 2', 'text' => 'second slide content' ), 601 * 'slide3' => array('caption' => 'Slide 3', 'text' => 'third slide content' ) 602 * ); 603 */ 604 function carousel($name="e-carousel", $array=array(), $options = null) 605 { 606 $interval = null; 607 $wrap = null; 608 $pause = null; 609 $indicators = ''; 610 $controls = ''; 611 612 $act = varset($options['default'], 0); 613 614 if(isset($options['wrap'])) 615 { 616 $wrap = 'data-wrap="'.$options['wrap'].'"'; 617 } 618 619 if(isset($options['interval'])) 620 { 621 $interval = 'data-interval="'.$options['interval'].'"'; 622 } 623 624 if(isset($options['pause'])) 625 { 626 $pause = 'data-pause="'.$options['pause'].'"'; 627 } 628 629 $navigation = isset($options['navigation']) ? $options['navigation'] : true; 630 $indicate = isset($options['indicators']) ? $options['indicators'] : true; 631 632 633 $start =' 634 <!-- Carousel --> 635 636 <div id="'.$name.'" class="carousel slide" data-ride="carousel" '.$interval.' '.$wrap.' '.$pause.'>'; 637 638 if($indicate && (count($array) > 1)) 639 { 640 $indicators = ' 641 <!-- Indicators --> 642 <ol class="carousel-indicators"> 643 '; 644 645 $c = 0; 646 foreach($array as $key=>$tab) 647 { 648 $active = ($c == $act) ? ' class="active"' : ''; 649 $indicators .= '<li data-target="#'.$name.'" data-slide-to="'.$c.'" '.$active.'></li>'; 650 $c++; 651 } 652 653 $indicators .= ' 654 </ol>'; 655 } 656 657 $inner = ' 658 659 <div class="carousel-inner"> 660 '; 661 662 663 $c=0; 664 foreach($array as $key=>$tab) 665 { 666 $active = ($c == $act) ? ' active' : ''; 667 $label = !empty($tab['label']) ? ' data-label="'.$tab['label'].'"' : ''; 668 $inner .= '<div class="carousel-item item'.$active.'" id="'.$key.'"'.$label.'>'; 669 $inner .= $tab['text']; 670 671 if(!empty($tab['caption'])) 672 { 673 $inner .= '<div class="carousel-caption">'.$tab['caption'].'</div>'; 674 } 675 676 $inner .= '</div>'; 677 $c++; 678 } 679 680 $inner .= ' 681 </div>'; 682 683 if($navigation && (count($array) > 1)) 684 { 685 $controls = ' 686 <a class="left carousel-control carousel-left" href="#'.$name.'" role="button" data-slide="prev"> 687 <span class="glyphicon glyphicon-chevron-left"></span> 688 </a> 689 <a class="right carousel-control carousel-right" href="#'.$name.'" role="button" data-slide="next"> 690 <span class="glyphicon glyphicon-chevron-right"></span> 691 </a>'; 692 } 693 694 $end = '</div><!-- End Carousel -->'; 695 696 if(!empty($options['data'])) 697 { 698 return array( 699 'start' => $start, 700 'indicators' => $indicators, 701 'inner' => $inner, 702 'controls' => $controls, 703 'end' => $end 704 ); 705 } 706 707 return $start.$indicators.$inner.$controls.$end; // $text; 708 709 } 710 711 /** 712 * Same as $this->text() except it adds input validation for urls. 713 * At this stage, checking only for spaces. Should include sef-urls. 714 * 715 * @param string $name 716 * @param string $value 717 * @param int $maxlength 718 * @param array $options 719 * @return string 720 */ 721 function url($name, $value = '', $maxlength = 80, $options= array()) 722 { 723 $options['pattern'] = '^\S*$'; 724 return $this->text($name, $value, $maxlength, $options); 725 } 726 727 /** 728 * Text-Field Form Element 729 * @param $name 730 * @param $value 731 * @param $maxlength 732 * @param $options 733 * - size: mini, small, medium, large, xlarge, xxlarge 734 * - class: 735 * - typeahead: 'users' 736 * 737 * @return string 738 */ 739 function text($name, $value = '', $maxlength = 80, $options= array()) 740 { 741 if(is_string($options)) 742 { 743 parse_str($options,$options); 744 } 745 746 if(!vartrue($options['class'])) 747 { 748 $options['class'] = "tbox"; 749 } 750 751 if(deftrue('BOOTSTRAP')) 752 { 753 $options['class'] .= ' form-control'; 754 } 755 756 /* 757 if(!vartrue($options['class'])) 758 { 759 if($maxlength < 10) 760 { 761 $options['class'] = 'tbox input-text span3'; 762 } 763 764 elseif($maxlength < 50) 765 { 766 $options['class'] = 'tbox input-text span7'; 767 } 768 769 elseif($maxlength > 99) 770 { 771 $options['class'] = 'tbox input-text span7'; 772 } 773 else 774 { 775 $options['class'] = 'tbox input-text'; 776 } 777 } 778 */ 779 780 if(!empty($options['selectize'])) 781 { 782 e107::js('core', 'selectize/js/selectize.min.js', 'jquery'); 783 e107::css('core', 'selectize/css/selectize.css', 'jquery'); 784 785 // Load selectize behavior. 786 e107::js('core', 'selectize/js/selectize.init.js', 'jquery'); 787 788 $options['selectize']['wrapperClass'] = 'selectize-control'; 789 $options['selectize']['inputClass'] = 'form-control selectize-input '; 790 $options['selectize']['dropdownClass'] = 'selectize-dropdown'; 791 $options['selectize']['dropdownContentClass'] = 'selectize-dropdown-content'; 792 $options['selectize']['copyClassesToDropdown'] = true; 793 794 $jsSettings = array( 795 'id' => vartrue($options['id'], $this->name2id($name)), 796 'options' => $options['selectize'], 797 // Multilingual support. 798 'strings' => array( 799 'anonymous' => LAN_ANONYMOUS, 800 ), 801 ); 802 803 // Merge field settings with other selectize field settings. 804 e107::js('settings', array('selectize' => array($jsSettings))); 805 806 $options['class'] = ''; 807 } 808 809 // TODO: remove typeahead. 810 if(vartrue($options['typeahead'])) 811 { 812 if(vartrue($options['typeahead']) == 'users') 813 { 814 $options['data-source'] = e_BASE."user.php"; 815 $options['class'] .= " e-typeahead"; 816 } 817 } 818 819 if(vartrue($options['size']) && !is_numeric($options['size'])) 820 { 821 $options['class'] .= " input-".$options['size']; 822 unset($options['size']); // don't include in html 'size='. 823 } 824 825 $mlength = vartrue($maxlength) ? "maxlength=".$maxlength : ""; 826 827 $type = varset($options['type']) == 'email' ? 'email' : 'text'; // used by $this->email(); 828 829 $options = $this->format_options('text', $name, $options); 830 831 832 //never allow id in format name-value for text fields 833 return "<input type='".$type."' name='{$name}' value='{$value}' {$mlength} ".$this->get_attributes($options, $name)." />"; 834 } 835 836 837 /** 838 * Create a input [type number] 839 * 840 * Additional options: 841 * - decimals: default 0; defines the number of decimals allowed in this field (0 = only integers; 1 = integers & floats with 1 decimal e.g. 4.1, etc.) 842 * - step: default 1; defines the step for the spinner and the max. number of decimals. If decimals is given, step will be ignored 843 * - min: default 0; minimum value allowed 844 * - max: default empty; maximum value allowed 845 * - pattern: default empty; allows to define an complex input pattern 846 * 847 * @param string $name 848 * @param integer $value 849 * @param integer $maxlength 850 * @param array $options decimals, step, min, max, pattern 851 * @return string 852 */ 853 function number($name, $value=0, $maxlength = 200, $options = array()) 854 { 855 if(is_string($options)) parse_str($options, $options); 856 857 if(!empty($options['maxlength'])) 858 { 859 $maxlength = $options['maxlength']; 860 } 861 862 unset($options['maxlength']); 863 864 if(empty($options['size'])) 865 { 866 $options['size'] = 15; 867 } 868 if(empty($options['class'])) 869 { 870 $options['class'] = 'tbox number e-spinner input-small '; 871 } 872 873 if(!empty($options['size'])) 874 { 875 $options['class'] .= ' input-'.$options['size']; 876 unset($options['size']); 877 } 878 879 $options['class'] .= " form-control"; 880 $options['type'] ='number'; 881 882 // Not used anymore 883 //$mlength = vartrue($maxlength) ? "maxlength=".$maxlength : ""; 884 885 // Always define the min. parameter 886 // defaults to 0 887 // setting the min option to a negative value allows negative inputs 888 $min = " min='".vartrue($options['min'], '0')."'"; 889 $max = isset($options['max']) ? " max='".$options['max']."'" : ''; 890 891 892 if (empty($options['pattern'])) 893 { 894 $options['pattern'] = '^'; 895 // ^\-?[0-9]*\.?[0-9]{0,2} 896 if (varset($options['min'], 0) < 0) 897 { 898 $options['pattern'] .= '\-?'; 899 } 900 $options['pattern'] .= '[0-9]*'; 901 902 // Integer & Floaat/Double value handling 903 if (isset($options['decimals'])) 904 { 905 if (intval($options['decimals']) > 0) 906 { 907 $options['pattern'] .= '\.?[0-9]{0,'.intval($options['decimals']).'}'; 908 } 909 910 // defined the step based on number of decimals 911 // 2 = 0.01 > allows integers and float numbers with up to 2 decimals (3.1 = OK; 3.12 = OK; 3.123 = NOK) 912 // 1 = 0.1 > allows integers and float numbers with up to 2 decimals (3.1 = OK; 3.12 = NOK) 913 // 0 = 1 > allows only integers, no float values 914 if (intval($options['decimals']) <= 0) 915 { 916 $step = "step='1'"; 917 } 918 else 919 { 920 $step = "step='0." . str_pad(1, intval($options['decimals']), 0, STR_PAD_LEFT) . "'"; 921 } 922 } 923 else 924 { 925 // decimal option not defined 926 // check for step option (1, 0.1, 0.01, and so on) 927 // or set default step 1 (integers only) 928 $step = "step='" . vartrue($options['step'], '1') . "'"; 929 } 930 931 } 932 933 $options = $this->format_options('text', $name, $options); 934 935 //never allow id in format name-value for text fields 936 if(THEME_LEGACY === false) 937 { 938 // return "<input pattern='[0-9]*' type='number' name='{$name}' value='{$value}' {$mlength} {$step} {$min} {$max} ".$this->get_attributes($options, $name)." />"; 939 return "<input type='number' name='{$name}' {$min} {$max} {$step} value='{$value}' ".$this->get_attributes($options, $name)." />"; 940 } 941 942 return $this->text($name, $value, $maxlength, $options); 943 } 944 945 946 947 function email($name, $value, $maxlength = 200, $options = array()) 948 { 949 $options['type'] = 'email'; 950 return $this->text($name,$value,$maxlength,$options); 951 } 952 953 954 955 function iconpreview($id, $default, $width='', $height='') // FIXME 956 { 957 unset($width,$height); // quick fix 958 // XXX - $name ?! 959 // $parms = $name."|".$width."|".$height."|".$id; 960 $sc_parameters = 'mode=preview&default='.$default.'&id='.$id; 961 return e107::getParser()->parseTemplate("{ICONPICKER=".$sc_parameters."}"); 962 } 963 964 /** 965 * @param $name 966 * @param $default - value 967 * @param $label 968 * @param $options - gylphs=1 969 * @param $ajax 970 * @return string 971 */ 972 function iconpicker($name, $default, $label, $options = array(), $ajax = true) 973 { 974 //v2.2.0 975 unset($label,$ajax); // no longer used. 976 977 $options['icon'] = 1; 978 $options['glyph'] = 1; 979 $options['w'] = 64; 980 $options['h'] = 64; 981 $options['media'] = '_icon'; 982 983 if(!isset($options['legacyPath'])) 984 { 985 $options['legacyPath'] = "{e_IMAGE}icons"; 986 } 987 988 return $this->mediapicker($name, $default, $options); 989 990 991 /* $options['media'] = '_icon'; 992 $options['legacyPath'] = "{e_IMAGE}icons"; 993 994 return $this->imagepicker($name, $default, $label, $options);*/ 995 996 997 } 998 999 1000 /** 1001 * Internal Function used by imagepicker, filepicker, mediapicker() 1002 * @param string $category 1003 * @param string $label 1004 * @param string $tagid 1005 * @param null $extras 1006 * @return string 1007 */ 1008 public function mediaUrl($category = '', $label = '', $tagid='', $extras=null) 1009 { 1010 if(is_string($extras)) 1011 { 1012 parse_str($extras,$extras); 1013 } 1014 1015 $category = str_replace('+', '^', $category); // Bc Fix. 1016 1017 $cat = ($category) ? '&for='.urlencode($category) : ""; 1018 $mode = vartrue($extras['mode'],'main'); 1019 $action = vartrue($extras['action'],'dialog'); 1020 1021 1022 1023 if(empty($label)) 1024 { 1025 $label = ' Upload an image or file'; 1026 } 1027 1028 // TODO - option to choose which tabs to display by default. 1029 1030 $url = e_ADMIN_ABS."image.php?mode={$mode}&action={$action}".$cat; 1031 1032 if(!empty($tagid)) 1033 { 1034 $url .= '&tagid='.$tagid; 1035 } 1036 1037 if(!empty($extras['bbcode'])) 1038 { 1039 $url .= '&bbcode='.$extras['bbcode']; 1040 } 1041 1042 $url .= "&iframe=1"; 1043 1044 if(vartrue($extras['w'])) 1045 { 1046 $url .= "&w=".$extras['w']; 1047 } 1048 1049 if(!empty($extras['image'])) 1050 { 1051 $url .= "&image=1"; 1052 } 1053 1054 if(!empty($extras['glyphs']) || !empty($extras['glyph'])) 1055 { 1056 $url .= "&glyph=1"; 1057 } 1058 1059 if(!empty($extras['icons']) || !empty($extras['icon'])) 1060 { 1061 $url .= "&icon=1"; 1062 } 1063 1064 if(!empty($extras['youtube'])) 1065 { 1066 $url .= "&youtube=1"; 1067 } 1068 1069 if(!empty($extras['video'])) 1070 { 1071 $url .= ($extras['video'] == 2) ? "&video=2" : "&video=1"; 1072 } 1073 1074 if(!empty($extras['audio'])) 1075 { 1076 $url .= "&audio=1"; 1077 } 1078 1079 if(!empty($extras['path']) && $extras['path'] == 'plugin') 1080 { 1081 $url .= "&path=".deftrue('e_CURRENT_PLUGIN'); 1082 } 1083 1084 if(E107_DBG_BASIC) 1085 { 1086 1087 $title = "Media Manager : ".$category; 1088 } 1089 else 1090 { 1091 $title = LAN_EDIT; 1092 } 1093 1094 $class = !empty($extras['class']) ? $extras['class']." " : ''; 1095 $title = !empty($extras['title']) ? $extras['title'] : $title; 1096 1097 $ret = "<a title=\"{$title}\" class='".$class."e-modal' data-modal-submit='true' data-modal-caption='".LAN_EFORM_007."' data-cache='false' data-target='#uiModal' href='".$url."'>".$label."</a>"; // using bootstrap. 1098 1099 if(!e107::getRegistry('core/form/mediaurl')) 1100 { 1101 e107::setRegistry('core/form/mediaurl', true); 1102 } 1103 1104 return $ret; 1105 } 1106 1107 1108 /** 1109 * Avatar Picker 1110 * @param string $name - form element name ie. value to be posted. 1111 * @param string $curVal - current avatar value. ie. the image-file name or URL. 1112 * @param array $options 1113 * @todo add a pref for allowing external or internal avatars or both. 1114 * @return string 1115 */ 1116 function avatarpicker($name, $curVal='',$options=array()) 1117 { 1118 1119 $tp = e107::getParser(); 1120 $pref = e107::getPref(); 1121 1122 $attr = "aw=".$pref['im_width']."&ah=".$pref['im_height']; 1123 $tp->setThumbSize($pref['im_width'],$pref['im_height']); 1124 1125 $blankImg = $tp->thumbUrl(e_IMAGE."generic/blank_avatar.jpg",$attr); 1126 $localonly = true; 1127 $idinput = $this->name2id($name); 1128 $previnput = $idinput."-preview"; 1129 $optioni = $idinput."-options"; 1130 1131 1132 $path = (substr($curVal,0,8) == '-upload-') ? '{e_AVATAR}upload/' : '{e_AVATAR}default/'; 1133 $newVal = str_replace('-upload-','',$curVal); 1134 1135 $img = (strpos($curVal,"://")!==false) ? $curVal : $tp->thumbUrl($path.$newVal); 1136 1137 if(!$curVal) 1138 { 1139 $img = $blankImg; 1140 } 1141 1142 $parm = $options; 1143 $classlocal = (!empty($parm['class'])) ? "class='".$parm['class']." e-expandit e-tip avatar'" : " class='img-rounded rounded e-expandit e-tip avatar "; 1144 $class = (!empty($parm['class'])) ? "class='".$parm['class']." e-expandit '" : " class='img-rounded rounded btn btn-default btn-secondary button e-expandit "; 1145 1146 if($localonly == true) 1147 { 1148 $text = "<input class='tbox' style='width:80%' id='{$idinput}' type='hidden' name='image' value='{$curVal}' />"; 1149 $text .= "<img src='".$img."' id='{$previnput}' ".$classlocal." style='cursor:pointer; width:".$pref['im_width']."px; height:".$pref['im_height']."px' title='".LAN_EFORM_001."' alt='".LAN_EFORM_001."' />"; 1150 } 1151 else 1152 { 1153 $text = "<input class='tbox' style='width:80%' id='{$idinput}' type='text' name='image' size='40' value='$curVal' maxlength='100' title=\"".LAN_SIGNUP_111."\" />"; 1154 $text .= "<img src='".$img."' id='{$previnput}' style='display:none' />"; 1155 $text .= "<input ".$class." type ='button' style='cursor:pointer' size='30' value=\"".LAN_EFORM_002."\" />"; 1156 } 1157 1158 $avFiles = e107::getFile()->get_files(e_AVATAR_DEFAULT,".jpg|.png|.gif|.jpeg|.JPG|.GIF|.PNG"); 1159 1160 $text .= "\n<div id='{$optioni}' style='display:none;padding:10px' >\n"; //TODO unique id. 1161 $count = 0; 1162 if (vartrue($pref['avatar_upload']) && FILE_UPLOADS && vartrue($options['upload'])) 1163 { 1164 $diz = LAN_USET_32.($pref['im_width'] || $pref['im_height'] ? "\n".str_replace(array('[x]-','[y]'), array($pref['im_width'], $pref['im_height']), LAN_USER_86) : ""); 1165 1166 $text .= "<div style='margin-bottom:10px'>".LAN_USET_26." 1167 <input class='tbox' name='file_userfile[avatar]' type='file' size='47' title=\"{$diz}\" /> 1168 </div>"; 1169 1170 if(count($avFiles) > 0) 1171 { 1172 $text .= "<div class='divider'><span>".LAN_EFORM_003."</span></div>"; 1173 $count = 1; 1174 } 1175 } 1176 1177 1178 foreach($avFiles as $fi) 1179 { 1180 $img_path = $tp->thumbUrl(e_AVATAR_DEFAULT.$fi['fname']); 1181 $text .= "\n<a class='e-expandit' title='".LAN_EFORM_004."' href='#{$optioni}'><img src='".$img_path."' alt='' onclick=\"insertext('".$fi['fname']."', '".$idinput."');document.getElementById('".$previnput."').src = this.src;return false\" /></a> "; 1182 $count++; 1183 1184 1185 //TODO javascript CSS selector 1186 } 1187 1188 if($count == 0) 1189 { 1190 $text .= "<div class='row'>"; 1191 $text .= "<div class='alert alert-info'>".LAN_EFORM_005."</div>"; 1192 1193 if(ADMIN) 1194 { 1195 $EAVATAR = e_AVATAR_DEFAULT; 1196 $text .= "<div class='alert alert-danger'>"; 1197 $text .= e107::getParser()->lanVars(e107::getParser()->toHTML(LAN_EFORM_006, true), array('x'=>$EAVATAR)); 1198 $text .= "</div>"; 1199 } 1200 1201 $text .= "</div>"; 1202 } 1203 1204 1205 $text .= " 1206 </div>"; 1207 1208 // Used by usersettings.php right now. 1209 1210 1211 1212 1213 1214 1215 1216 return $text; 1217 /* 1218 //TODO discuss and FIXME 1219 // Intentionally disable uploadable avatar and photos at this stage 1220 if (false && $pref['avatar_upload'] && FILE_UPLOADS) 1221 { 1222 $text .= "<br /><span class='smalltext'>".LAN_SIGNUP_25."</span> <input class='tbox' name='file_userfile[]' type='file' size='40' /> 1223 <br /><div class='smalltext'>".LAN_SIGNUP_34."</div>"; 1224 } 1225 1226 if (false && $pref['photo_upload'] && FILE_UPLOADS) 1227 { 1228 $text .= "<br /><span class='smalltext'>".LAN_SIGNUP_26."</span> <input class='tbox' name='file_userfile[]' type='file' size='40' /> 1229 <br /><div class='smalltext'>".LAN_SIGNUP_34."</div>"; 1230 } */ 1231 } 1232 1233 1234 /** 1235 * Image Picker 1236 * 1237 * @param string $name input name 1238 * @param string $default default value 1239 * @param string $previewURL 1240 * @param string $sc_parameters shortcode parameters 1241 * --- SC Parameter list --- 1242 * - media: if present - load from media category table 1243 * - w: preview width in pixels 1244 * - h: preview height in pixels 1245 * - help: tooltip 1246 * - video: when set to true, will enable the Youtube (video) tab. 1247 * @return string html output 1248 * @example $frm->imagepicker('banner_image', $_POST['banner_image'], '', 'banner'); // all images from category 'banner_image' + common images. 1249 * @example $frm->imagepicker('banner_image', $_POST['banner_image'], '', 'media=banner&w=600'); 1250 */ 1251 function imagepicker($name, $default, $previewURL = '', $sc_parameters = '') 1252 { 1253 1254 // $tp = e107::getParser(); 1255 1256 // $name_id = $this->name2id($name); 1257 // $meta_id = $name_id."-meta"; 1258 1259 if(is_string($sc_parameters)) 1260 { 1261 if(strpos($sc_parameters, '=') === false) $sc_parameters = 'media='.$sc_parameters; 1262 parse_str($sc_parameters, $sc_parameters); 1263 } 1264 elseif(empty($sc_parameters)) 1265 { 1266 $sc_parameters = array(); 1267 } 1268 1269 // $cat = $tp->toDB(vartrue($sc_parameters['media'])); 1270 1271 // v2.2.0 1272 unset($previewURL ); 1273 $sc_parameters['image'] = 1; 1274 $sc_parameters['dropzone'] = 1; 1275 if(!empty($sc_parameters['video'])) // bc fix 1276 { 1277 $sc_parameters['youtube'] = 1; 1278 } 1279 1280 return $this->mediapicker($name, $default, $sc_parameters); 1281 1282 1283 } 1284 1285 1286/** 1287 * Media Picker 1288 * 1289 1290 * @param string $name input name 1291 * @param string $default default value 1292 * @param string $parms shortcode parameters 1293 * --- $parms list --- 1294 * - media: if present - load from media category table 1295 * - w: preview width in pixels 1296 * - h: preview height in pixels 1297 * - help: tooltip 1298 * - youtube=1 (Enables the Youtube tab) 1299 * - image=1 (Enable the Images tab) 1300 * - video=1 (Enable the Video tab) 1301 * - audio=1 (Enable the Audio tab) 1302 * - glyph=1 (Enable the Glyphs tab). 1303 * - path=plugin (store in media/plugins/{current-plugin]) 1304 * - edit=false (disable media-manager popup button) 1305 * - rename (string) rename file to this value after upload. (don't forget the extension) 1306 * - resize array with numberic x values. (array 'w'=>x, 'h'=>x) - resize the uploaded image before importing during upload. 1307 * - convert=jpg (override pref and convert uploaded image to jpeg format. ) 1308 * @return string html output 1309 *@example $frm->imagepicker('banner_image', $_POST['banner_image'], '', 'media=banner&w=600'); 1310 */ 1311 function mediapicker($name, $default, $parms = '') 1312 { 1313 1314 1315 $tp = e107::getParser(); 1316 $name_id = $this->name2id($name); 1317 $meta_id = $name_id."-meta"; 1318 1319 if(is_string($parms)) 1320 { 1321 if(strpos($parms, '=') === false) $parms = 'media='.$parms; 1322 parse_str($parms, $parms); 1323 } 1324 elseif(empty($parms)) 1325 { 1326 $parms = array(); 1327 } 1328 1329 1330 if(empty($parms['media'])) 1331 { 1332 $parms['media'] = '_common'; 1333 } 1334 1335 $title = !empty($parms['help']) ? "title='".$parms['help']."'" : ""; 1336 1337 if(!isset($parms['w'])) 1338 { 1339 $parms['w'] = 206; 1340 } 1341 1342 if(!isset($parms['h'])) 1343 { 1344 $parms['h'] = 190; // 178 1345 } 1346 1347 // $width = vartrue($parms['w'], 220); 1348 // $height = vartrue($parms['h'], 190); 1349 // e107::getDebug()->log($parms); 1350 1351 // Test Files... 1352 // $default = '{e_MEDIA_VIDEO}2018-07/samplevideo_720x480_2mb.mp4'; 1353 // $default = '{e_MEDIA_FILE}2016-03/Colony_Harry_Gregson_Williams.mp3'; 1354 // $default = '{e_PLUGIN}gallery/images/butterfly.jpg'; 1355 // $default = 'NuIAYHVeFYs.youtube'; 1356 // $default = ''; // empty 1357 // $default = '{e_MEDIA_IMAGE}2018-07/Jellyfish.jpg'; 1358 1359 $class = ''; 1360 1361 if(!empty($parms['icon'])) 1362 { 1363 $class = 'icon-preview mediaselector-container-icon'; 1364 $parms['type'] = 'icon'; 1365 } 1366 1367 $preview = e107::getMedia()->previewTag($default,$parms); 1368 1369 $cat = $tp->toDB(vartrue($parms['media'])); 1370 1371 $ret = "<div class='mediaselector-container e-tip well well-small ".$class."' {$title} style='position:relative;vertical-align:top;margin-right:15px; display:inline-block; width:".$parms['w']."px;min-height:".$parms['h']."px;'>"; 1372 1373 $parms['class'] = 'btn btn-sm btn-default'; 1374 1375 $dropzone = !empty($parms['dropzone']) ? " dropzone" : ""; 1376 // $parms['modal-delete-label'] = LAN_DELETE; 1377 1378 if(empty($preview)) 1379 { 1380 $parms['title'] = LAN_ADD; 1381 $editIcon = $this->mediaUrl($cat, $tp->toGlyph('fa-plus', array('fw'=>1)), $name_id,$parms); 1382 $previewIcon = ''; 1383 } 1384 else 1385 { 1386 $editIcon = $this->mediaUrl($cat, $tp->toGlyph('fa-edit', array('fw'=>1)), $name_id,$parms); 1387 // $previewIcon = "<a title='".LAN_PREVIEW."' class='btn btn-sm btn-default btn-secondary e-modal' data-modal-caption='".LAN_PREVIEW."' href='".$previewURL."'>".$tp->toGlyph('fa-search', array('fw'=>1))."</a>"; 1388 $previewIcon = ''; 1389 } 1390 1391 if(isset($parms['edit']) && $parms['edit'] === false) // remove media-manager add/edit button. ie. drag-n-drop only. 1392 { 1393 $editIcon = ''; 1394 } 1395 1396 1397 if(!empty($parms['icon'])) // empty overlay without button. 1398 { 1399 $parms['class'] = ''; 1400 $editIcon = $this->mediaUrl($cat, "<span><!-- --></span>", $name_id,$parms); 1401 } 1402 1403 $ret .= "<div id='{$name_id}_prev' class='mediaselector-preview".$dropzone."'>"; 1404 1405 $ret .= $preview; // image, video. audio tag etc. 1406 1407 $ret .= '</div><div class="overlay"> 1408 <div class="text">'.$editIcon.$previewIcon.'</div> 1409 </div>'; 1410 1411 $ret .= "</div>\n"; 1412 $ret .= "<input type='hidden' name='{$name}' id='{$name_id}' value='{$default}' />"; 1413 $ret .= "<input type='hidden' name='mediameta_{$name}' id='{$meta_id}' value='' />"; 1414 1415 if(empty($dropzone)) 1416 { 1417 return $ret; 1418 } 1419 1420 if(!isset($parms['label'])) 1421 { 1422 $parms['label'] = defset('LAN_UI_DROPZONE_DROP_FILES', "Drop files here to upload"); 1423 } 1424 1425 $qry = "for=".$cat; 1426 1427 if(!empty($parms['path']) && $parms['path'] == 'plugin') 1428 { 1429 $qry .= "&path=".deftrue('e_CURRENT_PLUGIN'); 1430 } 1431 1432 if(!empty($parms['rename'])) 1433 { 1434 $qry .= "&rename=".$parms['rename']; 1435 } 1436 1437 if(!empty($parms['convert'])) 1438 { 1439 $qry .= "&convert=".$parms['convert']; 1440 } 1441 1442 if(isset($parms['w'])) 1443 { 1444 $qry .= "&w=".(int) $parms['w']; 1445 } 1446 1447 if(isset($parms['h'])) 1448 { 1449 $qry .= "&h=".(int) $parms['h']; 1450 } 1451 1452 if(!empty($parms['resize'])) 1453 { 1454 $resize = array('resize'=>$parms['resize']); 1455 $qry .= "&".http_build_query($resize); 1456 } 1457 1458 1459 // Drag-n-Drop Upload 1460 // @see https://www.dropzonejs.com/#server-side-implementation 1461 1462 e107::js('footer', e_WEB_ABS."lib/dropzone/dropzone.min.js"); 1463 e107::css('url', e_WEB_ABS."lib/dropzone/dropzone.min.css"); 1464 e107::css('inline', " 1465 .dropzone { background: transparent; border:0 } 1466 "); 1467 1468 1469 1470 $INLINEJS = " 1471 Dropzone.autoDiscover = false; 1472 $(function() { 1473 $('#".$name_id."_prev').dropzone({ 1474 url: '".e_JS."plupload/upload.php?".$qry."', 1475 createImageThumbnails: false, 1476 uploadMultiple :false, 1477 dictDefaultMessage: \"".$parms['label']."\", 1478 maxFilesize: ".(int) ini_get('upload_max_filesize').", 1479 success: function (file, response) { 1480 1481 file.previewElement.classList.add('dz-success'); 1482 1483 // console.log(response); 1484 1485 if(response) 1486 { 1487 var decoded = jQuery.parseJSON(response); 1488 console.log(decoded); 1489 if(decoded.preview && decoded.result) 1490 { 1491 $('#".$name_id."').val(decoded.result); 1492 $('#".$name_id."_prev').html(decoded.preview); 1493 } 1494 else if(decoded.error) 1495 { 1496 file.previewElement.classList.add('dz-error'); 1497 $('#".$name_id."_prev').html(decoded.error.message); 1498 } 1499 } 1500 1501 }, 1502 error: function (file, response) { 1503 file.previewElement.classList.add('dz-error'); 1504 } 1505 }); 1506 }); 1507 1508 "; 1509 1510 1511 e107::js('footer-inline', $INLINEJS); 1512 1513 return $ret; 1514 1515 } 1516 1517 1518 1519 /** 1520 * File Picker 1521 * 1522 * @param string name eg. 'myfield' or 'myfield[]' 1523 * @param mixed default 1524 * @param string label 1525 * @param mixed sc_parameters 1526 * @return string 1527 */ 1528 function filepicker($name, $default, $label = '', $sc_parameters = null) 1529 { 1530 $tp = e107::getParser(); 1531 $name_id = $this->name2id($name); 1532 unset($label); 1533 1534 if(is_string($sc_parameters)) 1535 { 1536 if(strpos($sc_parameters, '=') === false) $sc_parameters = 'media='.$sc_parameters; 1537 parse_str($sc_parameters, $sc_parameters); 1538 } 1539 1540 $cat = vartrue($sc_parameters['media']) ? $tp->toDB($sc_parameters['media']) : "_common_file"; 1541 1542 $ret = ''; 1543 1544 if($sc_parameters['data'] === 'array') 1545 { 1546 // Do not use $this->hidden() method - as it will break 'id' value. 1547 $ret .= "<input type='hidden' name='".$name."[path]' id='".$this->name2id($name."[path]")."' value='".varset($default['path'])."' />"; 1548 $ret .= "<input type='hidden' name='".$name."[name]' id='".$this->name2id($name."[name]")."' value='".varset($default['name'])."' />"; 1549 $ret .= "<input type='hidden' name='".$name."[id]' id='".$this->name2id($name."[id]")."' value='".varset($default['id'])."' />"; 1550 1551 $default = $default['path']; 1552 } 1553 else 1554 { 1555 $ret .= "<input type='hidden' name='{$name}' id='{$name_id}' value='{$default}' style='width:400px' />"; 1556 } 1557 1558 1559 $default_label = ($default) ? $default : LAN_CHOOSE_FILE; 1560 $label = "<span id='{$name_id}_prev' class='btn btn-default btn-secondary btn-small'>".basename($default_label)."</span>"; 1561 1562 $sc_parameters['mode'] = 'main'; 1563 $sc_parameters['action'] = 'dialog'; 1564 1565 1566 // $ret .= $this->mediaUrl($cat, $label,$name_id,"mode=dialog&action=list"); 1567 $ret .= $this->mediaUrl($cat, $label,$name_id,$sc_parameters); 1568 1569 1570 1571 1572 return $ret; 1573 1574 1575 } 1576 1577 1578 1579 1580 /** 1581 * Date field with popup calendar // NEW in 0.8/2.0 1582 * on Submit returns unix timestamp or string value. 1583 * @param string $name the name of the field 1584 * @param int|bool $datestamp UNIX timestamp - default value of the field 1585 * @param array|string { 1586 * @type string mode date or datetime 1587 * @type string format strftime format eg. '%Y-%m-%d' 1588 * @type string timezone eg. 'America/Los_Angeles' - intended timezone of the date/time entered. (offsets UTC value) 1589 * } 1590 * @example $frm->datepicker('my_field',time(),'mode=date'); 1591 * @example $frm->datepicker('my_field',time(),'mode=datetime&inline=1'); 1592 * @example $frm->datepicker('my_field',time(),'mode=date&format=yyyy-mm-dd'); 1593 * @example $frm->datepicker('my_field',time(),'mode=datetime&format=MM, dd, yyyy hh:ii'); 1594 * @example $frm->datepicker('my_field',time(),'mode=datetime&return=string'); 1595 * 1596 * @url http://trentrichardson.com/examples/timepicker/ 1597 * @return string 1598 */ 1599 function datepicker($name, $datestamp = false, $options = null) 1600 { 1601 if(!empty($options) && is_string($options)) 1602 { 1603 parse_str($options,$options); 1604 } 1605 1606 $mode = !empty($options['mode']) ? trim($options['mode']) : "date"; // OR 'datetime' 1607 1608 if(!empty($options['type'])) /** BC Fix. 'type' is @deprecated */ 1609 { 1610 $mode = trim($options['type']); 1611 } 1612 1613 $dateFormat = !empty($options['format']) ? trim($options['format']) :e107::getPref('inputdate', '%Y-%m-%d'); 1614 $ampm = (preg_match("/%l|%I|%p|%P/",$dateFormat)) ? 'true' : 'false'; 1615 $value = null; 1616 $hiddenValue = null; 1617 $useUnix = (isset($options['return']) && ($options['return'] === 'string')) ? 'false' : 'true'; 1618 $id = !empty($options['id']) ? $options['id'] : $this->name2id($name); 1619 $classes = array('date' => 'tbox e-date', 'datetime' => 'tbox e-datetime'); 1620 1621 if($mode == 'datetime' && !varset($options['format'])) 1622 { 1623 $dateFormat .= " ".e107::getPref('inputtime', '%H:%M:%S'); 1624 } 1625 1626 $dformat = e107::getDate()->toMask($dateFormat); 1627 1628 // If default value is set. 1629 if ($datestamp && $datestamp !='0000-00-00') // date-field support. 1630 { 1631 if(!is_numeric($datestamp)) 1632 { 1633 $datestamp = strtotime($datestamp); 1634 } 1635 1636 // Convert date to proper (selected) format. 1637 $hiddenValue = $value = e107::getDate()->convert_date($datestamp, $dformat); 1638 1639 if ($useUnix === 'true') 1640 { 1641 $hiddenValue = $datestamp; 1642 } 1643 } 1644 1645 $class = (isset($classes[$mode])) ? $classes[$mode] : "tbox e-date"; 1646 $size = !empty($options['size']) ? intval($options['size']) : 40; 1647 $required = !empty($options['required']) ? "required" : ""; 1648 $firstDay = isset($options['firstDay']) ? $options['firstDay'] : 0; 1649 $xsize = (!empty($options['size']) && !is_numeric($options['size'])) ? $options['size'] : 'xlarge'; 1650 $disabled = !empty($options['disabled']) ? "disabled" : ""; 1651 $placeholder = !empty($options['placeholder']) ? 'placeholder="'.$options['placeholder'].'"' : ''; 1652 $timezone = ''; 1653 1654 1655 1656 if(!empty($options['timezone'])) // since datetimepicker does not support timezones and assumes the browser timezone is the intended timezone. 1657 { 1658 date_default_timezone_set($options['timezone']); 1659 $targetOffset = date('Z'); 1660 date_default_timezone_set(USERTIMEZONE); 1661 $timezone = "data-date-timezone-offset='".$targetOffset."'"; 1662 } 1663 1664 $text = ""; 1665 1666 if(!empty($options['inline'])) 1667 { 1668 $text .= "<div class='{$class}' id='inline-{$id}' data-date-format='{$dformat}' data-date-ampm='{$ampm}' data-date-firstday='{$firstDay}'></div>"; 1669 $text .= "<input type='hidden' name='{$name}' id='{$id}' value='{$value}' data-date-format='{$dformat}' data-date-ampm='{$ampm}' data-date-firstday='{$firstDay}' />"; 1670 } 1671 else 1672 { 1673 $text .= "<input class='{$class} input-".$xsize." form-control' type='text' size='{$size}' id='e-datepicker-{$id}' value='{$value}' data-date-unix ='{$useUnix}' data-date-format='{$dformat}' data-date-ampm='{$ampm}' data-date-language='".e_LAN."' data-date-firstday='{$firstDay}' {$required} {$disabled} {$placeholder} {$timezone} />"; 1674 $ftype = (!empty($options['debug'])) ? 'text' : 'hidden'; 1675 $text .= "<input type='{$ftype}' name='{$name}' id='{$id}' value='{$hiddenValue}' />"; 1676 } 1677 1678 // TODO use Library Manager... 1679 e107::css('core', 'bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css', 'jquery'); 1680 e107::js('footer', '{e_WEB}js/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js', 'jquery', 4); 1681 e107::js('footer', '{e_WEB}js/bootstrap-datetimepicker/js/bootstrap-datetimepicker.init.js', 'jquery', 5); 1682 1683 if(e_LANGUAGE !== 'English') 1684 { 1685 e107::js('footer-inline', e107::getDate()->buildDateLocale()); 1686 } 1687 1688 return $text; 1689 } 1690 1691 1692 /** 1693 * Render a simple user dropdown list. 1694 * @param string $name - form field name 1695 * @param null $val - current value 1696 * @param array $options 1697 * @param string 'group' if == 'class' then users will be sorted into userclass groups. 1698 * @type string 'fields' 1699 * @type string 'classes' - single or comma-separated list of user-classes members to include. 1700 * @type string 'excludeSelf' = exlude logged in user from list. 1701 * @type string 'return' if == 'array' an array is returned. 1702 * @type string 'return' if == 'sqlWhere' an sql query is returned. 1703 * @return string|array select form element. 1704 */ 1705 public function userlist($name, $val=null, $options=array()) 1706 { 1707 1708 $fields = (!empty($options['fields'])) ? $options['fields'] : "user_id,user_name,user_class"; 1709 $class = (!empty($options['classes'])) ? $options['classes'] : e_UC_MEMBER ; // all users sharing the same class as the logged-in user. 1710 1711 $class = str_replace(" ","",$class); 1712 1713 switch ($class) 1714 { 1715 case e_UC_ADMIN: 1716 $where = "user_admin = 1"; 1717 $classList = e_UC_ADMIN; 1718 break; 1719 1720 case e_UC_MEMBER: 1721 $where = "user_ban = 0"; 1722 $classList = e_UC_MEMBER; 1723 break; 1724 1725 case e_UC_NOBODY: 1726 return ""; 1727 break; 1728 1729 case 'matchclass': 1730 $where = "user_class REGEXP '(^|,)(".str_replace(",","|", USERCLASS).")(,|$)'"; 1731 $classList = USERCLASS; 1732 $clist = explode(",",USERCLASS); 1733 if(count($clist) > 1 && !isset($options['group'])) // group classes by default if more than one found. 1734 { 1735 $options['group'] = 'class'; 1736 } 1737 break; 1738 1739 default: 1740 $where = "user_class REGEXP '(^|,)(".str_replace(",","|", $class).")(,|$)'"; 1741 $classList = $class; 1742 break; 1743 } 1744 1745 1746 if(!empty($options['return']) && $options['return'] == 'sqlWhere') // can be used by user.php ajax method.. 1747 { 1748 return $where; 1749 } 1750 1751 $users = e107::getDb()->retrieve("user",$fields, "WHERE ".$where." ORDER BY user_name LIMIT 1000",true); 1752 1753 if(empty($users)) 1754 { 1755 return LAN_UNAVAILABLE; 1756 } 1757 1758 $opt = array(); 1759 1760 if(!empty($options['group']) && $options['group'] == 'class') 1761 { 1762 $classes = explode(',',$classList); 1763 1764 foreach($classes as $cls) 1765 { 1766 $cname = e107::getUserClass()->getName($cls); 1767 1768 $cname = str_replace('_',' ', trim($cname)); 1769 foreach($users as $u) 1770 { 1771 $uclass = explode(',',$u['user_class']); 1772 1773 if(($classList == e_UC_ADMIN) || ($classList == e_UC_MEMBER) || in_array($cls,$uclass)) 1774 { 1775 $id = $u['user_id']; 1776 1777 if(!empty($options['excludeSelf']) && ($id == USERID)) 1778 { 1779 continue; 1780 } 1781 1782 $opt[$cname][$id] = $u['user_name']; 1783 } 1784 } 1785 1786 1787 } 1788 1789 } 1790 else 1791 { 1792 foreach($users as $u) 1793 { 1794 $id = $u['user_id']; 1795 $opt[$id] = $u['user_name']; 1796 } 1797 1798 } 1799 1800 1801 ksort($opt); 1802 1803 1804 if(!empty($options['return']) && $options['return'] == 'array') // can be used by user.php ajax method.. 1805 { 1806 return $opt; 1807 } 1808 1809 return $this->select($name,$opt,$val,$options, varset($options['default'],null)); 1810 1811 } 1812 1813 1814 1815 /** 1816 * User auto-complete search 1817 * XXX EXPERIMENTAL - subject to change. 1818 * @param string $name_fld field name for user name 1819 * @param string $id_fld field name for user id 1820 * @param string $default_name default user name value 1821 * @param integer $default_id default user id 1822 * @param array|string $options [optional] 'readonly' (make field read only), 'name' (db field name, default user_name) 1823 * @return string HTML text for display 1824 */ 1825 /* 1826 function userpicker($name_fld, $id_fld='', $default_name, $default_id, $options = array()) 1827 { 1828 if(!is_array($options)) 1829 { 1830 parse_str($options, $options); 1831 } 1832 1833 $default_name = vartrue($default_name, ''); 1834 $default_id = vartrue($default_id, ''); 1835 1836 $default_options = array(); 1837 if (!empty($default_name)) 1838 { 1839 $default_options = array( 1840 array( 1841 'value' => $default_id, 1842 'label' => $default_name, 1843 ), 1844 ); 1845 } 1846 1847 $defaults['selectize'] = array( 1848 'loadPath' => e_BASE . 'user.php', 1849 'create' => false, 1850 'maxItems' => 1, 1851 'mode' => 'multi', 1852 'options' => $default_options, 1853 ); 1854 1855 //TODO FIXME Filter by userclass. - see $frm->userlist(). 1856 1857 $options = array_replace_recursive($defaults, $options); 1858 1859 $ret = $this->text($name_fld, $default_id, 20, $options); 1860 1861 return $ret; 1862 } 1863 */ 1864 1865 1866 /** 1867 * User Field - auto-complete search 1868 * @param string $name form element name 1869 * @param string|array $value comma separated list of user ids or array of userid=>username pairs. 1870 * @param array|string $options [optional] 1871 * @type int 'limit' Maximum number of users 1872 * @type string 'id' Custom id 1873 * @type string 'inline' Inline ID. 1874 * 1875 * @example $frm->userpicker('author', 1); 1876 * @example $frm->userpicker('authors', "1,2,3"); 1877 * @example $frm->userpicker('author', array('user_id'=>1, 'user_name'=>'Admin'); 1878 * @example $frm->userpicker('authors', array(0=>array('user_id'=>1, 'user_name'=>'Admin', 1=>array('user_id'=>2, 'user_name'=>'John')); 1879 * 1880 * @todo $options['type'] = 'select' - dropdown selections box with data returned as array instead of comma-separated. 1881 * @return string HTML text for display 1882 */ 1883 function userpicker($name, $value, $options = array()) 1884 { 1885 if(!is_array($options)) 1886 { 1887 parse_str($options, $options); 1888 } 1889 1890 $defaultItems = array(); 1891 1892 if(is_array($value)) 1893 { 1894 if(isset($value[0]))// multiple users. 1895 { 1896 foreach($value as $val) 1897 { 1898 $defaultItems[] = array('value'=>$val['user_id'], 'label'=>$val['user_name']); 1899 } 1900 1901 } 1902 else // single user 1903 { 1904 $defaultItems[] = array('value'=>$value['user_id'], 'label'=>$value['user_name']); 1905 } 1906 1907 } 1908 elseif(!empty($value)) /// comma separated with user-id lookup. 1909 { 1910 $tmp = explode(",", $value); 1911 foreach($tmp as $uid) 1912 { 1913 if($user = e107::user($uid)) 1914 { 1915 $defaultItems[] = array('value'=>$user['user_id'], 'label'=>$user['user_name']); 1916 } 1917 } 1918 } 1919 1920 $parms = array( 1921 'selectize' => array( 1922 'loadPath' => e_HTTP.'user.php', 1923 'create' => false, 1924 'maxItems' => 1, 1925 'mode' => 'multi', 1926 'options' => $defaultItems 1927 ) 1928 ); 1929 1930 if(!empty($options['limit'])) 1931 { 1932 $parms['selectize']['maxItems'] = intval($options['limit']); 1933 } 1934 1935 if(!empty($options['id'])) 1936 { 1937 $parms['id'] = $options['id']; 1938 } 1939 1940 if(!empty($options['inline'])) 1941 { 1942 $parms['selectize']['e_editable'] = $options['inline']; 1943 } 1944 1945 //TODO FIXME Filter by userclass. - see $frm->userlist(). 1946 1947 $defValues = array(); 1948 1949 foreach($defaultItems as $val) 1950 { 1951 $defValues[] = $val['value']; 1952 } 1953 1954 $parms = array_merge($parms, $options); 1955 1956 return $this->text($name, implode(",",$defValues), 100, $parms); 1957 1958 } 1959 1960 1961 /** 1962 * A Rating element 1963 * 1964 * @param string $table 1965 * @param int $id 1966 * @param array $options 1967 * @return string 1968 */ 1969 function rate($table,$id,$options=array()) 1970 { 1971 $table = preg_replace('/\W/', '', $table); 1972 $id = intval($id); 1973 1974 return e107::getRate()->render($table, $id, $options); 1975 } 1976 1977 function like($table,$id,$options=null) 1978 { 1979 $table = preg_replace('/\W/', '', $table); 1980 $id = intval($id); 1981 1982 return e107::getRate()->renderLike($table,$id,$options); 1983 } 1984 1985 1986 /** 1987 * File Upload form element. 1988 * @param $name 1989 * @param array $options (optional) array('multiple'=>1) 1990 * @return string 1991 */ 1992 function file($name, $options = array()) 1993 { 1994 if(e_ADMIN_AREA && empty($options['class'])) 1995 { 1996 $options = array('class'=>'tbox well file'); 1997 } 1998 1999 $options = $this->format_options('file', $name, $options); 2000 2001 2002 2003 //never allow id in format name-value for text fields 2004 return "<input type='file' name='{$name}'".$this->get_attributes($options, $name)." />"; 2005 } 2006 2007 /** 2008 * Upload Element. (for the future) 2009 * 2010 * @param $name 2011 * @param array $options 2012 * @return string 2013 */ 2014 function upload($name, $options = array()) 2015 { 2016 unset($name,$options); 2017 return 'Ready to use upload form fields, optional - file list view'; 2018 } 2019 2020 function password($name, $value = '', $maxlength = 50, $options = array()) 2021 { 2022 if(is_string($options)) parse_str($options, $options); 2023 2024 $addon = ""; 2025 $gen = ""; 2026 2027 if(vartrue($options['generate'])) 2028 { 2029 $gen = ' <a href="#" class="btn btn-default btn-secondary btn-small e-tip" id="Spn_PasswordGenerator" title=" '.LAN_GEN_PW.' " >'.LAN_GENERATE.'</a> '; 2030 2031 if(empty($options['nomask'])) 2032 { 2033 $gen .= '<a class="btn btn-default btn-secondary btn-small e-tip" href="#" id="showPwd" title=" '.LAN_DISPL_PW.' ">'.LAN_SHOW.'</a><br />'; 2034 } 2035 } 2036 2037 if(vartrue($options['strength'])) 2038 { 2039 $addon .= "<div style='margin-top:4px'><div class='progress' style='float:left;display:inline-block;width:218px;margin-bottom:0'><div class='progress-bar bar' id='pwdMeter' style='width:0%' ></div></div> <div id='pwdStatus' class='smalltext' style='float:left;display:inline-block;width:150px;margin-left:5px'></span></div>"; 2040 } 2041 2042 $options['pattern'] = vartrue($options['pattern'],'[\S].{2,}[\S]'); 2043 $options['required'] = varset($options['required'], 1); 2044 $options['class'] = vartrue($options['class'],'e-password tbox'); 2045 2046 2047 e107::js('core', 'password/jquery.pwdMeter.js', 'jquery', 2); 2048 2049 e107::js('footer-inline', ' 2050 $(".e-password").pwdMeter({ 2051 minLength: 6, 2052 displayGeneratePassword: true, 2053 generatePassText: "Generate", 2054 randomPassLength: 12 2055 }); 2056 '); 2057 2058 if(deftrue('BOOTSTRAP')) 2059 { 2060 $options['class'] .= ' form-control'; 2061 } 2062 2063 if(vartrue($options['size']) && !is_numeric($options['size'])) 2064 { 2065 $options['class'] .= " input-".$options['size']; 2066 unset($options['size']); // don't include in html 'size='. 2067 } 2068 2069 $type = empty($options['nomask']) ? 'password' : 'text'; 2070 2071 $options = $this->format_options('text', $name, $options); 2072 2073 2074 //never allow id in format name-value for text fields 2075 $text = "<input type='".$type."' name='{$name}' value='{$value}' maxlength='{$maxlength}'".$this->get_attributes($options, $name)." />"; 2076 2077 if(empty($gen) && empty($addon)) 2078 { 2079 return $text; 2080 } 2081 else 2082 { 2083 return "<span class='form-inline'>".$text.$gen."</span>".vartrue($addon); 2084 } 2085 2086 } 2087 2088 2089 /** 2090 * Render Pagination using 'nextprev' shortcode. 2091 * @param string $url eg. e_REQUEST_SELF.'?from=[FROM]' 2092 * @param int $total total records 2093 * @param int $from value to replace [FROM] with in the URL 2094 * @param int $perPage number of items per page 2095 * @param array $options template, type, glyphs 2096 * @return string 2097 */ 2098 public function pagination($url='', $total=0, $from=0, $perPage=10, $options=array()) 2099 { 2100 2101 if(empty($total) || empty($perPage)) 2102 { 2103 return ''; 2104 } 2105 2106 if(BOOTSTRAP === 4) 2107 { 2108 return '<a class="pager-button btn btn-primary" href="'.$url.'">'.$total.'</a>'; 2109 } 2110 2111 if(!is_numeric($total)) 2112 { 2113 return '<ul class="pager"><li><a href="'.$url.'">'.$total.'</a></li></ul>'; 2114 } 2115 2116 2117 2118 require_once(e_CORE."shortcodes/single/nextprev.php"); 2119 2120 $nextprev = array( 2121 'tmpl_prefix' => varset($options['template'],'default'), 2122 'total' => intval($total), 2123 'amount' => intval($perPage), 2124 'current' => intval($from), 2125 'url' => urldecode($url), 2126 'type' => varset($options['type'],'record'), // page|record 2127 'glyphs' => vartrue($options['glyphs'],false) // 1|0 2128 ); 2129 2130 // e107::getDebug()->log($nextprev); 2131 2132 return nextprev_shortcode($nextprev); 2133 } 2134 2135 2136 /** 2137 * Render a bootStrap ProgressBar. 2138 * 2139 * @param string $name 2140 * @param number|string $value 2141 * @param array $options 2142 * @return string 2143 * @example Use 2144 */ 2145 public function progressBar($name,$value,$options=array()) 2146 { 2147 if(!deftrue('BOOTSTRAP')) // Legacy ProgressBar. 2148 { 2149 $barl = (file_exists(THEME.'images/barl.png') ? THEME_ABS.'images/barl.png' : e_PLUGIN_ABS.'poll/images/barl.png'); 2150 $barr = (file_exists(THEME.'images/barr.png') ? THEME_ABS.'images/barr.png' : e_PLUGIN_ABS.'poll/images/barr.png'); 2151 $bar = (file_exists(THEME.'images/bar.png') ? THEME_ABS.'images/bar.png' : e_PLUGIN_ABS.'poll/images/bar.png'); 2152 2153 return "<div style='background-image: url($barl); width: 5px; height: 14px; float: left;'></div> 2154 <div style='background-image: url($bar); width: ".intval($value)."%; height: 14px; float: left;'></div> 2155 <div style='background-image: url($barr); width: 5px; height: 14px; float: left;'></div>"; 2156 } 2157 2158 $class = vartrue($options['class'],''); 2159 $target = $this->name2id($name); 2160 2161 $striped = (vartrue($options['btn-label'])) ? ' progress-striped active' : ''; 2162 2163 if(strpos($value,'/')!==false) 2164 { 2165 $label = $value; 2166 list($score,$denom) = explode('/',$value); 2167 2168 // $multiplier = 100 / (int) $denom; 2169 2170 $value = ((int) $score / (int) $denom) * 100; 2171 2172 // $value = (int) $score * (int) $multiplier; 2173 $percVal = round(floatval($value)).'%'; 2174 } 2175 else 2176 { 2177 $percVal = round(floatval($value)).'%'; 2178 $label = $percVal; 2179 } 2180 2181 if(!empty($options['label'])) 2182 { 2183 $label = $options['label']; 2184 } 2185 2186 $id = !empty($options['id']) ? "id='".$options['id']."'" : ''; 2187 2188 $text = "<div {$id} class='progress {$striped}' > 2189 <div id='".$target."' class='progress-bar bar ".$class."' role='progressbar' aria-valuenow='".intval($value)."' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;width: ".$percVal."'>"; 2190 $text .= $label; 2191 $text .= "</div> 2192 </div>"; 2193 2194 $loading = vartrue($options['loading'], defset('LAN_LOADING', "Loading")); 2195 2196 $buttonId = $target.'-start'; 2197 2198 2199 2200 if(vartrue($options['btn-label'])) 2201 { 2202 $interval = vartrue($options['interval'],1000); 2203 $text .= '<a id="'.$buttonId.'" data-loading-text="'.$loading.'" data-progress-interval="'.$interval.'" data-progress-target="'.$target.'" data-progress="' . $options['url'] . '" data-progress-mode="'.varset($options['mode'],0).'" data-progress-show="'.varset($options['show'],0).'" data-progress-hide="'.$buttonId.'" class="btn btn-primary e-progress" >'.$options['btn-label'].'</a>'; 2204 $text .= ' <a data-progress-target="'.$target.'" class="btn btn-danger e-progress-cancel" >'.LAN_CANCEL.'</a>'; 2205 } 2206 2207 2208 return $text; 2209 2210 } 2211 2212 2213 /** 2214 * Textarea Element 2215 * @param string $name 2216 * @param string $value 2217 * @param int $rows 2218 * @param int $cols 2219 * @param array $options 2220 * @param int|bool $counter 2221 * @return string 2222 */ 2223 function textarea($name, $value, $rows = 10, $cols = 80, $options = array(), $counter = false) 2224 { 2225 if(is_string($options)) parse_str($options, $options); 2226 // auto-height support 2227 2228 if(empty($options['class'])) 2229 { 2230 $options['class'] = ''; 2231 } 2232 2233 if(vartrue($options['size']) && !is_numeric($options['size'])) 2234 { 2235 $options['class'] .= " form-control input-".$options['size']; 2236 unset($options['size']); // don't include in html 'size='. 2237 } 2238 elseif(!vartrue($options['noresize'])) 2239 { 2240 $options['class'] = (isset($options['class']) && $options['class']) ? $options['class'].' e-autoheight' : 'tbox col-md-7 span7 e-autoheight form-control'; 2241 } 2242 2243 $options = $this->format_options('textarea', $name, $options); 2244 2245// print_a($options); 2246 //never allow id in format name-value for text fields 2247 return "<textarea name='{$name}' rows='{$rows}' cols='{$cols}'".$this->get_attributes($options, $name).">{$value}</textarea>".(false !== $counter ? $this->hidden('__'.$name.'autoheight_opt', $counter) : ''); 2248 } 2249 2250 /** 2251 * Bbcode Area. Name, value, template, media-Cat, size, options array eg. counter 2252 * IMPORTANT: $$mediaCat is also used is the media-manager category identifier 2253 * 2254 * @param string $name 2255 * @param mixed $value 2256 * @param string $template 2257 * @param string $mediaCat _common 2258 * @param string $size : small | medium | large 2259 * @param array $options { 2260 * @type bool wysiwyg when set to false will disable wysiwyg if active. 2261 * @type string class override class. 2262 * } 2263 2264 * @return string 2265 */ 2266 function bbarea($name, $value, $template = '', $mediaCat='_common', $size = 'large', $options = array()) 2267 { 2268 if(is_string($options)) parse_str($options, $options); 2269 //size - large|medium|small 2270 //width should be explicit set by current admin theme 2271 // $size = 'input-large'; 2272 $height = ''; 2273 $cols = 70; 2274 2275 switch($size) 2276 { 2277 case 'tiny': 2278 $rows = '3'; 2279 $cols = 50; 2280 // $height = "style='height:250px'"; // inline required for wysiwyg 2281 break; 2282 2283 2284 case 'small': 2285 $rows = '7'; 2286 $height = "style='height:230px'"; // inline required for wysiwyg 2287 $size = "input-block-level"; 2288 break; 2289 2290 case 'medium': 2291 $rows = '10'; 2292 2293 $height = "style='height:375px'"; // inline required for wysiwyg 2294 $size = "input-block-level"; 2295 break; 2296 2297 case 'large': 2298 default: 2299 $rows = '20'; 2300 $size = 'large input-block-level'; 2301 // $height = "style='height:500px;width:1025px'"; // inline required for wysiwyg 2302 break; 2303 } 2304 2305 // auto-height support 2306/* 2307 $bbbar = ''; 2308 $wysiwyg = null; 2309 $wysiwygClass = ' e-wysiwyg'; 2310 2311 if(isset($options['wysiwyg'])) 2312 { 2313 $wysiwyg = $options['wysiwyg']; 2314 } 2315 2316 if($wysiwyg === false) 2317 { 2318 $wysiwygClass = ''; 2319 } 2320 2321 $options['class'] = 'tbox bbarea '.($size ? ' '.$size : '').$wysiwygClass.' e-autoheight form-control'; 2322*/ 2323 $options['class'] = 'tbox bbarea '.($size ? ' '.$size : '').' e-wysiwyg e-autoheight form-control'; 2324 2325 if (isset($options['id']) && !empty($options['id'])) 2326 { 2327 $help_tagid = $this->name2id($options['id'])."--preview"; 2328 } 2329 else 2330 { 2331 $help_tagid = $this->name2id($name)."--preview"; 2332 } 2333 2334 if (!isset($options['wysiwyg'])) 2335 { 2336 $options['wysiwyg'] = true; 2337 } 2338 2339 //if(e107::wysiwyg(true) === false || $wysiwyg === false) // bbarea loaded, so activate wysiwyg (if enabled in preferences) 2340 if(e107::wysiwyg($options['wysiwyg'],true) === 'bbcode') // bbarea loaded, so activate wysiwyg (if enabled in preferences) 2341 { 2342 $options['other'] = "onselect='storeCaret(this);' onclick='storeCaret(this);' onkeyup='storeCaret(this);' {$height}"; 2343 } 2344 else 2345 { 2346 $options['other'] = " ".$height; 2347 } 2348 2349 2350 $counter = vartrue($options['counter'],false); 2351 2352 $ret = "<div class='bbarea {$size}'> 2353 <div class='field-spacer'><!-- --></div>\n"; 2354 2355 2356 if(e107::wysiwyg() === true) // && $wysiwyg !== false) 2357 { 2358 $eParseList = e107::getConfig()->get('e_parse_list'); 2359 2360 if(!empty($eParseList)) 2361 { 2362 $opts = array( 2363 'field' => $name, 2364 ); 2365 2366 foreach($eParseList as $plugin) 2367 { 2368 $hookObj = e107::getAddon($plugin, 'e_parse'); 2369 2370 if($tmp = e107::callMethod($hookObj, 'toWYSIWYG', $value, $opts)) 2371 { 2372 $value = $tmp; 2373 } 2374 } 2375 } 2376 } 2377 2378 2379 $ret .= e107::getBB()->renderButtons($template,$help_tagid); 2380 $ret .= $this->textarea($name, $value, $rows, $cols, $options, $counter); // higher thank 70 will break some layouts. 2381 2382 $ret .= "</div>\n"; 2383 2384 $_SESSION['media_category'] = $mediaCat; // used by TinyMce. 2385 2386 2387 2388 2389 return $ret; 2390 2391 // Quick fix - hide TinyMCE links if not installed, dups are handled by JS handler 2392 /* 2393 2394 e107::getJs()->footerInline(" 2395 if(typeof tinyMCE === 'undefined') 2396 { 2397 \$$('a.e-wysiwyg-switch').invoke('hide'); 2398 } 2399 "); 2400 */ 2401 2402 2403 } 2404 2405 /** 2406 * Render a checkbox 2407 * @param string $name 2408 * @param mixed $value 2409 * @param boolean $checked 2410 * @param mixed $options query-string or array or string for a label. eg. label=Hello&foo=bar or array('label'=>Hello') or 'Hello' 2411 * @return string 2412 */ 2413 function checkbox($name, $value, $checked = false, $options = array()) 2414 { 2415 if(!is_array($options)) 2416 { 2417 if(strpos($options,"=")!==false) 2418 { 2419 parse_str($options, $options); 2420 } 2421 elseif(is_array($options)) 2422 { 2423 // do nothing. 2424 } 2425 else // Assume it's a label. 2426 { 2427 $options = array('label'=>$options); 2428 } 2429 2430 } 2431 2432 $labelClass = (!empty($options['inline'])) ? 'checkbox-inline' : 'checkbox form-check'; 2433 $labelTitle = ''; 2434 2435 $options = $this->format_options('checkbox', $name, $options); 2436 2437 $options['checked'] = $checked; //comes as separate argument just for convenience 2438 2439 $text = ""; 2440 2441 $active = ($checked === true) ? " active" : ""; // allow for styling if needed. 2442 2443 if(!empty($options['label'])) // add attributes to <label> 2444 { 2445 if(!empty($options['title'])) 2446 { 2447 $labelTitle = " title=\"".$options['title']."\""; 2448 unset($options['title']); 2449 } 2450 2451 if(!empty($options['class'])) 2452 { 2453 $labelClass .= " ".$options['class']; 2454 unset($options['class']); 2455 } 2456 } 2457 2458 if(!isset($options['class'])) 2459 { 2460 $options['class'] = ''; 2461 } 2462 2463 $options['class'] .= ' form-check-input'; 2464 2465 $pre = (vartrue($options['label'])) ? "<label class='".$labelClass.$active."'{$labelTitle}>" : ""; // Bootstrap compatible markup 2466 $post = (vartrue($options['label'])) ? "<span>".$options['label']."</span></label>" : ""; 2467 unset($options['label']); // not to be used as attribute; 2468 2469 $text .= "<input type='checkbox' name='{$name}' value='{$value}'".$this->get_attributes($options, $name, $value)." />"; 2470 2471 return $pre.$text.$post; 2472 } 2473 2474 2475 /** 2476 * Render an array of checkboxes. 2477 * @param string $name 2478 * @param array $option_array 2479 * @param mixed $checked 2480 * @param array $options [optional useKeyValues] 2481 */ 2482 function checkboxes($name, $option_array=array(), $checked=null, $options=array()) 2483 { 2484 $name = (strpos($name, '[') === false) ? $name.'[]' : $name; 2485 2486 if(!is_array($checked)) $checked = explode(",",$checked); 2487 2488 $text = array(); 2489 2490 $cname = $name; 2491 2492 foreach($option_array as $k=>$label) 2493 { 2494 if(!empty($options['useKeyValues'])) // ie. auto-generated 2495 { 2496 $key = $k; 2497 $c = in_array($k, $checked) ? true : false; 2498 } 2499 elseif(!empty($options['useLabelValues'])) 2500 { 2501 $key = $label; 2502 //print_a($label); 2503 $c = in_array($label, e107::getParser()->toDB($checked)) ? true : false; 2504 } 2505 else 2506 { 2507 $key = 1; 2508 $cname = str_replace('[]','['.$k.']',$name); 2509 $c = vartrue($checked[$k]); 2510 } 2511 2512 /** 2513 * Label overwrote the other supplied options (if any) 2514 * and also failed in case it contained a "=" character 2515 */ 2516 $options['label'] = $label; 2517 $text[] = $this->checkbox($cname, $key, $c, $options); 2518 } 2519 2520 $id = empty($options['id']) ? $this->name2id($name).'-container' : $options['id']; 2521 2522 // return print_a($checked,true); 2523 if(isset($options['list']) && $options['list']) 2524 { 2525 return "<ul id='".$id."' class='checkboxes checkbox'><li>".implode("</li><li>",$text)."</li></ul>"; 2526 } 2527 2528 2529 if(!empty($text)) 2530 { 2531 return "<div id='".$id."' class='checkboxes checkbox' style='display:inline-block'>".implode("",$text)."</div>"; 2532 } 2533 2534 return $text; 2535 2536 } 2537 2538 2539 function checkbox_label($label_title, $name, $value, $checked = false, $options = array()) 2540 { 2541 return $this->checkbox($name, $value, $checked, $options).$this->label($label_title, $name, $value); 2542 } 2543 2544 function checkbox_switch($name, $value, $checked = false, $label = '') 2545 { 2546 return $this->checkbox($name, $value, $checked).$this->label($label ? $label : LAN_ENABLED, $name, $value); 2547 } 2548 2549 function checkbox_toggle($name, $selector = 'multitoggle', $id = false, $label='') //TODO Fixme - labels will break this. Don't use checkbox, use html. 2550 { 2551 $selector = 'jstarget:'.$selector; 2552 if($id) $id = $this->name2id($id); 2553 2554 return $this->checkbox($name, $selector, false, array('id' => $id,'class' => 'checkbox checkbox-inline toggle-all','label'=>$label)); 2555 } 2556 2557 function uc_checkbox($name, $current_value, $uc_options, $field_options = array()) 2558 { 2559 if(!is_array($field_options)) parse_str($field_options, $field_options); 2560 return ' 2561 <div class="check-block"> 2562 '.$this->_uc->vetted_tree($name, array($this, '_uc_checkbox_cb'), $current_value, $uc_options, $field_options).' 2563 </div> 2564 '; 2565 } 2566 2567 2568 /** 2569 * Callback function used with $this->uc_checkbox 2570 * 2571 * @see user_class->select() for parameters 2572 */ 2573 function _uc_checkbox_cb($treename, $classnum, $current_value, $nest_level, $field_options) 2574 { 2575 if($classnum == e_UC_BLANK) 2576 return ''; 2577 2578 if (!is_array($current_value)) 2579 { 2580 $tmp = explode(',', $current_value); 2581 } 2582 2583 $classIndex = abs($classnum); // Handle negative class values 2584 $classSign = (substr($classnum, 0, 1) == '-') ? '-' : ''; 2585 2586 $class = $style = ''; 2587 if($nest_level == 0) 2588 { 2589 $class = " strong"; 2590 } 2591 else 2592 { 2593 $style = " style='text-indent:" . (1.2 * $nest_level) . "em'"; 2594 } 2595 $descr = varset($field_options['description']) ? ' <span class="smalltext">('.$this->_uc->uc_get_classdescription($classnum).')</span>' : ''; 2596 2597 return "<div class='field-spacer{$class}'{$style}>".$this->checkbox($treename.'[]', $classnum, in_array($classnum, $tmp), $field_options).$this->label($this->_uc->uc_get_classname($classIndex).$descr, $treename.'[]', $classnum)."</div>\n"; 2598 } 2599 2600 2601 function uc_label($classnum) 2602 { 2603 return $this->_uc->uc_get_classname($classnum); 2604 } 2605 2606 /** 2607 * A Radio Button Form Element 2608 * @param $name 2609 * @param @value array pair-values|string - auto-detected. 2610 * @param $checked boolean 2611 * @param $options 2612 */ 2613 function radio($name, $value, $checked = false, $options = null) 2614 { 2615 2616 if(!is_array($options)) parse_str($options, $options); 2617 2618 if(is_array($value)) 2619 { 2620 return $this->radio_multi($name, $value, $checked, $options); 2621 } 2622 2623 $labelFound = vartrue($options['label']); 2624 unset($options['label']); // label attribute not valid in html5 2625 2626 $options = $this->format_options('radio', $name, $options); 2627 $options['checked'] = $checked; //comes as separate argument just for convenience 2628 2629 if(empty($options['id'])) 2630 { 2631 unset($options['id']); 2632 } 2633 // $options['class'] = 'inline'; 2634 $text = ""; 2635 2636 2637 2638 // return print_a($options,true); 2639 if($labelFound) // Bootstrap compatible markup 2640 { 2641 $defaultClass = (deftrue('BOOTSTRAP')) ? 'radio-inline form-check-inline' : 'radio inline'; 2642 $dis = (!empty($options['disabled'])) ? " disabled" : ""; 2643 $text .= "<label class='{$defaultClass}{$dis}'>"; 2644 2645 } 2646 2647 2648 $text .= "<input class='form-check-input' type='radio' name='{$name}' value='".$value."'".$this->get_attributes($options, $name, $value)." />"; 2649 2650 if(vartrue($options['help'])) 2651 { 2652 $text .= "<div class='field-help'>".$options['help']."</div>"; 2653 } 2654 2655 if($labelFound) 2656 { 2657 $text .= " <span>".$labelFound."</span></label>"; 2658 } 2659 2660 return $text; 2661 } 2662 2663 /** 2664 * Boolean Radio Buttons / Checkbox (with Bootstrap Switch). 2665 * 2666 * @param string $name 2667 * Form element name. 2668 * @param bool $checked_enabled 2669 * Use the checked attribute or not. 2670 * @param string $label_enabled 2671 * Default is LAN_ENABLED 2672 * @param string $label_disabled 2673 * Default is LAN_DISABLED 2674 * @param array $options 2675 * - 'inverse' => 1 (invert values) 2676 * - 'reverse' => 1 (switch display order) 2677 * - 'switch' => 'normal' (size for Bootstrap Switch... mini, small, normal, large) 2678 * 2679 * @return string $text 2680 */ 2681 function radio_switch($name, $checked_enabled = false, $label_enabled = '', $label_disabled = '', $options = array()) 2682 { 2683 if(!is_array($options)) 2684 { 2685 parse_str($options, $options); 2686 } 2687 2688 $options_on = varset($options['enabled'], array()); 2689 $options_off = varset($options['disabled'], array()); 2690 2691 unset($options['enabled'], $options['disabled']); 2692 2693 $options_on = array_merge($options_on, $options); 2694 $options_off = array_merge($options_off, $options); 2695 2696 2697 if(vartrue($options['class']) == 'e-expandit' || vartrue($options['expandit'])) // See admin->prefs 'Single Login' for an example. 2698 { 2699 $options_on = array_merge($options, array('class' => 'e-expandit-on')); 2700 $options_off = array_merge($options, array('class' => 'e-expandit-off')); 2701 } 2702 2703 if(e_ADMIN_AREA === true) 2704 { 2705 $options['switch'] = 'small'; 2706 $label_enabled = ($label_enabled) ? strtoupper($label_enabled) : strtoupper(LAN_ON); 2707 $label_disabled = ($label_disabled) ? strtoupper($label_disabled): strtoupper(LAN_OFF); 2708 } 2709 2710 2711 $options_on['label'] = $label_enabled ? defset($label_enabled, $label_enabled) : LAN_ENABLED; 2712 $options_off['label'] = $label_disabled ? defset($label_disabled, $label_disabled) : LAN_DISABLED; 2713 2714 if(!empty($options['switch'])) 2715 { 2716 return $this->flipswitch($name,$checked_enabled, array('on'=>$options_on['label'],'off'=>$options_off['label']),$options); 2717 } 2718 elseif(!empty($options['inverse'])) // Same as 'writeParms'=>'reverse=1&enabled=LAN_DISABLED&disabled=LAN_ENABLED' 2719 { 2720 $text = $this->radio($name, 0, !$checked_enabled, $options_on) . " " . $this->radio($name, 1, $checked_enabled, $options_off); 2721 2722 } 2723 elseif(!empty($options['reverse'])) // reverse display order. 2724 { 2725 $text = $this->radio($name, 0, !$checked_enabled, $options_off) . " " . $this->radio($name, 1, $checked_enabled, $options_on); 2726 } 2727 else 2728 { 2729 $text = $this->radio($name, 1, $checked_enabled, $options_on) . " " . $this->radio($name, 0, !$checked_enabled, $options_off); 2730 } 2731 2732 return $text; 2733 } 2734 2735 2736 /** 2737 * @param string $name 2738 * @param bool|false $checked_enabled 2739 * @param array $labels on & off 2740 * @param array $options 2741 * @return string 2742 */ 2743 public function flipswitch($name, $checked_enabled = false, $labels=null, $options = array()) 2744 { 2745 2746 if(empty($labels)) 2747 { 2748 $labels = array('on' =>strtoupper(LAN_ON), 'off' =>strtoupper(LAN_OFF)); 2749 } 2750 2751 $value = $checked_enabled; 2752 2753 if(!empty($options['inverse'])) 2754 { 2755 $checked_enabled = !$checked_enabled; 2756 } 2757 2758 if(!empty($options['reverse'])) 2759 { 2760 $on = $labels['on']; 2761 $options_on['label'] = $labels['off']; 2762 $options_off['label'] = $on; 2763 unset($on); 2764 2765 } 2766 2767 if(empty($options['switch'])) 2768 { 2769 $options['switch'] = 'small'; 2770 } 2771 2772 2773 $switchName = $this->name2id($name) . '__switch'; // fixes array names. 2774 2775 $switchAttributes = array( 2776 'data-type' => 'switch', 2777 'data-name' => $name, 2778 'data-size' => $options['switch'], 2779 'data-on' => $labels['on'], 2780 'data-off' => $labels['off'], 2781 'data-inverse' => (int) !empty($options['inverse']), 2782 ); 2783 2784 $options += $switchAttributes; 2785 2786 if(e_ADMIN_AREA === true) 2787 { 2788 $options['data-wrapper'] = 'wrapper form-control'; 2789 2790 } 2791 2792 e107::library('load', 'bootstrap.switch'); 2793 e107::js('footer', '{e_WEB}js/bootstrap.switch.init.js', 'jquery', 5); 2794 2795 $text = $this->hidden($name, (int) $value); 2796 $text .= $this->checkbox($switchName, (int) $checked_enabled, $checked_enabled, $options); 2797 2798 return $text; 2799 } 2800 2801 2802 2803 2804 2805 /** 2806 * XXX INTERNAL ONLY - Use radio() instead. array will automatically trigger this internal method. 2807 * @param string $name 2808 * @param array $elements = arrays value => label 2809 * @param string/integer $checked = current value 2810 * @param boolean $multi_line 2811 * @param mixed $help array of field help items or string of field-help (to show on all) 2812 */ 2813 private function radio_multi($name, $elements, $checked, $options=array(), $help = null) 2814 { 2815 2816 2817 2818 /* // Bootstrap Test. 2819 return' <label class="checkbox"> 2820 <input type="checkbox" value=""> 2821 Option one is this and that—be sure to include why its great 2822 </label> 2823 2824 <label class="radio"> 2825 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked> 2826 Option one is this and that—be sure to include why its great 2827 </label> 2828 <label class="radio"> 2829 <input type="radio" name="optionsRadios" id="optionsRadios2" value="option2"> 2830 Option two can be something else and selecting it will deselect option one 2831 </label>'; 2832 */ 2833 2834 2835 $text = array(); 2836 2837 if(is_string($elements)) parse_str($elements, $elements); 2838 if(!is_array($options)) parse_str($options, $options); 2839 $help = ''; 2840 if(vartrue($options['help'])) 2841 { 2842 $help = "<div class='field-help'>".$options['help']."</div>"; 2843 unset($options['help']); 2844 } 2845 2846 foreach ($elements as $value => $label) 2847 { 2848 $label = defset($label, $label); 2849 2850 $helpLabel = (is_array($help)) ? vartrue($help[$value]) : $help; 2851 2852 // Bootstrap Style Code - for use later. 2853 $options['label'] = $label; 2854 $options['help'] = $helpLabel; 2855 $text[] = $this->radio($name, $value, (string) $checked === (string) $value, $options); 2856 2857 // $text[] = $this->radio($name, $value, (string) $checked === (string) $value)."".$this->label($label, $name, $value).(isset($helpLabel) ? "<div class='field-help'>".$helpLabel."</div>" : ''); 2858 } 2859 2860 // if($multi_line === false) 2861 // { 2862 // return implode(" ", $text); 2863 // } 2864 2865 // support of UI owned 'newline' parameter 2866 if(!varset($options['sep']) && vartrue($options['newline'])) $options['sep'] = '<br />'; // TODO div class=separator? 2867 $separator = varset($options['sep']," "); 2868 // return print_a($text,true); 2869 return implode($separator, $text).$help; 2870 2871 // return implode("\n", $text); 2872 //XXX Limiting markup. 2873 // return "<div class='field-spacer' style='width:50%;float:left'>".implode("</div><div class='field-spacer' style='width:50%;float:left'>", $text)."</div>"; 2874 2875 } 2876 2877 /** 2878 * Just for BC - use the $options['label'] instead. 2879 */ 2880 function label($text, $name = '', $value = '') 2881 { 2882 // $backtrack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2); 2883 // e107::getMessage()->addDebug("Deprecated \$frm->label() used in: ".print_a($backtrack,true)); 2884 $for_id = $this->_format_id('', $name, $value, 'for'); 2885 return "<label$for_id class='e-tip legacy'>{$text}</label>"; 2886 } 2887 2888 function help($text) 2889 { 2890 return !empty($text) ? '<div class="field-help">'.$text.'</div>' : ''; 2891 } 2892 2893 function select_open($name, $options = array()) 2894 { 2895 2896 if(!is_array($options)) parse_str($options, $options); 2897 2898 2899 if(!empty($options['size']) && !is_numeric($options['size'])) 2900 { 2901 if(!empty($options['class'])) 2902 { 2903 $options['class'] .= " form-control input-".$options['size']; 2904 } 2905 else 2906 { 2907 $options['class'] = "form-control input-".$options['size']; 2908 } 2909 2910 unset($options['size']); // don't include in html 'size='. 2911 } 2912 2913 if(!empty($options['title']) && is_array($options['title'])) 2914 { 2915 unset($options['title']); 2916 } 2917 2918 2919 $options = $this->format_options('select', $name, $options); 2920 2921 return "<select name='{$name}'".$this->get_attributes($options, $name).">"; 2922 } 2923 2924 2925 /** 2926 * @DEPRECATED - use select() instead. 2927 */ 2928 function selectbox($name, $option_array, $selected = false, $options = array(), $defaultBlank= false) 2929 { 2930 return $this->select($name, $option_array, $selected, $options, $defaultBlank); 2931 } 2932 2933 2934 2935 /** 2936 * 2937 * @param string $name 2938 * @param array $option_array 2939 * @param boolean $selected [optional] 2940 * @param string|array $options [optional] 2941 * @param bool $options['useValues'] when true uses array values as the key. 2942 * @param array $options['disabled'] list of $option_array keys which should be disabled. eg. array('key_1', 'key_2'); 2943 * @param bool|string $defaultBlank [optional] set to TRUE if the first entry should be blank, or to a string to use it for the blank description. 2944 * @return string HTML text for display 2945 */ 2946 function select($name, $option_array, $selected = false, $options = array(), $defaultBlank= false) 2947 { 2948 if(!is_array($options)) parse_str($options, $options); 2949 2950 if($option_array === 'yesno') 2951 { 2952 $option_array = array(1 => LAN_YES, 0 => LAN_NO); 2953 } 2954 2955 if(!empty($options['multiple'])) 2956 { 2957 $name = (strpos($name, '[') === false) ? $name.'[]' : $name; 2958 if(!is_array($selected)) $selected = explode(",",$selected); 2959 2960 } 2961 2962 $text = $this->select_open($name, $options)."\n"; 2963 2964 if(isset($options['default'])) 2965 { 2966 if($options['default'] === 'blank') 2967 { 2968 $options['default'] = ' '; 2969 } 2970 $text .= $this->option($options['default'], varset($options['defaultValue'],'')); 2971 } 2972 elseif($defaultBlank) 2973 { 2974 $diz = is_string($defaultBlank) ? $defaultBlank : ' '; 2975 $text .= $this->option($diz, ''); 2976 } 2977 2978 if(!empty($options['useValues'])) // use values as keys. 2979 { 2980 $new = array(); 2981 foreach($option_array as $v) 2982 { 2983 $new[$v] = (string) $v; 2984 } 2985 $option_array = $new; 2986 } 2987 2988 $text .= $this->option_multi($option_array, $selected, $options)."\n".$this->select_close(); 2989 return $text; 2990 } 2991 2992 2993 2994 2995 2996 2997 /** 2998 * Universal Userclass selector - checkboxes, dropdown, everything. 2999 * @param string $name - form element name 3000 * @param int $curval - current userclass value(s) as array or comma separated. 3001 * @param string $type - checkbox|dropdown default is dropdown. 3002 * @param string|array $options - classlist or query string or key=value pair. 3003 * @param string $options['options'] comma-separated list of display options. 'options=admin,mainadmin,classes&vetted=1&exclusions=0' etc. 3004 * 3005 * @example $frm->userclass('name', 0, 'dropdown', 'classes'); // display all userclasses 3006 * @example $frm->userclass('name', 0, 'dropdown', 'classes,matchclass'); // display only classes to which the user belongs. 3007 * @return string form element(s) 3008 */ 3009 function userclass($name, $curval=255, $type=null, $options=null) 3010 { 3011 if(!empty($options)) 3012 { 3013 if(is_array($options)) 3014 { 3015 $opt = $options; 3016 } 3017 elseif(strpos($options,'=')!==false) 3018 { 3019 parse_str($options,$opt); 3020 } 3021 else 3022 { 3023 $opt = array('options'=>$options); 3024 } 3025 3026 } 3027 else 3028 { 3029 $opt = array(); 3030 } 3031 3032 $optlist = vartrue($opt['options'],null); 3033 3034 switch ($type) 3035 { 3036 case 'checkbox': 3037 return e107::getUserClass()->uc_checkboxes($name, $curval, $optlist, null,false); 3038 break; 3039 3040 case 'dropdown': 3041 default: 3042 return e107::getUserClass()->uc_dropdown($name, $curval, $optlist, $opt); 3043 break; 3044 } 3045 3046 } 3047 3048 3049 /** 3050 * Renders a generic search box. If $filter has values, a filter box will be included with the options provided. 3051 * 3052 */ 3053 function search($name, $searchVal, $submitName, $filterName='', $filterArray=false, $filterVal=false) 3054 { 3055 $tp = e107::getParser(); 3056 3057 $text = '<span class="input-append input-group e-search"> 3058 '.$this->text($name, $searchVal,20,'class=search-query&placeholder='.LAN_SEARCH.'…').' 3059 <span class="input-group-btn"><button class="btn btn-primary" name="'.$submitName.'" type="submit">'.$tp->toGlyph('fa-search',' ').'</button></span> 3060 </span>'; 3061 3062 3063 3064 if(is_array($filterArray)) 3065 { 3066 $text .= $this->selectbox($filterName, $filterArray, $filterVal); 3067 } 3068 3069 // $text .= $this->admin_button($submitName,LAN_SEARCH,'search'); 3070 3071 return $text; 3072 3073 /* 3074 $text .= 3075 3076 <select style="display: none;" data-original-title="Filter the results below" name="filter_options" id="filter-options" class="e-tip tbox select filter" title=""> 3077 <option value="">Display All</option> 3078 <option value="___reset___">Clear Filter</option> 3079 <optgroup class="optgroup" label="Filter by Category"> 3080<option value="faq_parent__1">General</option> 3081<option value="faq_parent__2">Misc</option> 3082<option value="faq_parent__4">Test 3</option> 3083 </optgroup> 3084 3085 </select><div class="btn-group bootstrap-select e-tip tbox select filter"><button id="filter-options" class="btn dropdown-toggle clearfix" data-toggle="dropdown"><span class="filter-option pull-left">Display All</span> <span class="caret"></span></button><ul style="max-height: none; overflow-y: auto;" class="dropdown-menu" role="menu"><li rel="0"><a tabindex="-1" class="">Display All</a></li><li rel="1"><a tabindex="-1" class="">Clear Filter</a></li><li rel="2"><dt class="optgroup-div">Filter by Category</dt><a tabindex="-1" class="opt ">General</a></li><li rel="3"><a tabindex="-1" class="opt ">Misc</a></li><li rel="4"><a tabindex="-1" class="opt ">Test 3</a></li></ul></div> 3086 <div class="e-autocomplete"></div> 3087 3088 3089 <button type="submit" name="etrigger_filter" value="etrigger_filter" id="etrigger-filter" class="btn filter e-hide-if-js btn-primary"><span>Filter</span></button> 3090 3091 <span class="indicator" style="display: none;"> 3092 <img src="/e107_2.0/e107_images/generic/loading_16.gif" class="icon action S16" alt="Loading..."> 3093 </span> 3094 3095 */ 3096 } 3097 3098 3099 /** 3100 * @param $name 3101 * @param null $current_value 3102 * @param null $uc_options 3103 * @param array $select_options multiple, default 3104 * @param array $opt_options 3105 * @return string 3106 */ 3107 function uc_select($name, $current_value=null, $uc_options=null, $select_options = array(), $opt_options = array()) 3108 { 3109 3110/* var_dump($name); 3111 var_dump($current_value); 3112var_dump($uc_options); 3113var_dump($select_options);*/ 3114 3115 3116 if(!empty($select_options['multiple']) && substr($name,-1) != ']') 3117 { 3118 $name .= '[]'; 3119 } 3120 3121 if(($current_value === null || $current_value === '') && !empty($uc_options)) // make the first in the opt list the default value. 3122 { 3123 $tmp = explode(",", $uc_options); 3124 $current_value = e107::getUserClass()->getClassFromKey($tmp[0]); 3125 3126 if(isset($select_options['default'])) 3127 { 3128 $current_value = (int) $select_options['default']; 3129 } 3130 } 3131 3132 if(!empty($current_value) && !is_numeric($current_value)) // convert name to id. 3133 { 3134 //$current_value = $this->_uc->getID($current_value); 3135 // issue #3249 Accept also comma separated values 3136 if (!is_array($current_value)) 3137 { 3138 $current_value = explode(',', $current_value); 3139 } 3140 $tmp = array(); 3141 foreach($current_value as $val) 3142 { 3143 if (!empty($val)) 3144 { 3145 $tmp[] = !is_numeric($val) ? $this->_uc->getID(trim($val)) : (int) $val; 3146 } 3147 } 3148 $current_value = implode(',', $tmp); 3149 unset($tmp); 3150 } 3151 3152 $text = $this->select_open($name, $select_options)."\n"; 3153 $text .= $this->_uc->vetted_tree($name, array($this, '_uc_select_cb'), $current_value, $uc_options, $opt_options)."\n"; 3154 $text .= $this->select_close(); 3155 3156 return $text; 3157 } 3158 3159 // Callback for vetted_tree - Creates the option list for a selection box 3160 function _uc_select_cb($treename, $classnum, $current_value, $nest_level) 3161 { 3162 $classIndex = abs($classnum); // Handle negative class values 3163 $classSign = (substr($classnum, 0, 1) == '-') ? '-' : ''; 3164 3165 if($classnum == e_UC_BLANK) 3166 return $this->option(' ', ''); 3167 3168 $tmp = explode(',', $current_value); 3169 if($nest_level == 0) 3170 { 3171 $prefix = ''; 3172 $style = "font-weight:bold; font-style: italic;"; 3173 } 3174 elseif($nest_level == 1) 3175 { 3176 $prefix = ' '; 3177 $style = "font-weight:bold"; 3178 } 3179 else 3180 { 3181 $prefix = ' '.str_repeat('--', $nest_level - 1).'>'; 3182 $style = ''; 3183 } 3184 return $this->option($prefix.$this->_uc->uc_get_classname($classnum), $classSign.$classIndex, ($current_value !== '' && in_array($classnum, $tmp)), array("style"=>"{$style}"))."\n"; 3185 } 3186 3187 3188 function optgroup_open($label, $disabled = false, $options = null) 3189 { 3190 return "<optgroup class='optgroup ".varset($options['class'])."' label='{$label}'".($disabled ? " disabled='disabled'" : '').">\n"; 3191 } 3192 3193 /** 3194 * <option> tag generation. 3195 * @param $option_title 3196 * @param $value 3197 * @param $selected 3198 * @param $options (eg. disabled=1) 3199 */ 3200 function option($option_title, $value, $selected = false, $options = '') 3201 { 3202 if(is_string($options)) parse_str($options, $options); 3203 3204 if(false === $value) $value = ''; 3205 3206 $options = $this->format_options('option', '', $options); 3207 $options['selected'] = $selected; //comes as separate argument just for convenience 3208 3209 3210 3211 return "<option value='{$value}'".$this->get_attributes($options).">".defset($option_title, $option_title)."</option>"; 3212 } 3213 3214 3215 /** 3216 * Use selectbox() instead. 3217 */ 3218 function option_multi($option_array, $selected = false, $options = array()) 3219 { 3220 if(is_string($option_array)) 3221 { 3222 parse_str($option_array, $option_array); 3223 } 3224 3225 $text = ''; 3226 3227 if(empty($option_array)) 3228 { 3229 return $this->option('',''); 3230 } 3231 3232 $opts = $options; 3233 3234 foreach ((array) $option_array as $value => $label) 3235 { 3236 3237 if(is_array($label)) 3238 { 3239 $text .= $this->optgroup($value, $label, $selected, $options, 0); 3240 } 3241 else 3242 { 3243 $sel = is_array($selected) ? in_array($value, $selected) : ($value == $selected); 3244 3245 if(!empty($options['optDisabled']) && is_array($options['optDisabled'])) 3246 { 3247 $opts['disabled'] = in_array($value, $options['optDisabled']); 3248 } 3249 3250 if(!empty($options['title'][$value])) 3251 { 3252 $opts['data-title'] = $options['title'][$value]; 3253 } 3254 elseif(isset($opts['data-title'])) 3255 { 3256 unset($opts['data-title']); 3257 } 3258 3259 $text .= $this->option($label, $value, $sel, $opts)."\n"; 3260 } 3261 } 3262 3263 return $text; 3264 } 3265 3266 3267 /** 3268 * No compliant, but it works. 3269 * @param $value 3270 * @param $label 3271 * @param $selected 3272 * @param $options 3273 * @param int $level 3274 * @return string 3275 */ 3276 private function optgroup($value, $label, $selected, $options, $level=1) 3277 { 3278 $level++; 3279 $text = $this->optgroup_open($value, null, array('class'=>'level-'.$level)); 3280 3281 $opts = $options; 3282 3283 foreach($label as $val => $lab) 3284 { 3285 if(is_array($lab)) 3286 { 3287 $text .= $this->optgroup($val,$lab,$selected,$options,$level); 3288 } 3289 else 3290 { 3291 if(!empty($options['optDisabled']) && is_array($options['optDisabled'])) 3292 { 3293 $opts['disabled'] = in_array($val, $options['optDisabled']); 3294 } 3295 3296 $text .= $this->option($lab, $val, (is_array($selected) ? in_array($val, $selected) : $selected == $val), $opts)."\n"; 3297 } 3298 3299 } 3300 3301 $text .= $this->optgroup_close(); 3302 3303 return $text; 3304 } 3305 3306 3307 3308 3309 3310 function optgroup_close() 3311 { 3312 return "</optgroup>\n"; 3313 } 3314 3315 function select_close() 3316 { 3317 return "</select>"; 3318 } 3319 3320 function hidden($name, $value, $options = array()) 3321 { 3322 $options = $this->format_options('hidden', $name, $options); 3323 3324 return "<input type='hidden' name='{$name}' value='{$value}'".$this->get_attributes($options, $name, $value)." />"; 3325 } 3326 3327 /** 3328 * Generate hidden security field 3329 * @return string 3330 */ 3331 function token() 3332 { 3333 return "<input type='hidden' name='e-token' value='".defset('e_TOKEN', '')."' />"; 3334 } 3335 3336 function submit($name, $value, $options = array()) 3337 { 3338 $options = $this->format_options('submit', $name, $options); 3339 return "<input type='submit' name='{$name}' value='{$value}'".$this->get_attributes($options, $name, $value)." />"; 3340 } 3341 3342 function submit_image($name, $value, $image, $title='', $options = array()) 3343 { 3344 $tp = e107::getParser(); 3345 3346 if(!empty($options['icon'])) 3347 { 3348 $customIcon = $options['icon']; 3349 unset($options['icon']); 3350 } 3351 3352 $options = $this->format_options('submit_image', $name, $options); 3353 switch ($image) 3354 { 3355 case 'edit': 3356 $icon = (e_ADMIN_AREA === true) ? ADMIN_EDIT_ICON : $tp->toIcon("e-edit-32"); 3357 $options['class'] = $options['class'] == 'action' ? 'btn btn-default btn-secondary action edit' : $options['class']; 3358 break; 3359 3360 case 'delete': 3361 $icon = (e_ADMIN_AREA === true) ? ADMIN_DELETE_ICON : $tp->toIcon('fa-trash.glyph'); 3362 $options['class'] = $options['class'] == 'action' ? 'btn btn-default btn-secondary action delete' : $options['class']; 3363 $options['other'] = 'data-confirm="'.LAN_JSCONFIRM.'"'; 3364 break; 3365 3366 case 'execute': 3367 $icon = (e_ADMIN_AREA === true) ? ADMIN_EXECUTE_ICON : $tp->toIcon('fa-power-off.glyph'); 3368 $options['class'] = $options['class'] == 'action' ? 'btn btn-default btn-secondary action execute' : $options['class']; 3369 break; 3370 3371 case 'view': 3372 $icon = $tp->toIcon("e-view-32"); 3373 $options['class'] = $options['class'] == 'action' ? 'btn btn-default btn-secondary action view' : $options['class']; 3374 break; 3375 } 3376 3377 $options['title'] = $title;//shorthand 3378 3379 if(!empty($customIcon)) 3380 { 3381 $icon = $customIcon; 3382 } 3383 3384 return "<button type='submit' name='{$name}' data-placement='left' value='{$value}'".$this->get_attributes($options, $name, $value)." >".$icon."</button>"; 3385 3386 3387 } 3388 3389 /** 3390 * Alias of admin_button, adds the etrigger_ prefix required for UI triggers 3391 * @see e_form::admin_button() 3392 */ 3393 function admin_trigger($name, $value, $action = 'submit', $label = '', $options = array()) 3394 { 3395 return $this->admin_button('etrigger_'.$name, $value, $action, $label, $options); 3396 } 3397 3398 3399 /** 3400 * Generic Button Element. 3401 * @param string $name 3402 * @param string $value 3403 * @param string $action [optional] default is submit - use 'dropdown' for a bootstrap dropdown button. 3404 * @param string $label [optional] 3405 * @param string|array $options [optional] 3406 * @return string 3407 */ 3408 public function button($name, $value, $action = 'submit', $label = '', $options = array()) 3409 { 3410 if(deftrue('BOOTSTRAP') && $action == 'dropdown' && is_array($value)) 3411 { 3412 // $options = $this->format_options('admin_button', $name, $options); 3413 $options['class'] = vartrue($options['class']); 3414 3415 $align = vartrue($options['align'],'left'); 3416 3417 $text = '<div class="btn-group pull-'.$align.'"> 3418 <a class="btn dropdown-toggle '.$options['class'].'" data-toggle="dropdown" href="#"> 3419 '.($label ? $label : LAN_NO_LABEL_PROVIDED).' 3420 <span class="caret"></span> 3421 </a> 3422 <ul class="dropdown-menu"> 3423 '; 3424 3425 foreach($value as $k=>$v) 3426 { 3427 $text .= '<li>'.$v.'</li>'; 3428 } 3429 3430 $text .= ' 3431 </ul> 3432 </div>'; 3433 3434 return $text; 3435 } 3436 3437 3438 3439 return $this->admin_button($name, $value, $action, $label, $options); 3440 3441 } 3442 3443 /** 3444 * Render a Breadcrumb in Bootstrap format. 3445 * @param $array 3446 * @param $array[url] 3447 * @param $array[text] 3448 */ 3449 function breadcrumb($array) 3450 { 3451 if(!is_array($array)){ return; } 3452 3453 $opt = array(); 3454 3455 $homeicon = (deftrue('FONTAWESOME')) ? 'fa-home' : 'icon-home.glyph'; 3456 $homeIcon = e107::getParser()->toGlyph($homeicon,false); 3457 3458 3459 $opt[] = "<a href='".e_HTTP."'>".$homeIcon."</a>"; // Add Site-Pref to disable? 3460 3461 $text = "\n<ul class=\"breadcrumb\">\n"; 3462 $text .= "<li class=\"breadcrumb-item\">"; 3463 3464 foreach($array as $val) 3465 { 3466 if($val['url'] === e_REQUEST_URI) // automatic link removal for current page. 3467 { 3468 $val['url']= null; 3469 } 3470 3471 $ret = ""; 3472 $ret .= vartrue($val['url']) ? "<a href='".$val['url']."'>" : ""; 3473 $ret .= vartrue($val['text'],''); 3474 $ret .= vartrue($val['url']) ? "</a>" : ""; 3475 3476 if($ret != '') 3477 { 3478 $opt[] = $ret; 3479 } 3480 } 3481 3482 $sep = (deftrue('BOOTSTRAP')) ? "" : "<span class='divider'>/</span>"; 3483 3484 $text .= implode($sep."</li>\n<li class='breadcrumb-item'>",$opt); 3485 3486 $text .= "</li>\n</ul>"; 3487 3488 // return print_a($opt,true); 3489 3490 return $text; 3491 3492 } 3493 3494 3495 /** 3496 * Render a direct link admin-edit button on the frontend. 3497 * @param $url 3498 * @param string $perms 3499 * @return string 3500 */ 3501 public function instantEditButton($url, $perms='0') 3502 { 3503 if(deftrue("BOOTSTRAP") && getperms($perms)) 3504 { 3505 return "<span class='e-instant-edit hidden-print'><a target='_blank' title='".LAN_EDIT."' href='".$url."'>".e107::getParser()->toGlyph('fa-edit')."</a></span>"; 3506 } 3507 3508 return ''; 3509 3510 } 3511 3512 3513 3514 3515 /** 3516 * Admin Button - for front-end, use button(); 3517 * @param string $name 3518 * @param string $value 3519 * @param string $action [optional] default is submit 3520 * @param string $label [optional] 3521 * @param string|array $options [optional] 3522 * @return string 3523 */ 3524 function admin_button($name, $value, $action = 'submit', $label = '', $options = array()) 3525 { 3526 $btype = 'submit'; 3527 if(strpos($action, 'action') === 0) 3528 { 3529 $btype = 'button'; 3530 } 3531 3532 if(isset($options['loading']) && ($options['loading'] == false)) 3533 { 3534 unset($options['loading']); 3535 $include = ''; 3536 } 3537 else 3538 { 3539 // $include = (deftrue("FONTAWESOME")) ? "data-loading-icon='fa-spinner' data-disable='true'" : ""; 3540 $include = (deftrue("FONTAWESOME")) ? "data-loading-icon='fa-spinner' " : ""; // data-disable breaks db.php charset Fix. 3541 } 3542 3543 $confirmation = LAN_JSCONFIRM; 3544 3545 if(!empty($options['confirm'])) 3546 { 3547 $confirmation = $options['confirm']; 3548 } 3549 3550 $options = $this->format_options('admin_button', $name, $options); 3551 3552 $options['class'] = vartrue($options['class']); 3553 $options['class'] .= ' btn ' . $action; 3554 3555 if(empty($label)) 3556 { 3557 $label = $value; 3558 } 3559 3560 // Ability to use any kind of button class for the selected action. 3561 if (!$this->defaultButtonClassExists($options['class'])) 3562 { 3563 $options['class'] .= ' ' . $this->getDefaultButtonClassByAction($action); 3564 } 3565 3566 switch ($action) 3567 { 3568 case 'checkall': 3569 $options['class'] .= ' btn-mini btn-xs'; 3570 break; 3571 3572 case 'delete': 3573 case 'danger': 3574 3575 3576 3577 $options['other'] = 'data-confirm="'.$confirmation.'"'; 3578 break; 3579 3580 case 'batch': 3581 case 'batch e-hide-if-js': 3582 // FIXME hide-js shouldn't be here. 3583 break; 3584 3585 case 'filter': 3586 case 'filter e-hide-if-js': 3587 $options['class'] = 'btn btn-default'; 3588 break; 3589 } 3590 3591 return "<button " . $include . " type='{$btype}' name='{$name}' value='{$value}'" . $this->get_attributes($options, $name) . "><span>{$label}</span></button>"; 3592 } 3593 3594 /** 3595 * Helper function to check if a (CSS) class already contains a button class? 3596 * 3597 * @param string $class 3598 * The class we want to check. 3599 * 3600 * @return bool 3601 * True if $class already contains a button class. Otherwise false. 3602 */ 3603 function defaultButtonClassExists($class = '') 3604 { 3605 // Bootstrap button classes. 3606 // @see http://getbootstrap.com/css/#buttons-options 3607 $btnClasses = array( 3608 'btn-default', 3609 'btn-primary', 3610 'btn-success', 3611 'btn-info', 3612 'btn-warning', 3613 'btn-danger', 3614 'btn-link', 3615 ); 3616 3617 foreach($btnClasses as $btnClass) { 3618 if(strpos($class, $btnClass, 0) !== false) 3619 { 3620 return true; 3621 } 3622 } 3623 3624 return false; 3625 } 3626 3627 3628 3629 3630 3631 3632 /** 3633 * Helper function to get default button class by action. 3634 * 3635 * @param string $action 3636 * Action for a button. See button(). 3637 * 3638 * @return string $class 3639 * Default button class. 3640 */ 3641 function getDefaultButtonClassByAction($action) 3642 { 3643 switch($action) 3644 { 3645 case 'update': 3646 case 'create': 3647 case 'import': 3648 case 'submit': 3649 case 'success': 3650 $class = 'btn-success'; 3651 break; 3652 3653 case 'checkall': 3654 $class = 'btn-default'; 3655 break; 3656 3657 case 'cancel': 3658 $class = 'btn-default'; 3659 break; 3660 3661 case 'delete': 3662 case 'danger': 3663 $class = 'btn-danger'; 3664 break; 3665 3666 case 'execute': 3667 $class = 'btn-success'; 3668 break; 3669 3670 case 'other': 3671 case 'login': 3672 case 'primary': 3673 $class = 'btn-primary'; 3674 break; 3675 3676 case 'warning': 3677 case 'confirm': 3678 $class = 'btn-warning'; 3679 break; 3680 3681 case 'batch': 3682 case 'batch e-hide-if-js': 3683 $class = 'btn-primary'; 3684 break; 3685 3686 case 'filter': 3687 case 'filter e-hide-if-js': 3688 $class = 'btn-primary'; 3689 break; 3690 3691 case 'default': 3692 default: 3693 $class = 'btn-default'; 3694 break; 3695 } 3696 3697 return $class; 3698 } 3699 3700 function getNext() 3701 { 3702 if(!$this->_tabindex_enabled) return 0; 3703 $this->_tabindex_counter += 1; 3704 return $this->_tabindex_counter; 3705 } 3706 3707 function getCurrent() 3708 { 3709 if(!$this->_tabindex_enabled) return 0; 3710 return $this->_tabindex_counter; 3711 } 3712 3713 function resetTabindex($reset = 0) 3714 { 3715 $this->_tabindex_counter = $reset; 3716 } 3717 3718 function get_attributes($options, $name = '', $value = '') 3719 { 3720 $ret = ''; 3721 // 3722 foreach ($options as $option => $optval) 3723 { 3724 $optval = trim($optval); 3725 switch ($option) 3726 { 3727 3728 case 'id': 3729 $ret .= $this->_format_id($optval, $name, $value); 3730 break; 3731 3732 case 'class': 3733 if(!empty($optval)) $ret .= " class='{$optval}'"; 3734 break; 3735 3736 case 'size': 3737 if($optval) $ret .= " size='{$optval}'"; 3738 break; 3739 3740 case 'title': 3741 if($optval) $ret .= " title='{$optval}'"; 3742 break; 3743 3744 case 'label': 3745 if($optval) $ret .= " label='{$optval}'"; 3746 break; 3747 3748 case 'tabindex': 3749 if($optval) $ret .= " tabindex='{$optval}'"; 3750 elseif(false === $optval || !$this->_tabindex_enabled) break; 3751 else 3752 { 3753 $this->_tabindex_counter += 1; 3754 $ret .= " tabindex='".$this->_tabindex_counter."'"; 3755 } 3756 break; 3757 3758 case 'readonly': 3759 if($optval) $ret .= " readonly='readonly'"; 3760 break; 3761 3762 case 'multiple': 3763 if($optval) $ret .= " multiple='multiple'"; 3764 break; 3765 3766 case 'selected': 3767 if($optval) $ret .= " selected='selected'"; 3768 break; 3769 3770 case 'maxlength': 3771 if($optval) $ret .= " maxlength='{$optval}'"; 3772 break; 3773 3774 case 'checked': 3775 if($optval) $ret .= " checked='checked'"; 3776 break; 3777 3778 case 'disabled': 3779 if($optval) $ret .= " disabled='disabled'"; 3780 break; 3781 3782 case 'required': 3783 if($optval) $ret .= " required='required'"; 3784 break; 3785 3786 case 'autofocus': 3787 if($optval) $ret .= " autofocus='autofocus'"; 3788 break; 3789 3790 case 'placeholder': 3791 if($optval) { 3792 $optval = deftrue($optval, $optval); 3793 $ret .= " placeholder='{$optval}'"; 3794 } 3795 break; 3796 3797 case 'wrap': 3798 if($optval) $ret .= " wrap='{$optval}'"; 3799 break; 3800 3801 case 'autocomplete': 3802 if($optval) $ret .= " autocomplete='{$optval}'"; 3803 break; 3804 3805 case 'pattern': 3806 if($optval) $ret .= " pattern='{$optval}'"; 3807 break; 3808 3809 case 'other': 3810 if($optval) $ret .= " $optval"; 3811 break; 3812 } 3813 3814 if(substr($option,0,5) =='data-') 3815 { 3816 $ret .= " ".$option."='{$optval}'"; 3817 } 3818 3819 } 3820 3821 return $ret; 3822 } 3823 3824 /** 3825 * Auto-build field attribute id 3826 * 3827 * @param string $id_value value for attribute id passed with the option array 3828 * @param string $name the name attribute passed to that field 3829 * @param unknown_type $value the value attribute passed to that field 3830 * @return string formatted id attribute 3831 */ 3832 function _format_id($id_value, $name, $value = '', $return_attribute = 'id') 3833 { 3834 if($id_value === false) return ''; 3835 3836 //format data first 3837 $name = trim($this->name2id($name), '-'); 3838 $value = trim(preg_replace('#[^a-zA-Z0-9\-]#','-', $value), '-'); 3839 //$value = trim(preg_replace('#[^a-z0-9\-]#/i','-', $value), '-'); // This should work - but didn't for me! 3840 $value = trim(str_replace("/","-",$value), '-'); // Why? 3841 if(!$id_value && is_numeric($value)) $id_value = $value; 3842 3843 // clean - do it better, this could lead to dups 3844 $id_value = trim($id_value, '-'); 3845 3846 if(empty($id_value) ) return " {$return_attribute}='{$name}".($value ? "-{$value}" : '')."'";// also useful when name is e.g. name='my_name[some_id]' 3847 elseif(is_numeric($id_value) && $name) return " {$return_attribute}='{$name}-{$id_value}'";// also useful when name is e.g. name='my_name[]' 3848 else return " {$return_attribute}='{$id_value}'"; 3849 } 3850 3851 function name2id($name) 3852 { 3853 $name = strtolower($name); 3854 return rtrim(str_replace(array('[]', '[', ']', '_', '/', ' ','.', '(', ')', '::', ':', '?','='), array('-', '-', '', '-', '-', '-', '-','','','-','','-','-'), $name), '-'); 3855 } 3856 3857 /** 3858 * Format options based on the field type, 3859 * merge with default 3860 * 3861 * @param string $type 3862 * @param string $name form name attribute value 3863 * @param array|string $user_options 3864 * @return array merged options 3865 */ 3866 function format_options($type, $name, $user_options=null) 3867 { 3868 if(is_string($user_options)) 3869 { 3870 parse_str($user_options, $user_options); 3871 } 3872 3873 $def_options = $this->_default_options($type); 3874 3875 3876 if(is_array($user_options)) 3877 { 3878 $user_options['name'] = $name; //required for some of the automated tasks 3879 3880 foreach (array_keys($user_options) as $key) 3881 { 3882 if(!isset($def_options[$key]) && substr($key,0,5)!='data-') unset($user_options[$key]); // data-xxxx exempt //remove it? 3883 } 3884 } 3885 else 3886 { 3887 $user_options = array('name' => $name); //required for some of the automated tasks 3888 } 3889 3890 return array_merge($def_options, $user_options); 3891 } 3892 3893 /** 3894 * Get default options array based on the field type 3895 * 3896 * @param string $type 3897 * @return array default options 3898 */ 3899 function _default_options($type) 3900 { 3901 if(isset($this->_cached_attributes[$type])) return $this->_cached_attributes[$type]; 3902 3903 $def_options = array( 3904 'id' => '', 3905 'class' => '', 3906 'title' => '', 3907 'size' => '', 3908 'readonly' => false, 3909 'selected' => false, 3910 'checked' => false, 3911 'disabled' => false, 3912 'required' => false, 3913 'autofocus' => false, 3914 'tabindex' => 0, 3915 'label' => '', 3916 'placeholder' => '', 3917 'pattern' => '', 3918 'other' => '', 3919 'autocomplete' => '', 3920 'maxlength' => '', 3921 'wrap' => '', 3922 'multiple' => '', 3923 3924 // 'multiple' => false, - see case 'select' 3925 ); 3926 3927 $form_control = (THEME_LEGACY !== true) ? ' form-control' : ''; 3928 3929 switch ($type) { 3930 case 'hidden': 3931 $def_options = array('id' => false, 'disabled' => false, 'other' => ''); 3932 break; 3933 3934 case 'text': 3935 $def_options['class'] = 'tbox input-text'.$form_control; 3936 unset($def_options['selected'], $def_options['checked']); 3937 break; 3938 3939 case 'number': 3940 $def_options['class'] = 'tbox '.$form_control; 3941 break; 3942 3943 case 'file': 3944 $def_options['class'] = 'tbox file'; 3945 unset($def_options['selected'], $def_options['checked']); 3946 break; 3947 3948 case 'textarea': 3949 $def_options['class'] = 'tbox textarea'.$form_control; 3950 unset($def_options['selected'], $def_options['checked'], $def_options['size']); 3951 break; 3952 3953 case 'select': 3954 $def_options['class'] = 'tbox select'.$form_control; 3955 $def_options['multiple'] = false; 3956 unset($def_options['checked']); 3957 break; 3958 3959 case 'option': 3960 $def_options = array('class' => '', 'selected' => false, 'other' => '', 'disabled' => false, 'label' => ''); 3961 break; 3962 3963 case 'radio': 3964 //$def_options['class'] = ' '; 3965 $def_options = array('class' => '', 'id'=>''); 3966 unset($def_options['size'], $def_options['selected']); 3967 break; 3968 3969 case 'checkbox': 3970 unset($def_options['size'], $def_options['selected']); 3971 break; 3972 3973 case 'submit': 3974 $def_options['class'] = 'button btn btn-primary'; 3975 unset($def_options['checked'], $def_options['selected'], $def_options['readonly']); 3976 break; 3977 3978 case 'submit_image': 3979 $def_options['class'] = 'action'; 3980 unset($def_options['checked'], $def_options['selected'], $def_options['readonly']); 3981 break; 3982 3983 case 'admin_button': 3984 unset($def_options['checked'], $def_options['selected'], $def_options['readonly']); 3985 break; 3986 3987 } 3988 3989 $this->_cached_attributes[$type] = $def_options; 3990 return $def_options; 3991 } 3992 3993 function columnSelector($columnsArray, $columnsDefault = array(), $id = 'column_options') 3994 { 3995 $columnsArray = array_filter($columnsArray); 3996 3997 // navbar-header nav-header 3998 // navbar-header nav-header 3999 $text = '<div class="col-selection dropdown e-tip pull-right float-right" data-placement="left"> 4000 <a class="dropdown-toggle" title="'.LAN_EFORM_008.'" data-toggle="dropdown" href="#"><b class="caret"></b></a> 4001 <ul class="list-group dropdown-menu col-selection e-noclick" role="menu" aria-labelledby="dLabel"> 4002 4003 <li class="list-group-item "><h5 class="list-group-item-heading">'.LAN_EFORM_009.'</h5></li> 4004 <li class="list-group-item col-selection-list"> 4005 <ul class="nav scroll-menu" >'; 4006 4007 unset($columnsArray['options'], $columnsArray['checkboxes']); 4008 4009 foreach($columnsArray as $key => $fld) 4010 { 4011 if(!isset($fld['type']) || $fld['type'] === null) // Fixes #4083 4012 { 4013 continue; 4014 } 4015 4016 if (empty($fld['forced']) && empty($fld['nolist']) && vartrue($fld['type'])!='hidden' && vartrue($fld['type'])!='upload') 4017 { 4018 $checked = (in_array($key,$columnsDefault)) ? TRUE : FALSE; 4019 $ttl = isset($fld['title']) ? defset($fld['title'], $fld['title']) : $key; 4020 4021 $text .= " 4022 <li role='menuitem'><a href='#'> 4023 ".$this->checkbox('e-columns[]', $key, $checked,'label='.$ttl)." 4024 </a> 4025 </li> 4026 "; 4027 } 4028 } 4029 4030 // has issues with the checkboxes. 4031 $text .= " 4032 </ul> 4033 </li> 4034 <li class='list-group-item'> 4035 <div id='{$id}-button' class='right'> 4036 ".$this->admin_button('etrigger_ecolumns', LAN_SAVE, 'btn btn-primary btn-small')." 4037 </div> 4038 </li> 4039 </ul> 4040 </div>"; 4041 4042 // $text .= "</div></div>"; 4043 4044 $text .= ""; 4045 4046 4047 /* 4048 $text = '<div class="dropdown"> 4049 <a class="dropdown-toggle" data-toggle="dropdown" href="#"><b class="caret"></b></a> 4050 <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"> 4051 <li>hi</li> 4052 </ul> 4053 </div>'; 4054 */ 4055 return $text; 4056 } 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 function colGroup($fieldarray, $columnPref = '') 4069 { 4070 $text = ""; 4071 $count = 0; 4072 foreach($fieldarray as $key=>$val) 4073 { 4074 if ((in_array($key, $columnPref) || $key=='options' || vartrue($val['forced'])) && !vartrue($val['nolist'])) 4075 { 4076 4077 $class = vartrue($val['class']) ? 'class="'.$val['class'].'"' : ''; 4078 $width = vartrue($val['width']) ? ' style="width:'.$val['width'].'"' : ''; 4079 $text .= '<col '.$class.$width.' /> 4080 '; 4081 $count++; 4082 } 4083 } 4084 4085 return ' 4086 <colgroup> 4087 '.$text.' 4088 </colgroup> 4089 '; 4090 } 4091 4092 function thead($fieldarray, $columnPref = array(), $querypattern = '', $requeststr = '') 4093 { 4094 $text = ""; 4095 4096 $querypattern = filter_var($querypattern, FILTER_SANITIZE_STRING); 4097 if(!$requeststr) $requeststr = rawurldecode(e_QUERY); 4098 $requeststr = filter_var($requeststr, FILTER_SANITIZE_STRING); 4099 4100 // Recommended pattern: mode=list&field=[FIELD]&asc=[ASC]&from=[FROM] 4101 if(strpos($querypattern,'&')!==FALSE) 4102 { 4103 // we can assume it's always $_GET since that's what it will generate 4104 // more flexible (e.g. pass default values for order/field when they can't be found in e_QUERY) & secure 4105 $tmp = str_replace('&', '&', $requeststr ? $requeststr : e_QUERY); 4106 parse_str($tmp, $tmp); 4107 4108 $etmp = array(); 4109 parse_str(str_replace('&', '&', $querypattern), $etmp); 4110 } 4111 else // Legacy Queries. eg. main.[FIELD].[ASC].[FROM] 4112 { 4113 $tmp = explode(".", ($requeststr ? $requeststr : e_QUERY)); 4114 $etmp = explode(".", $querypattern); 4115 } 4116 4117 foreach($etmp as $key => $val) // I'm sure there's a more efficient way to do this, but too tired to see it right now!. 4118 { 4119 if($val == "[FIELD]") 4120 { 4121 $field = varset($tmp[$key]); 4122 } 4123 4124 if($val == "[ASC]") 4125 { 4126 $ascdesc = varset($tmp[$key]); 4127 } 4128 if($val == "[FROM]") 4129 { 4130 $fromval = varset($tmp[$key]); 4131 } 4132 } 4133 4134 if(!varset($fromval)){ $fromval = 0; } 4135 4136 $sorted = varset($ascdesc); 4137 $ascdesc = ($sorted == 'desc') ? 'asc' : 'desc'; 4138 4139 foreach($fieldarray as $key=>$val) 4140 { 4141 if ((in_array($key, $columnPref) || ($key === 'options' && isset($val['title'])) || (vartrue($val['forced']))) && !vartrue($val['nolist'])) 4142 { 4143 $cl = (vartrue($val['thclass'])) ? " class='".$val['thclass']."'" : ""; 4144 4145 $aClass = ($key === $field) ? "class='sorted-".$sorted."'" : ""; 4146 4147 $text .= " 4148 <th id='e-column-".str_replace('_', '-', $key)."'{$cl}> 4149 "; 4150 4151 if($querypattern!="" && !vartrue($val['nosort']) && $key != "options" && $key != "checkboxes") 4152 { 4153 $from = ($key == $field) ? $fromval : 0; 4154 $srch = array("[FIELD]","[ASC]","[FROM]"); 4155 $repl = array($key,$ascdesc,$from); 4156 $val['url'] = e_SELF."?".str_replace($srch,$repl,$querypattern); 4157 } 4158 4159 4160 4161 $text .= (vartrue($val['url'])) ? "<a ".$aClass." title=\"".LAN_SORT."\" href='".str_replace(array('&', '&'), array('&', '&'),$val['url'])."'>" : ""; // Really this column-sorting link should be auto-generated, or be autocreated via unobtrusive js. 4162 $text .= defset($val['title'], $val['title']); 4163 $text .= ($val['url']) ? "</a>" : ""; 4164 $text .= ($key === "options" && !vartrue($val['noselector'])) ? $this->columnSelector($fieldarray, $columnPref) : ""; 4165 $text .= ($key === "checkboxes") ? $this->checkbox_toggle('e-column-toggle', vartrue($val['toggle'], 'multiselect')) : ""; 4166 4167 4168 $text .= " 4169 </th> 4170 "; 4171 } 4172 } 4173 4174 return " 4175 <thead> 4176 <tr >".$text."</tr> 4177 </thead> 4178 "; 4179 4180 } 4181 4182 4183 /** 4184 * Render Table cells from hooks. 4185 * @param array $data 4186 * @return string 4187 */ 4188 function renderHooks($data) 4189 { 4190 $hooks = e107::getEvent()->triggerHook($data); 4191 4192 $text = ""; 4193 4194 if(!empty($hooks)) 4195 { 4196 foreach($hooks as $plugin => $hk) 4197 { 4198 $text .= "\n\n<!-- Hook : {$plugin} -->\n"; 4199 4200 if(!empty($hk)) 4201 { 4202 foreach($hk as $hook) 4203 { 4204 $text .= "\t\t\t<tr>\n"; 4205 $text .= "\t\t\t<td>".$hook['caption']."</td>\n"; 4206 $text .= "\t\t\t<td>".$hook['html'].""; 4207 $text .= (varset($hook['help'])) ? "\n<span class='field-help'>".$hook['help']."</span>" : ""; 4208 $text .= "</td>\n\t\t\t</tr>\n"; 4209 } 4210 4211 4212 } 4213 } 4214 } 4215 4216 return $text; 4217 } 4218 4219 4220 4221 4222 /** 4223 * Render Related Items for the current page/news-item etc. 4224 * @param string $type : comma separated list. ie. plugin folder names. 4225 * @param string $tags : comma separated list of keywords to return related items of. 4226 * @param array $curVal. eg. array('page'=> current-page-id-value); 4227 */ 4228 function renderRelated($parm,$tags, $curVal, $template=null) //XXX TODO Cache! 4229 { 4230 4231 if(empty($tags)) 4232 { 4233 return; 4234 } 4235 4236 $tags = str_replace(', ',',', $tags); //BC Fix, all tags should be comma separated without spaces ie. one,two NOT one, two 4237 4238 e107::setRegistry('core/form/related',$tags); // TODO Move to elsewhere so it works without rendering? e107::related() set and get by plugins? 4239 4240 if(!varset($parm['limit'])) 4241 { 4242 $parm = array('limit' => 5); 4243 } 4244 4245 if(!varset($parm['types'])) 4246 { 4247 $parm['types'] = 'news'; 4248 } 4249 4250 if(empty($template)) 4251 { 4252 $TEMPLATE['start'] = "<hr><h4>".defset('LAN_RELATED', 'Related')."</h4><ul class='e-related'>"; 4253 $TEMPLATE['item'] = "<li><a href='{RELATED_URL}'>{RELATED_TITLE}</a></li>"; 4254 $TEMPLATE['end'] = "</ul>"; 4255 4256 } 4257 else 4258 { 4259 $TEMPLATE = $template; 4260 } 4261 4262 4263 4264 $tp = e107::getParser(); 4265 4266 $types = explode(',',$parm['types']); 4267 $list = array(); 4268 4269 $head = $tp->parseTemplate($TEMPLATE['start'],true); 4270 4271 foreach($types as $plug) 4272 { 4273 4274 if(!$obj = e107::getAddon($plug,'e_related')) 4275 { 4276 continue; 4277 } 4278 4279 $parm['current'] = intval(varset($curVal[$plug])); 4280 4281 4282 4283 4284 $tmp = $obj->compile($tags,$parm); 4285 4286 if(count($tmp)) 4287 { 4288 foreach($tmp as $val) 4289 { 4290 4291 $row = array( 4292 'RELATED_URL' => $tp->replaceConstants($val['url'],'full'), 4293 'RELATED_TITLE' => $val['title'], 4294 'RELATED_IMAGE' => $tp->toImage($val['image']), 4295 'RELATED_SUMMARY' => $tp->toHTML($val['summary'],true,'BODY'), 4296 'RELATED_DATE' => $val['date'], 4297 ); 4298 4299 $list[] = $tp->simpleParse($TEMPLATE['item'], $row); 4300 4301 } 4302 } 4303 } 4304 4305 if(count($list)) 4306 { 4307 return "<div class='e-related clearfix hidden-print'>".$head.implode("\n",$list).$tp->parseTemplate($TEMPLATE['end'], true)."</div>"; 4308 4309 // return "<div class='e-related clearfix hidden-print'><hr><h4>".defset('LAN_RELATED', 'Related')."</h4><ul class='e-related'>".implode("\n",$list)."</div>"; //XXX Tablerender? 4310 } 4311 4312 } 4313 4314 4315 4316 /** 4317 * Render Table cells from field listing. 4318 * @param array $fieldarray - eg. $this->fields 4319 * @param array $currentlist - eg $this->fieldpref 4320 * @param array $fieldvalues - eg. $row 4321 * @param string $pid - eg. table_id 4322 * @return string 4323 */ 4324 function renderTableCells($fieldarray, $currentlist, $fieldvalues, $pid) 4325 { 4326 4327 $cnt = 0; 4328 $text = ''; 4329 4330 4331 foreach ($fieldarray as $field => $data) 4332 { 4333 4334 4335 // shouldn't happen... test with Admin->Users with user_xup visible and NULL values in user_xup table column before re-enabling this code. 4336 /* 4337 if(!isset($fieldvalues[$field]) && vartrue($data['alias'])) 4338 { 4339 $fieldvalues[$data['alias']] = $fieldvalues[$data['field']]; 4340 $field = $data['alias']; 4341 } 4342 */ 4343 4344 //Not found 4345 if((empty($data['forced']) && !in_array($field, $currentlist)) || !empty($data['nolist'])) 4346 { 4347 continue; 4348 } 4349 elseif(vartrue($data['type']) != 'method' && empty($data['forced']) && !isset($fieldvalues[$field]) && $fieldvalues[$field] !== null) 4350 { 4351 $text .= " 4352 <td> 4353 Not Found! ($field) 4354 </td> 4355 "; 4356 4357 continue; 4358 } 4359 4360 $tdclass = vartrue($data['class']); 4361 4362 if($field == 'checkboxes') $tdclass = $tdclass ? $tdclass.' autocheck e-pointer' : 'autocheck e-pointer'; 4363 4364 if($field == 'options') $tdclass = $tdclass ? $tdclass.' options' : 'options'; 4365 4366 4367 // there is no other way for now - prepare user data 4368 if('user' == vartrue($data['type']) /* && isset($data['readParms']['idField'])*/) 4369 { 4370 if(varset($data['readParms']) && is_string($data['readParms'])) parse_str($data['readParms'], $data['readParms']); 4371 if(isset($data['readParms']['idField'])) 4372 { 4373 $data['readParms']['__idval'] = $fieldvalues[$data['readParms']['idField']]; 4374 } 4375 elseif(isset($fieldvalues['user_id'])) // Default 4376 { 4377 $data['readParms']['__idval'] = $fieldvalues['user_id']; 4378 } 4379 4380 if(isset($data['readParms']['nameField'])) 4381 { 4382 $data['readParms']['__nameval'] = $fieldvalues[$data['readParms']['nameField']]; 4383 } 4384 elseif(isset($fieldvalues['user_name'])) // Default 4385 { 4386 $data['readParms']['__nameval'] = $fieldvalues['user_name']; 4387 } 4388 4389 } 4390 4391 $value = $this->renderValue($field, varset($fieldvalues[$field]), $data, varset($fieldvalues[$pid])); 4392 4393 4394 if($tdclass) 4395 { 4396 $tdclass = ' class="'.$tdclass.'"'; 4397 } 4398 4399 $text .= ' 4400 <td'.$tdclass.'> 4401 '.$value.' 4402 </td> 4403 '; 4404 4405 $cnt++; 4406 } 4407 4408 if($cnt) 4409 { 4410 return $text; 4411 } 4412 4413 return null; 4414 4415 } 4416 4417 /** 4418 * Render Table row and cells from field listing. 4419 * 4420 * @param array $fieldArray - eg. $this->fields 4421 * @param array $fieldPref - eg $this->fieldpref 4422 * @param array $fieldValues - eg. $row 4423 * @param string $pid - eg. table_id 4424 * @return string 4425 */ 4426 function renderTableRow($fieldArray, $fieldPref, $fieldValues, $pid) 4427 { 4428 4429 if(!$ret = $this->renderTableCells($fieldArray, $fieldPref, $fieldValues, $pid)) 4430 { 4431 return ''; 4432 } 4433 4434 $trclass = ''; 4435 // $trclass = vartrue($fieldvalues['__trclass']) ? ' class="'.$trclass.'"' : ''; 4436 unset($fieldValues['__trclass']); 4437 4438 return ' 4439 <tr'.$trclass.' id="row-' . $fieldValues[$pid].'"> 4440 '.$ret.' 4441 </tr> 4442 '; 4443 } 4444 4445 4446 4447 /** 4448 * Inline Token 4449 * @return string 4450 */ 4451 private function inlineToken() 4452 { 4453 $this->_inline_token = $this->_inline_token ?: 4454 password_hash(session_id(), PASSWORD_DEFAULT, ['cost' => 04]); 4455 return $this->_inline_token; 4456 } 4457 4458 /** 4459 * Create an Inline Edit link. 4460 * @param string $dbField : field being edited 4461 * @param int $pid : primary ID of the row being edited. 4462 * @param string $fieldName - Description of the field name (caption) 4463 * @param mixed $curVal : existing value of in the field 4464 * @param mixed $linkText : existing value displayed 4465 * @param string $type text|textarea|select|date|checklist 4466 * @param array $array : array data used in dropdowns etc. 4467 */ 4468 public function renderInline($dbField, $pid, $fieldName, $curVal, $linkText, $type='text', $array=null, $options=array()) 4469 { 4470 $jsonArray = array(); 4471 4472 if(!empty($array)) 4473 { 4474 foreach($array as $k=>$v) 4475 { 4476 $jsonArray[$k] = str_replace("'", "`", $v); 4477 } 4478 } 4479 4480 $source = e107::getParser()->toJSON($jsonArray, true); 4481 4482 $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 4483 4484 if(!isset($options['url'])) 4485 { 4486 $options['url'] = e_SELF."?mode={$mode}&action=inline&id={$pid}&ajax_used=1"; 4487 } 4488 4489 if(!empty($pid)) 4490 { 4491 $options['pk'] = $pid; 4492 } 4493 4494 $title = varset($options['title'] , (LAN_EDIT." ".$fieldName)); 4495 $class = varset($options['class'] ,''); 4496 4497 unset( $options['title']); 4498 4499 $text = "<a class='e-tip e-editable editable-click ".$class."' data-name='".$dbField."' "; 4500 $text .= (is_array($array)) ? "data-source='".$source."' " : ""; 4501 $text .= " title=\"".$title."\" data-type='".$type."' data-inputclass='x-editable-".$this->name2id($dbField)." ".$class."' data-value=\"{$curVal}\" href='#' "; 4502 4503 $options['token'] = $this->inlineToken(); 4504 4505 if(!empty($options)) 4506 { 4507 foreach($options as $k=>$opt) 4508 { 4509 if(!empty($opt)) 4510 { 4511 $text .= " data-".$k."='".$opt."'"; 4512 } 4513 } 4514 } 4515 4516 $text .= ">".$linkText."</a>"; 4517 4518 return $text; 4519 } 4520 4521 /** 4522 * Check if a value should be linked and wrap in <a> tag if required. 4523 * @todo global pref for the target option? 4524 * @param mixed $value 4525 * @param array $parms 4526 * @param $id 4527 * @example $frm->renderLink('label', array('link'=>'{e_PLUGIN}myplugin/myurl.php','target'=>'blank') 4528 * @example $frm->renderLink('label', array('link'=>'{e_PLUGIN}myplugin/myurl.php?id=[id]','target'=>'blank') 4529 * @example $frm->renderLink('label', array('link'=>'{e_PLUGIN}myplugin/myurl.php?id=[field-name]','target'=>'blank') 4530 * @example $frm->renderLink('label', array('link'=>'db-field-name','target'=>'blank') 4531 * @example $frm->renderLink('label', array('url'=>'e_url.php key','title'=>'click here'); 4532 * @return string 4533 */ 4534 public function renderLink($value, $parms, $id=null) 4535 { 4536 if(empty($parms['link']) && empty($parms['url'])) 4537 { 4538 return $value; 4539 } 4540 4541 /** @var e_admin_model $model */ 4542 if(!$model = e107::getRegistry('core/adminUI/currentListModel')) // Try list model 4543 { 4544 $model = e107::getRegistry('core/adminUI/currentModel'); // try create/edit model. 4545 } 4546 4547 $dialog = vartrue($parms['target']) =='dialog' ? " e-modal" : ""; // iframe 4548 $ext = vartrue($parms['target']) =='blank' ? " rel='external' " : ""; // new window 4549 $modal = vartrue($parms['target']) =='modal' ? " data-toggle='modal' data-cache='false' data-target='#uiModal' " : ""; 4550 4551 $link = null; 4552 4553 if(!empty($parms['url']) && !empty($model)) // ie. use e_url.php 4554 { 4555 //$plugin = $this->getController()->getPluginName(); 4556 if($plugin = e107::getRegistry('core/adminUI/currentPlugin')) 4557 { 4558 $data = $model->getData(); 4559 $link = e107::url($plugin,$parms['url'],$data); 4560 } 4561 } 4562 elseif(!empty($model)) // old way. 4563 { 4564 $tp = e107::getParser(); 4565 4566 $data = $model->getData(); 4567 4568 $link = str_replace('[id]',$id,$parms['link']); 4569 $link = $tp->replaceConstants($link); // SEF URL is not important since we're in admin. 4570 4571 if($parms['link'] === 'sef' ) 4572 { 4573 if(!$model->getUrl()) 4574 { 4575 /** @var e_admin_controller_ui $controller */ 4576 $controller = $this->getController(); 4577 $model->setUrl($controller->getUrl()); 4578 } 4579 4580 // assemble the url 4581 $link = $model->url(null); 4582 } 4583 elseif(!empty($data[$parms['link']])) // support for a field-name as the link. eg. link_url. 4584 { 4585 $link = $tp->replaceConstants(vartrue($data[$parms['link']])); 4586 } 4587 elseif(strpos($link,'[')!==false && preg_match('/\[(\w+)\]/',$link, $match)) // field-name within [ ] brackets. 4588 { 4589 $field = $match[1]; 4590 $link = str_replace($match[0], $data[$field],$link); 4591 } 4592 } 4593 // in case something goes wrong... 4594 if($link) 4595 { 4596 return "<a class='e-tip{$dialog}' {$ext} href='".$link."' {$modal} title='".varset($parms['title'],LAN_EFORM_010)."' >".$value."</a>"; 4597 } 4598 4599 return $value; 4600 4601 } 4602 4603 private function renderOptions($parms, $id, $attributes) 4604 { 4605 $tp = e107::getParser(); 4606 $cls = false; 4607 4608 $editIconDefault = deftrue('ADMIN_EDIT_ICON', $tp->toGlyph('fa-edit')); 4609 $deleteIconDefault = deftrue('ADMIN_DELETE_ICON', $tp->toGlyph('fa-trash')); 4610/* 4611 if($attributes['grid']) 4612 { 4613 $editIconDefault = $tp->toGlyph('fa-edit'); 4614 $deleteIconDefault = $tp->toGlyph('fa-trash'); 4615 } 4616*/ 4617 /** @var e_admin_controller_ui $controller */ 4618 $controller = $this->getController(); 4619 $sf = $controller->getSortField(); 4620 4621 if(!isset($parms['sort']) && !empty($sf)) 4622 { 4623 $parms['sort'] = true; 4624 } 4625 4626 $text = "<div class='btn-group'>"; 4627 4628 if(!empty($parms['sort']) && empty($attributes['grid'])) 4629 { 4630 $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 4631 $from = intval(vartrue($_GET['from'],0)); 4632 $text .= "<a class='e-sort sort-trigger btn btn-default' style='cursor:move' data-target='".e_SELF."?mode={$mode}&action=sort&ajax_used=1&from={$from}' title='".LAN_RE_ORDER."'>".ADMIN_SORT_ICON."</a> "; 4633 } 4634 4635 4636 if(varset($parms['editClass'])) 4637 { 4638 $cls = (deftrue($parms['editClass'])) ? constant($parms['editClass']) : $parms['editClass']; 4639 } 4640 4641 if((false === $cls || check_class($cls)) && varset($parms['edit'],1) == 1) 4642 { 4643 4644 parse_str(str_replace('&', '&', e_QUERY), $query); //FIXME - FIX THIS 4645 // keep other vars in tact 4646 $query['action'] = 'edit'; 4647 $query['id'] = $id; 4648 4649 4650 if(!empty($parms['target']) && $parms['target']=='modal') 4651 { 4652 $eModal = " e-modal "; 4653 $eModalCap = !empty($parms['modalCaption']) ? "data-modal-caption='".$parms['modalCaption']."'" : "data-modal-caption='#".$id."'"; 4654 $query['iframe'] = 1; 4655 } 4656 else 4657 { 4658 $eModal = ""; 4659 $eModalCap = ""; 4660 } 4661 4662 if(!empty($parms['modalSubmit'])) 4663 { 4664 $eModalCap .= " data-modal-submit='true'"; 4665 } 4666 4667 $query = http_build_query($query, null, '&'); 4668 $text .= "<a href='".e_SELF."?{$query}' class='btn btn-default btn-secondary".$eModal."' ".$eModalCap." title='".LAN_EDIT."' data-toggle='tooltip' data-placement='left'> 4669 ".$editIconDefault."</a>"; 4670 } 4671 4672 $delcls = !empty($attributes['noConfirm']) ? ' no-confirm' : ''; 4673 if(varset($parms['deleteClass']) && varset($parms['delete'],1) == 1) 4674 { 4675 $cls = (deftrue($parms['deleteClass'])) ? constant($parms['deleteClass']) : $parms['deleteClass']; 4676 4677 if(check_class($cls)) 4678 { 4679 $parms['class'] = 'action delete btn btn-default'.$delcls; 4680 unset($parms['deleteClass']); 4681 $parms['icon'] = $deleteIconDefault; 4682 $text .= $this->submit_image('etrigger_delete['.$id.']', $id, 'delete', LAN_DELETE.' [ ID: '.$id.' ]', $parms); 4683 } 4684 } 4685 else 4686 { 4687 $parms['class'] = 'action delete btn btn-default'.$delcls; 4688 $parms['icon'] = $deleteIconDefault; 4689 $text .= $this->submit_image('etrigger_delete['.$id.']', $id, 'delete', LAN_DELETE.' [ ID: '.$id.' ]', $parms); 4690 } 4691 4692 //$attributes['type'] = 'text'; 4693 $text .= "</div>"; 4694 4695 return $text; 4696 4697 } 4698 4699 /** 4700 * Render Field Value 4701 * @param string $field field name 4702 * @param mixed $value field value 4703 * @param array $attributes field attributes including render parameters, element options - see e_admin_ui::$fields for required format 4704 * @return string 4705 */ 4706 function renderValue($field, $value, $attributes, $id = 0) 4707 { 4708 4709 4710 if(!empty($attributes['multilan']) && is_array($value)) 4711 { 4712 $value = varset($value[e_LANGUAGE],''); 4713 } 4714 4715 $parms = array(); 4716 if(isset($attributes['readParms'])) 4717 { 4718 if(!is_array($attributes['readParms'])) parse_str($attributes['readParms'], $attributes['readParms']); 4719 $parms = $attributes['readParms']; 4720 } 4721 4722 // @see custom fields in cpage which accept json params. 4723 if(!empty($attributes['writeParms']) && $tmpOpt = e107::getParser()->isJSON($attributes['writeParms'])) 4724 { 4725 $attributes['writeParms'] = $tmpOpt; 4726 unset($tmpOpt); 4727 } 4728 4729 4730 4731 if(!empty($attributes['inline'])) $parms['editable'] = true; // attribute alias 4732 if(!empty($attributes['sort'])) $parms['sort'] = true; // attribute alias 4733 4734 if(!empty($parms['type'])) // Allow the use of a different 'type' in readMode. eg. type=method. 4735 { 4736 $attributes['type'] = $parms['type']; 4737 } 4738 4739 $this->renderValueTrigger($field, $value, $parms, $id); 4740 4741 $tp = e107::getParser(); 4742 switch($field) // special fields 4743 { 4744 case 'options': 4745 4746 if(!empty($attributes['type']) && ($attributes['type'] == "method")) // Allow override with 'options' function. 4747 { 4748 $attributes['mode'] = "read"; 4749 if(isset($attributes['method']) && $attributes['method'] && method_exists($this, $attributes['method'])) 4750 { 4751 $method = $attributes['method']; 4752 return $this->$method($parms, $value, $id, $attributes); 4753 4754 } 4755 elseif(method_exists($this, 'options')) 4756 { 4757 //return $this->options($field, $value, $attributes, $id); 4758 // consistent method arguments, fixed in admin cron administration 4759 $attributes['type'] = null; // prevent infinite loop. 4760 4761 return $this->options($parms, $value, $id, $attributes); 4762 } 4763 } 4764 4765 if(!$value) 4766 { 4767 $value = $this->renderOptions($parms, $id, $attributes); 4768 } 4769 4770 return $value; 4771 break; 4772 4773 case 'checkboxes': 4774 4775 //$attributes['type'] = 'text'; 4776 if(empty($attributes['writeParms'])) // avoid comflicts with a field called 'checkboxes' 4777 { 4778 $value = $this->checkbox(vartrue($attributes['toggle'], 'multiselect').'['.$id.']', $id); 4779 return $value; 4780 } 4781 4782 4783 break; 4784 } 4785 4786 if(!empty($attributes['grid']) && empty($attributes['type'])) 4787 { 4788 return null; 4789 } 4790 4791 if(empty($attributes['type'])) 4792 { 4793 e107::getDebug()->log("Field '".$field."' is missing a value for 'type'."); 4794 // e107::getDebug()->log($value); 4795 // e107::getDebug()->log($attributes); 4796 } 4797 4798 4799 switch($attributes['type']) 4800 { 4801 case 'number': 4802 if(!$value) $value = '0'; 4803 4804 if($parms) 4805 { 4806 if(!isset($parms['sep'])) $value = number_format($value, varset($parms['decimals'],0)); 4807 else $value = number_format($value, $parms['decimals'], vartrue($parms['point'], '.'), vartrue($parms['sep'], ' ')); 4808 } 4809 4810 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 4811 { 4812 $value = $this->renderInline($field,$id,$attributes['title'],$value, $value, 'number'); 4813 } 4814 elseif(!empty($parms['link'])) 4815 { 4816 $value = $this->renderLink($value,$parms,$id); 4817 } 4818 4819 4820 $value = vartrue($parms['pre']).$value.vartrue($parms['post']); 4821 // else same 4822 break; 4823 4824 case 'country': 4825 4826 $_value = $this->getCountry($value); 4827 4828 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 4829 { 4830 $arr = $this->getCountry(); 4831 $value = $this->renderInline($field,$id,$attributes['title'],$value, $_value, 'select', $arr); 4832 } 4833 else 4834 { 4835 $value = $_value; 4836 } 4837 4838 break; 4839 4840 case 'ip': 4841 //$e107 = e107::getInstance(); 4842 $value = "<span title='".$value."'>".e107::getIPHandler()->ipDecode($value).'</span>';; 4843 // else same 4844 break; 4845 4846 case 'templates': 4847 case 'layouts': 4848 4849 if(!empty($attributes['writeParms'])) 4850 { 4851 if(is_string($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']); 4852 } 4853 4854 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 4855 { 4856 $wparms = $attributes['writeParms']; 4857 4858 $location = vartrue($wparms['plugin']); // empty - core 4859 $ilocation = vartrue($wparms['id'], $location); // omit if same as plugin name 4860 $where = vartrue($wparms['area'], 'front'); //default is 'front' 4861 $filter = varset($wparms['filter']); 4862 $merge = isset($wparms['merge']) ? (bool) $wparms['merge'] : true; 4863 4864 $layouts = e107::getLayouts($location, $ilocation, $where, $filter, $merge, false); 4865 4866 $label = varset($layouts[$value], $value); 4867 4868 $value = $this->renderInline($field, $id, $attributes['title'], $value, $label, 'select', $layouts); 4869 } 4870 4871 $value = vartrue($parms['pre']) . $value . vartrue($parms['post']); 4872 break; 4873 4874 case 'checkboxes': 4875 case 'comma': 4876 case 'dropdown': 4877 // XXX - should we use readParams at all here? see writeParms check below 4878 4879 if($parms && is_array($parms)) // FIXME - add support for multi-level arrays (option groups) 4880 { 4881 //FIXME return no value at all when 'editable=1' is a readParm. See FAQs templates. 4882 // $value = vartrue($parms['pre']).vartrue($parms[$value]).vartrue($parms['post']); 4883 // break; 4884 } 4885 4886 // NEW - multiple (array values) support 4887 // FIXME - add support for multi-level arrays (option groups) 4888 if(!is_array($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']); 4889 $wparms = $attributes['writeParms']; 4890 4891 if(!is_array(varset($wparms['__options']))) parse_str($wparms['__options'], $wparms['__options']); 4892 4893 if(!empty($wparms['optArray'])) 4894 { 4895 $fopts = $wparms; 4896 $wparms = $fopts['optArray']; 4897 unset($fopts['optArray']); 4898 $wparms['__options'] = $fopts; 4899 } 4900 4901 4902 $opts = $wparms['__options']; 4903 unset($wparms['__options']); 4904 $_value = $value; 4905 4906 if($attributes['type'] == 'checkboxes' || $attributes['type'] == 'comma') 4907 { 4908 $opts['multiple'] = true; 4909 } 4910 4911 if(!empty($opts['multiple'])) 4912 { 4913 $ret = array(); 4914 $value = is_array($value) ? $value : explode(',', $value); 4915 foreach ($value as $v) 4916 { 4917 if(isset($wparms[$v])) $ret[] = $wparms[$v]; 4918 } 4919 $value = implode(', ', $ret); 4920 4921 4922 } 4923 else 4924 { 4925 $ret = ''; 4926 if(isset($wparms[$value])) $ret = $wparms[$value]; 4927 $value = $ret; 4928 } 4929 4930 $value = ($value ? vartrue($parms['pre']).defset($value, $value).vartrue($parms['post']) : ''); 4931 4932 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 4933 { 4934 $xtype = ($attributes['type'] == 'dropdown') ? 'select' : 'checklist'; 4935 $value = $this->renderInline($field, $id, $attributes['title'], $_value, $value, $xtype, $wparms); 4936 } 4937 4938 // return ; 4939 break; 4940 4941 case 'radio': 4942 4943 4944 if($parms && isset($parms[$value])) // FIXME - add support for multi-level arrays (option groups) 4945 { 4946 $value = vartrue($parms['pre']).vartrue($parms[$value]).vartrue($parms['post']); 4947 break; 4948 } 4949 4950 if(!is_array($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']); 4951 4952 if(!empty($attributes['writeParms']['optArray'])) 4953 { 4954 $radioValue = $attributes['writeParms']['optArray'][$value]; 4955 4956 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 4957 { 4958 $radioValue = $this->renderInline($field, $id, $attributes['title'], $value, $radioValue, 'select', $attributes['writeParms']['optArray']); 4959 } 4960 } 4961 else 4962 { 4963 $radioValue = vartrue($attributes['writeParms'][$value]); 4964 } 4965 4966 4967 $value = vartrue($attributes['writeParms']['__options']['pre']).$radioValue.vartrue($attributes['writeParms']['__options']['post']); 4968 break; 4969 4970 case 'tags': 4971 if(!empty($parms['constant'])) 4972 { 4973 $value = defset($value, $value); 4974 } 4975 4976 if(!empty($parms['truncate'])) 4977 { 4978 $value = $tp->text_truncate($value, $parms['truncate'], '...'); 4979 } 4980 elseif(!empty($parms['htmltruncate'])) 4981 { 4982 $value = $tp->html_truncate($value, $parms['htmltruncate'], '...'); 4983 } 4984 if(!empty($parms['wrap'])) 4985 { 4986 $value = $tp->htmlwrap($value, (int) $parms['wrap'], varset($parms['wrapChar'], ' ')); 4987 } 4988 4989 $value = $this->renderLink($value,$parms,$id); 4990 4991 if(empty($value)) 4992 { 4993 $value = '-'; 4994 $setValue = "data-value=''"; 4995 } 4996 else 4997 { 4998 $setValue = ""; 4999 5000 if($attributes['type'] == 'tags' && !empty($value)) 5001 { 5002 $setValue = "data-value='" . $value . "'"; 5003 $value = str_replace(",", ", ", $value); // add spaces so it wraps, but don't change the actual values. 5004 } 5005 } 5006 5007 5008 if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up 5009 { 5010 $options['selectize'] = array( 5011 'create' => true, 5012 'maxItems' => vartrue($parms['maxItems'], 7), 5013 'mode' => 'multi', 5014 'e_editable' => $field . '_' . $id, 5015 ); 5016 5017 $tpl = $this->text($field, $value, 80, $options); 5018 5019 $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 5020 $value = "<a id='" . $field . '_' . $id . "' class='e-tip e-editable editable-click editable-tags' data-emptytext='-' data-tpl='" . str_replace("'", '"', $tpl) . "' data-name='" . $field . "' data-token='".$this->inlineToken()."' title=\"" . LAN_EDIT . " " . $attributes['title'] . "\" data-type='text' data-pk='" . $id . "' " . $setValue . " data-url='" . e_SELF . "?mode={$mode}&action=inline&id={$id}&ajax_used=1' href='#'>" . $value . "</a>"; 5021 } 5022 5023 $value = vartrue($parms['pre']) . $value . vartrue($parms['post']); 5024 break; 5025 5026 case 'text': 5027 5028 if(!empty($parms['constant'])) 5029 { 5030 $value = defset($value,$value); 5031 } 5032 5033 if(vartrue($parms['truncate'])) 5034 { 5035 $value = $tp->text_truncate($value, $parms['truncate'], '...'); 5036 } 5037 elseif(vartrue($parms['htmltruncate'])) 5038 { 5039 $value = $tp->html_truncate($value, $parms['htmltruncate'], '...'); 5040 } 5041 if(vartrue($parms['wrap'])) 5042 { 5043 $value = $tp->htmlwrap($value, (int)$parms['wrap'], varset($parms['wrapChar'], ' ')); 5044 } 5045 5046 $value = $this->renderLink($value,$parms,$id); 5047 5048 5049 if(empty($value)) 5050 { 5051 $value = '-'; 5052 $setValue = "data-value=''"; 5053 } 5054 else 5055 { 5056 $setValue = ""; 5057 5058 if($attributes['type'] == 'tags' && !empty($value)) 5059 { 5060 $setValue = "data-value='".$value."'"; 5061 $value = str_replace(",", ", ", $value); // add spaces so it wraps, but don't change the actual values. 5062 } 5063 } 5064 5065 5066 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 5067 { 5068 $value = $this->renderInline($field,$id,$attributes['title'],$value, $value); 5069 } 5070 5071 $value = vartrue($parms['pre']).$value.vartrue($parms['post']); 5072 break; 5073 5074 5075 5076 case 'bbarea': 5077 case 'textarea': 5078 5079 5080 if($attributes['type'] == 'textarea' && !vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up 5081 { 5082 return $this->renderInline($field,$id,$attributes['title'],$value,substr($value,0,50)."...",'textarea'); //FIXME. 5083 } 5084 5085 5086 $expand = '<span class="e-expandit-ellipsis">...</span>'; 5087 $toexpand = false; 5088 if($attributes['type'] == 'bbarea' && !isset($parms['bb'])) $parms['bb'] = true; //force bb parsing for bbareas 5089 $elid = trim(str_replace('_', '-', $field)).'-'.$id; 5090 if(!vartrue($parms['noparse'])) $value = $tp->toHTML($value, (vartrue($parms['bb']) ? true : false), vartrue($parms['parse'])); 5091 if(vartrue($parms['expand']) || vartrue($parms['truncate']) || vartrue($parms['htmltruncate'])) 5092 { 5093 $ttl = vartrue($parms['expand']); 5094 if($ttl == 1) 5095 { 5096 $dataAttr = "data-text-more='" . LAN_MORE . "' data-text-less='" . LAN_LESS . "'"; 5097 $ttl = $expand."<button class='btn btn-default btn-secondary btn-xs btn-mini pull-right' {$dataAttr}>" . LAN_MORE . "</button>"; 5098 } 5099 5100 $expands = '<a href="#'.$elid.'-expand" class="e-show-if-js e-expandit e-expandit-inline">'.defset($ttl, $ttl)."</a>"; 5101 } 5102 5103 $oldval = $value; 5104 if(vartrue($parms['truncate'])) 5105 { 5106 $value = $oldval = strip_tags($value); 5107 $value = $tp->text_truncate($value, $parms['truncate'], ''); 5108 $toexpand = $value != $oldval; 5109 } 5110 elseif(vartrue($parms['htmltruncate'])) 5111 { 5112 $value = $tp->html_truncate($value, $parms['htmltruncate'], ''); 5113 $toexpand = $value != $oldval; 5114 } 5115 if($toexpand) 5116 { 5117 // force hide! TODO - core style .expand-c (expand container) 5118 $value .= '<span class="expand-c" style="display: none" id="'.$elid.'-expand"><span>'.str_replace($value,'',$oldval).'</span></span>'; 5119 $value .= varset($expands); // 'More..' button. Keep it at the bottom so it does't cut the sentence. 5120 } 5121 5122 5123 5124 break; 5125 5126 case 'icon': 5127 5128 $value = "<span class='icon-preview'>".$tp->toIcon($value,$parms)."</span>"; 5129 5130 break; 5131 5132 case 'file': 5133 if(vartrue($parms['base'])) 5134 { 5135 $url = $parms['base'].$value; 5136 } 5137 else $url = e107::getParser()->replaceConstants($value, 'full'); 5138 $name = basename($value); 5139 $value = '<a href="'.$url.'" title="Direct link to '.$name.'" rel="external">'.$name.'</a>'; 5140 break; 5141 5142 case 'image': //js tooltip... 5143 5144 $thparms = array(); 5145 $createLink = true; 5146 5147 // Support readParms example: thumb=1&w=200&h=300 5148 // Support readParms example: thumb=1&aw=80&ah=30 5149 if(isset($parms['h'])) { $thparms['h'] = intval($parms['h']); } 5150 if(isset($parms['ah'])) { $thparms['ah'] = intval($parms['ah']); } 5151 if(isset($parms['w'])) { $thparms['w'] = intval($parms['w']); } 5152 if(isset($parms['aw'])) { $thparms['aw'] = intval($parms['aw']); } 5153 if(isset($parms['crop'])) { $thparms['crop'] = $parms['crop']; } 5154 5155 5156 5157 if($value) 5158 { 5159 5160 if(strpos($value,",")!==false) 5161 { 5162 $tmp = explode(",",$value); 5163 $value = $tmp[0]; 5164 unset($tmp); 5165 } 5166 5167 if(empty($parms['thumb_aw']) && !empty($parms['thumb']) && strpos($parms['thumb'],'x')!==false) 5168 { 5169 list($parms['thumb_aw'],$parms['thumb_ah']) = explode('x',$parms['thumb']); 5170 } 5171 5172 $vparm = array('thumb'=>'tag','w'=> vartrue($parms['thumb_aw'],'80')); 5173 5174 if($video = e107::getParser()->toVideo($value,$vparm)) 5175 { 5176 return $video; 5177 } 5178 5179 $fileOnly = basename($value); 5180 // Not an image but a file. (media manager) 5181 if(!preg_match("/\.(png|jpg|jpeg|gif|PNG|JPG|JPEG|GIF)$/", $fileOnly) && false !== strpos($fileOnly,'.')) 5182 { 5183 $icon = "{e_IMAGE}filemanager/zip_32.png"; 5184 $src = $tp->replaceConstants(vartrue($parms['pre']).$icon, 'abs'); 5185 // return $value; 5186 return e107::getParser()->toGlyph('fa-file','size=2x'); 5187 // return '<img src="'.$src.'" alt="'.$value.'" class="e-thumb" title="'.$value.'" />'; 5188 } 5189 5190 5191 5192 if(!empty($parms['thumb'])) 5193 { 5194 5195 if(isset($parms['link']) && empty($parms['link'])) 5196 { 5197 $createLink = false; 5198 } 5199 5200 // Support readParms example: thumb=200x300 (wxh) 5201 if(strpos($parms['thumb'],'x')!==false) 5202 { 5203 list($thparms['w'],$thparms['h']) = explode('x',$parms['thumb']); 5204 } 5205 5206 // Support readParms example: thumb={width} 5207 if(!isset($parms['w']) && is_numeric($parms['thumb']) && '1' != $parms['thumb']) 5208 { 5209 $thparms['w'] = intval($parms['thumb']); 5210 } 5211 elseif(vartrue($parms['thumb_aw'])) // Legacy v2. 5212 { 5213 $thparms['aw'] = intval($parms['thumb_aw']); 5214 } 5215 5216 if(!empty($parms['legacyPath'])) 5217 { 5218 $thparms['legacy'] = $parms['legacyPath']; 5219 $parms['pre'] = rtrim($parms['legacyPath'],'/').'/'; 5220 } 5221 // return print_a($thparms,true); 5222 5223 if(!empty($value[0]) && $value[0] === '{') // full path to convert. 5224 { 5225 $src = $tp->replaceConstants($value, 'abs'); 5226 } 5227 else // legacy link without {e_XXX} path. eg. downloads thumbs. 5228 { 5229 $src = $tp->replaceConstants(vartrue($parms['pre']).$value, 'abs'); 5230 } 5231 5232 $alt = basename($src); 5233 5234 5235 $thparms['alt'] = $alt; 5236 $thparms['class'] = "thumbnail e-thumb"; 5237 5238 // e107::getDebug()->log($value); 5239 5240 $ttl = $tp->toImage($value, $thparms); 5241 5242 if($createLink === false) 5243 { 5244 return $ttl; 5245 } 5246 5247 5248 $value = '<a href="'.$src.'" data-modal-caption="'.$alt.'" data-target="#uiModal" class="e-modal e-image-preview" title="'.$alt.'" rel="external">'.$ttl.'</a>'; 5249 } 5250 else 5251 { 5252 $src = $tp->replaceConstants(vartrue($parms['pre']).$value, 'abs'); 5253 $alt = $src; //basename($value); 5254 $ttl = vartrue($parms['title'], 'LAN_PREVIEW'); 5255 $value = '<a href="'.$src.'" class="e-image-preview" title="'.$alt.'" rel="external">'.defset($ttl, $ttl).'</a>'; 5256 } 5257 } 5258 elseif(!empty($parms['fallback'])) 5259 { 5260 $value = $parms['fallback']; 5261 $thparms['class'] = "thumbnail e-thumb fallback"; 5262 return $tp->toImage($value, $thparms); 5263 } 5264 break; 5265 5266 5267 case 'media': 5268 5269 if(!empty($value) && $attributes['data'] === 'json') 5270 { 5271 $tmp = e107::unserialize($value); 5272 $value = !empty($tmp[0]['path']) ? $tmp[0]['path'] : null; // display first item. 5273 } 5274 5275 return e107::getMedia()->previewTag($value, $parms); 5276 break; 5277 5278 case 'files': 5279 $ret = '<ol>'; 5280 for ($i=0; $i < 5; $i++) 5281 { 5282 //$k = $key.'['.$i.'][path]'; 5283 $ival = $value[$i]['path']; 5284 $ret .= '<li>'.$ival.'</li>'; 5285 } 5286 $ret .= '</ol>'; 5287 $value = $ret; 5288 break; 5289 5290 case 'datestamp': 5291 $value = $value ? e107::getDate()->convert_date($value, vartrue($parms['mask'], 'short')) : ''; 5292 break; 5293 5294 case 'date': 5295 5296 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 5297 { 5298 $value = $this->renderInline($field,$id,$attributes['title'],$value, $value); 5299 } 5300 5301 // just show original value 5302 break; 5303 5304 case 'userclass': 5305 $dispvalue = $this->_uc->getName($value); 5306 // Inline Editing. 5307 if(empty($attributes['noedit']) && !empty($parms['editable']) && empty($parms['link'])) // avoid bad markup, better solution coming up 5308 { 5309 // $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 5310 5311 $uc_options = vartrue($parms['classlist'], 'public,guest,nobody,member,admin,main,classes'); // defaults to 'public,guest,nobody,member,classes' (userclass handler) 5312 unset($parms['classlist']); 5313 5314 $array = e107::getUserClass()->uc_required_class_list($uc_options); //XXX Ugly looking (non-standard) function naming - TODO discuss name change. 5315 5316 $value = $this->renderInline($field, $id, $attributes['title'], $value, $dispvalue, 'select', $array, array('placement'=>'left')); 5317 } 5318 else 5319 { 5320 $value = $dispvalue; 5321 } 5322 break; 5323 5324 case 'userclasses': 5325 // return $value; 5326 $classes = explode(',', $value); 5327 5328 $uv = array(); 5329 foreach ($classes as $cid) 5330 { 5331 if(!empty($parms['defaultLabel']) && $cid === '') 5332 { 5333 $uv[] = $parms['defaultLabel']; 5334 continue; 5335 } 5336 5337 $uv[] = $this->_uc->getName($cid); 5338 } 5339 5340 5341 5342 $dispvalue = implode(vartrue($parms['separator'],"<br />"), $uv); 5343 5344 // Inline Editing. 5345 if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up 5346 { 5347 $uc_options = vartrue($parms['classlist'], 'public,guest, nobody,member,admin,main,classes'); // defaults to 'public,guest,nobody,member,classes' (userclass handler) 5348 $array = e107::getUserClass()->uc_required_class_list($uc_options); //XXX Ugly looking (non-standard) function naming - TODO discuss name change. 5349 5350 //$mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 5351 $mode = $tp->filter(vartrue($_GET['mode'], ''),'w'); 5352 $source = str_replace('"',"'",json_encode($array, JSON_FORCE_OBJECT)); 5353 5354 //NOTE Leading ',' required on $value; so it picks up existing value. 5355 $value = "<a class='e-tip e-editable editable-click' data-placement='bottom' data-value=',".$value."' data-name='".$field."' data-source=\"".$source."\" title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='checklist' data-pk='".$id."' data-token='".$this->inlineToken()."' data-url='".e_SELF."?mode={$mode}&action=inline&id={$id}&ajax_used=1' href='#'>".$dispvalue."</a>"; 5356 } 5357 else 5358 { 5359 $value = $dispvalue; 5360 } 5361 5362 unset($parms['classlist']); 5363 5364 break; 5365 5366 /*case 'user_name': 5367 case 'user_loginname': 5368 case 'user_login': 5369 case 'user_customtitle': 5370 case 'user_email':*/ 5371 case 'user': 5372 5373 /*if(is_numeric($value)) 5374 { 5375 $value = e107::user($value); 5376 if($value) 5377 { 5378 $value = $value[$attributes['type']] ? $value[$attributes['type']] : $value['user_name']; 5379 } 5380 else 5381 { 5382 $value = 'not found'; 5383 } 5384 }*/ 5385 $row_id = $id; 5386 // Dirty, but the only way for now 5387 $id = 0; 5388 $ttl = LAN_ANONYMOUS; 5389 5390 //Defaults to user_id and user_name (when present) and when idField and nameField are not present. 5391 5392 5393 // previously set - real parameters are idField && nameField 5394 $id = vartrue($parms['__idval']); 5395 if($value && !is_numeric($value)) 5396 { 5397 $id = vartrue($parms['__idval']); 5398 $ttl = $value; 5399 } 5400 elseif($value && is_numeric($value)) 5401 { 5402 $id = $value; 5403 5404 if (vartrue($parms['__nameval'])) 5405 { 5406 $ttl = $parms['__nameval']; 5407 } 5408 else 5409 { 5410 $user = e107::user($value); 5411 if (vartrue($user['user_name'])) 5412 { 5413 $ttl = $user['user_name']; 5414 } 5415 } 5416 } 5417 5418 5419 if(!empty($parms['link']) && $id && $ttl && is_numeric($id)) 5420 { 5421 // Stay in admin area. 5422 $link = e_ADMIN."users.php?mode=main&action=edit&id=".$id."&readonly=1&iframe=1"; // e107::getUrl()->create('user/profile/view', array('id' => $id, 'name' => $ttl)) 5423 5424 $value = '<a class="e-modal" data-modal-caption="User #'.$id.' : '.$ttl.'" href="'.$link.'" title="'.LAN_EFORM_011.'">'.$ttl.'</a>'; 5425 } 5426 else 5427 { 5428 $value = $ttl; 5429 } 5430 5431 // Inline Editing. 5432 if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up 5433 { 5434 // Need a Unique Field ID to store field settings using e107::js('settings'). 5435 $fieldID = $this->name2id($field . '_' . microtime(true)); 5436 // Unique ID for each rows. 5437 $eEditableID = $this->name2id($fieldID . '_' . $row_id); 5438 // $tpl = $this->userpicker($field, '', $ttl, $id, array('id' => $fieldID, 'selectize' => array('e_editable' => $eEditableID))); 5439 5440 $tpl = $this->userpicker($fieldID, array('user_id'=>$id, 'user_name'=>$ttl), array('id' => $fieldID, 'inline' => $eEditableID)); 5441 $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 5442 $value = "<a id='" . $eEditableID . "' class='e-tip e-editable editable-click editable-userpicker' data-clear='false' data-token='".$this->inlineToken()."' data-tpl='" . str_replace("'", '"', $tpl) . "' data-name='" . $field . "' title=\"" . LAN_EDIT . " " . $attributes['title'] . "\" data-type='text' data-pk='" . $row_id . "' data-value='" . $id . "' data-url='" . e_SELF . "?mode={$mode}&action=inline&id={$row_id}&ajax_used=1' href='#'>" . $ttl . "</a>"; 5443 } 5444 5445 break; 5446 5447 /** 5448 * $parms['true'] - label to use for true 5449 * $parms['false'] - label to use for false 5450 * $parms['enabled'] - alias of $parms['true'] 5451 * $parms['disabled'] - alias of $parms['false'] 5452 * $parms['reverse'] - use 0 for true and 1 for false. 5453 */ 5454 case 'bool': 5455 case 'boolean': 5456 $false = vartrue($parms['trueonly']) ? "" : ADMIN_FALSE_ICON; 5457 5458 if(!empty($parms['enabled'])) 5459 { 5460 $parms['true'] = $parms['enabled']; 5461 } 5462 5463 if(!empty($parms['disabled'])) 5464 { 5465 $parms['false'] = $parms['disabled']; 5466 } 5467 5468 if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up 5469 { 5470 if(isset($parms['false'])) // custom representation for 'false'. (supports font-awesome when set by css) 5471 { 5472 $false = $parms['false']; 5473 } 5474 else 5475 { 5476 // https://stackoverflow.com/questions/2965971/how-to-add-images-in-select-list 5477 5478 $false = ($value === '') ? "□" : "⨯"; // "✗"; 5479 } 5480 5481 $true = varset($parms['true'], "✔" /*'✓'*/); // custom representation for 'true'. (supports font-awesome when set by css) 5482 5483 // $true = ''; 5484 // $false = '\f00d'; 5485 5486 $value = intval($value); 5487 5488 $wparms = (vartrue($parms['reverse'])) ? array(0=>$true, 1=>$false) : array(0=>$false, 1=>$true); 5489 $dispValue = $wparms[$value]; 5490 $styleClass = ''; 5491 5492 if($true ==='✔') 5493 { 5494 $styleClass = ($value === 1) ? 'admin-true-icon' : 'admin-false-icon'; 5495 } 5496 5497 5498 return $this->renderInline($field, $id, $attributes['title'], $value, $dispValue, 'select', $wparms, array('class'=>'e-editable-boolean '.$styleClass)); 5499 } 5500 5501 if(vartrue($parms['reverse'])) 5502 { 5503 $value = ($value) ? $false : ADMIN_TRUE_ICON; 5504 } 5505 else 5506 { 5507 $value = $value ? ADMIN_TRUE_ICON : $false; 5508 } 5509 5510 break; 5511 5512 case 'url': 5513 if(!$value) break; 5514 $ttl = $value; 5515 if(!empty($parms['href'])) 5516 { 5517 return $tp->replaceConstants(vartrue($parms['pre']).$value, varset($parms['replace_mod'],'abs')); 5518 } 5519 if(!empty($parms['truncate'])) 5520 { 5521 $ttl = $tp->text_truncate($value, $parms['truncate'], '...'); 5522 } 5523 5524 $target = (!empty($parms['target'])) ? " target='".$parms['target']."' " : ""; 5525 $class = (!empty($parms['class'])) ? " class='".$parms['class']."' " : ""; 5526 5527 $value = "<a ".$target.$class."href='".$tp->replaceConstants(vartrue($parms['pre']).$value, 'abs')."' title='{$value}'>".$ttl."</a>"; 5528 break; 5529 5530 case 'email': 5531 if(!$value) break; 5532 $ttl = $value; 5533 if(vartrue($parms['truncate'])) 5534 { 5535 $ttl = $tp->text_truncate($value, $parms['truncate'], '...'); 5536 } 5537 5538 $target = (!empty($parms['target'])) ? " target='".$parms['target']."' " : ""; 5539 $class = (!empty($parms['class'])) ? " class='".$parms['class']."' " : ""; 5540 5541 $value = "<a ".$target.$class."href='mailto:".$value."' title='{$value}'>".$ttl."</a>"; 5542 break; 5543 5544 case 'method': // Custom Function 5545 $method = varset($attributes['field']); // prevents table alias in method names. ie. u.my_method. 5546 $_value = $value; 5547 5548 if(!empty($attributes['data']) && $attributes['data'] == 'array') // FIXME @SecretR - please move this to where it should be. 5549 { 5550 $value = e107::unserialize($value); // (saved as array, return it as an array) 5551 } 5552 5553 $meth = (!empty($attributes['method'])) ? $attributes['method'] : $method; 5554 5555 if(strpos($meth,'::')!==false) 5556 { 5557 list($className,$meth) = explode('::', $meth); 5558 $cls = new $className(); 5559 } 5560 else 5561 { 5562 $cls = $this; 5563 } 5564 5565 if(method_exists($cls,$meth)) 5566 { 5567 $parms['field'] = $field; 5568 $mode = (!empty($attributes['mode'])) ? $attributes['mode'] :'read'; 5569 $value = call_user_func_array(array($cls, $meth), array($value, $mode, $parms)); 5570 } 5571 else 5572 { 5573 $className = get_class($cls); 5574 e107::getDebug()->log("Missing Method: ".$className."::".$meth." ".print_a($attributes,true)); 5575 return "<span class='label label-important label-danger' title='".$className."::".$meth."'>Missing Method</span>"; 5576 } 5577 // print_a($attributes); 5578 // Inline Editing. 5579 if(empty($attributes['noedit']) && !empty($parms['editable'])) // avoid bad markup, better solution coming up 5580 { 5581 5582 $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], '')); 5583 $methodParms = call_user_func_array(array($this, $meth), array($_value, 'inline', $parms)); 5584 5585 $inlineParms = (!empty($methodParms['inlineParms'])) ? $methodParms['inlineParms'] : null; 5586 5587 if(!empty($methodParms['inlineType'])) 5588 { 5589 $attributes['inline'] = $methodParms['inlineType']; 5590 $methodParms = (!empty($methodParms['inlineData'])) ? $methodParms['inlineData'] : null; 5591 } 5592 5593 5594 5595 if(is_string($attributes['inline'])) // text, textarea, select, checklist. 5596 { 5597 switch ($attributes['inline']) 5598 { 5599 5600 case 'checklist': 5601 $xtype = 'checklist'; 5602 break; 5603 5604 case 'select': 5605 case 'dropdown': 5606 $xtype = 'select'; 5607 break; 5608 5609 case 'textarea': 5610 $xtype = 'textarea'; 5611 break; 5612 5613 5614 default: 5615 $xtype = 'text'; 5616 $methodParms = null; 5617 break; 5618 } 5619 } 5620 5621 if(!empty($xtype)) 5622 { 5623 $value = varset($inlineParms['pre'],'').$this->renderInline($field, $id, $attributes['title'], $_value, $value, $xtype, $methodParms,$inlineParms).varset($inlineParms['post'],''); 5624 } 5625 5626 } 5627 5628 break; 5629 5630 case 'hidden': 5631 return (vartrue($parms['show']) ? ($value ? $value : vartrue($parms['empty'])) : ''); 5632 break; 5633 5634 case 'language': // All Known Languages. 5635 5636 if(!empty($value)) 5637 { 5638 $_value = $value; 5639 if(strlen($value) === 2) 5640 { 5641 $value = e107::getLanguage()->convert($value); 5642 } 5643 } 5644 5645 if(!vartrue($attributes['noedit']) && vartrue($parms['editable'])) 5646 { 5647 $wparms = e107::getLanguage()->getList(); 5648 return $this->renderInline($field, $id, $attributes['title'], $_value, $value, 'select', $wparms); 5649 } 5650 5651 return $value; 5652 5653 break; 5654 5655 case 'lanlist': // installed languages. 5656 $options = e107::getLanguage()->getLanSelectArray(); 5657 5658 if($options) // FIXME - add support for multi-level arrays (option groups) 5659 { 5660 if(!is_array($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']); 5661 $wparms = $attributes['writeParms']; 5662 if(!is_array(varset($wparms['__options']))) parse_str($wparms['__options'], $wparms['__options']); 5663 $opts = $wparms['__options']; 5664 if($opts['multiple']) 5665 { 5666 $ret = array(); 5667 $value = is_array($value) ? $value : explode(',', $value); 5668 foreach ($value as $v) 5669 { 5670 if(isset($options[$v])) $ret[] = $options[$v]; 5671 } 5672 $value = implode(', ', $ret); 5673 } 5674 else 5675 { 5676 $ret = ''; 5677 if(isset($options[$value])) $ret = $options[$value]; 5678 $value = $ret; 5679 } 5680 $value = ($value ? vartrue($parms['pre']).$value.vartrue($parms['post']) : ''); 5681 } 5682 else 5683 { 5684 $value = ''; 5685 } 5686 break; 5687 5688 //TODO - order 5689 5690 default: 5691 $value = $this->renderLink($value,$parms,$id); 5692 //unknown type 5693 break; 5694 } 5695 5696 return $value; 5697 } 5698 5699 /** 5700 * Auto-render Form Element 5701 * @param string $key 5702 * @param mixed $value 5703 * @param array $attributes field attributes including render parameters, element options - see e_admin_ui::$fields for required format 5704 * #param array (under construction) $required_data required array as defined in e_model/validator 5705 * @param mixed $attributes['writeParms']['default'] default value when empty (or default option when type='dropdown') 5706 * @param mixed $attributes['writeParms']['defaultValue'] default option value when type='dropdown' 5707 * @param mixed $attributes['writeParms']['empty'] default value when value is empty (dropdown and hidden only right now) 5708 * @return string 5709 */ 5710 function renderElement($key, $value, $attributes, $required_data = array(), $id = 0) 5711 { 5712 $tp = e107::getParser(); 5713 5714 $parms = vartrue($attributes['writeParms'], array()); 5715 5716 if($tmpOpt = $tp->isJSON($parms)) 5717 { 5718 $parms = $tmpOpt; 5719 unset($tmpOpt); 5720 } 5721 5722 if(is_string($parms)) parse_str($parms, $parms); 5723 5724 $ajaxParms = array(); 5725 5726 if(!empty($parms['ajax'])) 5727 { 5728 $ajaxParms['data-src'] = varset($parms['ajax']['src']); 5729 $ajaxParms['data-target'] = varset($parms['ajax']['target']); 5730 $ajaxParms['data-method'] = varset($parms['ajax']['method'], 'html'); 5731 $ajaxParms['data-loading'] = varset($parms['ajax']['loading'], 'fa-spinner'); //$tp->toGlyph('fa-spinner', array('spin'=>1)) 5732 5733 unset($attributes['writeParms']['ajax']); 5734 5735 // e107::getDebug()->log($parms['ajax']); 5736 } 5737 5738 if(!empty($attributes['multilan'])) 5739 { 5740 $value = is_array($value) ? varset($value[e_LANGUAGE],'') : $value; 5741 $parms['post'] = "<small class='e-tip admin-multilanguage-field input-group-addon' style='cursor:help; padding-left:10px' title='".LAN_EFORM_012." (".e_LANGUAGE.")'>".$tp->toGlyph('fa-language')."</small>".varset($parms['post']); 5742 $key = $key.'['.e_LANGUAGE.']'; 5743 } 5744 5745 if(empty($value) && !empty($parms['default']) && $attributes['type'] !== 'dropdown') // Allow writeParms to set default value. 5746 { 5747 $value = $parms['default']; 5748 } 5749 5750 // Two modes of read-only. 1 = read-only, but only when there is a value, 2 = read-only regardless. 5751 if(vartrue($attributes['readonly']) && (vartrue($value) || vartrue($attributes['readonly'])===2)) // quick fix (maybe 'noedit'=>'readonly'?) 5752 { 5753 if(vartrue($attributes['writeParms'])) // eg. different size thumbnail on the edit page. 5754 { 5755 $attributes['readParms'] = $attributes['writeParms']; 5756 } 5757 5758 return $this->renderValue($key, $value, $attributes).$this->hidden($key, $value); // 5759 } 5760 5761 // FIXME standard - writeParams['__options'] is introduced for list elements, bundle adding to writeParms is non reliable way 5762 $writeParamsOptionable = array('dropdown', 'comma', 'radio', 'lanlist', 'language', 'user'); 5763 $writeParamsDisabled = array('layouts', 'templates', 'userclass', 'userclasses'); 5764 5765 // FIXME it breaks all list like elements - dropdowns, radio, etc 5766 if(vartrue($required_data[0]) || vartrue($attributes['required'])) // HTML5 'required' attribute 5767 { 5768 // FIXME - another approach, raise standards, remove checks 5769 if(in_array($attributes['type'], $writeParamsOptionable)) 5770 { 5771 $parms['__options']['required'] = 1; 5772 } 5773 elseif(!in_array($attributes['type'], $writeParamsDisabled)) 5774 { 5775 $parms['required'] = 1; 5776 } 5777 } 5778 5779 // FIXME it breaks all list like elements - dropdowns, radio, etc 5780 if(vartrue($required_data[3]) || vartrue($attributes['pattern'])) // HTML5 'pattern' attribute 5781 { 5782 // FIXME - another approach, raise standards, remove checks 5783 if(in_array($attributes['type'], $writeParamsOptionable)) 5784 { 5785 $parms['__options']['pattern'] = vartrue($attributes['pattern'], $required_data[3]); 5786 } 5787 elseif(!in_array($attributes['type'], $writeParamsDisabled)) 5788 { 5789 $parms['pattern'] = vartrue($attributes['pattern'], $required_data[3]); 5790 } 5791 } 5792 5793 5794 5795 // XXX Fixes For the above. - use optArray variable. eg. $field['key']['writeParms']['optArray'] = array('one','two','three'); 5796 if(($attributes['type'] == 'dropdown' || $attributes['type'] == 'radio' || $attributes['type'] == 'checkboxes') && isset($parms['optArray'])) 5797 { 5798 $fopts = $parms; 5799 $parms = $fopts['optArray']; 5800 unset($fopts['optArray']); 5801 $parms['__options'] = $fopts; 5802 } 5803 5804 $this->renderElementTrigger($key, $value, $parms, $required_data, $id); 5805 5806 switch($attributes['type']) 5807 { 5808 case 'number': 5809 $maxlength = vartrue($parms['maxlength'], 255); 5810 unset($parms['maxlength']); 5811 if(!vartrue($parms['size'])) $parms['size'] = 'small'; 5812 if(!vartrue($parms['class'])) $parms['class'] = 'tbox number e-spinner '; 5813 if(!$value) $value = '0'; 5814 $ret = vartrue($parms['pre']).$this->number($key, $value, $maxlength, $parms).vartrue($parms['post']); 5815 break; 5816 5817 case 'country': 5818 $ret = vartrue($parms['pre']).$this->country($key, $value, $parms).vartrue($parms['post']); 5819 break; 5820 5821 case 'ip': 5822 $ret = vartrue($parms['pre']).$this->text($key, e107::getIPHandler()->ipDecode($value), 32, $parms).vartrue($parms['post']); 5823 break; 5824 5825 case 'email': 5826 $maxlength = vartrue($parms['maxlength'], 255); 5827 unset($parms['maxlength']); 5828 $ret = vartrue($parms['pre']).$this->email($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true 5829 break; 5830 5831 case 'url': 5832 $maxlength = vartrue($parms['maxlength'], 255); 5833 unset($parms['maxlength']); 5834 $ret = vartrue($parms['pre']).$this->url($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true 5835 5836 break; 5837 // case 'email': 5838 5839 case 'password': // encrypts to md5 when saved. 5840 $maxlength = vartrue($parms['maxlength'], 255); 5841 unset($parms['maxlength']); 5842 if(!isset($parms['required'])) 5843 { 5844 5845 $parms['required'] = false; 5846 } 5847 $ret = vartrue($parms['pre']).$this->password($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true 5848 5849 break; 5850 5851 case 'text': 5852 case 'progressbar': 5853 5854 $maxlength = vartrue($parms['maxlength'], 255); 5855 unset($parms['maxlength']); 5856 5857 if(!empty($parms['sef']) && e_LANGUAGE != "Japanese" && e_LANGUAGE != "Korean" && e_LANGUAGE != "Hebrew") // unsupported languages.(FIXME there are more) 5858 { 5859 $sefSource = $this->name2id($parms['sef']); 5860 $sefTarget = $this->name2id($key); 5861 if(!empty($parms['tdClassRight'])) 5862 { 5863 $parms['tdClassRight'] .= 'input-group'; 5864 } 5865 else 5866 { 5867 $parms['tdClassRight'] = 'input-group'; 5868 } 5869 5870 $parms['post'] = "<span class='form-inline input-group-btn pull-left'><a class='e-sef-generate btn btn-default' data-src='".$sefSource."' data-target='".$sefTarget."' data-sef-generate-confirm=\"".LAN_WILL_OVERWRITE_SEF." ".LAN_JSCONFIRM."\">".LAN_GENERATE."</a></span>"; 5871 } 5872 5873 if(!empty($parms['password'])) // password mechanism without the md5 storage. 5874 { 5875 $ret = vartrue($parms['pre']).$this->password($key, $value, $maxlength, $parms).vartrue($parms['post']); 5876 } 5877 5878 else 5879 { 5880 $ret = vartrue($parms['pre']).$this->text($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true 5881 } 5882 5883 5884 if(!empty($attributes['multilan'])) 5885 { 5886 $msize = vartrue($parms['size'], 'xxlarge'); 5887 $ret = "<span class='input-group input-".$msize."'>".$ret."</span>"; 5888 } 5889 5890 break; 5891 5892 case 'tags': 5893 $maxlength = vartrue($parms['maxlength'], 255); 5894 $ret = vartrue($parms['pre']).$this->tags($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true 5895 break; 5896 5897 case 'textarea': 5898 $text = ""; 5899 if(vartrue($parms['append']) && vartrue($value)) // similar to comments - TODO TBD. a 'comment' field type may be better. 5900 { 5901 $attributes['readParms'] = 'bb=1'; 5902 5903 $text = $this->renderValue($key, $value, $attributes); 5904 $text .= '<br />'; 5905 $value = ""; 5906 5907 // Appending needs is performed and customized using function: beforeUpdate($new_data, $old_data, $id) 5908 } 5909 5910 if(empty($parms['size'])) 5911 { 5912 $parms['size'] = 'xxlarge'; 5913 } 5914 5915 5916 $text .= vartrue($parms['pre']).$this->textarea($key, $value, vartrue($parms['rows'], 5), vartrue($parms['cols'], 40), vartrue($parms['__options'],$parms), varset($parms['counter'], false)).vartrue($parms['post']); 5917 $ret = $text; 5918 break; 5919 5920 case 'bbarea': 5921 $options = array('counter' => varset($parms['counter'], false)); 5922 // Media = media-category owner used by media-manager. 5923 $ret = vartrue($parms['pre']).$this->bbarea($key, $value, vartrue($parms['template']), vartrue($parms['media'],'_common_image'), vartrue($parms['size'], 'medium'),$options ).vartrue($parms['post']); 5924 break; 5925 5926 case 'video': 5927 case 'image': //TODO - thumb, image list shortcode, js tooltip... 5928 $label = varset($parms['label'], 'LAN_EDIT'); 5929 5930 if(!empty($parms['optArray'])) 5931 { 5932 5933 return $this->imageradio($key,$value,$parms); 5934 } 5935 5936 5937 unset($parms['label']); 5938 5939 if($attributes['type'] === 'video') 5940 { 5941 $parms['video'] = 2; // ie. video only. 5942 $parms['w'] = 280; 5943 } 5944 5945 5946 $ret = $this->imagepicker($key, $value, defset($label, $label), $parms); 5947 break; 5948 5949 case 'images': 5950 // return print_a($value, true); 5951 $ret = ""; 5952 $label = varset($parms['label'], 'LAN_EDIT'); 5953 $max = varset($parms['max'],5); 5954 5955 $ret .= "<div class='mediaselector-multi field-element-images'>"; 5956 5957 for ($i=0; $i < $max; $i++) 5958 { 5959 $k = $key.'['.$i.'][path]'; 5960 $ival = $value[$i]['path']; 5961 5962 $ret .= $this->imagepicker($k, $ival, defset($label, $label), $parms); 5963 } 5964 5965 $ret .= "</div>"; 5966 break; 5967 5968 /** Generic Media Pick for combinations of images, audio, video, glyphs, files, etc. Field Type = json */ 5969 case 'media': 5970 5971 $max = varset($parms['max'],1); 5972 5973 if(!empty($value) && $attributes['data'] === 'json') 5974 { 5975 $value = e107::unserialize($value); 5976 } 5977 5978 $ret = "<div class='mediaselector-multi field-element-media'>"; 5979 for ($i=0; $i < $max; $i++) 5980 { 5981 $k = $key.'['.$i.'][path]'; 5982 $ival = $value[$i]['path']; 5983 5984 $ret .= $this->mediapicker($k, $ival, $parms); 5985 } 5986 5987 $ret .= "</div>"; 5988 5989 return $ret; 5990 break; 5991 5992 case 'files': 5993 $label = varset($parms['label'], 'LAN_EDIT'); 5994 if($attributes['data'] == 'array') 5995 { 5996 $parms['data'] = 'array'; 5997 } 5998 5999 $ret = '<ol>'; 6000 for ($i=0; $i < 5; $i++) 6001 { 6002 // $k = $key.'['.$i.'][path]'; 6003 // $ival = $value[$i]['path']; 6004 $k = $key.'['.$i.']'; 6005 $ival = $value[$i]; 6006 $ret .= '<li>'.$this->filepicker($k, $ival, defset($label, $label), $parms).'</li>'; 6007 } 6008 $ret .= '</ol>'; 6009 break; 6010 6011 case 'file': //TODO - thumb, image list shortcode, js tooltip... 6012 $label = varset($parms['label'], 'LAN_EDIT'); 6013 unset($parms['label']); 6014 $ret = $this->filepicker($key, $value, defset($label, $label), $parms); 6015 break; 6016 6017 case 'icon': 6018 $label = varset($parms['label'], 'LAN_EDIT'); 6019 $ajax = varset($parms['ajax'], true) ? true : false; 6020 unset($parms['label'], $parms['ajax']); 6021 $ret = $this->iconpicker($key, $value, defset($label, $label), $parms, $ajax); 6022 break; 6023 6024 case 'date': // date will show the datepicker but won't convert the value to unix. ie. string value will be saved. (or may be processed manually with beforeCreate() etc. Format may be determined by $parm. 6025 case 'datestamp': 6026 // If hidden, value is updated regardless. eg. a 'last updated' field. 6027 // If not hidden, and there is a value, it is retained. eg. during the update of an existing record. 6028 // otherwise it is added. eg. during the creation of a new record. 6029 if(vartrue($parms['auto']) && (($value == null) || vartrue($parms['hidden']))) 6030 { 6031 $value = time(); 6032 } 6033 6034 if(vartrue($parms['readonly'])) // different to 'attribute-readonly' since the value may be auto-generated. 6035 { 6036 $ret = $this->renderValue($key, $value, $attributes).$this->hidden($key, $value); 6037 } 6038 elseif(vartrue($parms['hidden'])) 6039 { 6040 $ret = $this->hidden($key, $value); 6041 } 6042 else 6043 { 6044 $ret = $this->datepicker($key, $value, $parms); 6045 } 6046 break; 6047 6048 case 'layouts': //to do - exclude param (exact match) 6049 6050 $location = varset($parms['plugin']); // empty - core 6051 $ilocation = vartrue($parms['id'], $location); // omit if same as plugin name 6052 $where = vartrue($parms['area'], 'front'); //default is 'front' 6053 $filter = varset($parms['filter']); 6054 $merge = isset($parms['merge']) ? (bool) $parms['merge'] : true; 6055 6056 $layouts = e107::getLayouts($location, $ilocation, $where, $filter, $merge, false); 6057 6058 return vartrue($parms['pre'],'').$this->select($key, $layouts,$value,$parms).vartrue($parms['post'],''); 6059 6060 /* if($tmp = e107::getTemplateInfo($location,$ilocation, null,true,$merge)) // read xxxx_INFO array from template file. 6061 { 6062 $opt = array(); 6063 foreach($tmp as $k=>$inf) 6064 { 6065 $opt[$k] = $inf['title']; 6066 } 6067 6068 return vartrue($parms['pre'],'').$this->select($key,$opt,$value,$parms).vartrue($parms['post'],''); 6069 }*/ 6070 6071 6072 6073/* 6074 if(varset($parms['default']) && !isset($layouts[0]['default'])) 6075 { 6076 $layouts[0] = array('default' => $parms['default']) + $layouts[0]; 6077 } 6078 $info = array(); 6079 if($layouts[1]) 6080 { 6081 foreach ($layouts[1] as $k => $info_array) 6082 { 6083 if(isset($info_array['description'])) 6084 $info[$k] = defset($info_array['description'], $info_array['description']); 6085 } 6086 } 6087 6088 */ 6089 6090 //$this->selectbox($key, $layouts, $value) 6091 // $ret = (vartrue($parms['raw']) ? $layouts[0] : $this->radio_multi($key, $layouts[0], $value,array('sep'=>"<br />"), $info)); 6092 break; 6093 6094 case 'templates': //to do - exclude param (exact match) 6095 $templates = array(); 6096 if(varset($parms['default'])) 6097 { 6098 $templates['default'] = defset($parms['default'], $parms['default']); 6099 } 6100 $location = vartrue($parms['plugin']) ? e_PLUGIN.$parms['plugin'].'/' : e_THEME; 6101 $ilocation = vartrue($parms['location']); 6102 $tmp = e107::getFile()->get_files($location.'templates/'.$ilocation, vartrue($parms['fmask'], '_template\.php$'), vartrue($parms['omit'], 'standard'), vartrue($parms['recurse_level'], 0)); 6103 foreach(self::sort_get_files_output($tmp) as $files) 6104 { 6105 $k = str_replace('_template.php', '', $files['fname']); 6106 $templates[$k] = implode(' ', array_map('ucfirst', explode('_', $k))); //TODO add LANS? 6107 } 6108 6109 // override 6110 $where = vartrue($parms['area'], 'front'); 6111 $location = vartrue($parms['plugin']) ? $parms['plugin'].'/' : ''; 6112 $tmp = e107::getFile()->get_files(e107::getThemeInfo($where, 'rel').'templates/'.$location.$ilocation, vartrue($parms['fmask']), vartrue($parms['omit'], 'standard'), vartrue($parms['recurse_level'], 0)); 6113 foreach(self::sort_get_files_output($tmp) as $files) 6114 { 6115 $k = str_replace('_template.php', '', $files['fname']); 6116 $templates[$k] = implode(' ', array_map('ucfirst', explode('_', $k))); //TODO add LANS? 6117 } 6118 $ret = (vartrue($parms['raw']) ? $templates : $this->selectbox($key, $templates, $value)); 6119 break; 6120 6121 case 'checkboxes': 6122 6123 if(is_array($parms)) 6124 { 6125 $eloptions = vartrue($parms['__options'], array()); 6126 if(is_string($eloptions)) parse_str($eloptions, $eloptions); 6127 if($attributes['type'] === 'comma') $eloptions['multiple'] = true; 6128 unset($parms['__options']); 6129 6130 if(!is_array($value) && !empty($value)) 6131 { 6132 $value = explode(",",$value); 6133 } 6134 6135 6136 $ret = vartrue($eloptions['pre']).$this->checkboxes($key, (array) $parms, $value, $eloptions).vartrue($eloptions['post']); 6137 6138 6139 } 6140 return $ret; 6141 break; 6142 6143 6144 case 'dropdown': 6145 case 'comma': 6146 6147 6148 if(!empty($attributes['writeParms']['optArray'])) 6149 { 6150 $eloptions = $attributes['writeParms']; 6151 unset($eloptions['optArray']); 6152 } 6153 else 6154 { 6155 $eloptions = vartrue($parms['__options'], array()); 6156 } 6157 6158 $value = (isset($eloptions['empty']) && ($value === null)) ? $eloptions['empty'] : $value; 6159 6160 if(is_string($eloptions)) parse_str($eloptions, $eloptions); 6161 if($attributes['type'] === 'comma') $eloptions['multiple'] = true; 6162 unset($parms['__options']); 6163 if(vartrue($eloptions['multiple']) && !is_array($value)) $value = explode(',', $value); 6164 6165 // Allow Ajax API. 6166 if(!empty($ajaxParms)) 6167 { 6168 $eloptions = array_merge_recursive($eloptions, $ajaxParms); 6169 $eloptions['class'] = 'e-ajax ' . varset($eloptions['class']); 6170 } 6171 6172 $ret = vartrue($eloptions['pre']).$this->select($key, $parms, $value, $eloptions).vartrue($eloptions['post']); 6173 break; 6174 6175 case 'radio': 6176 // TODO - more options (multi-line, help) 6177 $eloptions = vartrue($parms['__options'], array()); 6178 if(is_string($eloptions)) parse_str($eloptions, $eloptions); 6179 unset($parms['__options']); 6180 $ret = vartrue($eloptions['pre']).$this->radio_multi($key, $parms, $value, $eloptions, false).vartrue($eloptions['post']); 6181 break; 6182 6183 case 'userclass': 6184 case 'userclasses': 6185 6186 6187 $uc_options = vartrue($parms['classlist'], 'public,guest,nobody,member,admin,main,classes'); // defaults to 'public,guest,nobody,member,classes' (userclass handler) 6188 unset($parms['classlist']); 6189 6190 6191 // $method = ($attributes['type'] == 'userclass') ? 'uc_select' : 'uc_select'; 6192 if(vartrue($attributes['type']) == 'userclasses'){ $parms['multiple'] = true; } 6193 6194 $ret = vartrue($parms['pre']).$this->uc_select($key, $value, $uc_options, vartrue($parms, array())). vartrue($parms['post']); 6195 break; 6196 6197 /*case 'user_name': 6198 case 'user_loginname': 6199 case 'user_login': 6200 case 'user_customtitle': 6201 case 'user_email':*/ 6202 case 'user': 6203 //user_id expected 6204 // Just temporary solution, could be changed soon 6205 6206 6207 if(!isset($parms['__options'])) $parms['__options'] = array(); 6208 if(!is_array($parms['__options'])) parse_str($parms['__options'], $parms['__options']); 6209 6210 if((empty($value) || !empty($parms['currentInit']) && empty($parms['default']) ) || !empty($parms['current']) || (vartrue($parms['default']) == 'USERID')) // include current user by default. 6211 { 6212 $value = array('user_id'=>USERID, 'user_name'=>USERNAME); 6213 if(vartrue($parms['current'])) 6214 { 6215 $parms['__options']['readonly'] = true; 6216 } 6217 6218 } 6219 6220 6221 6222 6223 6224 // if(!is_array($value)) 6225 // { 6226 // $value = $value ? e107::getSystemUser($value, true)->getUserData() : array();// e107::user($value); 6227 // } 6228 6229 $colname = vartrue($parms['nameType'], 'user_name'); 6230 $parms['__options']['name'] = $colname; 6231 6232 // if(!$value) $value = array(); 6233 // $uname = varset($value[$colname]); 6234 // $value = varset($value['user_id'], 0); 6235 6236 if(!empty($parms['limit'])) 6237 { 6238 $parms['__options']['limit'] = intval($parms['limit']); 6239 } 6240 6241 $ret = $this->userpicker(vartrue($parms['nameField'], $key), $value, vartrue($parms['__options'])); 6242 6243 // $ret = $this->userpicker(vartrue($parms['nameField'], $key), $key, $uname, $value, vartrue($parms['__options'])); 6244 break; 6245 6246 6247 /** 6248 * $parms['true'] - label to use for true 6249 * $parms['false'] - label to use for false 6250 * $parms['enabled'] - alias of $parms['true'] 6251 * $parms['disabled'] - alias of $parms['false'] 6252 * $parms['label'] - when set to 'yesno' uses yes/no instead of enabled/disabled 6253 */ 6254 case 'bool': 6255 case 'boolean': 6256 6257 if(varset($parms['label']) === 'yesno') 6258 { 6259 $lenabled = 'LAN_YES'; 6260 $ldisabled = 'LAN_NO'; 6261 } 6262 else 6263 { 6264 $lenabled = vartrue($parms['enabled'], 'LAN_ON'); 6265 $ldisabled = (!empty($parms['disabled']) && is_string($parms['disabled'])) ? $parms['disabled'] : 'LAN_OFF'; 6266 } 6267 6268 if(!empty($parms['true'])) 6269 { 6270 $lenabled = $parms['true']; 6271 } 6272 6273 if(!empty($parms['false'])) 6274 { 6275 $ldisabled = $parms['false']; 6276 } 6277 6278 6279 unset($parms['enabled'], $parms['disabled'], $parms['label']); 6280 $ret = vartrue($parms['pre']).$this->radio_switch($key, $value, defset($lenabled, $lenabled), defset($ldisabled, $ldisabled),$parms).vartrue($parms['post']); 6281 break; 6282 6283 case "checkbox": 6284 6285 $value = (isset($parms['value'])) ? $parms['value'] : $value; 6286 $ret = vartrue($parms['pre']).$this->checkbox($key, 1, $value,$parms).vartrue($parms['post']); 6287 break; 6288 6289 case 'method': // Custom Function 6290 $meth = (!empty($attributes['method'])) ? $attributes['method'] : $key; 6291 $parms['field'] = $key; 6292 6293 if(strpos($meth,'::')!==false) 6294 { 6295 list($className,$meth) = explode('::', $meth); 6296 $cls = new $className; 6297 } 6298 else 6299 { 6300 $cls = $this; 6301 } 6302 6303 $ret = call_user_func_array(array($cls, $meth), array($value, 'write', $parms)); 6304 break; 6305 6306 case 'upload': //TODO - from method 6307 // TODO uploadfile SC is now processing uploads as well (add it to admin UI), write/readParms have to be added (see uploadfile.php parms) 6308 $disbut = varset($parms['disable_button'], '0'); 6309 $ret = $tp->parseTemplate("{UPLOADFILE=".(vartrue($parms['path']) ? e107::getParser()->replaceConstants($parms['path']) : e_UPLOAD)."|nowarn&trigger=etrigger_uploadfiles&disable_button={$disbut}}"); 6310 break; 6311 6312 case 'hidden': 6313 6314 $value = (isset($parms['value'])) ? $parms['value'] : $value; 6315 $ret = (vartrue($parms['show']) ? ($value ? $value : varset($parms['empty'], $value)) : ''); 6316 $ret = $ret.$this->hidden($key, $value); 6317 break; 6318 6319 case 'lanlist': // installed languages 6320 case 'language': // all languages 6321 6322 $options = ($attributes['type'] === 'language') ? e107::getLanguage()->getList() : e107::getLanguage()->getLanSelectArray(); 6323 6324 $eloptions = vartrue($parms['__options'], array()); 6325 if(!is_array($eloptions)) parse_str($eloptions, $eloptions); 6326 unset($parms['__options']); 6327 if(vartrue($eloptions['multiple']) && !is_array($value)) $value = explode(',', $value); 6328 $ret = vartrue($eloptions['pre']).$this->selectbox($key, $options, $value, $eloptions).vartrue($eloptions['post']); 6329 break; 6330 6331 case null: 6332 // Possibly used in db but should not be submitted in form. @see news_extended. 6333 break; 6334 6335 default:// No LAN necessary, debug only. 6336 $ret = (ADMIN) ? "<span class='alert alert-error alert-danger'>".LAN_ERROR." Unknown 'type' : ".$attributes['type'] ."</span>" : $value; 6337 break; 6338 } 6339 6340 if(vartrue($parms['expand'])) 6341 { 6342 $k = "exp-".$this->name2id($key); 6343 $text = "<a class='e-expandit e-tip' href='#{$k}'>".$parms['expand']."</a>"; 6344 $text .= vartrue($parms['help']) ? '<div class="field-help">'.$parms['help'].'</div>' : ''; 6345 $text .= "<div id='{$k}' class='e-hideme'>".$ret."</div>"; 6346 return $text; 6347 } 6348 else 6349 { 6350 /** @deprecated usage @see renderCreateFieldset() should be attributes['help'] */ 6351 $ret .= vartrue($parms['help']) ? '<div class="field-help">'.$tp->toHTML($parms['help'],false,'defs').'</div>' : ''; 6352 } 6353 6354 return $ret; 6355 } 6356 6357 6358 private function imageradio($name,$value,$parms) 6359 { 6360 6361 if(!empty($parms['path'])) 6362 { 6363 $parms['legacy'] = $parms['path']; 6364 } 6365 6366 6367 $text = '<div class="clearfix">'; 6368 6369 6370 6371 foreach($parms['optArray'] as $key=>$val) 6372 { 6373 $thumbnail = e107::getParser()->toImage($val,$parms); 6374 6375 // $thumbnail = "<img class='img-responsive img-fluid thumbnail' src='".$preview ."' alt='".$val."' />"; 6376 6377 6378 $selected = ($val == $value) ? " checked" : ""; 6379 6380 $text .= " 6381 <div class='col-md-2 e-image-radio' > 6382 <label class='theme-selection' title=\"".$key."\"><input type='radio' name='".$name."' value='{$val}' required='required' $selected /> 6383 <div>".$thumbnail."</div> 6384 </label> 6385 </div>"; 6386 6387 } 6388 6389 $text .= "</div>"; 6390 6391 return $text; 6392 6393 } 6394 6395 6396 6397 /** 6398 * Generic List Form, used internally by admin UI 6399 * Expected options array format: 6400 * <code> 6401 * <?php 6402 * $form_options['myplugin'] = array( 6403 * 'id' => 'myplugin', // unique string used for building element ids, REQUIRED 6404 * 'pid' => 'primary_id', // primary field name, REQUIRED 6405 * 'url' => '{e_PLUGIN}myplug/admin_config.php', // if not set, e_SELF is used 6406 * 'query' => 'mode=main&action=list', // or e_QUERY if not set 6407 * 'head_query' => 'mode=main&action=list', // without field, asc and from vars, REQUIRED 6408 * 'np_query' => 'mode=main&action=list', // without from var, REQUIRED for next/prev functionality 6409 * 'legend' => 'Fieldset Legend', // hidden by default 6410 * 'form_pre' => '', // markup to be added before opening form element (e.g. Filter form) 6411 * 'form_post' => '', // markup to be added after closing form element 6412 * 'fields' => array(...), // see e_admin_ui::$fields 6413 * 'fieldpref' => array(...), // see e_admin_ui::$fieldpref 6414 * 'table_pre' => '', // markup to be added before opening table element 6415 * 'table_post' => '', // markup to be added after closing table element (e.g. Batch actions) 6416 * 'fieldset_pre' => '', // markup to be added before opening fieldset element 6417 * 'fieldset_post' => '', // markup to be added after closing fieldset element 6418 * 'perPage' => 15, // if 0 - no next/prev navigation 6419 * 'from' => 0, // current page, default 0 6420 * 'field' => 'field_name', //current order field name, default - primary field 6421 * 'asc' => 'desc', //current 'order by' rule, default 'asc' 6422 * ); 6423 * $tree_models['myplugin'] = new e_admin_tree_model($data); 6424 * </code> 6425 * TODO - move fieldset & table generation in separate methods, needed for ajax calls 6426 * @param array $form_options 6427 * @param e_admin_tree_model $tree_model 6428 * @param boolean $nocontainer don't enclose form in div container 6429 * @return string 6430 */ 6431 public function renderListForm($form_options, $tree_models, $nocontainer = false) 6432 { 6433 $tp = e107::getParser(); 6434 $text = ''; 6435 6436 6437 6438 foreach ($form_options as $fid => $options) 6439 { 6440 list($type,$plugin) = explode('-',$fid,2); 6441 6442 $plugin = str_replace('-','_',$plugin); 6443 6444 e107::setRegistry('core/adminUI/currentPlugin', $plugin); 6445 6446 /** @var e_tree_model $tree_model */ 6447 $tree_model = $tree_models[$fid]; 6448 $tree = $tree_model->getTree(); 6449 $total = $tree_model->getTotal(); 6450 6451 6452 $amount = $options['perPage']; 6453 $from = vartrue($options['from'], 0); 6454 $field = vartrue($options['field'], $options['pid']); 6455 $asc = strtoupper(vartrue($options['asc'], 'asc')); 6456 $elid = $fid;//$options['id']; 6457 $query = vartrue($options['query'],e_QUERY); // ? $options['query'] : ; 6458 if(vartrue($_GET['action']) == 'list') 6459 { 6460 $query = e_QUERY; //XXX Quick fix for loss of pagination after 'delete'. 6461 } 6462 $url = (isset($options['url']) ? $tp->replaceConstants($options['url'], 'abs') : e_SELF); 6463 $formurl = $url.($query ? '?'.$query : ''); 6464 $fields = $options['fields']; 6465 $current_fields = varset($options['fieldpref']) ? $options['fieldpref'] : array_keys($options['fields']); 6466 $legend_class = vartrue($options['legend_class'], 'e-hideme'); 6467 6468 6469 6470 $text .= " 6471 <form method='post' action='{$formurl}' id='{$elid}-list-form'> 6472 <div>".$this->token()." 6473 ".vartrue($options['fieldset_pre'])." 6474 <fieldset id='{$elid}-list'> 6475 <legend class='{$legend_class}'>".$options['legend']."</legend> 6476 ".vartrue($options['table_pre'])." 6477 <table class='table adminlist table-striped' id='{$elid}-list-table'> 6478 ".$this->colGroup($fields, $current_fields)." 6479 ".$this->thead($fields, $current_fields, varset($options['head_query']), varset($options['query']))." 6480 <tbody id='e-sort'> 6481 "; 6482 6483 if(!$tree) 6484 { 6485 $text .= " 6486 </tbody> 6487 </table>"; 6488 6489 $text .= "<div id='admin-ui-list-no-records-found' class=' alert alert-block alert-info center middle'>".LAN_NO_RECORDS_FOUND."</div>"; // not prone to column-count issues. 6490 } 6491 else 6492 { 6493 /** @var e_model $model */ 6494 foreach($tree as $model) 6495 { 6496 // $model->set('x_canonical_url', 'whatever'); 6497 6498 e107::setRegistry('core/adminUI/currentListModel', $model); 6499 $text .= $this->renderTableRow($fields, $current_fields, $model->getData(), $options['pid']); 6500 } 6501 6502 6503 e107::setRegistry('core/adminUI/currentListModel', null); 6504 6505 $text .= "</tbody> 6506 </table>"; 6507 } 6508 6509 6510 $text .= vartrue($options['table_post']); 6511 6512 6513 if($tree && $amount) 6514 { 6515 // New nextprev SC parameters 6516 $parms = 'total='.$total; 6517 $parms .= '&amount='.$amount; 6518 $parms .= '¤t='.$from; 6519 if(ADMIN_AREA) 6520 { 6521 $parms .= '&tmpl_prefix=admin'; 6522 } 6523 6524 // NOTE - the whole url is double encoded - reason is to not break parms query string 6525 // 'np_query' should be proper (urlencode'd) url query string 6526 $url = rawurlencode($url.'?'.(varset($options['np_query']) ? str_replace(array('&', '&'), array('&', '&'), $options['np_query']).'&' : '').'from=[FROM]'); 6527 $parms .= '&url='.$url; 6528 //$parms = $total.",".$amount.",".$from.",".$url.'?'.($options['np_query'] ? $options['np_query'].'&' : '').'from=[FROM]'; 6529 //$text .= $tp->parseTemplate("{NEXTPREV={$parms}}"); 6530 $nextprev = $tp->parseTemplate("{NEXTPREV={$parms}}"); 6531 if ($nextprev) 6532 { 6533 $text .= "<div class='nextprev-bar'>".$nextprev."</div>"; 6534 } 6535 } 6536 6537 $text .= " 6538 </fieldset> 6539 ".vartrue($options['fieldset_post'])." 6540 </div> 6541 </form> 6542 "; 6543 6544 e107::setRegistry('core/adminUI/currentPlugin', null); 6545 } 6546 if(!$nocontainer) 6547 { 6548 $class = deftrue('e_IFRAME') ? 'e-container e-container-modal' : 'e-container'; 6549 $text = '<div class="'.$class.'">'.$text.'</div>'; 6550 } 6551 return (vartrue($options['form_pre']).$text.vartrue($options['form_post'])); 6552 } 6553 6554 6555 /** 6556 * Used with 'carousel' generates slides with X number of cells/blocks per slide. 6557 * @param $cells 6558 * @param int $perPage 6559 * @return array 6560 */ 6561 private function slides($cells, $perPage=12) 6562 { 6563 $tmp = ''; 6564 $s = 0; 6565 $slides = array(); 6566 foreach($cells as $cell) 6567 { 6568 $tmp .= $cell; 6569 6570 $s++; 6571 if($s == $perPage) 6572 { 6573 $slides[] = array('text'=>$tmp); 6574 $tmp = ''; 6575 $s = 0; 6576 } 6577 } 6578 6579 if($s != $perPage && $s != 0) 6580 { 6581 $slides[] = array('text'=>$tmp); 6582 } 6583 6584 return $slides; 6585 6586 6587 } 6588 6589 6590 /** 6591 * Render Grid-list layout. used internally by admin UI 6592 * @param $form_options 6593 * @param $tree_models 6594 * @param bool|false $nocontainer 6595 * @return string 6596 */ 6597 public function renderGridForm($form_options, $tree_models, $nocontainer = false) 6598 { 6599 $tp = e107::getParser(); 6600 $text = ''; 6601 6602 6603 // print_a($form_options); 6604 6605 foreach ($form_options as $fid => $options) 6606 { 6607 $tree_model = $tree_models[$fid]; 6608 $tree = $tree_model->getTree(); 6609 $total = $tree_model->getTotal(); 6610 6611 $amount = $options['perPage']; 6612 $from = vartrue($options['from'], 0); 6613 $field = vartrue($options['field'], $options['pid']); 6614 $asc = strtoupper(vartrue($options['asc'], 'asc')); 6615 $elid = $fid;//$options['id']; 6616 $query = vartrue($options['query'],e_QUERY); // ? $options['query'] : ; 6617 if(vartrue($_GET['action']) == 'list') 6618 { 6619 $query = e_QUERY; //XXX Quick fix for loss of pagination after 'delete'. 6620 } 6621 $url = (isset($options['url']) ? $tp->replaceConstants($options['url'], 'abs') : e_SELF); 6622 $formurl = $url.($query ? '?'.$query : ''); 6623 $fields = $options['fields']; 6624 $current_fields = varset($options['fieldpref']) ? $options['fieldpref'] : array_keys($options['fields']); 6625 $legend_class = vartrue($options['legend_class'], 'e-hideme'); 6626 6627 6628 6629 $text .= " 6630 <form method='post' action='{$formurl}' id='{$elid}-list-form'> 6631 <div>".$this->token()." 6632 ".vartrue($options['fieldset_pre']); 6633 6634 $text .= " 6635 6636 <fieldset id='{$elid}-list'> 6637 <legend class='{$legend_class}'>".$options['legend']."</legend> 6638 ".vartrue($options['table_pre'])." 6639 <div class='row admingrid ' id='{$elid}-list-grid'> 6640 "; 6641 6642 6643 if(!$tree) 6644 { 6645 $text .= "</div>"; 6646 $text .= "<div id='admin-ui-list-no-records-found' class=' alert alert-block alert-info center middle'>".LAN_NO_RECORDS_FOUND."</div>"; // not prone to column-count issues. 6647 } 6648 else 6649 { 6650 6651 6652 if(empty($options['grid']['template'])) 6653 { 6654 $template = '<div class="panel panel-default"> 6655 <div class="e-overlay" >{IMAGE} 6656 <div class="e-overlay-content"> 6657 {OPTIONS} 6658 </div> 6659 </div> 6660 <div class="panel-footer">{TITLE}<span class="pull-right">{CHECKBOX}</span></div> 6661 </div>'; 6662 } 6663 else 6664 { 6665 $template = $options['grid']['template']; 6666 } 6667 6668 6669 $cls = !empty($options['grid']['class']) ? $options['grid']['class'] : 'col-md-2'; 6670 $pid = $options['pid']; 6671 $perPage = $options['grid']['perPage']; 6672 6673 6674 6675 $gridFields = $options['grid']; 6676 $gridFields['options'] = 'options'; 6677 $gridFields['checkbox'] = 'checkboxes'; 6678 6679 unset($gridFields['class'],$gridFields['perPage'], $gridFields['carousel']); 6680 6681 $cells = array(); 6682 foreach($tree as $model) 6683 { 6684 e107::setRegistry('core/adminUI/currentListModel', $model); 6685 6686 $data = $model->getData(); 6687 6688 $id = $data[$pid]; 6689 $vars = array(); 6690 6691 foreach($gridFields as $k=>$v) 6692 { 6693 $key = strtoupper($k); 6694 $fields[$v]['grid'] = true; 6695 $vars[$key] = $this->renderValue($v,$data[$v],$fields[$v],$id); 6696 } 6697 6698 $cells[] = "<div class='".$cls." admin-ui-grid'>". $tp->simpleParse($template,$vars). "</div>"; 6699 6700 } 6701 6702 6703 if($options['grid']['carousel'] === true) 6704 { 6705 $slides = $this->slides($cells, $perPage); 6706 $carouselData = $this->carousel('admin-ui-carousel',$slides, array('wrap'=>false, 'interval'=>false, 'data'=>true)); 6707 6708 $text .= $carouselData['start'].$carouselData['inner'].$carouselData['end']; 6709 6710 } 6711 else 6712 { 6713 $text .= implode("\n",$cells); 6714 } 6715 6716 6717 e107::setRegistry('core/adminUI/currentListModel', null); 6718 6719 $text .= "</div> 6720 <div class='clearfix'></div>"; 6721 } 6722 6723 6724 $text .= vartrue($options['table_post']); 6725 6726 6727 if($tree && $amount) 6728 { 6729 // New nextprev SC parameters 6730 $parms = 'total='.$total; 6731 $parms .= '&amount='.$amount; 6732 $parms .= '¤t='.$from; 6733 6734 if(ADMIN_AREA) 6735 { 6736 $parms .= '&tmpl_prefix=admin'; 6737 } 6738 6739 // NOTE - the whole url is double encoded - reason is to not break parms query string 6740 // 'np_query' should be proper (urlencode'd) url query string 6741 $url = rawurlencode($url.'?'.(varset($options['np_query']) ? str_replace(array('&', '&'), array('&', '&'), $options['np_query']).'&' : '').'from=[FROM]'); 6742 $parms .= '&url='.$url; 6743 //$parms = $total.",".$amount.",".$from.",".$url.'?'.($options['np_query'] ? $options['np_query'].'&' : '').'from=[FROM]'; 6744 //$text .= $tp->parseTemplate("{NEXTPREV={$parms}}"); 6745 $nextprev = $tp->parseTemplate("{NEXTPREV={$parms}}"); 6746 if ($nextprev) 6747 { 6748 $text .= "<div class='nextprev-bar'>".$nextprev."</div>"; 6749 } 6750 } 6751 6752 $text .= " 6753 </fieldset> 6754 ".vartrue($options['fieldset_post'])." 6755 </div> 6756 </form> 6757 "; 6758 } 6759 if(!$nocontainer) 6760 { 6761 $class = deftrue('e_IFRAME') ? 'e-container e-container-modal' : 'e-container'; 6762 $text = '<div class="'.$class.'">'.$text.'</div>'; 6763 } 6764 return (vartrue($options['form_pre']).$text.vartrue($options['form_post'])); 6765 } 6766 6767 /** 6768 * Generic DB Record Management Form. 6769 * TODO - lans 6770 * TODO - move fieldset & table generation in separate methods, needed for ajax calls 6771 * Expected arrays format: 6772 * <code> 6773 * <?php 6774 * $forms[0] = array( 6775 * 'id' => 'myplugin', 6776 * 'url' => '{e_PLUGIN}myplug/admin_config.php', //if not set, e_SELF is used 6777 * 'query' => 'mode=main&action=edit&id=1', //or e_QUERY if not set 6778 * 'tabs' => true, * 6779 * 'fieldsets' => array( 6780 * 'general' => array( 6781 * 'legend' => 'Fieldset Legend', 6782 * 'fields' => array(...), //see e_admin_ui::$fields 6783 * 'after_submit_options' => array('action' => 'Label'[,...]), // or true for default redirect options 6784 * 'after_submit_default' => 'action_name', 6785 * 'triggers' => 'auto', // standard create/update-cancel triggers 6786 * //or custom trigger array in format array('sibmit' => array('Title', 'create', '1'), 'cancel') - trigger name - title, action, optional hidden value (in this case named sibmit_value) 6787 * ), 6788 * 6789 * 'advanced' => array( 6790 * 'legend' => 'Fieldset Legend', 6791 * 'fields' => array(...), //see e_admin_ui::$fields 6792 * 'after_submit_options' => array('__default' => 'action_name' 'action' => 'Label'[,...]), // or true for default redirect options 6793 * 'triggers' => 'auto', // standard create/update-cancel triggers 6794 * //or custom trigger array in format array('submit' => array('Title', 'create', '1'), 'cancel' => array('cancel', 'cancel')) - trigger name - title, action, optional hidden value (in this case named sibmit_value) 6795 * ) 6796 * ) 6797 * ); 6798 * $models[0] = new e_admin_model($data); 6799 * $models[0]->setFieldIdName('primary_id'); // you need to do it if you don't use your own admin model extension 6800 * </code> 6801 * @param array $forms numerical array 6802 * @param array $models numerical array with values instance of e_admin_model 6803 * @param boolean $nocontainer don't enclose in div container 6804 * @return string 6805 */ 6806 function renderCreateForm($forms, $models, $nocontainer = false) 6807 { 6808 $text = ''; 6809 foreach ($forms as $fid => $form) 6810 { 6811 $model = $models[$fid]; 6812 6813 e107::setRegistry('core/adminUI/currentModel', $model); 6814 6815 if(!is_object($model)) 6816 { 6817 e107::getDebug()->log("No model object found with key ".$fid); 6818 } 6819 6820 $query = isset($form['query']) ? $form['query'] : e_QUERY ; 6821 $url = (isset($form['url']) ? e107::getParser()->replaceConstants($form['url'], 'abs') : e_SELF).($query ? '?'.$query : ''); 6822 $curTab = strval(varset($_GET['tab'],'0')); 6823 6824 $text .= " 6825 <form method='post' action='".$url."' id='{$form['id']}-form' enctype='multipart/form-data' autocomplete='off' > 6826 <div style='display:none'><input type='text' name='lastname_74758209201093747' autocomplete='off' id='_no_autocomplete_' /></div> 6827 <div id='admin-ui-edit'> 6828 ".vartrue($form['header'])." 6829 ".$this->token()." 6830 "; 6831 6832 foreach ($form['fieldsets'] as $elid => $data) 6833 { 6834 $elid = $form['id'].'-'.$elid; 6835 6836 if(vartrue($data['tabs'])) // Tabs Present 6837 { 6838 $text .= '<ul class="nav nav-tabs">'; 6839 foreach($data['tabs'] as $i=>$label) 6840 { 6841 $class = (strval($i) === $curTab) ? 'class="active" ' : ''; 6842 $text .= '<li '.$class.'><a href="#tab'.$i.'" data-toggle="tab">'.$label.'</a></li>'; 6843 } 6844 $text .= ' </ul><div class="tab-content">'; 6845 6846 foreach($data['tabs'] as $tabId=>$label) 6847 { 6848 $active = (strval($tabId) === $curTab) ? 'active' : ''; 6849 $text .= '<div class="tab-pane '.$active.'" id="tab'.$tabId.'">'; 6850 6851 // e107::getDebug()->log('elid: '.$elid. " tabid: ".$tabId); 6852 // e107::getDebug()->log($data); 6853 // e107::getDebug()->log($model); 6854 6855 6856 $text .= $this->renderCreateFieldset($elid, $data, $model, $tabId); 6857 $text .= "</div>"; 6858 } 6859 6860 $text .= "</div>"; 6861 $text .= $this->renderCreateButtonsBar( $data, $model->getId()); // Create/Update Buttons etc. 6862 6863 } 6864 else // No Tabs Present 6865 { 6866 $text .= $this->renderCreateFieldset($elid, $data, $model, false); 6867 $text .= $this->renderCreateButtonsBar( $data, $model->getId()); // Create/Update Buttons etc. 6868 } 6869 6870 6871 } 6872 6873 $text .= " 6874 ".vartrue($form['footer'])." 6875 </div> 6876 </form> 6877 "; 6878 6879 // e107::js('footer-inline',"Form.focusFirstElement('{$form['id']}-form');",'prototype'); 6880 // e107::getJs()->footerInline("Form.focusFirstElement('{$form['id']}-form');"); 6881 } 6882 if(!$nocontainer) 6883 { 6884 $class = deftrue('e_IFRAME') ? 'e-container e-container-modal' : 'e-container'; 6885 $text = '<div class="'.$class.'">'.$text.'</div>'; 6886 } 6887 return $text; 6888 } 6889 6890 /** 6891 * Create form fieldset, called internal by {@link renderCreateForm()) 6892 * 6893 * @param string $id field id 6894 * @param array $fdata fieldset data 6895 * @param object $model 6896 * @return string | false 6897 */ 6898 function renderCreateFieldset($id, $fdata, $model, $tab=0) 6899 { 6900 6901 6902 $start = vartrue($fdata['fieldset_pre'])." 6903 <fieldset id='{$id}-".$tab."'> 6904 <legend>".vartrue($fdata['legend'])."</legend> 6905 ".vartrue($fdata['table_pre'])." 6906 <table class='table adminform'> 6907 <colgroup> 6908 <col class='col-label' /> 6909 <col class='col-control' /> 6910 </colgroup> 6911 <tbody> 6912 "; 6913 6914 $text = ''; 6915 6916 // required fields - model definition 6917 $model_required = $model->getValidationRules(); 6918 $required_help = false; 6919 $hidden_fields = array(); 6920 6921 foreach($fdata['fields'] as $key => $att) 6922 { 6923 if($tab !== false && varset($att['tab'], 0) !== $tab) 6924 { 6925 continue; 6926 } 6927 6928 // convert aliases - not supported in edit mod 6929 if(vartrue($att['alias']) && !$model->hasData($key)) 6930 { 6931 $key = $att['field']; 6932 } 6933 6934 if($key == 'checkboxes' || $key == 'options' || ($att['type'] === null) || ($att['type'] === false)) 6935 { 6936 continue; 6937 } 6938 6939 $parms = vartrue($att['formparms'], array()); 6940 if(!is_array($parms)) parse_str($parms, $parms); 6941 $label = !empty($att['note']) ? '<div class="label-note">'.deftrue($att['note'], $att['note']).'</div>' : ''; 6942 $help = !empty($att['help']) ? '<div class="field-help" data-placement="left">'.deftrue($att['help'], $att['help']).'</div>' : ''; 6943 6944 6945 $valPath = trim(vartrue($att['dataPath'], $key), '/'); 6946 $keyName = $key; 6947 if(strpos($valPath, '/')) //not TRUE, cause string doesn't start with / 6948 { 6949 $tmp = explode('/', $valPath); 6950 $keyName = array_shift($tmp); 6951 foreach ($tmp as $path) 6952 { 6953 $keyName .= '['.$path.']'; 6954 } 6955 } 6956 6957 if(!empty($att['writeParms']) && !is_array($att['writeParms'])) 6958 { 6959 parse_str(varset($att['writeParms']), $writeParms); 6960 } 6961 else 6962 { 6963 $writeParms = varset($att['writeParms']); 6964 } 6965 6966 if(!empty($writeParms['sef'])) // group sef generate button with input element. 6967 { 6968 if(empty($writeParms['tdClassRight'])) 6969 { 6970 $writeParms['tdClassRight'] = 'input-group'; 6971 6972 } 6973 else 6974 { 6975 $writeParms['tdClassRight'] .= ' input-group'; 6976 } 6977 6978 } 6979 6980 if('hidden' === $att['type']) 6981 { 6982 6983 if(empty($writeParms['show'])) // hidden field and not displayed. Render element after the field-set. 6984 { 6985 $hidden_fields[] = $this->renderElement($keyName, $model->getIfPosted($valPath), $att, varset($model_required[$key], array())); 6986 6987 continue; 6988 } 6989 unset($tmp); 6990 } 6991 6992 // type null - system (special) fields 6993 if(vartrue($att['type']) !== null && !vartrue($att['noedit']) && $key != $model->getFieldIdName()) 6994 { 6995 $required = ''; 6996 $required_class = ''; 6997 if(isset($model_required[$key]) || vartrue($att['validate']) || !empty($att['writeParms']['required'])) 6998 { 6999 7000 $required = $this->getRequiredString(); 7001 $required_class = ' class="required-label" title="'.LAN_REQUIRED.'"'; 7002 $required_help = true; 7003 7004 if(!empty($att['validate'])) 7005 { 7006 // override 7007 $model_required[$key] = array(); 7008 $model_required[$key][] = true === $att['validate'] ? 'required' : $att['validate']; 7009 $model_required[$key][] = varset($att['rule']); 7010 $model_required[$key][] = $att['title']; 7011 $model_required[$key][] = varset($att['error']); 7012 } 7013 } 7014 7015 7016 if(in_array($key,$this->_field_warnings)) 7017 { 7018 if(is_string($writeParms)) 7019 { 7020 parse_str($writeParms,$writeParms); 7021 } 7022 7023 $writeParms['tdClassRight'] .= ' has-warning'; 7024 7025 } 7026 7027 $leftCell = "<span{$required_class}>".defset(vartrue($att['title']), vartrue($att['title']))."</span>".$required.$label; 7028 $rightCell = $this->renderElement($keyName, $model->getIfPosted($valPath), $att, varset($model_required[$key], array()), $model->getId())." ".$help; 7029 7030 $att['writeParms'] = $writeParms; 7031 7032 $text .= $this->renderCreateFieldRow($leftCell, $rightCell, $att); 7033 7034 7035 7036 } 7037 7038 7039 } 7040 7041 7042 if(!empty($text) || !empty($hidden_fields)) 7043 { 7044 $text = $start.$text; 7045 7046 $text .= " 7047 </tbody> 7048 </table>"; 7049 7050 $text .= vartrue($fdata['table_post']); 7051 7052 $text .= implode("\n", $hidden_fields); 7053 7054 $text .= "</fieldset>"; 7055 7056 $text .= vartrue($fdata['fieldset_post']); 7057 7058 return $text; 7059 } 7060 7061 7062 7063 return false; 7064 7065 7066 } 7067 7068 7069 7070 /** 7071 * Render Create/Edit Fieldset Row. 7072 * @param string $label 7073 * @param string $control 7074 * @param array $att 7075 * @return string 7076 */ 7077 public function renderCreateFieldRow($label, $control, $att = array()) 7078 { 7079 7080 $writeParms = $att['writeParms']; 7081 7082 if(vartrue($att['type']) == 'bbarea' || !empty($writeParms['nolabel'])) 7083 { 7084 $text = " 7085 <tr> 7086 <td colspan='2'>"; 7087 7088 $text .= (isset($writeParms['nolabel']) && $writeParms['nolabel'] == 2) ? '' : "<div style='padding-bottom:8px'>".$label."</div>" ; 7089 $text .= $control." 7090 </td> 7091 </tr> 7092 "; 7093 7094 return $text; 7095 7096 } 7097 7098 $leftCellClass = (!empty($writeParms['tdClassLeft'])) ? " class='".$writeParms['tdClassLeft']."'" : ""; 7099 $rightCellClass = (!empty($writeParms['tdClassRight'])) ? " class='".$writeParms['tdClassRight']."'" : ""; 7100 $trClass = (!empty($writeParms['trClass'])) ? " class='".$writeParms['trClass']."'" : ""; 7101 7102 $text = " 7103 <tr{$trClass}> 7104 <td{$leftCellClass}> 7105 ".$label." 7106 </td> 7107 <td{$rightCellClass}> 7108 ".$control." 7109 </td> 7110 </tr> 7111 "; 7112 7113 return $text; 7114 7115 } 7116 7117 7118 7119 7120 /** 7121 * Render the submit buttons in the Create/Edit Form. 7122 * @param array $fdata - admin-ui data such as $fields, $tabs, $after_submit_options etc. 7123 * @param int $id Primary ID of the record being edited (only in edit-mode) 7124 * @return string 7125 */ 7126 public function renderCreateButtonsBar($fdata, $id=null) // XXX Note model and $tab removed as of v2.3 7127 { 7128 $text = " 7129 <div class='buttons-bar center'> 7130 "; 7131 // After submit options 7132 $defsubmitopt = array('list' => LAN_EFORM_013, 'create' => LAN_EFORM_014, 'edit' => LAN_EFORM_015); 7133 $submitopt = isset($fdata['after_submit_options']) ? $fdata['after_submit_options'] : true; 7134 7135 if(true === $submitopt) 7136 { 7137 $submitopt = $defsubmitopt; 7138 } 7139 7140 if($submitopt) 7141 { 7142 $selected = isset($fdata['after_submit_default']) && array_key_exists($fdata['after_submit_default'], $submitopt) ? $fdata['after_submit_default'] : 'list'; 7143 } 7144 7145 $triggers = (empty($fdata['triggers']) && $fdata['triggers'] !== false) ? 'auto' : $fdata['triggers']; // vartrue($fdata['triggers'], 'auto'); 7146 7147 if(is_string($triggers) && 'auto' === $triggers) 7148 { 7149 $triggers = array(); 7150 if(!empty($id)) 7151 { 7152 $triggers['submit'] = array(LAN_UPDATE, 'update', $id); 7153 } 7154 else 7155 { 7156 $triggers['submit'] = array(LAN_CREATE, 'create', 0); 7157 } 7158 7159 $triggers['cancel'] = array(LAN_CANCEL, 'cancel'); 7160 } 7161 7162 if(!empty($triggers)) 7163 { 7164 foreach ($triggers as $trigger => $tdata) 7165 { 7166 $text .= ($trigger == 'submit') ? "<div class='etrigger-submit-group btn-group'>" : ""; 7167 $text .= $this->admin_button('etrigger_'.$trigger, $tdata[1], $tdata[1], $tdata[0]); 7168 7169 if($trigger == 'submit' && $submitopt) 7170 { 7171 7172 $text .= 7173 '<button class="btn btn-success dropdown-toggle left" data-toggle="dropdown"> 7174 <span class="caret"></span> 7175 </button> 7176 <ul class="dropdown-menu col-selection"> 7177 <li class="dropdown-header nav-header">'.LAN_EFORM_016.'</li> 7178 '; 7179 7180 foreach($submitopt as $k=>$v) 7181 { 7182 $text .= "<li class='after-submit'>".$this->radio('__after_submit_action', $k, $selected == $k, "label=".$v)."</li>"; 7183 } 7184 7185 $text .= '</ul>'; 7186 } 7187 7188 $text .= ($trigger == 'submit') ?"</div>" : ""; 7189 7190 if(isset($tdata[2])) 7191 { 7192 $text .= $this->hidden($trigger.'_value', $tdata[2]); 7193 } 7194 } 7195 } 7196 7197 $text .= " 7198 </div> 7199 7200 "; 7201 7202 return $text; 7203 } 7204 7205 7206 /** 7207 * Generic renderForm solution 7208 * @param @forms 7209 * @param @nocontainer 7210 * @return string 7211 */ 7212 function renderForm($forms, $nocontainer = false) 7213 { 7214 $text = ''; 7215 foreach ($forms as $fid => $form) 7216 { 7217 $query = isset($form['query']) ? $form['query'] : e_QUERY ; 7218 $url = (isset($form['url']) ? e107::getParser()->replaceConstants($form['url'], 'abs') : e_SELF).($query ? '?'.$query : ''); 7219 7220 $text .= " 7221 ".vartrue($form['form_pre'])." 7222 <form method='post' action='".$url."' id='{$form['id']}-form' enctype='multipart/form-data'> 7223 <div> 7224 ".vartrue($form['header'])." 7225 ".$this->token()." 7226 "; 7227 7228 foreach ($form['fieldsets'] as $elid => $fieldset_data) 7229 { 7230 $elid = $form['id'].'-'.$elid; 7231 $text .= $this->renderFieldset($elid, $fieldset_data); 7232 } 7233 7234 $text .= " 7235 ".vartrue($form['footer'])." 7236 </div> 7237 </form> 7238 ".vartrue($form['form_post'])." 7239 "; 7240 } 7241 if(!$nocontainer) 7242 { 7243 $class = deftrue('e_IFRAME') ? 'e-container e-container-modal' : 'e-container'; 7244 $text = '<div class="'.$class.'">'.$text.'</div>'; 7245 } 7246 return $text; 7247 } 7248 7249 /** 7250 * Generic renderFieldset solution, will be split to renderTable, renderCol/Row/Box etc - Still in use. 7251 */ 7252 function renderFieldset($id, $fdata) 7253 { 7254 $colgroup = ''; 7255 if(vartrue($fdata['table_colgroup'])) 7256 { 7257 $colgroup = " 7258 <colgroup span='".count($fdata['table_colgroup'])."'> 7259 "; 7260 foreach ($fdata['table_colgroup'] as $i => $colgr) 7261 { 7262 $colgroup .= "<col "; 7263 foreach ($colgr as $attr => $v) 7264 { 7265 $colgroup .= "{$attr}='{$v}'"; 7266 } 7267 $colgroup .= " /> 7268 "; 7269 } 7270 7271 $colgroup = "</colgroup> 7272 "; 7273 } 7274 $text = vartrue($fdata['fieldset_pre'])." 7275 <fieldset id='{$id}'> 7276 <legend>".vartrue($fdata['legend'])."</legend> 7277 ".vartrue($fdata['table_pre'])." 7278 7279 "; 7280 7281 if(vartrue($fdata['table_rows']) || vartrue($fdata['table_body'])) 7282 { 7283 $text .= " 7284 <table class='table adminform'> 7285 {$colgroup} 7286 <thead> 7287 ".vartrue($fdata['table_head'])." 7288 </thead> 7289 <tbody> 7290 "; 7291 7292 if(vartrue($fdata['table_rows'])) 7293 { 7294 foreach($fdata['table_rows'] as $index => $row) 7295 { 7296 $text .= " 7297 <tr id='{$id}-{$index}'> 7298 $row 7299 </tr> 7300 "; 7301 } 7302 } 7303 elseif(vartrue($fdata['table_body'])) 7304 { 7305 $text .= $fdata['table_body']; 7306 } 7307 7308 if(vartrue($fdata['table_note'])) 7309 { 7310 $note = '<div class="form-note">'.$fdata['table_note'].'</div>'; 7311 } 7312 7313 $text .= " 7314 </tbody> 7315 </table> 7316 ".$note." 7317 ".vartrue($fdata['table_post'])." 7318 "; 7319 } 7320 7321 $triggers = vartrue($fdata['triggers'], array()); 7322 if($triggers) 7323 { 7324 $text .= "<div class='buttons-bar center'> 7325 ".vartrue($fdata['pre_triggers'], '')." 7326 "; 7327 foreach ($triggers as $trigger => $tdata) 7328 { 7329 if(is_string($tdata)) 7330 { 7331 $text .= $tdata; 7332 continue; 7333 } 7334 $text .= $this->admin_button('etrigger_'.$trigger, $tdata[0], $tdata[1]); 7335 if(isset($tdata[2])) 7336 { 7337 $text .= $this->hidden($trigger.'_value', $tdata[2]); 7338 } 7339 } 7340 $text .= "</div>"; 7341 } 7342 7343 $text .= " 7344 </fieldset> 7345 ".vartrue($fdata['fieldset_post'])." 7346 "; 7347 return $text; 7348 } 7349 7350 /** 7351 * Render Value Trigger - override to modify field/value/parameters 7352 * @param string $field field name 7353 * @param mixed $value field value 7354 * @param array $params 'writeParams' key (see $controller->fields array) 7355 * @param int $id record ID 7356 */ 7357 public function renderValueTrigger(&$field, &$value, &$params, $id) 7358 { 7359 7360 } 7361 7362 /** 7363 * Render Element Trigger - override to modify field/value/parameters/validation data 7364 * @param string $field field name 7365 * @param mixed $value field value 7366 * @param array $params 'writeParams' key (see $controller->fields array) 7367 * @param array $required_data validation data 7368 * @param int $id record ID 7369 */ 7370 public function renderElementTrigger(&$field, &$value, &$params, &$required_data, $id) 7371 { 7372 7373 } 7374} 7375 7376// DEPRECATED - use above methods instead ($frm) 7377class form 7378{ 7379 function form_open($form_method, $form_action, $form_name = "", $form_target = "", $form_enctype = "", $form_js = "") 7380 { 7381 $method = ($form_method ? "method='".$form_method."'" : ""); 7382 $target = ($form_target ? " target='".$form_target."'" : ""); 7383 $name = ($form_name ? " id='".$form_name."' " : " id='myform'"); 7384 return "\n<form action='".$form_action."' ".$method.$target.$name.$form_enctype.$form_js."><div>".e107::getForm()->token()."</div>"; 7385 } 7386 7387 function form_text($form_name, $form_size, $form_value, $form_maxlength = FALSE, $form_class = "tbox form-control", $form_readonly = "", $form_tooltip = "", $form_js = "") { 7388 $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : ""); 7389 $value = (isset($form_value) ? " value='".$form_value."'" : ""); 7390 $size = ($form_size ? " size='".$form_size."'" : ""); 7391 $maxlength = ($form_maxlength ? " maxlength='".$form_maxlength."'" : ""); 7392 $readonly = ($form_readonly ? " readonly='readonly'" : ""); 7393 $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : ""); 7394 return "\n<input class='".$form_class."' type='text' ".$name.$value.$size.$maxlength.$readonly.$tooltip.$form_js." />"; 7395 } 7396 7397 function form_password($form_name, $form_size, $form_value, $form_maxlength = FALSE, $form_class = "tbox form-control", $form_readonly = "", $form_tooltip = "", $form_js = "") { 7398 $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : ""); 7399 $value = (isset($form_value) ? " value='".$form_value."'" : ""); 7400 $size = ($form_size ? " size='".$form_size."'" : ""); 7401 $maxlength = ($form_maxlength ? " maxlength='".$form_maxlength."'" : ""); 7402 $readonly = ($form_readonly ? " readonly='readonly'" : ""); 7403 $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : ""); 7404 return "\n<input class='".$form_class."' type='password' ".$name.$value.$size.$maxlength.$readonly.$tooltip.$form_js." />"; 7405 } 7406 7407 function form_button($form_type, $form_name, $form_value, $form_js = "", $form_image = "", $form_tooltip = "") { 7408 $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : ""); 7409 $image = ($form_image ? " src='".$form_image."' " : ""); 7410 $tooltip = ($form_tooltip ? " title='".$form_tooltip."' " : ""); 7411 return "\n<input class='btn btn-default btn-secondary button' type='".$form_type."' ".$form_js." value='".$form_value."'".$name.$image.$tooltip." />"; 7412 } 7413 7414 function form_textarea($form_name, $form_columns, $form_rows, $form_value, $form_js = "", $form_style = "", $form_wrap = "", $form_readonly = "", $form_tooltip = "") { 7415 $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : ""); 7416 $readonly = ($form_readonly ? " readonly='readonly'" : ""); 7417 $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : ""); 7418 $wrap = ($form_wrap ? " wrap='".$form_wrap."'" : ""); 7419 $style = ($form_style ? " style='".$form_style."'" : ""); 7420 return "\n<textarea class='tbox form-control' cols='".$form_columns."' rows='".$form_rows."' ".$name.$form_js.$style.$wrap.$readonly.$tooltip.">".$form_value."</textarea>"; 7421 } 7422 7423 function form_checkbox($form_name, $form_value, $form_checked = 0, $form_tooltip = "", $form_js = "") { 7424 $name = ($form_name ? " id='".$form_name.$form_value."' name='".$form_name."'" : ""); 7425 $checked = ($form_checked ? " checked='checked'" : ""); 7426 $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : ""); 7427 return "\n<input type='checkbox' value='".$form_value."'".$name.$checked.$tooltip.$form_js." />"; 7428 7429 } 7430 7431 function form_radio($form_name, $form_value, $form_checked = 0, $form_tooltip = "", $form_js = "") { 7432 $name = ($form_name ? " id='".$form_name.$form_value."' name='".$form_name."'" : ""); 7433 $checked = ($form_checked ? " checked='checked'" : ""); 7434 $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : ""); 7435 return "\n<input type='radio' value='".$form_value."'".$name.$checked.$tooltip.$form_js." />"; 7436 7437 } 7438 7439 function form_file($form_name, $form_size, $form_tooltip = "", $form_js = "") { 7440 $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : ""); 7441 $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : ""); 7442 return "<input type='file' class='tbox' size='".$form_size."'".$name.$tooltip.$form_js." />"; 7443 } 7444 7445 function form_select_open($form_name, $form_js = "") { 7446 return "\n<select id='".$form_name."' name='".$form_name."' class='tbox form-control' ".$form_js." >"; 7447 } 7448 7449 function form_select_close() { 7450 return "\n</select>"; 7451 } 7452 7453 function form_option($form_option, $form_selected = "", $form_value = "", $form_js = "") { 7454 $value = ($form_value !== FALSE ? " value='".$form_value."'" : ""); 7455 $selected = ($form_selected ? " selected='selected'" : ""); 7456 return "\n<option".$value.$selected." ".$form_js.">".$form_option."</option>"; 7457 } 7458 7459 function form_hidden($form_name, $form_value) { 7460 return "\n<input type='hidden' id='".$form_name."' name='".$form_name."' value='".$form_value."' />"; 7461 } 7462 7463 function form_close() { 7464 return "\n</form>"; 7465 } 7466} 7467 7468/* 7469Usage 7470echo $rs->form_open("post", e_SELF, "_blank"); 7471echo $rs->form_text("testname", 100, "this is the value", 100, 0, "tooltip"); 7472echo $rs->form_button("submit", "testsubmit", "SUBMIT!", "", "Click to submit"); 7473echo $rs->form_button("reset", "testreset", "RESET!", "", "Click to reset"); 7474echo $rs->form_textarea("textareaname", 10, 10, "Value", "overflow:hidden"); 7475echo $rs->form_checkbox("testcheckbox", 1, 1); 7476echo $rs->form_checkbox("testcheckbox2", 2); 7477echo $rs->form_hidden("hiddenname", "hiddenvalue"); 7478echo $rs->form_radio("testcheckbox", 1, 1); 7479echo $rs->form_radio("testcheckbox", 1); 7480echo $rs->form_file("testfile", "20"); 7481echo $rs->form_select_open("testselect"); 7482echo $rs->form_option("Option 1"); 7483echo $rs->form_option("Option 2"); 7484echo $rs->form_option("Option 3", 1, "defaultvalue"); 7485echo $rs->form_option("Option 4"); 7486echo $rs->form_select_close(); 7487echo $rs->form_close(); 7488*/ 7489 7490 7491 7492