This commit is contained in:
Andrew Nicols 2024-06-18 22:33:14 +08:00
commit 40938bd83b
No known key found for this signature in database
GPG key ID: 6D1E3157C8CFBF14
9 changed files with 41 additions and 50 deletions

View file

@ -1,3 +1,3 @@
define("tiny_noautolink/commands",["exports","editor_tiny/utils","core/str","tiny_noautolink/common","tiny_noautolink/noautolink"],(function(_exports,_utils,_str,_common,_noautolink){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.getSetup=void 0;_exports.getSetup=async()=>{const[buttonText,errorInvalidURL,infoEmptySelection,infoAddSuccess,infoRemoveSuccess,buttonImage]=await Promise.all([(0,_str.get_string)("buttontitle",_common.component),(0,_str.get_string)("errorinvalidurl",_common.component),(0,_str.get_string)("infoemptyselection",_common.component),(0,_str.get_string)("infoaddsuccess",_common.component),(0,_str.get_string)("inforemovesuccess",_common.component),(0,_utils.getButtonImage)("icon",_common.component)]);return editor=>{const messages={errorInvalidURL:errorInvalidURL,infoEmptySelection:infoEmptySelection,infoAddSuccess:infoAddSuccess,infoRemoveSuccess:infoRemoveSuccess};editor.ui.registry.addIcon(_common.buttonIcon,buttonImage.html),editor.ui.registry.addToggleButton(_common.buttonName,{icon:_common.buttonIcon,tooltip:buttonText,onAction:()=>{(0,_noautolink.handleAction)(editor,messages)},onSetup:(0,_noautolink.toggleActiveState)(editor)}),editor.ui.registry.addMenuItem(_common.buttonName,{icon:_common.buttonIcon,text:buttonText,onAction:()=>{(0,_noautolink.handleAction)(editor,messages)}})}}}));
define("tiny_noautolink/commands",["exports","editor_tiny/utils","core/str","tiny_noautolink/common","tiny_noautolink/noautolink"],(function(_exports,_utils,_str,_common,_noautolink){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.getSetup=void 0;_exports.getSetup=async()=>{const[buttonText,infoEmptySelection,infoAddSuccess,infoRemoveSuccess,buttonImage]=await Promise.all([(0,_str.get_string)("buttontitle",_common.component),(0,_str.get_string)("infoemptyselection",_common.component),(0,_str.get_string)("infoaddsuccess",_common.component),(0,_str.get_string)("inforemovesuccess",_common.component),(0,_utils.getButtonImage)("icon",_common.component)]);return editor=>{const messages={infoEmptySelection:infoEmptySelection,infoAddSuccess:infoAddSuccess,infoRemoveSuccess:infoRemoveSuccess};editor.ui.registry.addIcon(_common.buttonIcon,buttonImage.html),editor.ui.registry.addToggleButton(_common.buttonName,{icon:_common.buttonIcon,tooltip:buttonText,onAction:()=>{(0,_noautolink.handleAction)(editor,messages)},onSetup:(0,_noautolink.toggleActiveState)(editor)}),editor.ui.registry.addMenuItem(_common.buttonName,{icon:_common.buttonIcon,text:buttonText,onAction:()=>{(0,_noautolink.handleAction)(editor,messages)}})}}}));
//# sourceMappingURL=commands.min.js.map

View file

