PageRenderTime 73ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/e107_handlers/form_handler.php

https://github.com/CasperGemini/e107
PHP | 4384 lines | 2656 code | 795 blank | 933 comment | 486 complexity | 36b2a064186e9964bdf6e858e9dac778 MD5 | raw file
Possible License(s): GPL-2.0
  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. * $URL$
  12. * $Id$
  13. *
  14. */
  15. if (!defined('e107_INIT')) { exit; }
  16. /**
  17. *
  18. * @package e107
  19. * @subpackage e107_handlers
  20. * @version $Id$
  21. * @todo hardcoded text
  22. *
  23. * Automate Form fields creation. Produced markup is following e107 CSS/XHTML standards
  24. * If options argument is omitted, default values will be used (which OK most of the time)
  25. * Options are intended to handle some very special cases.
  26. *
  27. * Overall field options format (array or GET string like this one: var1=val1&var2=val2...):
  28. *
  29. * - id => (mixed) custom id attribute value
  30. * if numeric value is passed it'll be just appended to the name e.g. {filed-name}-{value}
  31. * if false is passed id will be not created
  32. * if empty string is passed (or no 'id' option is found)
  33. * in all other cases the value will be used as field id
  34. * default: empty string
  35. *
  36. * - class => (string) field class(es)
  37. * Example: 'tbox select class1 class2 class3'
  38. * NOTE: this will override core classes, so you have to explicit include them!
  39. * default: empty string
  40. *
  41. * - size => (int) size attribute value (used when needed)
  42. * default: 40
  43. *
  44. * - title (string) title attribute
  45. * default: empty string (omitted)
  46. *
  47. * - readonly => (bool) readonly attribute
  48. * default: false
  49. *
  50. * - selected => (bool) selected attribute (used when needed)
  51. * default: false
  52. *
  53. * checked => (bool) checked attribute (used when needed)
  54. * default: false
  55. * - disabled => (bool) disabled attribute
  56. * default: false
  57. *
  58. * - tabindex => (int) tabindex attribute value
  59. * default: inner tabindex counter
  60. *
  61. * - other => (string) additional data
  62. * Example: 'attribute1="value1" attribute2="value2"'
  63. * default: empty string
  64. */
  65. class e_form
  66. {
  67. protected $_tabindex_counter = 0;
  68. protected $_tabindex_enabled = true;
  69. protected $_cached_attributes = array();
  70. /**
  71. * @var user_class
  72. */
  73. protected $_uc;
  74. protected $_required_string;
  75. function __construct($enable_tabindex = false)
  76. {
  77. $this->_tabindex_enabled = $enable_tabindex;
  78. $this->_uc = e107::getUserClass();
  79. $this->setRequiredString('<span class="required">*&nbsp;</span>');
  80. }
  81. /**
  82. * Open a new form
  83. * @param string name
  84. * @param $method - post|get default is post
  85. * @param @target - e_REQUEST_URI by default
  86. * @param $other - unused at the moment.
  87. */
  88. public function open($name, $method=null, $target=null, $options=null)
  89. {
  90. if($target == null)
  91. {
  92. $target = e_REQUEST_URI;
  93. }
  94. if($method == null)
  95. {
  96. $method = "post";
  97. }
  98. $class = "";
  99. $autoComplete = "";
  100. parse_str($options,$options);
  101. $target = str_replace("&", "&amp;", $target);
  102. if(vartrue($options['class']))
  103. {
  104. $class = "class='".$options['class']."'";
  105. }
  106. if(isset($options['autocomplete'])) // leave as isset()
  107. {
  108. $autoComplete = " autocomplete='".($options['autocomplete'] ? 'on' : 'off')."'";
  109. }
  110. $text = "\n<form {$class} action='{$target}' id='".$this->name2id($name)."' method = '{$method}'{$autoComplete}>\n";
  111. if($method == 'get' && strpos($target,'='))
  112. {
  113. list($url,$qry) = explode("?",$target);
  114. parse_str($qry,$m);
  115. foreach($m as $k=>$v)
  116. {
  117. $text .= $this->hidden($k, $v);
  118. }
  119. }
  120. return $text;
  121. }
  122. /**
  123. * Close a Form
  124. */
  125. public function close()
  126. {
  127. return "</form>";
  128. }
  129. /**
  130. * Get required field markup string
  131. * @return string
  132. */
  133. public function getRequiredString()
  134. {
  135. return $this->_required_string;
  136. }
  137. /**
  138. * Set required field markup string
  139. * @param string $string
  140. * @return e_form
  141. */
  142. public function setRequiredString($string)
  143. {
  144. $this->_required_string = $string;
  145. return $this;
  146. }
  147. // For Comma separated keyword tags.
  148. function tags($name, $value, $maxlength = 200, $options = array())
  149. {
  150. if(is_string($options)) parse_str($options, $options);
  151. $options['class'] = 'tbox span1 e-tags';
  152. $options['size'] = 7;
  153. return $this->text($name, $value, $maxlength, $options);
  154. }
  155. /**
  156. * Text-Field Form Element
  157. * @param $name
  158. * @param $value
  159. * @param $maxlength
  160. * @param $options
  161. * - size: mini, small, medium, large, xlarge, xxlarge
  162. * - class:
  163. * - typeahead: 'users'
  164. *
  165. */
  166. function text($name, $value = '', $maxlength = 80, $options= array())
  167. {
  168. if(is_string($options))
  169. {
  170. parse_str($options,$options);
  171. }
  172. if(!vartrue($options['class']))
  173. {
  174. $options['class'] = "tbox";
  175. }
  176. if(deftrue('BOOTSTRAP') === 3)
  177. {
  178. $options['class'] .= ' form-control';
  179. }
  180. /*
  181. if(!vartrue($options['class']))
  182. {
  183. if($maxlength < 10)
  184. {
  185. $options['class'] = 'tbox input-text span3';
  186. }
  187. elseif($maxlength < 50)
  188. {
  189. $options['class'] = 'tbox input-text span7';
  190. }
  191. elseif($maxlength > 99)
  192. {
  193. $options['class'] = 'tbox input-text span7';
  194. }
  195. else
  196. {
  197. $options['class'] = 'tbox input-text';
  198. }
  199. }
  200. */
  201. if(vartrue($options['typeahead']))
  202. {
  203. if(vartrue($options['typeahead']) == 'users')
  204. {
  205. $options['data-source'] = e_BASE."user.php";
  206. $options['class'] .= " e-typeahead";
  207. }
  208. }
  209. if(vartrue($options['size']) && !is_numeric($options['size']))
  210. {
  211. $options['class'] .= " input-".$options['size'];
  212. unset($options['size']); // don't include in html 'size='.
  213. }
  214. $mlength = vartrue($maxlength) ? "maxlength=".$maxlength : "";
  215. $options = $this->format_options('text', $name, $options);
  216. //never allow id in format name-value for text fields
  217. return "<input type='text' name='{$name}' value='{$value}' {$mlength} ".$this->get_attributes($options, $name)." />";
  218. }
  219. function number($name, $value, $maxlength = 200, $options = array())
  220. {
  221. if(is_string($options)) parse_str($options, $options);
  222. if (vartrue($options['maxlength'])) $maxlength = $options['maxlength'];
  223. unset($options['maxlength']);
  224. if(!vartrue($options['size'])) $options['size'] = 15;
  225. if(!vartrue($options['class'])) $options['class'] = 'tbox number e-spinner input-small';
  226. if(!$value) $value = '0';
  227. return $this->text($name, $value, $maxlength, $options);
  228. }
  229. function email($name, $value, $maxlength = 200, $options = array())
  230. {
  231. $options = $this->format_options('text', $name, $options);
  232. //never allow id in format name-value for text fields
  233. return "<input type='email' name='{$name}' value='{$value}' maxlength='{$maxlength}'".$this->get_attributes($options, $name)." />
  234. ";
  235. }
  236. function iconpreview($id, $default, $width='', $height='') // FIXME
  237. {
  238. // XXX - $name ?!
  239. $parms = $name."|".$width."|".$height."|".$id;
  240. $sc_parameters .= 'mode=preview&default='.$default.'&id='.$id;
  241. return e107::getParser()->parseTemplate("{ICONPICKER=".$sc_parameters."}");
  242. }
  243. /**
  244. * @param $name
  245. * @param $default value
  246. * @param $label
  247. * @param $options - gylphs=1
  248. * @param $ajax
  249. */
  250. function iconpicker($name, $default, $label, $options = array(), $ajax = true)
  251. {
  252. $options['media'] = '_icon';
  253. return $this->imagepicker($name, $default, $label, $options);
  254. }
  255. /**
  256. * Internal Function used by imagepicker and filepicker
  257. */
  258. private function mediaUrl($category = '', $label = '', $tagid='', $extras=null)
  259. {
  260. $cat = ($category) ? '&amp;for='.$category : "";
  261. if(!$label) $label = ' Upload an image or file';
  262. if($tagid) $cat .= '&amp;tagid='.$tagid;
  263. if(is_string($extras))
  264. {
  265. parse_str($extras,$extras);
  266. }
  267. if(vartrue($extras['bbcode'])) $cat .= '&amp;bbcode=1';
  268. $mode = vartrue($extras['mode'],'main');
  269. $action = vartrue($extras['action'],'dialog');
  270. // $tabs // TODO - option to choose which tabs to display.
  271. //TODO Parse selection data back to parent form.
  272. $url = e_ADMIN_ABS."image.php?mode={$mode}&amp;action={$action}".$cat;
  273. $url .= "&amp;iframe=1";
  274. if(vartrue($extras['w']))
  275. {
  276. $url .= "&amp;w=".$extras['w'];
  277. }
  278. if(vartrue($extras['glyphs']))
  279. {
  280. $url .= "&amp;glyphs=1";
  281. }
  282. if(vartrue($extras['video']))
  283. {
  284. $url .= "&amp;video=1";
  285. }
  286. $title = "Media Manager : ".$category;
  287. // $ret = "<a title=\"{$title}\" rel='external' class='e-dialog' href='".$url."'>".$label."</a>"; // using colorXXXbox.
  288. $ret = "<a title=\"{$title}\" class='e-modal' data-modal-caption='Media Manager' data-cache='false' data-target='#uiModal' href='".$url."'>".$label."</a>"; // using bootstrap.
  289. // $footer = "<div style=\'padding:5px;text-align:center\' <a href=\'#\' >Save</a></div>";
  290. $footer = '';
  291. if(!e107::getRegistry('core/form/mediaurl'))
  292. {
  293. /*
  294. e107::js('core','core/admin.js','prototype');
  295. e107::js('core','core/dialog.js','prototype');
  296. e107::js('core','core/draggable.js','prototype');
  297. e107::css('core','core/dialog/dialog.css','prototype');
  298. e107::css('core','core/dialog/e107/e107.css','prototype');
  299. e107::js('footer-inline','
  300. $$("a.e-dialog").invoke("observe", "click", function(ev) {
  301. var element = ev.findElement("a");
  302. ev.stop();
  303. new e107Widgets.URLDialog(element.href, {
  304. id: element["id"] || "e-dialog",
  305. width: 890,
  306. height: 680
  307. }).center().setHeader("Media Manager : '.$category.'").setFooter('.$footer.').activate().show();
  308. });
  309. ','prototype');
  310. */
  311. e107::setRegistry('core/form/mediaurl', true);
  312. }
  313. return $ret;
  314. }
  315. /**
  316. * Avatar Picker
  317. * @param $name - form element name ie. value to be posted.
  318. * @param $curVal - current avatar value. ie. the image-file name or URL.
  319. */
  320. function avatarpicker($name,$curVal='',$options=array())
  321. {
  322. $tp = e107::getParser();
  323. $pref = e107::getPref();
  324. $attr = "aw=".$pref['im_width']."&ah=".$pref['im_height'];
  325. $tp->setThumbSize($pref['im_width'],$pref['im_height']);
  326. $blankImg = $tp->thumbUrl(e_IMAGE."generic/blank_avatar.jpg",$attr);
  327. $localonly = true; //TODO add a pref for allowing external or internal avatars or both.
  328. $idinput = $this->name2id($name);
  329. $previnput = $idinput."-preview";
  330. $optioni = $idinput."-options";
  331. $path = (substr($curVal,0,8) == '-upload-') ? '{e_AVATAR}upload/' : '{e_AVATAR}default/';
  332. $curVal = str_replace('-upload-','',$curVal);
  333. $img = (strpos($curVal,"://")!==false) ? $curVal : $tp->thumbUrl($path.$curVal);
  334. if(!$curVal)
  335. {
  336. $img = $blankImg;
  337. }
  338. if($localonly == true)
  339. {
  340. $text = "<input class='tbox' style='width:80%' id='{$idinput}' type='hidden' name='image' size='40' value='{$curVal}' maxlength='100' />";
  341. $text .= "<img src='".$img."' id='{$previnput}' class='img-rounded e-expandit e-tip avatar' style='cursor:pointer; width:".$pref['im_width']."px; height:".$pref['im_height']."px' title='Click on the avatar to change it'/>"; // TODO LAN
  342. }
  343. else
  344. {
  345. $text = "<input class='tbox' style='width:80%' id='{$idinput}' type='text' name='image' size='40' value='$curVal' maxlength='100' title=\"".LAN_SIGNUP_111."\" />";
  346. $text .= "<img src='".$img."' id='{$previnput}' style='display:none' />";
  347. $text .= "<input class='img-rounded btn btn-default button e-expandit' type ='button' style='cursor:pointer' size='30' value=\"Choose Avatar\" />"; //TODO Common LAN.
  348. }
  349. $avFiles = e107::getFile()->get_files(e_AVATAR_DEFAULT,".jpg|.png|.gif|.jpeg|.JPG|.GIF|.PNG");
  350. $text .= "\n<div id='{$optioni}' style='display:none;padding:10px' >\n"; //TODO unique id.
  351. if (vartrue($pref['avatar_upload']) && FILE_UPLOADS && vartrue($options['upload']))
  352. {
  353. $diz = LAN_USET_32.($pref['im_width'] || $pref['im_height'] ? "\n".str_replace(array('--WIDTH--','--HEIGHT--'), array($pref['im_width'], $pref['im_height']), LAN_USER_86) : "");
  354. $text .= "<div style='margin-bottom:10px'>".LAN_USET_26."
  355. <input class='tbox' name='file_userfile[avatar]' type='file' size='47' title=\"{$diz}\" />
  356. </div>
  357. <div class='divider'><span>OR</span></div>";
  358. }
  359. foreach($avFiles as $fi)
  360. {
  361. $img_path = $tp->thumbUrl(e_AVATAR_DEFAULT.$fi['fname']);
  362. $text .= "\n<a class='e-expandit' title='Choose this avatar' href='#{$optioni}'><img src='".$img_path."' alt='' onclick=\"insertext('".$fi['fname']."', '".$idinput."');document.getElementById('".$previnput."').src = this.src;\" /></a> ";
  363. //TODO javascript CSS selector
  364. }
  365. $text .= "<br />
  366. </div>";
  367. // Used by usersettings.php right now.
  368. return $text;
  369. //TODO discuss and FIXME
  370. // Intentionally disable uploadable avatar and photos at this stage
  371. if (false && $pref['avatar_upload'] && FILE_UPLOADS)
  372. {
  373. $text .= "<br /><span class='smalltext'>".LAN_SIGNUP_25."</span> <input class='tbox' name='file_userfile[]' type='file' size='40' />
  374. <br /><div class='smalltext'>".LAN_SIGNUP_34."</div>";
  375. }
  376. if (false && $pref['photo_upload'] && FILE_UPLOADS)
  377. {
  378. $text .= "<br /><span class='smalltext'>".LAN_SIGNUP_26."</span> <input class='tbox' name='file_userfile[]' type='file' size='40' />
  379. <br /><div class='smalltext'>".LAN_SIGNUP_34."</div>";
  380. }
  381. }
  382. /**
  383. * FIXME {IMAGESELECTOR} rewrite
  384. * @param string $name input name
  385. * @param string $default default value
  386. * @param string $label custom label
  387. * @param string $sc_parameters shortcode parameters
  388. * --- SC Parameter list ---
  389. * - media: if present - load from media category table
  390. * - w: preview width in pixels
  391. * - h: preview height in pixels
  392. * - help: tooltip
  393. * - video: when set to true, will enable the Youtube (video) tab.
  394. * @example $frm->imagepicker('banner_image', $_POST['banner_image'], '', 'banner'); // all images from category 'banner_image' + common images.
  395. * @example $frm->imagepicker('banner_image', $_POST['banner_image'], '', 'media=banner&w=600');
  396. * @return string html output
  397. */
  398. function imagepicker($name, $default, $label = '', $sc_parameters = '')
  399. {
  400. $tp = e107::getParser();
  401. $name_id = $this->name2id($name);
  402. $meta_id = $name_id."-meta";
  403. if(is_string($sc_parameters))
  404. {
  405. if(strpos($sc_parameters, '=') === false) $sc_parameters = 'media='.$sc_parameters;
  406. parse_str($sc_parameters, $sc_parameters);
  407. }
  408. // print_a($sc_parameters);
  409. if(empty($sc_parameters['media']))
  410. {
  411. $sc_parameters['media'] = '_common';
  412. }
  413. $default_thumb = $default;
  414. if($default)
  415. {
  416. if($video = $tp->toVideo($default, array('thumb'=>'src')))
  417. {
  418. $default_url = $video;
  419. }
  420. else
  421. {
  422. if('{' != $default[0])
  423. {
  424. // convert to sc path
  425. $default_thumb = $tp->createConstants($default, 'nice');
  426. $default = $tp->createConstants($default, 'mix');
  427. }
  428. $default_url = $tp->replaceConstants($default, 'abs');
  429. }
  430. $blank = FALSE;
  431. }
  432. else
  433. {
  434. //$default = $default_url = e_IMAGE_ABS."generic/blank.gif";
  435. $default_url = e_IMAGE_ABS."generic/nomedia.png";
  436. $blank = TRUE;
  437. }
  438. //$width = intval(vartrue($sc_parameters['width'], 150));
  439. $cat = $tp->toDB(vartrue($sc_parameters['media']));
  440. if($cat == '_icon') // ICONS
  441. {
  442. $ret = "<div class='imgselector-container' style='display:block;width:64px;min-height:64px'>";
  443. $thpath = isset($sc_parameters['nothumb']) || vartrue($hide) ? $default : $default_thumb;
  444. $label = "<div id='{$name_id}_prev' class='text-center well well-small image-selector' >";
  445. $label .= $tp->toIcon($default_url);
  446. $label .= "
  447. </div>";
  448. // $label = "<img id='{$name_id}_prev' src='{$default_url}' alt='{$default_url}' class='well well-small image-selector' style='{$style}' />";
  449. }
  450. else // Images
  451. {
  452. $title = (vartrue($sc_parameters['help'])) ? "title='".$sc_parameters['help']."'" : "";
  453. $width = vartrue($sc_parameters['w'], 120);
  454. $height = vartrue($sc_parameters['h'], 100);
  455. $ret = "<div class='imgselector-container e-tip' {$title} style='margin-right:25px; display:inline-block; width:".$width."px;min-height:".$height."px;'>";
  456. $att = 'aw='.$width."'&ah=".$height."'";
  457. $thpath = isset($sc_parameters['nothumb']) || vartrue($hide) ? $default : $tp->thumbUrl($default_thumb, $att, true);
  458. $label = "<img id='{$name_id}_prev' src='{$default_url}' alt='{$default_url}' class='well well-small image-selector' style='display:block;' />";
  459. if($cat != 'news' && $cat !='page' && $cat !='')
  460. {
  461. $cat = $cat . "_image";
  462. }
  463. }
  464. $ret .= $this->mediaUrl($cat, $label,$name_id,$sc_parameters);
  465. $ret .= "</div>\n";
  466. $ret .= "<input type='hidden' name='{$name}' id='{$name_id}' value='{$default}' />";
  467. $ret .= "<input type='hidden' name='mediameta_{$name}' id='{$meta_id}' value='' />";
  468. // $ret .= $this->text($name,$default); // to be hidden eventually.
  469. return $ret;
  470. // ----------------
  471. }
  472. function filepicker($name, $default, $label = '', $sc_parameters = '')
  473. {
  474. $tp = e107::getParser();
  475. $name_id = $this->name2id($name);
  476. if(is_string($sc_parameters))
  477. {
  478. if(strpos($sc_parameters, '=') === false) $sc_parameters = 'media='.$sc_parameters;
  479. parse_str($sc_parameters, $sc_parameters);
  480. }
  481. $cat = vartrue($sc_parameters['media']) ? $tp->toDB($sc_parameters['media']) : "_common_file";
  482. $default_label = ($default) ? $default : "Choose a file";
  483. $label = "<span id='{$name_id}_prev' class='btn btn-default btn-small'>".basename($default_label)."</span>";
  484. $sc_parameters['mode'] = 'main';
  485. $sc_parameters['action'] = 'dialog';
  486. // $ret .= $this->mediaUrl($cat, $label,$name_id,"mode=dialog&action=list");
  487. $ret .= $this->mediaUrl($cat, $label,$name_id,$sc_parameters);
  488. $ret .= "<input type='hidden' name='{$name}' id='{$name_id}' value='{$default}' style='width:400px' />";
  489. return $ret;
  490. }
  491. /**
  492. * Date field with popup calendar // NEW in 0.8/2.0
  493. *
  494. * @param string $name the name of the field
  495. * @param integer $datestamp UNIX timestamp - default value of the field
  496. * @param array or str
  497. * @example $frm->datepicker('my_field',time(),'type=date');
  498. * @example $frm->datepicker('my_field',time(),'type=datetime&inline=1');
  499. * @example $frm->datepicker('my_field',time(),'type=date&format=yyyy-mm-dd');
  500. * @example $frm->datepicker('my_field',time(),'type=datetime&format=MM, dd, yyyy hh:ii');
  501. *
  502. * @url http://trentrichardson.com/examples/timepicker/
  503. */
  504. function datepicker($name, $datestamp = false, $options = null)
  505. {
  506. if(vartrue($options) && is_string($options))
  507. {
  508. parse_str($options,$options);
  509. }
  510. $type = varset($options['type']) ? trim($options['type']) : "date"; // OR 'datetime'
  511. $dateFormat = varset($options['format']) ? trim($options['format']) :e107::getPref('inputdate', '%Y-%m-%d');
  512. $ampm = (preg_match("/%l|%I|%p|%P/",$dateFormat)) ? 'true' : 'false';
  513. if($type == 'datetime' && !varset($options['format']))
  514. {
  515. $dateFormat .= " ".e107::getPref('inputtime', '%H:%M:%S');
  516. }
  517. $dformat = e107::getDate()->toMask($dateFormat);
  518. $id = $this->name2id($name);
  519. $classes = array('date' => 'e-date', 'datetime' => 'e-datetime');
  520. if ($datestamp)
  521. {
  522. $value = is_numeric($datestamp) ? e107::getDate()->convert_date($datestamp, $dateFormat) : $datestamp; //date("d/m/Y H:i:s", $datestamp);
  523. }
  524. $text = "";
  525. // $text .= 'dformat='.$dformat.' defdisp='.$dateFormat;
  526. $class = (isset($classes[$type])) ? $classes[$type] : "tbox e-date";
  527. $size = vartrue($options['size']) ? intval($options['size']) : 40;
  528. $required = vartrue($options['required']) ? "required" : "";
  529. $firstDay = vartrue($options['firstDay']) ? $options['firstDay'] : 0;
  530. if(vartrue($options['inline']))
  531. {
  532. $text .= "<div class='{$class}' id='inline-{$id}' data-date-format='{$dformat}' data-date-ampm='{$ampm}' data-date-firstday='{$firstDay}' ></div>
  533. <input type='hidden' name='{$name}' id='{$id}' value='{$value}' data-date-format='{$dformat}' data-time-format='{$tformat}' data-date-ampm='{$ampm}' data-date-firstday='{$firstDay}' />
  534. ";
  535. }
  536. else
  537. {
  538. $text .= "<input class='{$class} input-xlarge' type='text' size='{$size}' name='{$name}' id='{$id}' value='{$value}' data-date-format='{$dformat}' data-date-ampm='{$ampm}' data-date-language='".e_LAN."' data-date-firstday='{$firstDay}' {$required} />";
  539. }
  540. // $text .= "ValueFormat: ".$dateFormat." Value: ".$value;
  541. // $text .= " ({$dformat}) type:".$dateFormat." ".$value;
  542. return $text;
  543. }
  544. /**
  545. * User auto-complete search
  546. *
  547. * @param string $name_fld field name for user name
  548. * @param string $id_fld field name for user id
  549. * @param string $default_name default user name value
  550. * @param integer $default_id default user id
  551. * @param array|string $options [optional] 'readonly' (make field read only), 'name' (db field name, default user_name)
  552. * @return string HTML text for display
  553. */
  554. function userpicker($name_fld, $id_fld, $default_name, $default_id, $options = array())
  555. {
  556. $tp = e107::getParser();
  557. if(!is_array($options)) parse_str($options, $options);
  558. $default_name = vartrue($default_name, '');
  559. $default_id = vartrue($default_id, 0);
  560. //TODO Auto-calculate $name_fld from $id_fld ie. append "_usersearch" here ?
  561. $fldid = $this->name2id($name_fld);
  562. $hidden_fldid = $this->name2id($id_fld);
  563. $ret = '<div class="input-append">';
  564. $ret .= $this->text($name_fld,$default_name,20, "class=e-tip&title=Type name of user&typeahead=users&readonly=".vartrue($options['readonly']))
  565. .$this->hidden($id_fld,$default_id, array('id' => $this->name2id($id_fld)))."<span class='add-on'>".$tp->toGlyph('fa-user')." <span id='{$fldid}-id'>".$default_id.'</span></span>';
  566. $ret .= "<a class='btn btn-inverse' href='#' id='{$fldid}-reset'>reset</a>
  567. </div>";
  568. e107::js('footer-inline', "
  569. \$('#{$fldid}').blur(function () {
  570. \$('#{$fldid}-id').html(\$('#{$hidden_fldid}').val());
  571. });
  572. \$('#{$fldid}-reset').click(function () {
  573. \$('#{$fldid}-id').html('0');
  574. \$('#{$hidden_fldid}').val(0);
  575. \$('#{$fldid}').val('');
  576. return false;
  577. });
  578. ");
  579. return $ret;
  580. /*
  581. $label_fld = str_replace('_', '-', $name_fld).'-upicker-lable';
  582. //'.$this->text($id_fld, $default_id, 10, array('id' => false, 'readonly'=>true, 'class'=>'tbox number')).'
  583. $ret = '
  584. <div class="e-autocomplete-c">
  585. '.$this->text($name_fld, $default_name, 150, array('id' => false, 'readonly' => vartrue($options['readonly']) ? true : false)).'
  586. <span id="'.$label_fld.'" class="'.($default_id ? 'success' : 'warning').'">Id #'.((int) $default_id).'</span>
  587. '.$this->hidden($id_fld, $default_id, array('id' => false)).'
  588. <span class="indicator" style="display: none;">
  589. <img src="'.e_IMAGE_ABS.'generic/loading_16.gif" class="icon action S16" alt="Loading..." />
  590. </span>
  591. <div class="e-autocomplete"></div>
  592. </div>
  593. ';
  594. e107::getJs()->requireCoreLib('scriptaculous/controls.js', 2);
  595. e107::getJs()->footerInline("
  596. //autocomplete fields
  597. \$\$('input[name={$name_fld}]').each(function(el) {
  598. if(el.readOnly) {
  599. el.observe('click', function(ev) { ev.stop(); var el1 = ev.findElement('input'); el1.blur(); } );
  600. el.next('span.indicator').hide();
  601. el.next('div.e-autocomplete').hide();
  602. return;
  603. }
  604. new Ajax.Autocompleter(el, el.next('div.e-autocomplete'), '".e_JS."e_ajax.php', {
  605. paramName: '{$name_fld}',
  606. minChars: 2,
  607. frequency: 0.5,
  608. afterUpdateElement: function(txt, li) {
  609. if(!\$(li)) return;
  610. var elnext = el.next('input[name={$id_fld}]'),
  611. ellab = \$('{$label_fld}');
  612. if(\$(li).id) {
  613. elnext.value = parseInt(\$(li).id);
  614. } else {
  615. elnext.value = 0
  616. }
  617. if(ellab)
  618. {
  619. ellab.removeClassName('warning').removeClassName('success');
  620. ellab.addClassName((elnext.value ? 'success' : 'warning')).update('Id #' + elnext.value);
  621. }
  622. },
  623. indicator: el.next('span.indicator'),
  624. parameters: 'ajax_used=1&ajax_sc=usersearch=".rawurlencode('searchfld='.str_replace('user_', '', vartrue($options['name'], 'user_name')).'--srcfld='.$name_fld)."'
  625. });
  626. });
  627. ");
  628. return $ret;
  629. */
  630. }
  631. /**
  632. * A Rating element
  633. * @var $text
  634. */
  635. function rate($table,$id,$options=null)
  636. {
  637. $table = preg_replace('/\W/', '', $table);
  638. $id = intval($id);
  639. return e107::getRate()->render($table, $id, $options);
  640. }
  641. function like($table,$id,$options=null)
  642. {
  643. $table = preg_replace('/\W/', '', $table);
  644. $id = intval($id);
  645. return e107::getRate()->renderLike($table,$id,$options);
  646. }
  647. function file($name, $options = array())
  648. {
  649. $options = $this->format_options('file', $name, $options);
  650. //never allow id in format name-value for text fields
  651. return "<input type='file' name='{$name}'".$this->get_attributes($options, $name)." />";
  652. }
  653. function upload($name, $options = array())
  654. {
  655. return 'Ready to use upload form fields, optional - file list view';
  656. }
  657. function password($name, $value = '', $maxlength = 50, $options = array())
  658. {
  659. if(is_string($options)) parse_str($options, $options);
  660. $addon = "";
  661. $gen = "";
  662. if(vartrue($options['generate']))
  663. {
  664. $gen = '&nbsp;<a href="#" class="btn btn-default btn-small e-tip" id="Spn_PasswordGenerator" title="Generate a password">Generate</a> <a class="btn btn-default btn-small e-tip" href="#" id="showPwd" title="Display the password">Show</a><br />';
  665. }
  666. if(vartrue($options['strength']))
  667. {
  668. $addon .= "<div style='margin-top:4px'><div id='pwdColor' class='progress' style='float:left;display:inline-block;width:218px'><div class='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>";
  669. }
  670. $options['pattern'] = vartrue($options['pattern'],'[\S]{4,}');
  671. $options['required'] = varset($options['required'], 1);
  672. $options['class'] = vartrue($options['class'],'e-password');
  673. if(deftrue('BOOTSTRAP') == 3)
  674. {
  675. $options['class'] .= ' form-control';
  676. }
  677. $options = $this->format_options('text', $name, $options);
  678. //never allow id in format name-value for text fields
  679. $text = "<input type='password' name='{$name}' value='{$value}' maxlength='{$maxlength}'".$this->get_attributes($options, $name)." />";
  680. return "<span class='form-inline'>".$text.$gen."</span>".vartrue($addon);
  681. }
  682. /**
  683. * Render a bootStrap ProgressBar.
  684. * @param string $name
  685. * @param number $value
  686. * @param array $options
  687. */
  688. public function progressBar($name,$value,$options=array())
  689. {
  690. if(!deftrue('BOOTSTRAP'))
  691. {
  692. return;
  693. }
  694. $class = vartrue($options['class'],'');
  695. return "<div class='progress ".$class."' id='".$this->name2id($name)."'>
  696. <div class='bar' style='width: ".number_format($value,1)."%'></div>
  697. </div>";
  698. }
  699. /**
  700. * Textarea Element
  701. * @param $name
  702. * @param $value
  703. * @param $rows
  704. * @param $cols
  705. * @param $options
  706. * @param $count
  707. */
  708. function textarea($name, $value, $rows = 10, $cols = 80, $options = array(), $counter = false)
  709. {
  710. if(is_string($options)) parse_str($options, $options);
  711. // auto-height support
  712. if(vartrue($options['size']) && !is_numeric($options['size']))
  713. {
  714. $options['class'] .= " input-".$options['size'];
  715. unset($options['size']); // don't include in html 'size='.
  716. }
  717. elseif(!vartrue($options['noresize']))
  718. {
  719. $options['class'] = (isset($options['class']) && $options['class']) ? $options['class'].' e-autoheight' : 'tbox span7 e-autoheight';
  720. }
  721. $options = $this->format_options('textarea', $name, $options);
  722. //never allow id in format name-value for text fields
  723. return "<textarea name='{$name}' rows='{$rows}' cols='{$cols}'".$this->get_attributes($options, $name).">{$value}</textarea>".(false !== $counter ? $this->hidden('__'.$name.'autoheight_opt', $counter) : '');
  724. }
  725. /**
  726. * Bbcode Area. Name, value, template, media-Cat, size, options array eg. counter
  727. * IMPORTANT: $$mediaCat is also used is the media-manager category identifier
  728. */
  729. function bbarea($name, $value, $template = '', $mediaCat='_common', $size = 'large', $options = array())
  730. {
  731. if(is_string($options)) parse_str($options, $options);
  732. //size - large|medium|small
  733. //width should be explicit set by current admin theme
  734. $size = 'input-large';
  735. switch($size)
  736. {
  737. case 'small':
  738. $rows = '7';
  739. $height = "style='height:250px'"; // inline required for wysiwyg
  740. break;
  741. case 'medium':
  742. $rows = '10';
  743. $height = "style='height:375px'"; // inline required for wysiwyg
  744. $size = "input-block-level";
  745. break;
  746. case 'large':
  747. default:
  748. $rows = '15';
  749. $size = 'large input-block-level';
  750. // $height = "style='height:500px;width:1025px'"; // inline required for wysiwyg
  751. break;
  752. }
  753. // auto-height support
  754. $options['class'] = 'tbox bbarea '.($size ? ' '.$size : '').' e-wysiwyg e-autoheight';
  755. $bbbar = '';
  756. $help_tagid = $this->name2id($name)."--preview";
  757. $options['other'] = "onselect='storeCaret(this);' onclick='storeCaret(this);' onkeyup='storeCaret(this);' {$height}";
  758. $counter = vartrue($options['counter'],false);
  759. $ret = "
  760. <div class='bbarea {$size}'>
  761. <div class='field-spacer'><!-- --></div>\n";
  762. $ret .= e107::getBB()->renderButtons($template,$help_tagid);
  763. $ret .= $this->textarea($name, $value, $rows, 70, $options, $counter); // higher thank 70 will break some layouts.
  764. $ret .= "</div>\n";
  765. $_SESSION['media_category'] = $mediaCat; // used by TinyMce.
  766. return $ret;
  767. // Quick fix - hide TinyMCE links if not installed, dups are handled by JS handler
  768. /*
  769. e107::getJs()->footerInline("
  770. if(typeof tinyMCE === 'undefined')
  771. {
  772. \$$('a.e-wysiwyg-switch').invoke('hide');
  773. }
  774. ");
  775. */
  776. }
  777. /**
  778. * Render a checkbox
  779. * @param string $name
  780. * @param mixed $value
  781. * @param boolean $checked
  782. * @param mixed $options query-string or array or string for a label. eg. label=Hello&foo=bar or array('label'=>Hello') or 'Hello'
  783. * @return void
  784. */
  785. function checkbox($name, $value, $checked = false, $options = array())
  786. {
  787. if(!is_array($options))
  788. {
  789. if(strpos($options,"=")!==false)
  790. {
  791. parse_str($options, $options);
  792. }
  793. else // Assume it's a label.
  794. {
  795. $options = array('label'=>$options);
  796. }
  797. }
  798. $options = $this->format_options('checkbox', $name, $options);
  799. $options['checked'] = $checked; //comes as separate argument just for convenience
  800. $text = "";
  801. $pre = (vartrue($options['label'])) ? "<label class='checkbox'>" : ""; // Bootstrap compatible markup
  802. $post = (vartrue($options['label'])) ? $options['label']."</label>" : "";
  803. unset($options['label']); // not to be used as attribute;
  804. $text .= "<input type='checkbox' name='{$name}' value='{$value}'".$this->get_attributes($options, $name, $value)." />";
  805. return $pre.$text.$post;
  806. }
  807. function checkbox_label($label_title, $name, $value, $checked = false, $options = array())
  808. {
  809. return $this->checkbox($name, $value, $checked, $options).$this->label($label_title, $name, $value);
  810. }
  811. function checkbox_switch($name, $value, $checked = false, $label = '')
  812. {
  813. return $this->checkbox($name, $value, $checked).$this->label($label ? $label : LAN_ENABLED, $name, $value);
  814. }
  815. function checkbox_toggle($name, $selector = 'multitoggle', $id = false, $label='')
  816. {
  817. $selector = 'jstarget:'.$selector;
  818. if($id) $id = $this->name2id($id);
  819. return $this->checkbox($name, $selector, false, array('id' => $id,'class' => 'checkbox toggle-all','label'=>$label));
  820. }
  821. function uc_checkbox($name, $current_value, $uc_options, $field_options = array())
  822. {
  823. if(!is_array($field_options)) parse_str($field_options, $field_options);
  824. return '
  825. <div class="check-block">
  826. '.$this->_uc->vetted_tree($name, array($this, '_uc_checkbox_cb'), $current_value, $uc_options, $field_options).'
  827. </div>
  828. ';
  829. }
  830. /**
  831. * Callback function used with $this->uc_checkbox
  832. *
  833. * @see user_class->select() for parameters
  834. */
  835. function _uc_checkbox_cb($treename, $classnum, $current_value, $nest_level, $field_options)
  836. {
  837. if($classnum == e_UC_BLANK)
  838. return '';
  839. if (!is_array($current_value))
  840. {
  841. $tmp = explode(',', $current_value);
  842. }
  843. $classIndex = abs($classnum); // Handle negative class values
  844. $classSign = (substr($classnum, 0, 1) == '-') ? '-' : '';
  845. $class = $style = '';
  846. if($nest_level == 0)
  847. {
  848. $class = " strong";
  849. }
  850. else
  851. {
  852. $style = " style='text-indent:" . (1.2 * $nest_level) . "em'";
  853. }
  854. $descr = varset($field_options['description']) ? ' <span class="smalltext">('.$this->_uc->uc_get_classdescription($classnum).')</span>' : '';
  855. 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";
  856. }
  857. function uc_label($classnum)
  858. {
  859. return $this->_uc->uc_get_classname($classnum);
  860. }
  861. /**
  862. * A Radio Button Form Element
  863. * @param $name
  864. * @param @value array pair-values|string - auto-detected.
  865. * @param $checked boolean
  866. * @param $options
  867. */
  868. function radio($name, $value, $checked = false, $options = null)
  869. {
  870. if(!is_array($options)) parse_str($options, $options);
  871. if(is_array($value))
  872. {
  873. return $this->radio_multi($name, $value, $checked, $options);
  874. }
  875. $labelFound = vartrue($options['label']);
  876. unset($options['label']); // label attribute not valid in html5
  877. $options = $this->format_options('radio', $name, $options);
  878. $options['checked'] = $checked; //comes as separate argument just for convenience
  879. // $options['class'] = 'inline';
  880. $text = "";
  881. // return print_a($options,true);
  882. if($labelFound) // Bootstrap compatible markup
  883. {
  884. $text .= "<label class='radio inline'>";
  885. }
  886. $text .= "<input type='radio' name='{$name}' value='".$value."'".$this->get_attributes($options, $name, $value)." />";
  887. if(vartrue($options['help']))
  888. {
  889. $text .= "<div class='field-help'>".$options['help']."</div>";
  890. }
  891. if($labelFound)
  892. {
  893. $text .= $labelFound."</label>";
  894. }
  895. return $text;
  896. }
  897. /**
  898. * @param name
  899. * @param check_enabled
  900. * @param label_enabled
  901. * @param label_disabled
  902. * @param options
  903. */
  904. function radio_switch($name, $checked_enabled = false, $label_enabled = '', $label_disabled = '',$options=array())
  905. {
  906. if(!is_array($options)) parse_str($options, $options);
  907. $options_on = varset($options['enabled'],array());
  908. $options_off = varset($options['disabled'],array());
  909. if(vartrue($options['class']) == 'e-expandit' || vartrue($options['expandit'])) // See admin->prefs 'Single Login' for an example.
  910. {
  911. $options_on = array_merge($options, array('class' => 'e-expandit-on'));
  912. $options_off = array_merge($options, array('class' => 'e-expandit-off'));
  913. }
  914. $options_on['label'] = $label_enabled ? defset($label_enabled,$label_enabled) : LAN_ENABLED;
  915. $options_off['label'] = $label_disabled ? defset($label_disabled,$label_disabled) : LAN_DISABLED;
  916. if(vartrue($options['reverse'])) // reverse order.
  917. {
  918. unset($options['reverse']);
  919. return $this->radio($name, 0, !$checked_enabled, $options_off)." ".
  920. $this->radio($name, 1, $checked_enabled, $options_on);
  921. // return $this->radio($name, 0, !$checked_enabled, $options_off)."".$this->label($label_disabled ? $label_disabled : LAN_DISABLED, $name, 0)."&nbsp;&nbsp;".
  922. // $this->radio($name, 1, $checked_enabled, $options_on)."".$this->label($label_enabled ? $label_enabled : LAN_ENABLED, $name, 1);
  923. }
  924. // $helpLabel = (is_array($help)) ? vartrue($help[$value]) : $help;
  925. // Bootstrap Style Code - for use later.
  926. // ['help'] = $helpLabel;
  927. // $text[] = $this->radio($name, $value, (string) $checked === (string) $value, $options);
  928. return $this->radio($name, 1, $checked_enabled, $options_on)." ".$this->radio($name, 0, !$checked_enabled, $options_off);
  929. // return $this->radio($name, 1, $checked_enabled, $options_on)."".$this->label($label_enabled ? $label_enabled : LAN_ENABLED, $name, 1)."&nbsp;&nbsp;
  930. // ".$this->radio($name, 0, !$checked_enabled, $options_off)."".$this->label($label_disabled ? $label_disabled : LAN_DISABLED, $name, 0);
  931. }
  932. /**
  933. * XXX INTERNAL ONLY - Use radio() instead. array will automatically trigger this internal method.
  934. * @param string $name
  935. * @param array $elements = arrays value => label
  936. * @param string/integer $checked = current value
  937. * @param boolean $multi_line
  938. * @param mixed $help array of field help items or string of field-help (to show on all)
  939. */
  940. private function radio_multi($name, $elements, $checked, $options=array(), $help = null)
  941. {
  942. /* // Bootstrap Test.
  943. return' <label class="checkbox">
  944. <input type="checkbox" value="">
  945. Option one is this and that—be sure to include why its great
  946. </label>
  947. <label class="radio">
  948. <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
  949. Option one is this and that—be sure to include why its great
  950. </label>
  951. <label class="radio">
  952. <input type="radio" name="optionsRadios" id="optionsRadios2" value="option2">
  953. Option two can be something else and selecting it will deselect option one
  954. </label>';
  955. */
  956. $text = array();
  957. if(is_string($elements)) parse_str($elements, $elements);
  958. if(!is_array($options)) parse_str($options, $options);
  959. $help = '';
  960. if(vartrue($options['help']))
  961. {
  962. $help = "<div class='field-help'>".$options['help']."</div>";
  963. unset($options['help']);
  964. }
  965. foreach ($elements as $value => $label)
  966. {
  967. $label = defset($label, $label);
  968. $helpLabel = (is_array($help)) ? vartrue($help[$value]) : $help;
  969. // Bootstrap Style Code - for use later.
  970. $options['label'] = $label;
  971. $options['help'] = $helpLabel;
  972. $text[] = $this->radio($name, $value, (string) $checked === (string) $value, $options);
  973. // $text[] = $this->radio($name, $value, (string) $checked === (string) $value)."".$this->label($label, $name, $value).(isset($helpLabel) ? "<div class='field-help'>".$helpLabel."</div>" : '');
  974. }
  975. if($multi_line === false)
  976. {
  977. // return implode("&nbsp;&nbsp;", $text);
  978. }
  979. // support of UI owned 'newline' parameter
  980. if(!varset($options['sep']) && vartrue($options['newline'])) $options['sep'] = '<br />'; // TODO div class=separator?
  981. $separator = varset($options['sep']," ");
  982. // return print_a($text,true);
  983. return implode($separator, $text).$help;
  984. // return implode("\n", $text);
  985. //XXX Limiting markup.
  986. // return "<div class='field-spacer' style='width:50%;float:left'>".implode("</div><div class='field-spacer' style='width:50%;float:left'>", $text)."</div>";
  987. }
  988. /**
  989. * Just for BC - use the $options['label'] instead.
  990. */
  991. function label($text, $name = '', $value = '')
  992. {
  993. e107::getMessage()->addDebug("Deprecated \$frm->label() used");
  994. $for_id = $this->_format_id('', $name, $value, 'for');
  995. return "<label$for_id class='e-tip legacy'>{$text}</label>";
  996. }
  997. function help($text)
  998. {
  999. return !empty($text) ? '<div class="field-help">'.$text.'</div>' : '';
  1000. }
  1001. function select_open($name, $options = array())
  1002. {
  1003. $options = $this->format_options('select', $name, $options);
  1004. return "<select name='{$name}'".$this->get_attributes($options, $name).">";
  1005. }
  1006. /**
  1007. * @DEPRECATED - use select() instead.
  1008. */
  1009. function selectbox($name, $option_array, $selected = false, $options = array(), $defaultBlank= false)
  1010. {
  1011. return $this->select($name, $option_array, $selected, $options, $defaultBlank);
  1012. }
  1013. /**
  1014. *
  1015. * @param string $name
  1016. * @param array $option_array
  1017. * @param boolean $selected [optional]
  1018. * @param string|array $options [optional]
  1019. * @param boolean|string $defaultBlank [optional] set to TRUE if the first entry should be blank, or to a string to use it for the blank description.
  1020. * @return string HTML text for display
  1021. */
  1022. function select($name, $option_array, $selected = false, $options = array(), $defaultBlank= false)
  1023. {
  1024. if(!is_array($options)) parse_str($options, $options);
  1025. if($option_array === 'yesno')
  1026. {
  1027. $option_array = array(1 => LAN_YES, 0 => LAN_NO);
  1028. }
  1029. if(vartrue($options['multiple']))
  1030. {
  1031. $name = (strpos($name, '[') === false) ? $name.'[]' : $name;
  1032. if(!is_array($selected)) $selected = explode(",",$selected);
  1033. }
  1034. $text = $this->select_open($name, $options)."\n";
  1035. if(isset($options['default']))
  1036. {
  1037. $text .= $this->option($options['default'], varset($options['defaultValue']));
  1038. }
  1039. elseif($defaultBlank)
  1040. {
  1041. $diz = is_string($defaultBlank) ? $defaultBlank : '&nbsp;';
  1042. $text .= $this->option($diz, '');
  1043. }
  1044. if(varset($options['useValues'])) // use values as keys.
  1045. {
  1046. $new = array();
  1047. foreach($option_array as $v)
  1048. {
  1049. $new[$v] = $v;
  1050. }
  1051. $option_array = $new;
  1052. }
  1053. $text .= $this->option_multi($option_array, $selected)."\n".$this->select_close();
  1054. return $text;
  1055. }
  1056. //TODO
  1057. /**
  1058. * Universal Userclass selector - checkboxes, dropdown, everything.
  1059. * @param $name - form element name
  1060. * @param $curval - current userclass value(s) as array or comma separated.
  1061. * @param $type - 'checkbox', 'dropdown',
  1062. * @param options - query string or array. 'options=admin,mainadmin,classes&vetted=1&exclusions=0' etc.
  1063. * @return the userclass form element
  1064. */
  1065. function userclass($name, $curval, $type, $options)
  1066. {
  1067. }
  1068. /**
  1069. * Renders a generic search box. If $filter has values, a filter box will be included with the options provided.
  1070. *
  1071. */
  1072. function search($name, $searchVal, $submitName, $filterName='', $filterArray=false, $filterVal=false)
  1073. {
  1074. $tp = e107::getParser();
  1075. $text = '<span class="input-append e-search">'.$tp->toGlyph('fa-search').'
  1076. '.$this->text($name, $searchVal,20,'class=search-query').'
  1077. <button class="btn btn-primary" name="'.$submitName.'" type="submit">'.LAN_GO.'</button>
  1078. </span>';
  1079. if(is_array($filter))
  1080. {
  1081. $text .= $this->selectbox($$filterName, $filterArray, $filterVal);
  1082. }
  1083. // $text .= $this->admin_button($submitName,LAN_SEARCH,'search');
  1084. return $text;
  1085. /*
  1086. $text .=
  1087. <select style="display: none;" data-original-title="Filter the results below" name="filter_options" id="filter-options" class="e-tip tbox select filter" title="">
  1088. <option value="">Display All</option>
  1089. <option value="___reset___">Clear Filter</option>
  1090. <optgroup class="optgroup" label="Filter by&nbsp;Category">
  1091. <option value="faq_parent__1">General</option>
  1092. <option value="faq_parent__2">Misc</option>
  1093. <option value="faq_parent__4">Test 3</option>
  1094. </optgroup>
  1095. </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>&nbsp;<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&nbsp;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>
  1096. <div class="e-autocomplete"></div>
  1097. <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>
  1098. <span class="indicator" style="display: none;">
  1099. <img src="/e107_2.0/e107_images/generic/loading_16.gif" class="icon action S16" alt="Loading...">
  1100. </span>
  1101. */
  1102. }
  1103. function uc_select($name, $current_value, $uc_options, $select_options = array(), $opt_options = array())
  1104. {
  1105. return $this->select_open($name, $select_options)."\n".$this->_uc->vetted_tree($name, array($this, '_uc_select_cb'), $current_value, $uc_options, $opt_options)."\n".$this->select_close();
  1106. }
  1107. // Callback for vetted_tree - Creates the option list for a selection box
  1108. function _uc_select_cb($treename, $classnum, $current_value, $nest_level)
  1109. {
  1110. $classIndex = abs($classnum); // Handle negative class values
  1111. $classSign = (substr($classnum, 0, 1) == '-') ? '-' : '';
  1112. if($classnum == e_UC_BLANK)
  1113. return $this->option('&nbsp;', '');
  1114. $tmp = explode(',', $current_value);
  1115. if($nest_level == 0)
  1116. {
  1117. $prefix = '';
  1118. $style = "font-weight:bold; font-style: italic;";
  1119. }
  1120. elseif($nest_level == 1)
  1121. {
  1122. $prefix = '&nbsp;&nbsp;';
  1123. $style = "font-weight:bold";
  1124. }
  1125. else
  1126. {
  1127. $prefix = '&nbsp;&nbsp;'.str_repeat('--', $nest_level - 1).'&gt;';
  1128. $style = '';
  1129. }
  1130. return $this->option($prefix.$this->_uc->uc_get_classname($classnum), $classSign.$classIndex, ($current_value !== '' && in_array($classnum, $tmp)), array("style"=>"{$style}"))."\n";
  1131. }
  1132. function optgroup_open($label, $disabled = false)
  1133. {
  1134. return "<optgroup class='optgroup' label='{$label}'".($disabled ? " disabled='disabled'" : '').">";
  1135. }
  1136. /**
  1137. * <option> tag generation.
  1138. * @param $option_title
  1139. * @param $value
  1140. * @param $selected
  1141. * @param $options (eg. disabled=1)
  1142. */
  1143. function option($option_title, $value, $selected = false, $options = '')
  1144. {
  1145. if(is_string($options)) parse_str($options, $options);
  1146. if(false === $value) $value = '';
  1147. $options = $this->format_options('option', '', $options);
  1148. $options['selected'] = $selected; //comes as separate argument just for convenience
  1149. return "<option value='{$value}'".$this->get_attributes($options).">".defset($option_title, $option_title)."</option>";
  1150. }
  1151. /**
  1152. * Use selectbox() instead.
  1153. */
  1154. function option_multi($option_array, $selected = false, $options = array())
  1155. {
  1156. if(is_string($option_array)) parse_str($option_array, $option_array);
  1157. $text = '';
  1158. foreach ($option_array as $value => $label)
  1159. {
  1160. if(is_array($label))
  1161. {
  1162. $text .= $this->optgroup_open($value);
  1163. foreach($label as $val => $lab)
  1164. {
  1165. $text .= $this->option($lab, $val, (is_array($selected) ? in_array($val, $selected) : $selected == $val), $options)."\n";
  1166. }
  1167. $text .= $this->optgroup_close();
  1168. }
  1169. else
  1170. {
  1171. $text .= $this->option($label, $value, (is_array($selected) ? in_array($value, $selected) : $selected == $value), $options)."\n";
  1172. }
  1173. }
  1174. return $text;
  1175. }
  1176. function optgroup_close()
  1177. {
  1178. return "</optgroup>";
  1179. }
  1180. function select_close()
  1181. {
  1182. return "</select>";
  1183. }
  1184. function hidden($name, $value, $options = array())
  1185. {
  1186. $options = $this->format_options('hidden', $name, $options);
  1187. return "<input type='hidden' name='{$name}' value='{$value}'".$this->get_attributes($options, $name, $value)." />";
  1188. }
  1189. /**
  1190. * Generate hidden security field
  1191. * @return string
  1192. */
  1193. function token()
  1194. {
  1195. return "<input type='hidden' name='e-token' value='".defset('e_TOKEN', '')."' />";
  1196. }
  1197. function submit($name, $value, $options = array())
  1198. {
  1199. $options = $this->format_options('submit', $name, $options);
  1200. return "<input type='submit' name='{$name}' value='{$value}'".$this->get_attributes($options, $name, $value)." />";
  1201. }
  1202. function submit_image($name, $value, $image, $title='', $options = array())
  1203. {
  1204. $tp = e107::getParser();
  1205. $options = $this->format_options('submit_image', $name, $options);
  1206. switch ($image)
  1207. {
  1208. case 'edit':
  1209. $icon = "e-edit-32";
  1210. $options['class'] = $options['class'] == 'action' ? 'btn btn-default action edit' : $options['class'];
  1211. break;
  1212. case 'delete':
  1213. $icon = "e-delete-32";
  1214. $options['class'] = $options['class'] == 'action' ? 'btn btn-default action delete' : $options['class'];
  1215. $options['other'] = 'data-confirm="'.LAN_JSCONFIRM.'"';
  1216. break;
  1217. case 'execute':
  1218. $icon = "e-execute-32";
  1219. $options['class'] = $options['class'] == 'action' ? 'btn btn-default action execute' : $options['class'];
  1220. break;
  1221. case 'view':
  1222. $icon = "e-view-32";
  1223. $options['class'] = $options['class'] == 'action' ? 'btn btn-default action view' : $options['class'];
  1224. break;
  1225. }
  1226. $options['title'] = $title;//shorthand
  1227. return "<button type='submit' name='{$name}' data-placement='left' value='{$value}'".$this->get_attributes($options, $name, $value)." >".$tp->toIcon($icon)."</button>";
  1228. }
  1229. /**
  1230. * Alias of admin_button, adds the etrigger_ prefix required for UI triggers
  1231. * @see e_form::admin_button()
  1232. */
  1233. function admin_trigger($name, $value, $action = 'submit', $label = '', $options = array())
  1234. {
  1235. return $this->admin_button('etrigger_'.$name, $value, $action, $label, $options);
  1236. }
  1237. /**
  1238. * Generic Button Element.
  1239. * @param string $name
  1240. * @param string $value
  1241. * @param string $action [optional] default is submit - use 'dropdown' for a bootstrap dropdown button.
  1242. * @param string $label [optional]
  1243. * @param string|array $options [optional]
  1244. * @return string
  1245. */
  1246. public function button($name, $value, $action = 'submit', $label = '', $options = array())
  1247. {
  1248. if(deftrue('BOOTSTRAP') && $action == 'dropdown' && is_array($value))
  1249. {
  1250. // $options = $this->format_options('admin_button', $name, $options);
  1251. $options['class'] = vartrue($options['class']);
  1252. $align = vartrue($options['align'],'left');
  1253. $text = '<div class="btn-group pull-'.$align.'">
  1254. <a class="btn dropdown-toggle '.$options['class'].'" data-toggle="dropdown" href="#">
  1255. '.($label ? $label : 'No Label Provided').'
  1256. <span class="caret"></span>
  1257. </a>
  1258. <ul class="dropdown-menu">
  1259. ';
  1260. foreach($value as $k=>$v)
  1261. {
  1262. $text .= '<li>'.$v.'</li>';
  1263. }
  1264. $text .= '
  1265. </ul>
  1266. </div>';
  1267. return $text;
  1268. }
  1269. return $this->admin_button($name, $value, $action, $label, $options);
  1270. }
  1271. /**
  1272. * Render a Breadcrumb in Bootstrap format.
  1273. * @param $array
  1274. */
  1275. function breadcrumb($array)
  1276. {
  1277. if(!is_array($array)){ return; }
  1278. $opt = array();
  1279. $homeIcon = e107::getParser()->toGlyph('icon-home.glyph',false);
  1280. $opt[] = "<a href='".e_HTTP."'>".$homeIcon."</a>"; // Add Site-Pref to disable?
  1281. $text = '<ul class="breadcrumb">
  1282. <li>';
  1283. foreach($array as $val)
  1284. {
  1285. $ret = "";
  1286. $ret .= vartrue($val['url']) ? "<a href='".$val['url']."'>" : "";
  1287. $ret .= vartrue($val['text'],'');
  1288. $ret .= vartrue($val['url']) ? "</a>" : "";
  1289. if($ret != '')
  1290. {
  1291. $opt[] = $ret;
  1292. }
  1293. }
  1294. $sep = (deftrue('BOOTSTRAP') === 3) ? "" : "<span class='divider'>/</span>";
  1295. $text .= implode($sep."</li><li>",$opt);
  1296. $text .= "</li></ul>";
  1297. // return print_a($opt,true);
  1298. return $text;
  1299. }
  1300. /**
  1301. * Admin Button - for front-end, use button();
  1302. * @param string $name
  1303. * @param string $value
  1304. * @param string $action [optional] default is submit
  1305. * @param string $label [optional]
  1306. * @param string|array $options [optional]
  1307. * @return string
  1308. */
  1309. function admin_button($name, $value, $action = 'submit', $label = '', $options = array())
  1310. {
  1311. $btype = 'submit';
  1312. if(strpos($action, 'action') === 0) $btype = 'button';
  1313. $options = $this->format_options('admin_button', $name, $options);
  1314. $options['class'] = vartrue($options['class']);
  1315. $options['class'] .= ' btn '.$action.' ';//shorthand
  1316. if(empty($label)) $label = $value;
  1317. switch ($action)
  1318. {
  1319. case 'update':
  1320. case 'create':
  1321. case 'import':
  1322. case 'submit':
  1323. $options['class'] .= 'btn-success';
  1324. break;
  1325. case 'checkall':
  1326. $options['class'] .= 'btn-mini';
  1327. break;
  1328. case 'cancel':
  1329. // use this for neutral colors.
  1330. break;
  1331. case 'delete':
  1332. $options['class'] .= 'btn-danger';
  1333. $options['other'] = 'data-confirm="'.LAN_JSCONFIRM.'"';
  1334. break;
  1335. case 'execute':
  1336. $options['class'] .= 'btn-success';
  1337. break;
  1338. case 'other':
  1339. case 'login':
  1340. $options['class'] .= 'btn-primary';
  1341. break;
  1342. case 'warning':
  1343. case 'confirm':
  1344. $options['class'] .= 'btn-warning';
  1345. break;
  1346. case 'batch':
  1347. case 'batch e-hide-if-js': // FIXME hide-js shouldn't be here.
  1348. $options['class'] .= 'btn-primary';
  1349. break;
  1350. case 'filter':
  1351. case 'filter e-hide-if-js': // FIXME hide-js shouldn't be here.
  1352. $options['class'] .= 'btn-primary';
  1353. break;
  1354. default:
  1355. $options['class'] .= 'btn-default';
  1356. break;
  1357. }
  1358. return "
  1359. <button type='{$btype}' name='{$name}' value='{$value}'".$this->get_attributes($options, $name)."><span>{$label}</span></button>
  1360. ";
  1361. }
  1362. function getNext()
  1363. {
  1364. if(!$this->_tabindex_enabled) return 0;
  1365. $this->_tabindex_counter += 1;
  1366. return $this->_tabindex_counter;
  1367. }
  1368. function getCurrent()
  1369. {
  1370. if(!$this->_tabindex_enabled) return 0;
  1371. return $this->_tabindex_counter;
  1372. }
  1373. function resetTabindex($reset = 0)
  1374. {
  1375. $this->_tabindex_counter = $reset;
  1376. }
  1377. function get_attributes($options, $name = '', $value = '')
  1378. {
  1379. $ret = '';
  1380. //
  1381. foreach ($options as $option => $optval)
  1382. {
  1383. $optval = trim($optval);
  1384. switch ($option)
  1385. {
  1386. case 'id':
  1387. $ret .= $this->_format_id($optval, $name, $value);
  1388. break;
  1389. case 'class':
  1390. if(!empty($optval)) $ret .= " class='{$optval}'";
  1391. break;
  1392. case 'size':
  1393. if($optval) $ret .= " size='{$optval}'";
  1394. break;
  1395. case 'title':
  1396. if($optval) $ret .= " title='{$optval}'";
  1397. break;
  1398. case 'label':
  1399. if($optval) $ret .= " label='{$optval}'";
  1400. break;
  1401. case 'tabindex':
  1402. if($optval) $ret .= " tabindex='{$optval}'";
  1403. elseif(false === $optval || !$this->_tabindex_enabled) break;
  1404. else
  1405. {
  1406. $this->_tabindex_counter += 1;
  1407. $ret .= " tabindex='".$this->_tabindex_counter."'";
  1408. }
  1409. break;
  1410. case 'readonly':
  1411. if($optval) $ret .= " readonly='readonly'";
  1412. break;
  1413. case 'multiple':
  1414. if($optval) $ret .= " multiple='multiple'";
  1415. break;
  1416. case 'selected':
  1417. if($optval) $ret .= " selected='selected'";
  1418. break;
  1419. case 'checked':
  1420. if($optval) $ret .= " checked='checked'";
  1421. break;
  1422. case 'disabled':
  1423. if($optval) $ret .= " disabled='disabled'";
  1424. break;
  1425. case 'required':
  1426. if($optval) $ret .= " required='required'";
  1427. break;
  1428. case 'autofocus':
  1429. if($optval) $ret .= " autofocus='autofocus'";
  1430. break;
  1431. case 'placeholder':
  1432. if($optval) $ret .= " placeholder='{$optval}'";
  1433. break;
  1434. case 'autocomplete':
  1435. if($optval) $ret .= " autocomplete='{$optval}'";
  1436. break;
  1437. case 'pattern':
  1438. if($optval) $ret .= " pattern='{$optval}'";
  1439. break;
  1440. case 'other':
  1441. if($optval) $ret .= " $optval";
  1442. break;
  1443. }
  1444. if(substr($option,0,5) =='data-')
  1445. {
  1446. $ret .= " ".$option."='{$optval}'";
  1447. }
  1448. }
  1449. return $ret;
  1450. }
  1451. /**
  1452. * Auto-build field attribute id
  1453. *
  1454. * @param string $id_value value for attribute id passed with the option array
  1455. * @param string $name the name attribute passed to that field
  1456. * @param unknown_type $value the value attribute passed to that field
  1457. * @return string formatted id attribute
  1458. */
  1459. function _format_id($id_value, $name, $value = '', $return_attribute = 'id')
  1460. {
  1461. if($id_value === false) return '';
  1462. //format data first
  1463. $name = trim($this->name2id($name), '-');
  1464. $value = trim(preg_replace('#[^a-zA-Z0-9\-]#','-', $value), '-');
  1465. //$value = trim(preg_replace('#[^a-z0-9\-]#/i','-', $value), '-'); // This should work - but didn't for me!
  1466. $value = trim(str_replace("/","-",$value), '-'); // Why?
  1467. if(!$id_value && is_numeric($value)) $id_value = $value;
  1468. // clean - do it better, this could lead to dups
  1469. $id_value = trim($id_value, '-');
  1470. if(empty($id_value) ) return " {$return_attribute}='{$name}".($value ? "-{$value}" : '')."'";// also useful when name is e.g. name='my_name[some_id]'
  1471. elseif(is_numeric($id_value) && $name) return " {$return_attribute}='{$name}-{$id_value}'";// also useful when name is e.g. name='my_name[]'
  1472. else return " {$return_attribute}='{$id_value}'";
  1473. }
  1474. function name2id($name)
  1475. {
  1476. $name = strtolower($name);
  1477. return rtrim(str_replace(array('[]', '[', ']', '_', '/', ' ','.'), array('-', '-', '', '-', '-', '-', '-'), $name), '-');
  1478. }
  1479. /**
  1480. * Format options based on the field type,
  1481. * merge with default
  1482. *
  1483. * @param string $type
  1484. * @param string $name form name attribute value
  1485. * @param array|string $user_options
  1486. * @return array merged options
  1487. */
  1488. function format_options($type, $name, $user_options=null)
  1489. {
  1490. if(is_string($user_options))
  1491. {
  1492. parse_str($user_options, $user_options);
  1493. }
  1494. $def_options = $this->_default_options($type);
  1495. if(is_array($user_options))
  1496. {
  1497. $user_options['name'] = $name; //required for some of the automated tasks
  1498. foreach (array_keys($user_options) as $key)
  1499. {
  1500. if(!isset($def_options[$key]) && substr($key,0,5)!='data-') unset($user_options[$key]); // data-xxxx exempt //remove it?
  1501. }
  1502. }
  1503. else
  1504. {
  1505. $user_options = array('name' => $name); //required for some of the automated tasks
  1506. }
  1507. return array_merge($def_options, $user_options);
  1508. }
  1509. /**
  1510. * Get default options array based on the field type
  1511. *
  1512. * @param string $type
  1513. * @return array default options
  1514. */
  1515. function _default_options($type)
  1516. {
  1517. if(isset($this->_cached_attributes[$type])) return $this->_cached_attributes[$type];
  1518. $def_options = array(
  1519. 'id' => '',
  1520. 'class' => '',
  1521. 'title' => '',
  1522. 'size' => '',
  1523. 'readonly' => false,
  1524. 'selected' => false,
  1525. 'checked' => false,
  1526. 'disabled' => false,
  1527. 'required' => false,
  1528. 'autofocus' => false,
  1529. 'tabindex' => 0,
  1530. 'label' => '',
  1531. 'placeholder' => '',
  1532. 'pattern' => '',
  1533. 'other' => '',
  1534. 'autocomplete' => ''
  1535. // 'multiple' => false, - see case 'select'
  1536. );
  1537. $form_control = (deftrue('BOOTSTRAP') === 3) ? ' form-control' : '';
  1538. switch ($type) {
  1539. case 'hidden':
  1540. $def_options = array('id' => false, 'disabled' => false, 'other' => '');
  1541. break;
  1542. case 'text':
  1543. $def_options['class'] = 'tbox input-text'.$form_control;
  1544. unset($def_options['selected'], $def_options['checked']);
  1545. break;
  1546. case 'file':
  1547. $def_options['class'] = 'tbox file';
  1548. unset($def_options['selected'], $def_options['checked']);
  1549. break;
  1550. case 'textarea':
  1551. $def_options['class'] = 'tbox textarea'.$form_control;
  1552. unset($def_options['selected'], $def_options['checked'], $def_options['size']);
  1553. break;
  1554. case 'select':
  1555. $def_options['class'] = 'tbox select'.$form_control;
  1556. $def_options['multiple'] = false;
  1557. unset($def_options['checked']);
  1558. break;
  1559. case 'option':
  1560. $def_options = array('class' => '', 'selected' => false, 'other' => '', 'disabled' => false, 'label' => '');
  1561. break;
  1562. case 'radio':
  1563. //$def_options['class'] = ' ';
  1564. unset($def_options['size'], $def_options['selected']);
  1565. break;
  1566. case 'checkbox':
  1567. unset($def_options['size'], $def_options['selected']);
  1568. break;
  1569. case 'submit':
  1570. $def_options['class'] = 'button';
  1571. unset($def_options['checked'], $def_options['selected'], $def_options['readonly']);
  1572. break;
  1573. case 'submit_image':
  1574. $def_options['class'] = 'action';
  1575. unset($def_options['checked'], $def_options['selected'], $def_options['readonly']);
  1576. break;
  1577. case 'admin_button':
  1578. unset($def_options['checked'], $def_options['selected'], $def_options['readonly']);
  1579. break;
  1580. }
  1581. $this->_cached_attributes[$type] = $def_options;
  1582. return $def_options;
  1583. }
  1584. function columnSelector($columnsArray, $columnsDefault = '', $id = 'column_options')
  1585. {
  1586. $columnsArray = array_filter($columnsArray);
  1587. $text = '<div class="dropdown e-tip pull-right" data-placement="left">
  1588. <a class="dropdown-toggle" title="Select columns to display" data-toggle="dropdown" href="#"><b class="caret"></b></a>
  1589. <ul class="dropdown-menu col-selection e-noclick" role="menu" aria-labelledby="dLabel">
  1590. <li class="nav-header">Display Columns</li>';
  1591. unset($columnsArray['options'], $columnsArray['checkboxes']);
  1592. foreach($columnsArray as $key => $fld)
  1593. {
  1594. if (!varset($fld['forced']) && !vartrue($fld['nolist']) && vartrue($fld['type'])!='upload')
  1595. {
  1596. $checked = (in_array($key,$columnsDefault)) ? TRUE : FALSE;
  1597. $ttl = isset($fld['title']) ? defset($fld['title'], $fld['title']) : $key;
  1598. // $text .= "
  1599. // <div class='field-spacer'>
  1600. // ".$this->checkbox_label($ttl, 'e-columns[]', $key, $checked)."
  1601. // </div>
  1602. // ";
  1603. //
  1604. $text .= "
  1605. <li role='menuitem'><a href='#'>
  1606. ".$this->checkbox('e-columns[]', $key, $checked,'label='.$ttl)."
  1607. </a>
  1608. </li>
  1609. ";
  1610. }
  1611. }
  1612. // has issues with the checkboxes.
  1613. $text .= "<li>
  1614. <div id='{$id}-button' class='right'>
  1615. ".$this->admin_button('etrigger_ecolumns', LAN_SAVE, 'btn-small')."
  1616. </div>
  1617. </li>
  1618. </ul>
  1619. </div>";
  1620. // $text .= "</div></div>";
  1621. $text .= "";
  1622. /*
  1623. $text = '<div class="dropdown">
  1624. <a class="dropdown-toggle" data-toggle="dropdown" href="#"><b class="caret"></b></a>
  1625. <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
  1626. <li>hi</li>
  1627. </ul>
  1628. </div>';
  1629. */
  1630. return $text;
  1631. }
  1632. function colGroup($fieldarray, $columnPref = '')
  1633. {
  1634. $text = "";
  1635. $count = 0;
  1636. foreach($fieldarray as $key=>$val)
  1637. {
  1638. if ((in_array($key, $columnPref) || $key=='options' || varsettrue($val['forced'])) && !vartrue($val['nolist']))
  1639. {
  1640. $class = vartrue($val['class']) ? 'class="'.$val['class'].'"' : '';
  1641. $width = vartrue($val['width']) ? ' style="width:'.$val['width'].'"' : '';
  1642. $text .= '<col '.$class.$width.' />
  1643. ';
  1644. $count++;
  1645. }
  1646. }
  1647. return '
  1648. <colgroup>
  1649. '.$text.'
  1650. </colgroup>
  1651. ';
  1652. }
  1653. function thead($fieldarray, $columnPref = array(), $querypattern = '', $requeststr = '')
  1654. {
  1655. $text = "";
  1656. // Recommended pattern: mode=list&field=[FIELD]&asc=[ASC]&from=[FROM]
  1657. if(strpos($querypattern,'&')!==FALSE)
  1658. {
  1659. // we can assume it's always $_GET since that's what it will generate
  1660. // more flexible (e.g. pass default values for order/field when they can't be found in e_QUERY) & secure
  1661. $tmp = str_replace('&amp;', '&', $requeststr ? $requeststr : e_QUERY);
  1662. parse_str($tmp, $tmp);
  1663. $etmp = array();
  1664. parse_str(str_replace('&amp;', '&', $querypattern), $etmp);
  1665. }
  1666. else // Legacy Queries. eg. main.[FIELD].[ASC].[FROM]
  1667. {
  1668. $tmp = explode(".", ($requeststr ? $requeststr : e_QUERY));
  1669. $etmp = explode(".", $querypattern);
  1670. }
  1671. 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!.
  1672. {
  1673. if($val == "[FIELD]")
  1674. {
  1675. $field = varset($tmp[$key]);
  1676. }
  1677. if($val == "[ASC]")
  1678. {
  1679. $ascdesc = varset($tmp[$key]);
  1680. }
  1681. if($val == "[FROM]")
  1682. {
  1683. $fromval = varset($tmp[$key]);
  1684. }
  1685. }
  1686. if(!varset($fromval)){ $fromval = 0; }
  1687. $ascdesc = (varset($ascdesc) == 'desc') ? 'asc' : 'desc';
  1688. foreach($fieldarray as $key=>$val)
  1689. {
  1690. if ((in_array($key, $columnPref) || $key == 'options' || (vartrue($val['forced']))) && !vartrue($val['nolist']))
  1691. {
  1692. $cl = (vartrue($val['thclass'])) ? " class='".$val['thclass']."'" : "";
  1693. $text .= "
  1694. <th id='e-column-".str_replace('_', '-', $key)."'{$cl}>
  1695. ";
  1696. if($querypattern!="" && !varsettrue($val['nosort']) && $key != "options" && $key != "checkboxes")
  1697. {
  1698. $from = ($key == $field) ? $fromval : 0;
  1699. $srch = array("[FIELD]","[ASC]","[FROM]");
  1700. $repl = array($key,$ascdesc,$from);
  1701. $val['url'] = e_SELF."?".str_replace($srch,$repl,$querypattern);
  1702. }
  1703. $text .= (vartrue($val['url'])) ? "<a href='".str_replace(array('&amp;', '&'), array('&', '&amp;'),$val['url'])."'>" : ""; // Really this column-sorting link should be auto-generated, or be autocreated via unobtrusive js.
  1704. $text .= defset($val['title'], $val['title']);
  1705. $text .= ($val['url']) ? "</a>" : "";
  1706. $text .= ($key == "options" && !vartrue($val['noselector'])) ? $this->columnSelector($fieldarray, $columnPref) : "";
  1707. $text .= ($key == "checkboxes") ? $this->checkbox_toggle('e-column-toggle', vartrue($val['toggle'], 'multiselect')) : "";
  1708. $text .= "
  1709. </th>
  1710. ";
  1711. }
  1712. }
  1713. return "
  1714. <thead>
  1715. <tr >".$text."</tr>
  1716. </thead>
  1717. ";
  1718. }
  1719. /**
  1720. * Render Table cells from hooks.
  1721. * @param array $data
  1722. * @return string
  1723. */
  1724. function renderHooks($data)
  1725. {
  1726. $hooks = e107::getEvent()->triggerHook($data);
  1727. $text = "";
  1728. if(!empty($hooks))
  1729. {
  1730. foreach($hooks as $plugin => $hk)
  1731. {
  1732. $text .= "\n\n<!-- Hook : {$plugin} -->\n";
  1733. if(!empty($hk))
  1734. {
  1735. foreach($hk as $hook)
  1736. {
  1737. $text .= "\t\t\t<tr>\n";
  1738. $text .= "\t\t\t<td>".$hook['caption']."</td>\n";
  1739. $text .= "\t\t\t<td>".$hook['html']."";
  1740. $text .= (varset($hook['help'])) ? "\n<span class='field-help'>".$hook['help']."</span>" : "";
  1741. $text .= "</td>\n\t\t\t</tr>\n";
  1742. }
  1743. }
  1744. }
  1745. }
  1746. return $text;
  1747. }
  1748. /**
  1749. * Render Related Items for the current page/news-item etc.
  1750. * @param string $type : comma separated list. ie. plugin folder names.
  1751. * @param string $tags : comma separated list of keywords to return related items of.
  1752. * @param array $curVal. eg. array('page'=> current-page-id-value);
  1753. */
  1754. function renderRelated($parm,$tags, $curVal) //XXX TODO Cache!
  1755. {
  1756. if(empty($tags))
  1757. {
  1758. return;
  1759. }
  1760. if(!varset($parm['limit']))
  1761. {
  1762. $parm = array('limit' => 5);
  1763. }
  1764. if(!varset($parm['types']))
  1765. {
  1766. $parm['types'] = 'news';
  1767. }
  1768. $tp = e107::getParser();
  1769. $types = explode(',',$parm['types']);
  1770. $list = array();
  1771. foreach($types as $plug)
  1772. {
  1773. if(!$obj = e107::getAddon($plug,'e_related'))
  1774. {
  1775. continue;
  1776. }
  1777. $parm['current'] = intval(varset($curVal[$plug]));
  1778. $tmp = $obj->compile($tags,$parm);
  1779. if(count($tmp))
  1780. {
  1781. foreach($tmp as $val)
  1782. {
  1783. $list[] = "<li><a href='".$tp->replaceConstants($val['url'],'full')."'>".$val['title']."</a></li>";
  1784. }
  1785. }
  1786. }
  1787. if(count($list))
  1788. {
  1789. return "<div class='e-related clearfix'><hr><h4>Related</h4><ul class='e-related'>".implode("\n",$list)."</ul></div>"; //XXX Tablerender?
  1790. }
  1791. }
  1792. /**
  1793. * Render Table cells from field listing.
  1794. * @param array $fieldarray - eg. $this->fields
  1795. * @param array $currentlist - eg $this->fieldpref
  1796. * @param array $fieldvalues - eg. $row
  1797. * @param string $pid - eg. table_id
  1798. * @return string
  1799. */
  1800. function renderTableRow($fieldarray, $currentlist, $fieldvalues, $pid)
  1801. {
  1802. $cnt = 0;
  1803. $ret = '';
  1804. /*$fieldarray = $obj->fields;
  1805. $currentlist = $obj->fieldpref;
  1806. $pid = $obj->pid;*/
  1807. $trclass = vartrue($fieldvalues['__trclass']) ? ' class="'.$trclass.'"' : '';
  1808. unset($fieldvalues['__trclass']);
  1809. foreach ($fieldarray as $field => $data)
  1810. {
  1811. // shouldn't happen...
  1812. if(!isset($fieldvalues[$field]) && vartrue($data['alias']))
  1813. {
  1814. $fieldvalues[$data['alias']] = $fieldvalues[$data['field']];
  1815. $field = $data['alias'];
  1816. }
  1817. //Not found
  1818. if((!varset($data['forced']) && !in_array($field, $currentlist)) || varset($data['nolist']))
  1819. {
  1820. continue;
  1821. }
  1822. elseif(vartrue($data['type']) != 'method' && !$data['forced'] && !isset($fieldvalues[$field]) && $fieldvalues[$field] !== NULL)
  1823. {
  1824. $ret .= "
  1825. <td>
  1826. Not Found! ($field)
  1827. </td>
  1828. ";
  1829. continue;
  1830. }
  1831. $tdclass = vartrue($data['class']);
  1832. if($field == 'checkboxes') $tdclass = $tdclass ? $tdclass.' autocheck e-pointer' : 'autocheck e-pointer';
  1833. if($field == 'options') $tdclass = $tdclass ? $tdclass.' options' : 'options';
  1834. // there is no other way for now - prepare user data
  1835. if('user' == vartrue($data['type']) /* && isset($data['readParms']['idField'])*/)
  1836. {
  1837. if(varset($data['readParms']) && is_string($data['readParms'])) parse_str($data['readParms'], $data['readParms']);
  1838. if(isset($data['readParms']['idField']))
  1839. {
  1840. $data['readParms']['__idval'] = $fieldvalues[$data['readParms']['idField']];
  1841. }
  1842. elseif(isset($fieldvalues['user_id'])) // Default
  1843. {
  1844. $data['readParms']['__idval'] = $fieldvalues['user_id'];
  1845. }
  1846. if(isset($data['readParms']['nameField']))
  1847. {
  1848. $data['readParms']['__nameval'] = $fieldvalues[$data['readParms']['nameField']];
  1849. }
  1850. elseif(isset($fieldvalues['user_name'])) // Default
  1851. {
  1852. $data['readParms']['__nameval'] = $fieldvalues['user_name'];
  1853. }
  1854. }
  1855. $value = $this->renderValue($field, varset($fieldvalues[$field]), $data, varset($fieldvalues[$pid]));
  1856. if($tdclass)
  1857. {
  1858. $tdclass = ' class="'.$tdclass.'"';
  1859. }
  1860. $ret .= '
  1861. <td'.$tdclass.'>
  1862. '.$value.'
  1863. </td>
  1864. ';
  1865. $cnt++;
  1866. }
  1867. if($cnt)
  1868. {
  1869. return '
  1870. <tr'.$trclass.' id="row-'.$fieldvalues[$pid].'">
  1871. '.$ret.'
  1872. </tr>
  1873. ';
  1874. }
  1875. return '';
  1876. }
  1877. /**
  1878. * Create an Inline Edit link.
  1879. * @param $dbField : field being edited //TODO allow for an array of all data here.
  1880. * @param $pid : primary ID of the row being edited.
  1881. * @param $fieldName - Description of the field name (caption)
  1882. * @param $curVal : existing value of in the field
  1883. * @param $linkText : existing value displayed
  1884. * @param $type text|textarea|select|date|checklist
  1885. * @param $array : array data used in dropdowns etc.
  1886. */
  1887. private function renderInline($dbField, $pid, $fieldName, $curVal, $linkText, $type='text', $array=null)
  1888. {
  1889. $source = str_replace('"',"'",json_encode($array, JSON_FORCE_OBJECT)); // SecretR - force object, fix number of bugs
  1890. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  1891. $text = "<a class='e-tip e-editable editable-click' data-name='".$dbField."' ";
  1892. $text .= (is_array($array)) ? "data-source=\"".$source."\" " : "";
  1893. $text .= " title=\"".LAN_EDIT." ".$fieldName."\" data-type='".$type."' data-value=\"{$curVal}\" data-pk='".$pid."' data-url='".e_SELF."?mode={$mode}&amp;action=inline&amp;id={$pid}&amp;ajax_used=1' href='#'>".$linkText."</a>";
  1894. return $text;
  1895. }
  1896. /**
  1897. * Render Field Value
  1898. * @param string $field field name
  1899. * @param mixed $value field value
  1900. * @param array $attributes field attributes including render parameters, element options - see e_admin_ui::$fields for required format
  1901. * @return string
  1902. */
  1903. function renderValue($field, $value, $attributes, $id = 0)
  1904. {
  1905. $parms = array();
  1906. if(isset($attributes['readParms']))
  1907. {
  1908. if(!is_array($attributes['readParms'])) parse_str($attributes['readParms'], $attributes['readParms']);
  1909. $parms = $attributes['readParms'];
  1910. }
  1911. if(vartrue($attributes['inline'])) $parms['editable'] = true; // attribute alias
  1912. if(vartrue($attributes['sort'])) $parms['sort'] = true; // attribute alias
  1913. $this->renderValueTrigger($field, $value, $parms, $id);
  1914. $tp = e107::getParser();
  1915. switch($field) // special fields
  1916. {
  1917. case 'options':
  1918. if(varset($attributes['type']) == "method") // Allow override with 'options' function.
  1919. {
  1920. $attributes['mode'] = "read";
  1921. if(isset($attributes['method']) && $attributes['method'] && method_exists($this, $attributes['method']))
  1922. {
  1923. $method = $attributes['method'];
  1924. return $this->$method($parms, $value, $id, $attributes);
  1925. }
  1926. elseif(method_exists($this, 'options'))
  1927. {
  1928. //return $this->options($field, $value, $attributes, $id);
  1929. // consistent method arguments, fixed in admin cron administration
  1930. return $this->options($parms, $value, $id, $attributes); // OLD breaks admin->cron 'options' column
  1931. }
  1932. }
  1933. if(!$value)
  1934. {
  1935. parse_str(str_replace('&amp;', '&', e_QUERY), $query); //FIXME - FIX THIS
  1936. // keep other vars in tact
  1937. $query['action'] = 'edit';
  1938. $query['id'] = $id;
  1939. //$edit_query = array('mode' => varset($query['mode']), 'action' => varset($query['action']), 'id' => $id);
  1940. $query = http_build_query($query);
  1941. $value = "<div class='btn-group'>";
  1942. if(vartrue($parms['sort']))//FIXME use a global variable such as $fieldpref
  1943. {
  1944. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  1945. $from = intval(vartrue($_GET['from'],0));
  1946. $value .= "<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='Re-order'>".ADMIN_SORT_ICON."</a> ";
  1947. }
  1948. $cls = false;
  1949. if(varset($parms['editClass']))
  1950. {
  1951. $cls = (deftrue($parms['editClass'])) ? constant($parms['editClass']) : $parms['editClass'];
  1952. }
  1953. if((false === $cls || check_class($cls)) && varset($parms['edit'],1) == 1)
  1954. {
  1955. /*
  1956. $value .= "<a href='".e_SELF."?{$query}' class='e-tip btn btn-large' title='".LAN_EDIT."' data-placement='left'>
  1957. <img class='icon action edit list' src='".ADMIN_EDIT_ICON_PATH."' alt='".LAN_EDIT."' /></a>";
  1958. */
  1959. $value .= "<a href='".e_SELF."?{$query}' class='btn btn-default' title='".LAN_EDIT."' data-toggle='tooltip' data-placement='left'>
  1960. ".ADMIN_EDIT_ICON."</a>";
  1961. }
  1962. $delcls = vartrue($attributes['noConfirm']) ? ' no-confirm' : '';
  1963. if(varset($parms['deleteClass']) && varset($parms['delete'],1) == 1)
  1964. {
  1965. $cls = (deftrue($parms['deleteClass'])) ? constant($parms['deleteClass']) : $parms['deleteClass'];
  1966. if(check_class($cls))
  1967. {
  1968. $value .= $this->submit_image('etrigger_delete['.$id.']', $id, 'delete', LAN_DELETE.' [ ID: '.$id.' ]', array('class' => 'action delete btn btn-default'.$delcls));
  1969. }
  1970. }
  1971. else
  1972. {
  1973. $value .= $this->submit_image('etrigger_delete['.$id.']', $id, 'delete', LAN_DELETE.' [ ID: '.$id.' ]', array('class' => 'action delete btn btn-default'.$delcls));
  1974. }
  1975. }
  1976. //$attributes['type'] = 'text';
  1977. $value .= "</div>";
  1978. return $value;
  1979. break;
  1980. case 'checkboxes':
  1981. $value = $this->checkbox(vartrue($attributes['toggle'], 'multiselect').'['.$id.']', $id);
  1982. //$attributes['type'] = 'text';
  1983. return $value;
  1984. break;
  1985. }
  1986. switch($attributes['type'])
  1987. {
  1988. case 'number':
  1989. if(!$value) $value = '0';
  1990. if($parms)
  1991. {
  1992. if(!isset($parms['sep'])) $value = number_format($value, $parms['decimals']);
  1993. else $value = number_format($value, $parms['decimals'], vartrue($parms['point'], '.'), vartrue($parms['sep'], ' '));
  1994. }
  1995. if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  1996. {
  1997. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  1998. $value = "<a class='e-tip e-editable editable-click' data-name='".$field."' title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='text' data-pk='".$id."' data-url='".e_SELF."?mode={$mode}&action=inline&id={$id}&ajax_used=1' href='#'>".$value."</a>";
  1999. }
  2000. $value = vartrue($parms['pre']).$value.vartrue($parms['post']);
  2001. // else same
  2002. break;
  2003. case 'ip':
  2004. //$e107 = e107::getInstance();
  2005. $value = e107::getIPHandler()->ipDecode($value);
  2006. // else same
  2007. break;
  2008. case 'templates':
  2009. case 'layouts':
  2010. $pre = vartrue($parms['pre']);
  2011. $post = vartrue($parms['post']);
  2012. unset($parms['pre'], $parms['post']);
  2013. if($parms)
  2014. {
  2015. $attributes['writeParms'] = $parms;
  2016. }
  2017. elseif(isset($attributes['writeParms']))
  2018. {
  2019. if(is_string($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']);
  2020. }
  2021. $attributes['writeParms']['raw'] = true;
  2022. $tmp = $this->renderElement($field, '', $attributes);
  2023. // Inline Editing. //@SecretR - please FIXME!
  2024. if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  2025. {
  2026. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  2027. $source = str_replace('"',"'",json_encode($wparms));
  2028. $value = "<a class='e-tip e-editable editable-click' data-name='".$field."' data-source=\"".$source."\" title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='select' data-pk='".$id."' data-url='".e_SELF."?mode=&amp;action=inline&amp;id={$id}&amp;ajax_used=1' href='#'>".$value."</a>";
  2029. }
  2030. // $value = $pre.vartrue($tmp[$value]).$post; // FIXME "Fatal error: Only variables can be passed by reference" featurebox list page.
  2031. break;
  2032. case 'comma':
  2033. case 'dropdown':
  2034. // XXX - should we use readParams at all here? see writeParms check below
  2035. if($parms && is_array($parms)) // FIXME - add support for multi-level arrays (option groups)
  2036. {
  2037. //FIXME return no value at all when 'editable=1' is a readParm. See FAQs templates.
  2038. // $value = vartrue($parms['pre']).vartrue($parms[$value]).vartrue($parms['post']);
  2039. // break;
  2040. }
  2041. // NEW - multiple (array values) support
  2042. // FIXME - add support for multi-level arrays (option groups)
  2043. if(!is_array($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']);
  2044. $wparms = $attributes['writeParms'];
  2045. if(!is_array(varset($wparms['__options']))) parse_str($wparms['__options'], $wparms['__options']);
  2046. $opts = $wparms['__options'];
  2047. unset($wparms['__options']);
  2048. $_value = $value;
  2049. if(vartrue($opts['multiple']) || vartrue($attributes['type']) == 'comma')
  2050. {
  2051. $ret = array();
  2052. $value = is_array($value) ? $value : explode(',', $value);
  2053. foreach ($value as $v)
  2054. {
  2055. if(isset($wparms[$v])) $ret[] = $wparms[$v];
  2056. }
  2057. $value = implode(', ', $ret);
  2058. }
  2059. else
  2060. {
  2061. $ret = '';
  2062. if(isset($wparms[$value])) $ret = $wparms[$value];
  2063. $value = $ret;
  2064. }
  2065. $value = ($value ? vartrue($parms['pre']).defset($value, $value).vartrue($parms['post']) : '');
  2066. // Inline Editing.
  2067. // Inline Editing with 'comma' @SecretR - please FIXME - empty values added. @see news 'render type' or 'media-manager' category for test examples.
  2068. if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  2069. {
  2070. $xtype = ($attributes['type'] == 'dropdown') ? 'select' : 'checklist';
  2071. // $value = "<a class='e-tip e-editable editable-click' data-name='".$field."' data-value='{$_value}' data-source=\"".$source."\" title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='".$xtype."' data-pk='".$id."' data-url='".e_SELF."?mode=&amp;action=inline&amp;id={$id}&amp;ajax_used=1' href='#'>".$value."</a>";
  2072. $value = $this->renderInline($field, $id, $attributes['title'], $_value, $value, $xtype, $wparms);
  2073. }
  2074. // return ;
  2075. break;
  2076. case 'radio':
  2077. if($parms && is_array($parms)) // FIXME - add support for multi-level arrays (option groups)
  2078. {
  2079. $value = vartrue($parms['pre']).vartrue($parms[$value]).vartrue($parms['post']);
  2080. break;
  2081. }
  2082. if(!is_array($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']);
  2083. $value = vartrue($attributes['writeParms']['__options']['pre']).vartrue($attributes['writeParms'][$value]).vartrue($attributes['writeParms']['__options']['post']);
  2084. break;
  2085. case 'tags':
  2086. case 'text':
  2087. if(vartrue($parms['truncate']))
  2088. {
  2089. $value = $tp->text_truncate($value, $parms['truncate'], '...');
  2090. }
  2091. elseif(vartrue($parms['htmltruncate']))
  2092. {
  2093. $value = $tp->html_truncate($value, $parms['htmltruncate'], '...');
  2094. }
  2095. if(vartrue($parms['wrap']))
  2096. {
  2097. $value = $tp->htmlwrap($value, (int)$parms['wrap'], varset($parms['wrapChar'], ' '));
  2098. }
  2099. if(vartrue($parms['link']) && $id/* && is_numeric($id)*/)
  2100. {
  2101. $link = str_replace('[id]',$id,$parms['link']);
  2102. $link = $tp->replaceConstants($link); // SEF URL is not important since we're in admin.
  2103. $dialog = vartrue($parms['target']) =='dialog' ? " e-dialog" : ""; // iframe
  2104. $ext = vartrue($parms['target']) =='blank' ? " rel='external' " : ""; // new window
  2105. $modal = vartrue($parms['target']) =='modal' ? " data-toggle='modal' data-cache='false' data-target='#uiModal' " : "";
  2106. if($parms['link'] == 'sef' && $this->getController()->getListModel())
  2107. {
  2108. $model = $this->getController()->getListModel();
  2109. // copy url config
  2110. $model->setUrl($this->getController()->getUrl());
  2111. // assemble the url
  2112. $link = $model->url();
  2113. }
  2114. elseif(vartrue($data[$parms['link']])) // support for a field-name as the link. eg. link_url.
  2115. {
  2116. $link = $tp->replaceConstants(vartrue($data[$parms['link']]));
  2117. }
  2118. // in case something goes wrong...
  2119. if($link) $value = "<a class='e-tip{$dialog}' {$ext} href='".$link."' {$modal} title='Quick View'>".$value."</a>";
  2120. }
  2121. if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  2122. {
  2123. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  2124. $value = "<a class='e-tip e-editable editable-click' data-name='".$field."' title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='text' data-pk='".$id."' data-url='".e_SELF."?mode={$mode}&amp;action=inline&amp;id={$id}&amp;ajax_used=1' href='#'>".$value."</a>";
  2125. }
  2126. $value = vartrue($parms['pre']).$value.vartrue($parms['post']);
  2127. break;
  2128. case 'bbarea':
  2129. case 'textarea':
  2130. if($attributes['type'] == 'textarea' && !vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  2131. {
  2132. return $this->renderInline($field,$id,$attributes['title'],$value,substr($value,0,50)."...",'textarea'); //FIXME.
  2133. }
  2134. $expand = '...';
  2135. $toexpand = false;
  2136. if($attributes['type'] == 'bbarea' && !isset($parms['bb'])) $parms['bb'] = true; //force bb parsing for bbareas
  2137. $elid = trim(str_replace('_', '-', $field)).'-'.$id;
  2138. if(!vartrue($parms['noparse'])) $value = $tp->toHTML($value, (vartrue($parms['bb']) ? true : false), vartrue($parms['parse']));
  2139. if(vartrue($parms['expand']) || vartrue($parms['truncate']) || vartrue($parms['htmltruncate']))
  2140. {
  2141. $ttl = vartrue($parms['expand']);
  2142. if($ttl == 1)
  2143. {
  2144. $ttl = $expand."<button class='btn btn-default btn-mini pull-right'>More..</button>";
  2145. $ttl1 = "<button class='btn btn-default btn-mini pull-right'>..Less</button>";
  2146. }
  2147. $expands = '<a href="#'.$elid.'-expand" class="e-show-if-js e-expandit">'.defset($ttl, $ttl)."</a>";
  2148. $contracts = '<a href="#'.$elid.'-expand" class="e-show-if-js e-expandit">'.defset($ttl1, $ttl1)."</a>";
  2149. }
  2150. $oldval = $value;
  2151. if(vartrue($parms['truncate']))
  2152. {
  2153. $value = $oldval = strip_tags($value);
  2154. $value = $tp->text_truncate($value, $parms['truncate'], '');
  2155. $toexpand = $value != $oldval;
  2156. }
  2157. elseif(vartrue($parms['htmltruncate']))
  2158. {
  2159. $value = $tp->html_truncate($value, $parms['htmltruncate'], '');
  2160. $toexpand = $value != $oldval;
  2161. }
  2162. if($toexpand)
  2163. {
  2164. // force hide! TODO - core style .expand-c (expand container)
  2165. // TODO: Hide 'More..' button when text fully displayed.
  2166. $value .= '<span class="expand-c" style="display: none" id="'.$elid.'-expand"><span>'.str_replace($value,'',$oldval).$contracts.'</span></span>';
  2167. $value .= $expands; // 'More..' button. Keep it at the bottom so it does't cut the sentence.
  2168. }
  2169. break;
  2170. case 'icon':
  2171. $value = $tp->toIcon($value,array('size'=>'2x'));
  2172. break;
  2173. case 'file':
  2174. if(vartrue($parms['base']))
  2175. {
  2176. $url = $parms['base'].$value;
  2177. }
  2178. else $url = e107::getParser()->replaceConstants($value, 'full');
  2179. $name = basename($value);
  2180. $value = '<a href="'.$url.'" title="Direct link to '.$name.'" rel="external">'.$name.'</a>';
  2181. break;
  2182. case 'image': //TODO - thumb, js tooltip...
  2183. if($value)
  2184. {
  2185. if(strpos($value,",")!==false)
  2186. {
  2187. $tmp = explode(",",$value);
  2188. $value = $tmp[0];
  2189. unset($tmp);
  2190. }
  2191. $vparm = array('thumb'=>'tag','w'=> vartrue($parms['thumb_aw'],'80'));
  2192. if($video = e107::getParser()->toVideo($value,$vparm))
  2193. {
  2194. return $video;
  2195. }
  2196. if(!preg_match("/[a-zA-z0-9_-\s\(\)]+\.(png|jpg|jpeg|gif|PNG|JPG|JPEG|GIF)$/",$value) && strpos($value,'.')!==false)
  2197. {
  2198. $icon = "{e_IMAGE}filemanager/zip_32.png";
  2199. $src = $tp->replaceConstants(vartrue($parms['pre']).$icon, 'abs');
  2200. // return '<img src="'.$src.'" alt="'.$value.'" class="e-thumb" title="'.$value.'" />';
  2201. }
  2202. if(vartrue($parms['thumb']))
  2203. {
  2204. $src = $tp->replaceConstants(vartrue($parms['pre']).$value, 'abs');
  2205. $thumb = $parms['thumb'];
  2206. $thparms = array();
  2207. if(is_numeric($thumb) && '1' != $thumb)
  2208. {
  2209. $thparms['w'] = intval($thumb);
  2210. }
  2211. elseif(vartrue($parms['thumb_aw']))
  2212. {
  2213. $thparms['aw'] = intval($parms['thumb_aw']);
  2214. }
  2215. $thsrc = $tp->thumbUrl(vartrue($parms['pre']).$value, $thparms, varset($parms['thumb_urlraw']));
  2216. $alt = basename($src);
  2217. $ttl = '<img src="'.$thsrc.'" alt="'.$alt.'" class="thumbnail e-thumb" />';
  2218. $value = '<a href="'.$src.'" data-modal-caption="'.$alt.'" data-target="#uiModal" class="e-modal e-image-preview" title="'.$alt.'" rel="external">'.$ttl.'</a>';
  2219. }
  2220. else
  2221. {
  2222. $src = $tp->replaceConstants(vartrue($parms['pre']).$value, 'abs');
  2223. $alt = $src; //basename($value);
  2224. $ttl = vartrue($parms['title'], 'LAN_PREVIEW');
  2225. $value = '<a href="'.$src.'" class="e-image-preview" title="'.$alt.'" rel="external">'.defset($ttl, $ttl).'</a>';
  2226. }
  2227. }
  2228. break;
  2229. case 'datestamp':
  2230. $value = $value ? e107::getDate()->convert_date($value, vartrue($parms['mask'], 'short')) : '';
  2231. break;
  2232. case 'date':
  2233. // just show original value
  2234. break;
  2235. case 'userclass':
  2236. $dispvalue = $this->_uc->uc_get_classname($value);
  2237. // Inline Editing.
  2238. if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  2239. {
  2240. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  2241. $array = e107::getUserClass()->uc_required_class_list(); //XXX Ugly looking (non-standard) function naming - TODO discuss name change.
  2242. $source = str_replace('"',"'",json_encode($array, JSON_FORCE_OBJECT));
  2243. //NOTE Leading ',' required on $value; so it picks up existing value.
  2244. $value = "<a class='e-tip e-editable editable-click' data-placement='left' data-value='".$value."' data-name='".$field."' data-source=\"".$source."\" title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='select' data-pk='".$id."' data-url='".e_SELF."?mode={$mode}&amp;action=inline&amp;id={$id}&amp;ajax_used=1' href='#'>".$dispvalue."</a>";
  2245. }
  2246. else
  2247. {
  2248. $value = $dispvalue;
  2249. }
  2250. break;
  2251. case 'userclasses':
  2252. $classes = explode(',', $value);
  2253. $uv = array();
  2254. foreach ($classes as $cid)
  2255. {
  2256. $uv[] = $this->_uc->uc_get_classname($cid);
  2257. }
  2258. $dispvalue = implode(vartrue($parms['separator'],"<br />"), $uv);
  2259. // Inline Editing.
  2260. if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
  2261. {
  2262. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  2263. $optlist = $parm['xxxxx']; // XXX TODO - add param for choice of class list options below.
  2264. $array = e107::getUserClass()->uc_required_class_list('nobody,admin,main,public,classes'); //XXX Ugly looking (non-standard) function naming - TODO discuss name change.
  2265. $source = str_replace('"',"'",json_encode($array, JSON_FORCE_OBJECT));
  2266. //NOTE Leading ',' required on $value; so it picks up existing value.
  2267. $value = "<a class='e-tip e-editable editable-click' data-placement='left' data-value=',".$value."' data-name='".$field."' data-source=\"".$source."\" title=\"".LAN_EDIT." ".$attributes['title']."\" data-type='checklist' data-pk='".$id."' data-url='".e_SELF."?mode={$mode}&amp;action=inline&amp;id={$id}&amp;ajax_used=1' href='#'>".$dispvalue."</a>";
  2268. }
  2269. else
  2270. {
  2271. $value = $dispvalue;
  2272. }
  2273. break;
  2274. /*case 'user_name':
  2275. case 'user_loginname':
  2276. case 'user_login':
  2277. case 'user_customtitle':
  2278. case 'user_email':*/
  2279. case 'user':
  2280. /*if(is_numeric($value))
  2281. {
  2282. $value = get_user_data($value);
  2283. if($value)
  2284. {
  2285. $value = $value[$attributes['type']] ? $value[$attributes['type']] : $value['user_name'];
  2286. }
  2287. else
  2288. {
  2289. $value = 'not found';
  2290. }
  2291. }*/
  2292. // Dirty, but the only way for now
  2293. $id = 0;
  2294. $ttl = LAN_ANONYMOUS;
  2295. //Defaults to user_id and user_name (when present) and when idField and nameField are not present.
  2296. // previously set - real parameters are idField && nameField
  2297. $id = vartrue($parms['__idval']);
  2298. if($value && !is_numeric($value))
  2299. {
  2300. $id = vartrue($parms['__idval']);
  2301. $ttl = $value;
  2302. }
  2303. elseif($value && is_numeric($value))
  2304. {
  2305. $id = $value;
  2306. $ttl = vartrue($parms['__nameval']);
  2307. }
  2308. if(vartrue($parms['link']) && $id && $ttl && is_numeric($id))
  2309. {
  2310. $value = '<a href="'.e107::getUrl()->create('user/profile/view', array('id' => $id, 'name' => $ttl)).'" title="Go to user profile">'.$ttl.'</a>';
  2311. }
  2312. else
  2313. {
  2314. $value = $ttl;
  2315. }
  2316. break;
  2317. case 'bool':
  2318. case 'boolean':
  2319. $false = vartrue($parms['trueonly']) ? "" : ADMIN_FALSE_ICON;
  2320. if(vartrue($parms['reverse']))
  2321. {
  2322. $value = ($value) ? $false : ADMIN_TRUE_ICON;
  2323. }
  2324. else
  2325. {
  2326. $value = $value ? ADMIN_TRUE_ICON : $false;
  2327. }
  2328. break;
  2329. case 'url':
  2330. if(!$value) break;
  2331. $ttl = $value;
  2332. if(vartrue($parms['href']))
  2333. {
  2334. return $tp->replaceConstants(vartrue($parms['pre']).$value, varset($parms['replace_mod'],'abs'));
  2335. }
  2336. if(vartrue($parms['truncate']))
  2337. {
  2338. $ttl = $tp->text_truncate($value, $parms['truncate'], '...');
  2339. }
  2340. $value = "<a href='".$tp->replaceConstants(vartrue($parms['pre']).$value, 'abs')."' title='{$value}'>".$ttl."</a>";
  2341. break;
  2342. case 'email':
  2343. if(!$value) break;
  2344. $ttl = $value;
  2345. if(vartrue($parms['truncate']))
  2346. {
  2347. $ttl = $tp->text_truncate($value, $parms['truncate'], '...');
  2348. }
  2349. $value = "<a href='mailto:".$value."' title='{$value}'>".$ttl."</a>";
  2350. break;
  2351. case 'method': // Custom Function
  2352. $method = $attributes['field']; // prevents table alias in method names. ie. u.my_method.
  2353. $_value = $value;
  2354. $value = call_user_func_array(array($this, $method), array($value, 'read', $parms));
  2355. // Inline Editing.
  2356. if(!vartrue($attributes['noedit']) && vartrue($parms['editable'])) // avoid bad markup, better solution coming up
  2357. {
  2358. $mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
  2359. $methodParms = call_user_func_array(array($this, $method), array($value, 'inline', $parms));
  2360. $source = str_replace('"',"'",json_encode($methodParms, JSON_FORCE_OBJECT));
  2361. $value = "<a class='e-tip e-editable editable-click' data-type='select' data-value='".$_value."' data-name='".$field."' data-source=\"".$source."\" title=\"".LAN_EDIT." ".$attributes['title']."\" data-pk='".$id."' data-url='".e_SELF."?mode=&amp;action=inline&amp;id={$id}&amp;ajax_used=1' href='#'>".$value."</a>";
  2362. }
  2363. break;
  2364. case 'hidden':
  2365. return (vartrue($parms['show']) ? ($value ? $value : vartrue($parms['empty'])) : '');
  2366. break;
  2367. case 'lanlist':
  2368. $options = e107::getLanguage()->getLanSelectArray();
  2369. if($options) // FIXME - add support for multi-level arrays (option groups)
  2370. {
  2371. if(!is_array($attributes['writeParms'])) parse_str($attributes['writeParms'], $attributes['writeParms']);
  2372. $wparms = $attributes['writeParms'];
  2373. if(!is_array(varset($wparms['__options']))) parse_str($wparms['__options'], $wparms['__options']);
  2374. $opts = $wparms['__options'];
  2375. if($opts['multiple'])
  2376. {
  2377. $ret = array();
  2378. $value = is_array($value) ? $value : explode(',', $value);
  2379. foreach ($value as $v)
  2380. {
  2381. if(isset($options[$v])) $ret[] = $options[$v];
  2382. }
  2383. $value = implode(', ', $ret);
  2384. }
  2385. else
  2386. {
  2387. $ret = '';
  2388. if(isset($options[$value])) $ret = $options[$value];
  2389. $value = $ret;
  2390. }
  2391. $value = ($value ? vartrue($parms['pre']).$value.vartrue($parms['post']) : '');
  2392. }
  2393. else
  2394. {
  2395. $value = '';
  2396. }
  2397. break;
  2398. //TODO - order
  2399. default:
  2400. //unknown type
  2401. break;
  2402. }
  2403. return $value;
  2404. }
  2405. /**
  2406. * Auto-render Form Element
  2407. * @param string $key
  2408. * @param mixed $value
  2409. * @param array $attributes field attributes including render parameters, element options - see e_admin_ui::$fields for required format
  2410. * #param array (under construction) $required_data required array as defined in e_model/validator
  2411. * @return string
  2412. */
  2413. function renderElement($key, $value, $attributes, $required_data = array(), $id = 0)
  2414. {
  2415. $parms = vartrue($attributes['writeParms'], array());
  2416. $tp = e107::getParser();
  2417. if(is_string($parms)) parse_str($parms, $parms);
  2418. // Two modes of read-only. 1 = read-only, but only when there is a value, 2 = read-only regardless.
  2419. if(vartrue($attributes['readonly']) && (vartrue($value) || vartrue($attributes['readonly'])===2)) // quick fix (maybe 'noedit'=>'readonly'?)
  2420. {
  2421. if(vartrue($attributes['writeParms'])) // eg. different size thumbnail on the edit page.
  2422. {
  2423. $attributes['readParms'] = $attributes['writeParms'];
  2424. }
  2425. return $this->renderValue($key, $value, $attributes).$this->hidden($key, $value); //
  2426. }
  2427. // FIXME standard - writeParams['__options'] is introduced for list elements, bundle adding to writeParms is non reliable way
  2428. $writeParamsOptionable = array('dropdown', 'comma', 'radio', 'lanlist', 'language', 'user');
  2429. $writeParamsDisabled = array('layouts', 'templates', 'userclass', 'userclasses');
  2430. // FIXME it breaks all list like elements - dropdowns, radio, etc
  2431. if(vartrue($required_data[0]) || vartrue($attributes['required'])) // HTML5 'required' attribute
  2432. {
  2433. // FIXME - another approach, raise standards, remove checks
  2434. if(in_array($attributes['type'], $writeParamsOptionable))
  2435. {
  2436. $parms['__options']['required'] = 1;
  2437. }
  2438. elseif(!in_array($attributes['type'], $writeParamsDisabled))
  2439. {
  2440. $parms['required'] = 1;
  2441. }
  2442. }
  2443. // FIXME it breaks all list like elements - dropdowns, radio, etc
  2444. if(vartrue($required_data[3]) || vartrue($attributes['pattern'])) // HTML5 'pattern' attribute
  2445. {
  2446. // FIXME - another approach, raise standards, remove checks
  2447. if(in_array($attributes['type'], $writeParamsOptionable))
  2448. {
  2449. $parms['__options']['pattern'] = vartrue($attributes['pattern'], $required_data[3]);
  2450. }
  2451. elseif(!in_array($attributes['type'], $writeParamsDisabled))
  2452. {
  2453. $parms['pattern'] = vartrue($attributes['pattern'], $required_data[3]);
  2454. }
  2455. }
  2456. $this->renderElementTrigger($key, $value, $parms, $required_data, $id);
  2457. switch($attributes['type'])
  2458. {
  2459. case 'number':
  2460. $maxlength = vartrue($parms['maxlength'], 255);
  2461. unset($parms['maxlength']);
  2462. if(!vartrue($parms['size'])) $parms['size'] = 'mini';
  2463. if(!vartrue($parms['class'])) $parms['class'] = 'tbox number e-spinner';
  2464. if(!$value) $value = '0';
  2465. $ret = vartrue($parms['pre']).$this->text($key, $value, $maxlength, $parms).vartrue($parms['post']);
  2466. break;
  2467. case 'ip':
  2468. $ret = $this->text($key, e107::getIPHandler()->ipDecode($value), 32, $parms);
  2469. break;
  2470. case 'url':
  2471. case 'email':
  2472. case 'text':
  2473. case 'password': // encrypts to md5 when saved.
  2474. $maxlength = vartrue($parms['maxlength'], 255);
  2475. unset($parms['maxlength']);
  2476. $ret = vartrue($parms['pre']).$this->text($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true
  2477. break;
  2478. case 'tags':
  2479. $ret = vartrue($parms['pre']).$this->tags($key, $value, $maxlength, $parms).vartrue($parms['post']); // vartrue($parms['__options']) is limited. See 'required'=>true
  2480. break;
  2481. case 'textarea':
  2482. $text = "";
  2483. if(vartrue($parms['append'])) // similar to comments - TODO TBD. a 'comment' field type may be better.
  2484. {
  2485. $attributes['readParms'] = 'bb=1';
  2486. $text = $this->renderValue($key, $value, $attributes).$this->hidden($key, $value).'<br />';
  2487. $value = "";
  2488. }
  2489. $text .= $this->textarea($key, $value, vartrue($parms['rows'], 5), vartrue($parms['cols'], 40), vartrue($parms['__options']), varset($parms['counter'], false));
  2490. $ret = $text;
  2491. break;
  2492. case 'bbarea':
  2493. $options = array('counter' => varset($parms['counter'], false));
  2494. // Media = media-category owner used by media-manager.
  2495. $ret = $this->bbarea($key, $value, vartrue($parms['template']), vartrue($parms['media']), vartrue($parms['size'], 'medium'),$options );
  2496. break;
  2497. case 'image': //TODO - thumb, image list shortcode, js tooltip...
  2498. $label = varset($parms['label'], 'LAN_EDIT');
  2499. unset($parms['label']);
  2500. $ret = $this->imagepicker($key, $value, defset($label, $label), $parms);
  2501. break;
  2502. case 'images':
  2503. $value = str_replace('&#039;',"'",html_entity_decode($value)); //FIXME @SecretR Horrible workaround to Line 3203 of admin_ui.php
  2504. $ival = e107::unserialize($value);
  2505. for ($i=0; $i < 5; $i++)
  2506. {
  2507. $k = $key.'[path]['.$i.']';
  2508. $ret .= $this->imagepicker($k, $ival['path'][$i], defset($label, $label), $parms);
  2509. }
  2510. break;
  2511. case 'file': //TODO - thumb, image list shortcode, js tooltip...
  2512. $label = varset($parms['label'], 'LAN_EDIT');
  2513. unset($parms['label']);
  2514. $ret = $this->filepicker($key, $value, defset($label, $label), $parms);
  2515. break;
  2516. case 'icon':
  2517. $label = varset($parms['label'], 'LAN_EDIT');
  2518. $ajax = varset($parms['ajax'], true) ? true : false;
  2519. unset($parms['label'], $parms['ajax']);
  2520. $ret = $this->iconpicker($key, $value, defset($label, $label), $parms, $ajax);
  2521. break;
  2522. 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.
  2523. case 'datestamp':
  2524. // If hidden, value is updated regardless. eg. a 'last updated' field.
  2525. // If not hidden, and there is a value, it is retained. eg. during the update of an existing record.
  2526. // otherwise it is added. eg. during the creation of a new record.
  2527. if(vartrue($parms['auto']) && (($value == null) || vartrue($parms['hidden'])))
  2528. {
  2529. $value = time();
  2530. }
  2531. if(vartrue($parms['readonly'])) // different to 'attribute-readonly' since the value may be auto-generated.
  2532. {
  2533. $ret = $this->renderValue($key, $value, $attributes).$this->hidden($key, $value);
  2534. }
  2535. elseif(vartrue($parms['hidden']))
  2536. {
  2537. $ret = $this->hidden($key, $value);
  2538. }
  2539. else
  2540. {
  2541. $ret = $this->datepicker($key, $value, $parms);
  2542. }
  2543. break;
  2544. case 'layouts': //to do - exclude param (exact match)
  2545. $location = varset($parms['plugin']); // empty - core
  2546. $ilocation = vartrue($parms['id'], $location); // omit if same as plugin name
  2547. $where = vartrue($parms['area'], 'front'); //default is 'front'
  2548. $filter = varset($parms['filter']);
  2549. $merge = vartrue($parms['merge']) ? true : false;
  2550. $layouts = e107::getLayouts($location, $ilocation, $where, $filter, $merge, true);
  2551. if(varset($parms['default']) && !isset($layouts[0]['default']))
  2552. {
  2553. $layouts[0] = array('default' => $parms['default']) + $layouts[0];
  2554. }
  2555. $info = array();
  2556. if($layouts[1])
  2557. {
  2558. foreach ($layouts[1] as $k => $info_array)
  2559. {
  2560. if(isset($info_array['description']))
  2561. $info[$k] = defset($info_array['description'], $info_array['description']);
  2562. }
  2563. }
  2564. //$this->selectbox($key, $layouts, $value)
  2565. $ret = (vartrue($parms['raw']) ? $layouts[0] : $this->radio_multi($key, $layouts[0], $value,array('sep'=>"<br />"), $info));
  2566. break;
  2567. case 'templates': //to do - exclude param (exact match)
  2568. $templates = array();
  2569. if(varset($parms['default']))
  2570. {
  2571. $templates['default'] = defset($parms['default'], $parms['default']);
  2572. }
  2573. $location = vartrue($parms['plugin']) ? e_PLUGIN.$parms['plugin'].'/' : e_THEME;
  2574. $ilocation = vartrue($parms['location']);
  2575. $tmp = e107::getFile()->get_files($location.'templates/'.$ilocation, vartrue($parms['fmask'], '_template\.php$'), vartrue($parms['omit'], 'standard'), vartrue($parms['recurse_level'], 0));
  2576. foreach($tmp as $files)
  2577. {
  2578. $k = str_replace('_template.php', '', $files['fname']);
  2579. $templates[$k] = implode(' ', array_map('ucfirst', explode('_', $k))); //TODO add LANS?
  2580. }
  2581. // override
  2582. $where = vartrue($parms['area'], 'front');
  2583. $location = vartrue($parms['plugin']) ? $parms['plugin'].'/' : '';
  2584. $tmp = e107::getFile()->get_files(e107::getThemeInfo($where, 'rel').'templates/'.$location.$ilocation, vartrue($parms['fmask']), vartrue($parms['omit'], 'standard'), vartrue($parms['recurse_level'], 0));
  2585. foreach($tmp as $files)
  2586. {
  2587. $k = str_replace('_template.php', '', $files['fname']);
  2588. $templates[$k] = implode(' ', array_map('ucfirst', explode('_', $k))); //TODO add LANS?
  2589. }
  2590. $ret = (vartrue($parms['raw']) ? $templates : $this->selectbox($key, $templates, $value));
  2591. break;
  2592. case 'dropdown':
  2593. case 'comma':
  2594. $eloptions = vartrue($parms['__options'], array());
  2595. if(is_string($eloptions)) parse_str($eloptions, $eloptions);
  2596. if($attributes['type'] === 'comma') $eloptions['multiple'] = true;
  2597. unset($parms['__options']);
  2598. if(vartrue($eloptions['multiple']) && !is_array($value)) $value = explode(',', $value);
  2599. $ret = vartrue($eloptions['pre']).$this->selectbox($key, $parms, $value, $eloptions).vartrue($eloptions['post']);
  2600. break;
  2601. case 'radio':
  2602. // TODO - more options (multi-line, help)
  2603. $eloptions = vartrue($parms['__options'], array());
  2604. if(is_string($eloptions)) parse_str($eloptions, $eloptions);
  2605. unset($parms['__options']);
  2606. $ret = vartrue($eloptions['pre']).$this->radio_multi($key, $parms, $value, $eloptions, false).vartrue($eloptions['post']);
  2607. break;
  2608. case 'userclass':
  2609. case 'userclasses':
  2610. $uc_options = vartrue($parms['classlist'], 'public,guest,nobody,member,admin,main,classes'); // defaults to 'public,guest,nobody,member,classes' (userclass handler)
  2611. unset($parms['classlist']);
  2612. $method = ($attributes['type'] == 'userclass') ? 'uc_select' : 'uc_select';
  2613. if(vartrue($atrributes['type']) == 'userclasses'){ $parms['multiple'] = true; }
  2614. $ret = $this->$method($key, $value, $uc_options, vartrue($parms, array()));
  2615. break;
  2616. /*case 'user_name':
  2617. case 'user_loginname':
  2618. case 'user_login':
  2619. case 'user_customtitle':
  2620. case 'user_email':*/
  2621. case 'user':
  2622. //user_id expected
  2623. // Just temporary solution, could be changed soon
  2624. if(!isset($parms['__options'])) $parms['__options'] = array();
  2625. if(!is_array($parms['__options'])) parse_str($parms['__options'], $parms['__options']);
  2626. if((empty($value) && varset($parms['currentInit'],USERID)!==0) || vartrue($parms['current'])) // include current user by default.
  2627. {
  2628. $value = USERID;
  2629. if(vartrue($parms['current']))
  2630. {
  2631. $parms['__options']['readonly'] = true;
  2632. }
  2633. }
  2634. if(!is_array($value))
  2635. {
  2636. $value = $value ? e107::getSystemUser($value, true)->getUserData() : array();// get_user_data($value);
  2637. }
  2638. $colname = vartrue($parms['nameType'], 'user_name');
  2639. $parms['__options']['name'] = $colname;
  2640. if(!$value) $value = array();
  2641. $uname = varset($value[$colname]);
  2642. $value = varset($value['user_id'], 0);
  2643. $ret = $this->userpicker(vartrue($parms['nameField'], $key.'_usersearch'), $key, $uname, $value, vartrue($parms['__options']));
  2644. break;
  2645. case 'bool':
  2646. case 'boolean':
  2647. if(varset($parms['label']) === 'yesno')
  2648. {
  2649. $lenabled = 'LAN_YES';
  2650. $ldisabled = 'LAN_NO';
  2651. }
  2652. else
  2653. {
  2654. $lenabled = vartrue($parms['enabled'], 'LAN_ENABLED');
  2655. $ldisabled = vartrue($parms['disabled'], 'LAN_DISABLED');
  2656. }
  2657. unset($parms['enabled'], $parms['disabled'], $parms['label']);
  2658. $ret = $this->radio_switch($key, $value, defset($lenabled, $lenabled), defset($ldisabled, $ldisabled),$parms);
  2659. break;
  2660. case 'method': // Custom Function
  2661. $ret = call_user_func_array(array($this, $key), array($value, 'write', $parms));
  2662. break;
  2663. case 'upload': //TODO - from method
  2664. // TODO uploadfile SC is now processing uploads as well (add it to admin UI), write/readParms have to be added (see uploadfile.php parms)
  2665. $disbut = varset($parms['disable_button'], '0');
  2666. $ret = $tp->parseTemplate("{UPLOADFILE=".(vartrue($parms['path']) ? e107::getParser()->replaceConstants($parms['path']) : e_UPLOAD)."|nowarn&trigger=etrigger_uploadfiles&disable_button={$disbut}}");
  2667. break;
  2668. case 'hidden':
  2669. $value = (isset($parms['value'])) ? $parms['value'] : $value;
  2670. $ret = (vartrue($parms['show']) ? ($value ? $value : varset($parms['empty'], $value)) : '');
  2671. //echo "<br />key=".$key."<br />value=".$value;
  2672. $ret = $ret.$this->hidden($key, $value);
  2673. break;
  2674. case 'lanlist':
  2675. case 'language':
  2676. $options = e107::getLanguage()->getLanSelectArray();
  2677. $eloptions = vartrue($parms['__options'], array());
  2678. if(!is_array($eloptions)) parse_str($eloptions, $eloptions);
  2679. unset($parms['__options']);
  2680. if(vartrue($eloptions['multiple']) && !is_array($value)) $value = explode(',', $value);
  2681. $ret = vartrue($eloptions['pre']).$this->selectbox($key, $options, $value, $eloptions).vartrue($eloptions['post']);
  2682. break;
  2683. default:// No LAN necessary, debug only.
  2684. $ret = (ADMIN) ? "<span class='alert alert-error'>".LAN_ERROR." Unknown 'type' : ".$attributes['type'] ."</span>" : $value;
  2685. break;
  2686. }
  2687. if(vartrue($parms['expand']))
  2688. {
  2689. $k = "exp-".$this->name2id($key);
  2690. $text = "<a class='e-expandit e-tip' href='#{$k}'>".$parms['expand']."</a>";
  2691. $text .= vartrue($parms['help']) ? '<div class="field-help">'.$parms['help'].'</div>' : '';
  2692. $text .= "<div id='{$k}' class='e-hideme'>".$ret."</div>";
  2693. return $text;
  2694. }
  2695. else
  2696. {
  2697. $ret .= vartrue($parms['help']) ? '<div class="field-help">'.$tp->toHtml($parms['help'],false,'defs').'</div>' : '';
  2698. }
  2699. return $ret;
  2700. }
  2701. /**
  2702. * Generic List Form, used internal by admin UI
  2703. * Expected options array format:
  2704. * <code>
  2705. * <?php
  2706. * $form_options['myplugin'] = array(
  2707. * 'id' => 'myplugin', // unique string used for building element ids, REQUIRED
  2708. * 'pid' => 'primary_id', // primary field name, REQUIRED
  2709. * 'url' => '{e_PLUGIN}myplug/admin_config.php', // if not set, e_SELF is used
  2710. * 'query' => 'mode=main&amp;action=list', // or e_QUERY if not set
  2711. * 'head_query' => 'mode=main&amp;action=list', // without field, asc and from vars, REQUIRED
  2712. * 'np_query' => 'mode=main&amp;action=list', // without from var, REQUIRED for next/prev functionality
  2713. * 'legend' => 'Fieldset Legend', // hidden by default
  2714. * 'form_pre' => '', // markup to be added before opening form element (e.g. Filter form)
  2715. * 'form_post' => '', // markup to be added after closing form element
  2716. * 'fields' => array(...), // see e_admin_ui::$fields
  2717. * 'fieldpref' => array(...), // see e_admin_ui::$fieldpref
  2718. * 'table_pre' => '', // markup to be added before opening table element
  2719. * 'table_post' => '', // markup to be added after closing table element (e.g. Batch actions)
  2720. * 'fieldset_pre' => '', // markup to be added before opening fieldset element
  2721. * 'fieldset_post' => '', // markup to be added after closing fieldset element
  2722. * 'perPage' => 15, // if 0 - no next/prev navigation
  2723. * 'from' => 0, // current page, default 0
  2724. * 'field' => 'field_name', //current order field name, default - primary field
  2725. * 'asc' => 'desc', //current 'order by' rule, default 'asc'
  2726. * );
  2727. * $tree_models['myplugin'] = new e_admin_tree_model($data);
  2728. * </code>
  2729. * TODO - move fieldset & table generation in separate methods, needed for ajax calls
  2730. * @param array $form_options
  2731. * @param e_admin_tree_model $tree_model
  2732. * @param boolean $nocontainer don't enclose form in div container
  2733. * @return string
  2734. */
  2735. public function renderListForm($form_options, $tree_models, $nocontainer = false)
  2736. {
  2737. $tp = e107::getParser();
  2738. $text = '';
  2739. // print_a($form_options);
  2740. foreach ($form_options as $fid => $options)
  2741. {
  2742. $tree_model = $tree_models[$fid];
  2743. $tree = $tree_model->getTree();
  2744. $total = $tree_model->getTotal();
  2745. $amount = $options['perPage'];
  2746. $from = vartrue($options['from'], 0);
  2747. $field = vartrue($options['field'], $options['pid']);
  2748. $asc = strtoupper(vartrue($options['asc'], 'asc'));
  2749. $elid = $fid;//$options['id'];
  2750. $query = isset($options['query']) ? $options['query'] : e_QUERY ;
  2751. if(vartrue($_GET['action']) == 'list')
  2752. {
  2753. $query = e_QUERY; //XXX Quick fix for loss of pagination after 'delete'.
  2754. }
  2755. $url = (isset($options['url']) ? $tp->replaceConstants($options['url'], 'abs') : e_SELF);
  2756. $formurl = $url.($query ? '?'.$query : '');
  2757. $fields = $options['fields'];
  2758. $current_fields = varset($options['fieldpref']) ? $options['fieldpref'] : array_keys($options['fields']);
  2759. $legend_class = vartrue($options['legend_class'], 'e-hideme');
  2760. $text .= "
  2761. <form method='post' action='{$formurl}' id='{$elid}-list-form'>
  2762. <div>".$this->token()."
  2763. ".vartrue($options['fieldset_pre'])."
  2764. <fieldset id='{$elid}-list'>
  2765. <legend class='{$legend_class}'>".$options['legend']."</legend>
  2766. ".vartrue($options['table_pre'])."
  2767. <table class='table adminlist table-striped' id='{$elid}-list-table'>
  2768. ".$this->colGroup($fields, $current_fields)."
  2769. ".$this->thead($fields, $current_fields, varset($options['head_query']), varset($options['query']))."
  2770. <tbody id='e-sort'>
  2771. ";
  2772. if(!$tree)
  2773. {
  2774. $text .= "
  2775. </tbody>
  2776. </table>";
  2777. $text .= "<div class='alert alert-block alert-info center middle'>".LAN_NO_RECORDS."</div>"; // not prone to column-count issues.
  2778. }
  2779. else
  2780. {
  2781. foreach($tree as $model)
  2782. {
  2783. e107::setRegistry('core/adminUI/currentListModel', $model);
  2784. $text .= $this->renderTableRow($fields, $current_fields, $model->getData(), $options['pid']);
  2785. }
  2786. e107::setRegistry('core/adminUI/currentListModel', null);
  2787. $text .= "</tbody>
  2788. </table>";
  2789. }
  2790. $text .= vartrue($options['table_post']);
  2791. if($tree && $amount)
  2792. {
  2793. // New nextprev SC parameters
  2794. $parms = 'total='.$total;
  2795. $parms .= '&amount='.$amount;
  2796. $parms .= '&current='.$from;
  2797. if(ADMIN_AREA)
  2798. {
  2799. $parms .= '&tmpl_prefix=admin';
  2800. }
  2801. // NOTE - the whole url is double encoded - reason is to not break parms query string
  2802. // 'np_query' should be proper (urlencode'd) url query string
  2803. $url = rawurlencode($url.'?'.(varset($options['np_query']) ? str_replace(array('&amp;', '&'), array('&', '&amp;'), $options['np_query']).'&amp;' : '').'from=[FROM]');
  2804. $parms .= '&url='.$url;
  2805. //$parms = $total.",".$amount.",".$from.",".$url.'?'.($options['np_query'] ? $options['np_query'].'&amp;' : '').'from=[FROM]';
  2806. //$text .= $tp->parseTemplate("{NEXTPREV={$parms}}");
  2807. $nextprev = $tp->parseTemplate("{NEXTPREV={$parms}}");
  2808. if ($nextprev)
  2809. {
  2810. $text .= "<div class='nextprev-bar'>".$nextprev."</div>";
  2811. }
  2812. }
  2813. $text .= "
  2814. </fieldset>
  2815. ".vartrue($options['fieldset_post'])."
  2816. </div>
  2817. </form>
  2818. ";
  2819. }
  2820. if(!$nocontainer)
  2821. {
  2822. $text = '<div class="e-container">'.$text.'</div>';
  2823. }
  2824. return (vartrue($options['form_pre']).$text.vartrue($options['form_post']));
  2825. }
  2826. /**
  2827. * Generic DB Record Management Form.
  2828. * TODO - lans
  2829. * TODO - move fieldset & table generation in separate methods, needed for ajax calls
  2830. * Expected arrays format:
  2831. * <code>
  2832. * <?php
  2833. * $forms[0] = array(
  2834. * 'id' => 'myplugin',
  2835. * 'url' => '{e_PLUGIN}myplug/admin_config.php', //if not set, e_SELF is used
  2836. * 'query' => 'mode=main&amp;action=edit&id=1', //or e_QUERY if not set
  2837. * 'tabs' => true, // TODO - NOT IMPLEMENTED YET - enable tabs (only if fieldset count is > 1) //XXX Multiple triggers in a single form?
  2838. * 'fieldsets' => array(
  2839. * 'general' => array(
  2840. * 'legend' => 'Fieldset Legend',
  2841. * 'fields' => array(...), //see e_admin_ui::$fields
  2842. * 'after_submit_options' => array('action' => 'Label'[,...]), // or true for default redirect options
  2843. * 'after_submit_default' => 'action_name',
  2844. * 'triggers' => 'auto', // standard create/update-cancel triggers
  2845. * //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)
  2846. * ),
  2847. *
  2848. * 'advanced' => array(
  2849. * 'legend' => 'Fieldset Legend',
  2850. * 'fields' => array(...), //see e_admin_ui::$fields
  2851. * 'after_submit_options' => array('__default' => 'action_name' 'action' => 'Label'[,...]), // or true for default redirect options
  2852. * 'triggers' => 'auto', // standard create/update-cancel triggers
  2853. * //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)
  2854. * )
  2855. * )
  2856. * );
  2857. * $models[0] = new e_admin_model($data);
  2858. * $models[0]->setFieldIdName('primary_id'); // you need to do it if you don't use your own admin model extension
  2859. * </code>
  2860. * @param array $forms numerical array
  2861. * @param array $models numerical array with values instance of e_admin_model
  2862. * @param boolean $nocontainer don't enclose in div container
  2863. * @return string
  2864. */
  2865. function renderCreateForm($forms, $models, $nocontainer = false)
  2866. {
  2867. $text = '';
  2868. foreach ($forms as $fid => $form)
  2869. {
  2870. $model = $models[$fid];
  2871. $query = isset($form['query']) ? $form['query'] : e_QUERY ;
  2872. $url = (isset($form['url']) ? e107::getParser()->replaceConstants($form['url'], 'abs') : e_SELF).($query ? '?'.$query : '');
  2873. $curTab = varset($_GET['tab'],0);
  2874. $text .= "
  2875. <form method='post' action='".$url."' id='{$form['id']}-form' enctype='multipart/form-data'>
  2876. <div>
  2877. ".vartrue($form['header'])."
  2878. ".$this->token()."
  2879. ";
  2880. foreach ($form['fieldsets'] as $elid => $data) //XXX rename 'fieldsets' to 'forms' ?
  2881. {
  2882. $elid = $form['id'].'-'.$elid;
  2883. if(vartrue($data['tabs'])) // Tabs Present
  2884. {
  2885. $text .= '<ul class="nav nav-tabs">';
  2886. foreach($data['tabs'] as $i=>$label)
  2887. {
  2888. $class = ($i == $curTab) ? 'class="active" ' : '';
  2889. $text .= '<li '.$class.'><a href="#tab'.$i.'" data-toggle="tab">'.$label.'</a></li>';
  2890. }
  2891. $text .= ' </ul><div class="tab-content">';
  2892. foreach($data['tabs'] as $tabId=>$label)
  2893. {
  2894. $active = ($tabId == $curTab) ? 'active' : '';
  2895. $text .= '<div class="tab-pane '.$active.'" id="tab'.$tabId.'">';
  2896. $text .= $this->renderCreateFieldset($elid, $data, $model, $tabId);
  2897. $text .= "</div>";
  2898. }
  2899. $text .= "</div>";
  2900. $text .= $this->renderCreateButtonsBar($elid, $data, $model, $tabId); // Create/Update Buttons etc.
  2901. }
  2902. else // No Tabs Present
  2903. {
  2904. $text .= $this->renderCreateFieldset($elid, $data, $model, false);
  2905. $text .= $this->renderCreateButtonsBar($elid, $data, $model, false); // Create/Update Buttons etc.
  2906. }
  2907. }
  2908. $text .= "
  2909. ".vartrue($form['footer'])."
  2910. </div>
  2911. </form>
  2912. ";
  2913. // e107::js('footer-inline',"Form.focusFirstElement('{$form['id']}-form');",'prototype');
  2914. // e107::getJs()->footerInline("Form.focusFirstElement('{$form['id']}-form');");
  2915. }
  2916. if(!$nocontainer)
  2917. {
  2918. $text = '<div class="e-container">'.$text.'</div>';
  2919. }
  2920. return $text;
  2921. }
  2922. /**
  2923. * Create form fieldset, called internal by {@link renderCreateForm())
  2924. *
  2925. * @param string $id field id
  2926. * @param array $fdata fieldset data
  2927. * @param e_admin_model $model
  2928. */
  2929. function renderCreateFieldset($id, $fdata, $model, $tab=0)
  2930. {
  2931. $text = vartrue($fdata['fieldset_pre'])."
  2932. <fieldset id='{$id}'>
  2933. <legend>".vartrue($fdata['legend'])."</legend>
  2934. ".vartrue($fdata['table_pre'])."
  2935. <table class='table adminform'>
  2936. <colgroup>
  2937. <col class='col-label' />
  2938. <col class='col-control' />
  2939. </colgroup>
  2940. <tbody>
  2941. ";
  2942. // required fields - model definition
  2943. $model_required = $model->getValidationRules();
  2944. $required_help = false;
  2945. $hidden_fields = array();
  2946. foreach($fdata['fields'] as $key => $att)
  2947. {
  2948. if($tab !== false && varset($att['tab'], 0) !== $tab)
  2949. {
  2950. continue;
  2951. }
  2952. // convert aliases - not supported in edit mod
  2953. if(vartrue($att['alias']) && !$model->hasData($key))
  2954. {
  2955. $key = $att['field'];
  2956. }
  2957. if($key == 'checkboxes' || $key == 'options')
  2958. {
  2959. continue;
  2960. }
  2961. $parms = vartrue($att['formparms'], array());
  2962. if(!is_array($parms)) parse_str($parms, $parms);
  2963. $label = vartrue($att['note']) ? '<div class="label-note">'.deftrue($att['note'], $att['note']).'</div>' : '';
  2964. $help = vartrue($att['help']) ? '<div class="field-help">'.deftrue($att['help'], $att['help']).'</div>' : '';
  2965. $valPath = trim(vartrue($att['dataPath'], $key), '/');
  2966. $keyName = $key;
  2967. if(strpos($valPath, '/')) //not TRUE, cause string doesn't start with /
  2968. {
  2969. $tmp = explode('/', $valPath);
  2970. $keyName = array_shift($tmp);
  2971. foreach ($tmp as $path)
  2972. {
  2973. $keyName .= '['.$path.']';
  2974. }
  2975. }
  2976. if('hidden' === $att['type'])
  2977. {
  2978. if(!is_array($att['writeParms'])) parse_str(varset($att['writeParms']), $tmp);
  2979. else $tmp = $att['writeParms'];
  2980. if(!vartrue($tmp['show']))
  2981. {
  2982. continue;
  2983. }
  2984. unset($tmp);
  2985. }
  2986. // type null - system (special) fields
  2987. if(vartrue($att['type']) !== null && !vartrue($att['noedit']) && $key != $model->getFieldIdName())
  2988. {
  2989. $required = '';
  2990. $required_class = '';
  2991. if(isset($model_required[$key]) || vartrue($att['validate']))
  2992. {
  2993. $required = $this->getRequiredString();
  2994. $required_class = ' class="required-label"'; // TODO - add 'required-label' to the core CSS definitions
  2995. $required_help = true;
  2996. if(vartrue($att['validate']))
  2997. {
  2998. // override
  2999. $model_required[$key] = array();
  3000. $model_required[$key][] = true === $att['validate'] ? 'required' : $att['validate'];
  3001. $model_required[$key][] = varset($att['rule']);
  3002. $model_required[$key][] = $att['title'];
  3003. $model_required[$key][] = varset($att['error']);
  3004. }
  3005. }
  3006. /*
  3007. if('hidden' === $att['type'])
  3008. {
  3009. parse_str(varset($att['writeParms']), $tmp);
  3010. if(!vartrue($tmp['show']))
  3011. {
  3012. $hidden_fields[] = $this->renderElement($keyName, $model->getIfPosted($valPath), $att, varset($model_required[$key], array()));
  3013. unset($tmp);
  3014. continue;
  3015. }
  3016. unset($tmp);
  3017. }
  3018. *
  3019. *
  3020. *
  3021. *
  3022. */
  3023. $leftCell = $required."<span{$required_class}>".defset(vartrue($att['title']), vartrue($att['title']))."</span>".$label;
  3024. $rightCell = $this->renderElement($keyName, $model->getIfPosted($valPath), $att, varset($model_required[$key], array()), $model->getId())." {$help}";
  3025. if(vartrue($att['type']) == 'bbarea')
  3026. {
  3027. $text .= "
  3028. <tr><td colspan='2'>
  3029. <div style='padding-bottom:8px'>".$leftCell."</div>".
  3030. $rightCell."
  3031. </td>
  3032. </tr>
  3033. ";
  3034. }
  3035. else
  3036. {
  3037. $text .= "
  3038. <tr>
  3039. <td>
  3040. ".$leftCell."
  3041. </td>
  3042. <td>
  3043. ".$rightCell."
  3044. </td>
  3045. </tr>
  3046. ";
  3047. }
  3048. }
  3049. //if($bckp) $model->remove($bckp);
  3050. }
  3051. //print_a($fdata);
  3052. if($required_help)
  3053. {
  3054. $required_help = '<div class="form-note">'.$this->getRequiredString().' - required fields</div>'; //TODO - lans
  3055. }
  3056. $text .= "
  3057. </tbody>
  3058. </table></fieldset>";
  3059. $text .= vartrue($fdata['fieldset_post']);
  3060. return $text;
  3061. /*
  3062. $text .= "
  3063. ".implode("\n", $hidden_fields)."
  3064. ".$required_help."
  3065. ".vartrue($fdata['table_post'])."
  3066. <div class='buttons-bar center'>
  3067. ";
  3068. // After submit options
  3069. $defsubmitopt = array('list' => 'go to list', 'create' => 'create another', 'edit' => 'edit current');
  3070. $submitopt = isset($fdata['after_submit_options']) ? $fdata['after_submit_options'] : true;
  3071. if(true === $submitopt)
  3072. {
  3073. $submitopt = $defsubmitopt;
  3074. }
  3075. if($submitopt)
  3076. {
  3077. $selected = isset($fdata['after_submit_default']) && array_key_exists($fdata['after_submit_default'], $submitopt) ? $fdata['after_submit_default'] : '';
  3078. }
  3079. $triggers = vartrue($fdata['triggers'], 'auto');
  3080. if(is_string($triggers) && 'auto' === $triggers)
  3081. {
  3082. $triggers = array();
  3083. if($model->getId())
  3084. {
  3085. $triggers['submit'] = array(LAN_UPDATE, 'update', $model->getId());
  3086. }
  3087. else
  3088. {
  3089. $triggers['submit'] = array(LAN_CREATE, 'create', 0);
  3090. }
  3091. $triggers['cancel'] = array(LAN_CANCEL, 'cancel');
  3092. }
  3093. foreach ($triggers as $trigger => $tdata)
  3094. {
  3095. $text .= ($trigger == 'submit') ? "<div class=' btn-group'>" : "";
  3096. $text .= $this->admin_button('etrigger_'.$trigger, $tdata[0], $tdata[1]);
  3097. if($trigger == 'submit' && $submitopt)
  3098. {
  3099. $text .=
  3100. '<button class="btn btn-success dropdown-toggle left" data-toggle="dropdown">
  3101. <span class="caret"></span>
  3102. </button>
  3103. <ul class="dropdown-menu col-selection">
  3104. <li class="nav-header">After submit:</li>
  3105. ';
  3106. foreach($defsubmitopt as $k=>$v)
  3107. {
  3108. $text .= "<li><a href='#' class='e-noclick'>".$this->radio('__after_submit_action', $k, $selected,"label=".$v)."</a></li>";
  3109. }
  3110. //$text .= '
  3111. // <li role="menuitem">
  3112. // <div class="options left" style="padding:5px">
  3113. // '.$this->radio_multi('__after_submit_action', $submitopt, $selected, true).'
  3114. // </div></li>';
  3115. $text .= '</ul>';
  3116. }
  3117. $text .= ($trigger == 'submit') ?"</div>" : "";
  3118. if(isset($tdata[2]))
  3119. {
  3120. $text .= $this->hidden($trigger.'_value', $tdata[2]);
  3121. }
  3122. }
  3123. $text .= "
  3124. </div>
  3125. ".vartrue($fdata['fieldset_post'])."
  3126. ";
  3127. return $text;
  3128. */
  3129. }
  3130. function renderCreateButtonsBar($id, $fdata, $model, $tab=0)
  3131. {
  3132. /*
  3133. $text = vartrue($fdata['fieldset_pre'])."
  3134. <fieldset id='{$id}'>
  3135. <legend>".vartrue($fdata['legend'])."</legend>
  3136. ".vartrue($fdata['table_pre'])."
  3137. <table class='table adminform'>
  3138. <colgroup>
  3139. <col class='col-label' />
  3140. <col class='col-control' />
  3141. </colgroup>
  3142. <tbody>
  3143. ";
  3144. */
  3145. // required fields - model definition
  3146. $model_required = $model->getValidationRules();
  3147. $required_help = false;
  3148. $hidden_fields = array();
  3149. foreach($fdata['fields'] as $key => $att)
  3150. {
  3151. if($tab !== false && varset($att['tab'], 0) !== $tab)
  3152. {
  3153. continue;
  3154. }
  3155. // convert aliases - not supported in edit mod
  3156. if(vartrue($att['alias']) && !$model->hasData($key))
  3157. {
  3158. $key = $att['field'];
  3159. }
  3160. if($key == 'checkboxes' || $key == 'options')
  3161. {
  3162. continue;
  3163. }
  3164. $parms = vartrue($att['formparms'], array());
  3165. if(!is_array($parms)) parse_str($parms, $parms);
  3166. $label = vartrue($att['note']) ? '<div class="label-note">'.deftrue($att['note'], $att['note']).'</div>' : '';
  3167. $help = vartrue($att['help']) ? '<div class="field-help">'.deftrue($att['help'], $att['help']).'</div>' : '';
  3168. $valPath = trim(vartrue($att['dataPath'], $key), '/');
  3169. $keyName = $key;
  3170. if(strpos($valPath, '/')) //not TRUE, cause string doesn't start with /
  3171. {
  3172. $tmp = explode('/', $valPath);
  3173. $keyName = array_shift($tmp);
  3174. foreach ($tmp as $path)
  3175. {
  3176. $keyName .= '['.$path.']';
  3177. }
  3178. }
  3179. if('hidden' === $att['type'])
  3180. {
  3181. if(!is_array($att['writeParms'])) parse_str(varset($att['writeParms']), $tmp);
  3182. else $tmp = $att['writeParms'];
  3183. if(!vartrue($tmp['show']))
  3184. {
  3185. $hidden_fields[] = $this->renderElement($keyName, $model->getIfPosted($valPath), $att, varset($model_required[$key], array()), $model->getId());
  3186. unset($tmp);
  3187. continue;
  3188. }
  3189. unset($tmp);
  3190. }
  3191. // type null - system (special) fields
  3192. if(vartrue($att['type']) !== null && !vartrue($att['noedit']) && $key != $model->getFieldIdName())
  3193. {
  3194. $required = '';
  3195. $required_class = '';
  3196. if(isset($model_required[$key]) || vartrue($att['validate']))
  3197. {
  3198. $required = $this->getRequiredString();
  3199. $required_class = ' class="required-label"'; // TODO - add 'required-label' to the core CSS definitions
  3200. $required_help = true;
  3201. if(vartrue($att['validate']))
  3202. {
  3203. // override
  3204. $model_required[$key] = array();
  3205. $model_required[$key][] = true === $att['validate'] ? 'required' : $att['validate'];
  3206. $model_required[$key][] = varset($att['rule']);
  3207. $model_required[$key][] = $att['title'];
  3208. $model_required[$key][] = varset($att['error']);
  3209. }
  3210. }
  3211. /*
  3212. $text .= "
  3213. <tr>
  3214. <td>
  3215. ".$required."<span{$required_class}>".defset(vartrue($att['title']), vartrue($att['title']))."</span>".$label."
  3216. </td>
  3217. <td>
  3218. ".$this->renderElement($keyName, $model->getIfPosted($valPath), $att, varset($model_required[$key], array()))."
  3219. {$help}
  3220. </td>
  3221. </tr>
  3222. ";
  3223. * */
  3224. }
  3225. //if($bckp) $model->remove($bckp);
  3226. }
  3227. if($required_help)
  3228. {
  3229. // $required_help = '<div class="form-note">'.$this->getRequiredString().' - required fields</div>'; //TODO - lans
  3230. }
  3231. // $text .= "
  3232. // </tbody>
  3233. // </table></fieldset>";
  3234. $text .= "
  3235. ".implode("\n", $hidden_fields)."
  3236. ".vartrue($fdata['table_post'])."
  3237. <div class='buttons-bar center'>
  3238. ";
  3239. // After submit options
  3240. $defsubmitopt = array('list' => 'go to list', 'create' => 'create another', 'edit' => 'edit current');
  3241. $submitopt = isset($fdata['after_submit_options']) ? $fdata['after_submit_options'] : true;
  3242. if(true === $submitopt)
  3243. {
  3244. $submitopt = $defsubmitopt;
  3245. }
  3246. if($submitopt)
  3247. {
  3248. $selected = isset($fdata['after_submit_default']) && array_key_exists($fdata['after_submit_default'], $submitopt) ? $fdata['after_submit_default'] : '';
  3249. }
  3250. $triggers = vartrue($fdata['triggers'], 'auto');
  3251. if(is_string($triggers) && 'auto' === $triggers)
  3252. {
  3253. $triggers = array();
  3254. if($model->getId())
  3255. {
  3256. $triggers['submit'] = array(LAN_UPDATE, 'update', $model->getId());
  3257. }
  3258. else
  3259. {
  3260. $triggers['submit'] = array(LAN_CREATE, 'create', 0);
  3261. }
  3262. $triggers['cancel'] = array(LAN_CANCEL, 'cancel');
  3263. }
  3264. foreach ($triggers as $trigger => $tdata)
  3265. {
  3266. $text .= ($trigger == 'submit') ? "<div class=' btn-group'>" : "";
  3267. $text .= $this->admin_button('etrigger_'.$trigger, $tdata[0], $tdata[1]);
  3268. if($trigger == 'submit' && $submitopt)
  3269. {
  3270. $text .=
  3271. '<button class="btn btn-success dropdown-toggle left" data-toggle="dropdown">
  3272. <span class="caret"></span>
  3273. </button>
  3274. <ul class="dropdown-menu col-selection">
  3275. <li class="nav-header">After submit:</li>
  3276. ';
  3277. foreach($defsubmitopt as $k=>$v)
  3278. {
  3279. $text .= "<li><a href='#' class='e-noclick'>".$this->radio('__after_submit_action', $k, $selected == $k, "label=".$v)."</a></li>";
  3280. }
  3281. //$text .= '
  3282. // <li role="menuitem">
  3283. // <div class="options left" style="padding:5px">
  3284. // '.$this->radio_multi('__after_submit_action', $submitopt, $selected, true).'
  3285. // </div></li>';
  3286. $text .= '</ul>';
  3287. }
  3288. $text .= ($trigger == 'submit') ?"</div>" : "";
  3289. if(isset($tdata[2]))
  3290. {
  3291. $text .= $this->hidden($trigger.'_value', $tdata[2]);
  3292. }
  3293. }
  3294. $text .= "
  3295. </div>
  3296. ".vartrue($fdata['fieldset_post'])."
  3297. ";
  3298. return $text;
  3299. }
  3300. /**
  3301. * Generic renderForm solution
  3302. * @param @forms
  3303. * @param @nocontainer
  3304. */
  3305. function renderForm($forms, $nocontainer = false)
  3306. {
  3307. $text = '';
  3308. foreach ($forms as $fid => $form)
  3309. {
  3310. $query = isset($form['query']) ? $form['query'] : e_QUERY ;
  3311. $url = (isset($form['url']) ? e107::getParser()->replaceConstants($form['url'], 'abs') : e_SELF).($query ? '?'.$query : '');
  3312. $text .= "
  3313. ".vartrue($form['form_pre'])."
  3314. <form method='post' action='".$url."' id='{$form['id']}-form' enctype='multipart/form-data'>
  3315. <div>
  3316. ".vartrue($form['header'])."
  3317. ".$this->token()."
  3318. ";
  3319. foreach ($form['fieldsets'] as $elid => $fieldset_data)
  3320. {
  3321. $elid = $form['id'].'-'.$elid;
  3322. $text .= $this->renderFieldset($elid, $fieldset_data);
  3323. }
  3324. $text .= "
  3325. ".vartrue($form['footer'])."
  3326. </div>
  3327. </form>
  3328. ".vartrue($form['form_post'])."
  3329. ";
  3330. }
  3331. if(!$nocontainer)
  3332. {
  3333. $text = '<div class="e-container">'.$text.'</div>';
  3334. }
  3335. return $text;
  3336. }
  3337. /**
  3338. * Generic renderFieldset solution, will be split to renderTable, renderCol/Row/Box etc - Still in use.
  3339. */
  3340. function renderFieldset($id, $fdata)
  3341. {
  3342. $colgroup = '';
  3343. if(vartrue($fdata['table_colgroup']))
  3344. {
  3345. $colgroup = "
  3346. <colgroup span='".count($fdata['table_colgroup'])."'>
  3347. ";
  3348. foreach ($fdata['table_colgroup'] as $i => $colgr)
  3349. {
  3350. $colgroup .= "<col ";
  3351. foreach ($colgr as $attr => $v)
  3352. {
  3353. $colgroup .= "{$attr}='{$v}'";
  3354. }
  3355. $colgroup .= " />
  3356. ";
  3357. }
  3358. $colgroup = "</colgroup>
  3359. ";
  3360. }
  3361. $text = vartrue($fdata['fieldset_pre'])."
  3362. <fieldset id='{$id}'>
  3363. <legend>".vartrue($fdata['legend'])."</legend>
  3364. ".vartrue($fdata['table_pre'])."
  3365. ";
  3366. if(vartrue($fdata['table_rows']) || vartrue($fdata['table_body']))
  3367. {
  3368. $text .= "
  3369. <table class='table adminform'>
  3370. {$colgroup}
  3371. <thead>
  3372. ".vartrue($fdata['table_head'])."
  3373. </thead>
  3374. <tbody>
  3375. ";
  3376. if(vartrue($fdata['table_rows']))
  3377. {
  3378. foreach($fdata['table_rows'] as $index => $row)
  3379. {
  3380. $text .= "
  3381. <tr id='{$id}-{$index}'>
  3382. $row
  3383. </tr>
  3384. ";
  3385. }
  3386. }
  3387. elseif(vartrue($fdata['table_body']))
  3388. {
  3389. $text .= $fdata['table_body'];
  3390. }
  3391. if(vartrue($fdata['table_note']))
  3392. {
  3393. $note = '<div class="form-note">'.$fdata['table_note'].'</div>';
  3394. }
  3395. $text .= "
  3396. </tbody>
  3397. </table>
  3398. ".$note."
  3399. ".vartrue($fdata['table_post'])."
  3400. ";
  3401. }
  3402. $triggers = vartrue($fdata['triggers'], array());
  3403. if($triggers)
  3404. {
  3405. $text .= "<div class='buttons-bar center'>
  3406. ".vartrue($fdata['pre_triggers'], '')."
  3407. ";
  3408. foreach ($triggers as $trigger => $tdata)
  3409. {
  3410. if(is_string($tdata))
  3411. {
  3412. $text .= $tdata;
  3413. continue;
  3414. }
  3415. $text .= $this->admin_button('etrigger_'.$trigger, $tdata[0], $tdata[1]);
  3416. if(isset($tdata[2]))
  3417. {
  3418. $text .= $this->hidden($trigger.'_value', $tdata[2]);
  3419. }
  3420. }
  3421. $text .= "</div>";
  3422. }
  3423. $text .= "
  3424. </fieldset>
  3425. ".vartrue($fdata['fieldset_post'])."
  3426. ";
  3427. return $text;
  3428. }
  3429. /**
  3430. * Render Value Trigger - override to modify field/value/parameters
  3431. * @param string $field field name
  3432. * @param mixed $value field value
  3433. * @param array $params 'writeParams' key (see $controller->fields array)
  3434. * @param int $id record ID
  3435. */
  3436. public function renderValueTrigger(&$field, &$value, &$params, $id)
  3437. {
  3438. }
  3439. /**
  3440. * Render Element Trigger - override to modify field/value/parameters/validation data
  3441. * @param string $field field name
  3442. * @param mixed $value field value
  3443. * @param array $params 'writeParams' key (see $controller->fields array)
  3444. * @param array $required_data validation data
  3445. * @param int $id record ID
  3446. */
  3447. public function renderElementTrigger(&$field, &$value, &$params, &$required_data, $id)
  3448. {
  3449. }
  3450. }
  3451. class form
  3452. {
  3453. function form_open($form_method, $form_action, $form_name = "", $form_target = "", $form_enctype = "", $form_js = "")
  3454. {
  3455. $method = ($form_method ? "method='".$form_method."'" : "");
  3456. $target = ($form_target ? " target='".$form_target."'" : "");
  3457. $name = ($form_name ? " id='".$form_name."' " : " id='myform'");
  3458. return "\n<form action='".$form_action."' ".$method.$target.$name.$form_enctype.$form_js."><div>".e107::getForm()->token()."</div>";
  3459. }
  3460. function form_text($form_name, $form_size, $form_value, $form_maxlength = FALSE, $form_class = "tbox", $form_readonly = "", $form_tooltip = "", $form_js = "") {
  3461. $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : "");
  3462. $value = (isset($form_value) ? " value='".$form_value."'" : "");
  3463. $size = ($form_size ? " size='".$form_size."'" : "");
  3464. $maxlength = ($form_maxlength ? " maxlength='".$form_maxlength."'" : "");
  3465. $readonly = ($form_readonly ? " readonly='readonly'" : "");
  3466. $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : "");
  3467. return "\n<input class='".$form_class."' type='text' ".$name.$value.$size.$maxlength.$readonly.$tooltip.$form_js." />";
  3468. }
  3469. function form_password($form_name, $form_size, $form_value, $form_maxlength = FALSE, $form_class = "tbox", $form_readonly = "", $form_tooltip = "", $form_js = "") {
  3470. $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : "");
  3471. $value = (isset($form_value) ? " value='".$form_value."'" : "");
  3472. $size = ($form_size ? " size='".$form_size."'" : "");
  3473. $maxlength = ($form_maxlength ? " maxlength='".$form_maxlength."'" : "");
  3474. $readonly = ($form_readonly ? " readonly='readonly'" : "");
  3475. $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : "");
  3476. return "\n<input class='".$form_class."' type='password' ".$name.$value.$size.$maxlength.$readonly.$tooltip.$form_js." />";
  3477. }
  3478. function form_button($form_type, $form_name, $form_value, $form_js = "", $form_image = "", $form_tooltip = "") {
  3479. $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : "");
  3480. $image = ($form_image ? " src='".$form_image."' " : "");
  3481. $tooltip = ($form_tooltip ? " title='".$form_tooltip."' " : "");
  3482. return "\n<input class='btn btn-default button' type='".$form_type."' ".$form_js." value='".$form_value."'".$name.$image.$tooltip." />";
  3483. }
  3484. function form_textarea($form_name, $form_columns, $form_rows, $form_value, $form_js = "", $form_style = "", $form_wrap = "", $form_readonly = "", $form_tooltip = "") {
  3485. $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : "");
  3486. $readonly = ($form_readonly ? " readonly='readonly'" : "");
  3487. $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : "");
  3488. $wrap = ($form_wrap ? " wrap='".$form_wrap."'" : "");
  3489. $style = ($form_style ? " style='".$form_style."'" : "");
  3490. return "\n<textarea class='tbox' cols='".$form_columns."' rows='".$form_rows."' ".$name.$form_js.$style.$wrap.$readonly.$tooltip.">".$form_value."</textarea>";
  3491. }
  3492. function form_checkbox($form_name, $form_value, $form_checked = 0, $form_tooltip = "", $form_js = "") {
  3493. $name = ($form_name ? " id='".$form_name.$form_value."' name='".$form_name."'" : "");
  3494. $checked = ($form_checked ? " checked='checked'" : "");
  3495. $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : "");
  3496. return "\n<input type='checkbox' value='".$form_value."'".$name.$checked.$tooltip.$form_js." />";
  3497. }
  3498. function form_radio($form_name, $form_value, $form_checked = 0, $form_tooltip = "", $form_js = "") {
  3499. $name = ($form_name ? " id='".$form_name.$form_value."' name='".$form_name."'" : "");
  3500. $checked = ($form_checked ? " checked='checked'" : "");
  3501. $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : "");
  3502. return "\n<input type='radio' value='".$form_value."'".$name.$checked.$tooltip.$form_js." />";
  3503. }
  3504. function form_file($form_name, $form_size, $form_tooltip = "", $form_js = "") {
  3505. $name = ($form_name ? " id='".$form_name."' name='".$form_name."'" : "");
  3506. $tooltip = ($form_tooltip ? " title='".$form_tooltip."'" : "");
  3507. return "<input type='file' class='tbox' size='".$form_size."'".$name.$tooltip.$form_js." />";
  3508. }
  3509. function form_select_open($form_name, $form_js = "") {
  3510. return "\n<select id='".$form_name."' name='".$form_name."' class='tbox' ".$form_js." >";
  3511. }
  3512. function form_select_close() {
  3513. return "\n</select>";
  3514. }
  3515. function form_option($form_option, $form_selected = "", $form_value = "", $form_js = "") {
  3516. $value = ($form_value !== FALSE ? " value='".$form_value."'" : "");
  3517. $selected = ($form_selected ? " selected='selected'" : "");
  3518. return "\n<option".$value.$selected." ".$form_js.">".$form_option."</option>";
  3519. }
  3520. function form_hidden($form_name, $form_value) {
  3521. return "\n<input type='hidden' id='".$form_name."' name='".$form_name."' value='".$form_value."' />";
  3522. }
  3523. function form_close() {
  3524. return "\n</form>";
  3525. }
  3526. }
  3527. /*
  3528. Usage
  3529. echo $rs->form_open("post", e_SELF, "_blank");
  3530. echo $rs->form_text("testname", 100, "this is the value", 100, 0, "tooltip");
  3531. echo $rs->form_button("submit", "testsubmit", "SUBMIT!", "", "Click to submit");
  3532. echo $rs->form_button("reset", "testreset", "RESET!", "", "Click to reset");
  3533. echo $rs->form_textarea("textareaname", 10, 10, "Value", "overflow:hidden");
  3534. echo $rs->form_checkbox("testcheckbox", 1, 1);
  3535. echo $rs->form_checkbox("testcheckbox2", 2);
  3536. echo $rs->form_hidden("hiddenname", "hiddenvalue");
  3537. echo $rs->form_radio("testcheckbox", 1, 1);
  3538. echo $rs->form_radio("testcheckbox", 1);
  3539. echo $rs->form_file("testfile", "20");
  3540. echo $rs->form_select_open("testselect");
  3541. echo $rs->form_option("Option 1");
  3542. echo $rs->form_option("Option 2");
  3543. echo $rs->form_option("Option 3", 1, "defaultvalue");
  3544. echo $rs->form_option("Option 4");
  3545. echo $rs->form_select_close();
  3546. echo $rs->form_close();
  3547. */
  3548. ?>