r4562 getNiftySelect(): move addJS() call here
[racktables-incomplete-works] / wwwroot / inc / interface-lib.php
1 <?php
2
3 define ('TAGNAME_REGEXP', '/^[\p{L}0-9]([. _~-]?[\p{L}0-9])*$/u');
4 define ('AUTOTAGNAME_REGEXP', '/^\$[\p{L}0-9]([. _~-]?[\p{L}0-9])*$/u');
5
6 // Let's have it here, so extensions can add their own images.
7 $image = array();
8 $image['logo']['path'] = 'pix/defaultlogo.png';
9 $image['logo']['width'] = 210;
10 $image['logo']['height'] = 40;
11 $image['rackspace']['path'] = 'pix/racks.png';
12 $image['rackspace']['width'] = 218;
13 $image['rackspace']['height'] = 200;
14 $image['objects']['path'] = 'pix/server.png';
15 $image['objects']['width'] = 218;
16 $image['objects']['height'] = 200;
17 $image['depot']['path'] = 'pix/server.png';
18 $image['depot']['width'] = 218;
19 $image['depot']['height'] = 200;
20 $image['files']['path'] = 'pix/files.png';
21 $image['files']['width'] = 218;
22 $image['files']['height'] = 200;
23 $image['ipv4space']['path'] = 'pix/addressspace.png';
24 $image['ipv4space']['width'] = 218;
25 $image['ipv4space']['height'] = 200;
26 $image['ipv6space']['path'] = 'pix/addressspacev6.png';
27 $image['ipv6space']['width'] = 218;
28 $image['ipv6space']['height'] = 200;
29 $image['ipv4slb']['path'] = 'pix/slb.png';
30 $image['ipv4slb']['width'] = 218;
31 $image['ipv4slb']['height'] = 200;
32 $image['config']['path'] = 'pix/configuration.png';
33 $image['config']['width'] = 218;
34 $image['config']['height'] = 200;
35 $image['reports']['path'] = 'pix/report.png';
36 $image['reports']['width'] = 218;
37 $image['reports']['height'] = 200;
38 $image['8021q']['path'] = 'pix/8021q.png';
39 $image['8021q']['width'] = 218;
40 $image['8021q']['height'] = 200;
41 $image['objectlog']['path'] = 'pix/crystal-mimetypes-shellscript-218x200.png';
42 $image['objectlog']['width'] = 218;
43 $image['objectlog']['height'] = 200;
44 $image['virtual']['path'] = 'pix/virtualresources.png';
45 $image['virtual']['width'] = 218;
46 $image['virtual']['height'] = 200;
47 $image['download']['path'] = 'pix/download.png';
48 $image['download']['width'] = 16;
49 $image['download']['height'] = 16;
50 $image['DOWNLOAD']['path'] = 'pix/download-big.png';
51 $image['DOWNLOAD']['width'] = 32;
52 $image['DOWNLOAD']['height'] = 32;
53 $image['plug']['path'] = 'pix/tango-network-wired.png';
54 $image['plug']['width'] = 16;
55 $image['plug']['height'] = 16;
56 $image['cut']['path'] = 'pix/tango-edit-cut-16x16.png';
57 $image['cut']['width'] = 16;
58 $image['cut']['height'] = 16;
59 $image['Cut']['path'] = 'pix/tango-edit-cut-22x22.png';
60 $image['Cut']['width'] = 22;
61 $image['Cut']['height'] = 22;
62 $image['Cut gray']['path'] = 'pix/tango-edit-cut-22x22-gray.png';
63 $image['Cut gray']['width'] = 22;
64 $image['Cut gray']['height'] = 22;
65 $image['CUT']['path'] = 'pix/tango-edit-cut-32x32.png';
66 $image['CUT']['width'] = 32;
67 $image['CUT']['height'] = 32;
68 $image['add']['path'] = 'pix/tango-list-add.png';
69 $image['add']['width'] = 16;
70 $image['add']['height'] = 16;
71 $image['ADD']['path'] = 'pix/tango-list-add-big.png';
72 $image['ADD']['width'] = 32;
73 $image['ADD']['height'] = 32;
74 $image['delete']['path'] = 'pix/tango-list-remove.png';
75 $image['delete']['width'] = 16;
76 $image['delete']['height'] = 16;
77 $image['DELETE']['path'] = 'pix/tango-list-remove-32x32.png';
78 $image['DELETE']['width'] = 32;
79 $image['DELETE']['height'] = 32;
80 $image['destroy']['path'] = 'pix/tango-user-trash-16x16.png';
81 $image['destroy']['width'] = 16;
82 $image['destroy']['height'] = 16;
83 $image['nodestroy']['path'] = 'pix/tango-user-trash-16x16-gray.png';
84 $image['nodestroy']['width'] = 16;
85 $image['nodestroy']['height'] = 16;
86 $image['NODESTROY']['path'] = 'pix/tango-user-trash-32x32-gray.png';
87 $image['NODESTROY']['width'] = 32;
88 $image['NODESTROY']['height'] = 32;
89 $image['DESTROY']['path'] = 'pix/tango-user-trash-32x32.png';
90 $image['DESTROY']['width'] = 32;
91 $image['DESTROY']['height'] = 32;
92 $image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
93 $image['nodelete']['width'] = 16;
94 $image['nodelete']['height'] = 16;
95 $image['inservice']['path'] = 'pix/tango-emblem-system.png';
96 $image['inservice']['width'] = 16;
97 $image['inservice']['height'] = 16;
98 $image['notinservice']['path'] = 'pix/tango-dialog-error.png';
99 $image['notinservice']['width'] = 16;
100 $image['notinservice']['height'] = 16;
101 $image['find']['path'] = 'pix/tango-system-search.png';
102 $image['find']['width'] = 16;
103 $image['find']['height'] = 16;
104 $image['next']['path'] = 'pix/tango-go-next.png';
105 $image['next']['width'] = 32;
106 $image['next']['height'] = 32;
107 $image['prev']['path'] = 'pix/tango-go-previous.png';
108 $image['prev']['width'] = 32;
109 $image['prev']['height'] = 32;
110 $image['COMMIT']['path'] = 'pix/tango-go-prev-next-32x32.png';
111 $image['COMMIT']['width'] = 32;
112 $image['COMMIT']['height'] = 32;
113 $image['COMMIT gray']['path'] = 'pix/tango-go-prev-next-gray-32x32.png';
114 $image['COMMIT gray']['width'] = 32;
115 $image['COMMIT gray']['height'] = 32;
116 $image['RECALC']['path'] = 'pix/tango-view-refresh-32x32.png';
117 $image['RECALC']['width'] = 32;
118 $image['RECALC']['height'] = 32;
119 $image['clear']['path'] = 'pix/tango-edit-clear.png';
120 $image['clear']['width'] = 16;
121 $image['clear']['height'] = 16;
122 $image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
123 $image['CLEAR']['width'] = 32;
124 $image['CLEAR']['height'] = 32;
125 $image['CLEAR gray']['path'] = 'pix/tango-edit-clear-gray-32x32.png';
126 $image['CLEAR gray']['width'] = 32;
127 $image['CLEAR gray']['height'] = 32;
128 $image['save']['path'] = 'pix/tango-document-save-16x16.png';
129 $image['save']['width'] = 16;
130 $image['save']['height'] = 16;
131 $image['SAVE']['path'] = 'pix/tango-document-save-32x32.png';
132 $image['SAVE']['width'] = 32;
133 $image['SAVE']['height'] = 32;
134 $image['NOSAVE']['path'] = 'pix/tango-document-save-32x32-gray.png';
135 $image['NOSAVE']['width'] = 32;
136 $image['NOSAVE']['height'] = 32;
137 $image['create']['path'] = 'pix/tango-document-new.png';
138 $image['create']['width'] = 16;
139 $image['create']['height'] = 16;
140 $image['CREATE']['path'] = 'pix/tango-document-new-big.png';
141 $image['CREATE']['width'] = 32;
142 $image['CREATE']['height'] = 32;
143 $image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
144 $image['DENIED']['width'] = 32;
145 $image['DENIED']['height'] = 32;
146 $image['node-collapsed']['path'] = 'pix/node-collapsed.png';
147 $image['node-collapsed']['width'] = 16;
148 $image['node-collapsed']['height'] = 16;
149 $image['node-expanded']['path'] = 'pix/node-expanded.png';
150 $image['node-expanded']['width'] = 16;
151 $image['node-expanded']['height'] = 16;
152 $image['node-expanded-static']['path'] = 'pix/node-expanded-static.png';
153 $image['node-expanded-static']['width'] = 16;
154 $image['node-expanded-static']['height'] = 16;
155 $image['dragons']['path'] = 'pix/mitsudragon.png';
156 $image['dragons']['width'] = 195;
157 $image['dragons']['height'] = 33;
158 $image['LB']['path'] = 'pix/loadbalancer.png';
159 $image['LB']['width'] = 32;
160 $image['LB']['height'] = 32;
161 $image['RS pool']['path'] = 'pix/serverpool.png';
162 $image['RS pool']['width'] = 48;
163 $image['RS pool']['height'] = 16;
164 $image['VS']['path'] = 'pix/servicesign.png';
165 $image['VS']['width'] = 39;
166 $image['VS']['height'] = 62;
167 $image['router']['path'] = 'pix/router.png';
168 $image['router']['width'] = 32;
169 $image['router']['height'] = 32;
170 $image['object']['path'] = 'pix/bracket-16x16.png';
171 $image['object']['width'] = 16;
172 $image['object']['height'] = 16;
173 $image['OBJECT']['path'] = 'pix/bracket-32x32.png';
174 $image['OBJECT']['width'] = 32;
175 $image['OBJECT']['height'] = 32;
176 $image['attach']['path'] = 'pix/tango-mail-attachment-16x16.png';
177 $image['attach']['width'] = 16;
178 $image['attach']['height'] = 16;
179 $image['Attach']['path'] = 'pix/tango-mail-attachment-22x22.png';
180 $image['Attach']['width'] = 22;
181 $image['Attach']['height'] = 22;
182 $image['ATTACH']['path'] = 'pix/tango-mail-attachment-32x32.png';
183 $image['ATTACH']['width'] = 32;
184 $image['ATTACH']['height'] = 32;
185 $image['favorite']['path'] = 'pix/tango-emblem-favorite.png';
186 $image['favorite']['width'] = 16;
187 $image['favorite']['height'] = 16;
188 $image['computer']['path'] = 'pix/tango-computer.png';
189 $image['computer']['width'] = 16;
190 $image['computer']['height'] = 16;
191 $image['empty file']['path'] = 'pix/crystal-file-empty-32x32.png';
192 $image['empty file']['width'] = 32;
193 $image['empty file']['height'] = 32;
194 $image['text file']['path'] = 'pix/crystal-file-text-32x32.png';
195 $image['text file']['width'] = 32;
196 $image['text file']['height'] = 32;
197 $image['image file']['path'] = 'pix/crystal-file-image-32x32.png';
198 $image['image file']['width'] = 32;
199 $image['image file']['height'] = 32;
200 $image['text']['path'] = 'pix/tango-text-x-generic-16x16.png';
201 $image['text']['width'] = 16;
202 $image['text']['height'] = 16;
203 $image['NET']['path'] = 'pix/crystal-network_local-32x32.png';
204 $image['NET']['width'] = 32;
205 $image['NET']['height'] = 32;
206 $image['net']['path'] = 'pix/crystal-network_local-16x16.png';
207 $image['net']['width'] = 16;
208 $image['net']['height'] = 16;
209 $image['USER']['path'] = 'pix/crystal-edit-user-32x32.png';
210 $image['USER']['width'] = 32;
211 $image['USER']['height'] = 32;
212 $image['setfilter']['path'] = 'pix/pgadmin3-viewfiltereddata.png';
213 $image['setfilter']['width'] = 32;
214 $image['setfilter']['height'] = 32;
215 $image['setfilter gray']['path'] = 'pix/pgadmin3-viewfiltereddata-grayscale.png';
216 $image['setfilter gray']['width'] = 32;
217 $image['setfilter gray']['height'] = 32;
218 $image['resetfilter']['path'] = 'pix/pgadmin3-viewdata.png';
219 $image['resetfilter']['width'] = 32;
220 $image['resetfilter']['height'] = 32;
221 $image['resetfilter gray']['path'] = 'pix/pgadmin3-viewdata-grayscale.png';
222 $image['resetfilter gray']['width'] = 32;
223 $image['resetfilter gray']['height'] = 32;
224 $image['knight']['path'] = 'pix/smiley_knight.png';
225 $image['knight']['width'] = 72;
226 $image['knight']['height'] = 33;
227 $image['Zoom']['path'] = 'pix/tango-system-search-22x22.png';
228 $image['Zoom']['width'] = 22;
229 $image['Zoom']['height'] = 22;
230 $image['Zooming']['path'] = 'pix/tango-view-fullscreen-22x22.png';
231 $image['Zooming']['width'] = 22;
232 $image['Zooming']['height'] = 22;
233 $image['UNLOCK']['path'] = 'pix/crystal-actions-unlock-32x32.png';
234 $image['UNLOCK']['width'] = 32;
235 $image['UNLOCK']['height'] = 32;
236 $image['CLOCK']['path'] = 'pix/tango-appointment-32x32.png';
237 $image['CLOCK']['width'] = 32;
238 $image['CLOCK']['height'] = 32;
239 $image['DQUEUE done']['path'] = 'pix/crystal-ok-32x32.png';
240 $image['DQUEUE done']['width'] = 32;
241 $image['DQUEUE done']['height'] = 32;
242 $image['DQUEUE sync_aging']['path'] = 'pix/tango-appointment-32x32.png';
243 $image['DQUEUE sync_aging']['width'] = 32;
244 $image['DQUEUE sync_aging']['height'] = 32;
245 $image['DQUEUE resync_aging']['path'] = 'pix/tango-appointment-32x32.png';
246 $image['DQUEUE resync_aging']['width'] = 32;
247 $image['DQUEUE resync_aging']['height'] = 32;
248 $image['DQUEUE sync_ready']['path'] = 'pix/tango-emblem-system-32x32.png';
249 $image['DQUEUE sync_ready']['width'] = 32;
250 $image['DQUEUE sync_ready']['height'] = 32;
251 $image['DQUEUE resync_ready']['path'] = 'pix/tango-emblem-important-32x32.png';
252 $image['DQUEUE resync_ready']['width'] = 32;
253 $image['DQUEUE resync_ready']['height'] = 32;
254 $image['DQUEUE failed']['path'] = 'pix/tango-emblem-unreadable-32x32.png';
255 $image['DQUEUE failed']['width'] = 32;
256 $image['DQUEUE failed']['height'] = 32;
257 $image['DQUEUE disabled']['path'] = 'pix/tango-emblem-readonly-32x32.png';
258 $image['DQUEUE disabled']['width'] = 32;
259 $image['DQUEUE disabled']['height'] = 32;
260 $image['COPY']['path'] = 'pix/tango-edit-copy-32x32.png';
261 $image['COPY']['width'] = 32;
262 $image['COPY']['height'] = 32;
263 $image['html']['path'] = 'pix/tango-text-html.png';
264 $image['html']['width'] = 16;
265 $image['html']['height'] = 16;
266
267 function printSelect ($optionList, $select_attrs = array(), $selected_id = NULL)
268 {
269 echo getSelect ($optionList, $select_attrs, $selected_id);
270 }
271
272 // Input array keys are OPTION VALUEs and input array values are OPTION text.
273 function getSelect ($optionList, $select_attrs = array(), $selected_id = NULL, $treat_single_special = TRUE)
274 {
275 $ret = '';
276 if (!array_key_exists ('name', $select_attrs))
277 return '';
278 // handle two corner cases in a specific way
279 if (count ($optionList) == 0)
280 return '(none)';
281 if (count ($optionList) == 1 && $treat_single_special)
282 {
283 foreach ($optionList as $key => $value) { break; }
284 return "<input type=hidden name=${select_attrs['name']} id=${select_attrs['name']} value=${key}>" . $value;
285 }
286 if (!array_key_exists ('id', $select_attrs))
287 $select_attrs['id'] = $select_attrs['name'];
288 $ret .= '<select';
289 foreach ($select_attrs as $attr_name => $attr_value)
290 $ret .= " ${attr_name}=${attr_value}";
291 $ret .= '>';
292 foreach ($optionList as $dict_key => $dict_value)
293 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>";
294 $ret .= '</select>';
295 return $ret;
296 }
297
298 function printNiftySelect ($groupList, $select_attrs = array(), $selected_id = NULL, $autocomplete = false)
299 {
300 echo getNiftySelect ($groupList, $select_attrs, $selected_id);
301 }
302
303 // Input is a cooked list of OPTGROUPs, each with own sub-list of OPTIONs in the same
304 // format as printSelect() expects.
305 // If tree is true, hierarchical drop-boxes are used, otherwise optgroups are used.
306 function getNiftySelect ($groupList, $select_attrs, $selected_id = NULL, $tree = false)
307 {
308 // special treatment for ungrouped data
309 if (count ($groupList) == 1 and isset ($groupList['other']))
310 return getSelect ($groupList['other'], $select_attrs, $selected_id);
311 if (!array_key_exists ('name', $select_attrs))
312 return '';
313 if (!array_key_exists ('id', $select_attrs))
314 $select_attrs['id'] = $select_attrs['name'];
315 if ($tree)
316 {
317 # it is safe to call many times for the same file
318 addJS ('js/jquery.optionTree.js');
319 $ret = "<input type=hidden name=${select_attrs['name']}>\n";
320 $ret .= "<script type='text/javascript'>\n";
321 $ret .= "\$(function() {\n";
322 $ret .= " var option_tree = {\n";
323 foreach ($groupList as $groupname => $groupdata)
324 {
325 $ret .= " '${groupname}': {";
326 foreach ($groupdata as $dict_key => $dict_value)
327 $ret .= "\"${dict_value}\":'${dict_key}', ";
328 $ret .= "},\n";
329 }
330 $ret .= " };\n";
331 $ret .= " var options = {empty_value: -1, choose: 'select...'};\n";
332 $ret .= " \$('input[name=${select_attrs['name']}]').optionTree(option_tree, options);\n";
333 $ret .= "});\n";
334 $ret .= "</script>\n";
335 }
336 else
337 {
338 $ret = '<select';
339 foreach ($select_attrs as $attr_name => $attr_value)
340 $ret .= " ${attr_name}=${attr_value}";
341 $ret .= ">\n";
342 foreach ($groupList as $groupname => $groupdata)
343 {
344 $ret .= "<optgroup label='${groupname}'>\n";
345 foreach ($groupdata as $dict_key => $dict_value)
346 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>\n";
347 $ret .= "</optgroup>\n";
348 }
349 $ret .= "</select>\n";
350 }
351 return $ret;
352 }
353
354 function printImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
355 {
356 echo getImageHREF ($tag, $title, $do_input, $tabindex);
357 }
358
359 // this would be better called mkIMG(), make "IMG" HTML element
360 function getImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
361 {
362 global $image;
363 if (!isset ($image[$tag]))
364 $tag = 'error';
365 $img = $image[$tag];
366 $img['path'] = '?module=chrome&uri=' . $img['path'];
367 if ($do_input == TRUE)
368 return
369 "<input type=image name=submit class=icon " .
370 "src='${img['path']}' " .
371 "border=0 " .
372 ($tabindex ? "tabindex=${tabindex}" : '') .
373 (!strlen ($title) ? '' : " title='${title}'") . // JT: Add title to input hrefs too
374 ">";
375 else
376 return
377 "<img " .
378 "src='${img['path']}' " .
379 "width=${img['width']} " .
380 "height=${img['height']} " .
381 "border=0 " .
382 (!strlen ($title) ? '' : "title='${title}'") .
383 ">";
384 }
385
386 function dos2unix ($text)
387 {
388 return str_replace ("\r\n", "\n", $text);
389 }
390
391 function escapeString ($value, $do_db_escape = FALSE)
392 {
393 $ret = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
394 if ($do_db_escape)
395 {
396 global $dbxlink;
397 $ret = substr ($dbxlink->quote ($ret), 1, -1);
398 }
399 return $ret;
400 }
401
402 function transformRequestData()
403 {
404 global $sic;
405 // Magic quotes feature is deprecated, but just in case the local system
406 // still has it activated, reverse its effect.
407 $do_magic_quotes = (function_exists ('get_magic_quotes_gpc') and get_magic_quotes_gpc());
408 $seen_keys = array();
409
410 // Escape any globals before we ever try to use them, but keep a copy of originals.
411 $sic = array();
412 // walk through merged GET and POST instead of REQUEST array because it
413 // can contain cookies with data which could not be decoded from UTF-8
414 foreach (array_merge($_GET, $_POST) as $key => $value)
415 {
416 if (is_array ($value))
417 $_REQUEST[$key] = $value;
418 else
419 {
420 $value = dos2unix ($value);
421 if ($do_magic_quotes)
422 $value = stripslashes ($value);
423 $_REQUEST[$key] = escapeString ($value);
424 }
425 $sic[$key] = $value;
426 $seen_keys[$key] = 1;
427 }
428
429 // delete cookie information from the $_REQUEST array
430 foreach (array_keys ($_REQUEST) as $key)
431 if (! isset ($seen_keys[$key]))
432 unset ($_REQUEST[$key]);
433
434 if (isset ($_SERVER['PHP_AUTH_USER']))
435 $_SERVER['PHP_AUTH_USER'] = escapeString ($_SERVER['PHP_AUTH_USER']);
436 if (isset ($_SERVER['REMOTE_USER']))
437 $_SERVER['REMOTE_USER'] = escapeString ($_SERVER['REMOTE_USER']);
438 }
439
440 // JS scripts should be included through this function.
441 // They automatically appear in the <head> of your page.
442 // $data is a JS filename, or JS code w/o tags around, if $inline = TRUE
443 // Scripts are included in the order of adding within the same group, and groups are sorted alphabetically.
444 function addJS ($data, $inline = FALSE, $group = 'default')
445 {
446 static $javascript = array();
447 static $seen_filenames = array();
448
449 if (! isset ($data))
450 {
451 ksort ($javascript);
452 return $javascript;
453 }
454 // Add jquery.js and racktables.js the first time a Javascript file is added.
455 if (empty($javascript))
456 {
457 $javascript = array
458 (
459 'a_core' => array
460 (
461 array('type' => 'file', 'script' => 'js/jquery-1.4.4.min.js'),
462 array('type' => 'file', 'script' => 'js/racktables.js'),
463 ),
464 );
465
466 // initialize core js filelist
467 foreach ($javascript as $group_name => $group_array)
468 foreach ($group_array as $item)
469 if ($item['type'] == 'file')
470 $seen_filenames[$item['script']] = 1;
471 }
472
473 if ($inline)
474 $javascript[$group][] = array
475 (
476 'type' => 'inline',
477 'script' => $data,
478 );
479 elseif (! isset ($seen_filenames[$data]))
480 {
481 $javascript[$group][] = array
482 (
483 'type' => 'file',
484 'script' => $data,
485 );
486 $seen_filenames[$data] = 1;
487 }
488 }
489
490 // CSS styles should be included through this function.
491 // They automatically appear in the <head> of your page.
492 // $data is a CSS filename, or CSS code w/o tags around, if $inline = TRUE
493 // Styles are included in the order of adding.
494 function addCSS ($data, $inline = FALSE)
495 {
496 static $styles = array();
497 static $seen_filenames = array();
498
499 if (! isset ($data))
500 return $styles;
501 if ($inline)
502 $styles[] = array
503 (
504 'type' => 'inline',
505 'style' => $data,
506 );
507 elseif (! isset ($seen_filenames[$data]))
508 {
509 $styles[] = array
510 (
511 'type' => 'file',
512 'style' => $data,
513 );
514 $seen_filenames[$data] = 1;
515 }
516 }
517
518 // print part of HTML HEAD block
519 function printPageHeaders ()
520 {
521 global $pageheaders;
522 ksort ($pageheaders);
523 foreach ($pageheaders as $s)
524 echo $s . "\n";
525
526 // add CSS styles
527 foreach (addCSS (NULL) as $item)
528 if ($item['type'] == 'inline')
529 echo '<style type="text/css">' . "\n" . trim ($item['style'], "\r\n") . "\n</style>\n";
530 elseif ($item['type'] == 'file')
531 echo "<link rel=stylesheet type='text/css' href='?module=chrome&uri=${item['style']}' />\n";
532
533 // add JS scripts
534 foreach (addJS (NULL) as $group_name => $js_list)
535 foreach ($js_list as $item)
536 if ($item['type'] == 'inline')
537 echo '<script type="text/javascript">' . "\n" . trim ($item['script'], "\r\n") . "\n</script>\n";
538 elseif ($item['type'] == 'file')
539 echo "<script type='text/javascript' src='?module=chrome&uri=${item['script']}'></script>\n";
540 }
541
542 function validTagName ($s, $allow_autotag = FALSE)
543 {
544 if (1 == preg_match (TAGNAME_REGEXP, $s))
545 return TRUE;
546 if ($allow_autotag and 1 == preg_match (AUTOTAGNAME_REGEXP, $s))
547 return TRUE;
548 return FALSE;
549 }
550
551 function serializeTags ($chain, $baseurl = '')
552 {
553 $tmp = array();
554 foreach ($chain as $taginfo)
555 {
556 if ($baseurl == '')
557 $tmp[] = $taginfo['tag'];
558 else
559 {
560 $title = '';
561 if (isset ($taginfo['user']) and isset ($taginfo['time']))
562 $title = 'title="' . htmlspecialchars ($taginfo['user'] . ', ' . formatAge ($taginfo['time']), ENT_QUOTES) . '"';
563 $tmp[] = "<a $title href='${baseurl}cft[]=${taginfo['id']}'>" . $taginfo['tag'] . "</a>";
564 }
565 }
566 return implode (', ', $tmp);
567 }
568
569 function startPortlet ($title = '')
570 {
571 echo "<div class=portlet><h2>${title}</h2>";
572 }
573
574 function finishPortlet ()
575 {
576 echo "</div>\n";
577 }
578
579 ?>