@ -1 +1 @@
{"version":3,"file":"commands.min.js","sources":["../src/commands.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport {getButtonImage} from 'editor_tiny/utils';\nimport {get_string as getString} from 'core/str';\nimport {component, buttonName, buttonIcon} from 'tiny_noautolink/common';\nimport {handleAction, toggleActiveState} from 'tiny_noautolink/noautolink';\n\n/**\n * Tiny noautolink commands.\n *\n * @module tiny_noautolink/commands\n * @copyright 2023 Meirza <meirza.arson@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const getSetup = async() => {\n const [\n buttonText,\n errorInvalidURL,\n infoEmptySelection,\n infoAddSuccess,\n infoRemoveSuccess,\n buttonImage,\n ] = await Promise.all([\n getString('buttontitle', component),\n getString('errorinvalidurl', component),\n getString('infoemptyselection', component),\n getString('infoaddsuccess', component),\n getString('inforemovesuccess', component),\n getButtonImage('icon', component),\n ]);\n\n return (editor) => {\n\n const messages = {\n errorInvalidURL: errorInvalidURL,\n infoEmptySelection: infoEmptySelection,\n infoAddSuccess: infoAddSuccess,\n infoRemoveSuccess: infoRemoveSuccess\n };\n\n // Register the noautolink Icon.\n editor.ui.registry.addIcon(buttonIcon, buttonImage.html);\n\n // Register the noautolink button.\n editor.ui.registry.addToggleButton(buttonName, {\n icon: buttonIcon,\n tooltip: buttonText,\n onAction: () => {\n handleAction(editor, messages);\n },\n onSetup: toggleActiveState(editor),\n });\n\n // Register the noautolink item.\n editor.ui.registry.addMenuItem(buttonName, {\n icon: buttonIcon,\n text: buttonText,\n onAction: () => {\n handleAction(editor, messages);\n },\n });\n };\n};\n"],"names":["async","buttonText","errorInvalidURL","infoEmptySelection","infoAddSuccess","infoRemoveSuccess","buttonImage","Promise","all","component","editor","messages","ui","registry","addIcon","buttonIcon","html","addToggleButton","buttonName","icon","tooltip","onAction","onSetup","addMenuItem","text"],"mappings":"0RA4BwBA,gBAEhBC,WACAC,gBACAC,mBACAC,eACAC,kBACAC,mBACMC,QAAQC,IAAI,EAClB,mBAAU,cAAeC,oBACzB,mBAAU,kBAAmBA,oBAC7B,mBAAU,qBAAsBA,oBAChC,mBAAU,iBAAkBA,oBAC5B,mBAAU,oBAAqBA,oBAC/B,yBAAe,OAAQA,4BAGnBC,eAEEC,SAAW,CACbT,gBAAiBA,gBACjBC,mBAAoBA,mBACpBC,eAAgBA,eAChBC,kBAAmBA,mBAIvBK,OAAOE,GAAGC,SAASC,QAAQC,mBAAYT,YAAYU,MAGnDN,OAAOE,GAAGC,SAASI,gBAAgBC,mBAAY,CAC3CC,KAAMJ,mBACNK,QAASnB,WACToB,SAAU,kCACOX,OAAQC,WAEzBW,SAAS,iCAAkBZ,UAI/BA,OAAOE,GAAGC,SAASU,YAAYL,mBAAY,CACvCC,KAAMJ,mBACNS,KAAMvB,WACNoB,SAAU,kCACOX,OAAQC"}
{"version":3,"file":"commands.min.js","sources":["../src/commands.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport {getButtonImage} from 'editor_tiny/utils';\nimport {get_string as getString} from 'core/str';\nimport {component, buttonName, buttonIcon} from 'tiny_noautolink/common';\nimport {handleAction, toggleActiveState} from 'tiny_noautolink/noautolink';\n\n/**\n * Tiny noautolink commands.\n *\n * @module tiny_noautolink/commands\n * @copyright 2023 Meirza <meirza.arson@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const getSetup = async() => {\n const [\n buttonText,\n infoEmptySelection,\n infoAddSuccess,\n infoRemoveSuccess,\n buttonImage,\n ] = await Promise.all([\n getString('buttontitle', component),\n getString('infoemptyselection', component),\n getString('infoaddsuccess', component),\n getString('inforemovesuccess', component),\n getButtonImage('icon', component),\n ]);\n\n return (editor) => {\n\n const messages = {\n infoEmptySelection: infoEmptySelection,\n infoAddSuccess: infoAddSuccess,\n infoRemoveSuccess: infoRemoveSuccess\n };\n\n // Register the noautolink Icon.\n editor.ui.registry.addIcon(buttonIcon, buttonImage.html);\n\n // Register the noautolink button.\n editor.ui.registry.addToggleButton(buttonName, {\n icon: buttonIcon,\n tooltip: buttonText,\n onAction: () => {\n handleAction(editor, messages);\n },\n onSetup: toggleActiveState(editor),\n });\n\n // Register the noautolink item.\n editor.ui.registry.addMenuItem(buttonName, {\n icon: buttonIcon,\n text: buttonText,\n onAction: () => {\n handleAction(editor, messages);\n },\n });\n };\n};\n"],"names":["async","buttonText","infoEmptySelection","infoAddSuccess","infoRemoveSuccess","buttonImage","Promise","all","component","editor","messages","ui","registry","addIcon","buttonIcon","html","addToggleButton","buttonName","icon","tooltip","onAction","onSetup","addMenuItem","text"],"mappings":"0RA4BwBA,gBAEhBC,WACAC,mBACAC,eACAC,kBACAC,mBACMC,QAAQC,IAAI,EAClB,mBAAU,cAAeC,oBACzB,mBAAU,qBAAsBA,oBAChC,mBAAU,iBAAkBA,oBAC5B,mBAAU,oBAAqBA,oBAC/B,yBAAe,OAAQA,4BAGnBC,eAEEC,SAAW,CACbR,mBAAoBA,mBACpBC,eAAgBA,eAChBC,kBAAmBA,mBAIvBK,OAAOE,GAAGC,SAASC,QAAQC,mBAAYT,YAAYU,MAGnDN,OAAOE,GAAGC,SAASI,gBAAgBC,mBAAY,CAC3CC,KAAMJ,mBACNK,QAASlB,WACTmB,SAAU,kCACOX,OAAQC,WAEzBW,SAAS,iCAAkBZ,UAI/BA,OAAOE,GAAGC,SAASU,YAAYL,mBAAY,CACvCC,KAAMJ,mBACNS,KAAMtB,WACNmB,SAAU,kCACOX,OAAQC"}

