Merge branch 'MDL-76474-401-2' of https://github.com/HuongNV13/moodle into MOODLE_401_STABLE

This commit is contained in:
Jun Pataleta 2023-01-12 11:55:41 +08:00
commit d24c201b6d
13 changed files with 98 additions and 11 deletions

View File

@ -1,3 +1,3 @@
define("editor_tiny/options",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.register=_exports.getPluginOptionName=_exports.getMoodleLang=_exports.getInitialPluginConfiguration=_exports.getFilepickers=_exports.getFilePicker=_exports.getDraftItemId=_exports.getCurrentLanguage=_exports.getContextId=void 0;_exports.register=(editor,options)=>{const registerOption=editor.options.register,setOption=editor.options.set;registerOption("moodle:contextid",{processor:"number",default:0}),setOption("moodle:contextid",options.context),registerOption("moodle:filepickers",{processor:"object",default:{}}),setOption("moodle:filepickers",options.filepicker),registerOption("moodle:draftitemid",{processor:"number",default:0}),setOption("moodle:draftitemid",options.draftitemid),registerOption("moodle:currentLanguage",{processor:"string",default:"en"}),setOption("moodle:currentLanguage",options.currentLanguage),registerOption("moodle:language",{processor:"object",default:{}}),setOption("moodle:language",options.language)};_exports.getContextId=editor=>editor.options.get("moodle:contextid");_exports.getDraftItemId=editor=>editor.options.get("moodle:draftitemid");const getFilepickers=editor=>editor.options.get("moodle:filepickers");_exports.getFilepickers=getFilepickers;_exports.getFilePicker=(editor,type)=>getFilepickers(editor)[type];_exports.getMoodleLang=editor=>editor.options.get("moodle:language");_exports.getCurrentLanguage=editor=>editor.options.get("moodle:currentLanguage");_exports.getInitialPluginConfiguration=options=>{const config={};return Object.entries(options.plugins).forEach((_ref=>{var _pluginConfig$config;let[pluginName,pluginConfig]=_ref;Object.entries(null!==(_pluginConfig$config=pluginConfig.config)&&void 0!==_pluginConfig$config?_pluginConfig$config:{}).forEach((_ref2=>{let[optionName,value]=_ref2;config[getPluginOptionName(pluginName,optionName)]=value}))})),config};const getPluginOptionName=(pluginName,optionName)=>"".concat(pluginName,":").concat(optionName);_exports.getPluginOptionName=getPluginOptionName}));
define("editor_tiny/options",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.registerPlaceholderSelectors=_exports.register=_exports.getPluginOptionName=_exports.getPlaceholderSelectors=_exports.getMoodleLang=_exports.getInitialPluginConfiguration=_exports.getFilepickers=_exports.getFilePicker=_exports.getDraftItemId=_exports.getCurrentLanguage=_exports.getContextId=void 0;_exports.register=(editor,options)=>{const registerOption=editor.options.register,setOption=editor.options.set;registerOption("moodle:contextid",{processor:"number",default:0}),setOption("moodle:contextid",options.context),registerOption("moodle:filepickers",{processor:"object",default:{}}),setOption("moodle:filepickers",options.filepicker),registerOption("moodle:draftitemid",{processor:"number",default:0}),setOption("moodle:draftitemid",options.draftitemid),registerOption("moodle:currentLanguage",{processor:"string",default:"en"}),setOption("moodle:currentLanguage",options.currentLanguage),registerOption("moodle:language",{processor:"object",default:{}}),setOption("moodle:language",options.language),registerOption("moodle:placeholderSelectors",{processor:"array",default:[]}),setOption("moodle:placeholderSelectors",options.placeholderSelectors)};_exports.getContextId=editor=>editor.options.get("moodle:contextid");_exports.getDraftItemId=editor=>editor.options.get("moodle:draftitemid");const getFilepickers=editor=>editor.options.get("moodle:filepickers");_exports.getFilepickers=getFilepickers;_exports.getFilePicker=(editor,type)=>getFilepickers(editor)[type];_exports.getMoodleLang=editor=>editor.options.get("moodle:language");_exports.getCurrentLanguage=editor=>editor.options.get("moodle:currentLanguage");_exports.getInitialPluginConfiguration=options=>{const config={};return Object.entries(options.plugins).forEach((_ref=>{var _pluginConfig$config;let[pluginName,pluginConfig]=_ref;Object.entries(null!==(_pluginConfig$config=pluginConfig.config)&&void 0!==_pluginConfig$config?_pluginConfig$config:{}).forEach((_ref2=>{let[optionName,value]=_ref2;config[getPluginOptionName(pluginName,optionName)]=value}))})),config};const getPluginOptionName=(pluginName,optionName)=>"".concat(pluginName,":").concat(optionName);_exports.getPluginOptionName=getPluginOptionName;const getPlaceholderSelectors=editor=>editor.options.get("moodle:placeholderSelectors");_exports.getPlaceholderSelectors=getPlaceholderSelectors;_exports.registerPlaceholderSelectors=(editor,selectors)=>{if(selectors.length){let existingData=getPlaceholderSelectors(editor);existingData=existingData.concat(selectors),editor.options.set("moodle:placeholderSelectors",existingData)}}}));
//# sourceMappingURL=options.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -26,6 +26,7 @@ const optionDraftItemId = 'moodle:draftitemid';
const filePickers = 'moodle:filepickers';
const optionsMoodleLang = 'moodle:language';
const currentLanguage = 'moodle:currentLanguage';
const optionPlaceholderSelectors = 'moodle:placeholderSelectors';
export const register = (editor, options) => {
const registerOption = editor.options.register;
@ -61,6 +62,12 @@ export const register = (editor, options) => {
"default": {},
});
setOption(optionsMoodleLang, options.language);
registerOption(optionPlaceholderSelectors, {
processor: 'array',
"default": [],
});
setOption(optionPlaceholderSelectors, options.placeholderSelectors);
};
export const getContextId = (editor) => editor.options.get(optionContextId);
@ -97,3 +104,25 @@ export const getInitialPluginConfiguration = (options) => {
* @returns {string}
*/
export const getPluginOptionName = (pluginName, optionName) => `${pluginName}:${optionName}`;
/**
* Get the placeholder selectors.
*
* @param {TinyMCE} editor
* @returns {array}
*/
export const getPlaceholderSelectors = (editor) => editor.options.get(optionPlaceholderSelectors);
/**
* Register placeholder selectos.
*
* @param {TinyMCE} editor
* @param {array} selectors
*/
export const registerPlaceholderSelectors = (editor, selectors) => {
if (selectors.length) {
let existingData = getPlaceholderSelectors(editor);
existingData = existingData.concat(selectors);
editor.options.set(optionPlaceholderSelectors, existingData);
}
};

View File

@ -183,10 +183,24 @@ class editor extends \texteditor {
'available' => get_string_manager()->get_list_of_languages()
],
// Placeholder selectors.
// Some contents (Example: placeholder elements) are only shown in the editor, and not to users. It is unrelated to the
// real display. We created a list of placeholder selectors, so we can decide to or not to apply rules, styles... to
// these elements.
// The default of this list will be empty.
// Other plugins can register their placeholder elements to placeholderSelectors list by calling
// editor_tiny/options::registerPlaceholderSelectors.
'placeholderSelectors' => [],
// Plugin configuration.
'plugins' => $this->manager->get_plugin_configuration($context, $options, $fpoptions, $this),
];
if (defined('BEHAT_SITE_RUNNING') && BEHAT_SITE_RUNNING) {
// Add sample selectors for Behat test.
$config->placeholderSelectors = ['.behat-tinymce-placeholder'];
}
foreach ($fpoptions as $fp) {
// Guess the draftitemid for the editor.
// Note: This is the best we can do at the moment.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -25,6 +25,7 @@ import {component} from './common';
import * as Modal from 'core/modal_factory';
import * as ModalEvents from 'core/modal_events';
import ColorBase from './colorbase';
import {getPlaceholderSelectors} from 'editor_tiny/options';
/**
* @typedef ProblemDetail
@ -48,6 +49,11 @@ export default class {
this.editor = editor;
this.colorBase = new ColorBase();
this.modal = null;
this.placeholderSelectors = null;
const placeholders = getPlaceholderSelectors(this.editor);
if (placeholders.length) {
this.placeholderSelectors = placeholders.join(', ');
}
}
destroy() {
@ -247,7 +253,14 @@ export default class {
nodeData: [],
};
warning.nodeData = [...nodes].map((node) => {
warning.nodeData = [...nodes].filter((node) => {
// If the failed node is a placeholder element. We should remove it from the list.
if (node !== this.editor && this.placeholderSelectors) {
return node.matches(this.placeholderSelectors) === false;
}
return node;
}).map((node) => {
const describedNode = getEventualNode(node);
// Find the index of the node within the type of node.

View File

@ -1,4 +1,4 @@
@editor @editor_tiny
@editor @editor_tiny @tiny_accessibilitychecker
Feature: Tiny editor accessibility checker
To write accessible content in Tiny, I need to check for accessibility warnings.
@ -43,3 +43,11 @@ Feature: Tiny editor accessibility checker
When I press "Save image"
And I click on the "Tools > Accessibility checker" menu item for the "Description" TinyMCE editor
Then I should see "Congratulations, no accessibility issues found!" in the "Accessibility checker" "dialogue"
@javascript
Scenario: Placeholder element will not be assessed by accessibility checker
Given I log in as "admin"
And I open my profile in edit mode
When I set the field "Description" to "<p>Some plain text</p><img src='/broken-image' width='1' height='1' class='behat-tinymce-placeholder'/><p>Some more text</p>"
And I click on the "Tools > Accessibility checker" menu item for the "Description" TinyMCE editor
Then I should see "Congratulations, no accessibility issues found!" in the "Accessibility checker" "dialogue"

View File

@ -0,0 +1,7 @@
This files describes API changes in tiny_accessibilitychecker - TinyMCE Accessibility checker plugin,
information provided here is intended especially for developers.
=== 4.1.1 ===
* The placeholder elements which were registered in placeholderSelectors in editor_tiny/options will not be
assessed by the accessibility checker plugin.

View File

@ -1,3 +1,3 @@
define("tiny_h5p/filtercontent",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=void 0;_exports.setup=async editor=>{editor.on("PreInit",(()=>{editor.formatter.register("h5p",{inline:"div",classes:"h5p-placeholder"})})),editor.on("SetContent",(()=>{editor.getBody().querySelectorAll(".h5p-placeholder:not([contenteditable])").forEach((node=>{node.contentEditable=!1}))}))}}));
define("tiny_h5p/filtercontent",["exports","editor_tiny/options"],(function(_exports,_options){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=void 0;_exports.setup=async editor=>{const classSelector=".".concat("h5p-placeholder");(0,_options.registerPlaceholderSelectors)(editor,[classSelector]),editor.on("PreInit",(()=>{editor.formatter.register("h5p",{inline:"div",classes:"h5p-placeholder"})})),editor.on("SetContent",(()=>{editor.getBody().querySelectorAll("".concat(classSelector,":not([contenteditable])")).forEach((node=>{node.contentEditable=!1}))}))}}));
//# sourceMappingURL=filtercontent.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"filtercontent.min.js","sources":["../src/filtercontent.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\n/**\n * Tiny H5P Content configuration.\n *\n * @module tiny_h5p/filtercontent\n * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const setup = async(editor) => {\n // Register the H5P Formatter for use in all buttons.\n editor.on('PreInit', () => {\n editor.formatter.register('h5p', {\n inline: 'div',\n classes: 'h5p-placeholder',\n });\n });\n\n editor.on('SetContent', () => {\n // Listen to the SetContent event on the editor and update any h5p-placeholder to not be editable.\n // Doing this means that the inner content of the placeholder cannot be changed without using the dialogue.\n // The SetContent event is called whenever content is changed by actions such as initial load, paste, undo, etc.\n editor.getBody().querySelectorAll('.h5p-placeholder:not([contenteditable])').forEach((node) => {\n node.contentEditable = false;\n });\n });\n};\n"],"names":["async","editor","on","formatter","register","inline","classes","getBody","querySelectorAll","forEach","node","contentEditable"],"mappings":"6JAuBqBA,MAAAA,SAEjBC,OAAOC,GAAG,WAAW,KACjBD,OAAOE,UAAUC,SAAS,MAAO,CAC7BC,OAAQ,MACRC,QAAS,uBAIjBL,OAAOC,GAAG,cAAc,KAIpBD,OAAOM,UAAUC,iBAAiB,2CAA2CC,SAASC,OAClFA,KAAKC,iBAAkB"}
{"version":3,"file":"filtercontent.min.js","sources":["../src/filtercontent.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\n/**\n * Tiny H5P Content configuration.\n *\n * @module tiny_h5p/filtercontent\n * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {registerPlaceholderSelectors} from 'editor_tiny/options';\n\nexport const setup = async(editor) => {\n const className = 'h5p-placeholder';\n const classSelector = `.${className}`;\n // Register the H5P Formatter to the placeholder selector list.\n registerPlaceholderSelectors(editor, [classSelector]);\n // Register the H5P Formatter for use in all buttons.\n editor.on('PreInit', () => {\n editor.formatter.register('h5p', {\n inline: 'div',\n classes: className,\n });\n });\n\n editor.on('SetContent', () => {\n // Listen to the SetContent event on the editor and update any h5p-placeholder to not be editable.\n // Doing this means that the inner content of the placeholder cannot be changed without using the dialogue.\n // The SetContent event is called whenever content is changed by actions such as initial load, paste, undo, etc.\n editor.getBody().querySelectorAll(`${classSelector}:not([contenteditable])`).forEach((node) => {\n node.contentEditable = false;\n });\n });\n};\n"],"names":["async","classSelector","editor","on","formatter","register","inline","classes","getBody","querySelectorAll","forEach","node","contentEditable"],"mappings":"4LAyBqBA,MAAAA,eAEXC,yBADY,6DAGWC,OAAQ,CAACD,gBAEtCC,OAAOC,GAAG,WAAW,KACjBD,OAAOE,UAAUC,SAAS,MAAO,CAC7BC,OAAQ,MACRC,QARU,uBAYlBL,OAAOC,GAAG,cAAc,KAIpBD,OAAOM,UAAUC,2BAAoBR,0CAAwCS,SAASC,OAClFA,KAAKC,iBAAkB"}

View File

@ -21,12 +21,18 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {registerPlaceholderSelectors} from 'editor_tiny/options';
export const setup = async(editor) => {
const className = 'h5p-placeholder';
const classSelector = `.${className}`;
// Register the H5P Formatter to the placeholder selector list.
registerPlaceholderSelectors(editor, [classSelector]);
// Register the H5P Formatter for use in all buttons.
editor.on('PreInit', () => {
editor.formatter.register('h5p', {
inline: 'div',
classes: 'h5p-placeholder',
classes: className,
});
});
@ -34,7 +40,7 @@ export const setup = async(editor) => {
// Listen to the SetContent event on the editor and update any h5p-placeholder to not be editable.
// Doing this means that the inner content of the placeholder cannot be changed without using the dialogue.
// The SetContent event is called whenever content is changed by actions such as initial load, paste, undo, etc.
editor.getBody().querySelectorAll('.h5p-placeholder:not([contenteditable])').forEach((node) => {
editor.getBody().querySelectorAll(`${classSelector}:not([contenteditable])`).forEach((node) => {
node.contentEditable = false;
});
});

View File

@ -0,0 +1,10 @@
This files describes API changes in /lib/editor/tiny/* - TinyMCE editor,
information provided here is intended especially for developers.
=== 4.1.1 ===
* A list of placeholder selectors was created and can be accessed by placeholderSelectors options. The purpose of this list
is to indicate the contents that are only shown in the editor and not to the users, by that way, we can decide to apply or
not to apply rules, styles, etc... to these contents.
Other Tiny plugins can register their placeholder elements to placeholderSelectors list
by calling editor_tiny/options::registerPlaceholderSelectors.