2 /****************************************************************/
4 /****************************************************************/
5 /* Copyright (c) 2002-2009 */
6 /* Inclusive Design Institute */
9 /* This program is free software. You can redistribute it and/or*/
10 /* modify it under the terms of the GNU General Public License */
11 /* as published by the Free Software Foundation. */
12 /****************************************************************/
13 // $Id: output.inc.php 10550 2010-12-17 17:48:06Z cindy $
14 if (!defined('AT_INCLUDE_PATH')) { exit; }
15 //require_once(AT_INCLUDE_PATH . 'classes/ContentOutputUtils.class.php');
17 /**********************************************************************************/
18 /* Output functions found in this file, in order:
20 /* - AT_date(format, timestamp, format_type)
23 /* - AT_print(input, name, Boolean runtime_html)
25 /* - smile_replace(text)
27 /* - make_clickable(text)
28 /* - image_replace(text)
29 /* - format_final_output(text, Boolean nl2br)
30 /* - highlight (input, var)
31 /* - format_content(input, Boolean html, glossary)
32 /* - find_terms(find_text)
34 /**********************************************************************************/
38 * Returns a formatted date string - Uses the same options as date(), but requires a % infront of each argument and the
39 * textual values are language dependent (unlike date()).
41 * @param string $format preferred date format
42 * @param string $timestamp value of timestamp
43 * @param int $format_type timestamp format, an AT_DATE constant
44 * @return string formatted date
45 * @see AT_DATE constants in include/lib/constants.inc.php
46 * @author Joel Kronenberg
50 The following options were added as language dependant:
51 %D: A textual representation of a week, three letters Mon through Sun
52 %F: A full textual representation of a month, such as January or March January through December
53 %l (lowercase 'L'): A full textual representation of the day of the week Sunday through Saturday
54 %M: A short textual representation of a month, three letters Jan through Dec
56 Support for the following maybe added later:
57 ?? %S: English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
58 ?? %a: Lowercase Ante meridiem and Post meridiem am or pm
59 ?? %A: Uppercase Ante meridiem and Post meridiem AM or PM
62 AT_DATE_MYSQL_DATETIME: YYYY-MM-DD HH:MM:SS
63 AT_DATE_MYSQL_TIMESTAMP_14: YYYYMMDDHHMMSS
64 AT_DATE_UNIX_TIMESTAMP: seconds since epoch
65 AT_DATE_INDEX_VALUE: 0-x, index into a date array
67 function AT_date($format='%Y-%M-%d', $timestamp = '', $format_type=AT_DATE_MYSQL_DATETIME) {
68 static $day_name_ext, $day_name_con, $month_name_ext, $month_name_con;
71 if (!isset($day_name_ext)) {
72 $day_name_ext = array( 'date_sunday',
80 $day_name_con = array( 'date_sun',
88 $month_name_ext = array('date_january',
101 $month_name_con = array('date_jan',
115 if ($format_type == AT_DATE_INDEX_VALUE) {
116 // apply timezone offset
117 // $timestamp = apply_timezone($timestamp);
119 if ($format == '%D') {
120 return _AT($day_name_con[$timestamp-1]);
121 } else if ($format == '%l') {
122 return _AT($day_name_ext[$timestamp-1]);
123 } else if ($format == '%F') {
124 return _AT($month_name_ext[$timestamp-1]);
125 } else if ($format == '%M') {
126 return _AT($month_name_con[$timestamp-1]);
130 if ($timestamp == '') {
132 $format_type = AT_DATE_UNIX_TIMESTAMP;
135 /* convert the date to a Unix timestamp before we do anything with it */
136 if ($format_type == AT_DATE_MYSQL_DATETIME) {
137 $year = substr($timestamp,0,4);
138 $month = substr($timestamp,5,2);
139 $day = substr($timestamp,8,2);
140 $hour = substr($timestamp,11,2);
141 $min = substr($timestamp,14,2);
142 $sec = substr($timestamp,17,2);
143 $timestamp = mktime($hour, $min, $sec, $month, $day, $year);
145 } else if ($format_type == AT_DATE_MYSQL_TIMESTAMP_14) {
146 $year = substr($timestamp,0,4);
147 $month = substr($timestamp,4,2);
148 $day = substr($timestamp,6,2);
149 $hour = substr($timestamp,8,2);
150 $minute = substr($timestamp,10,2);
151 $second = substr($timestamp,12,2);
152 $timestamp = mktime($hour, $minute, $second, $month, $day, $year);
155 // apply timezone offset
156 $timestamp = apply_timezone($timestamp);
158 /* pull out all the %X items from $format */
159 $first_token = strpos($format, '%');
160 if ($first_token === false) {
161 /* no tokens found */
164 $tokened_format = substr($format, $first_token);
166 $tokens = explode('%', $tokened_format);
167 array_shift($tokens);
168 $num_tokens = count($tokens);
171 for ($i=0; $i<$num_tokens; $i++) {
172 $tokens[$i] = substr($tokens[$i],0,1);
174 if ($tokens[$i] == 'D') {
175 $output = str_replace('%D', _AT($day_name_con[date('w', $timestamp)]),$output);
177 } else if ($tokens[$i] == 'l') {
178 $output = str_replace('%l', _AT($day_name_ext[date('w', $timestamp)]),$output);
180 } else if ($tokens[$i] == 'F') {
181 $output = str_replace('%F', _AT($month_name_ext[date('n', $timestamp)-1]),$output);
183 } else if ($tokens[$i] == 'M') {
184 $output = str_replace('%M', _AT($month_name_con[date('n', $timestamp)-1]),$output);
188 /* this token doesn't need translating */
189 $value = date($tokens[$i], $timestamp);
190 if ($value != $tokens[$i]) {
191 $output = str_replace('%'.$tokens[$i], $value, $output);
192 } /* else: this token isn't valid. so don't replace it. Eg. try %q */
200 * Converts language code to actual language message, caches them according to page url
202 * @param args unlimited number of arguments allowed but first arg MUST be name of the language variable/term
203 * i.e $args[0] = the term to the format string $_template[term]
204 * $args[1..x] = optional arguments to the formatting string
205 * @return string|array full resulting message
206 * @see $db in include/vitals.inc.php
207 * @see cache() in include/phpCache/phpCache.inc.php
208 * @see cache_variable() in include/phpCache/phpCache.inc.php
209 * @author Joel Kronenberg
212 global $_cache_template, $lang_et, $_rel_url;
215 $args = func_get_args();
218 if (!is_array($args[0])) {
220 * Added functionality for translating language code String (AT_ERROR|AT_INFOS|AT_WARNING|AT_FEEDBACK|AT_HELP).*
221 * to its text and returning the result. No caching needed.
222 * @author Jacek Materna
225 // Check for specific language prefix, extendible as needed
226 // 0002767: a substring+in_array test should be faster than a preg_match test.
227 // replaced the preg_match with a test of the substring.
228 $sub_arg = substr($args[0], 0, 7); // 7 is the shortest type of msg (AT_HELP)
229 if (in_array($sub_arg, array('AT_ERRO','AT_INFO','AT_WARN','AT_FEED','AT_HELP','AT_CONF'))) {
231 global $_base_path, $addslashes;
233 $args[0] = $addslashes($args[0]);
235 /* get $_msgs_new from the DB */
236 $sql = 'SELECT text FROM '.TABLE_PREFIX.'language_text WHERE term="' . $args[0] . '" AND (variable="_msgs" OR variable="_c_msgs") AND language_code="'.$_SESSION['lang'].'" ORDER BY variable ASC LIMIT 1';
238 $result = @mysql_query($sql, $db);
242 if ($row = @mysql_fetch_assoc($result)) {
243 // do not cache key as a digit (no contstant(), use string)
244 $msgs = str_replace('SITE_URL/', $_base_path, $row['text']);
245 if (defined('AT_DEVEL') && AT_DEVEL) {
246 $msgs .= ' <small><small>('. $args[0] .')</small></small>';
250 $sql = 'INSERT INTO '.TABLE_PREFIX.'language_pages (`term`, `page`) VALUES ("'.$args[0].'", "'.$_rel_url.'")';
251 mysql_query($sql, $db);
257 // a template variable
258 if (!isset($_template)) {
259 $url_parts = parse_url(AT_BASE_HREF);
260 $name = substr($_SERVER['PHP_SELF'], strlen($url_parts['path'])-1);
262 if ( !($lang_et = cache(120, 'lang', $_SESSION['lang'].'_'.$name)) ) {
265 /* get $_template from the DB */
267 $sql = "SELECT L.* FROM ".TABLE_PREFIX."language_text L, ".TABLE_PREFIX."language_pages P WHERE L.language_code='{$_SESSION['lang']}' AND L.variable<>'_msgs' AND L.term=P.term AND P.page='$_rel_url' ORDER BY L.variable ASC";
268 $result = mysql_query($sql, $db);
269 while ($row = mysql_fetch_assoc($result)) {
270 //Do not overwrite the variable that existed in the cache_template already.
271 //The edited terms (_c_template) will always be at the top of the resultset
273 if (isset($_cache_template[$row['term']])){
277 // saves us from doing an ORDER BY
278 if ($row['language_code'] == $_SESSION['lang']) {
279 $_cache_template[$row['term']] = stripslashes($row['text']);
280 } else if (!isset($_cache_template[$row['term']])) {
281 $_cache_template[$row['term']] = stripslashes($row['text']);
285 cache_variable('_cache_template');
286 endcache(true, false);
288 $_template = $_cache_template;
290 $num_args = func_num_args();
291 if (is_array($args[0])) {
293 $num_args = count($args);
295 $format = array_shift($args);
297 if (isset($_template[$format])) {
299 var_dump($_template);
304 $outString = vsprintf($_template[$format], $args);
305 $str = ob_get_contents();
311 if ($outString === false) {
312 return ('[Error parsing language. Variable: <code>'.$format.'</code>. Language: <code>'.$_SESSION['lang'].'</code> ]');
315 if (empty($outString)) {
317 $sql = 'SELECT L.* FROM '.TABLE_PREFIX.'language_text L WHERE L.language_code="'.$_SESSION['lang'].'" AND L.variable<>"_msgs" AND L.term="'.$format.'"';
319 $result = mysql_query($sql, $db);
320 $row = mysql_fetch_assoc($result);
322 $_template[$row['term']] = stripslashes($row['text']);
323 $outString = $_template[$row['term']];
324 if (empty($outString)) {
325 return ('[ '.$format.' ]');
327 $outString = $_template[$row['term']];
328 $outString = vsprintf($outString, $args);
330 /* update the locations */
331 $sql = 'INSERT INTO '.TABLE_PREFIX.'language_pages (`term`, `page`) VALUES ("'.$format.'", "'.$_rel_url.'")';
332 mysql_query($sql, $db);
338 /**********************************************************************************************************/
340 * Transforms text based on formatting preferences. Original $input is also changed (passed by reference).
342 * 1) $output = AT_print($input, $name);
345 * 2) echo AT_print($input, $name); // prefered method
348 * @param string $input text being transformed
349 * @param string $name the unique name of this field (convension: table_name.field_name)
350 * @param boolean $runtime_html forcefully disables html formatting for $input (only used by fields that
351 * have the 'formatting' option
352 * @return string transformed $input
353 * @see AT_FORMAT constants in include/lib/constants.inc.php
354 * @see query_bit() in include/vitals.inc.php
355 * @author Joel Kronenberg
357 function AT_print($input, $name, $runtime_html = true) {
358 global $_field_formatting, $_config;
360 if (!isset($_field_formatting[$name])) {
361 /* field not set, check if there's a global setting */
362 $parts = explode('.', $name);
364 /* check if wildcard is set: */
365 if (isset($_field_formatting[$parts[0].'.*'])) {
366 $name = $parts[0].'.*';
368 /* field not set, and there's no global setting */
369 /* same as AT_FORMAT_NONE */
374 if (query_bit($_field_formatting[$name], AT_FORMAT_QUOTES)) {
375 $input = str_replace('"', '"', $input);
378 if (query_bit($_field_formatting[$name], AT_FORMAT_CONTENT_DIR)) {
379 $input = str_replace('CONTENT_DIR/', '', $input);
382 if (query_bit($_field_formatting[$name], AT_FORMAT_HTML) && $runtime_html) {
383 /* what special things do we have to do if this is HTML ? remove unwanted HTML? validate? */
385 $input = str_replace('<', '<', $input);
386 $input = nl2br($input);
389 if (isset($_config['latex_server']) && $_config['latex_server']) {
390 $input = preg_replace('/\[tex\](.*?)\[\/tex\]/sie', "'<img src=\"'.\$_config['latex_server'].rawurlencode('$1').'\" align=\"middle\" alt=\"'.'$1'.'\" title=\"'.'$1'.'\">'", $input);
393 /* this has to be here, only because AT_FORMAT_HTML is the only check that has an else-block */
394 if ($_field_formatting[$name] === AT_FORMAT_NONE) {
398 if (query_bit($_field_formatting[$name], AT_FORMAT_EMOTICONS)) {
399 $input = smile_replace($input);
402 if (query_bit($_field_formatting[$name], AT_FORMAT_ATCODES)) {
403 $input = trim(myCodes(' ' . $input . ' '));
406 if (query_bit($_field_formatting[$name], AT_FORMAT_LINKS)) {
407 $input = trim(make_clickable(' ' . $input . ' '));
410 if (query_bit($_field_formatting[$name], AT_FORMAT_IMAGES)) {
411 $input = trim(image_replace(' ' . $input . ' '));
418 /********************************************************************************************/
419 // Global variables for emoticons
423 if (!isset($smile_pics)) {
424 $smile_pics[0] = $_base_path.'images/forum/smile.gif';
425 $smile_pics[1] = $_base_path.'images/forum/wink.gif';
426 $smile_pics[2] = $_base_path.'images/forum/frown.gif';
427 $smile_pics[3] = $_base_path.'images/forum/ohwell.gif';
428 $smile_pics[4] = $_base_path.'images/forum/tongue.gif';
429 $smile_pics[5] = $_base_path.'images/forum/51.gif';
430 $smile_pics[6] = $_base_path.'images/forum/52.gif';
431 $smile_pics[7] = $_base_path.'images/forum/54.gif';
432 $smile_pics[8] = $_base_path.'images/forum/27.gif';
433 $smile_pics[9] = $_base_path.'images/forum/19.gif';
434 $smile_pics[10] = $_base_path.'images/forum/3.gif';
435 $smile_pics[11] = $_base_path.'images/forum/56.gif';
438 if (!isset($smile_codes)) {
439 $smile_codes[0] = ':)';
440 $smile_codes[1] = ';)';
441 $smile_codes[2] = ':(';
442 $smile_codes[3] = '::ohwell::';
443 $smile_codes[4] = ':P';
444 $smile_codes[5] = '::evil::';
445 $smile_codes[6] = '::angry::';
446 $smile_codes[7] = '::lol::';
447 $smile_codes[8] = '::crazy::';
448 $smile_codes[9] = '::tired::';
449 $smile_codes[10] = '::confused::';
450 $smile_codes[11] = '::muah::';
454 * Replaces smile-code text into smilie image.
456 * @param string $text smile text to be transformed
457 * @return string transformed $text
458 * @see $smile_pics in include/lib/output.inc.php (above)
459 * @see $smile_codes in include/lib/output.inc.php (above)
460 * @author Joel Kronenberg
462 function smile_replace($text) {
467 $smiles[0] = '<img src="'.$smile_pics[0].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_smile').'" />';
468 $smiles[1] = '<img src="'.$smile_pics[1].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_wink').'" />';
469 $smiles[2] = '<img src="'.$smile_pics[2].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_frown').'" />';
470 $smiles[3]= '<img src="'.$smile_pics[3].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_oh_well').'" />';
471 $smiles[4]= '<img src="'.$smile_pics[4].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_tongue').'" />';
472 $smiles[5]= '<img src="'.$smile_pics[5].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_evil').'" />';
473 $smiles[6]= '<img src="'.$smile_pics[6].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_angry').'" />';
474 $smiles[7]= '<img src="'.$smile_pics[7].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_lol').'" />';
475 $smiles[8]= '<img src="'.$smile_pics[8].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_crazy').'" />';
476 $smiles[9]= '<img src="'.$smile_pics[9].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_tired').'" />';
477 $smiles[10]= '<img src="'.$smile_pics[10].'" border="0" height="17" width="19" align="bottom" alt="'._AT('smile_confused').'" />';
478 $smiles[11]= '<img src="'.$smile_pics[11].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_muah').'" />';
480 $text = str_replace($smile_codes[0],$smiles[0],$text);
481 $text = str_replace($smile_codes[1],$smiles[1],$text);
482 $text = str_replace($smile_codes[2],$smiles[2],$text);
483 $text = str_replace($smile_codes[3],$smiles[3],$text);
484 $text = str_replace($smile_codes[4],$smiles[4],$text);
485 $text = str_replace($smile_codes[5],$smiles[5],$text);
486 $text = str_replace($smile_codes[6],$smiles[6],$text);
487 $text = str_replace($smile_codes[7],$smiles[7],$text);
488 $text = str_replace($smile_codes[8],$smiles[8],$text);
489 $text = str_replace($smile_codes[9],$smiles[9],$text);
490 $text = str_replace($smile_codes[10],$smiles[10],$text);
491 $text = str_replace($smile_codes[11],$smiles[11],$text);
497 /* Used specifically for the visual editor
499 function smile_javascript () {
506 while ($smile_pics [$i]) {
507 echo 'case "'.$smile_codes[$i].'":'."\n";
508 echo 'pic = "'.$smile_pics[$i].'";'."\n";
514 function myCodes($text, $html = false) {
516 global $HTTP_USER_AGENT;
518 if (substr($HTTP_USER_AGENT,0,11) == 'Mozilla/4.7') {
519 $text = str_replace('[quote]','</p><p class="block">',$text);
520 $text = str_replace('[/quote]','</p><p>',$text);
522 $text = str_replace('[reply]','</p><p class="block">',$text);
523 $text = str_replace('[/reply]','</p><p>',$text);
525 $text = str_replace('[quote]','<blockquote>',$text);
526 $text = str_replace('[/quote]','</blockquote><p>',$text);
528 $text = str_replace('[reply]','</p><blockquote class="block"><p>',$text);
529 $text = str_replace('[/reply]','</p></blockquote><p>',$text);
532 $text = str_replace('[b]','<strong>',$text);
533 $text = str_replace('[/b]','</strong>',$text);
535 $text = str_replace('[i]','<em>',$text);
536 $text = str_replace('[/i]','</em>',$text);
538 $text = str_replace('[u]','<u>',$text);
539 $text = str_replace('[/u]','</u>',$text);
541 $text = str_replace('[center]','<center>',$text);
542 $text = str_replace('[/center]','</center><p>',$text);
545 $text = str_replace('[blue]','<span style="color: blue;">',$text);
546 $text = str_replace('[/blue]','</span>',$text);
548 $text = str_replace('[orange]','<span style="color: orange;">',$text);
549 $text = str_replace('[/orange]','</span>',$text);
551 $text = str_replace('[red]','<span style="color: red;">',$text);
552 $text = str_replace('[/red]','</span>',$text);
554 $text = str_replace('[purple]','<span style="color: purple;">',$text);
555 $text = str_replace('[/purple]','</span>',$text);
557 $text = str_replace('[green]','<span style="color: green;">',$text);
558 $text = str_replace('[/green]','</span>',$text);
560 $text = str_replace('[gray]','<span style="color: gray;">',$text);
561 $text = str_replace('[/gray]','</span>',$text);
563 $text = str_replace('[op]','<span class="bigspacer"></span> <a href="',$text);
564 $text = str_replace('[/op]','">'._AT('view_entire_post').'</a>',$text);
566 $text = str_replace('[head1]','<h2>',$text);
567 $text = str_replace('[/head1]','</h2>',$text);
569 $text = str_replace('[head2]','<h3>',$text);
570 $text = str_replace('[/head2]','</h3>',$text);
572 $text = str_replace('[cid]',$_base_path.'content.php?cid='.$_SESSION['s_cid'],$text);
574 // fix for http://www.atutor.ca/atutor/mantis/view.php?id=4104
575 global $sequence_links;
576 if ($_SESSION['course_id'] > 0 && !isset($sequence_links) && $_REQUEST['cid'] > 0) {
577 global $contentManager;
578 $sequence_links = $contentManager->generateSequenceCrumbs($_REQUEST['cid']);
580 if (isset($sequence_links['previous']) && $sequence_links['previous']['url']) {
581 $text = str_replace('[pid]', $sequence_links['previous']['url'], $text);
583 if (isset($sequence_links['next']) && $sequence_links['next']['url']) {
584 $text = str_replace('[nid]', $sequence_links['next']['url'], $text);
586 if (isset($sequence_links['resume']) && $sequence_links['resume']['url']) {
587 $text = str_replace('[nid]', $sequence_links['resume']['url'], $text);
589 if (isset($sequence_links['first']) && $sequence_links['first']['url']) {
590 $text = str_replace('[fid]', $sequence_links['first']['url'], $text);
593 //LAW - replace </p><p> tags in [code] tags with <br />
594 //http://www.atutor.ca/atutor/mantis/view.php?id=4134 - attempt to fix this bug - does not work as required
595 // $outputUtils = new ContentOutputUtils();
596 // $text = $outputUtils ->stripPtags($text);
598 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
599 $html = !$html ? 0 : 1;
601 // little hack added by greg to add syntax highlighting without using <?php \?\>
603 $text = str_replace("[code]","[code]<?php",$text);
604 $text = str_replace("[/code]","?>[/code]",$text);
606 $text = preg_replace("/\[code\]\s*(.*)\s*\[\\/code\]/Usei", "highlight_code(fix_quotes('\\1'), $html)", $text);
607 // now remove the <?php added above and leave the syntax colour behind.
608 $text = str_replace("<?php", "", $text);
609 $text = str_replace("?>", "", $text);
614 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
615 function highlight_code($code, $html) {
616 // XHTMLize PHP highlight_string output until it gets fixed in PHP
617 static $search = array(
623 static $replace = array(
629 $code = str_replace('<', '<', $code);
630 $code = str_replace("\r", '', $code);
633 return str_replace($search, $replace, highlight_string($code, true));
636 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
637 function fix_quotes($text){
638 return str_replace('\\"', '"', $text);
642 * This function converts the youtube playable url used in <object> tag (for instance: http://www.youtube.com/v/a0ryB0m0MiM)
643 * to youtube url that is used to browse (for instance: http://www.youtube.com/watch?v=a0ryB0m0MiM)
644 * @param: youtube playable URL. For instance, http://www.youtube.com/v/a0ryB0m0MiM
645 * @return: if the param is a youtube playable url, return the according youtube URL used to browse.
646 * For instance: http://www.youtube.com/watch?v=a0ryB0m0MiM
647 * Otherwise, return the original send-in parameter.
649 function convert_youtube_playURL_to_watchURL($youtube_playURL) {
650 return preg_replace("/(http:\/\/[a-z0-9\.]*)?youtube.com\/v\/(.*)/",
651 "\\1youtube.com/watch?v=\\2", $youtube_playURL);
655 * This function converts the youtube url that is used to browse (for instance: http://www.youtube.com/watch?v=a0ryB0m0MiM)
656 * to youtube playable url used in <object> tag (for instance: http://www.youtube.com/v/a0ryB0m0MiM)
657 * @param: the youtube URL used to browse.
658 * For instance: http://www.youtube.com/watch?v=a0ryB0m0MiM
659 * @return: if the param is a youtube url used to browse, return the according youtube playable URL.
660 * For instance, http://www.youtube.com/v/a0ryB0m0MiM
661 * Otherwise, return the original send-in parameter.
663 function convert_youtube_watchURL_to_playURL($youtube_watchURL) {
664 return preg_replace("/(http:\/\/[a-z0-9\.]*)?youtube.com\/watch\?v=(.*)/",
665 "\\1youtube.com/v/\\2", $youtube_watchURL);
668 function embed_media($text) {
671 if (preg_match("/\[media(\|[0-9]+\|[0-9]+)?\]*/", $text)==0){
675 // 1. remove the spaces in [media] tag, otherwise, the next line converts URL inside [media] into <a> tag
676 $text = preg_replace("/(\[media\])([\s]*)(.*)(\[\/media\])/", '$1$3$4', $text);
677 $text = preg_replace("/(\[media\])(.*)([\s]*)(\[\/media\])/U", '$1$2$4', $text);
679 $media_matches = array();
680 $media_replace = array();
682 // First, we search though the text for all different kinds of media defined by media tags and store the results in $media_matches.
683 // Then the different replacements for the different media tags are stored in $media_replace.
684 // Lastly, we loop through all $media_matches / $media_replaces. (We choose $media_replace as index because $media_matches is multi-dimensioned.) It is important that for each $media_matches there is a $media_replace with the same index. For each media match we check the width/height, or we use the default value of 425x350. We then replace the height/width/media1/media2 parameter placeholders in $media_replace with the correct ones, before running a str_replace on $text, replacing the given media with its correct replacement.
687 if (is_mobile_device() && get_mobile_device_type() == BLACKBERRY_DEVICE) {
688 preg_match_all("#\[media[0-9a-z\|]*\]http://([a-z0-9\.]*)?youtube.com/watch\?v=(.*)\[/media\]#iU",$text,$media_matches[],PREG_SET_ORDER);
689 $media_replace[] = '<script type="text/javascript" src="'.$_base_path.'jscripts/ATutorYouTubeOnBlackberry.js"></script>'."\n".
690 '<p id="blackberry_##MEDIA2##">'."\n".
692 ' src="http://gdata.youtube.com/feeds/mobile/videos/##MEDIA2##?alt=json-in-script&callback=ATutor.course.showYouTubeOnBlackberry&format=6" [^]'."\n".
693 ' type="text/javascript">'."\n".
696 preg_match_all("#\[media[0-9a-z\|]*\]http://([a-z0-9\.]*)?youtube.com/watch\?v=(.*)\[/media\]#iU",$text,$media_matches[],PREG_SET_ORDER);
697 $media_replace[] = '<object width="##WIDTH##" height="##HEIGHT##"><param name="movie" value="http://##MEDIA1##youtube.com/v/##MEDIA2##"></param><embed src="http://##MEDIA1##youtube.com/v/##MEDIA2##" type="application/x-shockwave-flash" width="##WIDTH##" height="##HEIGHT##"></embed></object>';
701 preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mpg\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
702 $media_replace[] = "<object data=\"##MEDIA1##.mpg\" type=\"video/mpeg\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mpg\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.mpg\">##MEDIA1##.mpg</a></object>";
705 preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).avi\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
706 $media_replace[] = "<object data=\"##MEDIA1##.avi\" type=\"video/x-msvideo\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.avi\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.avi\">##MEDIA1##.avi</a></object>";
709 preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).wmv\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
710 $media_replace[] = "<object data=\"##MEDIA1##.wmv\" type=\"video/x-ms-wmv\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.wmv\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.wmv\">##MEDIA1##.wmv</a></object>";
713 preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mov\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
714 $media_replace[] = "<object classid=\"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B\" codebase=\"http://www.apple.com/qtactivex/qtplugin.cab\" width=\"##WIDTH##\" height=\"##HEIGHT##\">\n".
715 " <param name=\"src\" value=\"##MEDIA1##.mov\">\n".
716 " <param name=\"controller\" value=\"true\">\n".
717 " <param name=\"autoplay\" value=\"false\">\n".
718 " <!--[if gte IE 7] > <!-->\n".
719 " <object type=\"video/quicktime\" data=\"##MEDIA1##.mov\" width=\"##WIDTH##\" height=\"##HEIGHT##\">\n".
720 " <param name=\"controller\" value=\"true\">\n".
721 " <param name=\"autoplay\" value=\"false\">\n".
722 " <a href=\"##MEDIA1##.mov\">##MEDIA1##.mov</a>\n".
724 " <!--<![endif]-->\n".
725 " <!--[if lt IE 7]>\n".
726 " <a href=\"##MEDIA1##.mov\">##MEDIA1##.mov</a>\n".
731 preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).swf\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
732 $media_replace[] = "<object type=\"application/x-shockwave-flash\" data=\"##MEDIA1##.swf\" width=\"##WIDTH##\" height=\"##HEIGHT##\"> <param name=\"movie\" value=\"##MEDIA1##.swf\"><param name=\"loop\" value=\"false\"><a href=\"##MEDIA1##.swf\">##MEDIA1##.swf</a></object>";
735 preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mp3\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
736 $media_replace[] = "<object type=\"audio/mpeg\" data=\"##MEDIA1##.mp3\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mp3\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.mp3\">##MEDIA1##.mp3</a></object>";
739 preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).wav\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
740 $media_replace[] ="<object type=\"audio/x-wav\" data=\"##MEDIA1##.wav\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.wav\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.wav\">##MEDIA1##.wav</a></object>";
743 preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).ogg\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
744 $media_replace[] ="<object type=\"application/ogg\" data=\"##MEDIA1##.ogg\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.ogg\"><a href=\"##MEDIA1##.ogg\">##MEDIA1##.ogg</a></object>";
747 preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).ogm\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
748 $media_replace[] ="<object type=\"application/ogm\" data=\"##MEDIA1##.ogm\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.ogm\"><a href=\"##MEDIA1##.ogg\">##MEDIA1##.ogm</a></object>";
751 preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).mid\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
752 $media_replace[] ="<object type=\"application/x-midi\" data=\"##MEDIA1##.mid\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mid\"><a href=\"##MEDIA1##.mid\">##MEDIA1##.mid</a></object>";
754 $text = preg_replace("#\[media[0-9a-z\|]*\](.+[^\s\"]+).mid\[/media\]#i", "<object type=\"application/x-midi\" data=\"\\1.mid\" width=\"".$width."\" height=\"".$height."\"><param name=\"src\" value=\"\\1.mid\"><a href=\"\\1.mid\">\\1.mid</a></object>", $text);
756 // Executing the replace
757 for ($i=0;$i<count($media_replace);$i++){
758 foreach($media_matches[$i] as $media)
761 //find width and height for each matched media
762 if (preg_match("/\[media\|([0-9]*)\|([0-9]*)\]*/", $media[0], $matches))
764 $width = $matches[1];
765 $height = $matches[2];
773 //replace media tags with embedded media for each media tag
774 $media_input = $media_replace[$i];
775 $media_input = str_replace("##WIDTH##","$width",$media_input);
776 $media_input = str_replace("##HEIGHT##","$height",$media_input);
777 $media_input = str_replace("##MEDIA1##","$media[1]",$media_input);
778 $media_input = str_replace("##MEDIA2##","$media[2]",$media_input);
780 $text = str_replace($media[0],$media_input,$text);
787 function make_clickable($text) {
788 $text = embed_media($text);
790 // $text = eregi_replace("([[:space:]])(http[s]?)://([^[:space:]<]*)([[:alnum:]#?/&=])", "\\1<a href=\"\\2://\\3\\4\">\\3\\4</a>", $text);
792 // $text = eregi_replace( '([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.
793 // '\@'.'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+)',
794 // "<a href=\"mailto:\\1\">\\1</a>",
797 // convert plain text URL to clickable URL.
798 // Limited conversion: It doesn't cover the case when the stuff in front of the URL is not a word. For example:
799 // <p>http://google.ca</p>
800 // "http://google.ca"
801 $text = preg_replace('/(^|[\n ])([\w]*?)((?<!(\[media\]))http(s)?:\/\/[\w]+[^ \,\"\n\r\t\)<]*)/is',
802 '$1$2<a href="$3">$3</a>', $text);
804 // convert email address to clickable URL that pops up "send email" interface with the address filled in
805 $text = preg_replace('/(?|<a href="mailto[\s]*:[\s]*([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'\@'
806 .'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+)">(.*)<\/a>'
807 .'|((((([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'\@'
808 .'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+))))))/i',
809 "<a href=\"mailto:\\1\">\\5</a>",
814 function image_replace($text) {
815 /* image urls do not require http:// */
817 // $text = eregi_replace("\[image(\|)?([[:alnum:][:space:]]*)\]" .
819 // "([[:alnum:]#?/&=:\"'_.-]+)" .
821 // "((\[/image\])|(.*\[/image\]))",
822 // "<img src=\"\\3\" alt=\"\\2\" />",
825 $text = preg_replace("/\[image(\|)?([a-zA-Z0-9\s]*)\]".
827 "([a-zA-Z0-9\#\?\/\&\=\:\\\"\'\_\.\-]+)[\s]*".
828 "((\[\/image\])|(.*\[\/image\]))/i",
829 "<img src=\"\\3\" alt=\"\\2\" />",
835 function format_final_output($text, $nl2br = true) {
838 $text = str_replace('CONTENT_DIR/', '', $text);
840 return nl2br(image_replace(make_clickable(myCodes(' '.$text, false))));
843 return image_replace(make_clickable(myCodes(' '.$text, true)));
847 function apply_customized_format($input) {
848 global $_input, $moduleFactory, $content_base_href, $_content_base_href;
851 $_content_base_href = $content_base_href;
853 $enabled_modules = $moduleFactory->getModules(AT_MODULE_STATUS_ENABLED);
855 if (is_array($enabled_modules))
857 foreach ($enabled_modules as $dir_name => $mod)
859 $module_content_format_file = AT_INCLUDE_PATH . '../mods/'.$dir_name.'/module_format_content.php';
860 if (file_exists($module_content_format_file))
862 include($module_content_format_file);
869 /****************************************************************************************/
870 /* @See: ./user/search.php & ./index.php */
871 function highlight($input, $var) {//$input is the string, $var is the text to be highlighted
876 The following 'if' statement is a check to ensure that the search term is not part of the tag, '<strong class="highlight">'. Words within this string are avoided in case a previously highlighted string is used for the haystack, $input. To avoid any html breaks in the highlighted string, the search word is avoided completely.
878 if (strpos('<strong class="highlight">', $var) !== false) {
881 while($i<strlen($input)){
882 if((($i + strlen($var)) <= strlen($input)) && (strcasecmp($var, substr($input, $i, strlen($var))) == 0)) {
883 $xtemp .= '<strong class="highlight">' . substr($input, $i , strlen($var)) . '</strong>';
887 $xtemp .= $input{$i};
897 /* @See: ./index.php */
898 function format_content($input, $html = 0, $glossary, $simple = false) {
899 global $_base_path, $_config;
902 $input = str_replace('<', '<', $input);
903 $input = str_replace('<?php', '<?php', $input); // for bug #2087
904 } elseif ($html==2) {
905 $output = '<iframe width="100%" frameborder="0" id="content_frame" marginheight="0" marginwidth="0" src="'.$input.'"></iframe>';
906 $output .= '<script type="text/javascript">
907 function resizeIframe() {
908 var height = document.documentElement.clientHeight;
910 // not sure how to get this dynamically
911 height -= 20; /* whatever you set your body bottom margin/padding to be */
913 document.getElementById(\'content_frame\').style.height = height +"px";
916 document.getElementById(\'content_frame\').onload = resizeIframe;
917 window.onresize = resizeIframe;
922 /* do the glossary search and replace: */
923 if (is_array($glossary)) {
924 foreach ($glossary as $k => $v) {
926 $v = str_replace("\n", '<br />', $v);
927 $v = str_replace("\r", '', $v);
929 /* escape special characters */
932 $k = str_replace('<', '<', $k);
933 $k = str_replace('/', '\/', $k);
936 $term = $original_term;
938 $term = '(\s*'.$term.'\s*)';
939 $term = str_replace(' ','((<br \/>)*\s*)', $term);
941 $def = htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
943 $input = preg_replace
944 ("/(\[\?\])$term(\[\/\?\])/i",
945 '<a href="'.$simple.'glossary.html#'.urlencode($original_term).'" target="body" class="at-term">\\2</a>',
948 $input = preg_replace
949 ("/(\[\?\])$term(\[\/\?\])/i",
950 '\\2<sup><a class="tooltip" href="'.$_base_path.'mods/_core/glossary/index.php?g_cid='.$_SESSION['s_cid'].htmlentities(SEP).'w='.urlencode($original_term).'#term" title="'.addslashes($original_term).': '.$def.'">?</a></sup>',$input);*/
952 $input = preg_replace
953 ("/(\[\?\])$term(\[\/\?\])/i",
954 '<a class="tooltip" href="'.$_base_path.'mods/_core/glossary/index.php?g_cid='.$_SESSION['s_cid'].htmlentities(SEP).'w='.urlencode($original_term).'#term" title="'.addslashes($original_term).': '.$def.'">\\2</a>',$input);
957 } else if (!$user_glossary) {
958 $input = str_replace(array('[?]','[/?]'), '', $input);
961 $input = str_replace('CONTENT_DIR', '', $input);
963 if (isset($_config['latex_server']) && $_config['latex_server']) {
964 $input = preg_replace('/\[tex\](.*?)\[\/tex\]/sie', "'<img src=\"'.\$_config['latex_server'].rawurlencode('$1').'\" align=\"middle\" alt=\"'.'$1'.'\" title=\"'.'$1'.'\">'", $input);
968 $x = apply_customized_format(format_final_output($input, false));
972 // the following has been taken out for this:
973 // http://atutor.ca/atutor/mantis/view.php?id=4593
974 // @date Oct 18, 2010
975 // $output = apply_customized_format(format_final_output($input));
978 $output = '<p>'.$output.'</p>';
982 function get_content_table($content)
984 preg_match_all("/<(h[\d]+)[^>]*>(.*)<\/(\s*)\\1(\s*)>/i", $content, $found_headers, PREG_SET_ORDER);
986 if (count($found_headers) == 0) return array("", $content);
991 for ($i = 0; $i < count($found_headers); $i++)
993 $div_id = "_header_" . $num_of_headers++;
997 $content_table = "<div id=\"toc\">\n<fieldset class=\"toc\"><legend>". _AT("table_of_contents")."</legend>\n";
1000 $content = str_replace($found_headers[$i][0], '<div id="'.$div_id.'">'.$found_headers[$i][0].'</div>', $content);
1001 $content_table .= '<a href="'.$_SERVER["REQUEST_URI"].'#'.$div_id.'" class="'.$found_headers[$i][1].'">'. $found_headers[$i][2]."</a>\n";
1003 if ($i == count($found_headers) - 1)
1005 $content_table .= "</fieldset></div><br />";
1008 return array($content_table, $content);
1012 function find_terms($find_text) {
1013 preg_match_all("/(\[\?\])(.[^\?]*)(\[\/\?\])/i", $find_text, $found_terms, PREG_PATTERN_ORDER);
1014 return $found_terms;
1017 /***********************************************************************
1018 @See /include/Classes/Message/Message.class.php
1023 * Take a code as input and grab its language specific message. Also cache the resulting
1024 * message. Return the message. Same as get_message but key value in cache is string
1026 * @param string $codes Message Code to translate - > 'term' field in DB
1027 * @return string The translated language specific message for code $code
1028 * @author Jacek Materna
1030 function getTranslatedCodeStr($codes) {
1032 /* this is where we want to get the msgs from the database inside a static variable */
1033 global $_cache_msgs_new;
1036 if (!isset($_msgs_new)) {
1037 if ( !($lang_et = cache(120, 'msgs_new', $_SESSION['lang'])) ) {
1038 global $db, $_base_path;
1040 $parent = Language::getParentCode($_SESSION['lang']);
1042 /* get $_msgs_new from the DB */
1043 $sql = 'SELECT * FROM '.TABLE_PREFIX.'language_text WHERE variable="_msgs" AND (language_code="'.$_SESSION['lang'].'" OR language_code="'.$parent.'")';
1044 $result = @mysql_query($sql, $db);
1046 while ($row = @mysql_fetch_assoc($result)) {
1047 // do not cache key as a digit (no contstant(), use string)
1048 $_cache_msgs_new[$row['term']] = str_replace('SITE_URL/', $_base_path, $row['text']);
1050 $_cache_msgs_new[$row['term']] .= ' <small><small>('.$row['term'].')</small></small>';
1054 cache_variable('_cache_msgs_new');
1055 endcache(true, false);
1057 $_msgs_new = $_cache_msgs_new;
1060 if (is_array($codes)) {
1061 /* this is an array with terms to replace */
1062 $code = array_shift($codes);
1064 $message = $_msgs_new[$code];
1067 /* replace the tokens with the terms */
1068 $message = vsprintf($message, $terms);
1071 $message = $_msgs_new[$codes];
1073 if ($message == '') {
1074 /* the language for this msg is missing: */
1076 $sql = 'SELECT * FROM '.TABLE_PREFIX.'language_text WHERE variable="_msgs"';
1077 $result = @mysql_query($sql, $db);
1079 while ($row = @mysql_fetch_assoc($result)) {
1080 if (($row['term']) === $codes) {
1081 $message = '['.$row['term'].']';
1091 function html_get_list($array) {
1093 foreach ($array as $value) {
1094 $list .= '<li>'.$value.'</li>';
1102 * print out list of page links
1104 function print_paginator($current_page, $num_rows, $request_args, $rows_per_page = 50, $window = 5) {
1105 $num_pages = ceil($num_rows / $rows_per_page);
1106 $request_args = '?'.$request_args;
1109 echo '<div class="paging">';
1112 $i=max($current_page-$window - max($window-$num_pages+$current_page,0), 1);
1115 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p=1" title="'._AT('page').' 1">1</a></li>';
1117 echo '<li>…</li>';
1121 for ($i; $i<= min($current_page+$window -min($current_page-$window,0),$num_pages); $i++) {
1122 if ($current_page == $i) {
1123 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$i.'" class="current" title="'._AT('page').' '. $current_page.'"><em>'.$current_page.'</em></a></li>';
1125 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$i.'" title="'._AT('page').' '. $i.'">'.$i.'</a></li>';
1128 if ($i <= $num_pages) {
1129 if ($i < $num_pages) {
1130 echo '<li>…</li>';
1132 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$num_pages.'" title="'._AT('page').' '. $num_pages.'">'.$num_pages.'</a></li>';
1140 * Replace or append source object with alternatives according to user's preferences
1142 * @param $cid: content id.
1143 * @param $content: the original content page ($content_row['text'], from content.php).
1144 * @param $info_only: boolean. Default value is "false". When it's "true", returns an array of 4 values:
1145 * $has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative
1146 * @param $only_on_secondary_type: Default value is "". Accept one of the values: 1(auditory), 2(sign_language), 3(text), 4(visual)
1147 * When the value is given, ignore the alternative preference settings and only replace/append
1148 * (replace or append is still from session preference) the objects with the alternatives with
1149 * the given alternative types.
1150 * @return string $content: the content page with the appropriated resources.
1151 * @see $db from include/vitals.inc.php
1152 * @author Cindy Qi Li
1154 function provide_alternatives($cid, $content, $info_only = false, $only_on_secondary_type = 0){
1157 $video_exts = array("mpg", "avi", "wmv", "mov", "swf", "mp4", "flv");
1159 $audio_exts = array("mp3", "wav", "ogg", "mid");
1163 $txt_exts = array("txt", "html", "htm");
1164 $image_exts = array("gif", "bmp", "png", "jpg", "jpeg", "png", "tif");
1165 $only_on_secondary_type = intval($only_on_secondary_type);
1167 // intialize the 4 returned values when $info_only is on
1170 $has_text_alternative = false;
1171 $has_audio_alternative = false;
1172 $has_visual_alternative = false;
1173 $has_sign_lang_alternative = false;
1176 if (!$info_only && !$only_on_secondary_type &&
1177 ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_TEXT']==0) &&
1178 ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_AUDIO']==0) &&
1179 ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_VISUAL']==0))
1181 //No user's preferences related to content format are declared
1185 return array($has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative);
1189 // get all relations between primary resources and their alternatives
1190 $sql = "SELECT DISTINCT c.content_path, pr.resource, prt.type_id primary_type,
1191 sr.secondary_resource, srt.type_id secondary_type
1192 FROM ".TABLE_PREFIX."primary_resources pr, ".
1193 TABLE_PREFIX."primary_resources_types prt,".
1194 TABLE_PREFIX."secondary_resources sr,".
1195 TABLE_PREFIX."secondary_resources_types srt,".
1196 TABLE_PREFIX."content c
1197 WHERE pr.content_id=".$cid."
1198 AND pr.primary_resource_id = prt.primary_resource_id
1199 AND pr.primary_resource_id = sr.primary_resource_id
1200 AND sr.language_code='".$_SESSION['lang']."'
1201 AND sr.secondary_resource_id = srt.secondary_resource_id
1202 AND pr.content_id = c.content_id";
1203 if ($only_on_secondary_type > 0) {
1204 $sql .= " AND srt.type_id=".$only_on_secondary_type;
1206 $sql .= " ORDER BY pr.primary_resource_id, prt.type_id";
1208 $result = mysql_query($sql, $db);
1210 if (mysql_num_rows($result) == 0) {
1214 return array($has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative);
1218 $primary_resource_names = array();
1219 while ($row = mysql_fetch_assoc($result)) {
1220 // if the primary resource is defined with multiple resource type,
1221 // the primary resource would be replaced/appended multiple times.
1222 // This is what we want at applying alternatives by default, but
1223 // not when only one secondary type is chosen to apply.
1224 // This fix is to remove the duplicates on the same primary resource.
1225 // A dilemma of this fix is, for example, if the primary resource type
1226 // is "text" and "visual", but
1227 // $_SESSION['prefs']['PREF_ALT_TO_TEXT_APPEND_OR_REPLACE'] == 'replace'
1228 // $_SESSION['prefs']['PREF_ALT_TO_VISUAL_APPEND_OR_REPLACE'] == 'append'
1229 // so, should replace happen or append happen? With this fix, whichever
1230 // the first in the sql return gets preserved in the array and processed.
1231 // The further improvement is requried to keep rows based on the selected
1232 // secondary type (http://www.atutor.ca/atutor/mantis/view.php?id=4598).
1233 if ($only_on_secondary_type > 0) {
1234 if (in_array($row['resource'], $primary_resource_names)) {
1237 $primary_resource_names[] = $row['resource'];
1240 $alternative_rows[] = $row;
1242 $youtube_playURL = convert_youtube_watchURL_to_playURL($row['resource']);
1244 if ($row['resource'] <> $youtube_playURL) {
1245 $row['resource'] = $youtube_playURL;
1246 $alternative_rows[] = $row;
1250 foreach ($alternative_rows as $row)
1252 if ($info_only || $only_on_secondary_type ||
1253 ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_TEXT']==1 && $row['primary_type']==3 &&
1254 ($_SESSION['prefs']['PREF_ALT_TO_TEXT']=="audio" && $row['secondary_type']==1 ||
1255 $_SESSION['prefs']['PREF_ALT_TO_TEXT']=="visual" && $row['secondary_type']==4 ||
1256 $_SESSION['prefs']['PREF_ALT_TO_TEXT']=="sign_lang" && $row['secondary_type']==2)) ||
1258 ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_AUDIO']==1 && $row['primary_type']==1 &&
1259 ($_SESSION['prefs']['PREF_ALT_TO_AUDIO']=="visual" && $row['secondary_type']==4 ||
1260 $_SESSION['prefs']['PREF_ALT_TO_AUDIO']=="text" && $row['secondary_type']==3 ||
1261 $_SESSION['prefs']['PREF_ALT_TO_AUDIO']=="sign_lang" && $row['secondary_type']==2)) ||
1263 ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_VISUAL']==1 && $row['primary_type']==4 &&
1264 ($_SESSION['prefs']['PREF_ALT_TO_VISUAL']=="audio" && $row['secondary_type']==1 ||
1265 $_SESSION['prefs']['PREF_ALT_TO_VISUAL']=="text" && $row['secondary_type']==3 ||
1266 $_SESSION['prefs']['PREF_ALT_TO_VISUAL']=="sign_lang" && $row['secondary_type']==2))
1269 $ext = substr($row['secondary_resource'], strrpos($row['secondary_resource'], '.')+1);
1271 // alternative is video or a youtube url
1272 if (in_array($ext, $video_exts) || in_array($ext, $audio_exts) ||
1273 preg_match("/http:\/\/.*youtube.com\/watch.*/", $row['secondary_resource'])) {
1274 if (in_array($ext, $audio_exts)) {
1275 // display audio medias in a smaller width/height (425 * 27)
1276 // A hack for now to handle audio media player size
1277 $target = '[media|'.$audio_width.'|'.$audio_height.']'.$row['secondary_resource'].'[/media]';
1279 // use default media size for video medias
1280 $target = '[media]'.$row['secondary_resource'].'[/media]';
1283 // a text primary to be replaced by a visual alternative
1284 else if (in_array($ext, $txt_exts))
1286 if ($row['content_path'] <> '')
1287 $file_location = $row['content_path'].'/'.$row['secondary_resource'];
1289 $file_location = $row['secondary_resource'];
1291 $file = AT_CONTENT_DIR.$_SESSION['course_id'] . '/'.$file_location;
1292 $target = '<br />'.file_get_contents($file);
1294 // check whether html file
1295 if (preg_match('/.*\<html.*\<\/html\>.*/s', $target))
1296 { // is a html file, use iframe to display
1297 // get real path to the text file
1298 if (defined('AT_FORCE_GET_FILE') && AT_FORCE_GET_FILE) {
1299 $course_base_href = 'get.php/';
1301 $course_base_href = 'content/' . $_SESSION['course_id'] . '/';
1304 $file = AT_BASE_HREF . $course_base_href.$file_location;
1306 $target = '<iframe width="100%" frameborder="0" class="autoHeight" scrolling="auto" src="'.$file.'"></iframe>';
1309 { // is a text file, insert/replace into content
1310 $target = nl2br($target);
1313 else if (in_array($ext, $image_exts))
1314 $target = '<img border="0" alt="'._AT('alternate_text').'" src="'.$row['secondary_resource'].'"/>';
1317 $target = '<p><a href="'.$row['secondary_resource'].'">'.$row['secondary_resource'].'</a></p>';
1319 // replace or append the target alternative to the source
1320 if (($row['primary_type']==3 && $_SESSION['prefs']['PREF_ALT_TO_TEXT_APPEND_OR_REPLACE'] == 'replace') ||
1321 ($row['primary_type']==1 && $_SESSION['prefs']['PREF_ALT_TO_AUDIO_APPEND_OR_REPLACE']=='replace') ||
1322 ($row['primary_type']==4 && $_SESSION['prefs']['PREF_ALT_TO_VISUAL_APPEND_OR_REPLACE']=='replace'))
1323 $pattern_replace_to = '${1}'."\n".$target."\n".'${3}';
1325 $pattern_replace_to = '${1}${2}'."<br /><br />\n".$target."\n".'${3}';
1327 // *** Alternative replace/append starts from here ***
1328 $processed = false; // one primary resource is only processed once
1330 // append/replace target alternative to [media]source[/media]
1331 if (!$processed && preg_match("/".preg_quote("[media").".*".preg_quote("]".$row['resource']."[/media]", "/")."/sU", $content))
1335 $content = preg_replace("/(.*)(".preg_quote("[media").".*".preg_quote("]".$row['resource']."[/media]", "/").")(.*)/sU",
1336 $pattern_replace_to, $content);
1338 if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1339 if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1340 if ($row['secondary_type'] == 3) $has_text_alternative = true;
1341 if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1345 // append/replace target alternative to <img ... src="source" ...></a>
1346 if (!$processed && preg_match("/\<img.*src=\"".preg_quote($row['resource'], "/")."\".*\/\>/sU", $content))
1350 $content = preg_replace("/(.*)(\<img.*src=\"".preg_quote($row['resource'], "/")."\".*\/\>)(.*)/sU",
1351 $pattern_replace_to, $content);
1353 if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1354 if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1355 if ($row['secondary_type'] == 3) $has_text_alternative = true;
1356 if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1360 // append/replace target alternative to <object ... source ...></object>
1361 if (!$processed && preg_match("/\<object.*".preg_quote($row['resource'], "/").".*\<\/object\>/sU", $content))
1365 $content = preg_replace("/(.*)(\<object.*".preg_quote($row['resource'], "/").".*\<\/object\>)(.*)/sU",
1366 $pattern_replace_to, $content);
1368 if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1369 if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1370 if ($row['secondary_type'] == 3) $has_text_alternative = true;
1371 if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1375 // append/replace target alternative to <a>...source...</a> or <a ...source...>...</a>
1376 // skip this "if" when the source object has been processed in aboved <img> tag
1377 if (!$processed && preg_match("/\<a.*".preg_quote($row['resource'], "/").".*\<\/a\>/sU", $content))
1381 $content = preg_replace("/(.*)(\<a.*".preg_quote($row['resource'], "/").".*\<\/a\>)(.*)/sU",
1382 $pattern_replace_to, $content);
1384 if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1385 if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1386 if ($row['secondary_type'] == 3) $has_text_alternative = true;
1387 if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1391 // append/replace target alternative to <embed ... source ...>
1392 if (!$processed && preg_match("/\<embed.*".preg_quote($row['resource'], "/").".*\>/sU", $content))
1396 $content = preg_replace("/(.*)(\<embed.*".preg_quote($row['resource'], "/").".*\>)(.*)/sU",
1397 $pattern_replace_to, $content);
1399 if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1400 if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1401 if ($row['secondary_type'] == 3) $has_text_alternative = true;
1402 if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1411 return array($has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative);
1417 * converts a unix timestamp into another UNIX timestamp with timezone offset added up.
1418 * Adds the user's timezone offset, then converts back to a MYSQL timestamp
1419 * Available both as a system config option, and a user preference, if both are set
1420 * they are added together
1421 * @param date MYSQL timestamp.
1422 * @return date MYSQL timestamp plus user's and/or system's timezone offset.
1423 * @author Greg Gay .
1425 function apply_timezone($timestamp){
1428 if($_config['time_zone']){
1429 $timestamp = ($timestamp + ($_config['time_zone']*3600));
1433 if(isset($_SESSION['prefs']['PREF_TIMEZONE'])){
1434 $timestamp = ($timestamp + ($_SESSION['prefs']['PREF_TIMEZONE']*3600));