View file

@ -5,6 +5,6 @@ define("tiny_noautolink/noautolink",["exports","core/pending"],(function(_export
* @module tiny_noautolink/noautolink
* @copyright 2023 Meirza <meirza.arson@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.toggleActiveState=_exports.handleAction=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};_exports.handleAction=(editor,messages)=>{const toggleState=isInAnchor(editor,editor.selection.getNode()),urlString=getSelectedContent(editor);toggleState||""===urlString?toggleState?unsetNoAutoLink(editor,messages,urlString):editor.notificationManager.open({text:messages.infoEmptySelection,type:"info",timeout:2e3}):setNoAutoLink(editor,messages,urlString)};const setNoAutoLink=(editor,messages,urlString)=>{if(isValidUrl(urlString)){const pendingPromise=new _pending.default("tiny_noautolink/setNoautolink");setNoautolinkOnSelection(editor,urlString).catch((error=>{editor.notificationManager.open({text:error,type:"error",timeout:2e3})})).finally((()=>{editor.notificationManager.open({text:messages.infoAddSuccess,type:"success",timeout:2e3}),pendingPromise.resolve()}))}else editor.notificationManager.open({text:messages.errorInvalidURL,type:"error",timeout:2e3})},unsetNoAutoLink=(editor,messages)=>{const nodeString=editor.selection.getNode().outerHTML.trim(),wrapper=document.createElement("div");wrapper.innerHTML=nodeString;if(wrapper.firstChild.classList.contains("nolink")){const pendingPromise=new _pending.default("tiny_noautolink/setNoautolink");unsetNoautolinkOnSelection(editor,nodeString).catch((error=>{editor.notificationManager.open({text:error,type:"error",timeout:2e3}),pendingPromise.reject(error)})).finally((()=>{editor.notificationManager.open({text:messages.infoRemoveSuccess,type:"success",timeout:2e3}),pendingPromise.resolve()}))}},getSelectedContent=editor=>{const selection=editor.selection;let content=selection.getContent({format:"text"}).trim();if(""==content){const range=selection.getRng();if(range.startContainer.nodeType===Node.TEXT_NODE){const textContent=range.startContainer.textContent,cursorOffset=range.startOffset;let wordStart=cursorOffset;for(;wordStart>0&&/\S/.test(textContent[wordStart-1]);)wordStart--;let wordEnd=cursorOffset;for(;wordEnd<textContent.length&&/\S/.test(textContent[wordEnd]);)wordEnd++;selection.setRng({startContainer:range.startContainer,startOffset:wordStart,endContainer:range.startContainer,endOffset:wordEnd}),content=selection.getContent({format:"text"}).trim()}}return content},setNoautolinkOnSelection=async(editor,url)=>{const newContent="<".concat("span",' class="').concat("nolink",'">').concat(url,"</").concat("span",">");editor.selection.setContent(newContent);const currentNode=editor.selection.getNode(),currentDOM=editor.dom.select("".concat("span",".").concat("nolink"),currentNode);currentDOM.forEach((function(value,index){value.outerHTML!=newContent||editor.selection.select(currentDOM[index])}))},unsetNoautolinkOnSelection=async(editor,url)=>{const regex=new RegExp("</?".concat("span","[^>]*>"),"g");url=url.replace(regex,"");editor.dom.getParent(editor.selection.getNode(),"span").outerHTML=url},isValidUrl=urlString=>!!new RegExp("^((http|https):\\/\\/|www\\.)((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(urlString),isInAnchor=(editor,selectedElm)=>null!==((editor,selectedElm)=>(selectedElm=selectedElm||editor.selection.getNode(),editor.dom.getParent(selectedElm,"".concat("span",".").concat("nolink"))))(editor,selectedElm);_exports.toggleActiveState=editor=>api=>{const updateState=()=>api.setActive(!editor.mode.isReadOnly()&&isInAnchor(editor,editor.selection.getNode()));return updateState(),((editor,toggler)=>(editor.on("NodeChange",toggler),()=>editor.off("NodeChange",toggler)))(editor,updateState)}}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.toggleActiveState=_exports.handleAction=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};_exports.handleAction=(editor,messages)=>{const toggleState=isInAnchor(editor,editor.selection.getNode()),urlString=getSelectedContent(editor);toggleState||""===urlString?toggleState?unsetNoAutoLink(editor,messages,urlString):editor.notificationManager.open({text:messages.infoEmptySelection,type:"info",timeout:2e3}):setNoAutoLink(editor,messages,urlString)};const setNoAutoLink=(editor,messages,urlString)=>{const pendingPromise=new _pending.default("tiny_noautolink/setNoautolink");setNoautolinkOnSelection(editor,urlString).catch((error=>{editor.notificationManager.open({text:error,type:"error",timeout:2e3})})).finally((()=>{editor.notificationManager.open({text:messages.infoAddSuccess,type:"success",timeout:2e3}),pendingPromise.resolve()}))},unsetNoAutoLink=(editor,messages)=>{const nodeString=editor.selection.getNode().outerHTML.trim(),wrapper=document.createElement("div");wrapper.innerHTML=nodeString;if(wrapper.firstChild.classList.contains("nolink")){const pendingPromise=new _pending.default("tiny_noautolink/setNoautolink");unsetNoautolinkOnSelection(editor,nodeString).catch((error=>{editor.notificationManager.open({text:error,type:"error",timeout:2e3}),pendingPromise.reject(error)})).finally((()=>{editor.notificationManager.open({text:messages.infoRemoveSuccess,type:"success",timeout:2e3}),pendingPromise.resolve()}))}},getSelectedContent=editor=>{const selection=editor.selection;let content=selection.getContent({format:"text"}).trim();if(""==content){const range=selection.getRng();if(range.startContainer.nodeType===Node.TEXT_NODE){const textContent=range.startContainer.textContent,cursorOffset=range.startOffset;let wordStart=cursorOffset;for(;wordStart>0&&/\S/.test(textContent[wordStart-1]);)wordStart--;let wordEnd=cursorOffset;for(;wordEnd<textContent.length&&/\S/.test(textContent[wordEnd]);)wordEnd++;selection.setRng({startContainer:range.startContainer,startOffset:wordStart,endContainer:range.startContainer,endOffset:wordEnd}),content=selection.getContent({format:"text"}).trim()}}return content},setNoautolinkOnSelection=async(editor,url)=>{const newContent="<".concat("span",' class="').concat("nolink",'">').concat(url,"</").concat("span",">");editor.selection.setContent(newContent);const currentNode=editor.selection.getNode(),currentDOM=editor.dom.select("".concat("span",".").concat("nolink"),currentNode);currentDOM.forEach((function(value,index){value.outerHTML!=newContent||editor.selection.select(currentDOM[index])}))},unsetNoautolinkOnSelection=async(editor,url)=>{const regex=new RegExp("</?".concat("span","[^>]*>"),"g");url=url.replace(regex,"");editor.dom.getParent(editor.selection.getNode(),"span").outerHTML=url},isInAnchor=(editor,selectedElm)=>null!==((editor,selectedElm)=>(selectedElm=selectedElm||editor.selection.getNode(),editor.dom.getParent(selectedElm,"".concat("span",".").concat("nolink"))))(editor,selectedElm);_exports.toggleActiveState=editor=>api=>{const updateState=()=>api.setActive(!editor.mode.isReadOnly()&&isInAnchor(editor,editor.selection.getNode()));return updateState(),((editor,toggler)=>(editor.on("NodeChange",toggler),()=>editor.off("NodeChange",toggler)))(editor,updateState)}}));
//# sourceMappingURL=noautolink.min.js.map

File diff suppressed because one or more lines are too long

View file

@ -29,14 +29,12 @@ import {handleAction, toggleActiveState} from 'tiny_noautolink/noautolink';
export const getSetup = async() => {
const [
buttonText,
errorInvalidURL,
infoEmptySelection,
infoAddSuccess,
infoRemoveSuccess,
buttonImage,
] = await Promise.all([
getString('buttontitle', component),
getString('errorinvalidurl', component),
getString('infoemptyselection', component),
getString('infoaddsuccess', component),
getString('inforemovesuccess', component),
@ -46,7 +44,6 @@ export const getSetup = async() => {
return (editor) => {
const messages = {
errorInvalidURL: errorInvalidURL,
infoEmptySelection: infoEmptySelection,
infoAddSuccess: infoAddSuccess,
infoRemoveSuccess: infoRemoveSuccess

View file

@ -53,21 +53,16 @@ export const handleAction = (editor, messages) => {
* @param {String} urlString
*/
const setNoAutoLink = (editor, messages, urlString) => {
// Check whether the string is a URL. Otherwise, show an error notification.
if (isValidUrl(urlString)) {
const pendingPromise = new Pending('tiny_noautolink/setNoautolink');
// Applying the auto-link prevention.
setNoautolinkOnSelection(editor, urlString)
.catch(error => {
editor.notificationManager.open({text: error, type: 'error', timeout: notificationTimeout});
})
.finally(() => {
editor.notificationManager.open({text: messages.infoAddSuccess, type: 'success', timeout: notificationTimeout});
pendingPromise.resolve();
});
} else {
editor.notificationManager.open({text: messages.errorInvalidURL, type: 'error', timeout: notificationTimeout});
}
const pendingPromise = new Pending('tiny_noautolink/setNoautolink');
// Applying the auto-link prevention.
setNoautolinkOnSelection(editor, urlString)
.catch(error => {
editor.notificationManager.open({text: error, type: 'error', timeout: notificationTimeout});
})
.finally(() => {
editor.notificationManager.open({text: messages.infoAddSuccess, type: 'success', timeout: notificationTimeout});
pendingPromise.resolve();
});
};
/**
@ -172,23 +167,6 @@ const unsetNoautolinkOnSelection = async(editor, url) => {
currentSpan.outerHTML = url;
};
/**
* Check if given string is a valid URL.
*
* @param {String} urlString URL the link will point to.
* @returns {boolean} True is valid, otherwise false.
*/
const isValidUrl = urlString => {
const urlPattern = new RegExp('^((http|https):\\/\\/|www\\.)' + // A URL must have one of these https/https/www.
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // Validate domain name.
'((\\d{1,3}\\.){3}\\d{1,3}))' + // Validate ip (v4) address.
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // Validate port and path.
'(\\?[;&a-z\\d%_.~+=-]*)?' + // Validate query string.
'(\\#[-a-z\\d_]*)?$', 'i'); // Validate fragment locator.
return !!urlPattern.test(urlString);
};
/**
* Get anchor element.
*
@ -233,4 +211,4 @@ export const toggleActiveState = (editor) => (api) => {
const updateState = () => api.setActive(!editor.mode.isReadOnly() && isInAnchor(editor, editor.selection.getNode()));
updateState();
return toggleState(editor, updateState);
};
};

View file

@ -1 +1,2 @@
helplinktext,tiny_noautolink
errorinvalidurl,tiny_noautolink

View file

@ -23,12 +23,12 @@
*/
$string['buttontitle'] = 'No auto-link';
$string['errorinvalidurl'] = 'The selected content is not a URL. Please try again.';
$string['infoaddsuccess'] = 'Auto-link prevention added.';
$string['infoemptyselection'] = 'Select a URL and try again.';
$string['infoemptyselection'] = 'Select text and try again.';
$string['inforemovesuccess'] = 'Auto-link prevention removed.';
$string['pluginname'] = 'No auto-link';
$string['privacy:metadata'] = 'The tiny_noautolink plugin does not store any personal data.';
// Deprecated since Moodle 4.5.
$string['helplinktext'] = 'No auto-link helper';
$string['errorinvalidurl'] = 'The selected content is not a URL. Please try again.';

View file

@ -1,21 +1,36 @@
@editor @editor_tiny @tiny_noautolink
Feature: Tiny noautolink
To avoid auto-linking, users need to wrap the URL with the 'nolink' class.
In order to prevent auto-linking in TinyMCE
As a User
I need be able to apply the auto-link prevention feature to the selected text
@javascript
Scenario: Insert a link, add and remove the auto-link prevention
Background:
Given I log in as "admin"
And I navigate to "Plugins > Text editors > TinyMCE editor > General settings" in site administration
And I click on "Enable No auto-link" "link"
When I open my profile in edit mode
And I set the field "Description" to "<p>https://moodle.org</p>"
@javascript
Scenario: Add and remove auto-link prevention to URLs
Given I open my profile in edit mode
And I set the field "Description" to "<p>https://moodle.org</p>"
# Add auto-link prevention.
And I select the "p" element in position "0" of the "Description" TinyMCE editor
And I click on the "No auto-link" button for the "Description" TinyMCE editor
When I click on the "No auto-link" button for the "Description" TinyMCE editor
Then the field "Description" matches value "<p><span class='nolink'>https://moodle.org</span></p>"
# Remove auto-link prevention.
And I select the "span" element in position "0" of the "Description" TinyMCE editor
And I click on the "No auto-link" button for the "Description" TinyMCE editor
Then the field "Description" matches value "<p>https://moodle.org</p>"
And the field "Description" matches value "<p>https://moodle.org</p>"
@javascript
Scenario: Add and remove auto-link prevention to simple text
Given I open my profile in edit mode
And I set the field "Description" to "Some text"
# Add auto-link prevention.
And I select the "p" element in position "0" of the "Description" TinyMCE editor
When I click on the "No auto-link" button for the "Description" TinyMCE editor
Then the field "Description" matches value "<p><span class='nolink'>Some text</span></p>"
# Remove auto-link prevention.
And I select the "span" element in position "0" of the "Description" TinyMCE editor
And I click on the "No auto-link" button for the "Description" TinyMCE editor
And the field "Description" matches value "<p>Some text</p>"