See Release Notes
Long Term Support Release
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Filter converting emoticon texts into images 20 * 21 * This filter uses the emoticon settings in Site admin > Appearance > HTML settings 22 * and replaces emoticon texts with images. 23 * 24 * @package filter 25 * @subpackage emoticon 26 * @see emoticon_manager 27 * @copyright 2010 David Mudrak <david@moodle.com> 28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 */ 30 31 defined('MOODLE_INTERNAL') || die(); 32 33 class filter_emoticon extends moodle_text_filter { 34 35 /** 36 * Internal cache used for replacing. Multidimensional array; 37 * - dimension 1: language, 38 * - dimension 2: theme. 39 * @var array 40 */ 41 protected static $emoticontexts = array(); 42 43 /** 44 * Internal cache used for replacing. Multidimensional array; 45 * - dimension 1: language, 46 * - dimension 2: theme. 47 * @var array 48 */ 49 protected static $emoticonimgs = array(); 50 51 /** 52 * Apply the filter to the text 53 * 54 * @see filter_manager::apply_filter_chain() 55 * @param string $text to be processed by the text 56 * @param array $options filter options 57 * @return string text after processing 58 */ 59 public function filter($text, array $options = array()) { 60 61 if (!isset($options['originalformat'])) { 62 // if the format is not specified, we are probably called by {@see format_string()} 63 // in that case, it would be dangerous to replace text with the image because it could 64 // be stripped. therefore, we do nothing 65 return $text; 66 } 67 if (in_array($options['originalformat'], explode(',', get_config('filter_emoticon', 'formats')))) { 68 return $this->replace_emoticons($text); 69 } 70 return $text; 71 } 72 73 //////////////////////////////////////////////////////////////////////////// 74 // internal implementation starts here 75 //////////////////////////////////////////////////////////////////////////// 76 77 /** 78 * Replace emoticons found in the text with their images 79 * 80 * @param string $text to modify 81 * @return string the modified result 82 */ 83 protected function replace_emoticons($text) { 84 global $CFG, $OUTPUT, $PAGE; 85 86 $lang = current_language(); 87 $theme = $PAGE->theme->name; 88 89 if (!isset(self::$emoticontexts[$lang][$theme]) or !isset(self::$emoticonimgs[$lang][$theme])) { 90 // prepare internal caches 91 $manager = get_emoticon_manager(); 92 $emoticons = $manager->get_emoticons(); 93 self::$emoticontexts[$lang][$theme] = array(); 94 self::$emoticonimgs[$lang][$theme] = array(); 95 foreach ($emoticons as $emoticon) { 96 self::$emoticontexts[$lang][$theme][] = $emoticon->text; 97 self::$emoticonimgs[$lang][$theme][] = $OUTPUT->render($manager->prepare_renderable_emoticon($emoticon)); 98 } 99 unset($emoticons); 100 } 101 102 if (empty(self::$emoticontexts[$lang][$theme])) { // No emoticons defined, nothing to process here. 103 return $text; 104 } 105 106 // Detect all zones that we should not handle (including the nested tags). 107 $processing = preg_split('/(<\/?(?:span|script|pre)[^>]*>)/is', $text, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 108 109 // Initialize the results. 110 $resulthtml = ""; 111 $exclude = 0; 112 113 // Define the patterns that mark the start of the forbidden zones. 114 $excludepattern = array('/^<script/is', '/^<span[^>]+class="nolink[^"]*"/is', '/^<pre/is'); 115 116 // Loop through the fragments. 117 foreach ($processing as $fragment) { 118 // If we are not ignoring, we MUST test if we should. 119 if ($exclude == 0) { 120 foreach ($excludepattern as $exp) { 121 if (preg_match($exp, $fragment)) { 122 $exclude = $exclude + 1; 123 break; 124 } 125 } 126 } 127 if ($exclude > 0) { 128 // If we are ignoring the fragment, then we must check if we may have reached the end of the zone. 129 if (strpos($fragment, '</span') !== false || strpos($fragment, '</script') !== false 130 || strpos($fragment, '</pre') !== false) { 131 $exclude -= 1; 132 // This is needed because of a double increment at the first element. 133 if ($exclude == 1) { 134 $exclude -= 1; 135 } 136 } else if (strpos($fragment, '<span') !== false || strpos($fragment, '<script') !== false 137 || strpos($fragment, '<pre') !== false) { 138 // If we find a nested tag we increase the exclusion level. 139 $exclude = $exclude + 1; 140 } 141 } else if (strpos($fragment, '<span') === false || 142 strpos($fragment, '</span') === false) { 143 // This is the meat of the code - this is run every time. 144 // This code only runs for fragments that are not ignored (including the tags themselves). 145 $fragment = str_replace(self::$emoticontexts[$lang][$theme], self::$emoticonimgs[$lang][$theme], $fragment); 146 } 147 $resulthtml .= $fragment; 148 } 149 150 return $resulthtml; 151 } 152 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body