See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Moodle editor field. 19 * 20 * @package core_form 21 * @category test 22 * @copyright 2012 David MonllaĆ³ 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. 27 28 use Behat\Mink\Element\NodeElement as NodeElement; 29 30 require_once (__DIR__ . '/behat_form_textarea.php'); 31 32 /** 33 * Moodle editor field. 34 * 35 * @package core_form 36 * @category test 37 * @copyright 2012 David MonllaĆ³ 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class behat_form_editor extends behat_form_textarea { 41 42 /** 43 * Sets the value to a field. 44 * 45 * @param string $value 46 */ 47 public function set_value($value): void { 48 $editorid = $this->field->getAttribute('id'); 49 if ($this->running_javascript()) { 50 $value = addslashes($value); 51 // This will be transported in JSON, which doesn't allow newlines in strings, so we must escape them. 52 $value = str_replace("\n", "\\n", $value); 53 behat_base::execute_in_matching_contexts('editor', 'set_editor_value', [ 54 $editorid, 55 $value, 56 ]); 57 58 } else { 59 parent::set_value($value); 60 } 61 } 62 63 /** 64 * Returns the current value of the select element. 65 * 66 * @return string 67 */ 68 public function get_value(): string { 69 if ($this->running_javascript()) { 70 // Give any listening editors a chance to persist the value to the textarea. 71 // Some editors only do this on form submission or similar events. 72 behat_base::execute_in_matching_contexts('editor', 'store_current_value', [ 73 $this->field->getAttribute('id'), 74 ]); 75 } 76 77 return parent::get_value(); 78 } 79 80 /** 81 * Select all the text in the form field. 82 * 83 */ 84 public function select_text() { 85 // NodeElement.keyPress simply doesn't work. 86 if (!$this->running_javascript()) { 87 throw new coding_exception('Selecting text requires javascript.'); 88 } 89 90 $editorid = $this->field->getAttribute('id'); 91 $js = ' (function() { 92 var e = document.getElementById("'.$editorid.'editable"), 93 r = rangy.createRange(), 94 s = rangy.getSelection(); 95 96 while ((e.firstChild !== null) && (e.firstChild.nodeType != document.TEXT_NODE)) { 97 e = e.firstChild; 98 } 99 e.focus(); 100 r.selectNodeContents(e); 101 s.setSingleRange(r); 102 }()); '; 103 behat_base::execute_script_in_session($this->session, $js); 104 } 105 106 /** 107 * Matches the provided value against the current field value. 108 * 109 * @param string $expectedvalue 110 * @return bool The provided value matches the field value? 111 */ 112 public function matches($expectedvalue) { 113 // Fetch the actual value to save fetching it multiple times. 114 $actualvalue = $this->get_value(); 115 116 if ($this->text_matches($expectedvalue, $actualvalue)) { 117 // The text is an exact match already. 118 return true; 119 } 120 121 if ($this->text_matches("<p>{$expectedvalue}</p>", $actualvalue)) { 122 // A text editor may silently wrap the content in p tags. 123 return true; 124 } 125 126 // Standardise both the expected value and the actual field value. 127 // We are likely dealing with HTML content, given this is an editor. 128 $expectedvalue = $this->standardise_html($expectedvalue); 129 $actualvalue = $this->standardise_html($actualvalue); 130 131 // Note: We don't need to worry about the floats here that we care about in text_matches. 132 // That condition isn't relevant to the content of an editor. 133 if ($expectedvalue === $actualvalue) { 134 return true; 135 } 136 137 return false; 138 } 139 140 /** 141 * Standardises the HTML content for comparison. 142 * 143 * @param string $html The HTML content to standardise 144 * @return string The standardised HTML content 145 */ 146 protected function standardise_html(string $html): string { 147 $document = new DOMDocument(); 148 $errorstate = libxml_use_internal_errors(true); 149 150 // Format the whitespace nicely. 151 $document->preserveWhiteSpace = false; 152 $document->formatOutput = true; 153 154 // Wrap the content in a DIV element so that it is not parsed weirdly. 155 // Note: We must remove newlines too because DOMDocument does not do so, despite preserveWhiteSpace being false. 156 // Unfortunately this is slightly limited in that it will also remove newlines from <pre> content and similar. 157 $document->loadHTML(str_replace("\n", "", "<div>{$html}</div>"), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 158 $document->normalizeDocument(); 159 libxml_clear_errors(); 160 libxml_use_internal_errors($errorstate); 161 162 // Save the content of the 'div' element, removing the <div> and </div> tags at the start and end. 163 return trim(substr( 164 $document->saveHTML($document->getElementsByTagName('div')->item(0)), 165 5, 166 -6 167 )); 168 } 169 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body