From 6854cb3f4d8219cf1829e32122eb2502a916eae9 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 1 Feb 2020 09:05:48 +0100 Subject: initial checkin --- includes/class.tpl.php | 1525 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1525 insertions(+) create mode 100644 includes/class.tpl.php (limited to 'includes/class.tpl.php') diff --git a/includes/class.tpl.php b/includes/class.tpl.php new file mode 100644 index 0000000..24b1105 --- /dev/null +++ b/includes/class.tpl.php @@ -0,0 +1,1525 @@ +_uses = array_merge($this->_uses, $args); + } + + public function assign($arg0 = null, $arg1 = null) + { + if (is_string($arg0)) { + $this->_vars[$arg0] = $arg1; + }elseif (is_array($arg0)) { + $this->_vars += $arg0; + }elseif (is_object($arg0)) { + $this->_vars += get_object_vars($arg0); + } + } + + public function getTheme() + { + return $this->_theme; + } + + public function setTheme($theme) + { + // Check available themes + $theme = trim($theme, '/'); + $themes = Flyspray::listThemes(); + if (in_array($theme, $themes)) { + $this->_theme = $theme.'/'; + } else { + $this->_theme = $themes[0].'/'; + } + } + + public function setTitle($title) + { + $this->_title = $title; + } + + public function themeUrl() + { + return sprintf('%sthemes/%s', $GLOBALS['baseurl'], $this->_theme); + } + + public function pushTpl($_tpl) + { + $this->_tpls[] = $_tpl; + } + + public function catch_start() + { + ob_start(); + } + + public function catch_end() + { + $this->_tpls[] = array(ob_get_contents()); + ob_end_clean(); + } + + public function display($_tpl, $_arg0 = null, $_arg1 = null) + { + // if only plain text + if (is_array($_tpl) && count($tpl)) { + echo $_tpl[0]; + return; + } + + // variables part + if (!is_null($_arg0)) { + $this->assign($_arg0, $_arg1); + } + + foreach ($this->_uses as $_var) { + global $$_var; + } + + extract($this->_vars, EXTR_REFS|EXTR_SKIP); + + if (is_readable(BASEDIR . '/themes/' . $this->_theme.'templates/'.$_tpl)) { + require BASEDIR . '/themes/' . $this->_theme.'templates/'.$_tpl; + } elseif (is_readable(BASEDIR . '/themes/CleanFS/templates/'.$_tpl)) { + # if a custom theme folder only contains a fraction of the .tpl files, use the template of the default full theme as fallback. + require BASEDIR . '/themes/CleanFS/templates/'.$_tpl; + } else { + # This is needed to catch times when there is no theme (for example setup pages, where BASEDIR is ../setup/ not ../) + require BASEDIR . "/templates/".$_tpl; + } + } + + public function render() + { + while (count($this->_tpls)) { + $this->display(array_shift($this->_tpls)); + } + } + + public function fetch($tpl, $arg0 = null, $arg1 = null) + { + ob_start(); + $this->display($tpl, $arg0, $arg1); + return ob_get_clean(); + } +} + +class FSTpl extends Tpl +{ + public $_uses = array('fs', 'conf', 'baseurl', 'language', 'proj', 'user'); + + public function get_image($name, $base = true) + { + global $proj, $baseurl; + $pathinfo = pathinfo($name); + $link = sprintf('themes/%s/', $proj->prefs['theme_style']); + if ($pathinfo['dirname'] != '.') { + $link .= $pathinfo['dirname'] . '/'; + $name = $pathinfo['basename']; + } + + $extensions = array('.png', '.gif', '.jpg', '.ico'); + + foreach ($extensions as $ext) { + if (is_file(BASEDIR . '/' . $link . $name . $ext)) { + return ($base) ? ($baseurl . $link . $name . $ext) : ($link . $name . $ext); + } + } + return ''; + } + +} + +/** + * Draws the form start tag and the important anticsrftoken on 'post'-forms + * + * @param string action + * @param string name optional attribute of form tag + * @param string method optional request method, default 'post' + * @param string enctype optional enctype, default 'multipart/form-data' + * @param string attr optional attributes for the form tag, example: 'id="myformid" class="myextracssclass"' + * + * @return string + */ +function tpl_form($action, $name=null, $method=null, $enctype=null, $attr='') +{ + global $baseurl; + + if (null === $method) { + $method='post'; + } + if (null === $enctype) { + $enctype='multipart/form-data'; + } + + if(substr($action,0,4)!='http'){$action=$baseurl.$action;} + return '
'. + ( $method=='post' ? '':''); +} + +/** + * Creates a link to a task + * + * @param array task with properties of a task. It also accepts a task_id, but that requires extra queries executed by this function. + * @param string text optional, by default the FS# + summary of task is used. + * @param bool strict check task permissions by the function too. Extra SQL queries if set true. default false. + * @param array attr extra attributes + * @param array title informations shown when hover over the link (title attribute of the HTML a-tag) + * + * @return string ready for html output + */ +function tpl_tasklink($task, $text = null, $strict = false, $attrs = array(), $title = array('status','summary','percent_complete')) +{ + global $user; + + $params = array(); + + if (!is_array($task) || !isset($task['status_name'])) { + $td_id = (is_array($task) && isset($task['task_id'])) ? $task['task_id'] : $task; + $task = Flyspray::getTaskDetails($td_id, true); + } + + if ($strict === true && (!is_object($user) || !$user->can_view_task($task))) { + return ''; + } + + if (is_object($user) && $user->can_view_task($task)) { + $summary = utf8_substr($task['item_summary'], 0, 64); + } else { + $summary = L('taskmadeprivate'); + } + + if (is_null($text)) { + $text = sprintf('FS#%d - %s', $task['task_id'], Filters::noXSS($summary)); + } elseif(is_string($text)) { + $text = htmlspecialchars(utf8_substr($text, 0, 64), ENT_QUOTES, 'utf-8'); + } else { + //we can't handle non-string stuff here. + return ''; + } + + if (!$task['task_id']) { + return $text; + } + + $title_text = array(); + + foreach($title as $info) + { + switch($info) + { + case 'status': + if ($task['is_closed']) { + $title_text[] = $task['resolution_name']; + $attrs['class'] = 'closedtasklink'; + } else { + $title_text[] = $task['status_name']; + } + break; + + case 'summary': + $title_text[] = $summary; + break; + + case 'assignedto': + if (isset($task['assigned_to_name']) ) { + if (is_array($task['assigned_to_name'])) { + $title_text[] = implode(', ', $task['assigned_to_name']); + } else { + $title_text[] = $task['assigned_to_name']; + } + } + break; + + case 'percent_complete': + $title_text[] = $task['percent_complete'].'%'; + break; + + case 'category': + if ($task['product_category']) { + if (!isset($task['category_name'])) { + $task = Flyspray::getTaskDetails($task['task_id'], true); + } + $title_text[] = $task['category_name']; + } + break; + + // ... more options if necessary + } + } + + $title_text = implode(' | ', $title_text); + + // to store search options + $params = $_GET; + unset($params['do'], $params['action'], $params['task_id'], $params['switch']); + if(isset($params['event_number'])){ + # shorter links to tasks from report page + unset($params['events'], $params['event_number'], $params['fromdate'], $params['todate'], $params['submit']); + } + + # We can unset the project param for shorter urls because flyspray knows project_id from current task data. + # Except we made a search from an 'all projects' view before, so the prev/next navigation on details page knows + # if it must search only in the project of current task or all projects the user is allowed to see tasks. + if(!isset($params['advancedsearch']) || (isset($params['project']) && $params['project']!=0) ){ + unset($params['project']); + } + + $url = htmlspecialchars(createURL('details', $task['task_id'], null, $params), ENT_QUOTES, 'utf-8'); + $title_text = htmlspecialchars($title_text, ENT_QUOTES, 'utf-8'); + $link = sprintf('%s',$url, $title_text, join_attrs($attrs), $text); + + if ($task['is_closed']) { + $link = ' ' . $link . ' '; + } + return $link; +} + +/* + * Creates a textlink to a user profile. + * + * For a link with user icon use tpl_userlinkavatar(). + * + * @param int uid user_id from {users} db table + */ +function tpl_userlink($uid) +{ + global $db, $user; + + static $cache = array(); + + if (is_array($uid)) { + list($uid, $uname, $rname) = $uid; + } elseif (empty($cache[$uid])) { + $sql = $db->query('SELECT user_name, real_name FROM {users} WHERE user_id = ?', + array(intval($uid))); + if ($sql && $db->countRows($sql)) { + list($uname, $rname) = $db->fetchRow($sql); + } + } + + if (isset($uname)) { + #$url = createURL(($user->perms('is_admin')) ? 'edituser' : 'user', $uid); + # peterdd: I think it is better just to link to the user's page instead direct to the 'edit user' page also for admins. + # With more personalisation coming (personal todo list, charts, ..) in future to flyspray + # the user page itself is of increasing value. Instead show the 'edit user'-button on user's page. + $url = createURL('user', $uid); + $cache[$uid] = vsprintf('%s', array_map(array('Filters', 'noXSS'), array($url, $rname))); + } elseif (empty($cache[$uid])) { + $cache[$uid] = eL('anonymous'); + } + + return $cache[$uid]; +} + +/** +* Builds the HTML string for displaying a gravatar image or an uploaded user image. +* The string for a user and a size is cached per request. +* +* Class and style parameter should be avoided to make this function more effective for caching (less SQL queries) +* +* @param int uid the id of the user +* @param int size in pixel for displaying. Should use global max_avatar_size pref setting by default. +* @param string class optional, avoid calling with class parameter for better 'cacheability' +* @param string style optional, avoid calling with style parameter for better 'cacheability' +*/ +function tpl_userlinkavatar($uid, $size, $class='', $style='') +{ + global $db, $user, $baseurl, $fs; + + static $avacache=array(); + + if( !($uid>0) ){ + return ''; + } + + if($uid>0 && (empty($avacache[$uid]) || !isset($avacache[$uid][$size]))){ + if (!isset($avacache[$uid]['uname'])) { + $sql = $db->query('SELECT user_name, real_name, email_address, profile_image FROM {users} WHERE user_id = ?', array(intval($uid))); + if ($sql && $db->countRows($sql)) { + list($uname, $rname, $email, $profile_image) = $db->fetchRow($sql); + } else { + return; + } + $avacache[$uid]['profile_image'] = $profile_image; + $avacache[$uid]['uname'] = $uname; + $avacache[$uid]['rname'] = $rname; + $avacache[$uid]['email'] = $email; + } + + if (is_file(BASEDIR.'/avatars/'.$avacache[$uid]['profile_image'])) { + $image = ''; + } else { + if (isset($fs->prefs['gravatars']) && $fs->prefs['gravatars'] == 1) { + $email = md5(strtolower(trim($avacache[$uid]['email']))); + $default = 'mm'; + $imgurl = '//www.gravatar.com/avatar/'.$email.'?d='.urlencode($default).'&s='.$size; + $image = ''; + } else { + $image = ''; + } + } + if (isset($avacache[$uid]['uname'])) { + #$url = createURL(($user->perms('is_admin')) ? 'edituser' : 'user', $uid); + # peterdd: I think it is better just to link to the user's page instead direct to the 'edit user' page also for admins. + # With more personalisation coming (personal todo list, charts, ..) in future to flyspray + # the user page itself is of increasing value. Instead show the 'edit user'-button on user's page. + $url = createURL('user', $uid); + $avacache[$uid][$size] = ''.$image.''; + } + } + return $avacache[$uid][$size]; +} + +function tpl_fast_tasklink($arr) +{ + return tpl_tasklink($arr[1], $arr[0]); +} + +/** + * Formats a task tag for HTML output based on a global $alltags array + * + * @param int id tag_id of {list_tag} db table + * @param bool showid set true if the tag_id is shown instead of the tag_name + * + * @return string ready for output + */ +function tpl_tag($id, $showid=false) { + global $alltags; + + if(!is_array($alltags)) { + $alltags=Flyspray::getAllTags(); + } + + if(isset($alltags[$id])){ + $out=''; + } + + $out.=''; + return $out; + } +} + +/** +* Convert a hexa decimal color code to its RGB equivalent +* +* used by tpl_tag() +* +* @param string $hexstr (hexadecimal color value) +* @param boolean $returnasstring (if set true, returns the value separated by the separator character. Otherwise returns associative array) +* @param string $seperator (to separate RGB values. Applicable only if second parameter is true.) +* @return array or string (depending on second parameter. Returns False if invalid hex color value) +* +* function is adapted from an exmaple on http://php.net/manual/de/function.hexdec.php +*/ +function hex2RGB($hexstr, $returnasstring = false, $seperator = ',') { + $hexstr = preg_replace("/[^0-9A-Fa-f]/", '', $hexstr); // Gets a proper hex string + $rgb = array(); + if (strlen($hexstr) == 6) { // if a proper hex code, convert using bitwise operation. No overhead... faster + $colorval = hexdec($hexstr); + $rgb['r'] = 0xFF & ($colorval >> 0x10); + $rgb['g'] = 0xFF & ($colorval >> 0x8); + $rgb['b'] = 0xFF & $colorval; + } elseif (strlen($hexstr) == 3) { // if shorthand notation, need some string manipulations + $rgb['r'] = hexdec(str_repeat(substr($hexstr, 0, 1), 2)); + $rgb['g'] = hexdec(str_repeat(substr($hexstr, 1, 1), 2)); + $rgb['b'] = hexdec(str_repeat(substr($hexstr, 2, 1), 2)); + } else { + return false; // invalid hex color code + } + return $returnasstring ? implode($seperator, $rgb) : $rgb; // returns the rgb string or the associative array +} + +/** + * joins an array of tag attributes together for output in a HTML tag. + * + * @param array attr + * + * @return string + */ +function join_attrs($attr = null) { + if (is_array($attr) && count($attr)) { + $arr = array(); + foreach ($attr as $key=>$val) { + $arr[] = vsprintf('%s = "%s"', array_map(array('Filters', 'noXSS'), array($key, $val))); + } + return ' '.join(' ', $arr); + } + return ''; +} + +/** + * Datepicker + */ +function tpl_datepicker($name, $label = '', $value = 0) { + global $user, $page; + + $date = ''; + + if ($value) { + if (!is_numeric($value)) { + $value = strtotime($value); + } + + if (!$user->isAnon()) { + $st = date('Z')/3600; // server GMT timezone + $value += ($user->infos['time_zone'] - $st) * 60 * 60; + } + + $date = date('Y-m-d', intval($value)); + + /* It must "look" as a date.. + * XXX : do not blindly copy this code to validate other dates + * this is mostly a tongue-in-cheek validation + * 1. it will fail on 32 bit systems on dates < 1970 + * 2. it will produce different results bewteen 32 and 64 bit systems for years < 1970 + * 3. it will not work when year > 2038 on 32 bit systems (see http://en.wikipedia.org/wiki/Year_2038_problem) + * + * Fortunately tasks are never opened to be dated on 1970 and maybe our sons or the future flyspray + * coders may be willing to fix the 2038 issue ( in the strange case 32 bit systems are still used by that year) :-) + */ + + } elseif (Req::has($name) && strlen(Req::val($name))) { + + //strtotime sadly returns -1 on faliure in php < 5.1 instead of false + $ts = strtotime(Req::val($name)); + + foreach (array('m','d','Y') as $period) { + //checkdate only accepts arguments of type integer + $$period = intval(date($period, $ts)); + } + // $ts has to be > 0 to get around php behavior change + // false is casted to 0 by the ZE + $date = ($ts > 0 && checkdate($m, $d, $Y)) ? Req::val($name) : ''; + } + + + $subPage = new FSTpl; + $subPage->setTheme($page->getTheme()); + $subPage->assign('name', $name); + $subPage->assign('date', $date); + $subPage->assign('label', $label); + $subPage->assign('dateformat', '%Y-%m-%d'); + $subPage->display('common.datepicker.tpl'); +} + +/** + * user selector + */ +function tpl_userselect($name, $value = null, $id = '', $attrs = array()) { + global $db, $user, $proj; + + if (!$id) { + $id = $name; + } + + if ($value && ctype_digit($value)) { + $sql = $db->query('SELECT user_name FROM {users} WHERE user_id = ?', array($value)); + $value = $db->fetchOne($sql); + } + + if (!$value) { + $value = ''; + } + + + $page = new FSTpl; + $page->setTheme($proj->prefs['theme_style']); + $page->assign('name', $name); + $page->assign('id', $id); + $page->assign('value', $value); + $page->assign('attrs', $attrs); + $page->display('common.userselect.tpl'); +} + +/** + * Creates the options for a date format select + * + * @selected The format that should by selected by default + * @return html formatted options for a select tag +**/ +function tpl_date_formats($selected, $detailed = false) +{ + $time = time(); + + # TODO: rewrite using 'return tpl_select(...)' + if (!$detailed) { + $dateFormats = array( + '%d.%m.%Y' => strftime('%d.%m.%Y', $time).' (DD.MM.YYYY)', # popular in many european countries + '%d/%m/%Y' => strftime('%d/%m/%Y', $time).' (DD/MM/YYYY)', # popular in Greek + '%m/%d/%Y' => strftime('%m/%d/%Y', $time).' (MM/DD/YYYY)', # popular in USA + + '%d.%m.%y' => strftime('%d.%m.%y', $time), + + '%Y.%m.%d' => strftime('%Y.%m.%d', $time), + '%y.%m.%d' => strftime('%y.%m.%d', $time), + + '%d-%m-%Y' => strftime('%d-%m-%Y', $time), + '%d-%m-%y' => strftime('%d-%m-%y', $time), + + '%Y-%m-%d' => strftime('%Y-%m-%d', $time).' (YYYY-MM-DD, ISO 8601)', + '%y-%m-%d' => strftime('%y-%m-%d', $time), + + '%d %b %Y' => strftime('%d %b %Y', $time), + '%d %B %Y' => strftime('%d %B %Y', $time), + + '%b %d %Y' => strftime('%b %d %Y', $time), + '%B %d %Y' => strftime('%B %d %Y', $time), + ); + } + else { + # TODO: maybe use optgroups for tpl_select() to separate 24h and 12h (am/pm) formats + $dateFormats = array( + '%d.%m.%Y %H:%M' => strftime('%d.%m.%Y %H:%M', $time), + '%d.%m.%y %H:%M' => strftime('%d.%m.%y %H:%M', $time), + + '%d.%m.%Y %I:%M %p' => strftime('%d.%m.%Y %I:%M %p', $time), + '%d.%m.%y %I:%M %p' => strftime('%d.%m.%y %I:%M %p', $time), + + '%Y.%m.%d %H:%M' => strftime('%Y.%m.%d %H:%M', $time), + '%y.%m.%d %H:%M' => strftime('%y.%m.%d %H:%M', $time), + + '%Y.%m.%d %I:%M %p' => strftime('%Y.%m.%d %I:%M %p', $time), + '%y.%m.%d %I:%M %p' => strftime('%y.%m.%d %I:%M %p', $time), + + '%d-%m-%Y %H:%M' => strftime('%d-%m-%Y %H:%M', $time), + '%d-%m-%y %H:%M' => strftime('%d-%m-%y %H:%M', $time), + + '%d-%m-%Y %I:%M %p' => strftime('%d-%m-%Y %I:%M %p', $time), + '%d-%m-%y %I:%M %p' => strftime('%d-%m-%y %I:%M %p', $time), + + '%Y-%m-%d %H:%M' => strftime('%Y-%m-%d %H:%M', $time), + '%y-%m-%d %H:%M' => strftime('%y-%m-%d %H:%M', $time), + + '%Y-%m-%d %I:%M %p' => strftime('%Y-%m-%d %I:%M %p', $time), + '%y-%m-%d %I:%M %p' => strftime('%y-%m-%d %I:%M %p', $time), + + '%d %b %Y %H:%M' => strftime('%d %b %Y %H:%M', $time), + '%d %B %Y %H:%M' => strftime('%d %B %Y %H:%M', $time), + + '%d %b %Y %I:%M %p' => strftime('%d %b %Y %I:%M %p', $time), + '%d %B %Y %I:%M %p' => strftime('%d %B %Y %I:%M %p', $time), + + '%b %d %Y %H:%M' => strftime('%b %d %Y %H:%M', $time), + '%B %d %Y %H:%M' => strftime('%B %d %Y %H:%M', $time), + + '%b %d %Y %I:%M %p' => strftime('%b %d %Y %I:%M %p', $time), + '%B %d %Y %I:%M %p' => strftime('%B %d %Y %I:%M %p', $time), + ); + } + + return tpl_options($dateFormats, $selected); +} + + +/** + * Options for a '; + return $html; +} + +/** + * called by tpl_select() + * + * @author peterdd + * + * @param array key-values pairs and can be nested + * + * @return string option- and optgroup-tags as one string + * + * @since 1.0.0-beta3 + * + * called recursively by itself + * Can also be called alone from template if the templates writes the wrapping select-tags. + * + * @example see [options]-array of example of tpl_select() + */ +function tpl_selectoptions($options=array(), $level=0){ + $html=''; + # such deep nesting is too weired - probably an endless loop lets + # return before something bad happens + if( $level>10){ + return; + } + #print_r($options); + #print_r($level); + foreach($options as $o){ + if(isset($o['optgroup'])){ + # we have an optgroup + $html.="\n".str_repeat("\t",$level).'$val){ + $html.=' '.$key.'="'.htmlspecialchars($val, ENT_QUOTES, 'utf-8').'"'; + } + } + $html.='>'; + # may contain options and suboptgroups.. + $html.=tpl_selectoptions($o['options'], $level+1); + $html.="\n".str_repeat("\t",$level).''; + } else{ + # we have a simple option + $html.="\n".str_repeat("\t",$level).''; + } + } + + return $html; +} + + +/** + * Creates a double select. + * + * Elements of arrays $options and $selected can be moved between eachother. The $selected list can also be sorted. + * + * @param string name + * @param array options + * @param array selected + * @param bool labelisvalue + * @param bool updown + */ +function tpl_double_select($name, $options, $selected = null, $labelisvalue = false, $updown = true) +{ + static $_id = 0; + static $tpl = null; + + if (!$tpl) { + global $proj; + + // poor man's cache + $tpl = new FSTpl(); + $tpl->setTheme($proj->prefs['theme_style']); + } + + settype($selected, 'array'); + settype($options, 'array'); + + $tpl->assign('id', '_task_id_'.($_id++)); + $tpl->assign('name', $name); + $tpl->assign('selected', $selected); + $tpl->assign('updown', $updown); + + $html = $tpl->fetch('common.dualselect.tpl'); + + $selectedones = array(); + + $opt1 = ''; + foreach ($options as $value => $label) { + if (is_array($label) && count($label) >= 2) { + $value = $label[0]; + $label = $label[1]; + } + if ($labelisvalue) { + $value = $label; + } + if (in_array($value, $selected)) { + $selectedones[$value] = $label; + continue; + } + $label = htmlspecialchars($label, ENT_QUOTES, 'utf-8'); + $value = htmlspecialchars($value, ENT_QUOTES, 'utf-8'); + + $opt1 .= sprintf('', $value, $label); + } + + $opt2 = ''; + foreach ($selected as $value) { + if (!isset($selectedones[$value])) { + continue; + } + $label = htmlspecialchars($selectedones[$value], ENT_QUOTES, 'utf-8'); + $value = htmlspecialchars($value, ENT_QUOTES, 'utf-8'); + + $opt2 .= sprintf('', $value, $label); + } + + return sprintf($html, $opt1, $opt2); +} + +/** + * Creates a HTML checkbox + * + * @param string name + * @param bool checked + * @param string id id attribute of the checkbox HTML element + * @param string value + * @param array attr tag attributes + * + * @return string for ready for HTML output + */ +function tpl_checkbox($name, $checked = false, $id = null, $value = 1, $attr = null) +{ + $name = htmlspecialchars($name, ENT_QUOTES, 'utf-8'); + $value = htmlspecialchars($value, ENT_QUOTES, 'utf-8'); + $html = sprintf(''; +} + +/** + * Image display + */ +function tpl_img($src, $alt = '') +{ + global $baseurl; + if (is_file(BASEDIR .'/'.$src)) { + return sprintf('%s', $baseurl, Filters::noXSS($src), Filters::noXSS($alt)); + } + return Filters::noXSS($alt); +} + +// Text formatting +//format has been already checked in constants.inc.php +if(isset($conf['general']['syntax_plugin'])) { + + $path_to_plugin = BASEDIR . '/plugins/' . $conf['general']['syntax_plugin'] . '/' . $conf['general']['syntax_plugin'] . '_formattext.inc.php'; + + if (is_readable($path_to_plugin)) { + include($path_to_plugin); + } +} + +class TextFormatter +{ + public static function get_javascript() + { + global $conf; + + $path_to_plugin = sprintf('%s/plugins/%s', BASEDIR, $conf['general']['syntax_plugin']); + $return = array(); + + if (!is_readable($path_to_plugin)) { + return $return; + } + + $d = dir($path_to_plugin); + while (false !== ($entry = $d->read())) { + if (substr($entry, -3) == '.js') { + $return[] = $conf['general']['syntax_plugin'] . '/' . $entry; + } + } + + return $return; + } + + public static function render($text, $type = null, $id = null, $instructions = null) + { + global $conf; + + $methods = get_class_methods($conf['general']['syntax_plugin'] . '_TextFormatter'); + $methods = is_array($methods) ? $methods : array(); + + if (in_array('render', $methods)) { + return call_user_func(array($conf['general']['syntax_plugin'] . '_TextFormatter', 'render'), + $text, $type, $id, $instructions); + } else { + $text=strip_tags($text, '

    1. '); + if ( $conf['general']['syntax_plugin'] + && $conf['general']['syntax_plugin'] != 'none' + && $conf['general']['syntax_plugin'] != 'html') { + $text='Unsupported output plugin '.$conf['general']['syntax_plugin'].'!' + .'
      Couldn\'t call '.$conf['general']['syntax_plugin'].'_TextFormatter::render()' + .'
      Temporarily handled like it is HTML until fixed.
      ' + .$text; + } + + //TODO: Remove Redundant Code once tested completely + //Author: Steve Tredinnick + //Have removed this as creating additional
      lines even though

      is already dealing with it + //possibly an conversion from Dokuwiki syntax to html issue, left in in case anyone has issues and needs to comment out + //$text = ' ' . nl2br($text) . ' '; + + // Change FS#123 into hyperlinks to tasks + return preg_replace_callback("/\b(?:FS#|bug )(\d+)\b/", 'tpl_fast_tasklink', trim($text)); + } + } + + public static function textarea($name, $rows, $cols, $attrs = null, $content = null) + { + global $conf; + + if (@in_array('textarea', get_class_methods($conf['general']['syntax_plugin'] . '_TextFormatter'))) { + return call_user_func(array($conf['general']['syntax_plugin'] . '_TextFormatter', 'textarea'), + $name, $rows, $cols, $attrs, $content); + } + + $name = htmlspecialchars($name, ENT_QUOTES, 'utf-8'); + $return = sprintf('