| Total Complexity | 274 |
| Total Lines | 1363 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like Html often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Html, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 22 | class Html |
||
| 23 | { |
||
| 24 | /** |
||
| 25 | * Automatically turn on enhanced selectboxes if there's more than this many options |
||
| 26 | */ |
||
| 27 | const SELECT_ENHANCED_ROW_COUNT = 12; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * activates URLs in a text, URLs get replaced by html-links |
||
| 31 | * |
||
| 32 | * @param string $content text containing URLs |
||
| 33 | * @return string html with activated links |
||
| 34 | */ |
||
| 35 | static function activate_links($content) |
||
| 36 | { |
||
| 37 | if (!$content || strlen($content) < 20) return $content; // performance |
||
| 38 | |||
| 39 | // Exclude everything which is already a link |
||
| 40 | $NotAnchor = '(?<!"|href=|href\s=\s|href=\s|href\s=)'; |
||
| 41 | |||
| 42 | // spamsaver emailaddress |
||
| 43 | $result = preg_replace('/'.$NotAnchor.'mailto:([a-z0-9._-]+)@([a-z0-9_-]+)\.([a-z0-9._-]+)/i', |
||
| 44 | "<a href=\"mailto:$1@$2.$3\" target=\"_blank\">$1 AT $2 DOT $3</a>", |
||
| 45 | $content); |
||
| 46 | |||
| 47 | // First match things beginning with http:// (or other protocols) |
||
| 48 | $optBracket0 = '(<|<)'; |
||
| 49 | $Protocol = '(http:\/\/|(ftp:\/\/|https:\/\/))'; // only http:// gets removed, other protocolls are shown |
||
| 50 | $Domain = '([\w-]+\.[\w\-.]+)'; |
||
| 51 | $Subdir = '([\w\-\.,@?^=%&;:\/~\+#]*[\w\-\@?^=%&\/~\+#])?'; |
||
| 52 | $optBracket = '(>|>)'; |
||
| 53 | $Expr = '/' .$optBracket0. $NotAnchor . $Protocol . $Domain . $Subdir . $optBracket . '/i'; |
||
| 54 | // use preg_replace_callback as we experienced problems with https links |
||
| 55 | $result2 = preg_replace_callback($Expr, function ($match) |
||
| 56 | { |
||
| 57 | return $match[1]."<a href=\"".($match[2]&&!$match[3]?$match[2]:'').($match[3]?$match[3]:'').$match[4].$match[5]."\" target=\"_blank\">".$match[4].$match[5]."</a>".$match[6]; |
||
| 58 | }, $result); |
||
| 59 | |||
| 60 | if (true) // hack to keep IDE from complaing about double assignments |
||
| 61 | { |
||
| 62 | // First match things beginning with http:// (or other protocols) |
||
| 63 | $Protocol = '(http:\/\/|(ftp:\/\/|https:\/\/))'; // only http:// gets removed, other protocolls are shown |
||
| 64 | $Domain = '([\w-]+\.[\w\-.]+)'; |
||
| 65 | $Subdir = '([\w\-\.,@?^=%&;:\/~\+#]*[\w\-\@?^=%&\/~\+#])?'; |
||
| 66 | $optStuff = '("|"|;)?'; |
||
| 67 | $Expr = '/' . $NotAnchor . $Protocol . $Domain . $Subdir . $optStuff . '/i'; |
||
| 68 | // use preg_replace_callback as we experienced problems with https links |
||
| 69 | $result3 = preg_replace_callback($Expr, function ($match) |
||
| 70 | { |
||
| 71 | $additionalQuote="";//at the end, ... |
||
| 72 | // only one " at the end is found. chance is, it is not belonging to the URL |
||
| 73 | if ($match[5]==';' && (strlen($match[4])-6) >=0 && strpos($match[4],'"',strlen($match[4])-6)!==false && strpos(substr($match[4],0,strlen($match[4])-6),'"')===false) |
||
| 74 | { |
||
| 75 | $match[4] = substr($match[4],0,strpos($match[4],'"',strlen($match[4])-6)); |
||
| 76 | $additionalQuote = """; |
||
| 77 | } |
||
| 78 | // if there is quoted stuff within the URL then we have at least one more " in match[4], so chance is the last " is matched by the one within |
||
| 79 | if ($match[5]==';' && (strlen($match[4])-6) >=0 && strpos($match[4],'"',strlen($match[4])-6)!==false && strpos(substr($match[4],0,strlen($match[4])-6),'"')!==false) |
||
| 80 | { |
||
| 81 | $match[4] .= $match[5]; |
||
| 82 | } |
||
| 83 | if ($match[5]==';'&&$match[4]==""") |
||
| 84 | { |
||
| 85 | $match[4] =''; |
||
| 86 | $additionalQuote = """; |
||
| 87 | } |
||
| 88 | //error_log(__METHOD__.__LINE__.array2string($match)); |
||
| 89 | return "<a href=\"".($match[1]&&!$match[2]?$match[1]:'').($match[2]?$match[2]:'').$match[3].$match[4]."\" target=\"_blank\">".$match[3].$match[4]."</a>$additionalQuote"; |
||
| 90 | }, $result2); |
||
| 91 | |||
| 92 | // Now match things beginning with www. |
||
| 93 | $optBracket0 = '(<|<)?'; |
||
| 94 | $NotHTTP = '(?<!:\/\/|" target=\"_blank\">)'; // avoid running again on http://www links already handled above |
||
| 95 | $Domain2 = 'www(\.[\w\-.]+)'; |
||
| 96 | $Subdir2 = '([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?'; |
||
| 97 | $optBracket = '(>|>|>|;)?'; |
||
| 98 | $Expr = '/' .$optBracket0. $NotAnchor . $NotHTTP . $Domain2 . $Subdir2 .$optBracket. '/i'; |
||
| 99 | //$Expr = '/' . $NotAnchor . $NotHTTP . $Domain . $Subdir . $optBracket . '/i'; |
||
| 100 | // use preg_replace_callback as we experienced problems with links such as <www.example.tld/pfad/zu/einer/pdf-Datei.pdf> |
||
| 101 | $result4 = preg_replace_callback( $Expr, function ($match) { |
||
| 102 | //error_log(__METHOD__.__LINE__.array2string($match)); |
||
| 103 | if ($match[4]==';' && (strlen($match[3])-4) >=0 && strpos($match[3],'>',strlen($match[3])-4)!==false) |
||
| 104 | { |
||
| 105 | $match[3] = substr($match[3],0,strpos($match[3],'>',strlen($match[3])-4)); |
||
| 106 | $match[4] = ">"; |
||
| 107 | } |
||
| 108 | if ($match[4]==';'&&$match[3]==">") |
||
| 109 | { |
||
| 110 | $match[3] =''; |
||
| 111 | $match[4] = ">"; |
||
| 112 | } |
||
| 113 | //error_log(__METHOD__.__LINE__.array2string($match)); |
||
| 114 | return $match[1]."<a href=\"http://www".$match[2].$match[3]."\" target=\"_blank\">"."www".$match[2].$match[3]."</a>".$match[4]; |
||
| 115 | }, $result3 ); |
||
| 116 | } |
||
| 117 | return $result4; |
||
| 118 | } |
||
| 119 | |||
| 120 | /** |
||
| 121 | * escapes chars with special meaning in html as entities |
||
| 122 | * |
||
| 123 | * Allows to use and char in the html-output and prevents XSS attacks. |
||
| 124 | * Some entities are allowed and get NOT escaped: -> prevented by 4th param = doubleencode=false |
||
| 125 | * - &# some translations (AFAIK: the arabic ones) need this; |
||
| 126 | * - < > for convenience -> should not happen anymore, as we do not doubleencode anymore (20101020) |
||
| 127 | * |
||
| 128 | * @param string $str string to escape |
||
| 129 | * @param boolean $double_encoding =false do we want double encoding or not, default no |
||
| 130 | * @return string |
||
| 131 | */ |
||
| 132 | static function htmlspecialchars($str, $double_encoding=false) |
||
| 133 | { |
||
| 134 | return htmlspecialchars($str,ENT_COMPAT,Translation::charset(),$double_encoding); |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * allows to show and select one item from an array |
||
| 139 | * |
||
| 140 | * @param string $name string with name of the submitted var which holds the key of the selected item form array |
||
| 141 | * @param string|array $key key(s) of already selected item(s) from $arr, eg. '1' or '1,2' or array with keys |
||
| 142 | * @param array $arr array with items to select, eg. $arr = array ( 'y' => 'yes','n' => 'no','m' => 'maybe'); |
||
| 143 | * @param boolean $no_lang NOT run the labels of the options through lang(), default false=use lang() |
||
| 144 | * @param string $options additional options (e.g. 'width') |
||
| 145 | * @param int $multiple number of lines for a multiselect, default 0 = no multiselect, < 0 sets size without multiple |
||
| 146 | * @param boolean $enhanced Use enhanced selectbox with search. Null for default yes if more than 12 options. |
||
| 147 | * @return string to set for a template or to echo into html page |
||
| 148 | */ |
||
| 149 | static function select($name, $key, $arr=0,$no_lang=false,$options='',$multiple=0,$enhanced=null) |
||
| 150 | { |
||
| 151 | if(is_null($enhanced)) $enhanced = false; //disabled by default (count($arr) > self::SELECT_ENHANCED_ROW_COUNT); |
||
| 152 | |||
| 153 | if (!is_array($arr)) |
||
| 154 | { |
||
| 155 | $arr = array('no','yes'); |
||
| 156 | } |
||
| 157 | if ((int)$multiple > 0) |
||
| 158 | { |
||
| 159 | $options .= ' multiple="1" size="'.(int)$multiple.'"'; |
||
| 160 | if (substr($name,-2) != '[]') |
||
| 161 | { |
||
| 162 | $name .= '[]'; |
||
| 163 | } |
||
| 164 | } |
||
| 165 | elseif($multiple < 0) |
||
| 166 | { |
||
| 167 | $options .= ' size="'.abs($multiple).'"'; |
||
| 168 | } |
||
| 169 | // fix width for MSIE < 9 in/for selectboxes |
||
| 170 | if (Header\UserAgent::type() == 'msie' && Header\UserAgent::version() < 9) |
||
| 171 | { |
||
| 172 | if (stripos($options,'onfocus="') === false) |
||
| 173 | { |
||
| 174 | $options .= ' onfocus="window.dropdown_menu_hack(this);" '; |
||
| 175 | } |
||
| 176 | else |
||
| 177 | { |
||
| 178 | $options = str_ireplace('onfocus="','onfocus="window.dropdown_menu_hack(this);',$options); |
||
| 179 | } |
||
| 180 | } |
||
| 181 | $out = "<select name=\"$name\" $options>\n"; |
||
| 182 | |||
| 183 | if (!is_array($key)) |
||
| 184 | { |
||
| 185 | // explode on ',' only if multiple values expected and the key contains just numbers and commas |
||
| 186 | $key = $multiple > 0 && preg_match('/^[,0-9]+$/',$key) ? explode(',',$key) : array($key); |
||
| 187 | } |
||
| 188 | foreach($arr as $k => $data) |
||
| 189 | { |
||
| 190 | if (!is_array($data) || count($data) == 2 && isset($data['label']) && isset($data['title'])) |
||
| 191 | { |
||
| 192 | $out .= self::select_option($k,is_array($data)?$data['label']:$data,$key,$no_lang, |
||
| 193 | is_array($data)?$data['title']:''); |
||
| 194 | } |
||
| 195 | else |
||
| 196 | { |
||
| 197 | if (isset($data['lable'])) |
||
| 198 | { |
||
| 199 | $k = $data['lable']; |
||
| 200 | unset($data['lable']); |
||
| 201 | } |
||
| 202 | $out .= '<optgroup label="'.self::htmlspecialchars($no_lang || $k == '' ? $k : lang($k))."\">\n"; |
||
| 203 | |||
| 204 | foreach($data as $k => $label) |
||
|
|
|||
| 205 | { |
||
| 206 | $out .= self::select_option($k,is_array($label)?$label['label']:$label,$key,$no_lang, |
||
| 207 | is_array($label)?$label['title']:''); |
||
| 208 | } |
||
| 209 | $out .= "</optgroup>\n"; |
||
| 210 | } |
||
| 211 | } |
||
| 212 | $out .= "</select>\n"; |
||
| 213 | |||
| 214 | if($enhanced) { |
||
| 215 | Framework::includeJS('/api/js/jquery/chosen/chosen.jquery.js'); |
||
| 216 | Framework::includeCSS('/api/js/jquery/chosen/chosen.css',null,false); |
||
| 217 | $out .= "<script>var lab = egw_LAB || \$LAB; lab.wait(function() {jQuery(function() {if(jQuery().chosen) jQuery('select[name=\"$name\"]').chosen({width: '100%'});});})</script>\n"; |
||
| 218 | } |
||
| 219 | return $out; |
||
| 220 | } |
||
| 221 | |||
| 222 | /** |
||
| 223 | * emulating a multiselectbox using checkboxes |
||
| 224 | * |
||
| 225 | * Unfortunaly this is not in all aspects like a multi-selectbox, eg. you cant select options via javascript |
||
| 226 | * in the same way. Therefor I made it an extra function. |
||
| 227 | * |
||
| 228 | * @param string $name string with name of the submitted var which holds the key of the selected item form array |
||
| 229 | * @param string|array $key key(s) of already selected item(s) from $arr, eg. '1' or '1,2' or array with keys |
||
| 230 | * @param array $arr array with items to select, eg. $arr = array ( 'y' => 'yes','n' => 'no','m' => 'maybe'); |
||
| 231 | * @param boolean $no_lang NOT run the labels of the options through lang(), default false=use lang() |
||
| 232 | * @param string $options additional options (e.g. 'width') |
||
| 233 | * @param int $multiple number of lines for a multiselect, default 3 |
||
| 234 | * @param boolean $selected_first show the selected items before the not selected ones, default true |
||
| 235 | * @param string $style ='' extra style settings like "width: 100%", default '' none |
||
| 236 | * @return string to set for a template or to echo into html page |
||
| 237 | */ |
||
| 238 | static function checkbox_multiselect($name, $key, $arr=0,$no_lang=false,$options='',$multiple=3,$selected_first=true,$style='',$enhanced = null) |
||
| 239 | { |
||
| 240 | //echo "<p align=right>checkbox_multiselect('$name',".array2string($key).",".array2string($arr).",$no_lang,'$options',$multiple,$selected_first,'$style')</p>\n"; |
||
| 241 | if(is_null($enhanced)) $enhanced = (count($arr) > self::SELECT_ENHANCED_ROW_COUNT); |
||
| 242 | |||
| 243 | if (!is_array($arr)) |
||
| 244 | { |
||
| 245 | $arr = array('no','yes'); |
||
| 246 | } |
||
| 247 | if ((int)$multiple <= 0) $multiple = 1; |
||
| 248 | |||
| 249 | if (substr($name,-2) != '[]') |
||
| 250 | { |
||
| 251 | $name .= '[]'; |
||
| 252 | } |
||
| 253 | $base_name = substr($name,0,-2); |
||
| 254 | |||
| 255 | if($enhanced) return self::select($name, $key, $arr,$no_lang,$options." style=\"$style\" ",$multiple,$enhanced); |
||
| 256 | |||
| 257 | if (!is_array($key)) |
||
| 258 | { |
||
| 259 | // explode on ',' only if multiple values expected and the key contains just numbers and commas |
||
| 260 | $key = preg_match('/^[,0-9]+$/',$key) ? explode(',',$key) : array($key); |
||
| 261 | } |
||
| 262 | $html = ''; |
||
| 263 | $options_no_id = preg_replace('/id="[^"]+"/i','',$options); |
||
| 264 | |||
| 265 | if ($selected_first) |
||
| 266 | { |
||
| 267 | $selected = $not_selected = array(); |
||
| 268 | foreach($arr as $val => $label) |
||
| 269 | { |
||
| 270 | if (in_array((string)$val,$key)) |
||
| 271 | { |
||
| 272 | $selected[$val] = $label; |
||
| 273 | } |
||
| 274 | else |
||
| 275 | { |
||
| 276 | $not_selected[$val] = $label; |
||
| 277 | } |
||
| 278 | } |
||
| 279 | $arr = $selected + $not_selected; |
||
| 280 | } |
||
| 281 | $max_len = 0; |
||
| 282 | foreach($arr as $val => $label) |
||
| 283 | { |
||
| 284 | if (is_array($label)) |
||
| 285 | { |
||
| 286 | $title = $label['title']; |
||
| 287 | $label = $label['label']; |
||
| 288 | } |
||
| 289 | else |
||
| 290 | { |
||
| 291 | $title = ''; |
||
| 292 | } |
||
| 293 | if ($label && !$no_lang) $label = lang($label); |
||
| 294 | if ($title && !$no_lang) $title = lang($title); |
||
| 295 | |||
| 296 | if (strlen($label) > $max_len) $max_len = strlen($label); |
||
| 297 | |||
| 298 | $html .= self::label(self::checkbox($name,in_array((string)$val,$key),$val,$options_no_id. |
||
| 299 | ' id="'.$base_name.'['.$val.']'.'"').self::htmlspecialchars($label), |
||
| 300 | $base_name.'['.$val.']','',($title ? 'title="'.self::htmlspecialchars($title).'" ':''))."<br />\n"; |
||
| 301 | } |
||
| 302 | if ($style && substr($style,-1) != ';') $style .= '; '; |
||
| 303 | if (strpos($style,'height')===false) $style .= 'height: '.(1.7*$multiple).'em; '; |
||
| 304 | if (strpos($style,'width')===false) $style .= 'width: '.(4+$max_len*($max_len < 15 ? 0.65 : 0.6)).'em; '; |
||
| 305 | $style .= 'background-color: white; overflow: auto; border: lightgray 2px inset; text-align: left;'; |
||
| 306 | |||
| 307 | return self::div($html,$options,'',$style); |
||
| 308 | } |
||
| 309 | |||
| 310 | /** |
||
| 311 | * generates an option-tag for a selectbox |
||
| 312 | * |
||
| 313 | * @param string $value value |
||
| 314 | * @param string $label label |
||
| 315 | * @param mixed $selected value or array of values of options to mark as selected |
||
| 316 | * @param boolean $no_lang NOT running the label through lang(), default false=use lang() |
||
| 317 | * @param string $extra extra text, e.g.: style="", default: '' |
||
| 318 | * @return string html |
||
| 319 | */ |
||
| 320 | static function select_option($value,$label,$selected,$no_lang=0,$title='',$extra='') |
||
| 321 | { |
||
| 322 | // the following compares strict as strings, to archive: '0' == 0 != '' |
||
| 323 | // the first non-strict search via array_search, is for performance reasons, to not always search the whole array with php |
||
| 324 | if (($found = ($key = array_search($value,$selected)) !== false) && (string) $value !== (string) $selected[$key]) |
||
| 325 | { |
||
| 326 | $found = false; |
||
| 327 | foreach($selected as $sel) |
||
| 328 | { |
||
| 329 | if (($found = (((string) $value) === ((string) $selected[$key])))) break; |
||
| 330 | } |
||
| 331 | unset($sel); |
||
| 332 | } |
||
| 333 | return '<option value="'.self::htmlspecialchars($value).'"'.($found ? ' selected="selected"' : '') . |
||
| 334 | ($title ? ' title="'.self::htmlspecialchars($no_lang ? $title : lang($title)).'"' : '') . |
||
| 335 | ($extra ? ' ' . $extra : '') . '>'. |
||
| 336 | self::htmlspecialchars($no_lang || $label == '' ? $label : lang($label)) . "</option>\n"; |
||
| 337 | } |
||
| 338 | |||
| 339 | /** |
||
| 340 | * generates a div-tag |
||
| 341 | * |
||
| 342 | * @param string $content of a div, or '' to generate only the opening tag |
||
| 343 | * @param string $options to include in the tag, default ''=none |
||
| 344 | * @param string $class css-class attribute, default ''=none |
||
| 345 | * @param string $style css-styles attribute, default ''=none |
||
| 346 | * @return string html |
||
| 347 | */ |
||
| 348 | static function div($content,$options='',$class='',$style='') |
||
| 349 | { |
||
| 350 | if ($class) $options .= ' class="'.$class.'"'; |
||
| 351 | if ($style) $options .= ' style="'.$style.'"'; |
||
| 352 | |||
| 353 | return "<div $options>\n".($content ? "$content</div>\n" : ''); |
||
| 354 | } |
||
| 355 | |||
| 356 | /** |
||
| 357 | * generate one or more hidden input tag(s) |
||
| 358 | * |
||
| 359 | * @param array|string $vars var-name or array with name / value pairs |
||
| 360 | * @param string $value value if $vars is no array, default '' |
||
| 361 | * @param boolean $ignore_empty if true all empty, zero (!) or unset values, plus filer=none |
||
| 362 | * @param string html |
||
| 363 | */ |
||
| 364 | static function input_hidden($vars,$value='',$ignore_empty=True) |
||
| 365 | { |
||
| 366 | if (!is_array($vars)) |
||
| 367 | { |
||
| 368 | $vars = array( $vars => $value ); |
||
| 369 | } |
||
| 370 | foreach($vars as $name => $value) |
||
| 371 | { |
||
| 372 | if (is_array($value)) |
||
| 373 | { |
||
| 374 | $value = json_encode($value); |
||
| 375 | } |
||
| 376 | if (!$ignore_empty || $value && !($name == 'filter' && $value == 'none')) // dont need to send all the empty vars |
||
| 377 | { |
||
| 378 | $html .= "<input type=\"hidden\" name=\"$name\" value=\"".self::htmlspecialchars($value)."\" />\n"; |
||
| 379 | } |
||
| 380 | } |
||
| 381 | return $html; |
||
| 382 | } |
||
| 383 | |||
| 384 | /** |
||
| 385 | * generate a textarea tag |
||
| 386 | * |
||
| 387 | * @param string $name name attr. of the tag |
||
| 388 | * @param string $value default |
||
| 389 | * @param boolean $ignore_empty if true all empty, zero (!) or unset values, plus filer=none |
||
| 390 | * @param boolean $double_encoding =false do we want double encoding or not, default no |
||
| 391 | * @param string html |
||
| 392 | */ |
||
| 393 | static function textarea($name,$value='',$options='',$double_encoding=false) |
||
| 394 | { |
||
| 395 | return "<textarea name=\"$name\" $options>".self::htmlspecialchars($value,$double_encoding)."</textarea>\n"; |
||
| 396 | } |
||
| 397 | |||
| 398 | /** |
||
| 399 | * Checks if HTMLarea (or an other richtext editor) is availible for the used browser |
||
| 400 | * |
||
| 401 | * @return boolean |
||
| 402 | */ |
||
| 403 | static function htmlarea_availible() |
||
| 408 | } |
||
| 409 | |||
| 410 | /** |
||
| 411 | * compability static function for former used htmlarea. Please use static function fckeditor now! |
||
| 412 | * |
||
| 413 | * creates a textarea inputfield for the htmlarea js-widget (returns the necessary html and js) |
||
| 414 | */ |
||
| 415 | static function htmlarea($name,$content='',$style='',$base_href=''/*,$plugins='',$custom_toolbar='',$set_width_height_in_config=false*/) |
||
| 422 | } |
||
| 423 | |||
| 424 | /** |
||
| 425 | * this static function is a wrapper for fckEditor to create some reuseable layouts |
||
| 426 | * |
||
| 427 | * @param string $_name name and id of the input-field |
||
| 428 | * @param string $_content of the tinymce (will be run through htmlspecialchars !!!), default '' |
||
| 429 | * @param string $_mode display mode of the tinymce editor can be: simple, extended or advanced |
||
| 430 | * @param array $_options (toolbar_expanded true/false) |
||
| 431 | * @param string $_height ='400px' |
||
| 432 | * @param string $_width ='100%' |
||
| 433 | * @param string $_start_path ='' if passed activates the browser for image at absolute path passed |
||
| 434 | * @param boolean $_purify =true run $_content through htmlpurifier before handing it to fckEditor |
||
| 435 | * @param mixed (boolean/string) $_focusToBody=false USED only for CKEDIOR true means yes, focus on top, you may specify TOP or BOTTOM (to focus on the end of the editor area) |
||
| 436 | * @param string $_executeJSAfterInit ='' Javascript to be executed after InstanceReady of CKEditor |
||
| 437 | * @return string the necessary html for the textarea |
||
| 438 | */ |
||
| 439 | static function fckEditor($_name, $_content, $_mode, $_options=array('toolbar_expanded' =>'true'), |
||
| 440 | $_height='400px', $_width='100%',$_start_path='',$_purify=true, $_focusToBody=false, $_executeJSAfterInit='') |
||
| 441 | { |
||
| 442 | //not used anymore but defined in function signature |
||
| 443 | unset ($_options); |
||
| 444 | |||
| 445 | if (!self::htmlarea_availible() || $_mode == 'ascii') |
||
| 446 | { |
||
| 447 | return self::textarea($_name,$_content,'style="width: '.$_width.'; height: '.$_height.';" id="'.htmlspecialchars($_name).'"'); |
||
| 448 | } |
||
| 449 | |||
| 450 | //include the ckeditor js file |
||
| 451 | Framework::includeJS('/vendor/tinymce/tinymce/tinymce.min.js'); |
||
| 452 | |||
| 453 | // run content through htmlpurifier |
||
| 454 | if ($_purify && !empty($_content)) |
||
| 455 | $_content = self::purify($_content); |
||
| 456 | |||
| 457 | // User preferences |
||
| 458 | $font = $GLOBALS['egw_info']['user']['preferences']['common']['rte_font']; |
||
| 459 | $font_size = $GLOBALS['egw_info']['user']['preferences']['common']['rte_font_size']; |
||
| 460 | $font_size_unit = $GLOBALS['egw_info']['user']['preferences']['common']['rte_font_unit']; |
||
| 461 | $rte_menubar = $GLOBALS['egw_info']['user']['preferences']['common']['rte_menubar']; |
||
| 462 | $focusToBody = $_focusToBody ? "tinymce" : false; |
||
| 463 | ContentSecurityPolicy::add('script-src', 'unsafe-inline'); |
||
| 464 | // we need to enable double encoding here, as ckEditor has to undo one level of encoding |
||
| 465 | // otherwise < and > chars eg. from html markup entered in regular (not source) input, will turn into html! |
||
| 466 | //error_log(__METHOD__.__LINE__.' '.Header\UserAgent::type().','.Header\UserAgent::version()); |
||
| 467 | return self::textarea($_name,$_content,'id="'.htmlspecialchars($_name).'"',true). // true = double encoding |
||
| 468 | ' |
||
| 469 | <script type="text/javascript"> |
||
| 470 | |||
| 471 | egw_LAB.wait(function() { |
||
| 472 | |||
| 473 | var imageUpload = egw.ajaxUrl("EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_htmlarea_upload")+"&type=htmlarea"; |
||
| 474 | imageUpload = imageUpload.substr(egw.webserverUrl.length+1); |
||
| 475 | var font_size_formats = { |
||
| 476 | pt: "8pt 10pt 12pt 14pt 18pt 24pt 36pt 48pt 72pt", |
||
| 477 | px:"8px 10px 12px 14px 18px 24px 36px 48px 72px" |
||
| 478 | }; |
||
| 479 | var language_code = { |
||
| 480 | bg: "bg_BG", ca: "ca", cs: "cs", da: "da", de: "de", en:"en_CA", |
||
| 481 | el:"el", "es-es":"es", et: "et", eu: "eu" , fa: "fa_IR", fi: "fi", |
||
| 482 | fr: "fr_FR", hi:"", hr:"hr", hu:"hu_HU", id: "id", it: "it", iw: "", |
||
| 483 | ja: "ja", ko: "ko_KR", lo: "", lt: "lt", lv: "lv", nl: "nl", no: "nb_NO", |
||
| 484 | pl: "pl", pt: "pt_PT", "pt-br": "pt_BR", ru: "ru", sk: "sk", sl: "sl_SI", |
||
| 485 | sv: "sv_SE", th: "th_TH", tr: "tr_TR", uk: "en_GB", vi: "vi_VN", zh: "zh_CN", |
||
| 486 | "zh-tw": "zh_TW" |
||
| 487 | }; |
||
| 488 | var name = "#"+"'.$_name.'".replace( /(:|\.|\[|\]|,|=|@)/g, "\\\$1" ); |
||
| 489 | var height = "'.$_height.'"; |
||
| 490 | var width = "'.$_width.'"; |
||
| 491 | var value = jQuery(name).val(); |
||
| 492 | /** |
||
| 493 | * language code represention for TinyMCE lang code |
||
| 494 | */ |
||
| 495 | var language_code = { |
||
| 496 | bg: "bg_BG", ca: "ca", cs: "cs", da: "da", de: "de", en:"en_CA", |
||
| 497 | el:"el", "es-es":"es", et: "et", eu: "eu" , fa: "fa_IR", fi: "fi", |
||
| 498 | fr: "fr_FR", hi:"", hr:"hr", hu:"hu_HU", id: "id", it: "it", iw: "", |
||
| 499 | ja: "ja", ko: "ko_KR", lo: "", lt: "lt", lv: "lv", nl: "nl", no: "nb_NO", |
||
| 500 | pl: "pl", pt: "pt_PT", "pt-br": "pt_BR", ru: "ru", sk: "sk", sl: "sl_SI", |
||
| 501 | sv: "sv_SE", th: "th_TH", tr: "tr_TR", uk: "en_GB", vi: "vi_VN", zh: "zh_CN", |
||
| 502 | "zh-tw": "zh_TW" |
||
| 503 | }; |
||
| 504 | tinymce.init({ |
||
| 505 | selector: name, |
||
| 506 | menubar: parseInt('. $rte_menubar.')? true : false, |
||
| 507 | branding: false, |
||
| 508 | resize: false, |
||
| 509 | height: height.match(/%/) ? height : parseInt(height), |
||
| 510 | width: width.match(/%/) ? width : parseInt(width), |
||
| 511 | min_height: 200, |
||
| 512 | auto_focus: "'.$focusToBody.'", |
||
| 513 | language: language_code["'. $GLOBALS['egw_info']['user']['preferences']['common']['lang'].'"], |
||
| 514 | language_url: egw.webserverUrl+"/api/js/tinymce/langs/"+language_code[egw.preference("lang", "common")]+".js", |
||
| 515 | browser_spellcheck: true, |
||
| 516 | contextmenu: false, |
||
| 517 | file_picker_callback: function(_callback, _value, _meta){ |
||
| 518 | var callback = _callback; |
||
| 519 | var attrs = { |
||
| 520 | menuaction: "filemanager.filemanager_select.select", |
||
| 521 | mode: "open", |
||
| 522 | method: "download_url", |
||
| 523 | path: "'. $_start_path.'" |
||
| 524 | }; |
||
| 525 | |||
| 526 | // Open the filemanager select in a popup |
||
| 527 | var popup = egw(window).open_link( |
||
| 528 | egw().link("/index.php", attrs), |
||
| 529 | "link_existing", |
||
| 530 | "680x400" |
||
| 531 | ); |
||
| 532 | if(popup) |
||
| 533 | { |
||
| 534 | // Safari and IE lose reference to global variables after window close |
||
| 535 | // Try to get updated data before window is closed then later we trigger |
||
| 536 | // change event on widget |
||
| 537 | egw().window.setTimeout(function(){ |
||
| 538 | jQuery(popup).bind("unload",function(){ |
||
| 539 | callback(this.selected_files, {alt:this.selected_files}); |
||
| 540 | }); |
||
| 541 | },1000); |
||
| 542 | } |
||
| 543 | }, |
||
| 544 | init_instance_callback : function(_editor){ |
||
| 545 | console.log(_editor); |
||
| 546 | _editor.execCommand("fontName", true,"'.$font.'"); |
||
| 547 | _editor.execCommand("fontSize", true,"'.$font_size.$font_size_unit.'"); |
||
| 548 | _editor.setContent(value); |
||
| 549 | }, |
||
| 550 | plugins: [ |
||
| 551 | "print searchreplace autolink directionality "+ |
||
| 552 | "visualblocks visualchars image link media template "+ |
||
| 553 | "codesample table charmap hr pagebreak nonbreaking anchor toc "+ |
||
| 554 | "insertdatetime advlist lists textcolor wordcount imagetools "+ |
||
| 555 | "colorpicker textpattern help paste code searchreplace" |
||
| 556 | ], |
||
| 557 | toolbar: "undo redo | formatselect | fontselect fontsizeselect | bold italic strikethrough forecolor backcolor | "+ |
||
| 558 | "link | alignleft aligncenter alignright alignjustify | numlist "+ |
||
| 559 | "bullist outdent indent | removeformat code| image | searchreplace", |
||
| 560 | block_formats: "Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;"+ |
||
| 561 | "Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre", |
||
| 562 | font_formats: "Andale Mono=andale mono,times;Arial=arial,helvetica,"+ |
||
| 563 | "sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book "+ |
||
| 564 | "antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;"+ |
||
| 565 | "Courier New=courier new,courier;Georgia=georgia,palatino;"+ |
||
| 566 | "Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;"+ |
||
| 567 | "Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,"+ |
||
| 568 | "monaco;Times New Roman=times new roman,times;Trebuchet "+ |
||
| 569 | "MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;"+ |
||
| 570 | "Wingdings=wingdings,zapf dingbats", |
||
| 571 | fontsize_formats:font_size_formats["'. $font_size_unit.'"], |
||
| 572 | }); |
||
| 573 | '.($_executeJSAfterInit?$_executeJSAfterInit:'').' |
||
| 574 | }); |
||
| 575 | </script> |
||
| 576 | '; |
||
| 577 | } |
||
| 578 | |||
| 579 | /** |
||
| 580 | * this static function is a wrapper for tinymce to create some reuseable layouts |
||
| 581 | * |
||
| 582 | * Please note: if you did not run init_tinymce already you this static function need to be called before the call to phpgw_header() !!! |
||
| 583 | * |
||
| 584 | * @param string $_name name and id of the input-field |
||
| 585 | * @param string $_mode display mode of the tinymce editor can be: simple, extended or advanced |
||
| 586 | * @param string $_content ='' of the tinymce (will be run through htmlspecialchars !!!), default '' |
||
| 587 | * @param string $_height ='400px' |
||
| 588 | * @param string $_width ='100%' |
||
| 589 | * @param boolean $_purify =true |
||
| 590 | * @param string $_border ='0px' NOT used for CKEditor |
||
| 591 | * @param mixed (boolean/string) $_focusToBody=false USED only for CKEDIOR true means yes, focus on top, you may specify TOP or BOTTOM (to focus on the end of the editor area) |
||
| 592 | * @param string $_executeJSAfterInit ='' Javascript to be executed after InstanceReady of CKEditor |
||
| 593 | * @return string the necessary html for the textarea |
||
| 594 | */ |
||
| 595 | static function fckEditorQuick($_name, $_mode, $_content='', $_height='400px', $_width='100%',$_purify=true, $_border='0px',$_focusToBody=false,$_executeJSAfterInit='') |
||
| 596 | { |
||
| 597 | if (!self::htmlarea_availible() || $_mode == 'ascii') |
||
| 598 | { |
||
| 599 | //TODO: use self::textarea |
||
| 600 | return "<textarea name=\"$_name\" style=\"".($_width?" width:".$_width.';':" width:100%;").($_height?" height:".$_height.';':" height:400px;").($_border?" border:".$_border.';':" border:0px;")."\">$_content</textarea>"; |
||
| 601 | } |
||
| 602 | else |
||
| 603 | { |
||
| 604 | return self::fckEditor($_name, $_content, $_mode, array(), $_height, $_width,'',$_purify,$_focusToBody,$_executeJSAfterInit); |
||
| 605 | } |
||
| 606 | } |
||
| 607 | |||
| 608 | /** |
||
| 609 | * represents html's input tag |
||
| 610 | * |
||
| 611 | * @param string $name name |
||
| 612 | * @param string $value default value of the field |
||
| 613 | * @param string $type type, default ''=not specified = text |
||
| 614 | * @param string $options attributes for the tag, default ''=none |
||
| 615 | */ |
||
| 616 | static function input($name,$value='',$type='',$options='' ) |
||
| 617 | { |
||
| 618 | switch ((string)$type) |
||
| 619 | { |
||
| 620 | case ''; |
||
| 621 | break; |
||
| 622 | default: |
||
| 623 | $type = 'type="'.htmlspecialchars($type).'"'; |
||
| 624 | } |
||
| 625 | return "<input $type name=\"$name\" value=\"".self::htmlspecialchars($value)."\" $options />\n"; |
||
| 626 | } |
||
| 627 | |||
| 628 | static protected $default_background_images = array( |
||
| 629 | 'save' => '/save(&|\]|$)/', |
||
| 630 | 'apply' => '/apply(&|\]|$)/', |
||
| 631 | 'cancel' => '/cancel(&|\]|$)/', |
||
| 632 | 'delete' => '/delete(&|\]|$)/', |
||
| 633 | 'edit' => '/edit(&|\]|$)/', |
||
| 634 | 'next' => '/(next|continue)(&|\]|$)/', |
||
| 635 | 'finish' => '/finish(&|\]|$)/', |
||
| 636 | 'back' => '/(back|previous)(&|\]|$)/', |
||
| 637 | 'copy' => '/copy(&|\]|$)/', |
||
| 638 | 'more' => '/more(&|\]|$)/', |
||
| 639 | 'check' => '/(yes|check)(&|\]|$)/', |
||
| 640 | 'cancelled' => '/no(&|\]|$)/', |
||
| 641 | 'ok' => '/ok(&|\]|$)/', |
||
| 642 | 'close' => '/close(&|\]|$)/', |
||
| 643 | 'add' => '/(add(&|\]|$)|create)/', // customfields use create* |
||
| 644 | ); |
||
| 645 | |||
| 646 | static protected $default_classes = array( |
||
| 647 | 'et2_button_cancel' => '/cancel(&|\]|$)/', // yellow |
||
| 648 | 'et2_button_question' => '/(yes|no)(&|\]|$)/', // yellow |
||
| 649 | 'et2_button_delete' => '/delete(&|\]|$)/' // red |
||
| 650 | ); |
||
| 651 | |||
| 652 | /** |
||
| 653 | * represents html's button (input type submit or input type button or image) |
||
| 654 | * |
||
| 655 | * @param string $name name |
||
| 656 | * @param string $label label of the button |
||
| 657 | * @param string $onClick javascript to call, when button is clicked |
||
| 658 | * @param boolean $no_lang NOT running the label through lang(), default false=use lang() |
||
| 659 | * @param string $options attributes for the tag, default ''=none |
||
| 660 | * @param string $image to show instead of the label, default ''=none |
||
| 661 | * @param string $app app to search the image in |
||
| 662 | * @param string $buttontype which type of html button (button|submit), default ='submit' |
||
| 663 | * @return string html |
||
| 664 | */ |
||
| 665 | static function submit_button($name,$label,$onClick='',$no_lang=false,$options='',$image='',$app='phpgwapi', $buttontype='submit') |
||
| 666 | { |
||
| 667 | // workaround for idots and IE button problem (wrong cursor-image) |
||
| 668 | if (Header\UserAgent::type() == 'msie') |
||
| 669 | { |
||
| 670 | $options .= ' style="cursor: pointer;"'; |
||
| 671 | } |
||
| 672 | // add et2_classes to "old" buttons |
||
| 673 | $classes = array('et2_button'); |
||
| 674 | |||
| 675 | if ($image != '') |
||
| 676 | { |
||
| 677 | $image = str_replace(array('.gif','.GIF','.png','.PNG'),'',$image); |
||
| 678 | |||
| 679 | if (!($path = Image::find($app, $image))) |
||
| 680 | { |
||
| 681 | $path = $image; // name may already contain absolut path |
||
| 682 | } |
||
| 683 | $image = ' src="'.$path.'"'; |
||
| 684 | $classes[] = 'image_button'; |
||
| 685 | } |
||
| 686 | if (!$no_lang) |
||
| 687 | { |
||
| 688 | $label = lang($label); |
||
| 689 | } |
||
| 690 | if (($accesskey = @strstr($label,'&')) && $accesskey[1] != ' ' && |
||
| 691 | (($pos = strpos($accesskey,';')) === false || $pos > 5)) |
||
| 692 | { |
||
| 693 | $label_u = str_replace('&'.$accesskey[1],'<u>'.$accesskey[1].'</u>',$label); |
||
| 694 | $label = str_replace('&','',$label); |
||
| 695 | $options .= ' accesskey="'.$accesskey[1].'" '.$options; |
||
| 696 | } |
||
| 697 | else |
||
| 698 | { |
||
| 699 | $accesskey = ''; |
||
| 700 | $label_u = $label; |
||
| 701 | } |
||
| 702 | if ($onClick) $options .= ' onclick="'.str_replace('"','\\"',$onClick).'"'; |
||
| 703 | |||
| 704 | // add default background-image to get et2 like buttons |
||
| 705 | foreach(self::$default_background_images as $img => $reg_exp) |
||
| 706 | { |
||
| 707 | if (preg_match($reg_exp, $name) && ($url = Image::find($GLOBALS['egw_info']['flags']['currentapp'], $img))) |
||
| 708 | { |
||
| 709 | $options .= ' style="background-image: url('.$url.');"'; |
||
| 710 | $classes[] = 'et2_button_with_image et2_button_text'; |
||
| 711 | break; |
||
| 712 | } |
||
| 713 | } |
||
| 714 | // add default class for cancel, delete or yes/no buttons |
||
| 715 | foreach(self::$default_classes as $class => $reg_exp) |
||
| 716 | { |
||
| 717 | if (preg_match($reg_exp, $name)) |
||
| 718 | { |
||
| 719 | $classes[] = $class; |
||
| 720 | break; |
||
| 721 | } |
||
| 722 | } |
||
| 723 | if (strpos($options, 'class="') !== false) |
||
| 724 | { |
||
| 725 | $options = str_replace('class="', 'class="'.implode(' ', $classes).' ', $options); |
||
| 726 | } |
||
| 727 | else |
||
| 728 | { |
||
| 729 | $options .= ' class="'.implode(' ', $classes).'"'; |
||
| 730 | } |
||
| 731 | |||
| 732 | return '<button type="'.$buttontype.'" name="'.htmlspecialchars($name). |
||
| 733 | '" value="'.htmlspecialchars($label). |
||
| 734 | '" '.$options.'>'. |
||
| 735 | ($image != '' ? '<img'.$image.' title="'.self::htmlspecialchars($label).'"> ' : ''). |
||
| 736 | ($image == '' || $accesskey ? self::htmlspecialchars($label_u) : '').'</button>'; |
||
| 737 | } |
||
| 738 | |||
| 739 | /** |
||
| 740 | * creates an absolut link + the query / get-variables |
||
| 741 | * |
||
| 742 | * Example link('/index.php?menuaction=infolog.uiinfolog.get_list',array('info_id' => 123)) |
||
| 743 | * gives 'http://domain/phpgw-path/index.php?menuaction=infolog.uiinfolog.get_list&info_id=123' |
||
| 744 | * |
||
| 745 | * @param string $_url egw-relative link, may include query / get-vars |
||
| 746 | * @param array|string $vars query or array ('name' => 'value', ...) with query |
||
| 747 | * @return string absolut link already run through $phpgw->link |
||
| 748 | */ |
||
| 749 | static function link($_url,$vars='') |
||
| 750 | { |
||
| 751 | if (!is_array($vars)) |
||
| 752 | { |
||
| 753 | parse_str($vars,$vars); |
||
| 754 | } |
||
| 755 | list($url,$v) = explode('?', $_url); // url may contain additional vars |
||
| 756 | if ($v) |
||
| 757 | { |
||
| 758 | parse_str($v,$v); |
||
| 759 | $vars += $v; |
||
| 760 | } |
||
| 761 | return Framework::link($url,$vars); |
||
| 762 | } |
||
| 763 | |||
| 764 | /** |
||
| 765 | * represents html checkbox |
||
| 766 | * |
||
| 767 | * @param string $name name |
||
| 768 | * @param boolean $checked box checked on display |
||
| 769 | * @param string $value value the var should be set to, default 'True' |
||
| 770 | * @param string $options attributes for the tag, default ''=none |
||
| 771 | * @return string html |
||
| 772 | */ |
||
| 773 | static function checkbox($name,$checked=false,$value='True',$options='') |
||
| 776 | } |
||
| 777 | |||
| 778 | /** |
||
| 779 | * represents a html form |
||
| 780 | * |
||
| 781 | * @param string $content of the form, if '' only the opening tag gets returned |
||
| 782 | * @param array $hidden_vars array with name-value pairs for hidden input fields |
||
| 783 | * @param string $_url eGW relative URL, will be run through the link function, if empty the current url is used |
||
| 784 | * @param string|array $url_vars parameters for the URL, send to link static function too |
||
| 785 | * @param string $name name of the form, defaul ''=none |
||
| 786 | * @param string $options attributes for the tag, default ''=none |
||
| 787 | * @param string $method method of the form, default 'POST' |
||
| 788 | * @return string html |
||
| 789 | */ |
||
| 790 | static function form($content,$hidden_vars,$_url,$url_vars='',$name='',$options='',$method='POST') |
||
| 791 | { |
||
| 792 | $url = $_url ? self::link($_url, $url_vars) : $_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING']; |
||
| 793 | $html = "<form method=\"$method\" ".($name != '' ? "name=\"$name\" " : '')."action=\"$url\" $options>\n"; |
||
| 794 | $html .= self::input_hidden($hidden_vars); |
||
| 795 | |||
| 796 | if ($content) |
||
| 797 | { |
||
| 798 | $html .= $content; |
||
| 799 | $html .= "</form>\n"; |
||
| 800 | } |
||
| 801 | return $html; |
||
| 802 | } |
||
| 803 | |||
| 804 | /** |
||
| 805 | * represents a html form with one button |
||
| 806 | * |
||
| 807 | * @param string $name name of the button |
||
| 808 | * @param string $label label of the button |
||
| 809 | * @param array $hidden_vars array with name-value pairs for hidden input fields |
||
| 810 | * @param string $url eGW relative URL, will be run through the link function |
||
| 811 | * @param string|array $url_vars parameters for the URL, send to link static function too |
||
| 812 | * @param string $options attributes for the tag, default ''=none |
||
| 813 | * @param string $form_name name of the form, defaul ''=none |
||
| 814 | * @param string $method method of the form, default 'POST' |
||
| 815 | * @return string html |
||
| 816 | */ |
||
| 817 | static function form_1button($name,$label,$hidden_vars,$url,$url_vars='',$form_name='',$method='POST') |
||
| 818 | { |
||
| 819 | return self::form(self::submit_button($name,$label),$hidden_vars,$url,$url_vars,$form_name,' style="display: inline-block"',$method); |
||
| 820 | } |
||
| 821 | |||
| 822 | const THEAD = 1; |
||
| 823 | const TFOOT = 2; |
||
| 824 | const TBODY = 3; |
||
| 825 | static $part2tag = array( |
||
| 826 | self::THEAD => 'thead', |
||
| 827 | self::TFOOT => 'tfoot', |
||
| 828 | self::TBODY => 'tbody', |
||
| 829 | ); |
||
| 830 | |||
| 831 | /** |
||
| 832 | * creates table from array of rows |
||
| 833 | * |
||
| 834 | * abstracts the html stuff for the table creation |
||
| 835 | * Example: $rows = array ( |
||
| 836 | * 'h1' => array( // optional header row(s) |
||
| 837 | * ), |
||
| 838 | * 'f1' => array( // optional footer row(s) |
||
| 839 | * ), |
||
| 840 | * '1' => array( |
||
| 841 | * 1 => 'cell1', '.1' => 'colspan=3', |
||
| 842 | * 2 => 'cell2', |
||
| 843 | * 3 => 'cell3', '.3' => 'width="10%"' |
||
| 844 | * ),'.1' => 'BGCOLOR="#0000FF"' ); |
||
| 845 | * table($rows,'width="100%"') = '<table width="100%"><tr><td colspan=3>cell1</td><td>cell2</td><td width="10%">cell3</td></tr></table>' |
||
| 846 | * |
||
| 847 | * @param array $rows with rows, each row is an array of the cols |
||
| 848 | * @param string $options options for the table-tag |
||
| 849 | * @param boolean $no_table_tr dont return the table- and outmost tr-tabs, default false=return table+tr |
||
| 850 | * @return string with html-code of the table |
||
| 851 | */ |
||
| 852 | static function table($rows,$options = '',$no_table_tr=False) |
||
| 853 | { |
||
| 854 | $html = $no_table_tr ? '' : "<table $options>\n"; |
||
| 855 | |||
| 856 | $part = 0; |
||
| 857 | foreach($rows as $key => $row) |
||
| 858 | { |
||
| 859 | if (!is_array($row)) |
||
| 860 | { |
||
| 861 | continue; // parameter |
||
| 862 | } |
||
| 863 | // get the current part from the optional 'h' or 'f' prefix of the key |
||
| 864 | $p = $key[0] == 'h' ? self::THEAD : ($key[0] == 'f' ? self::TFOOT : self::TBODY); |
||
| 865 | if ($part < $p && ($part || $p < self::TBODY)) // add only allowed and neccessary transitions |
||
| 866 | { |
||
| 867 | if ($part) $html .= '</'.self::$part2tag[$part].">\n"; |
||
| 868 | $html .= '<'.self::$part2tag[$part=$p].">\n"; |
||
| 869 | } |
||
| 870 | $html .= $no_table_tr && $key == 1 ? '' : "\t<tr ".$rows['.'.$key].">\n"; |
||
| 871 | |||
| 872 | foreach($row as $key => $cell) |
||
| 873 | { |
||
| 874 | if ($key[0] == '.') |
||
| 875 | { |
||
| 876 | continue; // parameter |
||
| 877 | } |
||
| 878 | $table_pos = strpos($cell,'<table'); |
||
| 879 | $td_pos = strpos($cell,'<td'); |
||
| 880 | if ($td_pos !== False && ($table_pos === False || $td_pos < $table_pos)) |
||
| 881 | { |
||
| 882 | $html .= $cell; |
||
| 883 | } |
||
| 884 | else |
||
| 885 | { |
||
| 886 | $html .= "\t\t<td ".$row['.'.$key].">$cell</td>\n"; |
||
| 887 | } |
||
| 888 | } |
||
| 889 | $html .= "\t</tr>\n"; |
||
| 890 | } |
||
| 891 | if (!is_array($rows)) |
||
| 892 | { |
||
| 893 | echo "<p>".function_backtrace()."</p>\n"; |
||
| 894 | } |
||
| 895 | if ($part) // close current part |
||
| 896 | { |
||
| 897 | $html .= "</".self::$part2tag[$part].">\n"; |
||
| 898 | } |
||
| 899 | $html .= "</table>\n"; |
||
| 900 | |||
| 901 | if ($no_table_tr) |
||
| 902 | { |
||
| 903 | $html = substr($html,0,-16); |
||
| 904 | } |
||
| 905 | return $html; |
||
| 906 | } |
||
| 907 | |||
| 908 | /** |
||
| 909 | * changes a selectbox to submit the form if it gets changed, to be used with the sbox-class |
||
| 910 | * |
||
| 911 | * @param string $sbox html with the select-box |
||
| 912 | * @param boolean $no_script if true generate a submit-button if javascript is off |
||
| 913 | * @return string html |
||
| 914 | */ |
||
| 915 | static function sbox_submit( $sbox,$no_script=false ) |
||
| 916 | { |
||
| 917 | $html = str_replace('<select','<select onchange="this.form.submit()" ',$sbox); |
||
| 918 | if ($no_script) |
||
| 919 | { |
||
| 920 | $html .= '<noscript>'.self::submit_button('send','>').'</noscript>'; |
||
| 921 | } |
||
| 922 | return $html; |
||
| 923 | } |
||
| 924 | |||
| 925 | /** |
||
| 926 | * html-widget showing progessbar with a view div's (html4 only, textual percentage otherwise) |
||
| 927 | * |
||
| 928 | * @param mixed $_percent percent-value, gets casted to int |
||
| 929 | * @param string $_title title for the progressbar, default ''=the percentage itself |
||
| 930 | * @param string $options attributes for the outmost div (may include onclick="...") |
||
| 931 | * @param string $width width, default 30px |
||
| 932 | * @param string $color color, default '#D00000' (dark red) |
||
| 933 | * @param string $height height, default 5px |
||
| 934 | * @return string html |
||
| 935 | */ |
||
| 936 | static function progressbar($_percent, $_title='',$options='',$width='',$color='',$height='' ) |
||
| 937 | { |
||
| 938 | $percent = (int)$_percent; |
||
| 939 | if (!$width) $width = '30px'; |
||
| 940 | if (!$height)$height= '5px'; |
||
| 941 | if (!$color) $color = '#D00000'; |
||
| 942 | $title = $_title ? self::htmlspecialchars($_title) : $percent.'%'; |
||
| 943 | |||
| 944 | return '<div class="onlyPrint">'.$title.'</div><div class="noPrint" title="'.$title.'" '.$options. |
||
| 945 | ' style="height: '.$height.'; width: '.$width.'; border: 1px solid black; padding: 1px; text-align: left;'. |
||
| 946 | (@stristr($options,'onclick="') ? ' cursor: pointer;' : '').'">'."\n\t". |
||
| 947 | '<div style="height: '.$height.'; width: '.$percent.'%; background: '.$color.';"></div>'."\n</div>\n"; |
||
| 948 | } |
||
| 949 | |||
| 950 | /** |
||
| 951 | * representates a html img tag, output a picture |
||
| 952 | * |
||
| 953 | * If the name ends with a '%' and the rest is numeric, a progressionbar is shown instead of an image. |
||
| 954 | * The vfs:/ pseudo protocoll allows to access images in the vfs, eg. vfs:/home/ralf/me.png |
||
| 955 | * Instead of a name you specify an array with get-vars, it is passed to eGW's link function. |
||
| 956 | * This way session-information gets passed, eg. $name=array('menuaction'=>'myapp.class.image','id'=>123). |
||
| 957 | * |
||
| 958 | * @param string $app app-name to search the image |
||
| 959 | * @param string|array $name image-name or URL (incl. vfs:/) or array with get-vars |
||
| 960 | * @param string $title tooltip, default '' = none |
||
| 961 | * @param string $options further options for the tag, default '' = none |
||
| 962 | * @return string the html |
||
| 963 | */ |
||
| 964 | static function image( $app,$name,$title='',$options='' ) |
||
| 965 | { |
||
| 966 | if (is_array($name)) // menuaction and other get-vars |
||
| 967 | { |
||
| 968 | $name = $GLOBALS['egw']->link('/index.php',$name); |
||
| 969 | } |
||
| 970 | if (substr($name,0,5) == 'vfs:/') // vfs pseudo protocoll |
||
| 971 | { |
||
| 972 | $name = Framework::link(Vfs::download_url(substr($name,4))); |
||
| 973 | } |
||
| 974 | if ($name[0] == '/' || substr($name,0,7) == 'http://' || substr($name,0,8) == 'https://' || stripos($name,'api/thumbnail.php') ) |
||
| 975 | { |
||
| 976 | if (!($name[0] == '/' || substr($name,0,7) == 'http://' || substr($name,0,8) == 'https://')) $name = '/'.$name; |
||
| 977 | $url = $name; |
||
| 978 | } |
||
| 979 | else // no URL, so try searching the image |
||
| 980 | { |
||
| 981 | $name = str_replace(array('.gif','.GIF','.png','.PNG'),'',$name); |
||
| 982 | |||
| 983 | if (!($url = Image::find($app,$name))) |
||
| 984 | { |
||
| 985 | $url = $name; // name may already contain absolut path |
||
| 986 | } |
||
| 987 | if($GLOBALS['egw_info']['server']['webserver_url']) |
||
| 988 | { |
||
| 989 | list(,$path) = explode($GLOBALS['egw_info']['server']['webserver_url'],$url); |
||
| 990 | |||
| 991 | if (!is_null($path)) $path = EGW_SERVER_ROOT.$path; |
||
| 992 | } |
||
| 993 | else |
||
| 994 | { |
||
| 995 | $path = EGW_SERVER_ROOT.$url; |
||
| 996 | } |
||
| 997 | |||
| 998 | if (is_null($path) || (!@is_readable($path) && stripos($path,'webdav.php')===false)) |
||
| 999 | { |
||
| 1000 | // if the image-name is a percentage, use a progressbar |
||
| 1001 | if (substr($name,-1) == '%' && is_numeric($percent = substr($name,0,-1))) |
||
| 1002 | { |
||
| 1003 | return self::progressbar($percent,$title); |
||
| 1004 | } |
||
| 1005 | return $title; |
||
| 1006 | } |
||
| 1007 | } |
||
| 1008 | if ($title) |
||
| 1009 | { |
||
| 1010 | $options .= ' title="'.self::htmlspecialchars($title).'"'; |
||
| 1011 | } |
||
| 1012 | |||
| 1013 | // This block makes pngfix.js useless, adding a check on disable_pngfix to have pngfix.js do its thing |
||
| 1014 | if (Header\UserAgent::type() == 'msie' && Header\UserAgent::version() < 7.0 && substr($url,-4) == '.png' && ($GLOBALS['egw_info']['user']['preferences']['common']['disable_pngfix'] || !isset($GLOBALS['egw_info']['user']['preferences']['common']['disable_pngfix']))) |
||
| 1015 | { |
||
| 1016 | $extra_styles = "display: inline-block; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='$url',sizingMethod='image'); width: 1px; height: 1px;"; |
||
| 1017 | if (false!==strpos($options,'style="')) |
||
| 1018 | { |
||
| 1019 | $options = str_replace('style="','style="'.$extra_styles, $options); |
||
| 1020 | } |
||
| 1021 | else |
||
| 1022 | { |
||
| 1023 | $options .= ' style="'.$extra_styles.'"'; |
||
| 1024 | } |
||
| 1025 | return "<span $options></span>"; |
||
| 1026 | } |
||
| 1027 | return "<img src=\"$url\" $options />"; |
||
| 1028 | } |
||
| 1029 | |||
| 1030 | /** |
||
| 1031 | * representates a html link |
||
| 1032 | * |
||
| 1033 | * @param string $content of the link, if '' only the opening tag gets returned |
||
| 1034 | * @param string $url eGW relative URL, will be run through the link function |
||
| 1035 | * @param string|array $vars parameters for the URL, send to link static function too |
||
| 1036 | * @param string $options attributes for the tag, default ''=none |
||
| 1037 | * @return string the html |
||
| 1038 | */ |
||
| 1039 | static function a_href( $content,$url,$vars='',$options='') |
||
| 1040 | { |
||
| 1041 | if (is_array($url)) |
||
| 1042 | { |
||
| 1043 | $vars = $url; |
||
| 1044 | $url = '/index.php'; |
||
| 1045 | } |
||
| 1046 | elseif (strpos($url,'/')===false && |
||
| 1047 | count(explode('.',$url)) >= 3 && |
||
| 1048 | !(strpos($url,'mailto:')!==false || |
||
| 1049 | strpos($url,'://')!==false || |
||
| 1050 | strpos($url,'javascript:')!==false)) |
||
| 1051 | { |
||
| 1052 | $url = "/index.php?menuaction=$url"; |
||
| 1053 | } |
||
| 1054 | if ($url[0] == '/') // link relative to eGW |
||
| 1055 | { |
||
| 1056 | $url = self::link($url,$vars); |
||
| 1057 | } |
||
| 1058 | //echo "<p>self::a_href('".self::htmlspecialchars($content)."','$url',".print_r($vars,True).") = ".self::link($url,$vars)."</p>"; |
||
| 1059 | return '<a href="'.self::htmlspecialchars($url).'" '.$options.'>'.$content.'</a>'; |
||
| 1060 | } |
||
| 1061 | |||
| 1062 | /** |
||
| 1063 | * representates a b tag (bold) |
||
| 1064 | * |
||
| 1065 | * @param string $content of the link, if '' only the opening tag gets returned |
||
| 1066 | * @return string the html |
||
| 1067 | */ |
||
| 1068 | static function bold($content) |
||
| 1069 | { |
||
| 1070 | return '<b>'.($content?$content.'</b>':''); |
||
| 1071 | } |
||
| 1072 | |||
| 1073 | /** |
||
| 1074 | * representates a hr tag (horizontal rule) |
||
| 1075 | * |
||
| 1076 | * @param string $width default ''=none given |
||
| 1077 | * @param string $options attributes for the tag, default ''=none |
||
| 1078 | * @return string the html |
||
| 1079 | */ |
||
| 1080 | static function hr($width='',$options='') |
||
| 1081 | { |
||
| 1082 | if ($width) $options .= " width=\"$width\""; |
||
| 1083 | |||
| 1084 | return "<hr $options />\n"; |
||
| 1085 | } |
||
| 1086 | |||
| 1087 | /** |
||
| 1088 | * formats option-string for most of the above functions |
||
| 1089 | * |
||
| 1090 | * Example: formatOptions('100%,,1','width,height,border') = ' width="100%" border="1"' |
||
| 1091 | * |
||
| 1092 | * @param mixed $options String (or Array) with option-values eg. '100%,,1' |
||
| 1093 | * @param mixed $names String (or Array) with the option-names eg. 'WIDTH,HEIGHT,BORDER' |
||
| 1094 | * @return string with options/attributes |
||
| 1095 | */ |
||
| 1096 | static function formatOptions($options,$names) |
||
| 1097 | { |
||
| 1098 | if (!is_array($options)) $options = explode(',',$options); |
||
| 1099 | if (!is_array($names)) $names = explode(',',$names); |
||
| 1100 | |||
| 1101 | foreach($options as $n => $val) |
||
| 1102 | { |
||
| 1103 | if ($val != '' && $names[$n] != '') |
||
| 1104 | { |
||
| 1105 | $html .= ' '.strtolower($names[$n]).'="'.$val.'"'; |
||
| 1106 | } |
||
| 1107 | } |
||
| 1108 | return $html; |
||
| 1109 | } |
||
| 1110 | |||
| 1111 | /** |
||
| 1112 | * html style tag (incl. type) |
||
| 1113 | * |
||
| 1114 | * @param string $styles css-style definitions |
||
| 1115 | * @return string html |
||
| 1116 | */ |
||
| 1117 | static function style($styles) |
||
| 1120 | } |
||
| 1121 | |||
| 1122 | /** |
||
| 1123 | * html label tag |
||
| 1124 | * |
||
| 1125 | * @param string $content the label |
||
| 1126 | * @param string $id for the for attribute, default ''=none |
||
| 1127 | * @param string $accesskey accesskey, default ''=none |
||
| 1128 | * @param string $options attributes for the tag, default ''=none |
||
| 1129 | * @return string the html |
||
| 1130 | */ |
||
| 1131 | static function label($content,$id='',$accesskey='',$options='') |
||
| 1132 | { |
||
| 1133 | if ($id != '') |
||
| 1134 | { |
||
| 1135 | $id = " for=\"$id\""; |
||
| 1136 | } |
||
| 1137 | if ($accesskey != '') |
||
| 1138 | { |
||
| 1139 | $accesskey = " accesskey=\"$accesskey\""; |
||
| 1140 | } |
||
| 1141 | return "<label$id$accesskey $options>$content</label>"; |
||
| 1142 | } |
||
| 1143 | |||
| 1144 | /** |
||
| 1145 | * html fieldset, eg. groups a group of radiobuttons |
||
| 1146 | * |
||
| 1147 | * @param string $content the content |
||
| 1148 | * @param string $legend legend / label of the fieldset, default ''=none |
||
| 1149 | * @param string $options attributes for the tag, default ''=none |
||
| 1150 | * @return string the html |
||
| 1151 | */ |
||
| 1152 | static function fieldset($content,$legend='',$options='') |
||
| 1153 | { |
||
| 1154 | $html = "<fieldset $options>".($legend ? '<legend>'.self::htmlspecialchars($legend).'</legend>' : '')."\n"; |
||
| 1155 | |||
| 1156 | if ($content) |
||
| 1157 | { |
||
| 1158 | $html .= $content; |
||
| 1159 | $html .= "\n</fieldset>\n"; |
||
| 1160 | } |
||
| 1161 | return $html; |
||
| 1162 | } |
||
| 1163 | |||
| 1164 | /** |
||
| 1165 | * tree widget using dhtmlXtree |
||
| 1166 | * |
||
| 1167 | * Code inspired by Lars's Felamimail uiwidgets::createFolderTree() |
||
| 1168 | * |
||
| 1169 | * @author Lars Kneschke <lars-AT-kneschke.de> original code in felamimail |
||
| 1170 | * @param array $_folders array of folders: pairs path => node (string label or array with keys: label, (optional) image, (optional) title, (optional) checked) |
||
| 1171 | * @param string $_selected path of selected folder |
||
| 1172 | * @param mixed $_topFolder =false node of topFolder or false for none |
||
| 1173 | * @param string $_onNodeSelect ='alert' js static function to call if node gets selected |
||
| 1174 | * @param string $tree ='foldertree' id of the div and name of the variable containing the tree object |
||
| 1175 | * @param string $_divClass ='' css class of the div |
||
| 1176 | * @param string $_leafImage ='' default image of a leaf-node, ''=default of foldertree, set it eg. 'folderClosed.gif' to show leafs as folders |
||
| 1177 | * @param boolean|string $_onCheckHandler =false string with handler-name to display a checkbox for each folder, or false (default), 'null' switches checkboxes on without an handler! |
||
| 1178 | * @param string $delimiter ='/' path-delimiter, default / |
||
| 1179 | * @param string $folderImageDir =null string path to the tree menu images, null uses default path |
||
| 1180 | * @param string|array $autoLoading =null EGw relative path or array with get parameter, both send through Framework::link |
||
| 1181 | * @param string $dataMode ='JSON' data type for autoloading: XML, JSON, CSV |
||
| 1182 | * @param boolean $dragndrop =false true to enable drag-n-drop (must be before autoloading get enabled!) |
||
| 1183 | * |
||
| 1184 | * @return string the html code, to be added into the template |
||
| 1185 | */ |
||
| 1186 | static function tree($_folders,$_selected,$_topFolder=false,$_onNodeSelect="null",$tree='foldertree',$_divClass='', |
||
| 1187 | $_leafImage='',$_onCheckHandler=false,$delimiter='/',$folderImageDir=null,$autoLoading=null,$dataMode='JSON', |
||
| 1188 | $dragndrop=false) |
||
| 1189 | { |
||
| 1190 | $webserver_url = $GLOBALS['egw_info']['server']['webserver_url']; |
||
| 1191 | if (empty($folderImageDir)) |
||
| 1192 | { |
||
| 1193 | $folderImageDir = $webserver_url.'/phpgwapi/templates/default/images'; |
||
| 1194 | } |
||
| 1195 | // check if we have template-set specific image path |
||
| 1196 | $image_path = $folderImageDir; |
||
| 1197 | if ($webserver_url && $webserver_url != '/') |
||
| 1198 | { |
||
| 1199 | list(,$image_path) = explode($webserver_url, $image_path, 2); |
||
| 1200 | } |
||
| 1201 | $templated_path = strtr($image_path, array( |
||
| 1202 | '/phpgwapi/templates/default' => $GLOBALS['egw']->framework->template_dir, |
||
| 1203 | '/default/' => '/'.$GLOBALS['egw']->framework->template.'/', |
||
| 1204 | )); |
||
| 1205 | if (file_exists(EGW_SERVER_ROOT.$templated_path.'/dhtmlxtree')) |
||
| 1206 | { |
||
| 1207 | $folderImageDir = ($webserver_url != '/' ? $webserver_url : '').$templated_path; |
||
| 1208 | //error_log(__METHOD__."() setting templated image-path: $folderImageDir"); |
||
| 1209 | } |
||
| 1210 | |||
| 1211 | static $tree_initialised=false; |
||
| 1212 | if (!$tree_initialised) |
||
| 1213 | { |
||
| 1214 | Framework::includeCSS('/api/js/dhtmlxtree/codebase/dhtmlxtree.css'); |
||
| 1215 | Framework::includeJS('/api/js/dhtmlxtree/codebase/dhtmlxcommon.js'); |
||
| 1216 | Framework::includeJS('/api/js/dhtmlxtree/sources/dhtmlxtree.js'); |
||
| 1217 | if ($autoLoading && $dataMode != 'XML') Framework::includeJS('/api/js/dhtmlxtree/sources/ext/dhtmlxtree_json.js'); |
||
| 1218 | $tree_initialised = true; |
||
| 1219 | if (!$_folders && !$autoLoading) return null; |
||
| 1220 | } |
||
| 1221 | $html = self::div("\n",'id="'.$tree.'"',$_divClass).$html; |
||
| 1222 | $html .= "<script type='text/javascript'>\n"; |
||
| 1223 | $html .= "var $tree;"; |
||
| 1224 | $html .= "egw_LAB.wait(function() {"; |
||
| 1225 | $html .= "$tree = new"." dhtmlXTreeObject('$tree','100%','100%',0);\n"; |
||
| 1226 | $html .= "$tree.parentObject.style.overflow='auto';\n"; // dhtmlXTree constructor has hidden hardcoded |
||
| 1227 | if (Translation::charset() == 'utf-8') $html .= "if ($tree.setEscapingMode) $tree.setEscapingMode('utf8');\n"; |
||
| 1228 | $html .= "$tree.setImagePath('$folderImageDir/dhtmlxtree/');\n"; |
||
| 1229 | |||
| 1230 | if($_onCheckHandler) |
||
| 1231 | { |
||
| 1232 | $html .= "$tree.enableCheckBoxes(1);\n"; |
||
| 1233 | $html .= "$tree.setOnCheckHandler('$_onCheckHandler');\n"; |
||
| 1234 | } |
||
| 1235 | |||
| 1236 | if ($dragndrop) $html .= "$tree.enableDragAndDrop(true);\n"; |
||
| 1237 | |||
| 1238 | if ($autoLoading) |
||
| 1239 | { |
||
| 1240 | $autoLoading = is_array($autoLoading) ? |
||
| 1241 | Framework::link('/index.php',$autoLoading) : Framework::link($autoLoading); |
||
| 1242 | $html .= "$tree.setXMLAutoLoading('$autoLoading');\n"; |
||
| 1243 | if ($dataMode != 'XML') $html .= "$tree.setDataMode('$dataMode');\n"; |
||
| 1244 | |||
| 1245 | // if no folders given, use xml url to load root, incl. setting of selected folder |
||
| 1246 | if (!$_folders) |
||
| 1247 | { |
||
| 1248 | if ($_selected) $autoLoading .= '&selected='.urlencode($_selected); |
||
| 1249 | unset($_selected); |
||
| 1250 | $html .= "$tree.loadXML('$autoLoading');\n"; |
||
| 1251 | $html .= "});"; |
||
| 1252 | return $html."</script>\n"; |
||
| 1253 | } |
||
| 1254 | } |
||
| 1255 | |||
| 1256 | $top = 0; |
||
| 1257 | if ($_topFolder) |
||
| 1258 | { |
||
| 1259 | $top = '--topfolder--'; |
||
| 1260 | $topImage = ''; |
||
| 1261 | if (is_array($_topFolder)) |
||
| 1262 | { |
||
| 1263 | $label = $_topFolder['label']; |
||
| 1264 | if (isset($_topFolder['image'])) |
||
| 1265 | { |
||
| 1266 | $topImage = $_topFolder['image']; |
||
| 1267 | } |
||
| 1268 | } |
||
| 1269 | else |
||
| 1270 | { |
||
| 1271 | $label = $_topFolder; |
||
| 1272 | } |
||
| 1273 | $html .= "\n$tree.insertNewItem(0,'$top','".addslashes($label)."',$_onNodeSelect,'$topImage','$topImage','$topImage','CHILD,TOP');\n"; |
||
| 1274 | |||
| 1275 | if (is_array($_topFolder) && isset($_topFolder['title'])) |
||
| 1276 | { |
||
| 1277 | $html .= "$tree.setItemText('$top','".addslashes($label)."','".addslashes($_topFolder['title'])."');\n"; |
||
| 1278 | } |
||
| 1279 | } |
||
| 1280 | if (is_string($_folders)) |
||
| 1281 | { |
||
| 1282 | switch($dataMode) |
||
| 1283 | { |
||
| 1284 | case 'JSON': |
||
| 1285 | $html .= "$tree.loadJSONObject($_folders);\n"; break; |
||
| 1286 | case 'XML': |
||
| 1287 | $html .= "$tree.loadXMLString('$_folders');\n"; break; |
||
| 1288 | } |
||
| 1289 | } |
||
| 1290 | else |
||
| 1291 | { |
||
| 1292 | // evtl. remove leading delimiter |
||
| 1293 | if ($_selected[0] == $delimiter) $_selected = substr($_selected,1); |
||
| 1294 | |||
| 1295 | $n = 0; |
||
| 1296 | foreach($_folders as $path => $data) |
||
| 1297 | { |
||
| 1298 | if (!is_array($data)) |
||
| 1299 | { |
||
| 1300 | $data = array('label' => $data); |
||
| 1301 | } |
||
| 1302 | $image1 = $image2 = $image3 = '0'; |
||
| 1303 | |||
| 1304 | // if _leafImage given, set it only for leaves, not for folders containing children |
||
| 1305 | if ($_leafImage) |
||
| 1306 | { |
||
| 1307 | $image1 = $image2 = $image3 = "'".$_leafImage."'"; |
||
| 1308 | if (($next_item = array_slice($_folders, $n+1, 1, true))) |
||
| 1309 | { |
||
| 1310 | $next_path = key($next_item); |
||
| 1311 | if (substr($next_path,0,strlen($path)+1) == $path.'/') |
||
| 1312 | { |
||
| 1313 | $image1 = $image2 = $image3 = '0'; |
||
| 1314 | } |
||
| 1315 | } |
||
| 1316 | } |
||
| 1317 | if (isset($data['image'])) |
||
| 1318 | { |
||
| 1319 | $image1 = $image2 = $image3 = "'".$data['image']."'"; |
||
| 1320 | } |
||
| 1321 | // evtl. remove leading delimiter |
||
| 1322 | if ($path[0] == $delimiter) $path = substr($path,1); |
||
| 1323 | $folderParts = explode($delimiter,$path); |
||
| 1324 | |||
| 1325 | //get rightmost folderpart |
||
| 1326 | $label = array_pop($folderParts); |
||
| 1327 | if (isset($data['label'])) $label = $data['label']; |
||
| 1328 | |||
| 1329 | // the rest of the array is the name of the parent |
||
| 1330 | $parentName = implode((array)$folderParts,$delimiter); |
||
| 1331 | if(empty($parentName)) $parentName = $top; |
||
| 1332 | |||
| 1333 | $entryOptions = !isset($data['child']) || $data['child'] ? 'CHILD' : ''; |
||
| 1334 | if ($_onCheckHandler && $_selected) // check selected items on multi selection |
||
| 1335 | { |
||
| 1336 | if (!is_array($_selected)) $_selected = explode(',',$_selected); |
||
| 1337 | if (array_search("$path",$_selected)!==false) $entryOptions .= ',CHECKED'; |
||
| 1338 | //echo "<p>path=$path, _selected=".print_r($_selected,true).": $entryOptions</p>\n"; |
||
| 1339 | } |
||
| 1340 | // highlight current item |
||
| 1341 | elseif ((string)$_selected === (string)$path) |
||
| 1342 | { |
||
| 1343 | $entryOptions .= ',SELECT'; |
||
| 1344 | } |
||
| 1345 | $html .= "$tree.insertNewItem('".addslashes($parentName)."','".addslashes($path)."','".addslashes($label). |
||
| 1346 | "',$_onNodeSelect,$image1,$image2,$image3,'$entryOptions');\n"; |
||
| 1347 | if (isset($data['title'])) |
||
| 1348 | { |
||
| 1349 | $html .= "$tree.setItemText('".addslashes($path)."','".addslashes($label)."','".addslashes($data['title'])."');\n"; |
||
| 1350 | } |
||
| 1351 | ++$n; |
||
| 1352 | } |
||
| 1353 | } |
||
| 1354 | $html .= "$tree.closeAllItems(0);\n"; |
||
| 1355 | if ($_selected) |
||
| 1356 | { |
||
| 1357 | foreach(is_array($_selected)?$_selected:array($_selected) as $path) |
||
| 1358 | { |
||
| 1359 | $html .= "$tree.openItem('".addslashes($path)."');\n"; |
||
| 1360 | } |
||
| 1361 | } |
||
| 1362 | else |
||
| 1363 | { |
||
| 1364 | $html .= "$tree.openItem('$top');\n"; |
||
| 1365 | } |
||
| 1366 | $html .= "});"; |
||
| 1367 | $html .= "</script>\n"; |
||
| 1368 | |||
| 1369 | return $html; |
||
| 1370 | } |
||
| 1371 | |||
| 1372 | /** |
||
| 1373 | * Runs HTMLPurifier over supplied html to remove malicious code |
||
| 1374 | * |
||
| 1375 | * @param string $html |
||
| 1376 | * @param array|string $config =null - config to influence the behavior of current purifying engine |
||
| 1377 | * @param array|string $spec =null - spec to influence the behavior of current purifying engine |
||
| 1378 | * The $spec argument can be used to disallow an otherwise legal attribute for an element, |
||
| 1379 | * or to restrict the attribute's values |
||
| 1380 | * @param boolean $_force =null - force the config passed to be used without merging to the default |
||
| 1381 | */ |
||
| 1382 | static function purify($html,$config=null,$spec=array(),$_force=false) |
||
| 1385 | } |
||
| 1386 | } |
||
| 1387 |