diff --git a/filter/emoticon/filter.php b/filter/emoticon/filter.php
index d579bf65b9f..5f5b3ff5dc0 100644
--- a/filter/emoticon/filter.php
+++ b/filter/emoticon/filter.php
@@ -32,6 +32,22 @@ defined('MOODLE_INTERNAL') || die();
class filter_emoticon extends moodle_text_filter {
+ /**
+ * Internal cache used for replacing. Multidimensional array;
+ * - dimension 1: language,
+ * - dimension 2: theme.
+ * @var array
+ */
+ protected static $emoticontexts = array();
+
+ /**
+ * Internal cache used for replacing. Multidimensional array;
+ * - dimension 1: language,
+ * - dimension 2: theme.
+ * @var array
+ */
+ protected static $emoticonimgs = array();
+
/**
* Apply the filter to the text
*
@@ -49,7 +65,7 @@ class filter_emoticon extends moodle_text_filter {
return $text;
}
if (in_array($options['originalformat'], explode(',', get_config('filter_emoticon', 'formats')))) {
- $this->replace_emoticons($text);
+ return $this->replace_emoticons($text);
}
return $text;
}
@@ -62,51 +78,73 @@ class filter_emoticon extends moodle_text_filter {
* Replace emoticons found in the text with their images
*
* @param string $text to modify
- * @return void
+ * @return string the modified result
*/
- protected function replace_emoticons(&$text) {
+ protected function replace_emoticons($text) {
global $CFG, $OUTPUT, $PAGE;
- static $emoticontexts = array(); // internal cache used for replacing
- static $emoticonimgs = array(); // internal cache used for replacing
$lang = current_language();
$theme = $PAGE->theme->name;
- if (!isset($emoticontexts[$lang][$theme]) or !isset($emoticonimgs[$lang][$theme])) {
+ if (!isset(self::$emoticontexts[$lang][$theme]) or !isset(self::$emoticonimgs[$lang][$theme])) {
// prepare internal caches
$manager = get_emoticon_manager();
$emoticons = $manager->get_emoticons();
- $emoticontexts[$lang][$theme] = array();
- $emoticonimgs[$lang][$theme] = array();
+ self::$emoticontexts[$lang][$theme] = array();
+ self::$emoticonimgs[$lang][$theme] = array();
foreach ($emoticons as $emoticon) {
- $emoticontexts[$lang][$theme][] = $emoticon->text;
- $emoticonimgs[$lang][$theme][] = $OUTPUT->render($manager->prepare_renderable_emoticon($emoticon));
+ self::$emoticontexts[$lang][$theme][] = $emoticon->text;
+ self::$emoticonimgs[$lang][$theme][] = $OUTPUT->render($manager->prepare_renderable_emoticon($emoticon));
}
unset($emoticons);
}
- if (empty($emoticontexts[$lang][$theme])) { // No emoticons defined, nothing to process here
- return;
+ if (empty(self::$emoticontexts[$lang][$theme])) { // No emoticons defined, nothing to process here.
+ return $text;
}
- // detect all the zones to text
- if ($excludes) {
- $text = str_replace(array_keys($excludes), $excludes, $text);
- }
+ return $resulthtml;
}
}
diff --git a/filter/emoticon/tests/filter_test.php b/filter/emoticon/tests/filter_test.php
index da3576a5419..10ee76e8303 100644
--- a/filter/emoticon/tests/filter_test.php
+++ b/filter/emoticon/tests/filter_test.php
@@ -34,29 +34,124 @@ require_once($CFG->dirroot . '/filter/emoticon/filter.php'); // Include the code
class filter_emoticon_testcase extends advanced_testcase {
/**
- * Verify configured target formats are observed. Just that.
+ * Tests the filter doesn't affect nolink classes.
+ *
+ * @dataProvider filter_emoticon_provider
*/
- public function test_filter_emoticon_formats() {
-
- $this->resetAfterTest(true); // We are modifying the config.
+ public function test_filter_emoticon($input, $format, $expected) {
+ $this->resetAfterTest();
$filter = new testable_filter_emoticon();
+ $this->assertEquals($expected, $filter->filter($input, [
+ 'originalformat' => $format,
+ ]));
+ }
- // Verify texts not matching target formats aren't filtered.
+ /**
+ * The data provider for filter emoticon tests.
+ *
+ * @return array
+ */
+ public function filter_emoticon_provider() {
+ $grr = '(grr)';
+ return [
+ 'FORMAT_MOODLE is not filtered' => [
+ 'input' => $grr,
+ 'format' => FORMAT_MOODLE,
+ 'expected' => $grr,
+ ],
+ 'FORMAT_MARKDOWN is not filtered' => [
+ 'input' => $grr,
+ 'format' => FORMAT_MARKDOWN,
+ 'expected' => $grr,
+ ],
+ 'FORMAT_PLAIN is not filtered' => [
+ 'input' => $grr,
+ 'format' => FORMAT_PLAIN,
+ 'expected' => $grr,
+ ],
+ 'FORMAT_HTML is filtered' => [
+ 'input' => $grr,
+ 'format' => FORMAT_HTML,
+ 'expected' => $this->get_converted_content_for_emoticon($grr),
+ ],
+ 'Script tag should not be processed' => [
+ 'input' => "",
+ 'format' => FORMAT_HTML,
+ 'expected' => "",
+ ],
+ 'Basic nolink should not be processed' => [
+ 'input' => '(n)',
+ 'format' => FORMAT_HTML,
+ 'expected' => '(n)',
+ ],
+ 'Nested nolink should not be processed' => [
+ 'input' => '(n)(n)',
+ 'format' => FORMAT_HTML,
+ 'expected' => '(n)(n)',
+ ],
+ 'Nested nolink should not be processed but following emoticon' => [
+ 'input' => '(n)(n)(n)',
+ 'format' => FORMAT_HTML,
+ 'expected' => '(n)(n)' . $this->get_converted_content_for_emoticon('(n)'),
+ ],
+ ];
+ }
+
+ /**
+ * Translate the text for a single emoticon into the rendered value.
+ *
+ * @param string $text The text to translate.
+ * @return string
+ */
+ public function get_converted_content_for_emoticon($text) {
+ global $OUTPUT;
+ $manager = get_emoticon_manager();
+ $emoticons = $manager->get_emoticons();
+ foreach ($emoticons as $emoticon) {
+ if ($emoticon->text == $text) {
+ return $OUTPUT->render($manager->prepare_renderable_emoticon($emoticon));
+ }
+ }
+
+ return $text;
+ }
+
+ /**
+ * Tests the filter doesn't break anything if activated but invalid format passed.
+ *
+ */
+ public function test_filter_invalidformat() {
+ global $PAGE;
+ $this->resetAfterTest();
+
+ $filter = new testable_filter_emoticon();
+ $input = '(grr)';
$expected = '(grr)';
- $options = array('originalformat' => FORMAT_MOODLE); // Only FORMAT_HTML is filtered, see {@link testable_filter_emoticon}.
- $this->assertEquals($expected, $filter->filter('(grr)', $options));
- $options = array('originalformat' => FORMAT_MARKDOWN); // Only FORMAT_HTML is filtered, see {@link testable_filter_emoticon}.
- $this->assertEquals($expected, $filter->filter('(grr)', $options));
+ $this->assertEquals($expected, $filter->filter($input, [
+ 'originalformat' => 'ILLEGALFORMAT',
+ ]));
+ }
- $options = array('originalformat' => FORMAT_PLAIN); // Only FORMAT_HTML is filtered, see {@link testable_filter_emoticon}.
- $this->assertEquals($expected, $filter->filter('(grr)', $options));
+ /**
+ * Tests the filter doesn't break anything if activated but no emoticons available.
+ *
+ */
+ public function test_filter_emptyemoticons() {
+ global $CFG;
+ $this->resetAfterTest();
+ // Empty the emoticons array.
+ $CFG->emoticons = null;
- // And texts matching target formats are filtered.
- $expected = '
';
- $options = array('originalformat' => FORMAT_HTML); // Only FORMAT_HTML is filtered, see {@link testable_filter_emoticon}.
- $this->assertEquals($expected, $filter->filter('(grr)', $options));
+ $filter = new filter_emoticon(context_system::instance(), array('originalformat' => FORMAT_HTML));
+
+ $input = '(grr)';
+ $expected = '(grr)';
+
+ $this->assertEquals($expected, $filter->filter($input, [
+ 'originalformat' => FORMAT_HTML,
+ ]));
}
}
@@ -65,6 +160,9 @@ class filter_emoticon_testcase extends advanced_testcase {
*/
class testable_filter_emoticon extends filter_emoticon {
public function __construct() {
+ // Reset static emoticon caches.
+ parent::$emoticontexts = array();
+ parent::$emoticonimgs = array();
// Use this context for filtering.
$this->context = context_system::instance();
// Define FORMAT_HTML as only one filtering in DB.