libdir/filterlib.php");
require_once("$CFG->libdir/ajax/ajaxlib.php");
/// Constants
/// Define text formatting types ... eventually we can add Wiki, BBcode etc
/**
* Does all sorts of transformations and filtering
*/
define('FORMAT_MOODLE', '0'); // Does all sorts of transformations and filtering
/**
* Plain HTML (with some tags stripped)
*/
define('FORMAT_HTML', '1'); // Plain HTML (with some tags stripped)
/**
* Plain text (even tags are printed in full)
*/
define('FORMAT_PLAIN', '2'); // Plain text (even tags are printed in full)
/**
* Wiki-formatted text
* Deprecated: left here just to note that '3' is not used (at the moment)
* and to catch any latent wiki-like text (which generates an error)
*/
define('FORMAT_WIKI', '3'); // Wiki-formatted text
/**
* Markdown-formatted text http://daringfireball.net/projects/markdown/
*/
define('FORMAT_MARKDOWN', '4'); // Markdown-formatted text http://daringfireball.net/projects/markdown/
/**
* TRUSTTEXT marker - if present in text, text cleaning should be bypassed
*/
define('TRUSTTEXT', '#####TRUSTTEXT#####');
/**
* Allowed tags - string of html tags that can be tested against for safe html tags
* @global string $ALLOWED_TAGS
*/
global $ALLOWED_TAGS;
$ALLOWED_TAGS =
'
';
return implode("\n", $menu);
}
/**
* Prints form items with the names $day, $month and $year
*
* @param string $day fieldname
* @param string $month fieldname
* @param string $year fieldname
* @param int $currenttime A default timestamp in GMT
* @param boolean $return
*/
function print_date_selector($day, $month, $year, $currenttime=0, $return=false) {
if (!$currenttime) {
$currenttime = time();
}
$currentdate = usergetdate($currenttime);
for ($i=1; $i<=31; $i++) {
$days[$i] = $i;
}
for ($i=1; $i<=12; $i++) {
$months[$i] = userdate(gmmktime(12,0,0,$i,15,2000), "%B");
}
for ($i=1970; $i<=2020; $i++) {
$years[$i] = $i;
}
return choose_from_menu($days, $day, $currentdate['mday'], '', '', '0', $return)
.choose_from_menu($months, $month, $currentdate['mon'], '', '', '0', $return)
.choose_from_menu($years, $year, $currentdate['year'], '', '', '0', $return);
}
/**
*Prints form items with the names $hour and $minute
*
* @param string $hour fieldname
* @param string ? $minute fieldname
* @param $currenttime A default timestamp in GMT
* @param int $step minute spacing
* @param boolean $return
*/
function print_time_selector($hour, $minute, $currenttime=0, $step=5, $return=false) {
if (!$currenttime) {
$currenttime = time();
}
$currentdate = usergetdate($currenttime);
if ($step != 1) {
$currentdate['minutes'] = ceil($currentdate['minutes']/$step)*$step;
}
for ($i=0; $i<=23; $i++) {
$hours[$i] = sprintf("%02d",$i);
}
for ($i=0; $i<=59; $i+=$step) {
$minutes[$i] = sprintf("%02d",$i);
}
return choose_from_menu($hours, $hour, $currentdate['hours'], '','','0',$return)
.choose_from_menu($minutes, $minute, $currentdate['minutes'], '','','0',$return);
}
/**
* Prints time limit value selector
*
* @uses $CFG
* @param int $timelimit default
* @param string $unit
* @param string $name
* @param boolean $return
*/
function print_timer_selector($timelimit = 0, $unit = '', $name = 'timelimit', $return=false) {
global $CFG;
if ($unit) {
$unit = ' '.$unit;
}
// Max timelimit is sessiontimeout - 10 minutes.
$maxvalue = ($CFG->sessiontimeout / 60) - 10;
for ($i=1; $i<=$maxvalue; $i++) {
$minutes[$i] = $i.$unit;
}
return choose_from_menu($minutes, $name, $timelimit, get_string('none'), '','','0',$return);
}
/**
* Prints a grade menu (as part of an existing form) with help
* Showing all possible numerical grades and scales
*
* @uses $CFG
* @param int $courseid ?
* @param string $name ?
* @param string $current ?
* @param boolean $includenograde ?
* @todo Finish documenting this function
*/
function print_grade_menu($courseid, $name, $current, $includenograde=true, $return=false) {
global $CFG;
$output = '';
$strscale = get_string('scale');
$strscales = get_string('scales');
$scales = get_scales_menu($courseid);
foreach ($scales as $i => $scalename) {
$grades[-$i] = $strscale .': '. $scalename;
}
if ($includenograde) {
$grades[0] = get_string('nograde');
}
for ($i=100; $i>=1; $i--) {
$grades[$i] = $i;
}
$output .= choose_from_menu($grades, $name, $current, '', '', 0, true);
$linkobject = '';
$output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true', 'ratingscales',
$linkobject, 400, 500, $strscales, 'none', true);
if ($return) {
return $output;
} else {
echo $output;
}
}
/**
* Prints a scale menu (as part of an existing form) including help button
* Just like {@link print_grade_menu()} but without the numeric grades
*
* @param int $courseid ?
* @param string $name ?
* @param string $current ?
* @todo Finish documenting this function
*/
function print_scale_menu($courseid, $name, $current, $return=false) {
global $CFG;
$output = '';
$strscales = get_string('scales');
$output .= choose_from_menu(get_scales_menu($courseid), $name, $current, '', '', 0, true);
$linkobject = '';
$output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true', 'ratingscales',
$linkobject, 400, 500, $strscales, 'none', true);
if ($return) {
return $output;
} else {
echo $output;
}
}
/**
* Prints a help button about a scale
*
* @uses $CFG
* @param id $courseid ?
* @param object $scale ?
* @todo Finish documenting this function
*/
function print_scale_menu_helpbutton($courseid, $scale, $return=false) {
global $CFG;
$output = '';
$strscales = get_string('scales');
$linkobject = '';
$output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true&scaleid='. $scale->id, 'ratingscale',
$linkobject, 400, 500, $scale->name, 'none', true);
if ($return) {
return $output;
} else {
echo $output;
}
}
/**
* Print an error page displaying an error message.
* Old method, don't call directly in new code - use print_error instead.
*
*
* @uses $SESSION
* @uses $CFG
* @param string $message The message to display to the user about the error.
* @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
*/
function error ($message, $link='') {
global $CFG, $SESSION;
$message = clean_text($message); // In case nasties are in here
if (defined('FULLME') && FULLME == 'cron') {
// Errors in cron should be mtrace'd.
mtrace($message);
die;
}
if (! defined('HEADER_PRINTED')) {
//header not yet printed
@header('HTTP/1.0 404 Not Found');
print_header(get_string('error'));
}
echo ' ';
print_simple_box($message, '', '', '', '', 'errorbox');
debugging('Stack trace:', DEBUG_DEVELOPER);
// in case we are logging upgrade in admin/index.php stop it
if (function_exists('upgrade_log_finish')) {
upgrade_log_finish();
}
if (empty($link) and !defined('ADMIN_EXT_HEADER_PRINTED')) {
if ( !empty($SESSION->fromurl) ) {
$link = $SESSION->fromurl;
unset($SESSION->fromurl);
} else {
$link = $CFG->wwwroot .'/';
}
}
if (!empty($link)) {
print_continue($link);
}
print_footer();
for ($i=0;$i<512;$i++) { // Padding to help IE work with 404
echo ' ';
}
die;
}
/**
* Print an error page displaying an error message. New method - use this for new code.
*
* @uses $SESSION
* @uses $CFG
* @param string $errorcode The name of the string from error.php to print
* @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
* @param object $a Extra words and phrases that might be required in the error string
*/
function print_error ($errorcode, $module='', $link='', $a=NULL) {
global $CFG;
if (empty($module) || $module == 'moodle' || $module == 'core') {
$module = 'error';
$modulelink = 'moodle';
} else {
$modulelink = $module;
}
if (!empty($CFG->errordocroot)) {
$errordocroot = $CFG->errordocroot;
} else if (!empty($CFG->docroot)) {
$errordocroot = $CFG->docroot;
} else {
$errordocroot = 'http://docs.moodle.org';
}
$message = '
';
error($message, $link);
}
/**
* Returns a string of html with an image of a help icon linked to a help page on a number of help topics.
* Should be used only with htmleditor or textarea.
* @param mixed $helptopics variable amount of params accepted. Each param may be a string or an array of arguments for
* helpbutton.
* @return string
*/
function editorhelpbutton(){
global $CFG, $SESSION;
$items = func_get_args();
$i = 1;
$urlparams = array();
$titles = array();
foreach ($items as $item){
if (is_array($item)){
$urlparams[] = "keyword$i=".urlencode($item[0]);
$urlparams[] = "title$i=".urlencode($item[1]);
if (isset($item[2])){
$urlparams[] = "module$i=".urlencode($item[2]);
}
$titles[] = trim($item[1], ". \t");
}elseif (is_string($item)){
$urlparams[] = "button$i=".urlencode($item);
switch ($item){
case 'reading' :
$titles[] = get_string("helpreading");
break;
case 'writing' :
$titles[] = get_string("helpwriting");
break;
case 'questions' :
$titles[] = get_string("helpquestions");
break;
case 'emoticons' :
$titles[] = get_string("helpemoticons");
break;
case 'richtext' :
$titles[] = get_string('helprichtext');
break;
case 'text' :
$titles[] = get_string('helptext');
break;
default :
error('Unknown help topic '.$item);
}
}
$i++;
}
if (count($titles)>1){
//join last two items with an 'and'
$a = new object();
$a->one = $titles[count($titles) - 2];
$a->two = $titles[count($titles) - 1];
$titles[count($titles) - 2] = get_string('and', '', $a);
unset($titles[count($titles) - 1]);
}
$alttag = join (', ', $titles);
$paramstring = join('&', $urlparams);
$linkobject = '';
return link_to_popup_window(s('/lib/form/editorhelp.php?'.$paramstring), $alttag, $linkobject, 400, 500, $alttag, 'none', true);
}
/**
* Print a help button.
*
* @uses $CFG
* @param string $page The keyword that defines a help page
* @param string $title The title of links, rollover tips, alt tags etc
* 'Help with' (or the language equivalent) will be prefixed and '...' will be stripped.
* @param string $module Which module is the page defined in
* @param mixed $image Use a help image for the link? (true/false/"both")
* @param boolean $linktext If true, display the title next to the help icon.
* @param string $text If defined then this text is used in the page, and
* the $page variable is ignored.
* @param boolean $return If true then the output is returned as a string, if false it is printed to the current page.
* @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif
* @return string
* @todo Finish documenting this function
*/
function helpbutton ($page, $title='', $module='moodle', $image=true, $linktext=false, $text='', $return=false,
$imagetext='') {
global $CFG, $COURSE;
// fix for MDL-7734
if (!empty($COURSE->lang)) {
$forcelang = $COURSE->lang;
} else {
$forcelang = '';
}
if ($module == '') {
$module = 'moodle';
}
$tooltip = get_string('helpprefix2', '', trim($title, ". \t"));
$linkobject = '';
if ($image) {
if ($linktext) {
// MDL-7469 If text link is displayed with help icon, change to alt to "help with this".
$linkobject .= $title.' ';
$tooltip = get_string('helpwiththis');
}
if ($imagetext) {
$linkobject .= $imagetext;
} else {
$linkobject .= '';
}
} else {
$linkobject .= $tooltip;
}
$tooltip .= ' ('.get_string('newwindow').')'; // Warn users about new window for Accessibility
// fix for MDL-7734
if ($text) {
$url = '/help.php?module='. $module .'&text='. s(urlencode($text).'&forcelang='.$forcelang);
} else {
$url = '/help.php?module='. $module .'&file='. $page .'.html&forcelang='.$forcelang;
}
$link = ''.
link_to_popup_window ($url, 'popup', $linkobject, 400, 500, $tooltip, 'none', true).
'';
if ($return) {
return $link;
} else {
echo $link;
}
}
/**
* Print a help button.
*
* Prints a special help button that is a link to the "live" emoticon popup
* @uses $CFG
* @uses $SESSION
* @param string $form ?
* @param string $field ?
* @todo Finish documenting this function
*/
function emoticonhelpbutton($form, $field, $return = false) {
global $CFG, $SESSION;
$SESSION->inserttextform = $form;
$SESSION->inserttextfield = $field;
$imagetext = '';
$help = helpbutton('emoticons', get_string('helpemoticons'), 'moodle', true, true, '', true, $imagetext);
if (!$return){
echo $help;
} else {
return $help;
}
}
/**
* Print a help button.
*
* Prints a special help button for html editors (htmlarea in this case)
* @uses $CFG
*/
function editorshortcutshelpbutton() {
global $CFG;
$imagetext = '';
return helpbutton('editorshortcuts', get_string('editorshortcutkeys'), 'moodle', true, false, '', true, $imagetext);
}
/**
* Print a message and exit.
*
* @uses $CFG
* @param string $message ?
* @param string $link ?
* @todo Finish documenting this function
*/
function notice ($message, $link='', $course=NULL) {
global $CFG, $SITE;
$message = clean_text($message);
print_box($message, 'generalbox', 'notice');
print_continue($link);
if (empty($course)) {
print_footer($SITE);
} else {
print_footer($course);
}
exit;
}
/**
* Print a message along with "Yes" and "No" links for the user to continue.
*
* @param string $message The text to display
* @param string $linkyes The link to take the user to if they choose "Yes"
* @param string $linkno The link to take the user to if they choose "No"
* TODO Document remaining arguments
*/
function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno=NULL, $methodyes='post', $methodno='post') {
global $CFG;
$message = clean_text($message);
$linkyes = clean_text($linkyes);
$linkno = clean_text($linkno);
print_box_start('generalbox', 'notice');
echo '
';
print_box_end();
}
/**
* Provide an definition of error_get_last for PHP before 5.2.0. This simply
* returns NULL, since there is not way to get the right answer.
*/
if (!function_exists('error_get_last')) {
// the eval is needed to prevent PHP 5.2+ from getting a parse error!
eval('
function error_get_last() {
return NULL;
}
');
}
/**
* Redirects the user to another page, after printing a notice
*
* @param string $url The url to take the user to
* @param string $message The text message to display to the user about the redirect, if any
* @param string $delay How long before refreshing to the new page at $url?
* @todo '&' needs to be encoded into '&' for XHTML compliance,
* however, this is not true for javascript. Therefore we
* first decode all entities in $url (since we cannot rely on)
* the correct input) and then encode for where it's needed
* echo "";
*/
function redirect($url, $message='', $delay=-1) {
global $CFG;
if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) {
$url = sid_process_url($url);
}
$message = clean_text($message);
$encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url);
$encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text(''));
$url = str_replace('&', '&', $encodedurl);
/// At developer debug level. Don't redirect if errors have been printed on screen.
/// Currenly only works in PHP 5.2+; we do not want strict PHP5 errors
$lasterror = error_get_last();
$error = defined('DEBUGGING_PRINTED') or (!empty($lasterror) && ($lasterror['type'] & DEBUG_DEVELOPER));
$errorprinted = debugging('', DEBUG_ALL) && $CFG->debugdisplay && $error;
if ($errorprinted) {
$message = "Error output, so disabling automatic redirect.
" . $message;
}
$performanceinfo = '';
if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) {
if (defined('MDL_PERFTOLOG') && !function_exists('register_shutdown_function')) {
$perf = get_performance_info();
error_log("PERF: " . $perf['txt']);
}
}
/// when no message and header printed yet, try to redirect
if (empty($message) and !defined('HEADER_PRINTED')) {
// Technically, HTTP/1.1 requires Location: header to contain
// the absolute path. (In practice browsers accept relative
// paths - but still, might as well do it properly.)
// This code turns relative into absolute.
if (!preg_match('|^[a-z]+:|', $url)) {
// Get host name http://www.wherever.com
$hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot);
if (preg_match('|^/|', $url)) {
// URLs beginning with / are relative to web server root so we just add them in
$url = $hostpart.$url;
} else {
// URLs not beginning with / are relative to path of current script, so add that on.
$url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url;
}
// Replace all ..s
while (true) {
$newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url);
if ($newurl == $url) {
break;
}
$url = $newurl;
}
}
$delay = 0;
//try header redirection first
@header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); //302 might not work for POST requests, 303 is ignored by obsolete clients
@header('Location: '.$url);
//another way for older browsers and already sent headers (eg trailing whitespace in config.php)
echo '';
echo ''; // To cope with Mozilla bug
die;
}
if ($delay == -1) {
$delay = 3; // if no delay specified wait 3 seconds
}
if (! defined('HEADER_PRINTED')) {
// this type of redirect might not be working in some browsers - such as lynx :-(
print_header('', '', '', '', $errorprinted ? '' : (''));
$delay += 3; // double redirect prevention, it was sometimes breaking upgrades before 1.7
}
echo '
';
if (!$errorprinted) {
?>
'. $message .''."\n";
if ($return) {
return $output;
}
echo $output;
}
/**
* Given an email address, this function will return an obfuscated version of it
*
* @param string $email The email address to obfuscate
* @return string
*/
function obfuscate_email($email) {
$i = 0;
$length = strlen($email);
$obfuscated = '';
while ($i < $length) {
if (rand(0,2)) {
$obfuscated.='%'.dechex(ord($email{$i}));
} else {
$obfuscated.=$email{$i};
}
$i++;
}
return $obfuscated;
}
/**
* This function takes some text and replaces about half of the characters
* with HTML entity equivalents. Return string is obviously longer.
*
* @param string $plaintext The text to be obfuscated
* @return string
*/
function obfuscate_text($plaintext) {
$i=0;
$length = strlen($plaintext);
$obfuscated='';
$prev_obfuscated = false;
while ($i < $length) {
$c = ord($plaintext{$i});
$numerical = ($c >= ord('0')) && ($c <= ord('9'));
if ($prev_obfuscated and $numerical ) {
$obfuscated.=''.ord($plaintext{$i}).';';
} else if (rand(0,2)) {
$obfuscated.=''.ord($plaintext{$i}).';';
$prev_obfuscated = true;
} else {
$obfuscated.=$plaintext{$i};
$prev_obfuscated = false;
}
$i++;
}
return $obfuscated;
}
/**
* This function uses the {@link obfuscate_email()} and {@link obfuscate_text()}
* to generate a fully obfuscated email link, ready to use.
*
* @param string $email The email address to display
* @param string $label The text to dispalyed as hyperlink to $email
* @param boolean $dimmed If true then use css class 'dimmed' for hyperlink
* @return string
*/
function obfuscate_mailto($email, $label='', $dimmed=false) {
if (empty($label)) {
$label = $email;
}
if ($dimmed) {
$title = get_string('emaildisable');
$dimmed = ' class="dimmed"';
} else {
$title = '';
$dimmed = '';
}
return sprintf("%s",
obfuscate_text('mailto'), obfuscate_email($email),
obfuscate_text($label));
}
/**
* Prints a single paging bar to provide access to other pages (usually in a search)
*
* @param int $totalcount Thetotal number of entries available to be paged through
* @param int $page The page you are currently viewing
* @param int $perpage The number of entries that should be shown per page
* @param mixed $baseurl If this is a string then it is the url which will be appended with $pagevar, an equals sign and the page number.
* If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page.
* @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
* @param bool $nocurr do not display the current page as a link
* @param bool $return whether to return an output string or echo now
* @return bool or string
*/
function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false, $return=false) {
$maxdisplay = 18;
$output = '';
if ($totalcount > $perpage) {
$output .= '
';
}
if ($return) {
return $output;
}
echo $output;
return true;
}
/**
* This function is used to rebuild the tag because some formats (PLAIN and WIKI)
* will transform it to html entities
*
* @param string $text Text to search for nolink tag in
* @return string
*/
function rebuildnolinktag($text) {
$text = preg_replace('/<(\/*nolink)>/i','<$1>',$text);
return $text;
}
/**
* Prints a nice side block with an optional header. The content can either
* be a block of HTML or a list of text with optional icons.
*
* @param string $heading Block $title embedded in HTML tags, for example
.
* @param string $content ?
* @param array $list ?
* @param array $icons ?
* @param string $footer ?
* @param array $attributes ?
* @param string $title Plain text title, as embedded in the $heading.
* @todo Finish documenting this function. Show example of various attributes, etc.
*/
function print_side_block($heading='', $content='', $list=NULL, $icons=NULL, $footer='', $attributes = array(), $title='') {
//Accessibility: skip block link, with title-text (or $block_id) to differentiate links.
static $block_id = 0;
$block_id++;
if (empty($heading)) {
$skip_text = get_string('skipblock', 'access').' '.$block_id;
}
else {
$skip_text = get_string('skipa', 'access', strip_tags($title));
}
$skip_link = ''."\n".get_accesshide($skip_text)."\n".'';
$skip_dest = '';
if (! empty($heading)) {
$heading = $skip_link . $heading;
}
/*else { //ELSE: I think a single link on a page, "Skip block 4" is too confusing - don't print.
echo $skip_link;
}*/
print_side_block_start($heading, $attributes);
if ($content) {
echo $content;
if ($footer) {
echo '';
}
} else {
if ($list) {
$row = 0;
//Accessibility: replaced unnecessary table with list, see themes/standard/styles_layout.css
echo "\n
\n";
foreach ($list as $key => $string) {
echo '
';
if ($icons) {
echo '
'. $icons[$key] .'
';
}
echo '
'. $string .'
';
echo "
\n";
$row = $row ? 0:1;
}
echo "
\n";
}
if ($footer) {
echo '';
}
}
print_side_block_end($attributes);
echo $skip_dest;
}
/**
* Starts a nice side block with an optional header.
*
* @param string $heading ?
* @param array $attributes ?
* @todo Finish documenting this function
*/
function print_side_block_start($heading='', $attributes = array()) {
global $CFG, $THEME;
if (!empty($THEME->customcorners)) {
require_once($CFG->dirroot.'/lib/custom_corners_lib.php');
}
// If there are no special attributes, give a default CSS class
if (empty($attributes) || !is_array($attributes)) {
$attributes = array('class' => 'sideblock');
} else if(!isset($attributes['class'])) {
$attributes['class'] = 'sideblock';
} else if(!strpos($attributes['class'], 'sideblock')) {
$attributes['class'] .= ' sideblock';
}
// OK, the class is surely there and in addition to anything
// else, it's tagged as a sideblock
/*
// IE misery: if I do it this way, blocks which start hidden cannot be "unhidden"
// If there is a cookie to hide this thing, start it hidden
if (!empty($attributes['id']) && isset($_COOKIE['hide:'.$attributes['id']])) {
$attributes['class'] = 'hidden '.$attributes['class'];
}
*/
$attrtext = '';
foreach ($attributes as $attr => $val) {
$attrtext .= ' '.$attr.'="'.$val.'"';
}
echo '
';
if (!empty($THEME->customcorners)) {
echo '
'."\n";
}
if ($heading) {
//Accessibility: replaced
with H2; no, H2 more appropriate in moodleblock.class.php: _title_html.
// echo '
'.$heading.'
';
echo '
';
if (!empty($THEME->customcorners)) {
echo '
';
echo '
';
echo '
';
}
echo $heading;
if (!empty($THEME->customcorners)) {
echo '
';
}
echo '
';
} else {
if (!empty($THEME->customcorners)) {
echo '
';
}
}
if (!empty($THEME->customcorners)) {
echo '
';
echo '
';
$THEME->customcornersopen += 1;
}
echo '
';
}
/**
* Print table ending tags for a side block box.
*/
function print_side_block_end($attributes = array()) {
global $CFG, $THEME;
echo '
';
if (!empty($THEME->customcorners)) {
require_once($CFG->dirroot.'/lib/custom_corners_lib.php');
print_custom_corners_end();
}
echo '
';
// IE workaround: if I do it THIS way, it works! WTF?
if (!empty($CFG->allowuserblockhiding) && isset($attributes['id'])) {
echo '';
}
}
/**
* Prints out code needed for spellchecking.
* Original idea by Ludo (Marc Alier).
*
* Opening CDATA and