From e49af69a1d8d5ecacb3740d0cc2a81c8e9904ec1 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 26 Sep 2024 21:45:18 +0800 Subject: [PATCH] MDL-83282 editor_atto: Remove Atto editor This minor patch removes the Atto editor, and all of its subplugins from Moodle core. --- .upgradenotes/MDL-83282-2024112007284289.yml | 9 + lib/db/upgrade.php | 19 + lib/editor/atto/adminlib.php | 252 - lib/editor/atto/amd/build/events.min.js | 12 - lib/editor/atto/amd/build/events.min.js.map | 1 - lib/editor/atto/amd/src/events.js | 65 - lib/editor/atto/autosave-ajax.php | 221 - lib/editor/atto/classes/plugininfo/atto.php | 87 - lib/editor/atto/classes/privacy/provider.php | 244 - .../classes/task/autosave_cleanup_task.php | 58 - lib/editor/atto/db/install.xml | 25 - lib/editor/atto/db/subplugins.json | 8 - lib/editor/atto/db/tasks.php | 44 - lib/editor/atto/db/upgrade.php | 44 - lib/editor/atto/lang/en/editor_atto.php | 54 - lib/editor/atto/lib.php | 207 - lib/editor/atto/pix/logo.png | Bin 2795 -> 0 bytes lib/editor/atto/pix/logo.svg | 91 - .../classes/privacy/provider.php | 46 - .../lang/en/atto_accessibilitychecker.php | 36 - .../atto/plugins/accessibilitychecker/lib.php | 46 - .../plugins/accessibilitychecker/styles.css | 4 - .../tests/behat/accessibilitychecker.feature | 76 - .../plugins/accessibilitychecker/version.php | 29 - ...-atto_accessibilitychecker-button-debug.js | 357 - ...le-atto_accessibilitychecker-button-min.js | 1 - ...moodle-atto_accessibilitychecker-button.js | 352 - .../yui/src/button/build.json | 10 - .../yui/src/button/js/button.js | 352 - .../yui/src/button/meta/button.json | 8 - .../classes/privacy/provider.php | 46 - .../lang/en/atto_accessibilityhelper.php | 34 - .../atto/plugins/accessibilityhelper/lib.php | 44 - .../tests/behat/accessibilityhelper.feature | 32 - .../plugins/accessibilityhelper/version.php | 29 - ...e-atto_accessibilityhelper-button-debug.js | 280 - ...dle-atto_accessibilityhelper-button-min.js | 1 - .../moodle-atto_accessibilityhelper-button.js | 280 - .../yui/src/button/build.json | 10 - .../yui/src/button/js/button.js | 275 - .../yui/src/button/meta/button.json | 7 - .../align/classes/privacy/provider.php | 46 - .../atto/plugins/align/lang/en/atto_align.php | 29 - lib/editor/atto/plugins/align/lib.php | 35 - .../plugins/align/tests/behat/align.feature | 52 - lib/editor/atto/plugins/align/version.php | 29 - .../moodle-atto_align-button-debug.js | 106 - .../moodle-atto_align-button-min.js | 1 - .../moodle-atto_align-button.js | 106 - .../plugins/align/yui/src/button/build.json | 10 - .../plugins/align/yui/src/button/js/button.js | 101 - .../align/yui/src/button/meta/button.json | 7 - .../backcolor/classes/privacy/provider.php | 46 - .../backcolor/lang/en/atto_backcolor.php | 32 - lib/editor/atto/plugins/backcolor/lib.php | 41 - lib/editor/atto/plugins/backcolor/styles.css | 26 - lib/editor/atto/plugins/backcolor/version.php | 29 - .../moodle-atto_backcolor-button-debug.js | 97 - .../moodle-atto_backcolor-button-min.js | 1 - .../moodle-atto_backcolor-button.js | 97 - .../backcolor/yui/src/button/build.json | 10 - .../backcolor/yui/src/button/js/button.js | 92 - .../backcolor/yui/src/button/meta/editor.js | 5 - .../plugins/bold/classes/privacy/provider.php | 46 - .../atto/plugins/bold/lang/en/atto_bold.php | 26 - .../plugins/bold/tests/behat/bold.feature | 35 - lib/editor/atto/plugins/bold/version.php | 29 - .../moodle-atto_bold-button-debug.js | 72 - .../moodle-atto_bold-button-min.js | 1 - .../moodle-atto_bold-button.js | 72 - .../plugins/bold/yui/src/button/build.json | 10 - .../plugins/bold/yui/src/button/js/button.js | 67 - .../bold/yui/src/button/meta/button.json | 7 - .../charmap/classes/privacy/provider.php | 46 - .../plugins/charmap/lang/en/atto_charmap.php | 293 - lib/editor/atto/plugins/charmap/lib.php | 306 - lib/editor/atto/plugins/charmap/styles.css | 4 - .../charmap/tests/behat/charmap.feature | 20 - lib/editor/atto/plugins/charmap/version.php | 29 - .../moodle-atto_charmap-button-debug.js | 431 - .../moodle-atto_charmap-button-min.js | 2 - .../moodle-atto_charmap-button.js | 431 - .../plugins/charmap/yui/src/button/build.json | 10 - .../charmap/yui/src/button/js/button.js | 426 - .../charmap/yui/src/button/meta/button.json | 7 - .../clear/classes/privacy/provider.php | 46 - .../atto/plugins/clear/lang/en/atto_clear.php | 26 - .../plugins/clear/tests/behat/clear.feature | 21 - lib/editor/atto/plugins/clear/version.php | 29 - .../moodle-atto_clear-button-debug.js | 46 - .../moodle-atto_clear-button-min.js | 1 - .../moodle-atto_clear-button.js | 46 - .../plugins/clear/yui/src/button/build.json | 10 - .../plugins/clear/yui/src/button/js/button.js | 41 - .../clear/yui/src/button/meta/button.json | 7 - .../collapse/classes/privacy/provider.php | 46 - .../collapse/lang/en/atto_collapse.php | 32 - lib/editor/atto/plugins/collapse/lib.php | 53 - lib/editor/atto/plugins/collapse/pix/icon.svg | 1 - lib/editor/atto/plugins/collapse/settings.php | 43 - lib/editor/atto/plugins/collapse/styles.css | 5 - .../collapse/tests/behat/collapse.feature | 12 - lib/editor/atto/plugins/collapse/version.php | 29 - .../moodle-atto_collapse-button-debug.js | 153 - .../moodle-atto_collapse-button-min.js | 1 - .../moodle-atto_collapse-button.js | 149 - .../collapse/yui/src/button/build.json | 10 - .../collapse/yui/src/button/js/button.js | 148 - .../collapse/yui/src/button/meta/button.json | 7 - .../emojipicker/classes/privacy/provider.php | 46 - .../emojipicker/lang/en/atto_emojipicker.php | 27 - lib/editor/atto/plugins/emojipicker/lib.php | 48 - .../atto/plugins/emojipicker/styles.css | 8 - .../atto/plugins/emojipicker/version.php | 29 - .../moodle-atto_emojipicker-button-debug.js | 143 - .../moodle-atto_emojipicker-button-min.js | 1 - .../moodle-atto_emojipicker-button.js | 143 - .../emojipicker/yui/src/button/build.json | 10 - .../emojipicker/yui/src/button/js/button.js | 138 - .../yui/src/button/meta/button.json | 7 - .../emoticon/classes/privacy/provider.php | 46 - .../emoticon/lang/en/atto_emoticon.php | 27 - lib/editor/atto/plugins/emoticon/lib.php | 54 - lib/editor/atto/plugins/emoticon/styles.css | 20 - lib/editor/atto/plugins/emoticon/version.php | 29 - .../moodle-atto_emoticon-button-debug.js | 170 - .../moodle-atto_emoticon-button-min.js | 1 - .../moodle-atto_emoticon-button.js | 170 - .../emoticon/yui/src/button/build.json | 10 - .../emoticon/yui/src/button/js/button.js | 165 - .../emoticon/yui/src/button/meta/button.json | 7 - lib/editor/atto/plugins/equation/ajax.php | 51 - .../equation/classes/privacy/provider.php | 46 - .../atto/plugins/equation/db/upgrade.php | 44 - .../equation/lang/en/atto_equation.php | 40 - lib/editor/atto/plugins/equation/lib.php | 93 - lib/editor/atto/plugins/equation/settings.php | 175 - lib/editor/atto/plugins/equation/styles.css | 11 - .../equation/tests/behat/equation.feature | 38 - lib/editor/atto/plugins/equation/version.php | 29 - .../moodle-atto_equation-button-debug.js | 791 - .../moodle-atto_equation-button-min.js | 2 - .../moodle-atto_equation-button.js | 789 - .../equation/yui/src/button/build.json | 10 - .../equation/yui/src/button/js/button.js | 777 - .../equation/yui/src/button/meta/button.json | 12 - .../fontcolor/classes/privacy/provider.php | 46 - .../fontcolor/lang/en/atto_fontcolor.php | 32 - lib/editor/atto/plugins/fontcolor/lib.php | 41 - lib/editor/atto/plugins/fontcolor/styles.css | 26 - lib/editor/atto/plugins/fontcolor/version.php | 29 - .../moodle-atto_fontcolor-button-debug.js | 99 - .../moodle-atto_fontcolor-button-min.js | 1 - .../moodle-atto_fontcolor-button.js | 99 - .../fontcolor/yui/src/button/build.json | 10 - .../fontcolor/yui/src/button/js/button.js | 94 - .../fontcolor/yui/src/button/meta/editor.js | 5 - .../plugins/h5p/classes/privacy/provider.php | 46 - lib/editor/atto/plugins/h5p/db/access.php | 35 - .../atto/plugins/h5p/lang/en/atto_h5p.php | 38 - lib/editor/atto/plugins/h5p/lib.php | 85 - .../atto/plugins/h5p/pix/icon-white.png | Bin 6257 -> 0 bytes .../atto/plugins/h5p/pix/icon-white.svg | 18 - lib/editor/atto/plugins/h5p/pix/icon.png | Bin 4541 -> 0 bytes lib/editor/atto/plugins/h5p/pix/icon.svg | 14 - lib/editor/atto/plugins/h5p/styles.css | 20 - .../atto/plugins/h5p/tests/behat/h5p.feature | 220 - lib/editor/atto/plugins/h5p/version.php | 29 - .../moodle-atto_h5p-button-debug.js | 605 - .../moodle-atto_h5p-button-min.js | 3 - .../moodle-atto_h5p-button.js | 605 - .../plugins/h5p/yui/src/button/build.json | 10 - .../plugins/h5p/yui/src/button/js/button.js | 600 - .../h5p/yui/src/button/meta/button.json | 7 - .../plugins/html/classes/privacy/provider.php | 46 - .../atto/plugins/html/lang/en/atto_html.php | 26 - lib/editor/atto/plugins/html/styles.css | 4 - .../plugins/html/tests/behat/html.feature | 31 - .../atto/plugins/html/thirdpartylibs.xml | 22 - lib/editor/atto/plugins/html/version.php | 29 - .../moodle-atto_html-beautify-debug.js | 8988 ----------- .../moodle-atto_html-beautify-min.js | 25 - .../moodle-atto_html-beautify.js | 8988 ----------- .../moodle-atto_html-button-debug.js | 201 - .../moodle-atto_html-button-min.js | 1 - .../moodle-atto_html-button.js | 201 - .../moodle-atto_html-codemirror-core.css | 346 - .../sam/moodle-atto_html-codemirror-skin.css | 0 .../skins/sam/moodle-atto_html-codemirror.css | 1 - .../moodle-atto_html-codemirror-debug.js | 12289 ---------------- .../moodle-atto_html-codemirror-min.js | 38 - .../moodle-atto_html-codemirror.js | 12289 ---------------- .../plugins/html/yui/src/beautify/LICENSE | 9 - .../plugins/html/yui/src/beautify/build.json | 16 - .../html/yui/src/beautify/js/beautify-css.js | 1693 --- .../html/yui/src/beautify/js/beautify-html.js | 3225 ---- .../html/yui/src/beautify/js/beautify.js | 4049 ----- .../html/yui/src/beautify/js/wrapper.js | 16 - .../html/yui/src/beautify/meta/beautify.json | 4 - .../html/yui/src/beautify/readme_moodle.txt | 7 - .../plugins/html/yui/src/button/build.json | 10 - .../plugins/html/yui/src/button/js/button.js | 188 - .../html/yui/src/button/meta/button.json | 11 - .../plugins/html/yui/src/codemirror/LICENSE | 21 - .../moodle-atto_html-codemirror-core.css | 346 - .../sam/moodle-atto_html-codemirror-skin.css | 0 .../html/yui/src/codemirror/build.json | 21 - .../html/yui/src/codemirror/js/codemirror.js | 9884 ------------- .../plugins/html/yui/src/codemirror/js/css.js | 862 -- .../html/yui/src/codemirror/js/htmlmixed.js | 153 - .../html/yui/src/codemirror/js/javascript.js | 960 -- .../html/yui/src/codemirror/js/wrapper-end.js | 5 - .../html/yui/src/codemirror/js/wrapper-mid.js | 1 - .../html/yui/src/codemirror/js/wrapper.js | 2 - .../plugins/html/yui/src/codemirror/js/xml.js | 417 - .../yui/src/codemirror/meta/codemirror.json | 7 - .../html/yui/src/codemirror/readme_moodle.txt | 28 - .../image/classes/privacy/provider.php | 46 - .../atto/plugins/image/lang/en/atto_image.php | 48 - lib/editor/atto/plugins/image/lib.php | 58 - lib/editor/atto/plugins/image/styles.css | 53 - .../plugins/image/tests/behat/image.feature | 93 - lib/editor/atto/plugins/image/version.php | 29 - .../moodle-atto_image-button-debug.js | 1116 -- .../moodle-atto_image-button-min.js | 3 - .../moodle-atto_image-button.js | 1114 -- .../plugins/image/yui/src/button/build.json | 10 - .../plugins/image/yui/src/button/js/button.js | 1111 -- .../image/yui/src/button/meta/button.json | 7 - .../indent/classes/privacy/provider.php | 46 - .../plugins/indent/lang/en/atto_indent.php | 28 - lib/editor/atto/plugins/indent/lib.php | 35 - .../plugins/indent/tests/behat/indent.feature | 37 - lib/editor/atto/plugins/indent/version.php | 29 - .../moodle-atto_indent-button-debug.js | 227 - .../moodle-atto_indent-button-min.js | 1 - .../moodle-atto_indent-button.js | 227 - .../plugins/indent/yui/src/button/build.json | 10 - .../indent/yui/src/button/js/button.js | 222 - .../indent/yui/src/button/meta/button.json | 7 - .../italic/classes/privacy/provider.php | 46 - .../plugins/italic/lang/en/atto_italic.php | 26 - .../plugins/italic/tests/behat/italic.feature | 35 - lib/editor/atto/plugins/italic/version.php | 29 - .../moodle-atto_italic-button-debug.js | 72 - .../moodle-atto_italic-button-min.js | 1 - .../moodle-atto_italic-button.js | 72 - .../plugins/italic/yui/src/button/build.json | 10 - .../italic/yui/src/button/js/button.js | 67 - .../italic/yui/src/button/meta/button.json | 7 - .../plugins/link/classes/privacy/provider.php | 46 - .../atto/plugins/link/lang/en/atto_link.php | 32 - lib/editor/atto/plugins/link/lib.php | 42 - .../plugins/link/tests/behat/link.feature | 115 - lib/editor/atto/plugins/link/version.php | 29 - .../moodle-atto_link-button-debug.js | 557 - .../moodle-atto_link-button-min.js | 2 - .../moodle-atto_link-button.js | 557 - .../plugins/link/yui/src/button/build.json | 10 - .../plugins/link/yui/src/button/js/button.js | 552 - .../link/yui/src/button/meta/button.json | 7 - .../managefiles/classes/privacy/provider.php | 46 - .../managefiles/lang/en/atto_managefiles.php | 34 - lib/editor/atto/plugins/managefiles/lib.php | 72 - .../atto/plugins/managefiles/manage.php | 114 - .../atto/plugins/managefiles/manage_form.php | 119 - .../atto/plugins/managefiles/styles.css | 19 - .../atto/plugins/managefiles/version.php | 29 - .../moodle-atto_managefiles-button-debug.js | 150 - .../moodle-atto_managefiles-button-min.js | 1 - .../moodle-atto_managefiles-button.js | 148 - ...moodle-atto_managefiles-usedfiles-debug.js | 206 - .../moodle-atto_managefiles-usedfiles-min.js | 1 - .../moodle-atto_managefiles-usedfiles.js | 205 - .../managefiles/yui/src/button/build.json | 10 - .../managefiles/yui/src/button/js/button.js | 145 - .../yui/src/button/meta/button.json | 7 - .../managefiles/yui/src/usedfiles/build.json | 10 - .../yui/src/usedfiles/js/usedfiles.js | 201 - .../yui/src/usedfiles/meta/usedfiles.json | 8 - .../media/classes/privacy/provider.php | 46 - .../atto/plugins/media/lang/en/atto_media.php | 84 - lib/editor/atto/plugins/media/lib.php | 128 - lib/editor/atto/plugins/media/styles.css | 4 - .../atto/plugins/media/styles_clean.css | 28 - .../plugins/media/tests/behat/media.feature | 206 - lib/editor/atto/plugins/media/version.php | 29 - .../moodle-atto_media-button-debug.js | 1066 -- .../moodle-atto_media-button-min.js | 5 - .../moodle-atto_media-button.js | 1066 -- .../plugins/media/yui/src/button/build.json | 10 - .../plugins/media/yui/src/button/js/button.js | 1061 -- .../media/yui/src/button/meta/button.json | 8 - .../noautolink/classes/privacy/provider.php | 46 - .../noautolink/lang/en/atto_noautolink.php | 26 - .../atto/plugins/noautolink/version.php | 29 - .../moodle-atto_noautolink-button-debug.js | 60 - .../moodle-atto_noautolink-button-min.js | 1 - .../moodle-atto_noautolink-button.js | 60 - .../noautolink/yui/src/button/build.json | 10 - .../noautolink/yui/src/button/js/button.js | 55 - .../yui/src/button/meta/button.json | 7 - .../orderedlist/classes/privacy/provider.php | 46 - .../orderedlist/lang/en/atto_orderedlist.php | 26 - .../tests/behat/orderedlist.feature | 18 - .../atto/plugins/orderedlist/version.php | 29 - .../moodle-atto_orderedlist-button-debug.js | 49 - .../moodle-atto_orderedlist-button-min.js | 1 - .../moodle-atto_orderedlist-button.js | 49 - .../orderedlist/yui/src/button/build.json | 10 - .../orderedlist/yui/src/button/js/button.js | 44 - .../yui/src/button/meta/button.json | 7 - .../recordrtc/classes/privacy/provider.php | 46 - .../atto/plugins/recordrtc/db/access.php | 44 - .../atto/plugins/recordrtc/db/upgrade.php | 45 - .../recordrtc/lang/en/atto_recordrtc.php | 80 - lib/editor/atto/plugins/recordrtc/lib.php | 145 - .../atto/plugins/recordrtc/pix/i/audiortc.svg | 1 - .../atto/plugins/recordrtc/pix/i/videortc.svg | 1 - .../atto/plugins/recordrtc/pix/icon.png | Bin 644 -> 0 bytes .../atto/plugins/recordrtc/settings.php | 86 - lib/editor/atto/plugins/recordrtc/styles.css | 39 - lib/editor/atto/plugins/recordrtc/version.php | 32 - .../moodle-atto_recordrtc-button-debug.js | 394 - .../moodle-atto_recordrtc-button-min.js | 1 - .../moodle-atto_recordrtc-button.js | 394 - .../moodle-atto_recordrtc-recording-debug.js | 855 -- .../moodle-atto_recordrtc-recording-min.js | 2 - .../moodle-atto_recordrtc-recording.js | 855 -- .../recordrtc/yui/src/button/build.json | 10 - .../recordrtc/yui/src/button/js/button.js | 389 - .../recordrtc/yui/src/button/meta/button.json | 8 - .../recordrtc/yui/src/recording/build.json | 14 - .../yui/src/recording/js/abstractmodule.js | 137 - .../yui/src/recording/js/audiomodule.js | 148 - .../yui/src/recording/js/commonmodule.js | 351 - .../yui/src/recording/js/compatcheckmodule.js | 58 - .../yui/src/recording/js/videomodule.js | 156 - .../yui/src/recording/meta/recording.json | 7 - .../plugins/rtl/classes/privacy/provider.php | 46 - .../atto/plugins/rtl/lang/en/atto_rtl.php | 28 - lib/editor/atto/plugins/rtl/lib.php | 44 - lib/editor/atto/plugins/rtl/version.php | 29 - .../moodle-atto_rtl-button-debug.js | 103 - .../moodle-atto_rtl-button-min.js | 1 - .../moodle-atto_rtl-button.js | 103 - .../plugins/rtl/yui/src/button/build.json | 10 - .../plugins/rtl/yui/src/button/js/button.js | 98 - .../rtl/yui/src/button/meta/button.json | 7 - .../strike/classes/privacy/provider.php | 46 - .../plugins/strike/lang/en/atto_strike.php | 26 - .../plugins/strike/tests/behat/strike.feature | 19 - lib/editor/atto/plugins/strike/version.php | 29 - .../moodle-atto_strike-button-debug.js | 72 - .../moodle-atto_strike-button-min.js | 1 - .../moodle-atto_strike-button.js | 72 - .../plugins/strike/yui/src/button/build.json | 10 - .../strike/yui/src/button/js/button.js | 67 - .../strike/yui/src/button/meta/button.json | 7 - .../subscript/classes/privacy/provider.php | 46 - .../subscript/lang/en/atto_subscript.php | 26 - .../subscript/tests/behat/subscript.feature | 35 - lib/editor/atto/plugins/subscript/version.php | 29 - .../moodle-atto_subscript-button-debug.js | 90 - .../moodle-atto_subscript-button-min.js | 1 - .../moodle-atto_subscript-button.js | 90 - .../subscript/yui/src/button/build.json | 10 - .../subscript/yui/src/button/js/button.js | 85 - .../subscript/yui/src/button/meta/button.json | 7 - .../superscript/classes/privacy/provider.php | 46 - .../superscript/lang/en/atto_superscript.php | 26 - .../tests/behat/superscript.feature | 35 - .../atto/plugins/superscript/version.php | 29 - .../moodle-atto_superscript-button-debug.js | 90 - .../moodle-atto_superscript-button-min.js | 1 - .../moodle-atto_superscript-button.js | 90 - .../superscript/yui/src/button/build.json | 10 - .../superscript/yui/src/button/js/button.js | 85 - .../yui/src/button/meta/button.json | 7 - .../table/classes/privacy/provider.php | 46 - .../atto/plugins/table/lang/en/atto_table.php | 66 - lib/editor/atto/plugins/table/lib.php | 85 - lib/editor/atto/plugins/table/settings.php | 58 - lib/editor/atto/plugins/table/styles.css | 29 - .../plugins/table/tests/behat/table.feature | 404 - lib/editor/atto/plugins/table/version.php | 29 - .../moodle-atto_table-button-debug.js | 1557 -- .../moodle-atto_table-button-min.js | 5 - .../moodle-atto_table-button.js | 1557 -- .../plugins/table/yui/src/button/build.json | 10 - .../plugins/table/yui/src/button/js/button.js | 1552 -- .../table/yui/src/button/meta/button.json | 10 - .../title/classes/privacy/provider.php | 46 - .../atto/plugins/title/lang/en/atto_title.php | 32 - lib/editor/atto/plugins/title/lib.php | 36 - .../plugins/title/tests/behat/title.feature | 19 - lib/editor/atto/plugins/title/version.php | 29 - .../moodle-atto_title-button-debug.js | 95 - .../moodle-atto_title-button-min.js | 1 - .../moodle-atto_title-button.js | 95 - .../plugins/title/yui/src/button/build.json | 10 - .../plugins/title/yui/src/button/js/button.js | 90 - .../title/yui/src/button/meta/button.json | 7 - .../underline/classes/privacy/provider.php | 46 - .../underline/lang/en/atto_underline.php | 26 - .../underline/tests/behat/underline.feature | 19 - lib/editor/atto/plugins/underline/version.php | 29 - .../moodle-atto_underline-button-debug.js | 51 - .../moodle-atto_underline-button-min.js | 1 - .../moodle-atto_underline-button.js | 51 - .../underline/yui/src/button/build.json | 10 - .../underline/yui/src/button/js/button.js | 46 - .../underline/yui/src/button/meta/button.json | 7 - .../plugins/undo/classes/privacy/provider.php | 46 - .../atto/plugins/undo/lang/en/atto_undo.php | 28 - lib/editor/atto/plugins/undo/lib.php | 44 - lib/editor/atto/plugins/undo/version.php | 29 - .../moodle-atto_undo-button-debug.js | 306 - .../moodle-atto_undo-button-min.js | 1 - .../moodle-atto_undo-button.js | 306 - .../plugins/undo/yui/src/button/build.json | 10 - .../plugins/undo/yui/src/button/js/button.js | 301 - .../undo/yui/src/button/meta/button.json | 7 - .../classes/privacy/provider.php | 46 - .../lang/en/atto_unorderedlist.php | 26 - .../tests/behat/unorderedlist.feature | 18 - .../atto/plugins/unorderedlist/version.php | 29 - .../moodle-atto_unorderedlist-button-debug.js | 49 - .../moodle-atto_unorderedlist-button-min.js | 1 - .../moodle-atto_unorderedlist-button.js | 49 - .../unorderedlist/yui/src/button/build.json | 10 - .../unorderedlist/yui/src/button/js/button.js | 44 - .../yui/src/button/meta/button.json | 7 - lib/editor/atto/readme_moodle.txt | 22 - lib/editor/atto/settings.php | 67 - lib/editor/atto/tests/behat/autosave.feature | 94 - .../atto/tests/behat/behat_editor_atto.php | 108 - lib/editor/atto/tests/behat/clean.feature | 169 - .../atto/tests/behat/customtoolbar.feature | 26 - lib/editor/atto/tests/behat/direction.feature | 49 - .../atto/tests/behat/disablecontrol.feature | 45 - .../tests/fixtures/custom_toolbar_example.php | 86 - .../atto/tests/fixtures/moodle-logo.mp4 | Bin 6930 -> 0 bytes .../atto/tests/fixtures/moodle-logo.png | Bin 4640 -> 0 bytes .../atto/tests/fixtures/moodle-logo.webm | Bin 5742 -> 0 bytes .../atto/tests/fixtures/pretty-good-en.vtt | 54 - .../atto/tests/fixtures/pretty-good-sv.vtt | 54 - .../atto/tests/privacy/provider_test.php | 655 - lib/editor/atto/thirdpartylibs.xml | 15 - lib/editor/atto/upgrade.txt | 35 - lib/editor/atto/version.php | 29 - .../moodle-editor_atto-editor-debug.js | 3195 ---- .../moodle-editor_atto-editor-min.js | 5 - .../moodle-editor_atto-editor.js | 3170 ---- .../moodle-editor_atto-menu-debug.js | 353 - .../moodle-editor_atto-menu-min.js | 1 - .../moodle-editor_atto-menu.js | 352 - .../moodle-editor_atto-plugin-debug.js | 1248 -- .../moodle-editor_atto-plugin-min.js | 2 - .../moodle-editor_atto-plugin.js | 1244 -- .../moodle-editor_atto-rangy-debug.js | 8087 ---------- .../moodle-editor_atto-rangy-min.js | 16 - .../moodle-editor_atto-rangy.js | 8087 ---------- lib/editor/atto/yui/src/editor/build.json | 33 - .../atto/yui/src/editor/js/autosave-io.js | 245 - lib/editor/atto/yui/src/editor/js/autosave.js | 287 - lib/editor/atto/yui/src/editor/js/clean.js | 656 - lib/editor/atto/yui/src/editor/js/commands.js | 177 - .../src/editor/js/editor-plugin-buttons.js | 975 -- .../src/editor/js/editor-plugin-dialogue.js | 108 - .../atto/yui/src/editor/js/editor-plugin.js | 148 - lib/editor/atto/yui/src/editor/js/editor.js | 535 - .../atto/yui/src/editor/js/filepicker.js | 81 - lib/editor/atto/yui/src/editor/js/menu.js | 348 - lib/editor/atto/yui/src/editor/js/notify.js | 140 - .../atto/yui/src/editor/js/selection.js | 424 - lib/editor/atto/yui/src/editor/js/styling.js | 223 - lib/editor/atto/yui/src/editor/js/textarea.js | 120 - .../yui/src/editor/js/toolbar-keyboardnav.js | 209 - lib/editor/atto/yui/src/editor/js/toolbar.js | 74 - .../atto/yui/src/editor/meta/editor.json | 43 - lib/editor/atto/yui/src/rangy/build.json | 21 - lib/editor/atto/yui/src/rangy/js/init.js | 18 - lib/editor/atto/yui/src/rangy/js/license.txt | 21 - .../yui/src/rangy/js/rangy-classapplier.js | 1092 -- .../atto/yui/src/rangy/js/rangy-core.js | 3888 ----- .../yui/src/rangy/js/rangy-highlighter.js | 611 - .../rangy/js/rangy-selectionsaverestore.js | 244 - .../atto/yui/src/rangy/js/rangy-serializer.js | 306 - .../atto/yui/src/rangy/js/rangy-textrange.js | 1922 --- lib/editor/atto/yui/src/rangy/meta/rangy.json | 5 - .../media/classes/form/manage_files_form.php | 2 +- lib/plugins.json | 70 +- version.php | 2 +- 494 files changed, 65 insertions(+), 147016 deletions(-) create mode 100644 .upgradenotes/MDL-83282-2024112007284289.yml delete mode 100644 lib/editor/atto/adminlib.php delete mode 100644 lib/editor/atto/amd/build/events.min.js delete mode 100644 lib/editor/atto/amd/build/events.min.js.map delete mode 100644 lib/editor/atto/amd/src/events.js delete mode 100644 lib/editor/atto/autosave-ajax.php delete mode 100644 lib/editor/atto/classes/plugininfo/atto.php delete mode 100644 lib/editor/atto/classes/privacy/provider.php delete mode 100644 lib/editor/atto/classes/task/autosave_cleanup_task.php delete mode 100644 lib/editor/atto/db/install.xml delete mode 100644 lib/editor/atto/db/subplugins.json delete mode 100644 lib/editor/atto/db/tasks.php delete mode 100644 lib/editor/atto/db/upgrade.php delete mode 100644 lib/editor/atto/lang/en/editor_atto.php delete mode 100644 lib/editor/atto/lib.php delete mode 100644 lib/editor/atto/pix/logo.png delete mode 100644 lib/editor/atto/pix/logo.svg delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/lang/en/atto_accessibilitychecker.php delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/lib.php delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/styles.css delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/version.php delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/accessibilitychecker/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/lang/en/atto_accessibilityhelper.php delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/lib.php delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/tests/behat/accessibilityhelper.feature delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/version.php delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-debug.js delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-min.js delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button.js delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/accessibilityhelper/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/align/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/align/lang/en/atto_align.php delete mode 100644 lib/editor/atto/plugins/align/lib.php delete mode 100644 lib/editor/atto/plugins/align/tests/behat/align.feature delete mode 100644 lib/editor/atto/plugins/align/version.php delete mode 100644 lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-debug.js delete mode 100644 lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-min.js delete mode 100644 lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button.js delete mode 100644 lib/editor/atto/plugins/align/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/align/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/align/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/backcolor/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/backcolor/lang/en/atto_backcolor.php delete mode 100644 lib/editor/atto/plugins/backcolor/lib.php delete mode 100644 lib/editor/atto/plugins/backcolor/styles.css delete mode 100644 lib/editor/atto/plugins/backcolor/version.php delete mode 100644 lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-debug.js delete mode 100644 lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-min.js delete mode 100644 lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button.js delete mode 100644 lib/editor/atto/plugins/backcolor/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/backcolor/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/backcolor/yui/src/button/meta/editor.js delete mode 100644 lib/editor/atto/plugins/bold/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/bold/lang/en/atto_bold.php delete mode 100644 lib/editor/atto/plugins/bold/tests/behat/bold.feature delete mode 100644 lib/editor/atto/plugins/bold/version.php delete mode 100644 lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-debug.js delete mode 100644 lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-min.js delete mode 100644 lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button.js delete mode 100644 lib/editor/atto/plugins/bold/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/bold/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/bold/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/charmap/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/charmap/lang/en/atto_charmap.php delete mode 100644 lib/editor/atto/plugins/charmap/lib.php delete mode 100644 lib/editor/atto/plugins/charmap/styles.css delete mode 100644 lib/editor/atto/plugins/charmap/tests/behat/charmap.feature delete mode 100644 lib/editor/atto/plugins/charmap/version.php delete mode 100644 lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-debug.js delete mode 100644 lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-min.js delete mode 100644 lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button.js delete mode 100644 lib/editor/atto/plugins/charmap/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/charmap/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/charmap/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/clear/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/clear/lang/en/atto_clear.php delete mode 100644 lib/editor/atto/plugins/clear/tests/behat/clear.feature delete mode 100644 lib/editor/atto/plugins/clear/version.php delete mode 100644 lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-debug.js delete mode 100644 lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-min.js delete mode 100644 lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button.js delete mode 100644 lib/editor/atto/plugins/clear/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/clear/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/clear/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/collapse/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/collapse/lang/en/atto_collapse.php delete mode 100644 lib/editor/atto/plugins/collapse/lib.php delete mode 100644 lib/editor/atto/plugins/collapse/pix/icon.svg delete mode 100644 lib/editor/atto/plugins/collapse/settings.php delete mode 100644 lib/editor/atto/plugins/collapse/styles.css delete mode 100644 lib/editor/atto/plugins/collapse/tests/behat/collapse.feature delete mode 100644 lib/editor/atto/plugins/collapse/version.php delete mode 100644 lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js delete mode 100644 lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js delete mode 100644 lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js delete mode 100644 lib/editor/atto/plugins/collapse/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/collapse/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/collapse/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/emojipicker/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/emojipicker/lang/en/atto_emojipicker.php delete mode 100644 lib/editor/atto/plugins/emojipicker/lib.php delete mode 100644 lib/editor/atto/plugins/emojipicker/styles.css delete mode 100644 lib/editor/atto/plugins/emojipicker/version.php delete mode 100644 lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js delete mode 100644 lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js delete mode 100644 lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js delete mode 100644 lib/editor/atto/plugins/emojipicker/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/emojipicker/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/emoticon/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/emoticon/lang/en/atto_emoticon.php delete mode 100644 lib/editor/atto/plugins/emoticon/lib.php delete mode 100644 lib/editor/atto/plugins/emoticon/styles.css delete mode 100644 lib/editor/atto/plugins/emoticon/version.php delete mode 100644 lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-debug.js delete mode 100644 lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-min.js delete mode 100644 lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button.js delete mode 100644 lib/editor/atto/plugins/emoticon/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/emoticon/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/emoticon/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/equation/ajax.php delete mode 100644 lib/editor/atto/plugins/equation/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/equation/db/upgrade.php delete mode 100644 lib/editor/atto/plugins/equation/lang/en/atto_equation.php delete mode 100644 lib/editor/atto/plugins/equation/lib.php delete mode 100644 lib/editor/atto/plugins/equation/settings.php delete mode 100644 lib/editor/atto/plugins/equation/styles.css delete mode 100644 lib/editor/atto/plugins/equation/tests/behat/equation.feature delete mode 100644 lib/editor/atto/plugins/equation/version.php delete mode 100644 lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js delete mode 100644 lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js delete mode 100644 lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js delete mode 100644 lib/editor/atto/plugins/equation/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/equation/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/equation/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/fontcolor/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/fontcolor/lang/en/atto_fontcolor.php delete mode 100644 lib/editor/atto/plugins/fontcolor/lib.php delete mode 100644 lib/editor/atto/plugins/fontcolor/styles.css delete mode 100644 lib/editor/atto/plugins/fontcolor/version.php delete mode 100644 lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-debug.js delete mode 100644 lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-min.js delete mode 100644 lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button.js delete mode 100644 lib/editor/atto/plugins/fontcolor/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/fontcolor/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/fontcolor/yui/src/button/meta/editor.js delete mode 100644 lib/editor/atto/plugins/h5p/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/h5p/db/access.php delete mode 100644 lib/editor/atto/plugins/h5p/lang/en/atto_h5p.php delete mode 100644 lib/editor/atto/plugins/h5p/lib.php delete mode 100644 lib/editor/atto/plugins/h5p/pix/icon-white.png delete mode 100644 lib/editor/atto/plugins/h5p/pix/icon-white.svg delete mode 100644 lib/editor/atto/plugins/h5p/pix/icon.png delete mode 100644 lib/editor/atto/plugins/h5p/pix/icon.svg delete mode 100644 lib/editor/atto/plugins/h5p/styles.css delete mode 100644 lib/editor/atto/plugins/h5p/tests/behat/h5p.feature delete mode 100644 lib/editor/atto/plugins/h5p/version.php delete mode 100644 lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-debug.js delete mode 100644 lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-min.js delete mode 100644 lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button.js delete mode 100644 lib/editor/atto/plugins/h5p/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/h5p/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/h5p/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/html/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/html/lang/en/atto_html.php delete mode 100644 lib/editor/atto/plugins/html/styles.css delete mode 100644 lib/editor/atto/plugins/html/tests/behat/html.feature delete mode 100644 lib/editor/atto/plugins/html/thirdpartylibs.xml delete mode 100644 lib/editor/atto/plugins/html/version.php delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-min.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-debug.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-min.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-codemirror/assets/moodle-atto_html-codemirror-core.css delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-codemirror/assets/skins/sam/moodle-atto_html-codemirror-skin.css delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-codemirror/assets/skins/sam/moodle-atto_html-codemirror.css delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-codemirror/moodle-atto_html-codemirror-debug.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-codemirror/moodle-atto_html-codemirror-min.js delete mode 100644 lib/editor/atto/plugins/html/yui/build/moodle-atto_html-codemirror/moodle-atto_html-codemirror.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/LICENSE delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/build.json delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-css.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-html.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/js/beautify.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/js/wrapper.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/meta/beautify.json delete mode 100644 lib/editor/atto/plugins/html/yui/src/beautify/readme_moodle.txt delete mode 100644 lib/editor/atto/plugins/html/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/html/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/LICENSE delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/assets/moodle-atto_html-codemirror-core.css delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/assets/skins/sam/moodle-atto_html-codemirror-skin.css delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/build.json delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/codemirror.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/css.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/htmlmixed.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/javascript.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/wrapper-end.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/wrapper-mid.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/wrapper.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/js/xml.js delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/meta/codemirror.json delete mode 100644 lib/editor/atto/plugins/html/yui/src/codemirror/readme_moodle.txt delete mode 100644 lib/editor/atto/plugins/image/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/image/lang/en/atto_image.php delete mode 100644 lib/editor/atto/plugins/image/lib.php delete mode 100644 lib/editor/atto/plugins/image/styles.css delete mode 100644 lib/editor/atto/plugins/image/tests/behat/image.feature delete mode 100644 lib/editor/atto/plugins/image/version.php delete mode 100644 lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js delete mode 100644 lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js delete mode 100644 lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js delete mode 100644 lib/editor/atto/plugins/image/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/image/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/image/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/indent/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/indent/lang/en/atto_indent.php delete mode 100644 lib/editor/atto/plugins/indent/lib.php delete mode 100644 lib/editor/atto/plugins/indent/tests/behat/indent.feature delete mode 100644 lib/editor/atto/plugins/indent/version.php delete mode 100644 lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-debug.js delete mode 100644 lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-min.js delete mode 100644 lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button.js delete mode 100644 lib/editor/atto/plugins/indent/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/indent/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/indent/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/italic/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/italic/lang/en/atto_italic.php delete mode 100644 lib/editor/atto/plugins/italic/tests/behat/italic.feature delete mode 100644 lib/editor/atto/plugins/italic/version.php delete mode 100644 lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-debug.js delete mode 100644 lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-min.js delete mode 100644 lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button.js delete mode 100644 lib/editor/atto/plugins/italic/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/italic/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/italic/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/link/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/link/lang/en/atto_link.php delete mode 100644 lib/editor/atto/plugins/link/lib.php delete mode 100644 lib/editor/atto/plugins/link/tests/behat/link.feature delete mode 100644 lib/editor/atto/plugins/link/version.php delete mode 100644 lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-debug.js delete mode 100644 lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-min.js delete mode 100644 lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button.js delete mode 100644 lib/editor/atto/plugins/link/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/link/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/link/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/managefiles/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/managefiles/lang/en/atto_managefiles.php delete mode 100644 lib/editor/atto/plugins/managefiles/lib.php delete mode 100644 lib/editor/atto/plugins/managefiles/manage.php delete mode 100644 lib/editor/atto/plugins/managefiles/manage_form.php delete mode 100644 lib/editor/atto/plugins/managefiles/styles.css delete mode 100644 lib/editor/atto/plugins/managefiles/version.php delete mode 100644 lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/managefiles/yui/src/usedfiles/build.json delete mode 100644 lib/editor/atto/plugins/managefiles/yui/src/usedfiles/js/usedfiles.js delete mode 100644 lib/editor/atto/plugins/managefiles/yui/src/usedfiles/meta/usedfiles.json delete mode 100644 lib/editor/atto/plugins/media/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/media/lang/en/atto_media.php delete mode 100644 lib/editor/atto/plugins/media/lib.php delete mode 100644 lib/editor/atto/plugins/media/styles.css delete mode 100644 lib/editor/atto/plugins/media/styles_clean.css delete mode 100644 lib/editor/atto/plugins/media/tests/behat/media.feature delete mode 100644 lib/editor/atto/plugins/media/version.php delete mode 100644 lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-debug.js delete mode 100644 lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-min.js delete mode 100644 lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button.js delete mode 100644 lib/editor/atto/plugins/media/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/media/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/media/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/noautolink/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/noautolink/lang/en/atto_noautolink.php delete mode 100644 lib/editor/atto/plugins/noautolink/version.php delete mode 100644 lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-debug.js delete mode 100644 lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-min.js delete mode 100644 lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button.js delete mode 100644 lib/editor/atto/plugins/noautolink/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/noautolink/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/noautolink/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/orderedlist/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/orderedlist/lang/en/atto_orderedlist.php delete mode 100644 lib/editor/atto/plugins/orderedlist/tests/behat/orderedlist.feature delete mode 100644 lib/editor/atto/plugins/orderedlist/version.php delete mode 100644 lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-debug.js delete mode 100644 lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-min.js delete mode 100644 lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button.js delete mode 100644 lib/editor/atto/plugins/orderedlist/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/orderedlist/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/orderedlist/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/recordrtc/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/recordrtc/db/access.php delete mode 100644 lib/editor/atto/plugins/recordrtc/db/upgrade.php delete mode 100644 lib/editor/atto/plugins/recordrtc/lang/en/atto_recordrtc.php delete mode 100644 lib/editor/atto/plugins/recordrtc/lib.php delete mode 100644 lib/editor/atto/plugins/recordrtc/pix/i/audiortc.svg delete mode 100644 lib/editor/atto/plugins/recordrtc/pix/i/videortc.svg delete mode 100644 lib/editor/atto/plugins/recordrtc/pix/icon.png delete mode 100644 lib/editor/atto/plugins/recordrtc/settings.php delete mode 100644 lib/editor/atto/plugins/recordrtc/styles.css delete mode 100644 lib/editor/atto/plugins/recordrtc/version.php delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-debug.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-min.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/build.json delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/js/abstractmodule.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/js/audiomodule.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/js/commonmodule.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/js/compatcheckmodule.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/js/videomodule.js delete mode 100644 lib/editor/atto/plugins/recordrtc/yui/src/recording/meta/recording.json delete mode 100644 lib/editor/atto/plugins/rtl/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/rtl/lang/en/atto_rtl.php delete mode 100644 lib/editor/atto/plugins/rtl/lib.php delete mode 100644 lib/editor/atto/plugins/rtl/version.php delete mode 100644 lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-debug.js delete mode 100644 lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-min.js delete mode 100644 lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button.js delete mode 100644 lib/editor/atto/plugins/rtl/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/rtl/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/rtl/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/strike/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/strike/lang/en/atto_strike.php delete mode 100644 lib/editor/atto/plugins/strike/tests/behat/strike.feature delete mode 100644 lib/editor/atto/plugins/strike/version.php delete mode 100644 lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-debug.js delete mode 100644 lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-min.js delete mode 100644 lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button.js delete mode 100644 lib/editor/atto/plugins/strike/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/strike/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/strike/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/subscript/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/subscript/lang/en/atto_subscript.php delete mode 100644 lib/editor/atto/plugins/subscript/tests/behat/subscript.feature delete mode 100644 lib/editor/atto/plugins/subscript/version.php delete mode 100644 lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-debug.js delete mode 100644 lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-min.js delete mode 100644 lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button.js delete mode 100644 lib/editor/atto/plugins/subscript/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/subscript/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/subscript/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/superscript/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/superscript/lang/en/atto_superscript.php delete mode 100644 lib/editor/atto/plugins/superscript/tests/behat/superscript.feature delete mode 100644 lib/editor/atto/plugins/superscript/version.php delete mode 100644 lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-debug.js delete mode 100644 lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-min.js delete mode 100644 lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button.js delete mode 100644 lib/editor/atto/plugins/superscript/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/superscript/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/superscript/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/table/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/table/lang/en/atto_table.php delete mode 100644 lib/editor/atto/plugins/table/lib.php delete mode 100644 lib/editor/atto/plugins/table/settings.php delete mode 100644 lib/editor/atto/plugins/table/styles.css delete mode 100644 lib/editor/atto/plugins/table/tests/behat/table.feature delete mode 100644 lib/editor/atto/plugins/table/version.php delete mode 100644 lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-debug.js delete mode 100644 lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-min.js delete mode 100644 lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button.js delete mode 100644 lib/editor/atto/plugins/table/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/table/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/table/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/title/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/title/lang/en/atto_title.php delete mode 100644 lib/editor/atto/plugins/title/lib.php delete mode 100644 lib/editor/atto/plugins/title/tests/behat/title.feature delete mode 100644 lib/editor/atto/plugins/title/version.php delete mode 100644 lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-debug.js delete mode 100644 lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-min.js delete mode 100644 lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button.js delete mode 100644 lib/editor/atto/plugins/title/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/title/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/title/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/underline/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/underline/lang/en/atto_underline.php delete mode 100644 lib/editor/atto/plugins/underline/tests/behat/underline.feature delete mode 100644 lib/editor/atto/plugins/underline/version.php delete mode 100644 lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-debug.js delete mode 100644 lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-min.js delete mode 100644 lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button.js delete mode 100644 lib/editor/atto/plugins/underline/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/underline/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/underline/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/undo/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/undo/lang/en/atto_undo.php delete mode 100644 lib/editor/atto/plugins/undo/lib.php delete mode 100644 lib/editor/atto/plugins/undo/version.php delete mode 100644 lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js delete mode 100644 lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js delete mode 100644 lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button.js delete mode 100644 lib/editor/atto/plugins/undo/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/undo/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/undo/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/plugins/unorderedlist/classes/privacy/provider.php delete mode 100644 lib/editor/atto/plugins/unorderedlist/lang/en/atto_unorderedlist.php delete mode 100644 lib/editor/atto/plugins/unorderedlist/tests/behat/unorderedlist.feature delete mode 100644 lib/editor/atto/plugins/unorderedlist/version.php delete mode 100644 lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-debug.js delete mode 100644 lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-min.js delete mode 100644 lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button.js delete mode 100644 lib/editor/atto/plugins/unorderedlist/yui/src/button/build.json delete mode 100644 lib/editor/atto/plugins/unorderedlist/yui/src/button/js/button.js delete mode 100644 lib/editor/atto/plugins/unorderedlist/yui/src/button/meta/button.json delete mode 100644 lib/editor/atto/readme_moodle.txt delete mode 100644 lib/editor/atto/settings.php delete mode 100644 lib/editor/atto/tests/behat/autosave.feature delete mode 100644 lib/editor/atto/tests/behat/behat_editor_atto.php delete mode 100644 lib/editor/atto/tests/behat/clean.feature delete mode 100644 lib/editor/atto/tests/behat/customtoolbar.feature delete mode 100644 lib/editor/atto/tests/behat/direction.feature delete mode 100644 lib/editor/atto/tests/behat/disablecontrol.feature delete mode 100644 lib/editor/atto/tests/fixtures/custom_toolbar_example.php delete mode 100644 lib/editor/atto/tests/fixtures/moodle-logo.mp4 delete mode 100644 lib/editor/atto/tests/fixtures/moodle-logo.png delete mode 100644 lib/editor/atto/tests/fixtures/moodle-logo.webm delete mode 100644 lib/editor/atto/tests/fixtures/pretty-good-en.vtt delete mode 100644 lib/editor/atto/tests/fixtures/pretty-good-sv.vtt delete mode 100644 lib/editor/atto/tests/privacy/provider_test.php delete mode 100644 lib/editor/atto/thirdpartylibs.xml delete mode 100644 lib/editor/atto/upgrade.txt delete mode 100644 lib/editor/atto/version.php delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-menu/moodle-editor_atto-menu-debug.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-menu/moodle-editor_atto-menu-min.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-menu/moodle-editor_atto-menu.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-debug.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-min.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-rangy/moodle-editor_atto-rangy-debug.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-rangy/moodle-editor_atto-rangy-min.js delete mode 100644 lib/editor/atto/yui/build/moodle-editor_atto-rangy/moodle-editor_atto-rangy.js delete mode 100644 lib/editor/atto/yui/src/editor/build.json delete mode 100644 lib/editor/atto/yui/src/editor/js/autosave-io.js delete mode 100644 lib/editor/atto/yui/src/editor/js/autosave.js delete mode 100644 lib/editor/atto/yui/src/editor/js/clean.js delete mode 100644 lib/editor/atto/yui/src/editor/js/commands.js delete mode 100644 lib/editor/atto/yui/src/editor/js/editor-plugin-buttons.js delete mode 100644 lib/editor/atto/yui/src/editor/js/editor-plugin-dialogue.js delete mode 100644 lib/editor/atto/yui/src/editor/js/editor-plugin.js delete mode 100644 lib/editor/atto/yui/src/editor/js/editor.js delete mode 100644 lib/editor/atto/yui/src/editor/js/filepicker.js delete mode 100644 lib/editor/atto/yui/src/editor/js/menu.js delete mode 100644 lib/editor/atto/yui/src/editor/js/notify.js delete mode 100644 lib/editor/atto/yui/src/editor/js/selection.js delete mode 100644 lib/editor/atto/yui/src/editor/js/styling.js delete mode 100644 lib/editor/atto/yui/src/editor/js/textarea.js delete mode 100644 lib/editor/atto/yui/src/editor/js/toolbar-keyboardnav.js delete mode 100644 lib/editor/atto/yui/src/editor/js/toolbar.js delete mode 100644 lib/editor/atto/yui/src/editor/meta/editor.json delete mode 100644 lib/editor/atto/yui/src/rangy/build.json delete mode 100644 lib/editor/atto/yui/src/rangy/js/init.js delete mode 100644 lib/editor/atto/yui/src/rangy/js/license.txt delete mode 100644 lib/editor/atto/yui/src/rangy/js/rangy-classapplier.js delete mode 100644 lib/editor/atto/yui/src/rangy/js/rangy-core.js delete mode 100644 lib/editor/atto/yui/src/rangy/js/rangy-highlighter.js delete mode 100644 lib/editor/atto/yui/src/rangy/js/rangy-selectionsaverestore.js delete mode 100644 lib/editor/atto/yui/src/rangy/js/rangy-serializer.js delete mode 100644 lib/editor/atto/yui/src/rangy/js/rangy-textrange.js delete mode 100644 lib/editor/atto/yui/src/rangy/meta/rangy.json diff --git a/.upgradenotes/MDL-83282-2024112007284289.yml b/.upgradenotes/MDL-83282-2024112007284289.yml new file mode 100644 index 00000000000..48da570c876 --- /dev/null +++ b/.upgradenotes/MDL-83282-2024112007284289.yml @@ -0,0 +1,9 @@ +issueNumber: MDL-83282 +notes: + core: + - message: | + The Atto HTML editor has been removed from core, along with all standard + subplugins. + + The editor is available for continued use in the Plugins Database. + type: removed diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 1a0cf7a874a..c7cc390b55e 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -1464,5 +1464,24 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2025022100.02); } + if ($oldversion < 2025030500.00) { + // If atto is no longer present, remove it. + if (!file_exists("{$CFG->dirroot}/lib/editor/atto/version.php")) { + // Remove each of the subplugins first. These are no longer on disk so the standard `uninstall_plugin` approach + // on atto itself will not remove them. + $plugins = array_keys(core_plugin_manager::instance()->get_plugins_of_type('atto')); + + // Now remove each. + foreach ($plugins as $pluginname) { + uninstall_plugin('atto', $pluginname); + } + + // Finally uninstall the actual plugin. + uninstall_plugin('editor', 'atto'); + } + + upgrade_main_savepoint(true, 2025030500.00); + } + return true; } diff --git a/lib/editor/atto/adminlib.php b/lib/editor/atto/adminlib.php deleted file mode 100644 index a1b9bd7e1d8..00000000000 --- a/lib/editor/atto/adminlib.php +++ /dev/null @@ -1,252 +0,0 @@ -. - -/** - * Atto admin setting stuff. - * - * @package editor_atto - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Admin setting for toolbar. - * - * @package editor_atto - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class editor_atto_toolbar_setting extends admin_setting_configtextarea { - - /** - * Validate data. - * - * This ensures that: - * - Plugins are only used once, - * - Group names are unique, - * - Lines match: group = plugin[, plugin[, plugin ...]], - * - There are some groups and plugins defined, - * - The plugins used are installed. - * - * @param string $data - * @return mixed True on success, else error message. - */ - public function validate($data) { - $result = parent::validate($data); - if ($result !== true) { - return $result; - } - - $lines = explode("\n", $data); - $groups = array(); - $plugins = array(); - - foreach ($lines as $line) { - if (!trim($line)) { - continue; - } - - $matches = array(); - if (!preg_match('/^\s*([a-z0-9]+)\s*=\s*([a-z0-9]+(\s*,\s*[a-z0-9]+)*)+\s*$/', $line, $matches)) { - $result = get_string('errorcannotparseline', 'editor_atto', $line); - break; - } - - $group = $matches[1]; - if (isset($groups[$group])) { - $result = get_string('errorgroupisusedtwice', 'editor_atto', $group); - break; - } - $groups[$group] = true; - - $lineplugins = array_map('trim', explode(',', $matches[2])); - foreach ($lineplugins as $plugin) { - if (isset($plugins[$plugin])) { - $result = get_string('errorpluginisusedtwice', 'editor_atto', $plugin); - break 2; - } else if (!core_component::get_component_directory('atto_' . $plugin)) { - $result = get_string('errorpluginnotfound', 'editor_atto', $plugin); - break 2; - } - $plugins[$plugin] = true; - } - } - - // We did not find any groups or plugins. - if (empty($groups) || empty($plugins)) { - $result = get_string('errornopluginsorgroupsfound', 'editor_atto'); - } - - return $result; - } - -} - -/** - * Special class for Atto plugins administration. - * - * @package editor_atto - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class editor_atto_subplugins_setting extends admin_setting { - - /** - * Constructor. - */ - public function __construct() { - $this->nosave = true; - parent::__construct('attosubplugins', get_string('subplugintype_atto_plural', 'editor_atto'), '', ''); - } - - /** - * Returns current value of this setting. - * Always returns true, does nothing. - * - * @return true - */ - public function get_setting() { - return true; - } - - /** - * Returns default setting if exists. - * Always returns true, does nothing. - * - * @return true - */ - public function get_defaultsetting() { - return true; - } - - /** - * Store new setting. - * Always returns '', does not write anything. - * - * @param string $data string or array, must not be NULL. - * @return string Always returns ''. - */ - public function write_setting($data) { - // Do not write any setting. - return ''; - } - - /** - * Checks if $query is one of the available subplugins. - * - * @param string $query The string to search for. - * @return bool Returns true if found, false if not. - */ - public function is_related($query) { - if (parent::is_related($query)) { - return true; - } - - $subplugins = core_component::get_plugin_list('atto'); - foreach ($subplugins as $name => $dir) { - if (stripos($name, $query) !== false) { - return true; - } - - $namestr = get_string('pluginname', 'atto_' . $name); - if (strpos(core_text::strtolower($namestr), core_text::strtolower($query)) !== false) { - return true; - } - } - return false; - } - - /** - * Builds the XHTML to display the control. - * - * @param mixed $data Unused. - * @param string $query - * @return string highlight. - */ - public function output_html($data, $query = '') { - global $CFG, $OUTPUT, $PAGE; - require_once($CFG->libdir . "/editorlib.php"); - require_once(__DIR__ . '/lib.php'); - $pluginmanager = core_plugin_manager::instance(); - - // Display strings. - $strtoolbarconfig = get_string('toolbarconfig', 'editor_atto'); - $strname = get_string('name'); - $strsettings = get_string('settings'); - $struninstall = get_string('uninstallplugin', 'core_admin'); - $strversion = get_string('version'); - - $subplugins = core_component::get_plugin_list('atto'); - - $return = $OUTPUT->heading(get_string('subplugintype_atto_plural', 'editor_atto'), 3, 'main', true); - $return .= $OUTPUT->box_start('generalbox attosubplugins'); - - $table = new html_table(); - $table->head = array($strname, $strversion, $strtoolbarconfig, $strsettings, $struninstall); - $table->align = array('left', 'left', 'center', 'center', 'center', 'center'); - $table->data = array(); - $table->attributes['class'] = 'admintable generaltable'; - - // Iterate through subplugins. - foreach ($subplugins as $name => $dir) { - $namestr = get_string('pluginname', 'atto_' . $name); - $version = get_config('atto_' . $name, 'version'); - if ($version === false) { - $version = ''; - } - $plugininfo = $pluginmanager->get_plugin_info('atto_' . $name); - - $toolbarconfig = $name; - - $displayname = $namestr; - - // Check if there is an icon in the atto plugin pix/ folder. - if ($PAGE->theme->resolve_image_location('icon', 'atto_' . $name, false)) { - $icon = $OUTPUT->pix_icon('icon', '', 'atto_' . $name, array('class' => 'icon pluginicon')); - } else { - // No icon found. - $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon')); - } - $displayname = $icon . $displayname; - - // Add settings link. - if (!$version) { - $settings = ''; - } else if ($url = $plugininfo->get_settings_url()) { - $settings = html_writer::link($url, $strsettings); - } else { - $settings = ''; - } - - // Add uninstall info. - $uninstall = ''; - if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('atto_' . $name, 'manage')) { - $uninstall = html_writer::link($uninstallurl, $struninstall); - } - - // Add a row to the table. - $row = new html_table_row(array($displayname, $version, $toolbarconfig, $settings, $uninstall)); - $table->data[] = $row; - } - $return .= html_writer::table($table); - $return .= html_writer::tag('p', get_string('tablenosave', 'admin')); - $return .= $OUTPUT->box_end(); - return highlight($query, $return); - } -} - diff --git a/lib/editor/atto/amd/build/events.min.js b/lib/editor/atto/amd/build/events.min.js deleted file mode 100644 index 29aadad4b24..00000000000 --- a/lib/editor/atto/amd/build/events.min.js +++ /dev/null @@ -1,12 +0,0 @@ -define("editor_atto/events",["exports","core/event_dispatcher"],(function(_exports,_event_dispatcher){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.notifyButtonHighlightToggled=_exports.eventTypes=void 0; -/** - * Javascript events for the `editor_atto` plugin. - * - * @module editor_atto/events - * @copyright 2021 Jun Pataleta - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 3.10.5 - */ -const eventTypes={attoButtonHighlightToggled:"editor_atto/attoButtonHighlightToggled"};_exports.eventTypes=eventTypes;_exports.notifyButtonHighlightToggled=(attoButton,buttonName,highlight)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.attoButtonHighlightToggled,{buttonName:buttonName,highlight:highlight},attoButton)})); - -//# sourceMappingURL=events.min.js.map \ No newline at end of file diff --git a/lib/editor/atto/amd/build/events.min.js.map b/lib/editor/atto/amd/build/events.min.js.map deleted file mode 100644 index 3b60ecc4f52..00000000000 --- a/lib/editor/atto/amd/build/events.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"events.min.js","sources":["../src/events.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/ //\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 .\n\n/**\n * Javascript events for the `editor_atto` plugin.\n *\n * @module editor_atto/events\n * @copyright 2021 Jun Pataleta \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.10.5\n */\n\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Events for the `editor_atto` plugin.\n *\n * @constant\n * @property {String} attoButtonHighlightToggled See {@link event:attoButtonHighlightToggled}\n */\nexport const eventTypes = {\n /**\n * An event triggered when a toolbar button's highlight gets toggled.\n *\n * @event attoButtonHighlightToggled\n * @type {CustomEvent}\n * @property {HTMLElement} target The button which had its highlight toggled.\n * @property {object} detail\n * @property {String} detail.buttonName The name of the Atto button that has had its highlight toggled.\n * @property {Boolean} detail.highlight True when the button was highlighted. False, otherwise.\n */\n attoButtonHighlightToggled: 'editor_atto/attoButtonHighlightToggled',\n};\n\n/**\n * Trigger an event to indicate that a button's highlight was toggled.\n *\n * @method notifyButtonHighlightToggled\n * @returns {CustomEvent}\n * @fires attoButtonHighlightToggled\n * @param {HTMLElement} attoButton The button object.\n * @param {String} buttonName The button name.\n * @param {Boolean} highlight True when the button was highlighted. False, otherwise.\n */\nexport const notifyButtonHighlightToggled = (attoButton, buttonName, highlight) => {\n return dispatchEvent(\n eventTypes.attoButtonHighlightToggled,\n {\n buttonName,\n highlight,\n },\n attoButton\n );\n};\n"],"names":["eventTypes","attoButtonHighlightToggled","attoButton","buttonName","highlight"],"mappings":";;;;;;;;;MA+BaA,WAAa,CAWtBC,2BAA4B,+GAaY,CAACC,WAAYC,WAAYC,aAC1D,mCACHJ,WAAWC,2BACX,CACIE,WAAAA,WACAC,UAAAA,WAEJF"} \ No newline at end of file diff --git a/lib/editor/atto/amd/src/events.js b/lib/editor/atto/amd/src/events.js deleted file mode 100644 index 05ca6045c22..00000000000 --- a/lib/editor/atto/amd/src/events.js +++ /dev/null @@ -1,65 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ // -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * Javascript events for the `editor_atto` plugin. - * - * @module editor_atto/events - * @copyright 2021 Jun Pataleta - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 3.10.5 - */ - -import {dispatchEvent} from 'core/event_dispatcher'; - -/** - * Events for the `editor_atto` plugin. - * - * @constant - * @property {String} attoButtonHighlightToggled See {@link event:attoButtonHighlightToggled} - */ -export const eventTypes = { - /** - * An event triggered when a toolbar button's highlight gets toggled. - * - * @event attoButtonHighlightToggled - * @type {CustomEvent} - * @property {HTMLElement} target The button which had its highlight toggled. - * @property {object} detail - * @property {String} detail.buttonName The name of the Atto button that has had its highlight toggled. - * @property {Boolean} detail.highlight True when the button was highlighted. False, otherwise. - */ - attoButtonHighlightToggled: 'editor_atto/attoButtonHighlightToggled', -}; - -/** - * Trigger an event to indicate that a button's highlight was toggled. - * - * @method notifyButtonHighlightToggled - * @returns {CustomEvent} - * @fires attoButtonHighlightToggled - * @param {HTMLElement} attoButton The button object. - * @param {String} buttonName The button name. - * @param {Boolean} highlight True when the button was highlighted. False, otherwise. - */ -export const notifyButtonHighlightToggled = (attoButton, buttonName, highlight) => { - return dispatchEvent( - eventTypes.attoButtonHighlightToggled, - { - buttonName, - highlight, - }, - attoButton - ); -}; diff --git a/lib/editor/atto/autosave-ajax.php b/lib/editor/atto/autosave-ajax.php deleted file mode 100644 index 28c13c35ee9..00000000000 --- a/lib/editor/atto/autosave-ajax.php +++ /dev/null @@ -1,221 +0,0 @@ -. - -/** - * Save and load draft text while a user is still editing a form. - * - * @package editor_atto - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -define('AJAX_SCRIPT', true); - -require_once(__DIR__ . '/../../../config.php'); -require_once($CFG->libdir . '/filestorage/file_storage.php'); - -// Clean up actions. -$actions = array_map(function($actionparams) { - $action = isset($actionparams['action']) ? $actionparams['action'] : null; - $params = []; - $keys = [ - 'action' => PARAM_ALPHA, - 'contextid' => PARAM_INT, - 'elementid' => PARAM_ALPHANUMEXT, - 'pagehash' => PARAM_ALPHANUMEXT, - 'pageinstance' => PARAM_ALPHANUMEXT - ]; - - if ($action == 'save') { - $keys['drafttext'] = PARAM_RAW; - } else if ($action == 'resume') { - $keys['draftid'] = PARAM_INT; - } - - foreach ($keys as $key => $type) { - // Replicate required_param(). - if (!isset($actionparams[$key])) { - throw new \moodle_exception('missingparam', '', '', $key); - } - $params[$key] = clean_param($actionparams[$key], $type); - } - - return $params; -}, isset($_REQUEST['actions']) ? $_REQUEST['actions'] : []); - -$now = time(); -// This is the oldest time any autosave text will be recovered from. -// This is so that there is a good chance the draft files will still exist (there are many variables so -// this is impossible to guarantee). -$before = $now - 60*60*24*4; - -$context = context_system::instance(); -$PAGE->set_url('/lib/editor/atto/autosave-ajax.php'); -$PAGE->set_context($context); - -require_login(); -if (isguestuser()) { - throw new \moodle_exception('accessdenied', 'admin'); -} -require_sesskey(); - -if (!in_array('atto', explode(',', get_config('core', 'texteditors')))) { - throw new \moodle_exception('accessdenied', 'admin'); -} - -$responses = array(); -foreach ($actions as $actionparams) { - - $action = $actionparams['action']; - $contextid = $actionparams['contextid']; - $elementid = $actionparams['elementid']; - $pagehash = $actionparams['pagehash']; - $pageinstance = $actionparams['pageinstance']; - - if ($action === 'save') { - $drafttext = $actionparams['drafttext']; - $params = array('elementid' => $elementid, - 'userid' => $USER->id, - 'pagehash' => $pagehash, - 'contextid' => $contextid); - - $record = $DB->get_record('editor_atto_autosave', $params); - if ($record && $record->pageinstance != $pageinstance) { - throw new \moodle_exception('concurrent access from the same user is not supported'); - die(); - } - - if (!$record) { - $record = new stdClass(); - $record->elementid = $elementid; - $record->userid = $USER->id; - $record->pagehash = $pagehash; - $record->contextid = $contextid; - $record->drafttext = $drafttext; - $record->pageinstance = $pageinstance; - $record->timemodified = $now; - - $DB->insert_record('editor_atto_autosave', $record); - - // No response means no error. - $responses[] = null; - continue; - } else { - $record->drafttext = $drafttext; - $record->timemodified = time(); - $DB->update_record('editor_atto_autosave', $record); - - // No response means no error. - $responses[] = null; - continue; - } - - } else if ($action == 'resume') { - $params = array('elementid' => $elementid, - 'userid' => $USER->id, - 'pagehash' => $pagehash, - 'contextid' => $contextid); - - $newdraftid = $actionparams['draftid']; - - $record = $DB->get_record('editor_atto_autosave', $params); - - if (!$record) { - $record = new stdClass(); - $record->elementid = $elementid; - $record->userid = $USER->id; - $record->pagehash = $pagehash; - $record->contextid = $contextid; - $record->pageinstance = $pageinstance; - $record->pagehash = $pagehash; - $record->draftid = $newdraftid; - $record->timemodified = time(); - $record->drafttext = ''; - - $DB->insert_record('editor_atto_autosave', $record); - - // No response means no error. - $responses[] = null; - continue; - - } else { - // Copy all draft files from the old draft area. - $usercontext = context_user::instance($USER->id); - $stale = $record->timemodified < $before; - require_once($CFG->libdir . '/filelib.php'); - - $fs = get_file_storage(); - $files = $fs->get_directory_files($usercontext->id, 'user', 'draft', $newdraftid, '/', true, true); - - $lastfilemodified = 0; - foreach ($files as $file) { - $lastfilemodified = max($lastfilemodified, $file->get_timemodified()); - } - if ($record->timemodified < $lastfilemodified) { - $stale = true; - } - - if (!$stale) { - // This function copies all the files in one draft area, to another area (in this case it's - // another draft area). It also rewrites the text to @@PLUGINFILE@@ links. - $newdrafttext = file_save_draft_area_files($record->draftid, - $usercontext->id, - 'user', - 'draft', - $newdraftid, - array(), - $record->drafttext); - - // Final rewrite to the new draft area (convert the @@PLUGINFILES@@ again). - $newdrafttext = file_rewrite_pluginfile_urls($newdrafttext, - 'draftfile.php', - $usercontext->id, - 'user', - 'draft', - $newdraftid); - $record->drafttext = $newdrafttext; - - $record->pageinstance = $pageinstance; - $record->draftid = $newdraftid; - $record->timemodified = time(); - $DB->update_record('editor_atto_autosave', $record); - - // A response means the draft has been restored and here is the auto-saved text. - $response = ['result' => $record->drafttext]; - $responses[] = $response; - - } else { - $DB->delete_records('editor_atto_autosave', array('id' => $record->id)); - - // No response means no error. - $responses[] = null; - } - continue; - } - - } else if ($action == 'reset') { - $params = array('elementid' => $elementid, - 'userid' => $USER->id, - 'pagehash' => $pagehash, - 'contextid' => $contextid); - - $DB->delete_records('editor_atto_autosave', $params); - $responses[] = null; - continue; - } -} - -echo json_encode($responses); diff --git a/lib/editor/atto/classes/plugininfo/atto.php b/lib/editor/atto/classes/plugininfo/atto.php deleted file mode 100644 index 11099e479ca..00000000000 --- a/lib/editor/atto/classes/plugininfo/atto.php +++ /dev/null @@ -1,87 +0,0 @@ -. - -/** - * Subplugin info class. - * - * @package editor_atto - * @copyright 2013 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace editor_atto\plugininfo; - -use core\plugininfo\base; - -defined('MOODLE_INTERNAL') || die(); - - -class atto extends base { - - /** - * Yes you can uninstall these plugins if you want. - * @return \moodle_url - */ - public function is_uninstall_allowed() { - return true; - } - - /** - * Return URL used for management of plugins of this type. - * @return \moodle_url - */ - public static function get_manage_url() { - return new \moodle_url('/admin/settings.php', array('section'=>'editorsettingsatto')); - } - - /** - * Include the settings.php file from sub plugins if they provide it. - * This is a copy of very similar implementations from various other subplugin areas. - * - * @return \moodle_url - */ - public function load_settings(\part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) { - global $CFG, $USER, $DB, $OUTPUT, $PAGE; // In case settings.php wants to refer to them. - /** @var \admin_root $ADMIN */ - $ADMIN = $adminroot; // May be used in settings.php. - $plugininfo = $this; // Also can be used inside settings.php. - - if (!$this->is_installed_and_upgraded()) { - return; - } - - if (!$hassiteconfig or !file_exists($this->full_path('settings.php'))) { - return; - } - - $section = $this->get_settings_section_name(); - $settings = new \admin_settingpage($section, $this->displayname, 'moodle/site:config', $this->is_enabled() === false); - include($this->full_path('settings.php')); // This may also set $settings to null. - - if ($settings) { - $ADMIN->add($parentnodename, $settings); - } - } - - /** - * Get the settings section name. - * It's used to get the setting links in the Atto sub-plugins table. - * - * @return null|string the settings section name. - */ - public function get_settings_section_name() { - return 'atto_' . $this->name . '_settings'; - } -} diff --git a/lib/editor/atto/classes/privacy/provider.php b/lib/editor/atto/classes/privacy/provider.php deleted file mode 100644 index f00f72aeedf..00000000000 --- a/lib/editor/atto/classes/privacy/provider.php +++ /dev/null @@ -1,244 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for editor_atto. - * - * @package editor_atto - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace editor_atto\privacy; - -defined('MOODLE_INTERNAL') || die(); - -use \core_privacy\local\request\approved_contextlist; -use \core_privacy\local\request\writer; -use \core_privacy\local\request\helper; -use \core_privacy\local\request\deletion_criteria; -use \core_privacy\local\metadata\collection; -use \core_privacy\local\request\userlist; -use \core_privacy\local\request\approved_userlist; - -/** - * Privacy Subsystem implementation for editor_atto. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements - // The Atto editor stores user provided data. - \core_privacy\local\metadata\provider, - // The Atto editor provides data directly to core. - \core_privacy\local\request\plugin\provider, - // The Atto editor is capable of determining which users have data within it. - \core_privacy\local\request\core_userlist_provider { - - /** - * Returns information about how editor_atto stores its data. - * - * @param collection $collection The initialised collection to add items to. - * @return collection A listing of user data stored through this system. - */ - public static function get_metadata(collection $collection): collection { - // There isn't much point giving details about the pageid, etc. - $collection->add_database_table('editor_atto_autosave', [ - 'userid' => 'privacy:metadata:database:atto_autosave:userid', - 'drafttext' => 'privacy:metadata:database:atto_autosave:drafttext', - 'timemodified' => 'privacy:metadata:database:atto_autosave:timemodified', - ], 'privacy:metadata:database:atto_autosave'); - - return $collection; - } - - /** - * Get the list of contexts that contain user information for the specified user. - * - * @param int $userid The user to search. - * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin. - */ - public static function get_contexts_for_userid(int $userid): \core_privacy\local\request\contextlist { - // This block doesn't know who information is stored against unless it - // is at the user context. - $contextlist = new \core_privacy\local\request\contextlist(); - - $sql = "SELECT - c.id - FROM {editor_atto_autosave} eas - JOIN {context} c ON c.id = eas.contextid - WHERE contextlevel = :contextuser AND c.instanceid = :userid"; - $contextlist->add_from_sql($sql, ['contextuser' => CONTEXT_USER, 'userid' => $userid]); - - $sql = "SELECT contextid FROM {editor_atto_autosave} WHERE userid = :userid"; - $contextlist->add_from_sql($sql, ['userid' => $userid]); - - return $contextlist; - } - - /** - * Get the list of users within a specific context. - * - * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. - */ - public static function get_users_in_context(userlist $userlist) { - $context = $userlist->get_context(); - - $params = [ - 'contextid' => $context->id - ]; - - $sql = "SELECT userid - FROM {editor_atto_autosave} - WHERE contextid = :contextid"; - - $userlist->add_from_sql('userid', $sql, $params); - } - - /** - * Export all user data for the specified user, in the specified contexts. - * - * @param approved_contextlist $contextlist The approved contexts to export information for. - */ - public static function export_user_data(approved_contextlist $contextlist) { - global $DB; - - $user = $contextlist->get_user(); - - // Firstly export all autosave records from all contexts in the list owned by the given user. - - list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED); - $contextparams['userid'] = $user->id; - - $sql = "SELECT * - FROM {editor_atto_autosave} - WHERE userid = :userid AND contextid {$contextsql}"; - - $autosaves = $DB->get_recordset_sql($sql, $contextparams); - self::export_autosaves($user, $autosaves); - - // Additionally export all eventual records in the given user's context regardless the actual owner. - // We still consider them to be the user's personal data even when edited by someone else. - - list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED); - $contextparams['userid'] = $user->id; - $contextparams['contextuser'] = CONTEXT_USER; - - $sql = "SELECT eas.* - FROM {editor_atto_autosave} eas - JOIN {context} c ON c.id = eas.contextid - WHERE c.id {$contextsql} AND c.contextlevel = :contextuser AND c.instanceid = :userid"; - - $autosaves = $DB->get_recordset_sql($sql, $contextparams); - self::export_autosaves($user, $autosaves); - } - - /** - * Export all autosave records in the recordset, and close the recordset when finished. - * - * @param \stdClass $user The user whose data is to be exported - * @param \moodle_recordset $autosaves The recordset containing the data to export - */ - protected static function export_autosaves(\stdClass $user, \moodle_recordset $autosaves) { - foreach ($autosaves as $autosave) { - $context = \context::instance_by_id($autosave->contextid); - $subcontext = [ - get_string('autosaves', 'editor_atto'), - $autosave->id, - ]; - - $html = writer::with_context($context) - ->rewrite_pluginfile_urls($subcontext, 'user', 'draft', $autosave->draftid, $autosave->drafttext); - - $data = (object) [ - 'drafttext' => format_text($html, FORMAT_HTML, static::get_filter_options()), - 'timemodified' => \core_privacy\local\request\transform::datetime($autosave->timemodified), - ]; - - if ($autosave->userid != $user->id) { - $data->author = \core_privacy\local\request\transform::user($autosave->userid); - } - - writer::with_context($context) - ->export_data($subcontext, $data) - ->export_area_files($subcontext, 'user', 'draft', $autosave->draftid); - } - $autosaves->close(); - } - - /** - * Delete all data for all users in the specified context. - * - * @param \context $context The specific context to delete data for. - */ - public static function delete_data_for_all_users_in_context(\context $context) { - global $DB; - - $DB->delete_records('editor_atto_autosave', [ - 'contextid' => $context->id, - ]); - } - - /** - * Delete multiple users within a single context. - * - * @param approved_userlist $userlist The approved context and user information to delete information for. - */ - public static function delete_data_for_users(approved_userlist $userlist) { - global $DB; - - $context = $userlist->get_context(); - $userids = $userlist->get_userids(); - - list($useridsql, $useridsqlparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); - $params = ['contextid' => $context->id] + $useridsqlparams; - - $DB->delete_records_select('editor_atto_autosave', "contextid = :contextid AND userid {$useridsql}", - $params); - } - - /** - * Delete all user data for the specified user, in the specified contexts. - * - * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. - */ - public static function delete_data_for_user(approved_contextlist $contextlist) { - global $DB; - - $user = $contextlist->get_user(); - - list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED); - $contextparams['userid'] = $user->id; - - $sql = "SELECT * FROM {editor_atto_autosave} WHERE contextid {$contextsql}"; - $autosaves = $DB->delete_records_select('editor_atto_autosave', "userid = :userid AND contextid {$contextsql}", - $contextparams); - } - - /** - * Get the filter options. - * - * This is shared to allow unit testing too. - * - * @return \stdClass - */ - public static function get_filter_options() { - return (object) [ - 'overflowdiv' => true, - 'noclean' => true, - ]; - } -} diff --git a/lib/editor/atto/classes/task/autosave_cleanup_task.php b/lib/editor/atto/classes/task/autosave_cleanup_task.php deleted file mode 100644 index f7ab9181901..00000000000 --- a/lib/editor/atto/classes/task/autosave_cleanup_task.php +++ /dev/null @@ -1,58 +0,0 @@ -. - -/** - * A scheduled task. - * - * @package editor_atto - * @copyright 2015 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace editor_atto\task; - -use \core\task\scheduled_task; - -/** - * Simple task to run the autosave cleanup task. - */ -class autosave_cleanup_task extends scheduled_task { - - /** - * Get a descriptive name for this task (shown to admins). - * - * @return string - */ - public function get_name() { - return get_string('taskautosavecleanup', 'editor_atto'); - } - - /** - * Do the job. - * Throw exceptions on errors (the job will be retried). - */ - public function execute() { - global $DB; - - $now = time(); - // This is the oldest time any autosave text will be recovered from. - // This is so that there is a good chance the draft files will still exist (there are many variables so - // this is impossible to guarantee). - $before = $now - 60*60*24*4; - - $DB->delete_records_select('editor_atto_autosave', 'timemodified < :before', array('before' => $before)); - } - -} diff --git a/lib/editor/atto/db/install.xml b/lib/editor/atto/db/install.xml deleted file mode 100644 index f13c52c16be..00000000000 --- a/lib/editor/atto/db/install.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
-
-
diff --git a/lib/editor/atto/db/subplugins.json b/lib/editor/atto/db/subplugins.json deleted file mode 100644 index 2f64fc77f3e..00000000000 --- a/lib/editor/atto/db/subplugins.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "subplugintypes": { - "atto": "plugins" - }, - "plugintypes": { - "atto": "lib/editor/atto/plugins" - } -} diff --git a/lib/editor/atto/db/tasks.php b/lib/editor/atto/db/tasks.php deleted file mode 100644 index 9aba0ee6801..00000000000 --- a/lib/editor/atto/db/tasks.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Definition of core scheduled tasks. - * - * The handlers defined on this file are processed and registered into - * the Moodle DB after any install or upgrade operation. All plugins - * support this. - * - * @package core - * @category task - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/* List of handlers */ - -$tasks = array( - array( - 'classname' => 'editor_atto\task\autosave_cleanup_task', - 'blocking' => 0, - 'minute' => 'R', - 'hour' => 'R', - 'day' => '*', - 'dayofweek' => 'R', - 'month' => '*' - ) -); diff --git a/lib/editor/atto/db/upgrade.php b/lib/editor/atto/db/upgrade.php deleted file mode 100644 index fdbccd4060c..00000000000 --- a/lib/editor/atto/db/upgrade.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Atto upgrade script. - * - * @package editor_atto - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Run all Atto upgrade steps between the current DB version and the current version on disk. - * @param int $oldversion The old version of atto in the DB. - * @return bool - */ -function xmldb_editor_atto_upgrade($oldversion) { - // Automatically generated Moodle v4.2.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.3.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.4.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.5.0 release upgrade line. - // Put any upgrade step following this. - - return true; -} diff --git a/lib/editor/atto/lang/en/editor_atto.php b/lib/editor/atto/lang/en/editor_atto.php deleted file mode 100644 index 48faa79a18d..00000000000 --- a/lib/editor/atto/lang/en/editor_atto.php +++ /dev/null @@ -1,54 +0,0 @@ -. - -/** - * Strings for component 'editor_atto', language 'en'. - * - * @package editor_atto - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['autosavefailed'] = 'Could not connect to the server. If you submit this page now, your changes may be lost.'; -$string['autosavefrequency'] = 'Autosave frequency'; -$string['autosavefrequency_desc'] = 'This is the number of seconds between auto save attempts. Atto will automatically save the text in the editor according to this setting, so that text can be automatically restored when the same user returns to the same form.'; -$string['autosavesucceeded'] = 'Draft saved.'; -$string['errorcannotparseline'] = 'The line \'{$a}\' is not in the correct format.'; -$string['errorgroupisusedtwice'] = 'The group \'{$a}\' is defined twice; group names must be unique.'; -$string['errornopluginsorgroupsfound'] = 'No plugins or groups found; please add some groups and plugins.'; -$string['errorpluginnotfound'] = 'The plugin \'{$a}\' cannot be used; it does not appear to be installed.'; -$string['errorpluginisusedtwice'] = 'The plugin \'{$a}\' is used twice; plugins can only be defined once.'; -$string['errortextrecovery'] = 'Unfortunately the draft version could not be restored.'; -$string['pluginname'] = 'Atto HTML editor'; -$string['richtexteditor'] = 'Rich text editor'; -$string['subplugintype_atto'] = 'Atto plugin'; -$string['subplugintype_atto_plural'] = 'Atto plugins'; -$string['settings'] = 'Atto toolbar settings'; -$string['taskautosavecleanup'] = 'Delete expired autosave drafts'; -$string['textrecovered'] = 'A draft version of this text was automatically restored.'; -$string['toolbarconfig'] = 'Toolbar config'; -$string['toolbarconfig_desc'] = 'The list of plugins and the order they are displayed can be configured here. The configuration consists of groups (one per line) followed by the ordered list of plugins for that group. The group is separated from the plugins with an equals sign and the plugins are separated with commas. The group names must be unique and should indicate what the buttons have in common. Button and group names should not be repeated and may only contain alphanumeric characters.'; -$string['editor_command_keycode'] = 'Cmd + {$a}'; -$string['editor_control_keycode'] = 'Ctrl + {$a}'; -$string['plugin_title_shortcut'] = '{$a->title} [{$a->shortcut}]'; -$string['recover'] = 'Recover'; -$string['infostatus'] = 'Information'; -$string['warningstatus'] = 'Warning'; -$string['autosaves'] = 'Editor autosave information'; -$string['privacy:metadata:database:atto_autosave'] = 'Automatically saved text editor drafts.'; -$string['privacy:metadata:database:atto_autosave:userid'] = 'The ID of the user whose data was saved.'; -$string['privacy:metadata:database:atto_autosave:drafttext'] = 'The text which was saved.'; -$string['privacy:metadata:database:atto_autosave:timemodified'] = 'The time that content was modified.'; diff --git a/lib/editor/atto/lib.php b/lib/editor/atto/lib.php deleted file mode 100644 index 182cf37dab2..00000000000 --- a/lib/editor/atto/lib.php +++ /dev/null @@ -1,207 +0,0 @@ -. - -/** - * YUI text editor integration. - * - * @package editor_atto - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * This is the texteditor implementation. - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class atto_texteditor extends texteditor { - - /** - * Is the current browser supported by this editor? - * - * Of course! - * @return bool - */ - public function supported_by_browser() { - return true; - } - - /** - * Returns array of supported text formats. - * @return array - */ - public function get_supported_formats() { - // FORMAT_MOODLE is not supported here, sorry. - return array(FORMAT_HTML => FORMAT_HTML); - } - - /** - * Returns text format preferred by this editor. - * @return int - */ - public function get_preferred_format() { - return FORMAT_HTML; - } - - /** - * Does this editor support picking from repositories? - * @return bool - */ - public function supports_repositories() { - return true; - } - - /** - * Use this editor for given element. - * - * Available Atto-specific options: - * atto:toolbar - set to a string to override the system config editor_atto/toolbar - * - * Available general options: - * context - set to the current context object - * enable_filemanagement - set false to get rid of the managefiles plugin - * autosave - true/false to control autosave - * - * Options are also passed through to the plugins. - * - * @param string $elementid - * @param array $options - * @param null $fpoptions - */ - public function use_editor($elementid, ?array $options=null, $fpoptions=null) { - global $PAGE; - - if (array_key_exists('atto:toolbar', $options)) { - $configstr = $options['atto:toolbar']; - } else { - $configstr = get_config('editor_atto', 'toolbar'); - } - - $grouplines = explode("\n", $configstr); - - $groups = array(); - - foreach ($grouplines as $groupline) { - $line = explode('=', $groupline); - if (count($line) > 1) { - $group = trim(array_shift($line)); - $plugins = array_map('trim', explode(',', array_shift($line))); - $groups[$group] = $plugins; - } - } - - $modules = array('moodle-editor_atto-editor'); - $options['context'] = empty($options['context']) ? context_system::instance() : $options['context']; - - $jsplugins = array(); - foreach ($groups as $group => $plugins) { - $groupplugins = array(); - foreach ($plugins as $plugin) { - // Do not die on missing plugin. - if (!core_component::get_component_directory('atto_' . $plugin)) { - continue; - } - - // Remove manage files if requested. - if ($plugin == 'managefiles' && isset($options['enable_filemanagement']) && !$options['enable_filemanagement']) { - continue; - } - - $jsplugin = array(); - $jsplugin['name'] = $plugin; - $jsplugin['params'] = array(); - $modules[] = 'moodle-atto_' . $plugin . '-button'; - - component_callback('atto_' . $plugin, 'strings_for_js'); - $extra = component_callback('atto_' . $plugin, 'params_for_js', array($elementid, $options, $fpoptions)); - - if ($extra) { - $jsplugin = array_merge($jsplugin, $extra); - } - // We always need the plugin name. - $PAGE->requires->string_for_js('pluginname', 'atto_' . $plugin); - $groupplugins[] = $jsplugin; - } - $jsplugins[] = array('group'=>$group, 'plugins'=>$groupplugins); - } - - $PAGE->requires->strings_for_js([ - 'editor_command_keycode', - 'editor_control_keycode', - 'plugin_title_shortcut', - 'textrecovered', - 'autosavefailed', - 'autosavesucceeded', - 'errortextrecovery', - 'richtexteditor', - ], 'editor_atto'); - $PAGE->requires->strings_for_js(array( - 'warning', - 'info' - ), 'moodle'); - $PAGE->requires->yui_module($modules, - 'Y.M.editor_atto.Editor.init', - array($this->get_init_params($elementid, $options, $fpoptions, $jsplugins))); - - } - - /** - * Create a params array to init the editor. - * - * @param string $elementid - * @param array $options - * @param array $fpoptions - */ - protected function get_init_params($elementid, ?array $options = null, ?array $fpoptions = null, $plugins = null) { - global $PAGE; - - $directionality = get_string('thisdirection', 'langconfig'); - $strtime = get_string('strftimetime'); - $strdate = get_string('strftimedaydate'); - $lang = current_language(); - $autosave = true; - $autosavefrequency = get_config('editor_atto', 'autosavefrequency'); - if (isset($options['autosave'])) { - $autosave = $options['autosave']; - } - $contentcss = $PAGE->theme->editor_css_url()->out(false); - - // Autosave disabled for guests and not logged in users. - if (isguestuser() OR !isloggedin()) { - $autosave = false; - } - // Note <> is a safe separator, because it will not appear in the output of s(). - $pagehash = sha1($PAGE->url . '<>' . s($this->get_text())); - $params = array( - 'elementid' => $elementid, - 'content_css' => $contentcss, - 'contextid' => $options['context']->id, - 'autosaveEnabled' => $autosave, - 'autosaveFrequency' => $autosavefrequency, - 'language' => $lang, - 'directionality' => $directionality, - 'filepickeroptions' => array(), - 'plugins' => $plugins, - 'pageHash' => $pagehash, - ); - if ($fpoptions) { - $params['filepickeroptions'] = $fpoptions; - } - return $params; - } -} diff --git a/lib/editor/atto/pix/logo.png b/lib/editor/atto/pix/logo.png deleted file mode 100644 index c7438a9075a9f84a2f41f0de41f1746343e25622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2795 zcmb7Gc{tQtA3rmO#$+t7Tb2-Glw|i-GWJY^gcvfm#*%#*>)2u{F&A-B$cU096GdfB zb|Kp>TM=2VNcP4u67TQc_xNpV)?G;CqpabUu6|e%Y5sa zUb~SwyuSXU@k5A2$5=AXJyg7(-E>`KD@RSIpWV~*Q7!W>9SM&XnO+8nWjwO!tUl-y zfK!tBX+g0dM;b9HCI#k@Fm=M;b@5&HHB2j*0vRwmhcXAPQHxz87Y8$zrulCYk&_xU zAI#2dTA5(#Q|=}#h=F+kT}+8Fdh;}+AaZ~H!(p;5lv{oZu}#PGksvr6VCD#b}j$?XF^wC zJ?`OH^5!Y?G_2AG-XHnjH(Gfn{UhzvuFq;VIm_z3xRfd~f0S zNucfj!u2o6h55zAl2VT9Os`J0GP_G1UyFYI`n9vK@6GqQ{(z|#&c*RpLK71c8s|qj zcqBNeThfDmW`q<88BG2Q_kN8YT==?c9d$)w<2)YE+5YAYbE0bOGvDO$8!8pW!&5Li zYHJ10GCB6Pt1A_UQ&UUdTpA;cRr?pKx%Zg|1*r)L42_If8XD61$q$NBr3n_Uu2}K2 zfw2wOejKAdmWEaNjmynlG&Nn`WG{YvQBqR!E1mxQ`SV!7p`zeWcV~2LtmL>DH)V5? zguyVGOw5nhcg8JjZAGDVhlVz?;|qaeq|qSxVP)l^Je?Tp-Cm#5t*xyAmRtw~0LI3~ z8lky9GVdhC2~ERHr7K0l!`2wg za~t`8`g~Bf8aurxNm&>yStq|G!QgQC{P-)X7H?-=T5hiCvGlGbIC!8HxycfpdmXt& zMDOt^HGLf@o{bq5f$i?@K7Rh(;$4`puP@Qw-lVp+mS|}?P!?d8qdsK~!y4re4ide* zy`?ev3kzNm+pALJ_2KCdnt!MV1qOEZ_xrD+%AH!d@Ez*Xy64Zwu%h*G2eXifL77%BWF|vC%4yT0>zG-EK-p{7PXd<+-5sN4WZB$8{TZKN;R9Z?gp z!L+X`EW}sLZQaqx^P|(Dr#qCFB6c>-y42>KOSVRcoFHs^W@dJYU|_%^T_KS~1O%?S zx(Z*RL5`=5YixvvMMS(EC^Rq_dFl{k>4ny^$@P{6vNei)8De!P3^C@$0|Z)3bR zD4tGVUtbRv(%lNDZLNHs>1CW5PkWIrb|FLllD+Edz}bXW)%N!Gu#JVg^$pJLsN$-! zTgf8YAWQYCab7r1TS-pty$a??of&6GTN`Ven%I6LHa0eTq?+6eZ;voFO=bp~ zw};-^*RkP@#+f3lQK0mzg#J98Zo-p-0_@^w<-v1tvW%E_`S_Z!H4N6M1vA1yW5gn?$ z0NT3!MBeL~C-M#*h~-7FF&jMfY?Qm8 zIe7{(uc;%!&ku|&wu%Omae=sb%`^RKae@!Z%gr4nPI(clf4wt-39$qz z-p!EbxURKzhO?H2hOJfY7 zGjGri&T5!AK>+&lbd;0`c>GySl$bh2*U`_*t7YiP<&eZ)%KSBgxqp{)g?b2qf3cck zb@_7lY+_=fXG<)%)|ZRM#ulH@!HXYMil`j5IL~DrX%vvndntpFQ&1>`!aG~p3C`Z$ zHV+F^zmKDurWO|z#6k#+Pk8DBE{Jw4i%nB)7Zw&gzVzJlTPeSOj3(6q#1|)CA9+Px zd9(7l@kdW4gOONXt{k(1So*?K32apC4g#7_G-=A!FpcBQZoJZetvXUC`hHW-kw;X;vb^XYu z@e19f&nwW_<>E|)PZ;-D?tVr{d!0S{rJX2xGN$~t4QHRztupi@(h6JEHc!EFZE^B1 zdDH~LGWsM-nkU@SS<6R@ZZ@E;&^ftbkYYg`oqRf!s($&9f^UP(qfHbvC_ n7>!KEEF-7?mrDCP0k_BZAwUpir97hp2~%K%H#K;wPrmUlg%}Fu diff --git a/lib/editor/atto/pix/logo.svg b/lib/editor/atto/pix/logo.svg deleted file mode 100644 index 2f2e945332d..00000000000 --- a/lib/editor/atto/pix/logo.svg +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - 10-18 - - diff --git a/lib/editor/atto/plugins/accessibilitychecker/classes/privacy/provider.php b/lib/editor/atto/plugins/accessibilitychecker/classes/privacy/provider.php deleted file mode 100644 index 08363c35533..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_accessibilitychecker - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_accessibilitychecker\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_accessibilitychecker implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/accessibilitychecker/lang/en/atto_accessibilitychecker.php b/lib/editor/atto/plugins/accessibilitychecker/lang/en/atto_accessibilitychecker.php deleted file mode 100644 index ecfbc88af98..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/lang/en/atto_accessibilitychecker.php +++ /dev/null @@ -1,36 +0,0 @@ -. - -/** - * Strings for component 'atto_accessibilitychecker', language 'en'. - * - * @package atto_accessibilitychecker - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['emptytext'] = 'Empty text'; -$string['entiredocument'] = 'Entire document'; -$string['imagesmissingalt'] = 'Images require alternative text. To fix this warning, add an alt attribute to your img tags. An empty alt attribute may be used, but only when the image is purely decorative and carries no information.'; -$string['needsmorecontrast'] = 'The colours of the foreground and background text do not have enough contrast. To fix this warning, change either foreground or background colour of the text so that it is easier to read.'; -$string['needsmoreheadings'] = 'There is a lot of text with no headings. Headings will allow screen reader users to navigate through the page easily and will make the page more usable for everyone.'; -$string['nowarnings'] = 'Congratulations, no accessibility problems found!'; -$string['pluginname'] = 'Accessibility checker'; -$string['report'] = 'Accessibility report:'; -$string['tablesmissingcaption'] = 'Tables should have captions. While it is not necessary for each table to have a caption, a caption is generally very helpful.'; -$string['tablesmissingheaders'] = 'Tables should use row and/or column headers.'; -$string['tableswithmergedcells'] = 'Tables should not contain merged cells. Despite being standard markup for tables for many years, some screen readers still do not fully support complex tables. When possible, try to "flatten" the table and avoid merged cells.'; -$string['privacy:metadata'] = 'The atto_accessibilitychecker plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/accessibilitychecker/lib.php b/lib/editor/atto/plugins/accessibilitychecker/lib.php deleted file mode 100644 index bd14a7f3cfb..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/lib.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_accessibilitychecker - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise this plugin - * @param string $elementid - */ -function atto_accessibilitychecker_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('nowarnings', - 'report', - 'imagesmissingalt', - 'needsmorecontrast', - 'needsmoreheadings', - 'tableswithmergedcells', - 'tablesmissingcaption', - 'emptytext', - 'entiredocument', - 'tablesmissingheaders'), - 'atto_accessibilitychecker'); -} - diff --git a/lib/editor/atto/plugins/accessibilitychecker/styles.css b/lib/editor/atto/plugins/accessibilitychecker/styles.css deleted file mode 100644 index a8330154580..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -.accessibilitywarnings img { - max-width: 32px; - max-height: 32px; -} diff --git a/lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature b/lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature deleted file mode 100644 index 6748b4e5dc5..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature +++ /dev/null @@ -1,76 +0,0 @@ -@editor @editor_atto @atto @atto_accessibilitychecker -Feature: Atto accessibility checker - To write accessible text in Atto, I need to check for accessibility warnings. - - @javascript - Scenario: Images with no alt - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

Some plain text

Some more text

" - When I click on "Show more buttons" "button" - And I click on "Accessibility checker" "button" - Then I should see "Images require alternative text." - And I follow "/broken-image" - And I wait "2" seconds - And I click on "Insert or edit image" "button" - And the field "Enter URL" matches value "/broken-image" - And I set the field "Describe this image for someone who cannot see it" to "No more warning!" - And I press "Save image" - And I press "Accessibility checker" - And I should see "Congratulations, no accessibility problems found!" - And I click on ".moodle-dialogue-focused .closebutton" "css_element" - And I select the text in the "Description" Atto editor - And I click on "Insert or edit image" "button" - And I set the field "Enter URL" to "/decorative-image.png" - And I set the field "Describe this image for someone who cannot see it" to "" - And I set the field "Width" to "1" - And I set the field "Height" to "1" - And I click on "This image is decorative only" "checkbox" - And I press "Save image" - And I press "Accessibility checker" - And I should see "Congratulations, no accessibility problems found!" - - @javascript - Scenario: Low contrast - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

Hard to read

" - When I click on "Show more buttons" "button" - And I click on "Accessibility checker" "button" - Then I should see "The colours of the foreground and background text do not have enough contrast." - - @javascript - Scenario: No headings - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

Sweet roll oat cake jelly-o macaroon donut oat cake. Caramels macaroon cookie sweet roll croissant cheesecake candy jelly-o. Gummies sugar plum sugar plum gingerbread dessert. Tiramisu bonbon jujubes danish marshmallow cookie chocolate cake cupcake tiramisu. Bear claw oat cake chocolate bar croissant. Lollipop cookie topping liquorice croissant. Brownie cookie cupcake lollipop cupcake cupcake. Fruitcake dessert sweet biscuit dragée caramels marzipan brownie. Chupa chups gingerbread apple pie cookie liquorice caramels carrot cake cookie gingerbread. Croissant candy jelly beans. Tiramisu apple pie dessert apple pie macaroon soufflé. Brownie powder carrot cake chocolate. Tart applicake croissant dragée macaroon chocolate donut.

Jelly beans gingerbread tootsie roll. Sugar plum tiramisu cotton candy toffee pie cotton candy tiramisu. Carrot cake chocolate bar sesame snaps cupcake cake dessert sweet fruitcake wafer. Marshmallow cupcake gingerbread pie sweet candy canes powder gummi bears. Jujubes cake muffin marshmallow candy jelly beans tootsie roll pie. Gummi bears applicake chocolate cake sweet jelly sesame snaps lollipop lollipop carrot cake. Marshmallow cake jelly beans. Jelly beans sesame snaps muffin halvah cookie ice cream candy canes carrot cake. Halvah donut marshmallow tiramisu. Cookie dessert gummi bears. Sugar plum apple pie jelly beans gummi bears tart chupa chups. Liquorice macaroon gummi bears gummies macaroon marshmallow sweet roll cake topping. Lemon drops caramels pie icing danish. Chocolate cake oat cake dessert halvah danish carrot cake apple pie.

" - When I click on "Show more buttons" "button" - And I click on "Accessibility checker" "button" - Then I should see "There is a lot of text with no headings." - - @javascript - Scenario: Merged cells - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "
Dogs that look good in pants
BreedCoolness
PoodleNOT COOL
Doberman
" - When I click on "Show more buttons" "button" - And I click on "Accessibility checker" "button" - Then I should see "Tables should not contain merged cells." - - @javascript - Scenario: Table missing row/column headers - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "
Dogs that look good in pants
BreedCoolness
PoodleNOT COOL
DobermanCOOL
" - When I click on "Show more buttons" "button" - And I click on "Accessibility checker" "button" - Then I should see "Tables should use row and/or column headers." - - @javascript - Scenario: Table missing caption - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "
BreedCoolness
PoodleNOT COOL
DobermanCOOL
" - When I click on "Show more buttons" "button" - And I click on "Accessibility checker" "button" - Then I should see "Tables should have captions." diff --git a/lib/editor/atto/plugins/accessibilitychecker/version.php b/lib/editor/atto/plugins/accessibilitychecker/version.php deleted file mode 100644 index 4a84c463204..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_accessibilitychecker - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_accessibilitychecker'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js deleted file mode 100644 index dc0202fd036..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js +++ /dev/null @@ -1,357 +0,0 @@ -YUI.add('moodle-atto_accessibilitychecker-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_accessibilitychecker - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_accessibilitychecker-button - */ - -/** - * Accessibility Checking tool for the Atto editor. - * - * @namespace M.atto_accessibilitychecker - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_accessibilitychecker'; - -Y.namespace('M.atto_accessibilitychecker').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - this.addButton({ - icon: 'e/accessibility_checker', - callback: this._displayDialogue - }); - }, - - /** - * Display the Accessibility Checker tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENT), - width: '500px', - focusAfterHide: true - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var content = Y.Node.create('
'); - content.append(this._getWarnings()); - - // Add ability to select problem areas in the editor. - content.delegate('click', function(e) { - e.preventDefault(); - - var host = this.get('host'), - node = e.currentTarget.getData('sourceNode'), - dialogue = this.getDialogue(); - - if (node) { - // Focus on the editor as we hide the dialogue. - dialogue.set('focusAfterHide', this.editor).hide(); - - // Then set the selection. - host.setSelection(host.getSelectionFromNode(node)); - } else { - // Hide the dialogue. - dialogue.hide(); - } - }, 'a', this); - - return content; - }, - - /** - * Find all problems with the content editable region. - * - * @method _getWarnings - * @return {Node} A complete list of all warnings and problems. - * @private - */ - _getWarnings: function() { - var problemNodes, - list = Y.Node.create('
'); - - // Images with no alt text or dodgy alt text. - problemNodes = []; - this.editor.all('img').each(function(img) { - var alt = img.getAttribute('alt'); - if (typeof alt === 'undefined' || alt === '') { - if (img.getAttribute('role') !== 'presentation') { - problemNodes.push(img); - } - } - }, this); - this._addWarnings(list, M.util.get_string('imagesmissingalt', COMPONENT), problemNodes, true); - - problemNodes = []; - this.editor.all('*').each(function(node) { - var foreground, - background, - ratio, - lum1, - lum2; - - // Check for non-empty text. - if (node.hasChildNodes() && Y.Lang.trim(node._node.childNodes[0].nodeValue) !== '') { - foreground = Y.Color.fromArray( - this._getComputedBackgroundColor(node, node.getComputedStyle('color')), - Y.Color.TYPES.RGBA - ); - background = Y.Color.fromArray(this._getComputedBackgroundColor(node), Y.Color.TYPES.RGBA); - - lum1 = this._getLuminanceFromCssColor(foreground); - lum2 = this._getLuminanceFromCssColor(background); - - // Algorithm from "http://www.w3.org/TR/WCAG20-GENERAL/G18.html". - if (lum1 > lum2) { - ratio = (lum1 + 0.05) / (lum2 + 0.05); - } else { - ratio = (lum2 + 0.05) / (lum1 + 0.05); - } - if (ratio <= 4.5) { - Y.log('Contrast ratio is too low: ' + ratio + - ' Colour 1: ' + foreground + - ' Colour 2: ' + background + - ' Luminance 1: ' + lum1 + - ' Luminance 2: ' + lum2); - - // We only want the highest node with dodgy contrast reported. - var i = 0; - var found = false; - for (i = 0; i < problemNodes.length; i++) { - if (node.ancestors('*').indexOf(problemNodes[i]) !== -1) { - // Do not add node - it already has a parent in the list. - found = true; - break; - } else if (problemNodes[i].ancestors('*').indexOf(node) !== -1) { - // Replace the existing node with this one because it is higher up the DOM. - problemNodes[i] = node; - found = true; - break; - } - } - if (!found) { - problemNodes.push(node); - } - } - } - }, this); - this._addWarnings(list, M.util.get_string('needsmorecontrast', COMPONENT), problemNodes, false); - - // Check for lots of text with no headings. - if (this.editor.get('text').length > 1000 && !this.editor.one('h3, h4, h5')) { - this._addWarnings(list, M.util.get_string('needsmoreheadings', COMPONENT), [this.editor], false); - } - - // Check for tables with no captions. - problemNodes = []; - this.editor.all('table').each(function(table) { - var caption = table.one('caption'); - if (caption === null || caption.get('text').trim() === '') { - problemNodes.push(table); - } - }, this); - this._addWarnings(list, M.util.get_string('tablesmissingcaption', COMPONENT), problemNodes, false); - - // Check for tables with merged cells. - problemNodes = []; - this.editor.all('table').each(function(table) { - var caption = table.one('[colspan],[rowspan]'); - if (caption !== null) { - problemNodes.push(table); - } - }, this); - this._addWarnings(list, M.util.get_string('tableswithmergedcells', COMPONENT), problemNodes, false); - - // Check for tables with no row/col headers - problemNodes = []; - this.editor.all('table').each(function(table) { - if (table.one('tr').one('td')) { - // First row has a non-header cell, so all rows must have at least one header. - table.all('tr').some(function(row) { - var header = row.one('th'); - if (!header || (header.get('text').trim() === '')) { - problemNodes.push(table); - return true; - } - return false; - }, this); - } else { - // First row must have at least one header then. - var hasHeader = false; - table.one('tr').all('th').some(function(header) { - hasHeader = true; - if (header.get('text').trim() === '') { - problemNodes.push(table); - return true; - } - return false; - }); - if (!hasHeader) { - problemNodes.push(table); - } - } - }, this); - this._addWarnings(list, M.util.get_string('tablesmissingheaders', COMPONENT), problemNodes, false); - - if (!list.hasChildNodes()) { - list.append('

' + M.util.get_string('nowarnings', COMPONENT) + '

'); - } - - // Return the list of current warnings. - return list; - }, - - /** - * Generate the HTML that lists the found warnings. - * - * @method _addWarnings - * @param {Node} list Node to append the html to. - * @param {String} description Description of this failure. - * @param {array} nodes An array of failing nodes. - * @param {boolean} imagewarnings true if the warnings are related to images, false if text. - */ - _addWarnings: function(list, description, nodes, imagewarnings) { - var warning, fails, i, src, textfield, li, link, text; - - if (nodes.length > 0) { - warning = Y.Node.create('

' + description + '

'); - fails = Y.Node.create('
    '); - i = 0; - for (i = 0; i < nodes.length; i++) { - li = Y.Node.create('
  1. '); - if (imagewarnings) { - src = nodes[i].getAttribute('src'); - link = Y.Node.create(' ' + src + ''); - } else { - textfield = ('innerText' in nodes[i]) ? 'innerText' : 'textContent'; - text = nodes[i].get(textfield).trim(); - if (text === '') { - text = M.util.get_string('emptytext', COMPONENT); - } - if (nodes[i] === this.editor) { - text = M.util.get_string('entiredocument', COMPONENT); - } - link = Y.Node.create('' + text + ''); - } - link.setData('sourceNode', nodes[i]); - li.append(link); - fails.append(li); - } - - warning.append(fails); - list.append(warning); - } - }, - - /** - * Convert a CSS color to a luminance value. - * - * @method _getLuminanceFromCssColor - * @param {String} colortext The Hex value for the colour - * @return {Number} The luminance value. - * @private - */ - _getLuminanceFromCssColor: function(colortext) { - var color; - - if (colortext === 'transparent') { - colortext = '#ffffff'; - } - color = Y.Color.toArray(Y.Color.toRGB(colortext)); - - // Algorithm from "http://www.w3.org/TR/WCAG20-GENERAL/G18.html". - var part1 = function(a) { - a = parseInt(a, 10) / 255.0; - if (a <= 0.03928) { - a = a / 12.92; - } else { - a = Math.pow(((a + 0.055) / 1.055), 2.4); - } - return a; - }; - - var r1 = part1(color[0]), - g1 = part1(color[1]), - b1 = part1(color[2]); - - return 0.2126 * r1 + 0.7152 * g1 + 0.0722 * b1; - }, - - /** - * Get the computed RGB converted to full alpha value, considering the node hierarchy. - * - * @method _getComputedBackgroundColor - * @param {Node} node - * @param {String} color The initial colour. If not specified, fetches the backgroundColor from the node. - * @return {Array} Colour in Array form (RGBA) - * @private - */ - _getComputedBackgroundColor: function(node, color) { - color = color || node.getComputedStyle('backgroundColor'); - - if (color.toLowerCase() === 'transparent') { - // Y.Color doesn't handle 'transparent' properly. - color = 'rgba(1, 1, 1, 0)'; - } - - // Convert the colour to its constituent parts in RGBA format, then fetch the alpha. - var colorParts = Y.Color.toArray(color); - var alpha = colorParts[3]; - - if (alpha === 1) { - // If the alpha of the background is already 1, then the parent background colour does not change anything. - return colorParts; - } - - // Fetch the computed background colour of the parent and use it to calculate the RGB of this item. - var parentColor = this._getComputedBackgroundColor(node.get('parentNode')); - return [ - // RGB = (alpha * R|G|B) + (1 - alpha * solid parent colour). - (1 - alpha) * parentColor[0] + alpha * colorParts[0], - (1 - alpha) * parentColor[1] + alpha * colorParts[1], - (1 - alpha) * parentColor[2] + alpha * colorParts[2], - // We always return a colour with full alpha. - 1 - ]; - } -}); - - -}, '@VERSION@', {"requires": ["color-base", "moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js deleted file mode 100644 index 32092df4f6a..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_accessibilitychecker-button",function(d,t){var g="atto_accessibilitychecker";d.namespace("M.atto_accessibilitychecker").Button=d.Base.create("button",d.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({icon:"e/accessibility_checker",callback:this._displayDialogue})},_displayDialogue:function(){this.getDialogue({headerContent:M.util.get_string("pluginname",g),width:"500px",focusAfterHide:!0}).set("bodyContent",this._getDialogueContent()).show()},_getDialogueContent:function(){var t=d.Node.create('
    ');return t.append(this._getWarnings()),t.delegate("click",function(t){t.preventDefault();var e=this.get("host"),t=t.currentTarget.getData("sourceNode"),i=this.getDialogue();t?(i.set("focusAfterHide",this.editor).hide(),e.setSelection(e.getSelectionFromNode(t))):i.hide()},"a",this),t},_getWarnings:function(){var t=d.Node.create("
    "),n=[];return this.editor.all("img").each(function(t){var e=t.getAttribute("alt");void 0!==e&&""!==e||"presentation"!==t.getAttribute("role")&&n.push(t)},this),this._addWarnings(t,M.util.get_string("imagesmissingalt",g),n,!0),n=[],this.editor.all("*").each(function(t){var e,i,o,r;if(t.hasChildNodes()&&""!==d.Lang.trim(t._node.childNodes[0].nodeValue)&&(e=d.Color.fromArray(this._getComputedBackgroundColor(t,t.getComputedStyle("color")),d.Color.TYPES.RGBA),i=d.Color.fromArray(this._getComputedBackgroundColor(t),d.Color.TYPES.RGBA),e=this._getLuminanceFromCssColor(e),((i=this._getLuminanceFromCssColor(i))"+M.util.get_string("nowarnings",g)+"

    "),t},_addWarnings:function(t,e,i,o){var r,n,a,s,l;if(0"+e+"

    "),r=d.Node.create('
      '),n=n=0;n"),(l=o?(a=i[n].getAttribute("src"),d.Node.create(' '+a+"")):(a="innerText"in i[n]?"innerText":"textContent",""===(l=i[n].get(a).trim())&&(l=M.util.get_string("emptytext",g)),i[n]===this.editor&&(l=M.util.get_string("entiredocument",g)),d.Node.create(''+l+""))).setData("sourceNode",i[n]),s.append(l),r.append(s);e.append(r),t.append(e)}},_getLuminanceFromCssColor:function(t){var e;return.2126*(e=function(t){return(t=parseInt(t,10)/255)<=.03928?t/=12.92:t=Math.pow((t+.055)/1.055,2.4),t})((t=d.Color.toArray(d.Color.toRGB(t="transparent"===t?"#ffffff":t)))[0])+.7152*e(t[1])+.0722*e(t[2])},_getComputedBackgroundColor:function(t,e){var i;return"transparent"===(e=e||t.getComputedStyle("backgroundColor")).toLowerCase()&&(e="rgba(1, 1, 1, 0)"),1===(i=(e=d.Color.toArray(e))[3])?e:[(1-i)*(t=this._getComputedBackgroundColor(t.get("parentNode")))[0]+i*e[0],(1-i)*t[1]+i*e[1],(1-i)*t[2]+i*e[2],1]}})},"@VERSION@",{requires:["color-base","moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js deleted file mode 100644 index cdfd16e63a2..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js +++ /dev/null @@ -1,352 +0,0 @@ -YUI.add('moodle-atto_accessibilitychecker-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_accessibilitychecker - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_accessibilitychecker-button - */ - -/** - * Accessibility Checking tool for the Atto editor. - * - * @namespace M.atto_accessibilitychecker - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_accessibilitychecker'; - -Y.namespace('M.atto_accessibilitychecker').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - this.addButton({ - icon: 'e/accessibility_checker', - callback: this._displayDialogue - }); - }, - - /** - * Display the Accessibility Checker tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENT), - width: '500px', - focusAfterHide: true - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var content = Y.Node.create('
      '); - content.append(this._getWarnings()); - - // Add ability to select problem areas in the editor. - content.delegate('click', function(e) { - e.preventDefault(); - - var host = this.get('host'), - node = e.currentTarget.getData('sourceNode'), - dialogue = this.getDialogue(); - - if (node) { - // Focus on the editor as we hide the dialogue. - dialogue.set('focusAfterHide', this.editor).hide(); - - // Then set the selection. - host.setSelection(host.getSelectionFromNode(node)); - } else { - // Hide the dialogue. - dialogue.hide(); - } - }, 'a', this); - - return content; - }, - - /** - * Find all problems with the content editable region. - * - * @method _getWarnings - * @return {Node} A complete list of all warnings and problems. - * @private - */ - _getWarnings: function() { - var problemNodes, - list = Y.Node.create('
      '); - - // Images with no alt text or dodgy alt text. - problemNodes = []; - this.editor.all('img').each(function(img) { - var alt = img.getAttribute('alt'); - if (typeof alt === 'undefined' || alt === '') { - if (img.getAttribute('role') !== 'presentation') { - problemNodes.push(img); - } - } - }, this); - this._addWarnings(list, M.util.get_string('imagesmissingalt', COMPONENT), problemNodes, true); - - problemNodes = []; - this.editor.all('*').each(function(node) { - var foreground, - background, - ratio, - lum1, - lum2; - - // Check for non-empty text. - if (node.hasChildNodes() && Y.Lang.trim(node._node.childNodes[0].nodeValue) !== '') { - foreground = Y.Color.fromArray( - this._getComputedBackgroundColor(node, node.getComputedStyle('color')), - Y.Color.TYPES.RGBA - ); - background = Y.Color.fromArray(this._getComputedBackgroundColor(node), Y.Color.TYPES.RGBA); - - lum1 = this._getLuminanceFromCssColor(foreground); - lum2 = this._getLuminanceFromCssColor(background); - - // Algorithm from "http://www.w3.org/TR/WCAG20-GENERAL/G18.html". - if (lum1 > lum2) { - ratio = (lum1 + 0.05) / (lum2 + 0.05); - } else { - ratio = (lum2 + 0.05) / (lum1 + 0.05); - } - if (ratio <= 4.5) { - - // We only want the highest node with dodgy contrast reported. - var i = 0; - var found = false; - for (i = 0; i < problemNodes.length; i++) { - if (node.ancestors('*').indexOf(problemNodes[i]) !== -1) { - // Do not add node - it already has a parent in the list. - found = true; - break; - } else if (problemNodes[i].ancestors('*').indexOf(node) !== -1) { - // Replace the existing node with this one because it is higher up the DOM. - problemNodes[i] = node; - found = true; - break; - } - } - if (!found) { - problemNodes.push(node); - } - } - } - }, this); - this._addWarnings(list, M.util.get_string('needsmorecontrast', COMPONENT), problemNodes, false); - - // Check for lots of text with no headings. - if (this.editor.get('text').length > 1000 && !this.editor.one('h3, h4, h5')) { - this._addWarnings(list, M.util.get_string('needsmoreheadings', COMPONENT), [this.editor], false); - } - - // Check for tables with no captions. - problemNodes = []; - this.editor.all('table').each(function(table) { - var caption = table.one('caption'); - if (caption === null || caption.get('text').trim() === '') { - problemNodes.push(table); - } - }, this); - this._addWarnings(list, M.util.get_string('tablesmissingcaption', COMPONENT), problemNodes, false); - - // Check for tables with merged cells. - problemNodes = []; - this.editor.all('table').each(function(table) { - var caption = table.one('[colspan],[rowspan]'); - if (caption !== null) { - problemNodes.push(table); - } - }, this); - this._addWarnings(list, M.util.get_string('tableswithmergedcells', COMPONENT), problemNodes, false); - - // Check for tables with no row/col headers - problemNodes = []; - this.editor.all('table').each(function(table) { - if (table.one('tr').one('td')) { - // First row has a non-header cell, so all rows must have at least one header. - table.all('tr').some(function(row) { - var header = row.one('th'); - if (!header || (header.get('text').trim() === '')) { - problemNodes.push(table); - return true; - } - return false; - }, this); - } else { - // First row must have at least one header then. - var hasHeader = false; - table.one('tr').all('th').some(function(header) { - hasHeader = true; - if (header.get('text').trim() === '') { - problemNodes.push(table); - return true; - } - return false; - }); - if (!hasHeader) { - problemNodes.push(table); - } - } - }, this); - this._addWarnings(list, M.util.get_string('tablesmissingheaders', COMPONENT), problemNodes, false); - - if (!list.hasChildNodes()) { - list.append('

      ' + M.util.get_string('nowarnings', COMPONENT) + '

      '); - } - - // Return the list of current warnings. - return list; - }, - - /** - * Generate the HTML that lists the found warnings. - * - * @method _addWarnings - * @param {Node} list Node to append the html to. - * @param {String} description Description of this failure. - * @param {array} nodes An array of failing nodes. - * @param {boolean} imagewarnings true if the warnings are related to images, false if text. - */ - _addWarnings: function(list, description, nodes, imagewarnings) { - var warning, fails, i, src, textfield, li, link, text; - - if (nodes.length > 0) { - warning = Y.Node.create('

      ' + description + '

      '); - fails = Y.Node.create('
        '); - i = 0; - for (i = 0; i < nodes.length; i++) { - li = Y.Node.create('
      1. '); - if (imagewarnings) { - src = nodes[i].getAttribute('src'); - link = Y.Node.create(' ' + src + ''); - } else { - textfield = ('innerText' in nodes[i]) ? 'innerText' : 'textContent'; - text = nodes[i].get(textfield).trim(); - if (text === '') { - text = M.util.get_string('emptytext', COMPONENT); - } - if (nodes[i] === this.editor) { - text = M.util.get_string('entiredocument', COMPONENT); - } - link = Y.Node.create('' + text + ''); - } - link.setData('sourceNode', nodes[i]); - li.append(link); - fails.append(li); - } - - warning.append(fails); - list.append(warning); - } - }, - - /** - * Convert a CSS color to a luminance value. - * - * @method _getLuminanceFromCssColor - * @param {String} colortext The Hex value for the colour - * @return {Number} The luminance value. - * @private - */ - _getLuminanceFromCssColor: function(colortext) { - var color; - - if (colortext === 'transparent') { - colortext = '#ffffff'; - } - color = Y.Color.toArray(Y.Color.toRGB(colortext)); - - // Algorithm from "http://www.w3.org/TR/WCAG20-GENERAL/G18.html". - var part1 = function(a) { - a = parseInt(a, 10) / 255.0; - if (a <= 0.03928) { - a = a / 12.92; - } else { - a = Math.pow(((a + 0.055) / 1.055), 2.4); - } - return a; - }; - - var r1 = part1(color[0]), - g1 = part1(color[1]), - b1 = part1(color[2]); - - return 0.2126 * r1 + 0.7152 * g1 + 0.0722 * b1; - }, - - /** - * Get the computed RGB converted to full alpha value, considering the node hierarchy. - * - * @method _getComputedBackgroundColor - * @param {Node} node - * @param {String} color The initial colour. If not specified, fetches the backgroundColor from the node. - * @return {Array} Colour in Array form (RGBA) - * @private - */ - _getComputedBackgroundColor: function(node, color) { - color = color || node.getComputedStyle('backgroundColor'); - - if (color.toLowerCase() === 'transparent') { - // Y.Color doesn't handle 'transparent' properly. - color = 'rgba(1, 1, 1, 0)'; - } - - // Convert the colour to its constituent parts in RGBA format, then fetch the alpha. - var colorParts = Y.Color.toArray(color); - var alpha = colorParts[3]; - - if (alpha === 1) { - // If the alpha of the background is already 1, then the parent background colour does not change anything. - return colorParts; - } - - // Fetch the computed background colour of the parent and use it to calculate the RGB of this item. - var parentColor = this._getComputedBackgroundColor(node.get('parentNode')); - return [ - // RGB = (alpha * R|G|B) + (1 - alpha * solid parent colour). - (1 - alpha) * parentColor[0] + alpha * colorParts[0], - (1 - alpha) * parentColor[1] + alpha * colorParts[1], - (1 - alpha) * parentColor[2] + alpha * colorParts[2], - // We always return a colour with full alpha. - 1 - ]; - } -}); - - -}, '@VERSION@', {"requires": ["color-base", "moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/build.json b/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/build.json deleted file mode 100644 index 0278528268a..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_accessibilitychecker-button", - "builds": { - "moodle-atto_accessibilitychecker-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js b/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js deleted file mode 100644 index 043cfa17373..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js +++ /dev/null @@ -1,352 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_accessibilitychecker - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_accessibilitychecker-button - */ - -/** - * Accessibility Checking tool for the Atto editor. - * - * @namespace M.atto_accessibilitychecker - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_accessibilitychecker'; - -Y.namespace('M.atto_accessibilitychecker').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - this.addButton({ - icon: 'e/accessibility_checker', - callback: this._displayDialogue - }); - }, - - /** - * Display the Accessibility Checker tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENT), - width: '500px', - focusAfterHide: true - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var content = Y.Node.create('
        '); - content.append(this._getWarnings()); - - // Add ability to select problem areas in the editor. - content.delegate('click', function(e) { - e.preventDefault(); - - var host = this.get('host'), - node = e.currentTarget.getData('sourceNode'), - dialogue = this.getDialogue(); - - if (node) { - // Focus on the editor as we hide the dialogue. - dialogue.set('focusAfterHide', this.editor).hide(); - - // Then set the selection. - host.setSelection(host.getSelectionFromNode(node)); - } else { - // Hide the dialogue. - dialogue.hide(); - } - }, 'a', this); - - return content; - }, - - /** - * Find all problems with the content editable region. - * - * @method _getWarnings - * @return {Node} A complete list of all warnings and problems. - * @private - */ - _getWarnings: function() { - var problemNodes, - list = Y.Node.create('
        '); - - // Images with no alt text or dodgy alt text. - problemNodes = []; - this.editor.all('img').each(function(img) { - var alt = img.getAttribute('alt'); - if (typeof alt === 'undefined' || alt === '') { - if (img.getAttribute('role') !== 'presentation') { - problemNodes.push(img); - } - } - }, this); - this._addWarnings(list, M.util.get_string('imagesmissingalt', COMPONENT), problemNodes, true); - - problemNodes = []; - this.editor.all('*').each(function(node) { - var foreground, - background, - ratio, - lum1, - lum2; - - // Check for non-empty text. - if (node.hasChildNodes() && Y.Lang.trim(node._node.childNodes[0].nodeValue) !== '') { - foreground = Y.Color.fromArray( - this._getComputedBackgroundColor(node, node.getComputedStyle('color')), - Y.Color.TYPES.RGBA - ); - background = Y.Color.fromArray(this._getComputedBackgroundColor(node), Y.Color.TYPES.RGBA); - - lum1 = this._getLuminanceFromCssColor(foreground); - lum2 = this._getLuminanceFromCssColor(background); - - // Algorithm from "http://www.w3.org/TR/WCAG20-GENERAL/G18.html". - if (lum1 > lum2) { - ratio = (lum1 + 0.05) / (lum2 + 0.05); - } else { - ratio = (lum2 + 0.05) / (lum1 + 0.05); - } - if (ratio <= 4.5) { - Y.log('Contrast ratio is too low: ' + ratio + - ' Colour 1: ' + foreground + - ' Colour 2: ' + background + - ' Luminance 1: ' + lum1 + - ' Luminance 2: ' + lum2); - - // We only want the highest node with dodgy contrast reported. - var i = 0; - var found = false; - for (i = 0; i < problemNodes.length; i++) { - if (node.ancestors('*').indexOf(problemNodes[i]) !== -1) { - // Do not add node - it already has a parent in the list. - found = true; - break; - } else if (problemNodes[i].ancestors('*').indexOf(node) !== -1) { - // Replace the existing node with this one because it is higher up the DOM. - problemNodes[i] = node; - found = true; - break; - } - } - if (!found) { - problemNodes.push(node); - } - } - } - }, this); - this._addWarnings(list, M.util.get_string('needsmorecontrast', COMPONENT), problemNodes, false); - - // Check for lots of text with no headings. - if (this.editor.get('text').length > 1000 && !this.editor.one('h3, h4, h5')) { - this._addWarnings(list, M.util.get_string('needsmoreheadings', COMPONENT), [this.editor], false); - } - - // Check for tables with no captions. - problemNodes = []; - this.editor.all('table').each(function(table) { - var caption = table.one('caption'); - if (caption === null || caption.get('text').trim() === '') { - problemNodes.push(table); - } - }, this); - this._addWarnings(list, M.util.get_string('tablesmissingcaption', COMPONENT), problemNodes, false); - - // Check for tables with merged cells. - problemNodes = []; - this.editor.all('table').each(function(table) { - var caption = table.one('[colspan],[rowspan]'); - if (caption !== null) { - problemNodes.push(table); - } - }, this); - this._addWarnings(list, M.util.get_string('tableswithmergedcells', COMPONENT), problemNodes, false); - - // Check for tables with no row/col headers - problemNodes = []; - this.editor.all('table').each(function(table) { - if (table.one('tr').one('td')) { - // First row has a non-header cell, so all rows must have at least one header. - table.all('tr').some(function(row) { - var header = row.one('th'); - if (!header || (header.get('text').trim() === '')) { - problemNodes.push(table); - return true; - } - return false; - }, this); - } else { - // First row must have at least one header then. - var hasHeader = false; - table.one('tr').all('th').some(function(header) { - hasHeader = true; - if (header.get('text').trim() === '') { - problemNodes.push(table); - return true; - } - return false; - }); - if (!hasHeader) { - problemNodes.push(table); - } - } - }, this); - this._addWarnings(list, M.util.get_string('tablesmissingheaders', COMPONENT), problemNodes, false); - - if (!list.hasChildNodes()) { - list.append('

        ' + M.util.get_string('nowarnings', COMPONENT) + '

        '); - } - - // Return the list of current warnings. - return list; - }, - - /** - * Generate the HTML that lists the found warnings. - * - * @method _addWarnings - * @param {Node} list Node to append the html to. - * @param {String} description Description of this failure. - * @param {array} nodes An array of failing nodes. - * @param {boolean} imagewarnings true if the warnings are related to images, false if text. - */ - _addWarnings: function(list, description, nodes, imagewarnings) { - var warning, fails, i, src, textfield, li, link, text; - - if (nodes.length > 0) { - warning = Y.Node.create('

        ' + description + '

        '); - fails = Y.Node.create('
          '); - i = 0; - for (i = 0; i < nodes.length; i++) { - li = Y.Node.create('
        1. '); - if (imagewarnings) { - src = nodes[i].getAttribute('src'); - link = Y.Node.create(' ' + src + ''); - } else { - textfield = ('innerText' in nodes[i]) ? 'innerText' : 'textContent'; - text = nodes[i].get(textfield).trim(); - if (text === '') { - text = M.util.get_string('emptytext', COMPONENT); - } - if (nodes[i] === this.editor) { - text = M.util.get_string('entiredocument', COMPONENT); - } - link = Y.Node.create('' + text + ''); - } - link.setData('sourceNode', nodes[i]); - li.append(link); - fails.append(li); - } - - warning.append(fails); - list.append(warning); - } - }, - - /** - * Convert a CSS color to a luminance value. - * - * @method _getLuminanceFromCssColor - * @param {String} colortext The Hex value for the colour - * @return {Number} The luminance value. - * @private - */ - _getLuminanceFromCssColor: function(colortext) { - var color; - - if (colortext === 'transparent') { - colortext = '#ffffff'; - } - color = Y.Color.toArray(Y.Color.toRGB(colortext)); - - // Algorithm from "http://www.w3.org/TR/WCAG20-GENERAL/G18.html". - var part1 = function(a) { - a = parseInt(a, 10) / 255.0; - if (a <= 0.03928) { - a = a / 12.92; - } else { - a = Math.pow(((a + 0.055) / 1.055), 2.4); - } - return a; - }; - - var r1 = part1(color[0]), - g1 = part1(color[1]), - b1 = part1(color[2]); - - return 0.2126 * r1 + 0.7152 * g1 + 0.0722 * b1; - }, - - /** - * Get the computed RGB converted to full alpha value, considering the node hierarchy. - * - * @method _getComputedBackgroundColor - * @param {Node} node - * @param {String} color The initial colour. If not specified, fetches the backgroundColor from the node. - * @return {Array} Colour in Array form (RGBA) - * @private - */ - _getComputedBackgroundColor: function(node, color) { - color = color || node.getComputedStyle('backgroundColor'); - - if (color.toLowerCase() === 'transparent') { - // Y.Color doesn't handle 'transparent' properly. - color = 'rgba(1, 1, 1, 0)'; - } - - // Convert the colour to its constituent parts in RGBA format, then fetch the alpha. - var colorParts = Y.Color.toArray(color); - var alpha = colorParts[3]; - - if (alpha === 1) { - // If the alpha of the background is already 1, then the parent background colour does not change anything. - return colorParts; - } - - // Fetch the computed background colour of the parent and use it to calculate the RGB of this item. - var parentColor = this._getComputedBackgroundColor(node.get('parentNode')); - return [ - // RGB = (alpha * R|G|B) + (1 - alpha * solid parent colour). - (1 - alpha) * parentColor[0] + alpha * colorParts[0], - (1 - alpha) * parentColor[1] + alpha * colorParts[1], - (1 - alpha) * parentColor[2] + alpha * colorParts[2], - // We always return a colour with full alpha. - 1 - ]; - } -}); diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/meta/button.json b/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/meta/button.json deleted file mode 100644 index af6ecb764a3..00000000000 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/meta/button.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "moodle-atto_accessibilitychecker-button": { - "requires": [ - "color-base", - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/accessibilityhelper/classes/privacy/provider.php b/lib/editor/atto/plugins/accessibilityhelper/classes/privacy/provider.php deleted file mode 100644 index d04a2cf2dab..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_accessibilityhelper - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_accessibilityhelper\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_accessibilityhelper implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/accessibilityhelper/lang/en/atto_accessibilityhelper.php b/lib/editor/atto/plugins/accessibilityhelper/lang/en/atto_accessibilityhelper.php deleted file mode 100644 index 8053356a9ea..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/lang/en/atto_accessibilityhelper.php +++ /dev/null @@ -1,34 +0,0 @@ -. - -/** - * Strings for component 'atto_accessibilityhelper', language 'en'. - * - * @package atto_accessibilityhelper - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Screenreader helper'; -$string['liststyles'] = 'Styles for current selection:'; -$string['nostyles'] = 'No styles'; -$string['listlinks'] = 'Links in text editor:'; -$string['nolinks'] = 'No links'; -$string['selectlink'] = 'Select link'; -$string['listimages'] = 'Images in text editor:'; -$string['noimages'] = 'No images'; -$string['selectimage'] = 'Select image'; -$string['privacy:metadata'] = 'The atto_accessibilityhelper plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/accessibilityhelper/lib.php b/lib/editor/atto/plugins/accessibilityhelper/lib.php deleted file mode 100644 index 4f39206739a..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/lib.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_accessibilityhelper - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise this plugin - * @param string $elementid - */ -function atto_accessibilityhelper_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('liststyles', - 'nostyles', - 'listlinks', - 'nolinks', - 'selectlink', - 'listimages', - 'noimages', - 'selectimage'), - 'atto_accessibilityhelper'); -} - diff --git a/lib/editor/atto/plugins/accessibilityhelper/tests/behat/accessibilityhelper.feature b/lib/editor/atto/plugins/accessibilityhelper/tests/behat/accessibilityhelper.feature deleted file mode 100644 index 3d05e6c7521..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/tests/behat/accessibilityhelper.feature +++ /dev/null @@ -1,32 +0,0 @@ -@editor @editor_atto @atto @atto_accessibilityhelper -Feature: Atto accessibility helper - To use a screen reader effectively in Atto, I may need additional information about the text - - @javascript - Scenario: Images and links - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

          Some plain text

          Image 1

          Some link text

          " - And I select the text in the "Description" Atto editor - When I click on "Show more buttons" "button" - And I click on "Screenreader helper" "button" - Then I should see "Links in text editor" - And I should see "Some link text" - And I should see "Images in text editor" - And I should see "Image 1" - And I should not see "No images" - And I should not see "No links" - - @javascript - Scenario: Styles - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

          Some plain text

          " - When I click on "Show more buttons" "button" - And I select the text in the "Description" Atto editor - And I click on "Unordered list" "button" - And I click on "Screenreader helper" "button" - And I select the text in the "Description" Atto editor - # This shows the current HTML tags applied to the selected text. - # This is required because they are not always read by a screen reader. - Then I should see "UL, LI" diff --git a/lib/editor/atto/plugins/accessibilityhelper/version.php b/lib/editor/atto/plugins/accessibilityhelper/version.php deleted file mode 100644 index 499e6d4549d..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_accessibilityhelper - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_accessibilityhelper'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-debug.js b/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-debug.js deleted file mode 100644 index 0dd0891dd78..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-debug.js +++ /dev/null @@ -1,280 +0,0 @@ -YUI.add('moodle-atto_accessibilityhelper-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_accessibilityhelper - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_accessibilityhelper-button - */ - -/** - * Atto text editor accessibilityhelper plugin. - * - * This plugin adds some functions to do things that screen readers do not do well. - * Specifically, listing the active styles for the selected text, - * listing the images in the page, listing the links in the page. - * - * - * @namespace M.atto_accessibilityhelper - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_accessibilityhelper', - TEMPLATE = '' + - // The list of styles. - '

          ' + - '{{get_string "liststyles" component}}
          ' + - '' + - '

          ' + - '' + - - '

          ' + - '{{get_string "listlinks" component}}
          ' + - '' + - '

          ' + - '' + - - '

          ' + - '{{get_string "listimages" component}}
          ' + - '' + - '

          ' + - '', - - CSS = { - STYLESLABEL: COMPONENT + '_styleslabel', - LINKSLABEL: COMPONENT + '_linkslabel', - IMAGESLABEL: COMPONENT + '_imageslabel' - }; - -Y.namespace('M.atto_accessibilityhelper').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - this.addButton({ - icon: 'e/screenreader_helper', - callback: this._displayDialogue - }); - }, - - /** - * Display the Accessibility Helper tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENT), - width: '800px', - focusAfterHide: true - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - CSS: CSS, - component: COMPONENT - })); - - // Add the data. - content.one('.listStyles') - .empty() - .appendChild(this._listStyles()); - content.one('.listLinks') - .empty() - .appendChild(this._listLinks()); - content.one('.listImages') - .empty() - .appendChild(this._listImages()); - - return content; - }, - - /** - * List the styles present for the selection. - * - * @method _listStyles - * @return {String} The list of styles in use. - * @private - */ - _listStyles: function() { - // Clear the status node. - var list = [], - host = this.get('host'), - current = host.getSelectionParentNode(), - tagname; - - if (current) { - current = Y.one(current); - } - - while (current && (current !== this.editor)) { - tagname = current.get('tagName'); - if (typeof tagname !== 'undefined') { - list.push(Y.Escape.html(tagname)); - } - current = current.ancestor(); - } - if (list.length === 0) { - list.push(M.util.get_string('nostyles', COMPONENT)); - } - - list.reverse(); - - // Append the list of current styles. - return list.join(', '); - }, - - /** - * List the links for the current editor - * - * @method _listLinks - * @return {string} - * @private - */ - _listLinks: function() { - var list = Y.Node.create('
            '), - listitem, - selectlink; - - this.editor.all('a').each(function(link) { - selectlink = Y.Node.create('' + - Y.Escape.html(link.get('text')) + - ''); - - selectlink.setData('sourcelink', link); - selectlink.on('click', this._linkSelected, this); - - listitem = Y.Node.create('
          1. '); - listitem.appendChild(selectlink); - - list.appendChild(listitem); - }, this); - - if (!list.hasChildNodes()) { - list.append('
          2. ' + M.util.get_string('nolinks', COMPONENT) + '
          3. '); - } - - // Append the list of current styles. - return list; - }, - - /** - * List the images used in the editor. - * - * @method _listImages - * @return {Node} A Node containing all of the images present in the editor. - * @private - */ - _listImages: function() { - var list = Y.Node.create('
              '), - listitem, - selectimage; - - this.editor.all('img').each(function(image) { - // Get the alt or title or img url of the image. - var imgalt = image.getAttribute('alt'); - if (imgalt === '') { - imgalt = image.getAttribute('title'); - if (imgalt === '') { - imgalt = image.getAttribute('src'); - } - } - - selectimage = Y.Node.create('' + - Y.Escape.html(imgalt) + - ''); - - selectimage.setData('sourceimage', image); - selectimage.on('click', this._imageSelected, this); - - listitem = Y.Node.create('
            1. '); - listitem.append(selectimage); - list.append(listitem); - }, this); - if (!list.hasChildNodes()) { - list.append('
            2. ' + M.util.get_string('noimages', COMPONENT) + '
            3. '); - } - - // Append the list of current styles. - return list; - }, - - /** - * Event handler for selecting an image. - * - * @method _imageSelected - * @param {EventFacade} e - * @private - */ - _imageSelected: function(e) { - e.preventDefault(); - - this.getDialogue({ - focusAfterNode: null - }).hide(); - - var host = this.get('host'), - target = e.target.getData('sourceimage'); - - this.editor.focus(); - host.setSelection(host.getSelectionFromNode(target)); - }, - - /** - * Event handler for selecting a link. - * - * @method _linkSelected - * @param {EventFacade} e - * @private - */ - _linkSelected: function(e) { - e.preventDefault(); - - this.getDialogue({ - focusAfterNode: null - }).hide(); - - var host = this.get('host'), - target = e.target.getData('sourcelink'); - - this.editor.focus(); - host.setSelection(host.getSelectionFromNode(target)); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-min.js b/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-min.js deleted file mode 100644 index ccabc14a3e8..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_accessibilityhelper-button",function(a,e){var n="atto_accessibilityhelper",t={STYLESLABEL:n+"_styleslabel",LINKSLABEL:n+"_linkslabel",IMAGESLABEL:n+"_imageslabel"};a.namespace("M.atto_accessibilityhelper").Button=a.Base.create("button",a.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({icon:"e/screenreader_helper",callback:this._displayDialogue})},_displayDialogue:function(){this.getDialogue({headerContent:M.util.get_string("pluginname",n),width:"800px",focusAfterHide:!0}).set("bodyContent",this._getDialogueContent()).show()},_getDialogueContent:function(){var e=a.Handlebars.compile('

              {{get_string "liststyles" component}}

              {{get_string "listlinks" component}}

              {{get_string "listimages" component}}

              '),e=a.Node.create(e({CSS:t,component:n}));return e.one(".listStyles").empty().appendChild(this._listStyles()),e.one(".listLinks").empty().appendChild(this._listLinks()),e.one(".listImages").empty().appendChild(this._listImages()),e},_listStyles:function(){for(var e,t=[],i=(i=this.get("host").getSelectionParentNode())&&a.one(i);i&&i!==this.editor;)void 0!==(e=i.get("tagName"))&&t.push(a.Escape.html(e)),i=i.ancestor();return 0===t.length&&t.push(M.util.get_string("nostyles",n)),t.reverse(),t.join(", ")},_listLinks:function(){var t,i,l=a.Node.create("
                ");return this.editor.all("a").each(function(e){(i=a.Node.create(''+a.Escape.html(e.get("text"))+"")).setData("sourcelink",e),i.on("click",this._linkSelected,this),(t=a.Node.create("
              1. ")).appendChild(i),l.appendChild(t)},this),l.hasChildNodes()||l.append("
              2. "+M.util.get_string("nolinks",n)+"
              3. "),l},_listImages:function(){var i,l,s=a.Node.create("
                  ");return this.editor.all("img").each(function(e){var t=e.getAttribute("alt");""===t&&""===(t=e.getAttribute("title"))&&(t=e.getAttribute("src")),(l=a.Node.create(''+a.Escape.html(t)+"")).setData("sourceimage",e),l.on("click",this._imageSelected,this),(i=a.Node.create("
                1. ")).append(l),s.append(i)},this),s.hasChildNodes()||s.append("
                2. "+M.util.get_string("noimages",n)+"
                3. "),s},_imageSelected:function(e){e.preventDefault(),this.getDialogue({focusAfterNode:null}).hide();var t=this.get("host"),e=e.target.getData("sourceimage");this.editor.focus(),t.setSelection(t.getSelectionFromNode(e))},_linkSelected:function(e){e.preventDefault(),this.getDialogue({focusAfterNode:null}).hide();var t=this.get("host"),e=e.target.getData("sourcelink");this.editor.focus(),t.setSelection(t.getSelectionFromNode(e))}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button.js b/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button.js deleted file mode 100644 index 0dd0891dd78..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/yui/build/moodle-atto_accessibilityhelper-button/moodle-atto_accessibilityhelper-button.js +++ /dev/null @@ -1,280 +0,0 @@ -YUI.add('moodle-atto_accessibilityhelper-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_accessibilityhelper - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_accessibilityhelper-button - */ - -/** - * Atto text editor accessibilityhelper plugin. - * - * This plugin adds some functions to do things that screen readers do not do well. - * Specifically, listing the active styles for the selected text, - * listing the images in the page, listing the links in the page. - * - * - * @namespace M.atto_accessibilityhelper - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_accessibilityhelper', - TEMPLATE = '' + - // The list of styles. - '

                  ' + - '{{get_string "liststyles" component}}
                  ' + - '' + - '

                  ' + - '' + - - '

                  ' + - '{{get_string "listlinks" component}}
                  ' + - '' + - '

                  ' + - '' + - - '

                  ' + - '{{get_string "listimages" component}}
                  ' + - '' + - '

                  ' + - '', - - CSS = { - STYLESLABEL: COMPONENT + '_styleslabel', - LINKSLABEL: COMPONENT + '_linkslabel', - IMAGESLABEL: COMPONENT + '_imageslabel' - }; - -Y.namespace('M.atto_accessibilityhelper').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - this.addButton({ - icon: 'e/screenreader_helper', - callback: this._displayDialogue - }); - }, - - /** - * Display the Accessibility Helper tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENT), - width: '800px', - focusAfterHide: true - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - CSS: CSS, - component: COMPONENT - })); - - // Add the data. - content.one('.listStyles') - .empty() - .appendChild(this._listStyles()); - content.one('.listLinks') - .empty() - .appendChild(this._listLinks()); - content.one('.listImages') - .empty() - .appendChild(this._listImages()); - - return content; - }, - - /** - * List the styles present for the selection. - * - * @method _listStyles - * @return {String} The list of styles in use. - * @private - */ - _listStyles: function() { - // Clear the status node. - var list = [], - host = this.get('host'), - current = host.getSelectionParentNode(), - tagname; - - if (current) { - current = Y.one(current); - } - - while (current && (current !== this.editor)) { - tagname = current.get('tagName'); - if (typeof tagname !== 'undefined') { - list.push(Y.Escape.html(tagname)); - } - current = current.ancestor(); - } - if (list.length === 0) { - list.push(M.util.get_string('nostyles', COMPONENT)); - } - - list.reverse(); - - // Append the list of current styles. - return list.join(', '); - }, - - /** - * List the links for the current editor - * - * @method _listLinks - * @return {string} - * @private - */ - _listLinks: function() { - var list = Y.Node.create('
                    '), - listitem, - selectlink; - - this.editor.all('a').each(function(link) { - selectlink = Y.Node.create('' + - Y.Escape.html(link.get('text')) + - ''); - - selectlink.setData('sourcelink', link); - selectlink.on('click', this._linkSelected, this); - - listitem = Y.Node.create('
                  1. '); - listitem.appendChild(selectlink); - - list.appendChild(listitem); - }, this); - - if (!list.hasChildNodes()) { - list.append('
                  2. ' + M.util.get_string('nolinks', COMPONENT) + '
                  3. '); - } - - // Append the list of current styles. - return list; - }, - - /** - * List the images used in the editor. - * - * @method _listImages - * @return {Node} A Node containing all of the images present in the editor. - * @private - */ - _listImages: function() { - var list = Y.Node.create('
                      '), - listitem, - selectimage; - - this.editor.all('img').each(function(image) { - // Get the alt or title or img url of the image. - var imgalt = image.getAttribute('alt'); - if (imgalt === '') { - imgalt = image.getAttribute('title'); - if (imgalt === '') { - imgalt = image.getAttribute('src'); - } - } - - selectimage = Y.Node.create('' + - Y.Escape.html(imgalt) + - ''); - - selectimage.setData('sourceimage', image); - selectimage.on('click', this._imageSelected, this); - - listitem = Y.Node.create('
                    1. '); - listitem.append(selectimage); - list.append(listitem); - }, this); - if (!list.hasChildNodes()) { - list.append('
                    2. ' + M.util.get_string('noimages', COMPONENT) + '
                    3. '); - } - - // Append the list of current styles. - return list; - }, - - /** - * Event handler for selecting an image. - * - * @method _imageSelected - * @param {EventFacade} e - * @private - */ - _imageSelected: function(e) { - e.preventDefault(); - - this.getDialogue({ - focusAfterNode: null - }).hide(); - - var host = this.get('host'), - target = e.target.getData('sourceimage'); - - this.editor.focus(); - host.setSelection(host.getSelectionFromNode(target)); - }, - - /** - * Event handler for selecting a link. - * - * @method _linkSelected - * @param {EventFacade} e - * @private - */ - _linkSelected: function(e) { - e.preventDefault(); - - this.getDialogue({ - focusAfterNode: null - }).hide(); - - var host = this.get('host'), - target = e.target.getData('sourcelink'); - - this.editor.focus(); - host.setSelection(host.getSelectionFromNode(target)); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/build.json b/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/build.json deleted file mode 100644 index e0fd3462631..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_accessibilityhelper-button", - "builds": { - "moodle-atto_accessibilityhelper-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/js/button.js b/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/js/button.js deleted file mode 100644 index d01d387f0e4..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/js/button.js +++ /dev/null @@ -1,275 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_accessibilityhelper - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_accessibilityhelper-button - */ - -/** - * Atto text editor accessibilityhelper plugin. - * - * This plugin adds some functions to do things that screen readers do not do well. - * Specifically, listing the active styles for the selected text, - * listing the images in the page, listing the links in the page. - * - * - * @namespace M.atto_accessibilityhelper - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_accessibilityhelper', - TEMPLATE = '' + - // The list of styles. - '

                      ' + - '{{get_string "liststyles" component}}
                      ' + - '' + - '

                      ' + - '' + - - '

                      ' + - '{{get_string "listlinks" component}}
                      ' + - '' + - '

                      ' + - '' + - - '

                      ' + - '{{get_string "listimages" component}}
                      ' + - '' + - '

                      ' + - '', - - CSS = { - STYLESLABEL: COMPONENT + '_styleslabel', - LINKSLABEL: COMPONENT + '_linkslabel', - IMAGESLABEL: COMPONENT + '_imageslabel' - }; - -Y.namespace('M.atto_accessibilityhelper').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - this.addButton({ - icon: 'e/screenreader_helper', - callback: this._displayDialogue - }); - }, - - /** - * Display the Accessibility Helper tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENT), - width: '800px', - focusAfterHide: true - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - CSS: CSS, - component: COMPONENT - })); - - // Add the data. - content.one('.listStyles') - .empty() - .appendChild(this._listStyles()); - content.one('.listLinks') - .empty() - .appendChild(this._listLinks()); - content.one('.listImages') - .empty() - .appendChild(this._listImages()); - - return content; - }, - - /** - * List the styles present for the selection. - * - * @method _listStyles - * @return {String} The list of styles in use. - * @private - */ - _listStyles: function() { - // Clear the status node. - var list = [], - host = this.get('host'), - current = host.getSelectionParentNode(), - tagname; - - if (current) { - current = Y.one(current); - } - - while (current && (current !== this.editor)) { - tagname = current.get('tagName'); - if (typeof tagname !== 'undefined') { - list.push(Y.Escape.html(tagname)); - } - current = current.ancestor(); - } - if (list.length === 0) { - list.push(M.util.get_string('nostyles', COMPONENT)); - } - - list.reverse(); - - // Append the list of current styles. - return list.join(', '); - }, - - /** - * List the links for the current editor - * - * @method _listLinks - * @return {string} - * @private - */ - _listLinks: function() { - var list = Y.Node.create('
                        '), - listitem, - selectlink; - - this.editor.all('a').each(function(link) { - selectlink = Y.Node.create('' + - Y.Escape.html(link.get('text')) + - ''); - - selectlink.setData('sourcelink', link); - selectlink.on('click', this._linkSelected, this); - - listitem = Y.Node.create('
                      1. '); - listitem.appendChild(selectlink); - - list.appendChild(listitem); - }, this); - - if (!list.hasChildNodes()) { - list.append('
                      2. ' + M.util.get_string('nolinks', COMPONENT) + '
                      3. '); - } - - // Append the list of current styles. - return list; - }, - - /** - * List the images used in the editor. - * - * @method _listImages - * @return {Node} A Node containing all of the images present in the editor. - * @private - */ - _listImages: function() { - var list = Y.Node.create('
                          '), - listitem, - selectimage; - - this.editor.all('img').each(function(image) { - // Get the alt or title or img url of the image. - var imgalt = image.getAttribute('alt'); - if (imgalt === '') { - imgalt = image.getAttribute('title'); - if (imgalt === '') { - imgalt = image.getAttribute('src'); - } - } - - selectimage = Y.Node.create('' + - Y.Escape.html(imgalt) + - ''); - - selectimage.setData('sourceimage', image); - selectimage.on('click', this._imageSelected, this); - - listitem = Y.Node.create('
                        1. '); - listitem.append(selectimage); - list.append(listitem); - }, this); - if (!list.hasChildNodes()) { - list.append('
                        2. ' + M.util.get_string('noimages', COMPONENT) + '
                        3. '); - } - - // Append the list of current styles. - return list; - }, - - /** - * Event handler for selecting an image. - * - * @method _imageSelected - * @param {EventFacade} e - * @private - */ - _imageSelected: function(e) { - e.preventDefault(); - - this.getDialogue({ - focusAfterNode: null - }).hide(); - - var host = this.get('host'), - target = e.target.getData('sourceimage'); - - this.editor.focus(); - host.setSelection(host.getSelectionFromNode(target)); - }, - - /** - * Event handler for selecting a link. - * - * @method _linkSelected - * @param {EventFacade} e - * @private - */ - _linkSelected: function(e) { - e.preventDefault(); - - this.getDialogue({ - focusAfterNode: null - }).hide(); - - var host = this.get('host'), - target = e.target.getData('sourcelink'); - - this.editor.focus(); - host.setSelection(host.getSelectionFromNode(target)); - } -}); diff --git a/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/meta/button.json b/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/meta/button.json deleted file mode 100644 index 81dd844fe1e..00000000000 --- a/lib/editor/atto/plugins/accessibilityhelper/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_accessibilityhelper-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/align/classes/privacy/provider.php b/lib/editor/atto/plugins/align/classes/privacy/provider.php deleted file mode 100644 index c528965c356..00000000000 --- a/lib/editor/atto/plugins/align/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_align - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_align\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_align implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/align/lang/en/atto_align.php b/lib/editor/atto/plugins/align/lang/en/atto_align.php deleted file mode 100644 index f8dbcdefa43..00000000000 --- a/lib/editor/atto/plugins/align/lang/en/atto_align.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Strings for component 'atto_align', language 'en'. - * - * @package atto_align - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['center'] = 'Center'; -$string['leftalign'] = 'Left align'; -$string['pluginname'] = 'Text align'; -$string['rightalign'] = 'Right align'; -$string['privacy:metadata'] = 'The atto_align plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/align/lib.php b/lib/editor/atto/plugins/align/lib.php deleted file mode 100644 index 1363af8c463..00000000000 --- a/lib/editor/atto/plugins/align/lib.php +++ /dev/null @@ -1,35 +0,0 @@ -. - -/** - * Atto text editor align plugin lib. - * - * @package atto_align - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_align_strings_for_js() { - global $PAGE; - $PAGE->requires->strings_for_js(array('center', 'leftalign', 'rightalign'), 'atto_align'); -} diff --git a/lib/editor/atto/plugins/align/tests/behat/align.feature b/lib/editor/atto/plugins/align/tests/behat/align.feature deleted file mode 100644 index 9e3a9009c85..00000000000 --- a/lib/editor/atto/plugins/align/tests/behat/align.feature +++ /dev/null @@ -1,52 +0,0 @@ -@editor @editor_atto @atto @atto_align -Feature: Atto align text - To format text in Atto, I need to use the align buttons. - - @javascript - Scenario: Right align some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          Fascism

                          " - And I click on "Show more buttons" "button" - And I select the text in the "Description" Atto editor - When I click on "Right align" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "style=\"text-align:right;\"" - - @javascript - Scenario: Left align some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          Communism

                          " - And I click on "Show more buttons" "button" - And I select the text in the "Description" Atto editor - When I click on "Right align" "button" - And I click on "Left align" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "style=\"text-align:left;\"" - - @javascript - Scenario: Center align some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          United Future

                          " - And I click on "Show more buttons" "button" - And I select the text in the "Description" Atto editor - When I click on "Center" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "style=\"text-align:center;\"" diff --git a/lib/editor/atto/plugins/align/version.php b/lib/editor/atto/plugins/align/version.php deleted file mode 100644 index 1cb50f3ad50..00000000000 --- a/lib/editor/atto/plugins/align/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor align plugin version file. - * - * @package atto_align - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_align'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-debug.js b/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-debug.js deleted file mode 100644 index 38645d7d2e3..00000000000 --- a/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-debug.js +++ /dev/null @@ -1,106 +0,0 @@ -YUI.add('moodle-atto_align-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_align - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_align-button - */ - -/** - * Atto text editor align plugin. - * - * @namespace M.atto_align - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_align').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var alignment; - - alignment = 'justifyLeft'; - this.addButton({ - icon: 'e/align_left', - title: 'leftalign', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - - alignment = 'justifyCenter'; - this.addButton({ - icon: 'e/align_center', - title: 'center', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - - alignment = 'justifyRight'; - this.addButton({ - icon: 'e/align_right', - title: 'rightalign', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - }, - - - /** - * Change the alignment to the specified justification. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} justification The execCommand for the new justification. - * @private - */ - _changeStyle: function(e, justification) { - var host = this.get('host'); - - // We temporarily re-enable CSS styling to try to have the most consistency. - // Though, IE, as always, is stubborn and will do its own thing... - host.enableCssStyling(); - - document.execCommand(justification, false, null); - - // To clean up IE's mess. - this.editor.all('*[align]').each(function(node) { - var align = node.get('align'); - if (align) { - node.setStyle('text-align', align); - node.removeAttribute('align'); - } - }, this); - - // Re-disable the CSS styling after making the change. - host.disableCssStyling(); - - // Mark the text as having been updated. - this.markUpdated(); - - this.editor.focus(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-min.js b/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-min.js deleted file mode 100644 index 5d0151c3da6..00000000000 --- a/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_align-button",function(t,e){t.namespace("M.atto_align").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){var t="justifyLeft";this.addButton({icon:"e/align_left",title:"leftalign",buttonName:t,callback:this._changeStyle,callbackArgs:t}),this.addButton({icon:"e/align_center",title:"center",buttonName:t="justifyCenter",callback:this._changeStyle,callbackArgs:t}),this.addButton({icon:"e/align_right",title:"rightalign",buttonName:t="justifyRight",callback:this._changeStyle,callbackArgs:t})},_changeStyle:function(t,e){var i=this.get("host");i.enableCssStyling(),document.execCommand(e,!1,null),this.editor.all("*[align]").each(function(t){var e=t.get("align");e&&(t.setStyle("text-align",e),t.removeAttribute("align"))},this),i.disableCssStyling(),this.markUpdated(),this.editor.focus()}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button.js b/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button.js deleted file mode 100644 index 38645d7d2e3..00000000000 --- a/lib/editor/atto/plugins/align/yui/build/moodle-atto_align-button/moodle-atto_align-button.js +++ /dev/null @@ -1,106 +0,0 @@ -YUI.add('moodle-atto_align-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_align - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_align-button - */ - -/** - * Atto text editor align plugin. - * - * @namespace M.atto_align - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_align').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var alignment; - - alignment = 'justifyLeft'; - this.addButton({ - icon: 'e/align_left', - title: 'leftalign', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - - alignment = 'justifyCenter'; - this.addButton({ - icon: 'e/align_center', - title: 'center', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - - alignment = 'justifyRight'; - this.addButton({ - icon: 'e/align_right', - title: 'rightalign', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - }, - - - /** - * Change the alignment to the specified justification. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} justification The execCommand for the new justification. - * @private - */ - _changeStyle: function(e, justification) { - var host = this.get('host'); - - // We temporarily re-enable CSS styling to try to have the most consistency. - // Though, IE, as always, is stubborn and will do its own thing... - host.enableCssStyling(); - - document.execCommand(justification, false, null); - - // To clean up IE's mess. - this.editor.all('*[align]').each(function(node) { - var align = node.get('align'); - if (align) { - node.setStyle('text-align', align); - node.removeAttribute('align'); - } - }, this); - - // Re-disable the CSS styling after making the change. - host.disableCssStyling(); - - // Mark the text as having been updated. - this.markUpdated(); - - this.editor.focus(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/align/yui/src/button/build.json b/lib/editor/atto/plugins/align/yui/src/button/build.json deleted file mode 100644 index 4fc220c461c..00000000000 --- a/lib/editor/atto/plugins/align/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_align-button", - "builds": { - "moodle-atto_align-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/align/yui/src/button/js/button.js b/lib/editor/atto/plugins/align/yui/src/button/js/button.js deleted file mode 100644 index 019699a598a..00000000000 --- a/lib/editor/atto/plugins/align/yui/src/button/js/button.js +++ /dev/null @@ -1,101 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_align - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_align-button - */ - -/** - * Atto text editor align plugin. - * - * @namespace M.atto_align - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_align').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var alignment; - - alignment = 'justifyLeft'; - this.addButton({ - icon: 'e/align_left', - title: 'leftalign', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - - alignment = 'justifyCenter'; - this.addButton({ - icon: 'e/align_center', - title: 'center', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - - alignment = 'justifyRight'; - this.addButton({ - icon: 'e/align_right', - title: 'rightalign', - buttonName: alignment, - callback: this._changeStyle, - callbackArgs: alignment - }); - }, - - - /** - * Change the alignment to the specified justification. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} justification The execCommand for the new justification. - * @private - */ - _changeStyle: function(e, justification) { - var host = this.get('host'); - - // We temporarily re-enable CSS styling to try to have the most consistency. - // Though, IE, as always, is stubborn and will do its own thing... - host.enableCssStyling(); - - document.execCommand(justification, false, null); - - // To clean up IE's mess. - this.editor.all('*[align]').each(function(node) { - var align = node.get('align'); - if (align) { - node.setStyle('text-align', align); - node.removeAttribute('align'); - } - }, this); - - // Re-disable the CSS styling after making the change. - host.disableCssStyling(); - - // Mark the text as having been updated. - this.markUpdated(); - - this.editor.focus(); - } -}); diff --git a/lib/editor/atto/plugins/align/yui/src/button/meta/button.json b/lib/editor/atto/plugins/align/yui/src/button/meta/button.json deleted file mode 100644 index cd4d458c329..00000000000 --- a/lib/editor/atto/plugins/align/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_align-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/backcolor/classes/privacy/provider.php b/lib/editor/atto/plugins/backcolor/classes/privacy/provider.php deleted file mode 100644 index fb2bc0b927a..00000000000 --- a/lib/editor/atto/plugins/backcolor/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_backcolor - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_backcolor\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_backcolor implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/backcolor/lang/en/atto_backcolor.php b/lib/editor/atto/plugins/backcolor/lang/en/atto_backcolor.php deleted file mode 100644 index 2afcfdd7bc8..00000000000 --- a/lib/editor/atto/plugins/backcolor/lang/en/atto_backcolor.php +++ /dev/null @@ -1,32 +0,0 @@ -. - -/** - * Strings for component 'atto_backcolor', language 'en'. - * - * @package atto_backcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['color_white'] = 'White'; -$string['color_red'] = 'Red'; -$string['color_yellow'] = 'Yellow'; -$string['color_green'] = 'Green'; -$string['color_blue'] = 'Blue'; -$string['color_black'] = 'Black'; -$string['pluginname'] = 'Background colour'; -$string['privacy:metadata'] = 'The atto_backcolor plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/backcolor/lib.php b/lib/editor/atto/plugins/backcolor/lib.php deleted file mode 100644 index f21a4689bf6..00000000000 --- a/lib/editor/atto/plugins/backcolor/lib.php +++ /dev/null @@ -1,41 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_backcolor - * @copyright 2021 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the js strings required for this module. - */ -function atto_backcolor_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js([ - 'color_white', - 'color_red', - 'color_yellow', - 'color_green', - 'color_blue', - 'color_black' - ], 'atto_backcolor'); -} diff --git a/lib/editor/atto/plugins/backcolor/styles.css b/lib/editor/atto/plugins/backcolor/styles.css deleted file mode 100644 index 75f81c75a93..00000000000 --- a/lib/editor/atto/plugins/backcolor/styles.css +++ /dev/null @@ -1,26 +0,0 @@ -.atto_backcolor_button .dropdown-menu { - min-width: inherit; -} - -.atto_backcolor_button .dropdown-menu .atto_menuentry { - padding-top: 5px; - padding-bottom: 5px; -} - -.atto_backcolor_button .dropdown-menu .atto_menuentry a[role=menuitem] { - display: flex; -} - -.atto_backcolor_button .dropdown-menu .atto_menuentry a[role=menuitem]:hover, -.atto_backcolor_button .dropdown-menu .atto_menuentry a[role=menuitem]:focus { - box-shadow: #0f6fc5 0 0 3px 1px; -} - -.atto_backcolor_button .dropdown-menu .coloroption { - display: flex; - align-items: center; - float: left; - height: 20px; - width: 20px; - border: 1px solid #ccc; -} diff --git a/lib/editor/atto/plugins/backcolor/version.php b/lib/editor/atto/plugins/backcolor/version.php deleted file mode 100644 index 19011ad360f..00000000000 --- a/lib/editor/atto/plugins/backcolor/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_backcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_backcolor'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-debug.js b/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-debug.js deleted file mode 100644 index 902830a4c32..00000000000 --- a/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-debug.js +++ /dev/null @@ -1,97 +0,0 @@ -YUI.add('moodle-atto_backcolor-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_backcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_backcolor-button - */ - -/** - * Atto text editor backcolor plugin. - * - * @namespace M.atto_backcolor - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var colors = [ - { - name: 'white', - color: '#FFFFFF' - }, { - name: 'red', - color: '#EF4540' - }, { - name: 'yellow', - color: '#FFCF35' - }, { - name: 'green', - color: '#98CA3E' - }, { - name: 'blue', - color: '#7D9FD3' - }, { - name: 'black', - color: '#333333' - } - ]; - -Y.namespace('M.atto_backcolor').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(colors, function(color) { - var colorLabel = M.util.get_string('color_' + color.name, 'atto_backcolor'); - items.push({ - text: '
                          ', - callbackArgs: color.color - }); - }); - - this.addToolbarMenu({ - icon: 'e/text_highlight', - overlayWidth: '4', - globalItemConfig: { - inlineFormat: true, - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the background color to the specified color. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new background color - * @private - */ - _changeStyle: function(e, color) { - this.get('host').formatSelectionInlineStyle({ - backgroundColor: color - }); - } -}); - - -}, '@VERSION@'); diff --git a/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-min.js b/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-min.js deleted file mode 100644 index 847612cddc0..00000000000 --- a/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_backcolor-button",function(o,t){var e=[{name:"white",color:"#FFFFFF"},{name:"red",color:"#EF4540"},{name:"yellow",color:"#FFCF35"},{name:"green",color:"#98CA3E"},{name:"blue",color:"#7D9FD3"},{name:"black",color:"#333333"}];o.namespace("M.atto_backcolor").Button=o.Base.create("button",o.M.editor_atto.EditorPlugin,[],{initializer:function(){var a=[];o.Array.each(e,function(o){var t=M.util.get_string("color_"+o.name,"atto_backcolor");a.push({text:'
                          ',callbackArgs:o.color})}),this.addToolbarMenu({icon:"e/text_highlight",overlayWidth:"4",globalItemConfig:{inlineFormat:!0,callback:this._changeStyle},items:a})},_changeStyle:function(o,t){this.get("host").formatSelectionInlineStyle({backgroundColor:t})}})},"@VERSION@"); \ No newline at end of file diff --git a/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button.js b/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button.js deleted file mode 100644 index 902830a4c32..00000000000 --- a/lib/editor/atto/plugins/backcolor/yui/build/moodle-atto_backcolor-button/moodle-atto_backcolor-button.js +++ /dev/null @@ -1,97 +0,0 @@ -YUI.add('moodle-atto_backcolor-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_backcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_backcolor-button - */ - -/** - * Atto text editor backcolor plugin. - * - * @namespace M.atto_backcolor - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var colors = [ - { - name: 'white', - color: '#FFFFFF' - }, { - name: 'red', - color: '#EF4540' - }, { - name: 'yellow', - color: '#FFCF35' - }, { - name: 'green', - color: '#98CA3E' - }, { - name: 'blue', - color: '#7D9FD3' - }, { - name: 'black', - color: '#333333' - } - ]; - -Y.namespace('M.atto_backcolor').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(colors, function(color) { - var colorLabel = M.util.get_string('color_' + color.name, 'atto_backcolor'); - items.push({ - text: '
                          ', - callbackArgs: color.color - }); - }); - - this.addToolbarMenu({ - icon: 'e/text_highlight', - overlayWidth: '4', - globalItemConfig: { - inlineFormat: true, - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the background color to the specified color. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new background color - * @private - */ - _changeStyle: function(e, color) { - this.get('host').formatSelectionInlineStyle({ - backgroundColor: color - }); - } -}); - - -}, '@VERSION@'); diff --git a/lib/editor/atto/plugins/backcolor/yui/src/button/build.json b/lib/editor/atto/plugins/backcolor/yui/src/button/build.json deleted file mode 100644 index ab856c03ba1..00000000000 --- a/lib/editor/atto/plugins/backcolor/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_backcolor-button", - "builds": { - "moodle-atto_backcolor-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/backcolor/yui/src/button/js/button.js b/lib/editor/atto/plugins/backcolor/yui/src/button/js/button.js deleted file mode 100644 index 441a12bd7c0..00000000000 --- a/lib/editor/atto/plugins/backcolor/yui/src/button/js/button.js +++ /dev/null @@ -1,92 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_backcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_backcolor-button - */ - -/** - * Atto text editor backcolor plugin. - * - * @namespace M.atto_backcolor - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var colors = [ - { - name: 'white', - color: '#FFFFFF' - }, { - name: 'red', - color: '#EF4540' - }, { - name: 'yellow', - color: '#FFCF35' - }, { - name: 'green', - color: '#98CA3E' - }, { - name: 'blue', - color: '#7D9FD3' - }, { - name: 'black', - color: '#333333' - } - ]; - -Y.namespace('M.atto_backcolor').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(colors, function(color) { - var colorLabel = M.util.get_string('color_' + color.name, 'atto_backcolor'); - items.push({ - text: '
                          ', - callbackArgs: color.color - }); - }); - - this.addToolbarMenu({ - icon: 'e/text_highlight', - overlayWidth: '4', - globalItemConfig: { - inlineFormat: true, - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the background color to the specified color. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new background color - * @private - */ - _changeStyle: function(e, color) { - this.get('host').formatSelectionInlineStyle({ - backgroundColor: color - }); - } -}); diff --git a/lib/editor/atto/plugins/backcolor/yui/src/button/meta/editor.js b/lib/editor/atto/plugins/backcolor/yui/src/button/meta/editor.js deleted file mode 100644 index d6cb6235e1a..00000000000 --- a/lib/editor/atto/plugins/backcolor/yui/src/button/meta/editor.js +++ /dev/null @@ -1,5 +0,0 @@ -{ - "moodle-atto_backcolor-button": { - "requires": ["node"] - } -} diff --git a/lib/editor/atto/plugins/bold/classes/privacy/provider.php b/lib/editor/atto/plugins/bold/classes/privacy/provider.php deleted file mode 100644 index f2504984ab9..00000000000 --- a/lib/editor/atto/plugins/bold/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_bold - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_bold\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_bold implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/bold/lang/en/atto_bold.php b/lib/editor/atto/plugins/bold/lang/en/atto_bold.php deleted file mode 100644 index 8dacbc8f671..00000000000 --- a/lib/editor/atto/plugins/bold/lang/en/atto_bold.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_bold', language 'en'. - * - * @package atto_bold - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Bold'; -$string['privacy:metadata'] = 'The atto_bold plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/bold/tests/behat/bold.feature b/lib/editor/atto/plugins/bold/tests/behat/bold.feature deleted file mode 100644 index fe5b8619906..00000000000 --- a/lib/editor/atto/plugins/bold/tests/behat/bold.feature +++ /dev/null @@ -1,35 +0,0 @@ -@editor @editor_atto @atto @atto_bold @_bug_phantomjs -Feature: Atto bold button - To format text in Atto, I need to use the bold button. - - @javascript - Scenario: Bold some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Badger" - And I select the text in the "Description" Atto editor - When I click on "Bold" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Badger" - - @javascript - Scenario: Unbold some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Mouse" - And I select the text in the "Description" Atto editor - When I click on "Bold" "button" - And I click on "Bold" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should not see "Mouse" - And I should see "Mouse" diff --git a/lib/editor/atto/plugins/bold/version.php b/lib/editor/atto/plugins/bold/version.php deleted file mode 100644 index c6d22f453a0..00000000000 --- a/lib/editor/atto/plugins/bold/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_bold - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_bold'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-debug.js b/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-debug.js deleted file mode 100644 index c1ae54dd3cf..00000000000 --- a/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-debug.js +++ /dev/null @@ -1,72 +0,0 @@ -YUI.add('moodle-atto_bold-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_bold - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_bold-button - */ - -/** - * Atto text editor bold plugin. - * - * @namespace M.atto_bold - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_bold').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var bold; - - this.addButton({ - callback: this._toggleBold, - icon: 'e/bold', - buttonName: bold, - inlineFormat: true, - - // Key code for the keyboard shortcut which triggers this button: - keys: '66', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'strong, b' - }); - }, - /** - * Toggle the bold setting. - * - * @method _toggleBold - * @param {EventFacade} e - */ - _toggleBold: function() { - var host = this.get('host'); - - // Use the "bold" command for simplicity. This will toggle tags off as well. - document.execCommand('bold', false, null); - - // Then change all tags to tags. This will change any existing tags as well. - host.changeToCSS('b', 'bf-editor-bold-strong'); - host.changeToTags('bf-editor-bold-strong', 'strong'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-min.js b/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-min.js deleted file mode 100644 index 6751687f60b..00000000000 --- a/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_bold-button",function(o,t){o.namespace("M.atto_bold").Button=o.Base.create("button",o.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({callback:this._toggleBold,icon:"e/bold",buttonName:void 0,inlineFormat:!0,keys:"66",tags:"strong, b"})},_toggleBold:function(){var o=this.get("host");document.execCommand("bold",!1,null),o.changeToCSS("b","bf-editor-bold-strong"),o.changeToTags("bf-editor-bold-strong","strong")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button.js b/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button.js deleted file mode 100644 index c1ae54dd3cf..00000000000 --- a/lib/editor/atto/plugins/bold/yui/build/moodle-atto_bold-button/moodle-atto_bold-button.js +++ /dev/null @@ -1,72 +0,0 @@ -YUI.add('moodle-atto_bold-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_bold - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_bold-button - */ - -/** - * Atto text editor bold plugin. - * - * @namespace M.atto_bold - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_bold').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var bold; - - this.addButton({ - callback: this._toggleBold, - icon: 'e/bold', - buttonName: bold, - inlineFormat: true, - - // Key code for the keyboard shortcut which triggers this button: - keys: '66', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'strong, b' - }); - }, - /** - * Toggle the bold setting. - * - * @method _toggleBold - * @param {EventFacade} e - */ - _toggleBold: function() { - var host = this.get('host'); - - // Use the "bold" command for simplicity. This will toggle tags off as well. - document.execCommand('bold', false, null); - - // Then change all tags to tags. This will change any existing tags as well. - host.changeToCSS('b', 'bf-editor-bold-strong'); - host.changeToTags('bf-editor-bold-strong', 'strong'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/bold/yui/src/button/build.json b/lib/editor/atto/plugins/bold/yui/src/button/build.json deleted file mode 100644 index 112075088a9..00000000000 --- a/lib/editor/atto/plugins/bold/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_bold-button", - "builds": { - "moodle-atto_bold-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/bold/yui/src/button/js/button.js b/lib/editor/atto/plugins/bold/yui/src/button/js/button.js deleted file mode 100644 index 3215bfe63de..00000000000 --- a/lib/editor/atto/plugins/bold/yui/src/button/js/button.js +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_bold - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_bold-button - */ - -/** - * Atto text editor bold plugin. - * - * @namespace M.atto_bold - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_bold').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var bold; - - this.addButton({ - callback: this._toggleBold, - icon: 'e/bold', - buttonName: bold, - inlineFormat: true, - - // Key code for the keyboard shortcut which triggers this button: - keys: '66', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'strong, b' - }); - }, - /** - * Toggle the bold setting. - * - * @method _toggleBold - * @param {EventFacade} e - */ - _toggleBold: function() { - var host = this.get('host'); - - // Use the "bold" command for simplicity. This will toggle tags off as well. - document.execCommand('bold', false, null); - - // Then change all tags to tags. This will change any existing tags as well. - host.changeToCSS('b', 'bf-editor-bold-strong'); - host.changeToTags('bf-editor-bold-strong', 'strong'); - } -}); diff --git a/lib/editor/atto/plugins/bold/yui/src/button/meta/button.json b/lib/editor/atto/plugins/bold/yui/src/button/meta/button.json deleted file mode 100644 index c90cc588638..00000000000 --- a/lib/editor/atto/plugins/bold/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_bold-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/charmap/classes/privacy/provider.php b/lib/editor/atto/plugins/charmap/classes/privacy/provider.php deleted file mode 100644 index 8667870103b..00000000000 --- a/lib/editor/atto/plugins/charmap/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_charmap - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_charmap\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_charmap implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/charmap/lang/en/atto_charmap.php b/lib/editor/atto/plugins/charmap/lang/en/atto_charmap.php deleted file mode 100644 index dae50dee54d..00000000000 --- a/lib/editor/atto/plugins/charmap/lang/en/atto_charmap.php +++ /dev/null @@ -1,293 +0,0 @@ -. - -/** - * Strings for component 'atto_charmap', language 'en'. - * - * @package atto_charmap - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['insertcharacter'] = 'Insert character'; -$string['pluginname'] = 'Insert character'; - -// The following are not ordered on purpose, they are kept -// in the order in which they appear in the user interface. -$string['interrobang'] = 'interrobang'; -$string['nobreakspace'] = 'no-break space'; -$string['ampersand'] = 'ampersand'; -$string['quotationmark'] = 'quotation mark'; -$string['centsign'] = 'cent sign'; -$string['eurosign'] = 'euro sign'; -$string['poundsign'] = 'pound sign'; -$string['yensign'] = 'yen sign'; -$string['copyrightsign'] = 'copyright sign'; -$string['registeredsign'] = 'registered sign'; -$string['trademarksign'] = 'trade mark sign'; -$string['permillesign'] = 'per mille sign'; -$string['microsign'] = 'micro sign'; -$string['middledot'] = 'middle dot'; -$string['bullet'] = 'bullet'; -$string['threedotleader'] = 'three dot leader'; -$string['minutesfeet'] = 'minutes / feet'; -$string['secondsinches'] = 'seconds / inches'; -$string['sectionsign'] = 'section sign'; -$string['paragraphsign'] = 'paragraph sign'; -$string['sharpsesszed'] = 'sharp s / ess-zed'; -$string['singleleftpointinganglequotationmark'] = 'single left-pointing angle quotation mark'; -$string['singlerightpointinganglequotationmark'] = 'single right-pointing angle quotation mark'; -$string['leftpointingguillemet'] = 'left pointing guillemet'; -$string['rightpointingguillemet'] = 'right pointing guillemet'; -$string['leftsinglequotationmark'] = 'left single quotation mark'; -$string['rightsinglequotationmark'] = 'right single quotation mark'; -$string['leftdoublequotationmark'] = 'left double quotation mark'; -$string['rightdoublequotationmark'] = 'right double quotation mark'; -$string['singlelow9quotationmark'] = 'single low-9 quotation mark'; -$string['doublelow9quotationmark'] = 'double low-9 quotation mark'; -$string['lessthansign'] = 'less-than sign'; -$string['greaterthansign'] = 'greater-than sign'; -$string['lessthanorequalto'] = 'less-than or equal to'; -$string['greaterthanorequalto'] = 'greater-than or equal to'; -$string['endash'] = 'en dash'; -$string['emdash'] = 'em dash'; -$string['macron'] = 'macron'; -$string['overline'] = 'overline'; -$string['currencysign'] = 'currency sign'; -$string['brokenbar'] = 'broken bar'; -$string['diaeresis'] = 'diaeresis'; -$string['invertedexclamationmark'] = 'inverted exclamation mark'; -$string['turnedquestionmark'] = 'turned question mark'; -$string['circumflexaccent'] = 'circumflex accent'; -$string['smalltilde'] = 'small tilde'; -$string['degreesign'] = 'degree sign'; -$string['minussign'] = 'minus sign'; -$string['plusminussign'] = 'plus-minus sign'; -$string['divisionsign'] = 'division sign'; -$string['fractionslash'] = 'fraction slash'; -$string['multiplicationsign'] = 'multiplication sign'; -$string['superscriptone'] = 'superscript one'; -$string['superscripttwo'] = 'superscript two'; -$string['superscriptthree'] = 'superscript three'; -$string['fractiononequarter'] = 'fraction one quarter'; -$string['fractiononehalf'] = 'fraction one half'; -$string['fractionthreequarters'] = 'fraction three quarters'; -$string['functionflorin'] = 'function / florin'; -$string['integral'] = 'integral'; -$string['narysumation'] = 'n-ary sumation'; -$string['infinity'] = 'infinity'; -$string['squareroot'] = 'square root'; -$string['similarto'] = 'similar to'; -$string['approximatelyequalto'] = 'approximately equal to'; -$string['almostequalto'] = 'almost equal to'; -$string['notequalto'] = 'not equal to'; -$string['identicalto'] = 'identical to'; -$string['elementof'] = 'element of'; -$string['notanelementof'] = 'not an element of'; -$string['containsasmember'] = 'contains as member'; -$string['naryproduct'] = 'n-ary product'; -$string['logicaland'] = 'logical and'; -$string['logicalor'] = 'logical or'; -$string['notsign'] = 'not sign'; -$string['intersection'] = 'intersection'; -$string['union'] = 'union'; -$string['partialdifferential'] = 'partial differential'; -$string['forall'] = 'for all'; -$string['thereexists'] = 'there exists'; -$string['diameter'] = 'diameter'; -$string['backwarddifference'] = 'backward difference'; -$string['asteriskoperator'] = 'asterisk operator'; -$string['proportionalto'] = 'proportional to'; -$string['angle'] = 'angle'; -$string['acuteaccent'] = 'acute accent'; -$string['cedilla'] = 'cedilla'; -$string['feminineordinalindicator'] = 'feminine ordinal indicator'; -$string['masculineordinalindicator'] = 'masculine ordinal indicator'; -$string['dagger'] = 'dagger'; -$string['doubledagger'] = 'double dagger'; -$string['agrave_caps'] = 'A - grave'; -$string['aacute_caps'] = 'A - acute'; -$string['acircumflex_caps'] = 'A - circumflex'; -$string['atilde_caps'] = 'A - tilde'; -$string['adiaeresis_caps'] = 'A - diaeresis'; -$string['aringabove_caps'] = 'A - ring above'; -$string['amacron_caps'] = 'A - macron'; -$string['ligatureae_caps'] = 'ligature AE'; -$string['ccedilla_caps'] = 'C - cedilla'; -$string['egrave_caps'] = 'E - grave'; -$string['eacute_caps'] = 'E - acute'; -$string['ecircumflex_caps'] = 'E - circumflex'; -$string['ediaeresis_caps'] = 'E - diaeresis'; -$string['emacron_caps'] = 'E - macron'; -$string['igrave_caps'] = 'I - grave'; -$string['iacute_caps'] = 'I - acute'; -$string['icircumflex_caps'] = 'I - circumflex'; -$string['idiaeresis_caps'] = 'I - diaeresis'; -$string['imacron_caps'] = 'I - macron'; -$string['eth_caps'] = 'ETH'; -$string['ntilde_caps'] = 'N - tilde'; -$string['ograve_caps'] = 'O - grave'; -$string['oacute_caps'] = 'O - acute'; -$string['ocircumflex_caps'] = 'O - circumflex'; -$string['otilde_caps'] = 'O - tilde'; -$string['odiaeresis_caps'] = 'O - diaeresis'; -$string['oslash_caps'] = 'O - slash'; -$string['omacron_caps'] = 'O - macron'; -$string['ligatureoe_caps'] = 'ligature OE'; -$string['scaron_caps'] = 'S - caron'; -$string['ugrave_caps'] = 'U - grave'; -$string['uacute_caps'] = 'U - acute'; -$string['ucircumflex_caps'] = 'U - circumflex'; -$string['udiaeresis_caps'] = 'U - diaeresis'; -$string['umacron_caps'] = 'U - macron'; -$string['yacute_caps'] = 'Y - acute'; -$string['ydiaeresis_caps'] = 'Y - diaeresis'; -$string['thorn_caps'] = 'THORN'; -$string['agrave'] = 'a - grave'; -$string['aacute'] = 'a - acute'; -$string['acircumflex'] = 'a - circumflex'; -$string['atilde'] = 'a - tilde'; -$string['adiaeresis'] = 'a - diaeresis'; -$string['aringabove'] = 'a - ring above'; -$string['amacron'] = 'a - macron'; -$string['ligatureae'] = 'ligature ae'; -$string['ccedilla'] = 'c - cedilla'; -$string['egrave'] = 'e - grave'; -$string['eacute'] = 'e - acute'; -$string['ecircumflex'] = 'e - circumflex'; -$string['ediaeresis'] = 'e - diaeresis'; -$string['emacron'] = 'e - macron'; -$string['igrave'] = 'i - grave'; -$string['iacute'] = 'i - acute'; -$string['icircumflex'] = 'i - circumflex'; -$string['idiaeresis'] = 'i - diaeresis'; -$string['imacron'] = 'i - macron'; -$string['eth'] = 'eth'; -$string['ntilde'] = 'n - tilde'; -$string['ograve'] = 'o - grave'; -$string['oacute'] = 'o - acute'; -$string['ocircumflex'] = 'o - circumflex'; -$string['otilde'] = 'o - tilde'; -$string['odiaeresis'] = 'o - diaeresis'; -$string['oslash'] = 'o slash'; -$string['omacron'] = 'o - macron'; -$string['ligatureoe'] = 'ligature oe'; -$string['scaron'] = 's - caron'; -$string['ugrave'] = 'u - grave'; -$string['uacute'] = 'u - acute'; -$string['ucircumflex'] = 'u - circumflex'; -$string['udiaeresis'] = 'u - diaeresis'; -$string['umacron'] = 'u - macron'; -$string['yacute'] = 'y - acute'; -$string['thorn'] = 'thorn'; -$string['ydiaeresis'] = 'y - diaeresis'; -$string['alpha_caps'] = 'Alpha'; -$string['beta_caps'] = 'Beta'; -$string['gamma_caps'] = 'Gamma'; -$string['delta_caps'] = 'Delta'; -$string['epsilon_caps'] = 'Epsilon'; -$string['zeta_caps'] = 'Zeta'; -$string['eta_caps'] = 'Eta'; -$string['theta_caps'] = 'Theta'; -$string['iota_caps'] = 'Iota'; -$string['kappa_caps'] = 'Kappa'; -$string['lambda_caps'] = 'Lambda'; -$string['mu_caps'] = 'Mu'; -$string['nu_caps'] = 'Nu'; -$string['xi_caps'] = 'Xi'; -$string['omicron_caps'] = 'Omicron'; -$string['pi_caps'] = 'Pi'; -$string['rho_caps'] = 'Rho'; -$string['sigma_caps'] = 'Sigma'; -$string['tau_caps'] = 'Tau'; -$string['upsilon_caps'] = 'Upsilon'; -$string['phi_caps'] = 'Phi'; -$string['chi_caps'] = 'Chi'; -$string['psi_caps'] = 'Psi'; -$string['omega_caps'] = 'Omega'; -$string['alpha'] = 'alpha'; -$string['beta'] = 'beta'; -$string['gamma'] = 'gamma'; -$string['delta'] = 'delta'; -$string['epsilon'] = 'epsilon'; -$string['zeta'] = 'zeta'; -$string['eta'] = 'eta'; -$string['theta'] = 'theta'; -$string['iota'] = 'iota'; -$string['kappa'] = 'kappa'; -$string['lambda'] = 'lambda'; -$string['mu'] = 'mu'; -$string['nu'] = 'nu'; -$string['xi'] = 'xi'; -$string['omicron'] = 'omicron'; -$string['pi'] = 'pi'; -$string['rho'] = 'rho'; -$string['finalsigma'] = 'final sigma'; -$string['sigma'] = 'sigma'; -$string['tau'] = 'tau'; -$string['upsilon'] = 'upsilon'; -$string['phi'] = 'phi'; -$string['chi'] = 'chi'; -$string['psi'] = 'psi'; -$string['omega'] = 'omega'; -$string['alefsymbol'] = 'alef symbol'; -$string['pisymbol'] = 'pi symbol'; -$string['realpartsymbol'] = 'real part symbol'; -$string['thetasymbol'] = 'theta symbol'; -$string['upsilonhooksymbol'] = 'upsilon - hook symbol'; -$string['weierstrassp'] = 'Weierstrass p'; -$string['imaginarypart'] = 'imaginary part'; -$string['leftwardsarrow'] = 'leftwards arrow'; -$string['upwardsarrow'] = 'upwards arrow'; -$string['rightwardsarrow'] = 'rightwards arrow'; -$string['downwardsarrow'] = 'downwards arrow'; -$string['leftrightarrow'] = 'left right arrow'; -$string['carriagereturn'] = 'carriage return'; -$string['leftwardsdoublearrow'] = 'leftwards double arrow'; -$string['upwardsdoublearrow'] = 'upwards double arrow'; -$string['rightwardsdoublearrow'] = 'rightwards double arrow'; -$string['downwardsdoublearrow'] = 'downwards double arrow'; -$string['leftrightdoublearrow'] = 'left right double arrow'; -$string['therefore'] = 'therefore'; -$string['subsetof'] = 'subset of'; -$string['supersetof'] = 'superset of'; -$string['notasubsetof'] = 'not a subset of'; -$string['subsetoforequalto'] = 'subset of or equal to'; -$string['supersetoforequalto'] = 'superset of or equal to'; -$string['circledplus'] = 'circled plus'; -$string['circledtimes'] = 'circled times'; -$string['perpendicular'] = 'perpendicular'; -$string['dotoperator'] = 'dot operator'; -$string['leftceiling'] = 'left ceiling'; -$string['rightceiling'] = 'right ceiling'; -$string['leftfloor'] = 'left floor'; -$string['rightfloor'] = 'right floor'; -$string['leftpointinganglebracket'] = 'left-pointing angle bracket'; -$string['rightpointinganglebracket'] = 'right-pointing angle bracket'; -$string['lozenge'] = 'lozenge'; -$string['blackspadesuit'] = 'black spade suit'; -$string['blackclubsuit'] = 'black club suit'; -$string['blackheartsuit'] = 'black heart suit'; -$string['blackdiamondsuit'] = 'black diamond suit'; -$string['enspace'] = 'en space'; -$string['emspace'] = 'em space'; -$string['thinspace'] = 'thin space'; -$string['zerowidthnonjoiner'] = 'zero width non-joiner'; -$string['zerowidthjoiner'] = 'zero width joiner'; -$string['lefttorightmark'] = 'left-to-right mark'; -$string['righttoleftmark'] = 'right-to-left mark'; -$string['softhyphen'] = 'soft hyphen'; -$string['privacy:metadata'] = 'The atto_charmap plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/charmap/lib.php b/lib/editor/atto/plugins/charmap/lib.php deleted file mode 100644 index b6c81a65854..00000000000 --- a/lib/editor/atto/plugins/charmap/lib.php +++ /dev/null @@ -1,306 +0,0 @@ -. - -/** - * Atto text editor charmap plugin lib. - * - * @package atto_charmap - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_charmap_strings_for_js() { - global $PAGE; - - // In order to prevent extra strings to be imported, comment/uncomment the characters - // which are enabled in the JavaScript part of this plugin. - $PAGE->requires->strings_for_js( - array( - 'amacron', - 'emacron', - 'imacron', - 'omacron', - 'umacron', - 'amacron_caps', - 'emacron_caps', - 'imacron_caps', - 'omacron_caps', - 'umacron_caps', - 'interrobang', - 'insertcharacter', - 'nobreakspace', - 'ampersand', - 'quotationmark', - 'centsign', - 'eurosign', - 'poundsign', - 'yensign', - 'copyrightsign', - 'registeredsign', - 'trademarksign', - 'permillesign', - 'microsign', - 'middledot', - 'bullet', - 'threedotleader', - 'minutesfeet', - 'secondsinches', - 'sectionsign', - 'paragraphsign', - 'sharpsesszed', - 'singleleftpointinganglequotationmark', - 'singlerightpointinganglequotationmark', - 'leftpointingguillemet', - 'rightpointingguillemet', - 'leftsinglequotationmark', - 'rightsinglequotationmark', - 'leftdoublequotationmark', - 'rightdoublequotationmark', - 'singlelow9quotationmark', - 'doublelow9quotationmark', - 'lessthansign', - 'greaterthansign', - 'lessthanorequalto', - 'greaterthanorequalto', - 'endash', - 'emdash', - 'macron', - 'overline', - 'currencysign', - 'brokenbar', - 'diaeresis', - 'invertedexclamationmark', - 'turnedquestionmark', - 'circumflexaccent', - 'smalltilde', - 'degreesign', - 'minussign', - 'plusminussign', - 'divisionsign', - 'fractionslash', - 'multiplicationsign', - 'superscriptone', - 'superscripttwo', - 'superscriptthree', - 'fractiononequarter', - 'fractiononehalf', - 'fractionthreequarters', - 'functionflorin', - 'integral', - 'narysumation', - 'infinity', - 'squareroot', - // 'similarto', - // 'approximatelyequalto', - 'almostequalto', - 'notequalto', - 'identicalto', - // 'elementof', - // 'notanelementof', - // 'containsasmember', - 'naryproduct', - // 'logicaland', - // 'logicalor', - 'notsign', - 'intersection', - // 'union', - 'partialdifferential', - // 'forall', - // 'thereexists', - // 'diameter', - // 'backwarddifference', - // 'asteriskoperator', - // 'proportionalto', - // 'angle', - 'acuteaccent', - 'cedilla', - 'feminineordinalindicator', - 'masculineordinalindicator', - 'dagger', - 'doubledagger', - 'agrave_caps', - 'aacute_caps', - 'acircumflex_caps', - 'atilde_caps', - 'adiaeresis_caps', - 'aringabove_caps', - 'ligatureae_caps', - 'ccedilla_caps', - 'egrave_caps', - 'eacute_caps', - 'ecircumflex_caps', - 'ediaeresis_caps', - 'igrave_caps', - 'iacute_caps', - 'icircumflex_caps', - 'idiaeresis_caps', - 'eth_caps', - 'ntilde_caps', - 'ograve_caps', - 'oacute_caps', - 'ocircumflex_caps', - 'otilde_caps', - 'odiaeresis_caps', - 'oslash_caps', - 'ligatureoe_caps', - 'scaron_caps', - 'ugrave_caps', - 'uacute_caps', - 'ucircumflex_caps', - 'udiaeresis_caps', - 'yacute_caps', - 'ydiaeresis_caps', - 'thorn_caps', - 'agrave', - 'aacute', - 'acircumflex', - 'atilde', - 'adiaeresis', - 'aringabove', - 'ligatureae', - 'ccedilla', - 'egrave', - 'eacute', - 'ecircumflex', - 'ediaeresis', - 'igrave', - 'iacute', - 'icircumflex', - 'idiaeresis', - 'eth', - 'ntilde', - 'ograve', - 'oacute', - 'ocircumflex', - 'otilde', - 'odiaeresis', - 'oslash', - 'ligatureoe', - 'scaron', - 'ugrave', - 'uacute', - 'ucircumflex', - 'udiaeresis', - 'yacute', - 'thorn', - 'ydiaeresis', - 'alpha_caps', - 'beta_caps', - 'gamma_caps', - 'delta_caps', - 'epsilon_caps', - 'zeta_caps', - 'eta_caps', - 'theta_caps', - 'iota_caps', - 'kappa_caps', - 'lambda_caps', - 'mu_caps', - 'nu_caps', - 'xi_caps', - 'omicron_caps', - 'pi_caps', - 'rho_caps', - 'sigma_caps', - 'tau_caps', - 'upsilon_caps', - 'phi_caps', - 'chi_caps', - 'psi_caps', - 'omega_caps', - 'alpha', - 'beta', - 'gamma', - 'delta', - 'epsilon', - 'zeta', - 'eta', - 'theta', - 'iota', - 'kappa', - 'lambda', - 'mu', - 'nu', - 'xi', - 'omicron', - 'pi', - 'rho', - 'finalsigma', - 'sigma', - 'tau', - 'upsilon', - 'phi', - 'chi', - 'psi', - 'omega', - // 'alefsymbol', - // 'pisymbol', - // 'realpartsymbol', - // 'thetasymbol', - // 'upsilonhooksymbol', - // 'weierstrassp', - // 'imaginarypart', - 'leftwardsarrow', - 'upwardsarrow', - 'rightwardsarrow', - 'downwardsarrow', - 'leftrightarrow', - // 'carriagereturn', - // 'leftwardsdoublearrow', - // 'upwardsdoublearrow', - // 'rightwardsdoublearrow', - // 'downwardsdoublearrow', - // 'leftrightdoublearrow', - // 'therefore', - // 'subsetof', - // 'supersetof', - // 'notasubsetof', - // 'subsetoforequalto', - // 'supersetoforequalto', - // 'circledplus', - // 'circledtimes', - // 'perpendicular', - // 'dotoperator', - // 'leftceiling', - // 'rightceiling', - // 'leftfloor', - // 'rightfloor', - // 'leftpointinganglebracket', - // 'rightpointinganglebracket', - 'lozenge', - 'blackspadesuit', - 'blackclubsuit', - 'blackheartsuit', - 'blackdiamondsuit', - // 'enspace', - // 'emspace', - // 'thinspace', - // 'zerowidthnonjoiner', - // 'zerowidthjoiner', - // 'lefttorightmark', - // 'righttoleftmark', - // 'softhyphen', - ), - 'atto_charmap' - ); -} diff --git a/lib/editor/atto/plugins/charmap/styles.css b/lib/editor/atto/plugins/charmap/styles.css deleted file mode 100644 index 465646202bf..00000000000 --- a/lib/editor/atto/plugins/charmap/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -.atto_charmap_selector button { - width: 2.18rem; - margin: 0.1rem; -} diff --git a/lib/editor/atto/plugins/charmap/tests/behat/charmap.feature b/lib/editor/atto/plugins/charmap/tests/behat/charmap.feature deleted file mode 100644 index 2ef4895fee1..00000000000 --- a/lib/editor/atto/plugins/charmap/tests/behat/charmap.feature +++ /dev/null @@ -1,20 +0,0 @@ -@editor @editor_atto @atto @atto_charmap -Feature: Atto charmap button - To format text in Atto, I need to add symbols - - @javascript - Scenario: Insert symbols - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          1980 Mullet

                          " - And I select the text in the "Description" Atto editor - When I click on "Show more buttons" "button" - And I click on "Insert character" "button" - And I click on "a - macron" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "ā" diff --git a/lib/editor/atto/plugins/charmap/version.php b/lib/editor/atto/plugins/charmap/version.php deleted file mode 100644 index 468046a07e9..00000000000 --- a/lib/editor/atto/plugins/charmap/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor charmap plugin version file. - * - * @package atto_charmap - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_charmap'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-debug.js b/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-debug.js deleted file mode 100644 index 43f1310115a..00000000000 --- a/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-debug.js +++ /dev/null @@ -1,431 +0,0 @@ -YUI.add('moodle-atto_charmap-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_charmap - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Atto text editor character map plugin - * - * @module moodle-atto_charmap-button - */ - -var COMPONENTNAME = 'atto_charmap', - CSS = { - BUTTON: 'atto_charmap_character', - CHARMAP: 'atto_charmap_selector' - }, - /* - * Map of special characters, kindly borrowed from TinyMCE. - * - * Each entries contains in order: - * - {String} HTML code - * - {String} HTML numerical code - * - {Boolean} Whether or not to include it in the list - * - {String} The language string key - * - * @property CHARMAP - * @type {Array} - */ - CHARMAP = [ - [' ', ' ', true, 'nobreakspace'], - ['&', '&', true, 'ampersand'], - ['"', '"', true, 'quotationmark'], - ['‽', '‽', true, 'interrobang'], - // Finance. - ['¢', '¢', true, 'centsign'], - ['€', '€', true, 'eurosign'], - ['£', '£', true, 'poundsign'], - ['¥', '¥', true, 'yensign'], - // Signs. - ['©', '©', true, 'copyrightsign'], - ['®', '®', true, 'registeredsign'], - ['™', '™', true, 'trademarksign'], - ['‰', '‰', true, 'permillesign'], - ['µ', 'µ', true, 'microsign'], - ['·', '·', true, 'middledot'], - ['•', '•', true, 'bullet'], - ['…', '…', true, 'threedotleader'], - ['′', '′', true, 'minutesfeet'], - ['″', '″', true, 'secondsinches'], - ['§', '§', true, 'sectionsign'], - ['¶', '¶', true, 'paragraphsign'], - ['ß', 'ß', true, 'sharpsesszed'], - // Quotations. - ['‹', '‹', true, 'singleleftpointinganglequotationmark'], - ['›', '›', true, 'singlerightpointinganglequotationmark'], - ['«', '«', true, 'leftpointingguillemet'], - ['»', '»', true, 'rightpointingguillemet'], - ['‘', '‘', true, 'leftsinglequotationmark'], - ['’', '’', true, 'rightsinglequotationmark'], - ['“', '“', true, 'leftdoublequotationmark'], - ['”', '”', true, 'rightdoublequotationmark'], - ['‚', '‚', true, 'singlelow9quotationmark'], - ['„', '„', true, 'doublelow9quotationmark'], - ['<', '<', true, 'lessthansign'], - ['>', '>', true, 'greaterthansign'], - ['≤', '≤', true, 'lessthanorequalto'], - ['≥', '≥', true, 'greaterthanorequalto'], - ['–', '–', true, 'endash'], - ['—', '—', true, 'emdash'], - ['¯', '¯', true, 'macron'], - ['‾', '‾', true, 'overline'], - ['¤', '¤', true, 'currencysign'], - ['¦', '¦', true, 'brokenbar'], - ['¨', '¨', true, 'diaeresis'], - ['¡', '¡', true, 'invertedexclamationmark'], - ['¿', '¿', true, 'turnedquestionmark'], - ['ˆ', 'ˆ', true, 'circumflexaccent'], - ['˜', '˜', true, 'smalltilde'], - ['°', '°', true, 'degreesign'], - ['−', '−', true, 'minussign'], - ['±', '±', true, 'plusminussign'], - ['÷', '÷', true, 'divisionsign'], - ['⁄', '⁄', true, 'fractionslash'], - ['×', '×', true, 'multiplicationsign'], - ['¹', '¹', true, 'superscriptone'], - ['²', '²', true, 'superscripttwo'], - ['³', '³', true, 'superscriptthree'], - ['¼', '¼', true, 'fractiononequarter'], - ['½', '½', true, 'fractiononehalf'], - ['¾', '¾', true, 'fractionthreequarters'], - // Math / logical. - ['ƒ', 'ƒ', true, 'functionflorin'], - ['∫', '∫', true, 'integral'], - ['∑', '∑', true, 'narysumation'], - ['∞', '∞', true, 'infinity'], - ['√', '√', true, 'squareroot'], - ['∼', '∼', false, 'similarto'], - ['≅', '≅', false, 'approximatelyequalto'], - ['≈', '≈', true, 'almostequalto'], - ['≠', '≠', true, 'notequalto'], - ['≡', '≡', true, 'identicalto'], - ['∈', '∈', false, 'elementof'], - ['∉', '∉', false, 'notanelementof'], - ['∋', '∋', false, 'containsasmember'], - ['∏', '∏', true, 'naryproduct'], - ['∧', '∧', false, 'logicaland'], - ['∨', '∨', false, 'logicalor'], - ['¬', '¬', true, 'notsign'], - ['∩', '∩', true, 'intersection'], - ['∪', '∪', false, 'union'], - ['∂', '∂', true, 'partialdifferential'], - ['∀', '∀', false, 'forall'], - ['∃', '∃', false, 'thereexists'], - ['∅', '∅', false, 'diameter'], - ['∇', '∇', false, 'backwarddifference'], - ['∗', '∗', false, 'asteriskoperator'], - ['∝', '∝', false, 'proportionalto'], - ['∠', '∠', false, 'angle'], - // Undefined. - ['´', '´', true, 'acuteaccent'], - ['¸', '¸', true, 'cedilla'], - ['ª', 'ª', true, 'feminineordinalindicator'], - ['º', 'º', true, 'masculineordinalindicator'], - ['†', '†', true, 'dagger'], - ['‡', '‡', true, 'doubledagger'], - // Alphabetical special chars. - ['À', 'À', true, 'agrave_caps'], - ['Á', 'Á', true, 'aacute_caps'], - ['Â', 'Â', true, 'acircumflex_caps'], - ['Ã', 'Ã', true, 'atilde_caps'], - ['Ä', 'Ä', true, 'adiaeresis_caps'], - ['Å', 'Å', true, 'aringabove_caps'], - ['Ā', 'Ā', true, 'amacron_caps'], - ['Æ', 'Æ', true, 'ligatureae_caps'], - ['Ç', 'Ç', true, 'ccedilla_caps'], - ['È', 'È', true, 'egrave_caps'], - ['É', 'É', true, 'eacute_caps'], - ['Ê', 'Ê', true, 'ecircumflex_caps'], - ['Ë', 'Ë', true, 'ediaeresis_caps'], - ['Ē', 'Ē', true, 'emacron_caps'], - ['Ì', 'Ì', true, 'igrave_caps'], - ['Í', 'Í', true, 'iacute_caps'], - ['Î', 'Î', true, 'icircumflex_caps'], - ['Ï', 'Ï', true, 'idiaeresis_caps'], - ['Ī', 'Ī', true, 'imacron_caps'], - ['Ð', 'Ð', true, 'eth_caps'], - ['Ñ', 'Ñ', true, 'ntilde_caps'], - ['Ò', 'Ò', true, 'ograve_caps'], - ['Ó', 'Ó', true, 'oacute_caps'], - ['Ô', 'Ô', true, 'ocircumflex_caps'], - ['Õ', 'Õ', true, 'otilde_caps'], - ['Ö', 'Ö', true, 'odiaeresis_caps'], - ['Ø', 'Ø', true, 'oslash_caps'], - ['Ō', 'Ō', true, 'omacron_caps'], - ['Œ', 'Œ', true, 'ligatureoe_caps'], - ['Š', 'Š', true, 'scaron_caps'], - ['Ù', 'Ù', true, 'ugrave_caps'], - ['Ú', 'Ú', true, 'uacute_caps'], - ['Û', 'Û', true, 'ucircumflex_caps'], - ['Ü', 'Ü', true, 'udiaeresis_caps'], - ['Ū', 'Ū', true, 'umacron_caps'], - ['Ý', 'Ý', true, 'yacute_caps'], - ['Ÿ', 'Ÿ', true, 'ydiaeresis_caps'], - ['Þ', 'Þ', true, 'thorn_caps'], - ['à', 'à', true, 'agrave'], - ['á', 'á', true, 'aacute'], - ['â', 'â', true, 'acircumflex'], - ['ã', 'ã', true, 'atilde'], - ['ä', 'ä', true, 'adiaeresis'], - ['å', 'å', true, 'aringabove'], - ['ā', 'ā', true, 'amacron'], - ['æ', 'æ', true, 'ligatureae'], - ['ç', 'ç', true, 'ccedilla'], - ['è', 'è', true, 'egrave'], - ['é', 'é', true, 'eacute'], - ['ê', 'ê', true, 'ecircumflex'], - ['ë', 'ë', true, 'ediaeresis'], - ['ē', 'ē', true, 'emacron'], - ['ì', 'ì', true, 'igrave'], - ['í', 'í', true, 'iacute'], - ['î', 'î', true, 'icircumflex'], - ['ï', 'ï', true, 'idiaeresis'], - ['ī', 'ī', true, 'imacron'], - ['ð', 'ð', true, 'eth'], - ['ñ', 'ñ', true, 'ntilde'], - ['ò', 'ò', true, 'ograve'], - ['ó', 'ó', true, 'oacute'], - ['ô', 'ô', true, 'ocircumflex'], - ['õ', 'õ', true, 'otilde'], - ['ö', 'ö', true, 'odiaeresis'], - ['ø', 'ø', true, 'oslash'], - ['ō', 'ō', true, 'omacron'], - ['œ', 'œ', true, 'ligatureoe'], - ['š', 'š', true, 'scaron'], - ['ù', 'ù', true, 'ugrave'], - ['ú', 'ú', true, 'uacute'], - ['û', 'û', true, 'ucircumflex'], - ['ü', 'ü', true, 'udiaeresis'], - ['ū', 'ū', true, 'umacron'], - ['ý', 'ý', true, 'yacute'], - ['þ', 'þ', true, 'thorn'], - ['ÿ', 'ÿ', true, 'ydiaeresis'], - ['Α', 'Α', true, 'alpha_caps'], - ['Β', 'Β', true, 'beta_caps'], - ['Γ', 'Γ', true, 'gamma_caps'], - ['Δ', 'Δ', true, 'delta_caps'], - ['Ε', 'Ε', true, 'epsilon_caps'], - ['Ζ', 'Ζ', true, 'zeta_caps'], - ['Η', 'Η', true, 'eta_caps'], - ['Θ', 'Θ', true, 'theta_caps'], - ['Ι', 'Ι', true, 'iota_caps'], - ['Κ', 'Κ', true, 'kappa_caps'], - ['Λ', 'Λ', true, 'lambda_caps'], - ['Μ', 'Μ', true, 'mu_caps'], - ['Ν', 'Ν', true, 'nu_caps'], - ['Ξ', 'Ξ', true, 'xi_caps'], - ['Ο', 'Ο', true, 'omicron_caps'], - ['Π', 'Π', true, 'pi_caps'], - ['Ρ', 'Ρ', true, 'rho_caps'], - ['Σ', 'Σ', true, 'sigma_caps'], - ['Τ', 'Τ', true, 'tau_caps'], - ['Υ', 'Υ', true, 'upsilon_caps'], - ['Φ', 'Φ', true, 'phi_caps'], - ['Χ', 'Χ', true, 'chi_caps'], - ['Ψ', 'Ψ', true, 'psi_caps'], - ['Ω', 'Ω', true, 'omega_caps'], - ['α', 'α', true, 'alpha'], - ['β', 'β', true, 'beta'], - ['γ', 'γ', true, 'gamma'], - ['δ', 'δ', true, 'delta'], - ['ε', 'ε', true, 'epsilon'], - ['ζ', 'ζ', true, 'zeta'], - ['η', 'η', true, 'eta'], - ['θ', 'θ', true, 'theta'], - ['ι', 'ι', true, 'iota'], - ['κ', 'κ', true, 'kappa'], - ['λ', 'λ', true, 'lambda'], - ['μ', 'μ', true, 'mu'], - ['ν', 'ν', true, 'nu'], - ['ξ', 'ξ', true, 'xi'], - ['ο', 'ο', true, 'omicron'], - ['π', 'π', true, 'pi'], - ['ρ', 'ρ', true, 'rho'], - ['ς', 'ς', true, 'finalsigma'], - ['σ', 'σ', true, 'sigma'], - ['τ', 'τ', true, 'tau'], - ['υ', 'υ', true, 'upsilon'], - ['φ', 'φ', true, 'phi'], - ['χ', 'χ', true, 'chi'], - ['ψ', 'ψ', true, 'psi'], - ['ω', 'ω', true, 'omega'], - // Symbols. - ['ℵ', 'ℵ', false, 'alefsymbol'], - ['ϖ', 'ϖ', false, 'pisymbol'], - ['ℜ', 'ℜ', false, 'realpartsymbol'], - ['ϑ', 'ϑ', false, 'thetasymbol'], - ['ϒ', 'ϒ', false, 'upsilonhooksymbol'], - ['℘', '℘', false, 'weierstrassp'], - ['ℑ', 'ℑ', false, 'imaginarypart'], - // Arrows. - ['←', '←', true, 'leftwardsarrow'], - ['↑', '↑', true, 'upwardsarrow'], - ['→', '→', true, 'rightwardsarrow'], - ['↓', '↓', true, 'downwardsarrow'], - ['↔', '↔', true, 'leftrightarrow'], - ['↵', '↵', false, 'carriagereturn'], - ['⇐', '⇐', false, 'leftwardsdoublearrow'], - ['⇑', '⇑', false, 'upwardsdoublearrow'], - ['⇒', '⇒', false, 'rightwardsdoublearrow'], - ['⇓', '⇓', false, 'downwardsdoublearrow'], - ['⇔', '⇔', false, 'leftrightdoublearrow'], - ['∴', '∴', false, 'therefore'], - ['⊂', '⊂', false, 'subsetof'], - ['⊃', '⊃', false, 'supersetof'], - ['⊄', '⊄', false, 'notasubsetof'], - ['⊆', '⊆', false, 'subsetoforequalto'], - ['⊇', '⊇', false, 'supersetoforequalto'], - ['⊕', '⊕', false, 'circledplus'], - ['⊗', '⊗', false, 'circledtimes'], - ['⊥', '⊥', false, 'perpendicular'], - ['⋅', '⋅', false, 'dotoperator'], - ['⌈', '⌈', false, 'leftceiling'], - ['⌉', '⌉', false, 'rightceiling'], - ['⌊', '⌊', false, 'leftfloor'], - ['⌋', '⌋', false, 'rightfloor'], - ['⟨', '〈', false, 'leftpointinganglebracket'], - ['⟩', '〉', false, 'rightpointinganglebracket'], - ['◊', '◊', true, 'lozenge'], - ['♠', '♠', true, 'blackspadesuit'], - ['♣', '♣', true, 'blackclubsuit'], - ['♥', '♥', true, 'blackheartsuit'], - ['♦', '♦', true, 'blackdiamondsuit'], - [' ', ' ', false, 'enspace'], - [' ', ' ', false, 'emspace'], - [' ', ' ', false, 'thinspace'], - ['‌', '‌', false, 'zerowidthnonjoiner'], - ['‍', '‍', false, 'zerowidthjoiner'], - ['‎', '‎', false, 'lefttorightmark'], - ['‏', '‏', false, 'righttoleftmark'], - ['­', '­', false, 'softhyphen'] - ]; - -/** - * Atto text editor charmap plugin. - * - * @namespace M.atto_charmap - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_charmap').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - this.addButton({ - icon: 'e/special_character', - callback: this._displayDialogue - }); - }, - - /** - * Display the Character Map selector. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('insertcharacter', COMPONENTNAME), - focusAfterHide: true - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile( - '
                          ' + - '{{#each CHARMAP}}' + - '{{#if this.[2]}}' + - '' + - '{{/if}}' + - '{{/each}}' + - '
                          ' - ); - - var content = Y.Node.create(template({ - component: COMPONENTNAME, - CSS: CSS, - CHARMAP: CHARMAP - })); - - content.delegate('click', this._insertChar, '.' + CSS.BUTTON, this); - return content; - }, - - /** - * Insert the picked character into the editor. - * - * @method _insertChar - * @param {EventFacade} e - * @private - */ - _insertChar: function(e) { - var character = e.target.getData('character'); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - var host = this.get('host'); - - // Focus on the last point. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(character); - - // And mark the text area as updated. - this.markUpdated(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-min.js b/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-min.js deleted file mode 100644 index 5feccf6942d..00000000000 --- a/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button-min.js +++ /dev/null @@ -1,2 +0,0 @@ -YUI.add("moodle-atto_charmap-button",function(e,a){var i="atto_charmap",t={BUTTON:"atto_charmap_character",CHARMAP:"atto_charmap_selector"},r=[[" "," ",!0,"nobreakspace"],["&","&",!0,"ampersand"],[""",""",!0,"quotationmark"],["‽","‽",!0,"interrobang"],["¢","¢",!0,"centsign"],["€","€",!0,"eurosign"],["£","£",!0,"poundsign"],["¥","¥",!0,"yensign"],["©","©",!0,"copyrightsign"],["®","®",!0,"registeredsign"],["™","™",!0,"trademarksign"],["‰","‰",!0,"permillesign"],["µ","µ",!0,"microsign"],["·","·",!0,"middledot"],["•","•",!0,"bullet"],["…","…",!0,"threedotleader"],["′","′",!0,"minutesfeet"],["″","″",!0,"secondsinches"],["§","§",!0,"sectionsign"],["¶","¶",!0,"paragraphsign"],["ß","ß",!0,"sharpsesszed"],["‹","‹",!0,"singleleftpointinganglequotationmark"],["›","›",!0,"singlerightpointinganglequotationmark"],["«","«",!0,"leftpointingguillemet"],["»","»",!0,"rightpointingguillemet"],["‘","‘",!0,"leftsinglequotationmark"],["’","’",!0,"rightsinglequotationmark"],["“","“",!0,"leftdoublequotationmark"],["”","”",!0,"rightdoublequotationmark"],["‚","‚",!0,"singlelow9quotationmark"],["„","„",!0,"doublelow9quotationmark"],["<","<",!0,"lessthansign"],[">",">",!0,"greaterthansign"],["≤","≤",!0,"lessthanorequalto"],["≥","≥",!0,"greaterthanorequalto"],["–","–",!0,"endash"],["—","—",!0,"emdash"],["¯","¯",!0,"macron"],["‾","‾",!0,"overline"],["¤","¤",!0,"currencysign"],["¦","¦",!0,"brokenbar"],["¨","¨",!0,"diaeresis"],["¡","¡",!0,"invertedexclamationmark"],["¿","¿",!0,"turnedquestionmark"],["ˆ","ˆ",!0,"circumflexaccent"],["˜","˜",!0,"smalltilde"],["°","°",!0,"degreesign"],["−","−",!0,"minussign"],["±","±",!0,"plusminussign"],["÷","÷",!0,"divisionsign"],["⁄","⁄",!0,"fractionslash"],["×","×",!0,"multiplicationsign"],["¹","¹",!0,"superscriptone"],["²","²",!0,"superscripttwo"],["³","³",!0,"superscriptthree"],["¼","¼",!0,"fractiononequarter"],["½","½",!0,"fractiononehalf"],["¾","¾",!0,"fractionthreequarters"],["ƒ","ƒ",!0,"functionflorin"],["∫","∫",!0,"integral"],["∑","∑",!0,"narysumation"],["∞","∞",!0,"infinity"],["√","√",!0,"squareroot"],["∼","∼",!1,"similarto"],["≅","≅",!1,"approximatelyequalto"],["≈","≈",!0,"almostequalto"],["≠","≠",!0,"notequalto"],["≡","≡",!0,"identicalto"],["∈","∈",!1,"elementof"],["∉","∉",!1,"notanelementof"],["∋","∋",!1,"containsasmember"],["∏","∏",!0,"naryproduct"],["∧","∧",!1,"logicaland"],["∨","∨",!1,"logicalor"],["¬","¬",!0,"notsign"],["∩","∩",!0,"intersection"],["∪","∪",!1,"union"],["∂","∂",!0,"partialdifferential"],["∀","∀",!1,"forall"],["∃","∃",!1,"thereexists"],["∅","∅",!1,"diameter"],["∇","∇",!1,"backwarddifference"],["∗","∗",!1,"asteriskoperator"],["∝","∝",!1,"proportionalto"],["∠","∠",!1,"angle"],["´","´",!0,"acuteaccent"],["¸","¸",!0,"cedilla"],["ª","ª",!0,"feminineordinalindicator"],["º","º",!0,"masculineordinalindicator"],["†","†",!0,"dagger"],["‡","‡",!0,"doubledagger"],["À","À",!0,"agrave_caps"],["Á","Á",!0,"aacute_caps"],["Â","Â",!0,"acircumflex_caps"],["Ã","Ã",!0,"atilde_caps"],["Ä","Ä",!0,"adiaeresis_caps"],["Å","Å",!0,"aringabove_caps"],["Ā","Ā",!0,"amacron_caps"],["Æ","Æ",!0,"ligatureae_caps"],["Ç","Ç",!0,"ccedilla_caps"],["È","È",!0,"egrave_caps"],["É","É",!0,"eacute_caps"],["Ê","Ê",!0,"ecircumflex_caps"],["Ë","Ë",!0,"ediaeresis_caps"],["Ē","Ē",!0,"emacron_caps"],["Ì","Ì",!0,"igrave_caps"],["Í","Í",!0,"iacute_caps"],["Î","Î",!0,"icircumflex_caps"],["Ï","Ï",!0,"idiaeresis_caps"],["Ī","Ī",!0,"imacron_caps"],["Ð","Ð",!0,"eth_caps"],["Ñ","Ñ",!0,"ntilde_caps"],["Ò","Ò",!0,"ograve_caps"],["Ó","Ó",!0,"oacute_caps"],["Ô","Ô",!0,"ocircumflex_caps"],["Õ","Õ",!0,"otilde_caps"],["Ö","Ö",!0,"odiaeresis_caps"],["Ø","Ø",!0,"oslash_caps"],["Ō","Ō",!0,"omacron_caps"],["Œ","Œ",!0,"ligatureoe_caps"],["Š","Š",!0,"scaron_caps"],["Ù","Ù",!0,"ugrave_caps"],["Ú","Ú",!0,"uacute_caps"],["Û","Û",!0,"ucircumflex_caps"],["Ü","Ü",!0,"udiaeresis_caps"],["Ū","Ū",!0,"umacron_caps"],["Ý","Ý",!0,"yacute_caps"],["Ÿ","Ÿ",!0,"ydiaeresis_caps"],["Þ","Þ",!0,"thorn_caps"],["à","à",!0,"agrave"],["á","á",!0,"aacute"],["â","â",!0,"acircumflex"],["ã","ã",!0,"atilde"],["ä","ä",!0,"adiaeresis"],["å","å",!0,"aringabove"],["ā","ā",!0,"amacron"],["æ","æ",!0,"ligatureae"],["ç","ç",!0,"ccedilla"],["è","è",!0,"egrave"],["é","é",!0,"eacute"],["ê","ê",!0,"ecircumflex"],["ë","ë",!0,"ediaeresis"],["ē","ē",!0,"emacron"],["ì","ì",!0,"igrave"],["í","í",!0,"iacute"],["î","î",!0,"icircumflex"],["ï","ï",!0,"idiaeresis"],["ī","ī",!0, -"imacron"],["ð","ð",!0,"eth"],["ñ","ñ",!0,"ntilde"],["ò","ò",!0,"ograve"],["ó","ó",!0,"oacute"],["ô","ô",!0,"ocircumflex"],["õ","õ",!0,"otilde"],["ö","ö",!0,"odiaeresis"],["ø","ø",!0,"oslash"],["ō","ō",!0,"omacron"],["œ","œ",!0,"ligatureoe"],["š","š",!0,"scaron"],["ù","ù",!0,"ugrave"],["ú","ú",!0,"uacute"],["û","û",!0,"ucircumflex"],["ü","ü",!0,"udiaeresis"],["ū","ū",!0,"umacron"],["ý","ý",!0,"yacute"],["þ","þ",!0,"thorn"],["ÿ","ÿ",!0,"ydiaeresis"],["Α","Α",!0,"alpha_caps"],["Β","Β",!0,"beta_caps"],["Γ","Γ",!0,"gamma_caps"],["Δ","Δ",!0,"delta_caps"],["Ε","Ε",!0,"epsilon_caps"],["Ζ","Ζ",!0,"zeta_caps"],["Η","Η",!0,"eta_caps"],["Θ","Θ",!0,"theta_caps"],["Ι","Ι",!0,"iota_caps"],["Κ","Κ",!0,"kappa_caps"],["Λ","Λ",!0,"lambda_caps"],["Μ","Μ",!0,"mu_caps"],["Ν","Ν",!0,"nu_caps"],["Ξ","Ξ",!0,"xi_caps"],["Ο","Ο",!0,"omicron_caps"],["Π","Π",!0,"pi_caps"],["Ρ","Ρ",!0,"rho_caps"],["Σ","Σ",!0,"sigma_caps"],["Τ","Τ",!0,"tau_caps"],["Υ","Υ",!0,"upsilon_caps"],["Φ","Φ",!0,"phi_caps"],["Χ","Χ",!0,"chi_caps"],["Ψ","Ψ",!0,"psi_caps"],["Ω","Ω",!0,"omega_caps"],["α","α",!0,"alpha"],["β","β",!0,"beta"],["γ","γ",!0,"gamma"],["δ","δ",!0,"delta"],["ε","ε",!0,"epsilon"],["ζ","ζ",!0,"zeta"],["η","η",!0,"eta"],["θ","θ",!0,"theta"],["ι","ι",!0,"iota"],["κ","κ",!0,"kappa"],["λ","λ",!0,"lambda"],["μ","μ",!0,"mu"],["ν","ν",!0,"nu"],["ξ","ξ",!0,"xi"],["ο","ο",!0,"omicron"],["π","π",!0,"pi"],["ρ","ρ",!0,"rho"],["ς","ς",!0,"finalsigma"],["σ","σ",!0,"sigma"],["τ","τ",!0,"tau"],["υ","υ",!0,"upsilon"],["φ","φ",!0,"phi"],["χ","χ",!0,"chi"],["ψ","ψ",!0,"psi"],["ω","ω",!0,"omega"],["ℵ","ℵ",!1,"alefsymbol"],["ϖ","ϖ",!1,"pisymbol"],["ℜ","ℜ",!1,"realpartsymbol"],["ϑ","ϑ",!1,"thetasymbol"],["ϒ","ϒ",!1,"upsilonhooksymbol"],["℘","℘",!1,"weierstrassp"],["ℑ","ℑ",!1,"imaginarypart"],["←","←",!0,"leftwardsarrow"],["↑","↑",!0,"upwardsarrow"],["→","→",!0,"rightwardsarrow"],["↓","↓",!0,"downwardsarrow"],["↔","↔",!0,"leftrightarrow"],["↵","↵",!1,"carriagereturn"],["⇐","⇐",!1,"leftwardsdoublearrow"],["⇑","⇑",!1,"upwardsdoublearrow"],["⇒","⇒",!1,"rightwardsdoublearrow"],["⇓","⇓",!1,"downwardsdoublearrow"],["⇔","⇔",!1,"leftrightdoublearrow"],["∴","∴",!1,"therefore"],["⊂","⊂",!1,"subsetof"],["⊃","⊃",!1,"supersetof"],["⊄","⊄",!1,"notasubsetof"],["⊆","⊆",!1,"subsetoforequalto"],["⊇","⊇",!1,"supersetoforequalto"],["⊕","⊕",!1,"circledplus"],["⊗","⊗",!1,"circledtimes"],["⊥","⊥",!1,"perpendicular"],["⋅","⋅",!1,"dotoperator"],["⌈","⌈",!1,"leftceiling"],["⌉","⌉",!1,"rightceiling"],["⌊","⌊",!1,"leftfloor"],["⌋","⌋",!1,"rightfloor"],["⟨","〈",!1,"leftpointinganglebracket"],["⟩","〉",!1,"rightpointinganglebracket"],["◊","◊",!0,"lozenge"],["♠","♠",!0,"blackspadesuit"],["♣","♣",!0,"blackclubsuit"],["♥","♥",!0,"blackheartsuit"],["♦","♦",!0,"blackdiamondsuit"],[" "," ",!1,"enspace"],[" "," ",!1,"emspace"],[" "," ",!1,"thinspace"],["‌","‌",!1,"zerowidthnonjoiner"],["‍","‍",!1,"zerowidthjoiner"],["‎","‎",!1,"lefttorightmark"],["‏","‏",!1,"righttoleftmark"],["­","­",!1,"softhyphen"]];e.namespace("M.atto_charmap").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){this.addButton({icon:"e/special_character",callback:this._displayDialogue})},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&this.getDialogue({headerContent:M.util.get_string("insertcharacter",i),focusAfterHide:!0},!0).set("bodyContent",this._getDialogueContent()).show()},_getDialogueContent:function(){var a=e.Handlebars.compile('
                          {{#each CHARMAP}}{{#if this.[2]}}{{/if}}{{/each}}
                          '),a=e.Node.create(a({component:i,CSS:t,CHARMAP:r}));return a.delegate("click",this._insertChar,"."+t.BUTTON,this),a},_insertChar:function(a){var e,a=a.target.getData("character");this.getDialogue({focusAfterHide:null}).hide(),(e=this.get("host")).setSelection(this._currentSelection),e.insertContentAtFocusPoint(a),this.markUpdated()}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button.js b/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button.js deleted file mode 100644 index 43f1310115a..00000000000 --- a/lib/editor/atto/plugins/charmap/yui/build/moodle-atto_charmap-button/moodle-atto_charmap-button.js +++ /dev/null @@ -1,431 +0,0 @@ -YUI.add('moodle-atto_charmap-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_charmap - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Atto text editor character map plugin - * - * @module moodle-atto_charmap-button - */ - -var COMPONENTNAME = 'atto_charmap', - CSS = { - BUTTON: 'atto_charmap_character', - CHARMAP: 'atto_charmap_selector' - }, - /* - * Map of special characters, kindly borrowed from TinyMCE. - * - * Each entries contains in order: - * - {String} HTML code - * - {String} HTML numerical code - * - {Boolean} Whether or not to include it in the list - * - {String} The language string key - * - * @property CHARMAP - * @type {Array} - */ - CHARMAP = [ - [' ', ' ', true, 'nobreakspace'], - ['&', '&', true, 'ampersand'], - ['"', '"', true, 'quotationmark'], - ['‽', '‽', true, 'interrobang'], - // Finance. - ['¢', '¢', true, 'centsign'], - ['€', '€', true, 'eurosign'], - ['£', '£', true, 'poundsign'], - ['¥', '¥', true, 'yensign'], - // Signs. - ['©', '©', true, 'copyrightsign'], - ['®', '®', true, 'registeredsign'], - ['™', '™', true, 'trademarksign'], - ['‰', '‰', true, 'permillesign'], - ['µ', 'µ', true, 'microsign'], - ['·', '·', true, 'middledot'], - ['•', '•', true, 'bullet'], - ['…', '…', true, 'threedotleader'], - ['′', '′', true, 'minutesfeet'], - ['″', '″', true, 'secondsinches'], - ['§', '§', true, 'sectionsign'], - ['¶', '¶', true, 'paragraphsign'], - ['ß', 'ß', true, 'sharpsesszed'], - // Quotations. - ['‹', '‹', true, 'singleleftpointinganglequotationmark'], - ['›', '›', true, 'singlerightpointinganglequotationmark'], - ['«', '«', true, 'leftpointingguillemet'], - ['»', '»', true, 'rightpointingguillemet'], - ['‘', '‘', true, 'leftsinglequotationmark'], - ['’', '’', true, 'rightsinglequotationmark'], - ['“', '“', true, 'leftdoublequotationmark'], - ['”', '”', true, 'rightdoublequotationmark'], - ['‚', '‚', true, 'singlelow9quotationmark'], - ['„', '„', true, 'doublelow9quotationmark'], - ['<', '<', true, 'lessthansign'], - ['>', '>', true, 'greaterthansign'], - ['≤', '≤', true, 'lessthanorequalto'], - ['≥', '≥', true, 'greaterthanorequalto'], - ['–', '–', true, 'endash'], - ['—', '—', true, 'emdash'], - ['¯', '¯', true, 'macron'], - ['‾', '‾', true, 'overline'], - ['¤', '¤', true, 'currencysign'], - ['¦', '¦', true, 'brokenbar'], - ['¨', '¨', true, 'diaeresis'], - ['¡', '¡', true, 'invertedexclamationmark'], - ['¿', '¿', true, 'turnedquestionmark'], - ['ˆ', 'ˆ', true, 'circumflexaccent'], - ['˜', '˜', true, 'smalltilde'], - ['°', '°', true, 'degreesign'], - ['−', '−', true, 'minussign'], - ['±', '±', true, 'plusminussign'], - ['÷', '÷', true, 'divisionsign'], - ['⁄', '⁄', true, 'fractionslash'], - ['×', '×', true, 'multiplicationsign'], - ['¹', '¹', true, 'superscriptone'], - ['²', '²', true, 'superscripttwo'], - ['³', '³', true, 'superscriptthree'], - ['¼', '¼', true, 'fractiononequarter'], - ['½', '½', true, 'fractiononehalf'], - ['¾', '¾', true, 'fractionthreequarters'], - // Math / logical. - ['ƒ', 'ƒ', true, 'functionflorin'], - ['∫', '∫', true, 'integral'], - ['∑', '∑', true, 'narysumation'], - ['∞', '∞', true, 'infinity'], - ['√', '√', true, 'squareroot'], - ['∼', '∼', false, 'similarto'], - ['≅', '≅', false, 'approximatelyequalto'], - ['≈', '≈', true, 'almostequalto'], - ['≠', '≠', true, 'notequalto'], - ['≡', '≡', true, 'identicalto'], - ['∈', '∈', false, 'elementof'], - ['∉', '∉', false, 'notanelementof'], - ['∋', '∋', false, 'containsasmember'], - ['∏', '∏', true, 'naryproduct'], - ['∧', '∧', false, 'logicaland'], - ['∨', '∨', false, 'logicalor'], - ['¬', '¬', true, 'notsign'], - ['∩', '∩', true, 'intersection'], - ['∪', '∪', false, 'union'], - ['∂', '∂', true, 'partialdifferential'], - ['∀', '∀', false, 'forall'], - ['∃', '∃', false, 'thereexists'], - ['∅', '∅', false, 'diameter'], - ['∇', '∇', false, 'backwarddifference'], - ['∗', '∗', false, 'asteriskoperator'], - ['∝', '∝', false, 'proportionalto'], - ['∠', '∠', false, 'angle'], - // Undefined. - ['´', '´', true, 'acuteaccent'], - ['¸', '¸', true, 'cedilla'], - ['ª', 'ª', true, 'feminineordinalindicator'], - ['º', 'º', true, 'masculineordinalindicator'], - ['†', '†', true, 'dagger'], - ['‡', '‡', true, 'doubledagger'], - // Alphabetical special chars. - ['À', 'À', true, 'agrave_caps'], - ['Á', 'Á', true, 'aacute_caps'], - ['Â', 'Â', true, 'acircumflex_caps'], - ['Ã', 'Ã', true, 'atilde_caps'], - ['Ä', 'Ä', true, 'adiaeresis_caps'], - ['Å', 'Å', true, 'aringabove_caps'], - ['Ā', 'Ā', true, 'amacron_caps'], - ['Æ', 'Æ', true, 'ligatureae_caps'], - ['Ç', 'Ç', true, 'ccedilla_caps'], - ['È', 'È', true, 'egrave_caps'], - ['É', 'É', true, 'eacute_caps'], - ['Ê', 'Ê', true, 'ecircumflex_caps'], - ['Ë', 'Ë', true, 'ediaeresis_caps'], - ['Ē', 'Ē', true, 'emacron_caps'], - ['Ì', 'Ì', true, 'igrave_caps'], - ['Í', 'Í', true, 'iacute_caps'], - ['Î', 'Î', true, 'icircumflex_caps'], - ['Ï', 'Ï', true, 'idiaeresis_caps'], - ['Ī', 'Ī', true, 'imacron_caps'], - ['Ð', 'Ð', true, 'eth_caps'], - ['Ñ', 'Ñ', true, 'ntilde_caps'], - ['Ò', 'Ò', true, 'ograve_caps'], - ['Ó', 'Ó', true, 'oacute_caps'], - ['Ô', 'Ô', true, 'ocircumflex_caps'], - ['Õ', 'Õ', true, 'otilde_caps'], - ['Ö', 'Ö', true, 'odiaeresis_caps'], - ['Ø', 'Ø', true, 'oslash_caps'], - ['Ō', 'Ō', true, 'omacron_caps'], - ['Œ', 'Œ', true, 'ligatureoe_caps'], - ['Š', 'Š', true, 'scaron_caps'], - ['Ù', 'Ù', true, 'ugrave_caps'], - ['Ú', 'Ú', true, 'uacute_caps'], - ['Û', 'Û', true, 'ucircumflex_caps'], - ['Ü', 'Ü', true, 'udiaeresis_caps'], - ['Ū', 'Ū', true, 'umacron_caps'], - ['Ý', 'Ý', true, 'yacute_caps'], - ['Ÿ', 'Ÿ', true, 'ydiaeresis_caps'], - ['Þ', 'Þ', true, 'thorn_caps'], - ['à', 'à', true, 'agrave'], - ['á', 'á', true, 'aacute'], - ['â', 'â', true, 'acircumflex'], - ['ã', 'ã', true, 'atilde'], - ['ä', 'ä', true, 'adiaeresis'], - ['å', 'å', true, 'aringabove'], - ['ā', 'ā', true, 'amacron'], - ['æ', 'æ', true, 'ligatureae'], - ['ç', 'ç', true, 'ccedilla'], - ['è', 'è', true, 'egrave'], - ['é', 'é', true, 'eacute'], - ['ê', 'ê', true, 'ecircumflex'], - ['ë', 'ë', true, 'ediaeresis'], - ['ē', 'ē', true, 'emacron'], - ['ì', 'ì', true, 'igrave'], - ['í', 'í', true, 'iacute'], - ['î', 'î', true, 'icircumflex'], - ['ï', 'ï', true, 'idiaeresis'], - ['ī', 'ī', true, 'imacron'], - ['ð', 'ð', true, 'eth'], - ['ñ', 'ñ', true, 'ntilde'], - ['ò', 'ò', true, 'ograve'], - ['ó', 'ó', true, 'oacute'], - ['ô', 'ô', true, 'ocircumflex'], - ['õ', 'õ', true, 'otilde'], - ['ö', 'ö', true, 'odiaeresis'], - ['ø', 'ø', true, 'oslash'], - ['ō', 'ō', true, 'omacron'], - ['œ', 'œ', true, 'ligatureoe'], - ['š', 'š', true, 'scaron'], - ['ù', 'ù', true, 'ugrave'], - ['ú', 'ú', true, 'uacute'], - ['û', 'û', true, 'ucircumflex'], - ['ü', 'ü', true, 'udiaeresis'], - ['ū', 'ū', true, 'umacron'], - ['ý', 'ý', true, 'yacute'], - ['þ', 'þ', true, 'thorn'], - ['ÿ', 'ÿ', true, 'ydiaeresis'], - ['Α', 'Α', true, 'alpha_caps'], - ['Β', 'Β', true, 'beta_caps'], - ['Γ', 'Γ', true, 'gamma_caps'], - ['Δ', 'Δ', true, 'delta_caps'], - ['Ε', 'Ε', true, 'epsilon_caps'], - ['Ζ', 'Ζ', true, 'zeta_caps'], - ['Η', 'Η', true, 'eta_caps'], - ['Θ', 'Θ', true, 'theta_caps'], - ['Ι', 'Ι', true, 'iota_caps'], - ['Κ', 'Κ', true, 'kappa_caps'], - ['Λ', 'Λ', true, 'lambda_caps'], - ['Μ', 'Μ', true, 'mu_caps'], - ['Ν', 'Ν', true, 'nu_caps'], - ['Ξ', 'Ξ', true, 'xi_caps'], - ['Ο', 'Ο', true, 'omicron_caps'], - ['Π', 'Π', true, 'pi_caps'], - ['Ρ', 'Ρ', true, 'rho_caps'], - ['Σ', 'Σ', true, 'sigma_caps'], - ['Τ', 'Τ', true, 'tau_caps'], - ['Υ', 'Υ', true, 'upsilon_caps'], - ['Φ', 'Φ', true, 'phi_caps'], - ['Χ', 'Χ', true, 'chi_caps'], - ['Ψ', 'Ψ', true, 'psi_caps'], - ['Ω', 'Ω', true, 'omega_caps'], - ['α', 'α', true, 'alpha'], - ['β', 'β', true, 'beta'], - ['γ', 'γ', true, 'gamma'], - ['δ', 'δ', true, 'delta'], - ['ε', 'ε', true, 'epsilon'], - ['ζ', 'ζ', true, 'zeta'], - ['η', 'η', true, 'eta'], - ['θ', 'θ', true, 'theta'], - ['ι', 'ι', true, 'iota'], - ['κ', 'κ', true, 'kappa'], - ['λ', 'λ', true, 'lambda'], - ['μ', 'μ', true, 'mu'], - ['ν', 'ν', true, 'nu'], - ['ξ', 'ξ', true, 'xi'], - ['ο', 'ο', true, 'omicron'], - ['π', 'π', true, 'pi'], - ['ρ', 'ρ', true, 'rho'], - ['ς', 'ς', true, 'finalsigma'], - ['σ', 'σ', true, 'sigma'], - ['τ', 'τ', true, 'tau'], - ['υ', 'υ', true, 'upsilon'], - ['φ', 'φ', true, 'phi'], - ['χ', 'χ', true, 'chi'], - ['ψ', 'ψ', true, 'psi'], - ['ω', 'ω', true, 'omega'], - // Symbols. - ['ℵ', 'ℵ', false, 'alefsymbol'], - ['ϖ', 'ϖ', false, 'pisymbol'], - ['ℜ', 'ℜ', false, 'realpartsymbol'], - ['ϑ', 'ϑ', false, 'thetasymbol'], - ['ϒ', 'ϒ', false, 'upsilonhooksymbol'], - ['℘', '℘', false, 'weierstrassp'], - ['ℑ', 'ℑ', false, 'imaginarypart'], - // Arrows. - ['←', '←', true, 'leftwardsarrow'], - ['↑', '↑', true, 'upwardsarrow'], - ['→', '→', true, 'rightwardsarrow'], - ['↓', '↓', true, 'downwardsarrow'], - ['↔', '↔', true, 'leftrightarrow'], - ['↵', '↵', false, 'carriagereturn'], - ['⇐', '⇐', false, 'leftwardsdoublearrow'], - ['⇑', '⇑', false, 'upwardsdoublearrow'], - ['⇒', '⇒', false, 'rightwardsdoublearrow'], - ['⇓', '⇓', false, 'downwardsdoublearrow'], - ['⇔', '⇔', false, 'leftrightdoublearrow'], - ['∴', '∴', false, 'therefore'], - ['⊂', '⊂', false, 'subsetof'], - ['⊃', '⊃', false, 'supersetof'], - ['⊄', '⊄', false, 'notasubsetof'], - ['⊆', '⊆', false, 'subsetoforequalto'], - ['⊇', '⊇', false, 'supersetoforequalto'], - ['⊕', '⊕', false, 'circledplus'], - ['⊗', '⊗', false, 'circledtimes'], - ['⊥', '⊥', false, 'perpendicular'], - ['⋅', '⋅', false, 'dotoperator'], - ['⌈', '⌈', false, 'leftceiling'], - ['⌉', '⌉', false, 'rightceiling'], - ['⌊', '⌊', false, 'leftfloor'], - ['⌋', '⌋', false, 'rightfloor'], - ['⟨', '〈', false, 'leftpointinganglebracket'], - ['⟩', '〉', false, 'rightpointinganglebracket'], - ['◊', '◊', true, 'lozenge'], - ['♠', '♠', true, 'blackspadesuit'], - ['♣', '♣', true, 'blackclubsuit'], - ['♥', '♥', true, 'blackheartsuit'], - ['♦', '♦', true, 'blackdiamondsuit'], - [' ', ' ', false, 'enspace'], - [' ', ' ', false, 'emspace'], - [' ', ' ', false, 'thinspace'], - ['‌', '‌', false, 'zerowidthnonjoiner'], - ['‍', '‍', false, 'zerowidthjoiner'], - ['‎', '‎', false, 'lefttorightmark'], - ['‏', '‏', false, 'righttoleftmark'], - ['­', '­', false, 'softhyphen'] - ]; - -/** - * Atto text editor charmap plugin. - * - * @namespace M.atto_charmap - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_charmap').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - this.addButton({ - icon: 'e/special_character', - callback: this._displayDialogue - }); - }, - - /** - * Display the Character Map selector. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('insertcharacter', COMPONENTNAME), - focusAfterHide: true - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile( - '
                          ' + - '{{#each CHARMAP}}' + - '{{#if this.[2]}}' + - '' + - '{{/if}}' + - '{{/each}}' + - '
                          ' - ); - - var content = Y.Node.create(template({ - component: COMPONENTNAME, - CSS: CSS, - CHARMAP: CHARMAP - })); - - content.delegate('click', this._insertChar, '.' + CSS.BUTTON, this); - return content; - }, - - /** - * Insert the picked character into the editor. - * - * @method _insertChar - * @param {EventFacade} e - * @private - */ - _insertChar: function(e) { - var character = e.target.getData('character'); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - var host = this.get('host'); - - // Focus on the last point. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(character); - - // And mark the text area as updated. - this.markUpdated(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/charmap/yui/src/button/build.json b/lib/editor/atto/plugins/charmap/yui/src/button/build.json deleted file mode 100644 index 71d2a089737..00000000000 --- a/lib/editor/atto/plugins/charmap/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_charmap-button", - "builds": { - "moodle-atto_charmap-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/charmap/yui/src/button/js/button.js b/lib/editor/atto/plugins/charmap/yui/src/button/js/button.js deleted file mode 100644 index 395edf40980..00000000000 --- a/lib/editor/atto/plugins/charmap/yui/src/button/js/button.js +++ /dev/null @@ -1,426 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_charmap - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Atto text editor character map plugin - * - * @module moodle-atto_charmap-button - */ - -var COMPONENTNAME = 'atto_charmap', - CSS = { - BUTTON: 'atto_charmap_character', - CHARMAP: 'atto_charmap_selector' - }, - /* - * Map of special characters, kindly borrowed from TinyMCE. - * - * Each entries contains in order: - * - {String} HTML code - * - {String} HTML numerical code - * - {Boolean} Whether or not to include it in the list - * - {String} The language string key - * - * @property CHARMAP - * @type {Array} - */ - CHARMAP = [ - [' ', ' ', true, 'nobreakspace'], - ['&', '&', true, 'ampersand'], - ['"', '"', true, 'quotationmark'], - ['‽', '‽', true, 'interrobang'], - // Finance. - ['¢', '¢', true, 'centsign'], - ['€', '€', true, 'eurosign'], - ['£', '£', true, 'poundsign'], - ['¥', '¥', true, 'yensign'], - // Signs. - ['©', '©', true, 'copyrightsign'], - ['®', '®', true, 'registeredsign'], - ['™', '™', true, 'trademarksign'], - ['‰', '‰', true, 'permillesign'], - ['µ', 'µ', true, 'microsign'], - ['·', '·', true, 'middledot'], - ['•', '•', true, 'bullet'], - ['…', '…', true, 'threedotleader'], - ['′', '′', true, 'minutesfeet'], - ['″', '″', true, 'secondsinches'], - ['§', '§', true, 'sectionsign'], - ['¶', '¶', true, 'paragraphsign'], - ['ß', 'ß', true, 'sharpsesszed'], - // Quotations. - ['‹', '‹', true, 'singleleftpointinganglequotationmark'], - ['›', '›', true, 'singlerightpointinganglequotationmark'], - ['«', '«', true, 'leftpointingguillemet'], - ['»', '»', true, 'rightpointingguillemet'], - ['‘', '‘', true, 'leftsinglequotationmark'], - ['’', '’', true, 'rightsinglequotationmark'], - ['“', '“', true, 'leftdoublequotationmark'], - ['”', '”', true, 'rightdoublequotationmark'], - ['‚', '‚', true, 'singlelow9quotationmark'], - ['„', '„', true, 'doublelow9quotationmark'], - ['<', '<', true, 'lessthansign'], - ['>', '>', true, 'greaterthansign'], - ['≤', '≤', true, 'lessthanorequalto'], - ['≥', '≥', true, 'greaterthanorequalto'], - ['–', '–', true, 'endash'], - ['—', '—', true, 'emdash'], - ['¯', '¯', true, 'macron'], - ['‾', '‾', true, 'overline'], - ['¤', '¤', true, 'currencysign'], - ['¦', '¦', true, 'brokenbar'], - ['¨', '¨', true, 'diaeresis'], - ['¡', '¡', true, 'invertedexclamationmark'], - ['¿', '¿', true, 'turnedquestionmark'], - ['ˆ', 'ˆ', true, 'circumflexaccent'], - ['˜', '˜', true, 'smalltilde'], - ['°', '°', true, 'degreesign'], - ['−', '−', true, 'minussign'], - ['±', '±', true, 'plusminussign'], - ['÷', '÷', true, 'divisionsign'], - ['⁄', '⁄', true, 'fractionslash'], - ['×', '×', true, 'multiplicationsign'], - ['¹', '¹', true, 'superscriptone'], - ['²', '²', true, 'superscripttwo'], - ['³', '³', true, 'superscriptthree'], - ['¼', '¼', true, 'fractiononequarter'], - ['½', '½', true, 'fractiononehalf'], - ['¾', '¾', true, 'fractionthreequarters'], - // Math / logical. - ['ƒ', 'ƒ', true, 'functionflorin'], - ['∫', '∫', true, 'integral'], - ['∑', '∑', true, 'narysumation'], - ['∞', '∞', true, 'infinity'], - ['√', '√', true, 'squareroot'], - ['∼', '∼', false, 'similarto'], - ['≅', '≅', false, 'approximatelyequalto'], - ['≈', '≈', true, 'almostequalto'], - ['≠', '≠', true, 'notequalto'], - ['≡', '≡', true, 'identicalto'], - ['∈', '∈', false, 'elementof'], - ['∉', '∉', false, 'notanelementof'], - ['∋', '∋', false, 'containsasmember'], - ['∏', '∏', true, 'naryproduct'], - ['∧', '∧', false, 'logicaland'], - ['∨', '∨', false, 'logicalor'], - ['¬', '¬', true, 'notsign'], - ['∩', '∩', true, 'intersection'], - ['∪', '∪', false, 'union'], - ['∂', '∂', true, 'partialdifferential'], - ['∀', '∀', false, 'forall'], - ['∃', '∃', false, 'thereexists'], - ['∅', '∅', false, 'diameter'], - ['∇', '∇', false, 'backwarddifference'], - ['∗', '∗', false, 'asteriskoperator'], - ['∝', '∝', false, 'proportionalto'], - ['∠', '∠', false, 'angle'], - // Undefined. - ['´', '´', true, 'acuteaccent'], - ['¸', '¸', true, 'cedilla'], - ['ª', 'ª', true, 'feminineordinalindicator'], - ['º', 'º', true, 'masculineordinalindicator'], - ['†', '†', true, 'dagger'], - ['‡', '‡', true, 'doubledagger'], - // Alphabetical special chars. - ['À', 'À', true, 'agrave_caps'], - ['Á', 'Á', true, 'aacute_caps'], - ['Â', 'Â', true, 'acircumflex_caps'], - ['Ã', 'Ã', true, 'atilde_caps'], - ['Ä', 'Ä', true, 'adiaeresis_caps'], - ['Å', 'Å', true, 'aringabove_caps'], - ['Ā', 'Ā', true, 'amacron_caps'], - ['Æ', 'Æ', true, 'ligatureae_caps'], - ['Ç', 'Ç', true, 'ccedilla_caps'], - ['È', 'È', true, 'egrave_caps'], - ['É', 'É', true, 'eacute_caps'], - ['Ê', 'Ê', true, 'ecircumflex_caps'], - ['Ë', 'Ë', true, 'ediaeresis_caps'], - ['Ē', 'Ē', true, 'emacron_caps'], - ['Ì', 'Ì', true, 'igrave_caps'], - ['Í', 'Í', true, 'iacute_caps'], - ['Î', 'Î', true, 'icircumflex_caps'], - ['Ï', 'Ï', true, 'idiaeresis_caps'], - ['Ī', 'Ī', true, 'imacron_caps'], - ['Ð', 'Ð', true, 'eth_caps'], - ['Ñ', 'Ñ', true, 'ntilde_caps'], - ['Ò', 'Ò', true, 'ograve_caps'], - ['Ó', 'Ó', true, 'oacute_caps'], - ['Ô', 'Ô', true, 'ocircumflex_caps'], - ['Õ', 'Õ', true, 'otilde_caps'], - ['Ö', 'Ö', true, 'odiaeresis_caps'], - ['Ø', 'Ø', true, 'oslash_caps'], - ['Ō', 'Ō', true, 'omacron_caps'], - ['Œ', 'Œ', true, 'ligatureoe_caps'], - ['Š', 'Š', true, 'scaron_caps'], - ['Ù', 'Ù', true, 'ugrave_caps'], - ['Ú', 'Ú', true, 'uacute_caps'], - ['Û', 'Û', true, 'ucircumflex_caps'], - ['Ü', 'Ü', true, 'udiaeresis_caps'], - ['Ū', 'Ū', true, 'umacron_caps'], - ['Ý', 'Ý', true, 'yacute_caps'], - ['Ÿ', 'Ÿ', true, 'ydiaeresis_caps'], - ['Þ', 'Þ', true, 'thorn_caps'], - ['à', 'à', true, 'agrave'], - ['á', 'á', true, 'aacute'], - ['â', 'â', true, 'acircumflex'], - ['ã', 'ã', true, 'atilde'], - ['ä', 'ä', true, 'adiaeresis'], - ['å', 'å', true, 'aringabove'], - ['ā', 'ā', true, 'amacron'], - ['æ', 'æ', true, 'ligatureae'], - ['ç', 'ç', true, 'ccedilla'], - ['è', 'è', true, 'egrave'], - ['é', 'é', true, 'eacute'], - ['ê', 'ê', true, 'ecircumflex'], - ['ë', 'ë', true, 'ediaeresis'], - ['ē', 'ē', true, 'emacron'], - ['ì', 'ì', true, 'igrave'], - ['í', 'í', true, 'iacute'], - ['î', 'î', true, 'icircumflex'], - ['ï', 'ï', true, 'idiaeresis'], - ['ī', 'ī', true, 'imacron'], - ['ð', 'ð', true, 'eth'], - ['ñ', 'ñ', true, 'ntilde'], - ['ò', 'ò', true, 'ograve'], - ['ó', 'ó', true, 'oacute'], - ['ô', 'ô', true, 'ocircumflex'], - ['õ', 'õ', true, 'otilde'], - ['ö', 'ö', true, 'odiaeresis'], - ['ø', 'ø', true, 'oslash'], - ['ō', 'ō', true, 'omacron'], - ['œ', 'œ', true, 'ligatureoe'], - ['š', 'š', true, 'scaron'], - ['ù', 'ù', true, 'ugrave'], - ['ú', 'ú', true, 'uacute'], - ['û', 'û', true, 'ucircumflex'], - ['ü', 'ü', true, 'udiaeresis'], - ['ū', 'ū', true, 'umacron'], - ['ý', 'ý', true, 'yacute'], - ['þ', 'þ', true, 'thorn'], - ['ÿ', 'ÿ', true, 'ydiaeresis'], - ['Α', 'Α', true, 'alpha_caps'], - ['Β', 'Β', true, 'beta_caps'], - ['Γ', 'Γ', true, 'gamma_caps'], - ['Δ', 'Δ', true, 'delta_caps'], - ['Ε', 'Ε', true, 'epsilon_caps'], - ['Ζ', 'Ζ', true, 'zeta_caps'], - ['Η', 'Η', true, 'eta_caps'], - ['Θ', 'Θ', true, 'theta_caps'], - ['Ι', 'Ι', true, 'iota_caps'], - ['Κ', 'Κ', true, 'kappa_caps'], - ['Λ', 'Λ', true, 'lambda_caps'], - ['Μ', 'Μ', true, 'mu_caps'], - ['Ν', 'Ν', true, 'nu_caps'], - ['Ξ', 'Ξ', true, 'xi_caps'], - ['Ο', 'Ο', true, 'omicron_caps'], - ['Π', 'Π', true, 'pi_caps'], - ['Ρ', 'Ρ', true, 'rho_caps'], - ['Σ', 'Σ', true, 'sigma_caps'], - ['Τ', 'Τ', true, 'tau_caps'], - ['Υ', 'Υ', true, 'upsilon_caps'], - ['Φ', 'Φ', true, 'phi_caps'], - ['Χ', 'Χ', true, 'chi_caps'], - ['Ψ', 'Ψ', true, 'psi_caps'], - ['Ω', 'Ω', true, 'omega_caps'], - ['α', 'α', true, 'alpha'], - ['β', 'β', true, 'beta'], - ['γ', 'γ', true, 'gamma'], - ['δ', 'δ', true, 'delta'], - ['ε', 'ε', true, 'epsilon'], - ['ζ', 'ζ', true, 'zeta'], - ['η', 'η', true, 'eta'], - ['θ', 'θ', true, 'theta'], - ['ι', 'ι', true, 'iota'], - ['κ', 'κ', true, 'kappa'], - ['λ', 'λ', true, 'lambda'], - ['μ', 'μ', true, 'mu'], - ['ν', 'ν', true, 'nu'], - ['ξ', 'ξ', true, 'xi'], - ['ο', 'ο', true, 'omicron'], - ['π', 'π', true, 'pi'], - ['ρ', 'ρ', true, 'rho'], - ['ς', 'ς', true, 'finalsigma'], - ['σ', 'σ', true, 'sigma'], - ['τ', 'τ', true, 'tau'], - ['υ', 'υ', true, 'upsilon'], - ['φ', 'φ', true, 'phi'], - ['χ', 'χ', true, 'chi'], - ['ψ', 'ψ', true, 'psi'], - ['ω', 'ω', true, 'omega'], - // Symbols. - ['ℵ', 'ℵ', false, 'alefsymbol'], - ['ϖ', 'ϖ', false, 'pisymbol'], - ['ℜ', 'ℜ', false, 'realpartsymbol'], - ['ϑ', 'ϑ', false, 'thetasymbol'], - ['ϒ', 'ϒ', false, 'upsilonhooksymbol'], - ['℘', '℘', false, 'weierstrassp'], - ['ℑ', 'ℑ', false, 'imaginarypart'], - // Arrows. - ['←', '←', true, 'leftwardsarrow'], - ['↑', '↑', true, 'upwardsarrow'], - ['→', '→', true, 'rightwardsarrow'], - ['↓', '↓', true, 'downwardsarrow'], - ['↔', '↔', true, 'leftrightarrow'], - ['↵', '↵', false, 'carriagereturn'], - ['⇐', '⇐', false, 'leftwardsdoublearrow'], - ['⇑', '⇑', false, 'upwardsdoublearrow'], - ['⇒', '⇒', false, 'rightwardsdoublearrow'], - ['⇓', '⇓', false, 'downwardsdoublearrow'], - ['⇔', '⇔', false, 'leftrightdoublearrow'], - ['∴', '∴', false, 'therefore'], - ['⊂', '⊂', false, 'subsetof'], - ['⊃', '⊃', false, 'supersetof'], - ['⊄', '⊄', false, 'notasubsetof'], - ['⊆', '⊆', false, 'subsetoforequalto'], - ['⊇', '⊇', false, 'supersetoforequalto'], - ['⊕', '⊕', false, 'circledplus'], - ['⊗', '⊗', false, 'circledtimes'], - ['⊥', '⊥', false, 'perpendicular'], - ['⋅', '⋅', false, 'dotoperator'], - ['⌈', '⌈', false, 'leftceiling'], - ['⌉', '⌉', false, 'rightceiling'], - ['⌊', '⌊', false, 'leftfloor'], - ['⌋', '⌋', false, 'rightfloor'], - ['⟨', '〈', false, 'leftpointinganglebracket'], - ['⟩', '〉', false, 'rightpointinganglebracket'], - ['◊', '◊', true, 'lozenge'], - ['♠', '♠', true, 'blackspadesuit'], - ['♣', '♣', true, 'blackclubsuit'], - ['♥', '♥', true, 'blackheartsuit'], - ['♦', '♦', true, 'blackdiamondsuit'], - [' ', ' ', false, 'enspace'], - [' ', ' ', false, 'emspace'], - [' ', ' ', false, 'thinspace'], - ['‌', '‌', false, 'zerowidthnonjoiner'], - ['‍', '‍', false, 'zerowidthjoiner'], - ['‎', '‎', false, 'lefttorightmark'], - ['‏', '‏', false, 'righttoleftmark'], - ['­', '­', false, 'softhyphen'] - ]; - -/** - * Atto text editor charmap plugin. - * - * @namespace M.atto_charmap - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_charmap').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - this.addButton({ - icon: 'e/special_character', - callback: this._displayDialogue - }); - }, - - /** - * Display the Character Map selector. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('insertcharacter', COMPONENTNAME), - focusAfterHide: true - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Return the dialogue content for the tool. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile( - '
                          ' + - '{{#each CHARMAP}}' + - '{{#if this.[2]}}' + - '' + - '{{/if}}' + - '{{/each}}' + - '
                          ' - ); - - var content = Y.Node.create(template({ - component: COMPONENTNAME, - CSS: CSS, - CHARMAP: CHARMAP - })); - - content.delegate('click', this._insertChar, '.' + CSS.BUTTON, this); - return content; - }, - - /** - * Insert the picked character into the editor. - * - * @method _insertChar - * @param {EventFacade} e - * @private - */ - _insertChar: function(e) { - var character = e.target.getData('character'); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - var host = this.get('host'); - - // Focus on the last point. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(character); - - // And mark the text area as updated. - this.markUpdated(); - } -}); diff --git a/lib/editor/atto/plugins/charmap/yui/src/button/meta/button.json b/lib/editor/atto/plugins/charmap/yui/src/button/meta/button.json deleted file mode 100644 index 46d3d5e9b78..00000000000 --- a/lib/editor/atto/plugins/charmap/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_charmap-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/clear/classes/privacy/provider.php b/lib/editor/atto/plugins/clear/classes/privacy/provider.php deleted file mode 100644 index f1a58c471f7..00000000000 --- a/lib/editor/atto/plugins/clear/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_clear - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_clear\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_clear implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/clear/lang/en/atto_clear.php b/lib/editor/atto/plugins/clear/lang/en/atto_clear.php deleted file mode 100644 index 7ee632d2664..00000000000 --- a/lib/editor/atto/plugins/clear/lang/en/atto_clear.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_clear', language 'en'. - * - * @package atto_clear - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Clear formatting'; -$string['privacy:metadata'] = 'The atto_clear plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/clear/tests/behat/clear.feature b/lib/editor/atto/plugins/clear/tests/behat/clear.feature deleted file mode 100644 index 883aaf51c3f..00000000000 --- a/lib/editor/atto/plugins/clear/tests/behat/clear.feature +++ /dev/null @@ -1,21 +0,0 @@ -@editor @editor_atto @atto @atto_clear @_bug_phantomjs -Feature: Atto clear button - To format text in Atto, I need to remove formatting - - @javascript - Scenario: Clear formatting - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Pisa" - And I select the text in the "Description" Atto editor - And I click on "Italic" "button" - And I click on "Show more buttons" "button" - And I select the text in the "Description" Atto editor - When I click on "Clear formatting" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should not see "Pisa" diff --git a/lib/editor/atto/plugins/clear/version.php b/lib/editor/atto/plugins/clear/version.php deleted file mode 100644 index 40a1fe8bf34..00000000000 --- a/lib/editor/atto/plugins/clear/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_clear - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_clear'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-debug.js b/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-debug.js deleted file mode 100644 index abd59108660..00000000000 --- a/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-debug.js +++ /dev/null @@ -1,46 +0,0 @@ -YUI.add('moodle-atto_clear-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_clear - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_clear-button - */ - -/** - * Atto text editor clear plugin. - * - * @namespace M.atto_clear - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_clear').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'removeFormat', - icon: 'e/clear_formatting' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-min.js b/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-min.js deleted file mode 100644 index 8fc2f891941..00000000000 --- a/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_clear-button",function(t,o){t.namespace("M.atto_clear").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addBasicButton({exec:"removeFormat",icon:"e/clear_formatting"})}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button.js b/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button.js deleted file mode 100644 index abd59108660..00000000000 --- a/lib/editor/atto/plugins/clear/yui/build/moodle-atto_clear-button/moodle-atto_clear-button.js +++ /dev/null @@ -1,46 +0,0 @@ -YUI.add('moodle-atto_clear-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_clear - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_clear-button - */ - -/** - * Atto text editor clear plugin. - * - * @namespace M.atto_clear - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_clear').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'removeFormat', - icon: 'e/clear_formatting' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/clear/yui/src/button/build.json b/lib/editor/atto/plugins/clear/yui/src/button/build.json deleted file mode 100644 index aeee2de6040..00000000000 --- a/lib/editor/atto/plugins/clear/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_clear-button", - "builds": { - "moodle-atto_clear-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/clear/yui/src/button/js/button.js b/lib/editor/atto/plugins/clear/yui/src/button/js/button.js deleted file mode 100644 index 6d4fc5583fc..00000000000 --- a/lib/editor/atto/plugins/clear/yui/src/button/js/button.js +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_clear - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_clear-button - */ - -/** - * Atto text editor clear plugin. - * - * @namespace M.atto_clear - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_clear').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'removeFormat', - icon: 'e/clear_formatting' - }); - } -}); diff --git a/lib/editor/atto/plugins/clear/yui/src/button/meta/button.json b/lib/editor/atto/plugins/clear/yui/src/button/meta/button.json deleted file mode 100644 index 10697073e4d..00000000000 --- a/lib/editor/atto/plugins/clear/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_clear-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/collapse/classes/privacy/provider.php b/lib/editor/atto/plugins/collapse/classes/privacy/provider.php deleted file mode 100644 index 74b37ac80e3..00000000000 --- a/lib/editor/atto/plugins/collapse/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_collapse - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_collapse\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_collapse implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/collapse/lang/en/atto_collapse.php b/lib/editor/atto/plugins/collapse/lang/en/atto_collapse.php deleted file mode 100644 index 0cda4b16eac..00000000000 --- a/lib/editor/atto/plugins/collapse/lang/en/atto_collapse.php +++ /dev/null @@ -1,32 +0,0 @@ -. - -/** - * Strings for component 'atto_collapse', language 'en'. - * - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Show/hide advanced buttons'; -$string['privacy:metadata'] = 'The atto_collapse plugin does not store any personal data.'; -$string['settings'] = 'Collapse toolbar settings'; -$string['showfewer'] = 'Show fewer buttons'; -$string['showgroups'] = 'Show first (n) groups when collapsed.'; -$string['showgroups_desc'] = 'When the toolbar is collapsed (it is by default) only this many groups will be displayed at once.'; -$string['showmore'] = 'Show more buttons'; -$string['youareonsecondrow'] = 'You are now on another row of the editor\'s toolbar, where there are more buttons.'; diff --git a/lib/editor/atto/plugins/collapse/lib.php b/lib/editor/atto/plugins/collapse/lib.php deleted file mode 100644 index 5f243ce7e56..00000000000 --- a/lib/editor/atto/plugins/collapse/lib.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the js strings required for this module. - */ -function atto_collapse_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('showmore', 'showfewer', 'youareonsecondrow'), 'atto_collapse'); -} - -/** - * Set params for this plugin - * @param string $elementid - */ -function atto_collapse_params_for_js($elementid, $options, $fpoptions) { - // Pass the number of visible groups as a param. - $params = array('showgroups' => get_config('atto_collapse', 'showgroups')); - return $params; -} - -/** - * Map icons for font-awesome themes. - */ -function atto_collapse_get_fontawesome_icon_map() { - return [ - 'atto_collapse:icon' => 'fa-chevron-down', - ]; -} diff --git a/lib/editor/atto/plugins/collapse/pix/icon.svg b/lib/editor/atto/plugins/collapse/pix/icon.svg deleted file mode 100644 index 1ff953818ed..00000000000 --- a/lib/editor/atto/plugins/collapse/pix/icon.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/editor/atto/plugins/collapse/settings.php b/lib/editor/atto/plugins/collapse/settings.php deleted file mode 100644 index 5fd521b90e9..00000000000 --- a/lib/editor/atto/plugins/collapse/settings.php +++ /dev/null @@ -1,43 +0,0 @@ -. - -/** - * Settings that allow configuration of the list of tex examples in the equation editor. - * - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$ADMIN->add('editoratto', new admin_category('atto_collapse', new lang_string('pluginname', 'atto_collapse'))); - -$settings = new admin_settingpage('atto_collapse_settings', new lang_string('settings', 'atto_collapse')); -if ($ADMIN->fulltree) { - // Number of groups to show when collapsed. - $name = new lang_string('showgroups', 'atto_collapse'); - $desc = new lang_string('showgroups_desc', 'atto_collapse'); - $default = 6; - $options = array_combine(range(1, 20), range(1, 20)); - - $setting = new admin_setting_configselect('atto_collapse/showgroups', - $name, - $desc, - $default, - $options); - $settings->add($setting); -} diff --git a/lib/editor/atto/plugins/collapse/styles.css b/lib/editor/atto/plugins/collapse/styles.css deleted file mode 100644 index dea44eccf2d..00000000000 --- a/lib/editor/atto/plugins/collapse/styles.css +++ /dev/null @@ -1,5 +0,0 @@ -@media (max-width: 768px) { - .toolbarbreak { - display: none; - } -} \ No newline at end of file diff --git a/lib/editor/atto/plugins/collapse/tests/behat/collapse.feature b/lib/editor/atto/plugins/collapse/tests/behat/collapse.feature deleted file mode 100644 index ef2823be114..00000000000 --- a/lib/editor/atto/plugins/collapse/tests/behat/collapse.feature +++ /dev/null @@ -1,12 +0,0 @@ -@editor @editor_atto @atto @atto_collapse -Feature: Atto collapse button - To access all the tools in Atto, I need to toggle the toolbar - - @javascript - Scenario: Toggle toolbar - Given I log in as "admin" - And I open my profile in edit mode - When I click on "Show more buttons" "button" - Then "Equation editor" "button" should be visible - And I click on "Show fewer buttons" "button" - Then "Equation editor" "button" should not be visible diff --git a/lib/editor/atto/plugins/collapse/version.php b/lib/editor/atto/plugins/collapse/version.php deleted file mode 100644 index f872c14d2bb..00000000000 --- a/lib/editor/atto/plugins/collapse/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_collapse'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js b/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js deleted file mode 100644 index 115d08413fb..00000000000 --- a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js +++ /dev/null @@ -1,153 +0,0 @@ -YUI.add('moodle-atto_collapse-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_collapse-button - */ - -/** - * Atto text editor collapse plugin. - * - * @namespace M.atto_collapse - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var PLUGINNAME = 'atto_collapse', - ATTRSHOWGROUPS = 'showgroups', - COLLAPSE = 'collapse', - COLLAPSED = 'collapsed', - GROUPS = '.atto_group', - ROWS = '.atto_toolbar_row'; - -Y.namespace('M.atto_collapse').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var toolbarGroupCount = Y.Object.size(this.get('host').get('plugins')); - if (toolbarGroupCount <= 1 + parseInt(this.get(ATTRSHOWGROUPS), 10)) { - Y.log("There are not enough groups to require toggling - not adding the button", - 'debug', 'moodle-atto_collapse'); - return; - } - - if (this.toolbar.all(GROUPS).size() > this.get(ATTRSHOWGROUPS)) { - Y.log("The collapse plugin is shown after it's cut-off - not adding the button", - 'debug', 'moodle-atto_collapse'); - return; - } - - var button = this.addButton({ - icon: 'icon', - iconComponent: PLUGINNAME, - callback: this._toggle - }); - - // Perform a toggle after all plugins have been loaded for the first time. - this.get('host').on('pluginsloaded', function(e, button) { - // Add 2 rows in the toolbar. - var toolbarRows = [ - Y.Node.create('
                          '), - Y.Node.create('
                          '), - ]; - this.toolbar.appendChild(toolbarRows[0]).insert(toolbarRows[1], 'after'); - - // Split toolbar buttons between the 2 rows created above. - var buttonGroups = this.toolbar.all(GROUPS); - buttonGroups.slice(0, this.get(ATTRSHOWGROUPS)).each(function(buttonGroup) { - toolbarRows[0].appendChild(buttonGroup); - }); - buttonGroups.slice(this.get(ATTRSHOWGROUPS)).each(function(buttonGroup) { - toolbarRows[1].appendChild(buttonGroup); - }); - - this._setVisibility(button); - button.setAttribute('aria-expanded', 'false'); - }, this, button); - }, - - /** - * Toggle the visibility of the extra groups in the toolbar. - * - * @method _toggle - * @param {EventFacade} e - * @private - */ - _toggle: function(e) { - e.preventDefault(); - var button = this.buttons[COLLAPSE]; - - if (button.getData(COLLAPSED)) { - this.highlightButtons(COLLAPSE); - this._setVisibility(button, true); - this.toolbar.all(ROWS).item(1).focus(); - } else { - this.unHighlightButtons(COLLAPSE); - this._setVisibility(button); - this.buttons[this.name].focus(); - } - }, - - /** - * Set the visibility of the toolbar groups. - * - * @method _setVisibility - * @param {Node} button The collapse button - * @param {Booelan} visibility Whether the groups should be made visible - * @private - */ - _setVisibility: function(button, visibility) { - var secondaryRow = this.toolbar.all(ROWS).item(1); - - if (visibility) { - button.set('title', M.util.get_string('showfewer', PLUGINNAME)); - secondaryRow.show(); - button.setData(COLLAPSED, false); - button.setAttribute('aria-expanded', 'true'); - } else { - button.set('title', M.util.get_string('showmore', PLUGINNAME)); - secondaryRow.hide(); - button.setData(COLLAPSED, true); - button.setAttribute('aria-expanded', 'false'); - } - - // We don't want to have both aria-pressed and aria-expanded set. So we remove aria-pressed here. - button.removeAttribute('aria-pressed'); - } -}, { - ATTRS: { - /** - * How many groups to show when collapsed. - * - * @attribute showgroups - * @type Number - * @default 3 - */ - showgroups: { - value: 3 - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js b/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js deleted file mode 100644 index b1d105fc3ec..00000000000 --- a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_collapse-button",function(s,t){var a="atto_collapse",l="showgroups",e="collapse",o="collapsed",r=".atto_group",n=".atto_toolbar_row";s.namespace("M.atto_collapse").Button=s.Base.create("button",s.M.editor_atto.EditorPlugin,[],{initializer:function(){var t=s.Object.size(this.get("host").get("plugins"));t<=1+parseInt(this.get(l),10)||this.toolbar.all(r).size()>this.get(l)||(t=this.addButton({icon:"icon",iconComponent:a,callback:this._toggle}),this.get("host").on("pluginsloaded",function(t,e){var i,o=[s.Node.create('
                          '),s.Node.create('
                          ')];this.toolbar.appendChild(o[0]).insert(o[1],"after"),(i=this.toolbar.all(r)).slice(0,this.get(l)).each(function(t){o[0].appendChild(t)}),i.slice(this.get(l)).each(function(t){o[1].appendChild(t)}),this._setVisibility(e),e.setAttribute("aria-expanded","false")},this,t))},_toggle:function(t){t.preventDefault();t=this.buttons[e];t.getData(o)?(this.highlightButtons(e),this._setVisibility(t,!0),this.toolbar.all(n).item(1).focus()):(this.unHighlightButtons(e),this._setVisibility(t),this.buttons[this.name].focus())},_setVisibility:function(t,e){var i=this.toolbar.all(n).item(1);e?(t.set("title",M.util.get_string("showfewer",a)),i.show(),t.setData(o,!1),t.setAttribute("aria-expanded","true")):(t.set("title",M.util.get_string("showmore",a)),i.hide(),t.setData(o,!0),t.setAttribute("aria-expanded","false")),t.removeAttribute("aria-pressed")}},{ATTRS:{showgroups:{value:3}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js b/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js deleted file mode 100644 index cf3f15e41a5..00000000000 --- a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js +++ /dev/null @@ -1,149 +0,0 @@ -YUI.add('moodle-atto_collapse-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_collapse-button - */ - -/** - * Atto text editor collapse plugin. - * - * @namespace M.atto_collapse - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var PLUGINNAME = 'atto_collapse', - ATTRSHOWGROUPS = 'showgroups', - COLLAPSE = 'collapse', - COLLAPSED = 'collapsed', - GROUPS = '.atto_group', - ROWS = '.atto_toolbar_row'; - -Y.namespace('M.atto_collapse').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var toolbarGroupCount = Y.Object.size(this.get('host').get('plugins')); - if (toolbarGroupCount <= 1 + parseInt(this.get(ATTRSHOWGROUPS), 10)) { - return; - } - - if (this.toolbar.all(GROUPS).size() > this.get(ATTRSHOWGROUPS)) { - return; - } - - var button = this.addButton({ - icon: 'icon', - iconComponent: PLUGINNAME, - callback: this._toggle - }); - - // Perform a toggle after all plugins have been loaded for the first time. - this.get('host').on('pluginsloaded', function(e, button) { - // Add 2 rows in the toolbar. - var toolbarRows = [ - Y.Node.create('
                          '), - Y.Node.create('
                          '), - ]; - this.toolbar.appendChild(toolbarRows[0]).insert(toolbarRows[1], 'after'); - - // Split toolbar buttons between the 2 rows created above. - var buttonGroups = this.toolbar.all(GROUPS); - buttonGroups.slice(0, this.get(ATTRSHOWGROUPS)).each(function(buttonGroup) { - toolbarRows[0].appendChild(buttonGroup); - }); - buttonGroups.slice(this.get(ATTRSHOWGROUPS)).each(function(buttonGroup) { - toolbarRows[1].appendChild(buttonGroup); - }); - - this._setVisibility(button); - button.setAttribute('aria-expanded', 'false'); - }, this, button); - }, - - /** - * Toggle the visibility of the extra groups in the toolbar. - * - * @method _toggle - * @param {EventFacade} e - * @private - */ - _toggle: function(e) { - e.preventDefault(); - var button = this.buttons[COLLAPSE]; - - if (button.getData(COLLAPSED)) { - this.highlightButtons(COLLAPSE); - this._setVisibility(button, true); - this.toolbar.all(ROWS).item(1).focus(); - } else { - this.unHighlightButtons(COLLAPSE); - this._setVisibility(button); - this.buttons[this.name].focus(); - } - }, - - /** - * Set the visibility of the toolbar groups. - * - * @method _setVisibility - * @param {Node} button The collapse button - * @param {Booelan} visibility Whether the groups should be made visible - * @private - */ - _setVisibility: function(button, visibility) { - var secondaryRow = this.toolbar.all(ROWS).item(1); - - if (visibility) { - button.set('title', M.util.get_string('showfewer', PLUGINNAME)); - secondaryRow.show(); - button.setData(COLLAPSED, false); - button.setAttribute('aria-expanded', 'true'); - } else { - button.set('title', M.util.get_string('showmore', PLUGINNAME)); - secondaryRow.hide(); - button.setData(COLLAPSED, true); - button.setAttribute('aria-expanded', 'false'); - } - - // We don't want to have both aria-pressed and aria-expanded set. So we remove aria-pressed here. - button.removeAttribute('aria-pressed'); - } -}, { - ATTRS: { - /** - * How many groups to show when collapsed. - * - * @attribute showgroups - * @type Number - * @default 3 - */ - showgroups: { - value: 3 - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/collapse/yui/src/button/build.json b/lib/editor/atto/plugins/collapse/yui/src/button/build.json deleted file mode 100644 index c0f7f198ed0..00000000000 --- a/lib/editor/atto/plugins/collapse/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_collapse-button", - "builds": { - "moodle-atto_collapse-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/collapse/yui/src/button/js/button.js b/lib/editor/atto/plugins/collapse/yui/src/button/js/button.js deleted file mode 100644 index 88dfd3b6c94..00000000000 --- a/lib/editor/atto/plugins/collapse/yui/src/button/js/button.js +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_collapse - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_collapse-button - */ - -/** - * Atto text editor collapse plugin. - * - * @namespace M.atto_collapse - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var PLUGINNAME = 'atto_collapse', - ATTRSHOWGROUPS = 'showgroups', - COLLAPSE = 'collapse', - COLLAPSED = 'collapsed', - GROUPS = '.atto_group', - ROWS = '.atto_toolbar_row'; - -Y.namespace('M.atto_collapse').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var toolbarGroupCount = Y.Object.size(this.get('host').get('plugins')); - if (toolbarGroupCount <= 1 + parseInt(this.get(ATTRSHOWGROUPS), 10)) { - Y.log("There are not enough groups to require toggling - not adding the button", - 'debug', 'moodle-atto_collapse'); - return; - } - - if (this.toolbar.all(GROUPS).size() > this.get(ATTRSHOWGROUPS)) { - Y.log("The collapse plugin is shown after it's cut-off - not adding the button", - 'debug', 'moodle-atto_collapse'); - return; - } - - var button = this.addButton({ - icon: 'icon', - iconComponent: PLUGINNAME, - callback: this._toggle - }); - - // Perform a toggle after all plugins have been loaded for the first time. - this.get('host').on('pluginsloaded', function(e, button) { - // Add 2 rows in the toolbar. - var toolbarRows = [ - Y.Node.create('
                          '), - Y.Node.create('
                          '), - ]; - this.toolbar.appendChild(toolbarRows[0]).insert(toolbarRows[1], 'after'); - - // Split toolbar buttons between the 2 rows created above. - var buttonGroups = this.toolbar.all(GROUPS); - buttonGroups.slice(0, this.get(ATTRSHOWGROUPS)).each(function(buttonGroup) { - toolbarRows[0].appendChild(buttonGroup); - }); - buttonGroups.slice(this.get(ATTRSHOWGROUPS)).each(function(buttonGroup) { - toolbarRows[1].appendChild(buttonGroup); - }); - - this._setVisibility(button); - button.setAttribute('aria-expanded', 'false'); - }, this, button); - }, - - /** - * Toggle the visibility of the extra groups in the toolbar. - * - * @method _toggle - * @param {EventFacade} e - * @private - */ - _toggle: function(e) { - e.preventDefault(); - var button = this.buttons[COLLAPSE]; - - if (button.getData(COLLAPSED)) { - this.highlightButtons(COLLAPSE); - this._setVisibility(button, true); - this.toolbar.all(ROWS).item(1).focus(); - } else { - this.unHighlightButtons(COLLAPSE); - this._setVisibility(button); - this.buttons[this.name].focus(); - } - }, - - /** - * Set the visibility of the toolbar groups. - * - * @method _setVisibility - * @param {Node} button The collapse button - * @param {Booelan} visibility Whether the groups should be made visible - * @private - */ - _setVisibility: function(button, visibility) { - var secondaryRow = this.toolbar.all(ROWS).item(1); - - if (visibility) { - button.set('title', M.util.get_string('showfewer', PLUGINNAME)); - secondaryRow.show(); - button.setData(COLLAPSED, false); - button.setAttribute('aria-expanded', 'true'); - } else { - button.set('title', M.util.get_string('showmore', PLUGINNAME)); - secondaryRow.hide(); - button.setData(COLLAPSED, true); - button.setAttribute('aria-expanded', 'false'); - } - - // We don't want to have both aria-pressed and aria-expanded set. So we remove aria-pressed here. - button.removeAttribute('aria-pressed'); - } -}, { - ATTRS: { - /** - * How many groups to show when collapsed. - * - * @attribute showgroups - * @type Number - * @default 3 - */ - showgroups: { - value: 3 - } - } -}); diff --git a/lib/editor/atto/plugins/collapse/yui/src/button/meta/button.json b/lib/editor/atto/plugins/collapse/yui/src/button/meta/button.json deleted file mode 100644 index f4b22c61f51..00000000000 --- a/lib/editor/atto/plugins/collapse/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_collapse-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/emojipicker/classes/privacy/provider.php b/lib/editor/atto/plugins/emojipicker/classes/privacy/provider.php deleted file mode 100644 index a88d6213b28..00000000000 --- a/lib/editor/atto/plugins/emojipicker/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for atto_emojipicker. - * - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_emojipicker\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_emojipicker implementing null_provider. - * - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/emojipicker/lang/en/atto_emojipicker.php b/lib/editor/atto/plugins/emojipicker/lang/en/atto_emojipicker.php deleted file mode 100644 index 50bee0f4e60..00000000000 --- a/lib/editor/atto/plugins/emojipicker/lang/en/atto_emojipicker.php +++ /dev/null @@ -1,27 +0,0 @@ -. - -/** - * Strings for component 'atto_emojipicker', language 'en'. - * - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['emojipicker'] = 'Emoji picker'; -$string['pluginname'] = 'Emoji picker'; -$string['privacy:metadata'] = 'The atto_emojipicker plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/emojipicker/lib.php b/lib/editor/atto/plugins/emojipicker/lib.php deleted file mode 100644 index 2c50535b780..00000000000 --- a/lib/editor/atto/plugins/emojipicker/lib.php +++ /dev/null @@ -1,48 +0,0 @@ -. - -/** - * Atto text editor emoji picker plugin lib. - * - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_emojipicker_strings_for_js() { - global $PAGE; - $PAGE->requires->strings_for_js(['emojipicker'], 'atto_emojipicker'); -} - -/** - * Sends the parameters to JS module. - * - * @return array - */ -function atto_emojipicker_params_for_js() { - global $CFG; - - return [ - 'disabled' => empty($CFG->allowemojipicker) ? true : false - ]; -} diff --git a/lib/editor/atto/plugins/emojipicker/styles.css b/lib/editor/atto/plugins/emojipicker/styles.css deleted file mode 100644 index 34278fe0d64..00000000000 --- a/lib/editor/atto/plugins/emojipicker/styles.css +++ /dev/null @@ -1,8 +0,0 @@ -.emoji-picker-dialogue.moodle-dialogue-base .moodle-dialogue .moodle-dialogue-bd { - padding: 0; -} - -.emoji-picker-dialogue .emoji-picker { - box-shadow: none !important; /* stylelint-disable-line declaration-no-important */ - border: 0; -} \ No newline at end of file diff --git a/lib/editor/atto/plugins/emojipicker/version.php b/lib/editor/atto/plugins/emojipicker/version.php deleted file mode 100644 index ee5d12a8c60..00000000000 --- a/lib/editor/atto/plugins/emojipicker/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor emoji picker plugin version file. - * - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_emojipicker'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js deleted file mode 100644 index ba10edad2a6..00000000000 --- a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js +++ /dev/null @@ -1,143 +0,0 @@ -YUI.add('moodle-atto_emojipicker-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_emojipicker-button - */ - -var COMPONENTNAME = 'atto_emojipicker', - EMOJI_PICKER_SEARCH_INPUT = '[data-region="search-input"]'; - -/** - * Atto text editor emoji picker plugin. - * - * @namespace M.atto_emojipicker - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_emojipicker').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - if (this.get('disabled')) { - return; - } - - this.addButton({ - icon: 'e/emoticons', - callback: this._displayDialogue - }); - }, - - /** - * Display the emoji picker. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('emojipicker', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - additionalBaseClass: 'emoji-picker-dialogue' - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Insert the emoticon. - * - * @method _insertEmote - * @param {String} emoji - * @private - */ - _insertEmoji: function(emoji) { - var host = this.get('host'); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Focus on the previous selection. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(emoji); - - this.markUpdated(); - }, - - /** - * Generates the content of the dialogue, attaching event listeners to - * the content. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var wrapper = Y.Node.create('
                          '); - - require(['core/templates', 'core/emoji/picker'], function(Templates, initialiseEmojiPicker) { - Templates.render('core/emoji/picker', {}).then(function(html) { - var domNode = wrapper.getDOMNode(); - domNode.innerHTML = html; - initialiseEmojiPicker(domNode, this._insertEmoji.bind(this)); - this.getDialogue().centerDialogue(); - domNode.querySelector(EMOJI_PICKER_SEARCH_INPUT).focus(); - }.bind(this)); - }.bind(this)); - - return wrapper; - } -}, { - ATTRS: { - disabled: { - value: true - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js deleted file mode 100644 index 30de959d312..00000000000 --- a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_emojipicker-button",function(e,t){e.namespace("M.atto_emojipicker").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){this.get("disabled")||this.addButton({icon:"e/emoticons",callback:this._displayDialogue})},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&this.getDialogue({headerContent:M.util.get_string("emojipicker","atto_emojipicker"),width:"auto",focusAfterHide:!0,additionalBaseClass:"emoji-picker-dialogue"},!0).set("bodyContent",this._getDialogueContent()).show()},_insertEmoji:function(e){var t=this.get("host");this.getDialogue({focusAfterHide:null}).hide(),t.setSelection(this._currentSelection),t.insertContentAtFocusPoint(e),this.markUpdated()},_getDialogueContent:function(){var o=e.Node.create("
                          ");return require(["core/templates","core/emoji/picker"],function(e,i){e.render("core/emoji/picker",{}).then(function(e){var t=o.getDOMNode();t.innerHTML=e,i(t,this._insertEmoji.bind(this)),this.getDialogue().centerDialogue(),t.querySelector('[data-region="search-input"]').focus()}.bind(this))}.bind(this)),o}},{ATTRS:{disabled:{value:!0}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js deleted file mode 100644 index ba10edad2a6..00000000000 --- a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js +++ /dev/null @@ -1,143 +0,0 @@ -YUI.add('moodle-atto_emojipicker-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_emojipicker-button - */ - -var COMPONENTNAME = 'atto_emojipicker', - EMOJI_PICKER_SEARCH_INPUT = '[data-region="search-input"]'; - -/** - * Atto text editor emoji picker plugin. - * - * @namespace M.atto_emojipicker - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_emojipicker').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - if (this.get('disabled')) { - return; - } - - this.addButton({ - icon: 'e/emoticons', - callback: this._displayDialogue - }); - }, - - /** - * Display the emoji picker. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('emojipicker', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - additionalBaseClass: 'emoji-picker-dialogue' - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Insert the emoticon. - * - * @method _insertEmote - * @param {String} emoji - * @private - */ - _insertEmoji: function(emoji) { - var host = this.get('host'); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Focus on the previous selection. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(emoji); - - this.markUpdated(); - }, - - /** - * Generates the content of the dialogue, attaching event listeners to - * the content. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var wrapper = Y.Node.create('
                          '); - - require(['core/templates', 'core/emoji/picker'], function(Templates, initialiseEmojiPicker) { - Templates.render('core/emoji/picker', {}).then(function(html) { - var domNode = wrapper.getDOMNode(); - domNode.innerHTML = html; - initialiseEmojiPicker(domNode, this._insertEmoji.bind(this)); - this.getDialogue().centerDialogue(); - domNode.querySelector(EMOJI_PICKER_SEARCH_INPUT).focus(); - }.bind(this)); - }.bind(this)); - - return wrapper; - } -}, { - ATTRS: { - disabled: { - value: true - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/emojipicker/yui/src/button/build.json b/lib/editor/atto/plugins/emojipicker/yui/src/button/build.json deleted file mode 100644 index 0a50ee9297d..00000000000 --- a/lib/editor/atto/plugins/emojipicker/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_emojipicker-button", - "builds": { - "moodle-atto_emojipicker-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js b/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js deleted file mode 100644 index 88d7efdb7c4..00000000000 --- a/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js +++ /dev/null @@ -1,138 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_emojipicker - * @copyright 2019 Ryan Wyllie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_emojipicker-button - */ - -var COMPONENTNAME = 'atto_emojipicker', - EMOJI_PICKER_SEARCH_INPUT = '[data-region="search-input"]'; - -/** - * Atto text editor emoji picker plugin. - * - * @namespace M.atto_emojipicker - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_emojipicker').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - if (this.get('disabled')) { - return; - } - - this.addButton({ - icon: 'e/emoticons', - callback: this._displayDialogue - }); - }, - - /** - * Display the emoji picker. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('emojipicker', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - additionalBaseClass: 'emoji-picker-dialogue' - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Insert the emoticon. - * - * @method _insertEmote - * @param {String} emoji - * @private - */ - _insertEmoji: function(emoji) { - var host = this.get('host'); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Focus on the previous selection. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(emoji); - - this.markUpdated(); - }, - - /** - * Generates the content of the dialogue, attaching event listeners to - * the content. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var wrapper = Y.Node.create('
                          '); - - require(['core/templates', 'core/emoji/picker'], function(Templates, initialiseEmojiPicker) { - Templates.render('core/emoji/picker', {}).then(function(html) { - var domNode = wrapper.getDOMNode(); - domNode.innerHTML = html; - initialiseEmojiPicker(domNode, this._insertEmoji.bind(this)); - this.getDialogue().centerDialogue(); - domNode.querySelector(EMOJI_PICKER_SEARCH_INPUT).focus(); - }.bind(this)); - }.bind(this)); - - return wrapper; - } -}, { - ATTRS: { - disabled: { - value: true - } - } -}); diff --git a/lib/editor/atto/plugins/emojipicker/yui/src/button/meta/button.json b/lib/editor/atto/plugins/emojipicker/yui/src/button/meta/button.json deleted file mode 100644 index 9ea3e8152ac..00000000000 --- a/lib/editor/atto/plugins/emojipicker/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_emojipicker-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/emoticon/classes/privacy/provider.php b/lib/editor/atto/plugins/emoticon/classes/privacy/provider.php deleted file mode 100644 index 8260c4d3fe2..00000000000 --- a/lib/editor/atto/plugins/emoticon/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_emoticon - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_emoticon\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_emoticon implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/emoticon/lang/en/atto_emoticon.php b/lib/editor/atto/plugins/emoticon/lang/en/atto_emoticon.php deleted file mode 100644 index 5786ba72b67..00000000000 --- a/lib/editor/atto/plugins/emoticon/lang/en/atto_emoticon.php +++ /dev/null @@ -1,27 +0,0 @@ -. - -/** - * Strings for component 'atto_emoticon', language 'en'. - * - * @package atto_emoticon - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['insertemoticon'] = 'Insert emoticon'; -$string['pluginname'] = 'Emoticon'; -$string['privacy:metadata'] = 'The atto_emoticon plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/emoticon/lib.php b/lib/editor/atto/plugins/emoticon/lib.php deleted file mode 100644 index 50d0860e8c4..00000000000 --- a/lib/editor/atto/plugins/emoticon/lib.php +++ /dev/null @@ -1,54 +0,0 @@ -. - -/** - * Atto text editor emoticon plugin lib. - * - * @package atto_emoticon - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_emoticon_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('insertemoticon'), 'atto_emoticon'); - - // Load the strings required by the emotes. - $manager = get_emoticon_manager(); - foreach ($manager->get_emoticons(true) as $emote) { - $PAGE->requires->string_for_js($emote->altidentifier, $emote->altcomponent); - } -} - -/** - * Sends the parameters to JS module. - * - * @return array - */ -function atto_emoticon_params_for_js($elementid, $options, $fpoptions) { - $manager = get_emoticon_manager(); - return array( - 'emoticons' => $manager->get_emoticons(true) - ); -} diff --git a/lib/editor/atto/plugins/emoticon/styles.css b/lib/editor/atto/plugins/emoticon/styles.css deleted file mode 100644 index 90fddab1ff7..00000000000 --- a/lib/editor/atto/plugins/emoticon/styles.css +++ /dev/null @@ -1,20 +0,0 @@ -.atto_emoticon_map ul { - padding: 0; - margin: 0; - display: table; - width: 100%; -} - -.atto_emoticon_map li { - display: table-row; - white-space: nowrap; -} - -.atto_emoticon_map li div { - display: table-cell; - padding: 0 1em; -} - -.atto_emoticon_emote img { - width: 16px; -} diff --git a/lib/editor/atto/plugins/emoticon/version.php b/lib/editor/atto/plugins/emoticon/version.php deleted file mode 100644 index 2998c32c038..00000000000 --- a/lib/editor/atto/plugins/emoticon/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor emoticon plugin version file. - * - * @package atto_emoticon - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_emoticon'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-debug.js b/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-debug.js deleted file mode 100644 index b4c308538ea..00000000000 --- a/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-debug.js +++ /dev/null @@ -1,170 +0,0 @@ -YUI.add('moodle-atto_emoticon-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_emoticon - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_emoticon-button - */ - -var COMPONENTNAME = 'atto_emoticon', - CSS = { - EMOTE: 'atto_emoticon_emote', - MAP: 'atto_emoticon_map' - }, - SELECTORS = { - EMOTE: '.atto_emoticon_emote' - }, - TEMPLATE = '' + - '
                          ' + - '
                            ' + - '{{#each emoticons}}' + - '
                          • ' + - '' + - '' + - '' + - '
                            ' + - '
                            {{text}}
                            ' + - '
                            {{get_string altidentifier altcomponent}}
                            ' + - '
                          • ' + - '{{/each}}' + - '
                          ' + - '
                          '; - -/** - * Atto text editor emoticon plugin. - * - * @namespace M.atto_emoticon - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_emoticon').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - this.addButton({ - icon: 'e/emoticons', - callback: this._displayDialogue - }); - }, - - /** - * Display the Emoticon chooser. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('insertemoticon', COMPONENTNAME), - focusAfterHide: true - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Insert the emoticon. - * - * @method _insertEmote - * @param {EventFacade} e - * @private - */ - _insertEmote: function(e) { - var target = e.target.ancestor(SELECTORS.EMOTE, true), - host = this.get('host'); - - e.preventDefault(); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Build the Emoticon text. - var html = ' ' + target.getData('text') + ' '; - - // Focus on the previous selection. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(html); - - this.markUpdated(); - }, - - /** - * Generates the content of the dialogue, attaching event listeners to - * the content. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - emoticons: this.get('emoticons'), - CSS: CSS - })); - content.delegate('click', this._insertEmote, SELECTORS.EMOTE, this); - content.delegate('key', this._insertEmote, '32', SELECTORS.EMOTE, this); - - return content; - } -}, { - ATTRS: { - /** - * The list of emoticons to display. - * - * @attribute emoticons - * @type array - * @default {} - */ - emoticons: { - value: {} - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-min.js b/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-min.js deleted file mode 100644 index af413e5203b..00000000000 --- a/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_emoticon-button",function(e,t){var i={EMOTE:"atto_emoticon_emote",MAP:"atto_emoticon_map"},o=".atto_emoticon_emote";e.namespace("M.atto_emoticon").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){this.addButton({icon:"e/emoticons",callback:this._displayDialogue})},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&this.getDialogue({headerContent:M.util.get_string("insertemoticon","atto_emoticon"),focusAfterHide:!0},!0).set("bodyContent",this._getDialogueContent()).show()},_insertEmote:function(t){var e=t.target.ancestor(o,!0),i=this.get("host");t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),t=" "+e.getData("text")+" ",i.setSelection(this._currentSelection),i.insertContentAtFocusPoint(t),this.markUpdated()},_getDialogueContent:function(){var t=e.Handlebars.compile('
                            {{#each emoticons}}
                          • {{get_string altidentifier altcomponent}}
                            {{text}}
                            {{get_string altidentifier altcomponent}}
                          • {{/each}}
                          '),t=e.Node.create(t({emoticons:this.get("emoticons"),CSS:i}));return t.delegate("click",this._insertEmote,o,this),t.delegate("key",this._insertEmote,"32",o,this),t}},{ATTRS:{emoticons:{value:{}}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button.js b/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button.js deleted file mode 100644 index b4c308538ea..00000000000 --- a/lib/editor/atto/plugins/emoticon/yui/build/moodle-atto_emoticon-button/moodle-atto_emoticon-button.js +++ /dev/null @@ -1,170 +0,0 @@ -YUI.add('moodle-atto_emoticon-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_emoticon - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_emoticon-button - */ - -var COMPONENTNAME = 'atto_emoticon', - CSS = { - EMOTE: 'atto_emoticon_emote', - MAP: 'atto_emoticon_map' - }, - SELECTORS = { - EMOTE: '.atto_emoticon_emote' - }, - TEMPLATE = '' + - '
                          ' + - '
                            ' + - '{{#each emoticons}}' + - '
                          • ' + - '' + - '' + - '' + - '
                            ' + - '
                            {{text}}
                            ' + - '
                            {{get_string altidentifier altcomponent}}
                            ' + - '
                          • ' + - '{{/each}}' + - '
                          ' + - '
                          '; - -/** - * Atto text editor emoticon plugin. - * - * @namespace M.atto_emoticon - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_emoticon').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - this.addButton({ - icon: 'e/emoticons', - callback: this._displayDialogue - }); - }, - - /** - * Display the Emoticon chooser. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('insertemoticon', COMPONENTNAME), - focusAfterHide: true - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Insert the emoticon. - * - * @method _insertEmote - * @param {EventFacade} e - * @private - */ - _insertEmote: function(e) { - var target = e.target.ancestor(SELECTORS.EMOTE, true), - host = this.get('host'); - - e.preventDefault(); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Build the Emoticon text. - var html = ' ' + target.getData('text') + ' '; - - // Focus on the previous selection. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(html); - - this.markUpdated(); - }, - - /** - * Generates the content of the dialogue, attaching event listeners to - * the content. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - emoticons: this.get('emoticons'), - CSS: CSS - })); - content.delegate('click', this._insertEmote, SELECTORS.EMOTE, this); - content.delegate('key', this._insertEmote, '32', SELECTORS.EMOTE, this); - - return content; - } -}, { - ATTRS: { - /** - * The list of emoticons to display. - * - * @attribute emoticons - * @type array - * @default {} - */ - emoticons: { - value: {} - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/emoticon/yui/src/button/build.json b/lib/editor/atto/plugins/emoticon/yui/src/button/build.json deleted file mode 100644 index b4253b5742b..00000000000 --- a/lib/editor/atto/plugins/emoticon/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_emoticon-button", - "builds": { - "moodle-atto_emoticon-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/emoticon/yui/src/button/js/button.js b/lib/editor/atto/plugins/emoticon/yui/src/button/js/button.js deleted file mode 100644 index 752fca1c5f2..00000000000 --- a/lib/editor/atto/plugins/emoticon/yui/src/button/js/button.js +++ /dev/null @@ -1,165 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_emoticon - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_emoticon-button - */ - -var COMPONENTNAME = 'atto_emoticon', - CSS = { - EMOTE: 'atto_emoticon_emote', - MAP: 'atto_emoticon_map' - }, - SELECTORS = { - EMOTE: '.atto_emoticon_emote' - }, - TEMPLATE = '' + - '
                          ' + - '
                            ' + - '{{#each emoticons}}' + - '
                          • ' + - '' + - '' + - '' + - '
                            ' + - '
                            {{text}}
                            ' + - '
                            {{get_string altidentifier altcomponent}}
                            ' + - '
                          • ' + - '{{/each}}' + - '
                          ' + - '
                          '; - -/** - * Atto text editor emoticon plugin. - * - * @namespace M.atto_emoticon - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_emoticon').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - this.addButton({ - icon: 'e/emoticons', - callback: this._displayDialogue - }); - }, - - /** - * Display the Emoticon chooser. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('insertemoticon', COMPONENTNAME), - focusAfterHide: true - }, true); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Insert the emoticon. - * - * @method _insertEmote - * @param {EventFacade} e - * @private - */ - _insertEmote: function(e) { - var target = e.target.ancestor(SELECTORS.EMOTE, true), - host = this.get('host'); - - e.preventDefault(); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Build the Emoticon text. - var html = ' ' + target.getData('text') + ' '; - - // Focus on the previous selection. - host.setSelection(this._currentSelection); - - // And add the character. - host.insertContentAtFocusPoint(html); - - this.markUpdated(); - }, - - /** - * Generates the content of the dialogue, attaching event listeners to - * the content. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - emoticons: this.get('emoticons'), - CSS: CSS - })); - content.delegate('click', this._insertEmote, SELECTORS.EMOTE, this); - content.delegate('key', this._insertEmote, '32', SELECTORS.EMOTE, this); - - return content; - } -}, { - ATTRS: { - /** - * The list of emoticons to display. - * - * @attribute emoticons - * @type array - * @default {} - */ - emoticons: { - value: {} - } - } -}); diff --git a/lib/editor/atto/plugins/emoticon/yui/src/button/meta/button.json b/lib/editor/atto/plugins/emoticon/yui/src/button/meta/button.json deleted file mode 100644 index a17ef6d963d..00000000000 --- a/lib/editor/atto/plugins/emoticon/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_emoticon-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/equation/ajax.php b/lib/editor/atto/plugins/equation/ajax.php deleted file mode 100644 index 527a9df91be..00000000000 --- a/lib/editor/atto/plugins/equation/ajax.php +++ /dev/null @@ -1,51 +0,0 @@ -. - -/** - * Renders text with the active filters and returns it. Used to create previews of equations - * using whatever tex filters are enabled. - * - * @package atto_equation - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -define('AJAX_SCRIPT', true); - -require_once(__DIR__ . '/../../../../../config.php'); - -$contextid = required_param('contextid', PARAM_INT); - -list($context, $course, $cm) = get_context_info_array($contextid); -$PAGE->set_url('/lib/editor/atto/plugins/equation/ajax.php'); -$PAGE->set_context($context); - -require_login($course, false, $cm); -require_sesskey(); - -$action = required_param('action', PARAM_ALPHA); - -if ($action === 'filtertext') { - $text = required_param('text', PARAM_RAW); - - $result = filter_manager::instance()->filter_text($text, $context); - echo $OUTPUT->header(); - echo $result; - - die(); -} - -throw new \moodle_exception('invalidarguments'); diff --git a/lib/editor/atto/plugins/equation/classes/privacy/provider.php b/lib/editor/atto/plugins/equation/classes/privacy/provider.php deleted file mode 100644 index d561a457811..00000000000 --- a/lib/editor/atto/plugins/equation/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_equation - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_equation\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_equation implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/equation/db/upgrade.php b/lib/editor/atto/plugins/equation/db/upgrade.php deleted file mode 100644 index 1a6367f30fa..00000000000 --- a/lib/editor/atto/plugins/equation/db/upgrade.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Atto equation plugin upgrade script. - * - * @package atto_equation - * @copyright 2015 Sam Chaffee - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Run all Atto equation upgrade steps between the current DB version and the current version on disk. - * @param int $oldversion The old version of atto equation in the DB. - * @return bool - */ -function xmldb_atto_equation_upgrade($oldversion) { - // Automatically generated Moodle v4.2.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.3.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.4.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.5.0 release upgrade line. - // Put any upgrade step following this. - - return true; -} diff --git a/lib/editor/atto/plugins/equation/lang/en/atto_equation.php b/lib/editor/atto/plugins/equation/lang/en/atto_equation.php deleted file mode 100644 index c30c00d4e6c..00000000000 --- a/lib/editor/atto/plugins/equation/lang/en/atto_equation.php +++ /dev/null @@ -1,40 +0,0 @@ -. - -/** - * Strings for component 'atto_equation', language 'en'. - * - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['editequation'] = 'Edit equation using TeX'; -$string['librarygroup1'] = 'Operators'; -$string['librarygroup1_desc'] = 'TeX commands listed on the operators tab.'; -$string['librarygroup2'] = 'Arrows'; -$string['librarygroup2_desc'] = 'TeX commands listed on the arrows tab.'; -$string['librarygroup3'] = 'Greek symbols'; -$string['librarygroup3_desc'] = 'TeX commands listed on the Greek symbols tab.'; -$string['librarygroup4'] = 'Advanced'; -$string['librarygroup4_desc'] = 'TeX commands listed on the advanced tab.'; -$string['pluginname'] = 'Equation editor'; -$string['preview'] = 'Equation preview'; -$string['cursorinfo'] = 'An arrow indicates the position that new elements from the element library will be inserted.'; -$string['saveequation'] = 'Save equation'; -$string['settings'] = 'Equation editor settings'; -$string['update'] = 'Update'; -$string['privacy:metadata'] = 'The atto_equation plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/equation/lib.php b/lib/editor/atto/plugins/equation/lib.php deleted file mode 100644 index 8dcb1859eae..00000000000 --- a/lib/editor/atto/plugins/equation/lib.php +++ /dev/null @@ -1,93 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Get the list of strings for this plugin. - * @param string $elementid - */ -function atto_equation_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('saveequation', - 'editequation', - 'preview', - 'cursorinfo', - 'update', - 'librarygroup1', - 'librarygroup2', - 'librarygroup3', - 'librarygroup4'), - 'atto_equation'); -} - -/** - * Set params for this plugin. - * - * @param string $elementid - * @param stdClass $options - the options for the editor, including the context. - * @param stdClass $fpoptions - unused. - */ -function atto_equation_params_for_js($elementid, $options, $fpoptions) { - $texexample = '$$\pi$$'; - - // Format a string with the active filter set. - // If it is modified - we assume that some sort of text filter is working in this context. - $formatoptions = [ - 'context' => $options['context'], - 'noclean' => $options['noclean'] ?? false, - 'trusted' => $options['trusted'] ?? false, - ]; - - $result = format_text($texexample, true, $formatoptions); - - $texfilteractive = ($texexample !== $result); - $context = $options['context']; - - // Tex example librarys. - $library = array( - 'group1' => array( - 'groupname' => 'librarygroup1', - 'elements' => get_config('atto_equation', 'librarygroup1'), - 'active' => true, - ), - 'group2' => array( - 'groupname' => 'librarygroup2', - 'elements' => get_config('atto_equation', 'librarygroup2'), - ), - 'group3' => array( - 'groupname' => 'librarygroup3', - 'elements' => get_config('atto_equation', 'librarygroup3'), - ), - 'group4' => array( - 'groupname' => 'librarygroup4', - 'elements' => get_config('atto_equation', 'librarygroup4'), - )); - - return array('texfilteractive' => $texfilteractive, - 'contextid' => $context->id, - 'library' => $library, - 'texdocsurl' => get_docs_url('Using_TeX_Notation')); -} diff --git a/lib/editor/atto/plugins/equation/settings.php b/lib/editor/atto/plugins/equation/settings.php deleted file mode 100644 index 118611edb6c..00000000000 --- a/lib/editor/atto/plugins/equation/settings.php +++ /dev/null @@ -1,175 +0,0 @@ -. - -/** - * Settings that allow configuration of the list of tex examples in the equation editor. - * - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$ADMIN->add('editoratto', new admin_category('atto_equation', new lang_string('pluginname', 'atto_equation'))); - -$settings = new admin_settingpage('atto_equation_settings', new lang_string('settings', 'atto_equation')); -if ($ADMIN->fulltree) { - // Group 1 - $name = new lang_string('librarygroup1', 'atto_equation'); - $desc = new lang_string('librarygroup1_desc', 'atto_equation'); - $default = ' -\cdot -\times -\ast -\div -\diamond -\pm -\mp -\oplus -\ominus -\otimes -\oslash -\odot -\circ -\bullet -\asymp -\equiv -\subseteq -\supseteq -\leq -\geq -\preceq -\succeq -\sim -\simeq -\approx -\subset -\supset -\ll -\gg -\prec -\succ -\infty -\in -\ni -\forall -\exists -\neq -'; - $setting = new admin_setting_configtextarea('atto_equation/librarygroup1', - $name, - $desc, - $default); - $settings->add($setting); - - // Group 2 - $name = new lang_string('librarygroup2', 'atto_equation'); - $desc = new lang_string('librarygroup2_desc', 'atto_equation'); - $default = ' -\leftarrow -\rightarrow -\uparrow -\downarrow -\leftrightarrow -\nearrow -\searrow -\swarrow -\nwarrow -\Leftarrow -\Rightarrow -\Uparrow -\Downarrow -\Leftrightarrow -'; - $setting = new admin_setting_configtextarea('atto_equation/librarygroup2', - $name, - $desc, - $default); - $settings->add($setting); - - // Group 3 - $name = new lang_string('librarygroup3', 'atto_equation'); - $desc = new lang_string('librarygroup3_desc', 'atto_equation'); - $default = ' -\alpha -\beta -\gamma -\delta -\epsilon -\zeta -\eta -\theta -\iota -\kappa -\lambda -\mu -\nu -\xi -\pi -\rho -\sigma -\tau -\upsilon -\phi -\chi -\psi -\omega -\Gamma -\Delta -\Theta -\Lambda -\Xi -\Pi -\Sigma -\Upsilon -\Phi -\Psi -\Omega -'; - $setting = new admin_setting_configtextarea('atto_equation/librarygroup3', - $name, - $desc, - $default); - $settings->add($setting); - - // Group 4 - $name = new lang_string('librarygroup4', 'atto_equation'); - $desc = new lang_string('librarygroup4_desc', 'atto_equation'); - $default = ' -\sum{a,b} -\sqrt[a]{b+c} -\int_{a}^{b}{c} -\iint_{a}^{b}{c} -\iiint_{a}^{b}{c} -\oint{a} -(a) -[a] -\lbrace{a}\rbrace -\left| \begin{matrix} a_1 & a_2 \\\\ a_3 & a_4 \end{matrix} \right| -\frac{a}{b+c} -\vec{a} -\binom {a} {b} -{a \brack b} -{a \brace b} -'; - $setting = new admin_setting_configtextarea('atto_equation/librarygroup4', - $name, - $desc, - $default); - $settings->add($setting); - -} diff --git a/lib/editor/atto/plugins/equation/styles.css b/lib/editor/atto/plugins/equation/styles.css deleted file mode 100644 index 3cac262f071..00000000000 --- a/lib/editor/atto/plugins/equation/styles.css +++ /dev/null @@ -1,11 +0,0 @@ -.atto_equation_library button { - margin: 0.25%; - min-width: 12%; -} - -#page-admin-setting-atto_equation_settings .form-defaultinfo { - max-height: 10em; - overflow: auto; - padding: 5px; - min-width: 206px; -} diff --git a/lib/editor/atto/plugins/equation/tests/behat/equation.feature b/lib/editor/atto/plugins/equation/tests/behat/equation.feature deleted file mode 100644 index fff9e8f9a97..00000000000 --- a/lib/editor/atto/plugins/equation/tests/behat/equation.feature +++ /dev/null @@ -1,38 +0,0 @@ -@editor @editor_atto @atto @atto_equation @_bug_phantomjs -Feature: Atto equation editor - To teach maths to students, I need to write equations - - @javascript - Scenario: Create an equation - Given I log in as "admin" - When I open my profile in edit mode - And I set the field "Description" to "

                          Equation test

                          " - # Set field on the bottom of page, so equation editor dialogue is visible. - And I expand all fieldsets - And I set the field "Picture description" to "Test" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - And I click on "Equation editor" "button" - And the "class" attribute of "Edit equation using" "field" should contain "text-ltr" - And I set the field "Edit equation using" to " = 1 \div 0" - And I click on "\infty" "button" - And I click on "Save equation" "button" - And I click on "Update profile" "button" - And I follow "Profile" in the user menu - Then "\infty" "text" should exist - - @javascript - Scenario: Edit an equation - Given I log in as "admin" - When I open my profile in edit mode - And I set the field "Description" to "

                          \( \pi \)

                          " - # Set field on the bottom of page, so equation editor dialogue is visible. - And I expand all fieldsets - And I set the field "Picture description" to "Test" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - And I click on "Equation editor" "button" - And the "class" attribute of "Edit equation using" "field" should contain "text-ltr" - Then the field "Edit equation using" matches value " \pi " - And I click on "Save equation" "button" - And the field "Description" matches value "

                          \( \pi \)

                          " diff --git a/lib/editor/atto/plugins/equation/version.php b/lib/editor/atto/plugins/equation/version.php deleted file mode 100644 index 411158479bb..00000000000 --- a/lib/editor/atto/plugins/equation/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_equation'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js deleted file mode 100644 index 126b96aef22..00000000000 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js +++ /dev/null @@ -1,791 +0,0 @@ -YUI.add('moodle-atto_equation-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Atto text editor equation plugin. - */ - -/** - * Atto equation editor. - * - * @namespace M.atto_equation - * @class Button - * @extends M.editor_atto.EditorPlugin - */ -var COMPONENTNAME = 'atto_equation', - LOGNAME = 'atto_equation', - CSS = { - EQUATION_TEXT: 'atto_equation_equation', - EQUATION_PREVIEW: 'atto_equation_preview', - SUBMIT: 'atto_equation_submit', - LIBRARY: 'atto_equation_library', - LIBRARY_GROUPS: 'atto_equation_groups', - LIBRARY_GROUP_PREFIX: 'atto_equation_group' - }, - SELECTORS = { - LIBRARY: '.' + CSS.LIBRARY, - LIBRARY_GROUP: '.' + CSS.LIBRARY_GROUPS + ' > div > div', - EQUATION_TEXT: '.' + CSS.EQUATION_TEXT, - EQUATION_PREVIEW: '.' + CSS.EQUATION_PREVIEW, - SUBMIT: '.' + CSS.SUBMIT, - LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button' - }, - DELIMITERS = { - START: '\\(', - END: '\\)' - }, - TEMPLATES = { - FORM: '' + - '
                          ' + - '{{{library}}}' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          {{get_string "cursorinfo" component}}
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - LIBRARY: '' + - '
                          ' + - '' + - '
                          ' + - '{{#each library}}' + - '
                          ' + - '
                          ' + - '{{#split "\n" elements}}' + - '' + - '{{/split}}' + - '
                          ' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' - }; - -Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * The selection object returned by the browser. - * - * @property _currentSelection - * @type Range - * @default null - * @private - */ - _currentSelection: null, - - /** - * The cursor position in the equation textarea. - * - * @property _lastCursorPos - * @type Number - * @default 0 - * @private - */ - _lastCursorPos: 0, - - /** - * A reference to the dialogue content. - * - * @property _content - * @type Node - * @private - */ - _content: null, - - /** - * The source equation we are editing in the text. - * - * @property _sourceEquation - * @type Object - * @private - */ - _sourceEquation: null, - - /** - * A reference to the tab focus set on each group. - * - * The keys are the IDs of the group, the value is the Node on which the focus is set. - * - * @property _groupFocus - * @type Object - * @private - */ - _groupFocus: null, - - /** - * Regular Expression patterns used to pick out the equations in a String. - * - * @property _equationPatterns - * @type Array - * @private - */ - _equationPatterns: [ - // We use space or not space because . does not match new lines. - // $$ blah $$. - /\$\$([\S\s]+?)\$\$/, - // E.g. "\( blah \)". - /\\\(([\S\s]+?)\\\)/, - // E.g. "\[ blah \]". - /\\\[([\S\s]+?)\\\]/, - // E.g. "[tex] blah [/tex]". - /\[tex\]([\S\s]+?)\[\/tex\]/ - ], - - initializer: function() { - this._groupFocus = {}; - - // If there is a tex filter active - enable this button. - if (this.get('texfilteractive')) { - // Add the button to the toolbar. - this.addButton({ - icon: 'e/math', - callback: this._displayDialogue - }); - - // We need custom highlight logic for this button. - this.get('host').on('atto:selectionchanged', function() { - if (this._resolveEquation()) { - this.highlightButtons(); - } else { - this.unHighlightButtons(); - } - }, this); - - // We need to convert these to a non dom node based format. - this.editor.all('tex').each(function(texNode) { - var replacement = Y.Node.create('' + - DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + - ''); - texNode.replace(replacement); - }); - } - - }, - - /** - * Display the equation editor. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection === false) { - return; - } - - // This needs to be done before the dialogue is opened because the focus will shift to the dialogue. - var equation = this._resolveEquation(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENTNAME), - focusAfterHide: true, - width: 600, - focusOnShowSelector: SELECTORS.LIBRARY_BUTTON - }); - - var content = this._getDialogueContent(); - dialogue.set('bodyContent', content); - - dialogue.show(); - // Notify the filters about the modified nodes. - require(['core/event'], function(event) { - event.notifyFilterContentUpdated(dialogue.get('boundingBox').getDOMNode()); - }); - - if (equation) { - content.one(SELECTORS.EQUATION_TEXT).set('text', equation); - } - this._updatePreview(false); - }, - - /** - * If there is selected text and it is part of an equation, - * extract the equation (and set it in the form). - * - * @method _resolveEquation - * @private - * @return {String|Boolean} The equation or false. - */ - _resolveEquation: function() { - - // Find the equation in the surrounding text. - var selectedNode = this.get('host').getSelectionParentNode(), - selection = this.get('host').getSelection(), - text, - returnValue = false; - - // Prevent resolving equations when we don't have focus. - if (!this.get('host').isActive()) { - return false; - } - - // Note this is a document fragment and YUI doesn't like them. - if (!selectedNode) { - return false; - } - - // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection. - if (!selection || selection.length === 0) { - return false; - } - - this.sourceEquation = null; - - selection = selection[0]; - - text = Y.one(selectedNode).get('text'); - - // For each of these patterns we have a RegExp which captures the inner component of the equation but also - // includes the delimiters. - // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire - // equation including delimiters and returning one entry per match of the whole equation. - // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the - // match results. - Y.Array.find(this._equationPatterns, function(pattern) { - // For each pattern in turn, find all whole matches (including the delimiters). - var patternMatches = text.match(new RegExp(pattern.source, "g")); - - if (patternMatches && patternMatches.length) { - // This pattern matches at least once. See if this pattern matches our current position. - // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent - // searches which is the required behaviour of this function. - return Y.Array.find(patternMatches, function(match) { - // Check each occurrence of this match. - var startIndex = 0; - while (text.indexOf(match, startIndex) !== -1) { - // Determine whether the cursor is in the current occurrence of this string. - // Note: We do not support a selection exceeding the bounds of an equation. - var startOuter = text.indexOf(match, startIndex), - endOuter = startOuter + match.length, - startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter), - endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter); - - if (startMatch && endMatch) { - // This match is in our current position - fetch the innerMatch data. - var innerMatch = match.match(pattern); - if (innerMatch && innerMatch.length) { - // We need the start and end of the inner match for later. - var startInner = text.indexOf(innerMatch[1], startOuter), - endInner = startInner + innerMatch[1].length; - - // We'll be returning the inner match for use in the editor itself. - returnValue = innerMatch[1]; - - // Save all data for later. - this.sourceEquation = { - // Outer match data. - startOuterPosition: startOuter, - endOuterPosition: endOuter, - outerMatch: match, - - // Inner match data. - startInnerPosition: startInner, - endInnerPosition: endInner, - innerMatch: innerMatch - }; - - // This breaks out of both Y.Array.find functions. - return true; - } - } - - // Update the startIndex to match the end of the current match so that we can continue hunting - // for further matches. - startIndex = endOuter; - } - }, this); - } - }, this); - - // We trim the equation when we load it and then add spaces when we save it. - if (returnValue !== false) { - returnValue = returnValue.trim(); - } - return returnValue; - }, - - /** - * Handle insertion of a new equation, or update of an existing one. - * - * @method _setEquation - * @param {EventFacade} e - * @private - */ - _setEquation: function(e) { - var input, - selectedNode, - text, - value, - host, - newText; - - host = this.get('host'); - - e.preventDefault(); - this.getDialogue({ - focusAfterHide: null - }).hide(); - - input = e.currentTarget.ancestor('.atto_form').one('textarea'); - - value = input.get('value'); - if (value !== '') { - host.setSelection(this._currentSelection); - - if (this.sourceEquation) { - // Replace the equation. - selectedNode = Y.one(host.getSelectionParentNode()); - text = selectedNode.get('text'); - value = ' ' + value + ' '; - newText = text.slice(0, this.sourceEquation.startInnerPosition) + - value + - text.slice(this.sourceEquation.endInnerPosition); - - selectedNode.set('text', newText); - } else { - // Insert the new equation. - value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END; - host.insertContentAtFocusPoint(value); - } - - // Clean the YUI ids from the HTML. - this.markUpdated(); - } - }, - - /** - * Smart throttle, only call a function every delay milli seconds, - * and always run the last call. Y.throttle does not work here, - * because it calls the function immediately, the first time, and then - * ignores repeated calls within X seconds. This does not guarantee - * that the last call will be executed (which is required here). - * - * @param {function} fn - * @param {Number} delay Delay in milliseconds - * @method _throttle - * @private - */ - _throttle: function(fn, delay) { - var timer = null; - return function() { - var context = this, args = arguments; - clearTimeout(timer); - timer = setTimeout(function() { - fn.apply(context, args); - }, delay); - }; - }, - - /** - * Update the preview div to match the current equation. - * - * @param {EventFacade} e - * @method _updatePreview - * @private - */ - _updatePreview: function(e) { - var textarea = this._content.one(SELECTORS.EQUATION_TEXT), - equation = textarea.get('value'), - url, - currentPos = textarea.get('selectionStart'), - prefix = '', - cursorLatex = '\\Downarrow ', - isChar, - params; - - if (e) { - e.preventDefault(); - } - - // Move the cursor so it does not break expressions. - // Start at the very beginning. - if (!currentPos) { - currentPos = 0; - } - - // First move back to the beginning of the line. - while (equation.charAt(currentPos) === '\\' && currentPos >= 0) { - currentPos -= 1; - } - isChar = /[a-zA-Z\{]/; - if (currentPos !== 0) { - if (equation.charAt(currentPos - 1) != '{') { - // Now match to the end of the line. - while (isChar.test(equation.charAt(currentPos)) && - currentPos < equation.length && - isChar.test(equation.charAt(currentPos - 1))) { - currentPos += 1; - } - } - } - // Save the cursor position - for insertion from the library. - this._lastCursorPos = currentPos; - equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos); - - equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END; - // Make an ajax request to the filter. - url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: equation - }; - - Y.io(url, { - context: this, - data: params, - timeout: 500, - on: { - complete: this._loadPreview - } - }); - }, - - /** - * Load returned preview text into preview - * - * @param {String} id - * @param {EventFacade} e - * @method _loadPreview - * @private - */ - _loadPreview: function(id, preview) { - var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW); - - if (preview.status === 200) { - previewNode.setHTML(preview.responseText); - - // Notify the filters about the modified nodes. - require(['core/event'], function(event) { - event.notifyFilterContentUpdated(previewNode.getDOMNode()); - }); - } - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} - * @private - */ - _getDialogueContent: function() { - var library = this._getLibraryContent(), - throttledUpdate = this._throttle(this._updatePreview, 500), - template = Y.Handlebars.compile(TEMPLATES.FORM); - - this._content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - component: COMPONENTNAME, - library: library, - texdocsurl: this.get('texdocsurl'), - CSS: CSS - })); - - // Sets the default focus. - this._content.all(SELECTORS.LIBRARY_GROUP).each(function(group) { - // The first button gets the focus. - this._setGroupTabFocus(group, group.one('button')); - // Sometimes the filter adds an anchor in the button, no tabindex on that. - group.all('button a').setAttribute('tabindex', '-1'); - }, this); - - // Keyboard navigation in groups. - this._content.delegate('key', this._groupNavigation, 'down:37,39', SELECTORS.LIBRARY_BUTTON, this); - - this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', throttledUpdate, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', throttledUpdate, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', throttledUpdate, this); - this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this); - - return this._content; - }, - - /** - * Callback handling the keyboard navigation in the groups of the library. - * - * @param {EventFacade} e The event. - * @method _groupNavigation - * @private - */ - _groupNavigation: function(e) { - e.preventDefault(); - - var current = e.currentTarget, - parent = current.get('parentNode'), // This must be the
                          containing all the buttons of the group. - buttons = parent.all('button'), - direction = e.keyCode !== 37 ? 1 : -1, - index = buttons.indexOf(current), - nextButton; - - if (index < 0) { - Y.log('Unable to find the current button in the list of buttons', 'debug', LOGNAME); - index = 0; - } - - index += direction; - if (index < 0) { - index = buttons.size() - 1; - } else if (index >= buttons.size()) { - index = 0; - } - nextButton = buttons.item(index); - - this._setGroupTabFocus(parent, nextButton); - nextButton.focus(); - }, - - /** - * Sets tab focus for the group. - * - * @method _setGroupTabFocus - * @param {Node} button The node that focus should now be set to. - * @private - */ - _setGroupTabFocus: function(parent, button) { - var parentId = parent.generateID(); - - // Unset the previous entry. - if (typeof this._groupFocus[parentId] !== 'undefined') { - this._groupFocus[parentId].setAttribute('tabindex', '-1'); - } - - // Set on the new entry. - this._groupFocus[parentId] = button; - button.setAttribute('tabindex', 0); - parent.setAttribute('aria-activedescendant', button.generateID()); - }, - - /** - * Reponse to button presses in the TeX library panels. - * - * @method _selectLibraryItem - * @param {EventFacade} e - * @return {string} - * @private - */ - _selectLibraryItem: function(e) { - var tex = e.currentTarget.getAttribute('data-tex'), - oldValue, - newValue, - input, - focusPoint = 0; - - e.preventDefault(); - - // Set the group focus on the button. - this._setGroupTabFocus(e.currentTarget.get('parentNode'), e.currentTarget); - - input = e.currentTarget.ancestor('.atto_form').one('textarea'); - - oldValue = input.get('value'); - - newValue = oldValue.substring(0, this._lastCursorPos); - if (newValue.charAt(newValue.length - 1) !== ' ') { - newValue += ' '; - } - newValue += tex; - focusPoint = newValue.length; - - if (oldValue.charAt(this._lastCursorPos) !== ' ') { - newValue += ' '; - } - newValue += oldValue.substring(this._lastCursorPos, oldValue.length); - - input.set('value', newValue); - input.focus(); - - var realInput = input.getDOMNode(); - if (typeof realInput.selectionStart === "number") { - // Modern browsers have selectionStart and selectionEnd to control the cursor position. - realInput.selectionStart = realInput.selectionEnd = focusPoint; - } else if (typeof realInput.createTextRange !== "undefined") { - // Legacy browsers (IE<=9) use createTextRange(). - var range = realInput.createTextRange(); - range.moveToPoint(focusPoint); - range.select(); - } - // Focus must be set before updating the preview for the cursor box to be in the correct location. - this._updatePreview(false); - }, - - /** - * Return the HTML for rendering the library of predefined buttons. - * - * @method _getLibraryContent - * @return {string} - * @private - */ - _getLibraryContent: function() { - var template = Y.Handlebars.compile(TEMPLATES.LIBRARY), - library = this.get('library'), - content = ''; - - // Helper to iterate over a newline separated string. - Y.Handlebars.registerHelper('split', function(delimiter, str, options) { - var parts, - current, - out; - if (typeof delimiter === "undefined" || typeof str === "undefined") { - Y.log('Handlebars split helper: String and delimiter are required.', 'debug', 'moodle-atto_equation-button'); - return ''; - } - - out = ''; - parts = str.trim().split(delimiter); - while (parts.length > 0) { - current = parts.shift().trim(); - out += options.fn(current); - } - - return out; - }); - content = template({ - elementid: this.get('host').get('elementid'), - elementidescaped: this._escapeQuerySelector(this.get('host').get('elementid')), - component: COMPONENTNAME, - library: library, - CSS: CSS, - DELIMITERS: DELIMITERS - }); - - var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - var params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: content - }; - - var preview = Y.io(url, { - sync: true, - data: params, - method: 'POST' - }); - - if (preview.status === 200) { - content = preview.responseText; - } - return content; - }, - - /** - * Escape special characters in string used as a JS query selector - * - * @method _excapeQuerySelector - * @param {string} selector - * @returns {string} - */ - _escapeQuerySelector: function(selector) { - - // Bootstrap requires that query selectors have special chars excaped. - // See: https://getbootstrap.com/docs/4.2/getting-started/javascript/#selectors - - return selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1'); - } - -}, { - ATTRS: { - /** - * Whether the TeX filter is currently active. - * - * @attribute texfilteractive - * @type Boolean - */ - texfilteractive: { - value: false - }, - - /** - * The contextid to use when generating this preview. - * - * @attribute contextid - * @type String - */ - contextid: { - value: null - }, - - /** - * The content of the example library. - * - * @attribute library - * @type object - */ - library: { - value: {} - }, - - /** - * The link to the Moodle Docs page about TeX. - * - * @attribute texdocsurl - * @type string - */ - texdocsurl: { - value: null - } - - } -}); - - -}, '@VERSION@', { - "requires": [ - "moodle-editor_atto-plugin", - "moodle-core-event", - "io", - "event-valuechange", - "tabview", - "array-extras" - ] -}); diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js deleted file mode 100644 index b1fd862ce26..00000000000 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js +++ /dev/null @@ -1,2 +0,0 @@ -YUI.add("moodle-atto_equation-button",function(a,t){var n="atto_equation",o={EQUATION_TEXT:"atto_equation_equation",EQUATION_PREVIEW:"atto_equation_preview",SUBMIT:"atto_equation_submit",LIBRARY:"atto_equation_library",LIBRARY_GROUPS:"atto_equation_groups",LIBRARY_GROUP_PREFIX:"atto_equation_group"},s={LIBRARY:"."+o.LIBRARY,LIBRARY_GROUP:"."+o.LIBRARY_GROUPS+" > div > div",EQUATION_TEXT:"."+o.EQUATION_TEXT,EQUATION_PREVIEW:"."+o.EQUATION_PREVIEW,SUBMIT:"."+o.SUBMIT,LIBRARY_BUTTON:"."+o.LIBRARY+" button"},r={START:"\\(",END:"\\)"},u='
                          {{{library}}}
                          {{get_string "cursorinfo" component}}

                          ',l='
                          {{#each library}}
                          {{#split "\n" elements}}{{/split}}
                          {{/each}}
                          ';a.namespace("M.atto_equation").Button=a.Base.create("button",a.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_lastCursorPos:0,_content:null,_sourceEquation:null,_groupFocus:null,_equationPatterns:[/\$\$([\S\s]+?)\$\$/,/\\\(([\S\s]+?)\\\)/,/\\\[([\S\s]+?)\\\]/,/\[tex\]([\S\s]+?)\[\/tex\]/],initializer:function(){this._groupFocus={},this.get("texfilteractive")&&(this.addButton({icon:"e/math",callback:this._displayDialogue}),this.get("host").on("atto:selectionchanged",function(){this._resolveEquation()?this.highlightButtons():this.unHighlightButtons()},this),this.editor.all("tex").each(function(t){var e=a.Node.create(""+r.START+" "+t.get("text")+" "+r.END+"");t.replace(e)}))},_displayDialogue:function(){var t,e,i;this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&(t=this._resolveEquation(),e=this.getDialogue({headerContent:M.util.get_string("pluginname",n),focusAfterHide:!0,width:600,focusOnShowSelector:s.LIBRARY_BUTTON}),i=this._getDialogueContent(),e.set("bodyContent",i),e.show(),require(["core/event"],function(t){t.notifyFilterContentUpdated(e.get("boundingBox").getDOMNode())}),t&&i.one(s.EQUATION_TEXT).set("text",t),this._updatePreview(!1))},_resolveEquation:function(){var u,t=this.get("host").getSelectionParentNode(),l=this.get("host").getSelection(),c=!1;return!!this.get("host").isActive()&&(!!t&&(!(!l||0===l.length)&&(this.sourceEquation=null,l=l[0],u=a.one(t).get("text"),a.Array.find(this._equationPatterns,function(r){var t=u.match(new RegExp(r.source,"g"));if(t&&t.length)return a.Array.find(t,function(t){for(var e,i,n,o,a,s=0;-1!==u.indexOf(t,s);){if(i=(e=u.indexOf(t,s))+t.length,o=l.startOffset>=e&&l.startOffsete,o&&a&&(n=t.match(r))&&n.length)return a=(o=u.indexOf(n[1],e))+n[1].length,c=n[1],this.sourceEquation={startOuterPosition:e,endOuterPosition:i,outerMatch:t,startInnerPosition:o,endInnerPosition:a,innerMatch:n},!0;s=i}},this)},this),c=!1!==c?c.trim():c)))},_setEquation:function(t){var e,i,n=this.get("host");t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),""!==(t=t.currentTarget.ancestor(".atto_form").one("textarea").get("value"))&&(n.setSelection(this._currentSelection),this.sourceEquation?(t=" "+t+" ",i=(i=(e=a.one(n.getSelectionParentNode())).get("text")).slice(0,this.sourceEquation.startInnerPosition)+t+i.slice(this.sourceEquation.endInnerPosition),e.set("text",i)):n.insertContentAtFocusPoint(t=r.START+" "+t+" "+r.END),this.markUpdated())},_throttle:function(i,n){var o=null;return function(){var t=this,e=arguments;clearTimeout(o),o=setTimeout(function(){i.apply(t,e)},n)}},_updatePreview:function(t){var e,i=this._content.one(s.EQUATION_TEXT),n=i.get("value"),o=i.get("selectionStart");for(t&&t.preventDefault(),o=o||0;"\\"===n.charAt(o)&&0<=o;)--o;if(e=/[a-zA-Z\{]/,0!==o&&"{"!=n.charAt(o-1))for(;e.test(n.charAt(o))&&o=n.size()&&(e=0),t=n.item(e),this._setGroupTabFocus(i,t),t.focus()},_setGroupTabFocus:function(t,e){var i=t.generateID();"undefined"!=typeof this._groupFocus[i]&&this._groupFocus[i].setAttribute("tabindex","-1"),(this._groupFocus[i]=e).setAttribute("tabindex",0),t.setAttribute("aria-activedescendant",e.generateID())},_selectLibraryItem:function(t){var e,i,n=t.currentTarget.getAttribute("data-tex");t.preventDefault(),this._setGroupTabFocus(t.currentTarget.get("parentNode"),t.currentTarget)," "!==(i=(e=(t=t.currentTarget.ancestor(".atto_form").one("textarea")).get("value")).substring(0,this._lastCursorPos)).charAt(i.length-1)&&(i+=" "),n=(i+=n).length," "!==e.charAt(this._lastCursorPos)&&(i+=" "),i+=e.substring(this._lastCursorPos,e.length),t.set("value",i),t.focus(),"number"==typeof(e=t.getDOMNode()).selectionStart?e.selectionStart=e.selectionEnd=n:"undefined"!=typeof e.createTextRange&&((i=e.createTextRange()).moveToPoint(n),i.select()),this._updatePreview(!1)},_getLibraryContent:function(){var t=a.Handlebars.compile(l),e=this.get("library"),i="";return a.Handlebars.registerHelper("split",function(t,e,i){var n,o,a;if(void 0===t||void 0===e)return"";for(a="",n=e.trim().split(t);0. - -/** - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Atto text editor equation plugin. - */ - -/** - * Atto equation editor. - * - * @namespace M.atto_equation - * @class Button - * @extends M.editor_atto.EditorPlugin - */ -var COMPONENTNAME = 'atto_equation', - LOGNAME = 'atto_equation', - CSS = { - EQUATION_TEXT: 'atto_equation_equation', - EQUATION_PREVIEW: 'atto_equation_preview', - SUBMIT: 'atto_equation_submit', - LIBRARY: 'atto_equation_library', - LIBRARY_GROUPS: 'atto_equation_groups', - LIBRARY_GROUP_PREFIX: 'atto_equation_group' - }, - SELECTORS = { - LIBRARY: '.' + CSS.LIBRARY, - LIBRARY_GROUP: '.' + CSS.LIBRARY_GROUPS + ' > div > div', - EQUATION_TEXT: '.' + CSS.EQUATION_TEXT, - EQUATION_PREVIEW: '.' + CSS.EQUATION_PREVIEW, - SUBMIT: '.' + CSS.SUBMIT, - LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button' - }, - DELIMITERS = { - START: '\\(', - END: '\\)' - }, - TEMPLATES = { - FORM: '' + - '
                          ' + - '{{{library}}}' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          {{get_string "cursorinfo" component}}
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - LIBRARY: '' + - '
                          ' + - '' + - '
                          ' + - '{{#each library}}' + - '
                          ' + - '
                          ' + - '{{#split "\n" elements}}' + - '' + - '{{/split}}' + - '
                          ' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' - }; - -Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * The selection object returned by the browser. - * - * @property _currentSelection - * @type Range - * @default null - * @private - */ - _currentSelection: null, - - /** - * The cursor position in the equation textarea. - * - * @property _lastCursorPos - * @type Number - * @default 0 - * @private - */ - _lastCursorPos: 0, - - /** - * A reference to the dialogue content. - * - * @property _content - * @type Node - * @private - */ - _content: null, - - /** - * The source equation we are editing in the text. - * - * @property _sourceEquation - * @type Object - * @private - */ - _sourceEquation: null, - - /** - * A reference to the tab focus set on each group. - * - * The keys are the IDs of the group, the value is the Node on which the focus is set. - * - * @property _groupFocus - * @type Object - * @private - */ - _groupFocus: null, - - /** - * Regular Expression patterns used to pick out the equations in a String. - * - * @property _equationPatterns - * @type Array - * @private - */ - _equationPatterns: [ - // We use space or not space because . does not match new lines. - // $$ blah $$. - /\$\$([\S\s]+?)\$\$/, - // E.g. "\( blah \)". - /\\\(([\S\s]+?)\\\)/, - // E.g. "\[ blah \]". - /\\\[([\S\s]+?)\\\]/, - // E.g. "[tex] blah [/tex]". - /\[tex\]([\S\s]+?)\[\/tex\]/ - ], - - initializer: function() { - this._groupFocus = {}; - - // If there is a tex filter active - enable this button. - if (this.get('texfilteractive')) { - // Add the button to the toolbar. - this.addButton({ - icon: 'e/math', - callback: this._displayDialogue - }); - - // We need custom highlight logic for this button. - this.get('host').on('atto:selectionchanged', function() { - if (this._resolveEquation()) { - this.highlightButtons(); - } else { - this.unHighlightButtons(); - } - }, this); - - // We need to convert these to a non dom node based format. - this.editor.all('tex').each(function(texNode) { - var replacement = Y.Node.create('' + - DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + - ''); - texNode.replace(replacement); - }); - } - - }, - - /** - * Display the equation editor. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection === false) { - return; - } - - // This needs to be done before the dialogue is opened because the focus will shift to the dialogue. - var equation = this._resolveEquation(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENTNAME), - focusAfterHide: true, - width: 600, - focusOnShowSelector: SELECTORS.LIBRARY_BUTTON - }); - - var content = this._getDialogueContent(); - dialogue.set('bodyContent', content); - - dialogue.show(); - // Notify the filters about the modified nodes. - require(['core/event'], function(event) { - event.notifyFilterContentUpdated(dialogue.get('boundingBox').getDOMNode()); - }); - - if (equation) { - content.one(SELECTORS.EQUATION_TEXT).set('text', equation); - } - this._updatePreview(false); - }, - - /** - * If there is selected text and it is part of an equation, - * extract the equation (and set it in the form). - * - * @method _resolveEquation - * @private - * @return {String|Boolean} The equation or false. - */ - _resolveEquation: function() { - - // Find the equation in the surrounding text. - var selectedNode = this.get('host').getSelectionParentNode(), - selection = this.get('host').getSelection(), - text, - returnValue = false; - - // Prevent resolving equations when we don't have focus. - if (!this.get('host').isActive()) { - return false; - } - - // Note this is a document fragment and YUI doesn't like them. - if (!selectedNode) { - return false; - } - - // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection. - if (!selection || selection.length === 0) { - return false; - } - - this.sourceEquation = null; - - selection = selection[0]; - - text = Y.one(selectedNode).get('text'); - - // For each of these patterns we have a RegExp which captures the inner component of the equation but also - // includes the delimiters. - // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire - // equation including delimiters and returning one entry per match of the whole equation. - // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the - // match results. - Y.Array.find(this._equationPatterns, function(pattern) { - // For each pattern in turn, find all whole matches (including the delimiters). - var patternMatches = text.match(new RegExp(pattern.source, "g")); - - if (patternMatches && patternMatches.length) { - // This pattern matches at least once. See if this pattern matches our current position. - // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent - // searches which is the required behaviour of this function. - return Y.Array.find(patternMatches, function(match) { - // Check each occurrence of this match. - var startIndex = 0; - while (text.indexOf(match, startIndex) !== -1) { - // Determine whether the cursor is in the current occurrence of this string. - // Note: We do not support a selection exceeding the bounds of an equation. - var startOuter = text.indexOf(match, startIndex), - endOuter = startOuter + match.length, - startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter), - endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter); - - if (startMatch && endMatch) { - // This match is in our current position - fetch the innerMatch data. - var innerMatch = match.match(pattern); - if (innerMatch && innerMatch.length) { - // We need the start and end of the inner match for later. - var startInner = text.indexOf(innerMatch[1], startOuter), - endInner = startInner + innerMatch[1].length; - - // We'll be returning the inner match for use in the editor itself. - returnValue = innerMatch[1]; - - // Save all data for later. - this.sourceEquation = { - // Outer match data. - startOuterPosition: startOuter, - endOuterPosition: endOuter, - outerMatch: match, - - // Inner match data. - startInnerPosition: startInner, - endInnerPosition: endInner, - innerMatch: innerMatch - }; - - // This breaks out of both Y.Array.find functions. - return true; - } - } - - // Update the startIndex to match the end of the current match so that we can continue hunting - // for further matches. - startIndex = endOuter; - } - }, this); - } - }, this); - - // We trim the equation when we load it and then add spaces when we save it. - if (returnValue !== false) { - returnValue = returnValue.trim(); - } - return returnValue; - }, - - /** - * Handle insertion of a new equation, or update of an existing one. - * - * @method _setEquation - * @param {EventFacade} e - * @private - */ - _setEquation: function(e) { - var input, - selectedNode, - text, - value, - host, - newText; - - host = this.get('host'); - - e.preventDefault(); - this.getDialogue({ - focusAfterHide: null - }).hide(); - - input = e.currentTarget.ancestor('.atto_form').one('textarea'); - - value = input.get('value'); - if (value !== '') { - host.setSelection(this._currentSelection); - - if (this.sourceEquation) { - // Replace the equation. - selectedNode = Y.one(host.getSelectionParentNode()); - text = selectedNode.get('text'); - value = ' ' + value + ' '; - newText = text.slice(0, this.sourceEquation.startInnerPosition) + - value + - text.slice(this.sourceEquation.endInnerPosition); - - selectedNode.set('text', newText); - } else { - // Insert the new equation. - value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END; - host.insertContentAtFocusPoint(value); - } - - // Clean the YUI ids from the HTML. - this.markUpdated(); - } - }, - - /** - * Smart throttle, only call a function every delay milli seconds, - * and always run the last call. Y.throttle does not work here, - * because it calls the function immediately, the first time, and then - * ignores repeated calls within X seconds. This does not guarantee - * that the last call will be executed (which is required here). - * - * @param {function} fn - * @param {Number} delay Delay in milliseconds - * @method _throttle - * @private - */ - _throttle: function(fn, delay) { - var timer = null; - return function() { - var context = this, args = arguments; - clearTimeout(timer); - timer = setTimeout(function() { - fn.apply(context, args); - }, delay); - }; - }, - - /** - * Update the preview div to match the current equation. - * - * @param {EventFacade} e - * @method _updatePreview - * @private - */ - _updatePreview: function(e) { - var textarea = this._content.one(SELECTORS.EQUATION_TEXT), - equation = textarea.get('value'), - url, - currentPos = textarea.get('selectionStart'), - prefix = '', - cursorLatex = '\\Downarrow ', - isChar, - params; - - if (e) { - e.preventDefault(); - } - - // Move the cursor so it does not break expressions. - // Start at the very beginning. - if (!currentPos) { - currentPos = 0; - } - - // First move back to the beginning of the line. - while (equation.charAt(currentPos) === '\\' && currentPos >= 0) { - currentPos -= 1; - } - isChar = /[a-zA-Z\{]/; - if (currentPos !== 0) { - if (equation.charAt(currentPos - 1) != '{') { - // Now match to the end of the line. - while (isChar.test(equation.charAt(currentPos)) && - currentPos < equation.length && - isChar.test(equation.charAt(currentPos - 1))) { - currentPos += 1; - } - } - } - // Save the cursor position - for insertion from the library. - this._lastCursorPos = currentPos; - equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos); - - equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END; - // Make an ajax request to the filter. - url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: equation - }; - - Y.io(url, { - context: this, - data: params, - timeout: 500, - on: { - complete: this._loadPreview - } - }); - }, - - /** - * Load returned preview text into preview - * - * @param {String} id - * @param {EventFacade} e - * @method _loadPreview - * @private - */ - _loadPreview: function(id, preview) { - var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW); - - if (preview.status === 200) { - previewNode.setHTML(preview.responseText); - - // Notify the filters about the modified nodes. - require(['core/event'], function(event) { - event.notifyFilterContentUpdated(previewNode.getDOMNode()); - }); - } - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} - * @private - */ - _getDialogueContent: function() { - var library = this._getLibraryContent(), - throttledUpdate = this._throttle(this._updatePreview, 500), - template = Y.Handlebars.compile(TEMPLATES.FORM); - - this._content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - component: COMPONENTNAME, - library: library, - texdocsurl: this.get('texdocsurl'), - CSS: CSS - })); - - // Sets the default focus. - this._content.all(SELECTORS.LIBRARY_GROUP).each(function(group) { - // The first button gets the focus. - this._setGroupTabFocus(group, group.one('button')); - // Sometimes the filter adds an anchor in the button, no tabindex on that. - group.all('button a').setAttribute('tabindex', '-1'); - }, this); - - // Keyboard navigation in groups. - this._content.delegate('key', this._groupNavigation, 'down:37,39', SELECTORS.LIBRARY_BUTTON, this); - - this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', throttledUpdate, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', throttledUpdate, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', throttledUpdate, this); - this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this); - - return this._content; - }, - - /** - * Callback handling the keyboard navigation in the groups of the library. - * - * @param {EventFacade} e The event. - * @method _groupNavigation - * @private - */ - _groupNavigation: function(e) { - e.preventDefault(); - - var current = e.currentTarget, - parent = current.get('parentNode'), // This must be the
                          containing all the buttons of the group. - buttons = parent.all('button'), - direction = e.keyCode !== 37 ? 1 : -1, - index = buttons.indexOf(current), - nextButton; - - if (index < 0) { - index = 0; - } - - index += direction; - if (index < 0) { - index = buttons.size() - 1; - } else if (index >= buttons.size()) { - index = 0; - } - nextButton = buttons.item(index); - - this._setGroupTabFocus(parent, nextButton); - nextButton.focus(); - }, - - /** - * Sets tab focus for the group. - * - * @method _setGroupTabFocus - * @param {Node} button The node that focus should now be set to. - * @private - */ - _setGroupTabFocus: function(parent, button) { - var parentId = parent.generateID(); - - // Unset the previous entry. - if (typeof this._groupFocus[parentId] !== 'undefined') { - this._groupFocus[parentId].setAttribute('tabindex', '-1'); - } - - // Set on the new entry. - this._groupFocus[parentId] = button; - button.setAttribute('tabindex', 0); - parent.setAttribute('aria-activedescendant', button.generateID()); - }, - - /** - * Reponse to button presses in the TeX library panels. - * - * @method _selectLibraryItem - * @param {EventFacade} e - * @return {string} - * @private - */ - _selectLibraryItem: function(e) { - var tex = e.currentTarget.getAttribute('data-tex'), - oldValue, - newValue, - input, - focusPoint = 0; - - e.preventDefault(); - - // Set the group focus on the button. - this._setGroupTabFocus(e.currentTarget.get('parentNode'), e.currentTarget); - - input = e.currentTarget.ancestor('.atto_form').one('textarea'); - - oldValue = input.get('value'); - - newValue = oldValue.substring(0, this._lastCursorPos); - if (newValue.charAt(newValue.length - 1) !== ' ') { - newValue += ' '; - } - newValue += tex; - focusPoint = newValue.length; - - if (oldValue.charAt(this._lastCursorPos) !== ' ') { - newValue += ' '; - } - newValue += oldValue.substring(this._lastCursorPos, oldValue.length); - - input.set('value', newValue); - input.focus(); - - var realInput = input.getDOMNode(); - if (typeof realInput.selectionStart === "number") { - // Modern browsers have selectionStart and selectionEnd to control the cursor position. - realInput.selectionStart = realInput.selectionEnd = focusPoint; - } else if (typeof realInput.createTextRange !== "undefined") { - // Legacy browsers (IE<=9) use createTextRange(). - var range = realInput.createTextRange(); - range.moveToPoint(focusPoint); - range.select(); - } - // Focus must be set before updating the preview for the cursor box to be in the correct location. - this._updatePreview(false); - }, - - /** - * Return the HTML for rendering the library of predefined buttons. - * - * @method _getLibraryContent - * @return {string} - * @private - */ - _getLibraryContent: function() { - var template = Y.Handlebars.compile(TEMPLATES.LIBRARY), - library = this.get('library'), - content = ''; - - // Helper to iterate over a newline separated string. - Y.Handlebars.registerHelper('split', function(delimiter, str, options) { - var parts, - current, - out; - if (typeof delimiter === "undefined" || typeof str === "undefined") { - return ''; - } - - out = ''; - parts = str.trim().split(delimiter); - while (parts.length > 0) { - current = parts.shift().trim(); - out += options.fn(current); - } - - return out; - }); - content = template({ - elementid: this.get('host').get('elementid'), - elementidescaped: this._escapeQuerySelector(this.get('host').get('elementid')), - component: COMPONENTNAME, - library: library, - CSS: CSS, - DELIMITERS: DELIMITERS - }); - - var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - var params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: content - }; - - var preview = Y.io(url, { - sync: true, - data: params, - method: 'POST' - }); - - if (preview.status === 200) { - content = preview.responseText; - } - return content; - }, - - /** - * Escape special characters in string used as a JS query selector - * - * @method _excapeQuerySelector - * @param {string} selector - * @returns {string} - */ - _escapeQuerySelector: function(selector) { - - // Bootstrap requires that query selectors have special chars excaped. - // See: https://getbootstrap.com/docs/4.2/getting-started/javascript/#selectors - - return selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1'); - } - -}, { - ATTRS: { - /** - * Whether the TeX filter is currently active. - * - * @attribute texfilteractive - * @type Boolean - */ - texfilteractive: { - value: false - }, - - /** - * The contextid to use when generating this preview. - * - * @attribute contextid - * @type String - */ - contextid: { - value: null - }, - - /** - * The content of the example library. - * - * @attribute library - * @type object - */ - library: { - value: {} - }, - - /** - * The link to the Moodle Docs page about TeX. - * - * @attribute texdocsurl - * @type string - */ - texdocsurl: { - value: null - } - - } -}); - - -}, '@VERSION@', { - "requires": [ - "moodle-editor_atto-plugin", - "moodle-core-event", - "io", - "event-valuechange", - "tabview", - "array-extras" - ] -}); diff --git a/lib/editor/atto/plugins/equation/yui/src/button/build.json b/lib/editor/atto/plugins/equation/yui/src/button/build.json deleted file mode 100644 index a396fd1903a..00000000000 --- a/lib/editor/atto/plugins/equation/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_equation-button", - "builds": { - "moodle-atto_equation-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/equation/yui/src/button/js/button.js b/lib/editor/atto/plugins/equation/yui/src/button/js/button.js deleted file mode 100644 index 35c8d455a2f..00000000000 --- a/lib/editor/atto/plugins/equation/yui/src/button/js/button.js +++ /dev/null @@ -1,777 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_equation - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Atto text editor equation plugin. - */ - -/** - * Atto equation editor. - * - * @namespace M.atto_equation - * @class Button - * @extends M.editor_atto.EditorPlugin - */ -var COMPONENTNAME = 'atto_equation', - LOGNAME = 'atto_equation', - CSS = { - EQUATION_TEXT: 'atto_equation_equation', - EQUATION_PREVIEW: 'atto_equation_preview', - SUBMIT: 'atto_equation_submit', - LIBRARY: 'atto_equation_library', - LIBRARY_GROUPS: 'atto_equation_groups', - LIBRARY_GROUP_PREFIX: 'atto_equation_group' - }, - SELECTORS = { - LIBRARY: '.' + CSS.LIBRARY, - LIBRARY_GROUP: '.' + CSS.LIBRARY_GROUPS + ' > div > div', - EQUATION_TEXT: '.' + CSS.EQUATION_TEXT, - EQUATION_PREVIEW: '.' + CSS.EQUATION_PREVIEW, - SUBMIT: '.' + CSS.SUBMIT, - LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button' - }, - DELIMITERS = { - START: '\\(', - END: '\\)' - }, - TEMPLATES = { - FORM: '' + - '
                          ' + - '{{{library}}}' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          {{get_string "cursorinfo" component}}
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - LIBRARY: '' + - '
                          ' + - '' + - '
                          ' + - '{{#each library}}' + - '
                          ' + - '
                          ' + - '{{#split "\n" elements}}' + - '' + - '{{/split}}' + - '
                          ' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' - }; - -Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * The selection object returned by the browser. - * - * @property _currentSelection - * @type Range - * @default null - * @private - */ - _currentSelection: null, - - /** - * The cursor position in the equation textarea. - * - * @property _lastCursorPos - * @type Number - * @default 0 - * @private - */ - _lastCursorPos: 0, - - /** - * A reference to the dialogue content. - * - * @property _content - * @type Node - * @private - */ - _content: null, - - /** - * The source equation we are editing in the text. - * - * @property _sourceEquation - * @type Object - * @private - */ - _sourceEquation: null, - - /** - * A reference to the tab focus set on each group. - * - * The keys are the IDs of the group, the value is the Node on which the focus is set. - * - * @property _groupFocus - * @type Object - * @private - */ - _groupFocus: null, - - /** - * Regular Expression patterns used to pick out the equations in a String. - * - * @property _equationPatterns - * @type Array - * @private - */ - _equationPatterns: [ - // We use space or not space because . does not match new lines. - // $$ blah $$. - /\$\$([\S\s]+?)\$\$/, - // E.g. "\( blah \)". - /\\\(([\S\s]+?)\\\)/, - // E.g. "\[ blah \]". - /\\\[([\S\s]+?)\\\]/, - // E.g. "[tex] blah [/tex]". - /\[tex\]([\S\s]+?)\[\/tex\]/ - ], - - initializer: function() { - this._groupFocus = {}; - - // If there is a tex filter active - enable this button. - if (this.get('texfilteractive')) { - // Add the button to the toolbar. - this.addButton({ - icon: 'e/math', - callback: this._displayDialogue - }); - - // We need custom highlight logic for this button. - this.get('host').on('atto:selectionchanged', function() { - if (this._resolveEquation()) { - this.highlightButtons(); - } else { - this.unHighlightButtons(); - } - }, this); - - // We need to convert these to a non dom node based format. - this.editor.all('tex').each(function(texNode) { - var replacement = Y.Node.create('' + - DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + - ''); - texNode.replace(replacement); - }); - } - - }, - - /** - * Display the equation editor. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection === false) { - return; - } - - // This needs to be done before the dialogue is opened because the focus will shift to the dialogue. - var equation = this._resolveEquation(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENTNAME), - focusAfterHide: true, - width: 600, - focusOnShowSelector: SELECTORS.LIBRARY_BUTTON - }); - - var content = this._getDialogueContent(); - dialogue.set('bodyContent', content); - - dialogue.show(); - // Notify the filters about the modified nodes. - require(['core/event'], function(event) { - event.notifyFilterContentUpdated(dialogue.get('boundingBox').getDOMNode()); - }); - - if (equation) { - content.one(SELECTORS.EQUATION_TEXT).set('text', equation); - } - this._updatePreview(false); - }, - - /** - * If there is selected text and it is part of an equation, - * extract the equation (and set it in the form). - * - * @method _resolveEquation - * @private - * @return {String|Boolean} The equation or false. - */ - _resolveEquation: function() { - - // Find the equation in the surrounding text. - var selectedNode = this.get('host').getSelectionParentNode(), - selection = this.get('host').getSelection(), - text, - returnValue = false; - - // Prevent resolving equations when we don't have focus. - if (!this.get('host').isActive()) { - return false; - } - - // Note this is a document fragment and YUI doesn't like them. - if (!selectedNode) { - return false; - } - - // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection. - if (!selection || selection.length === 0) { - return false; - } - - this.sourceEquation = null; - - selection = selection[0]; - - text = Y.one(selectedNode).get('text'); - - // For each of these patterns we have a RegExp which captures the inner component of the equation but also - // includes the delimiters. - // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire - // equation including delimiters and returning one entry per match of the whole equation. - // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the - // match results. - Y.Array.find(this._equationPatterns, function(pattern) { - // For each pattern in turn, find all whole matches (including the delimiters). - var patternMatches = text.match(new RegExp(pattern.source, "g")); - - if (patternMatches && patternMatches.length) { - // This pattern matches at least once. See if this pattern matches our current position. - // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent - // searches which is the required behaviour of this function. - return Y.Array.find(patternMatches, function(match) { - // Check each occurrence of this match. - var startIndex = 0; - while (text.indexOf(match, startIndex) !== -1) { - // Determine whether the cursor is in the current occurrence of this string. - // Note: We do not support a selection exceeding the bounds of an equation. - var startOuter = text.indexOf(match, startIndex), - endOuter = startOuter + match.length, - startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter), - endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter); - - if (startMatch && endMatch) { - // This match is in our current position - fetch the innerMatch data. - var innerMatch = match.match(pattern); - if (innerMatch && innerMatch.length) { - // We need the start and end of the inner match for later. - var startInner = text.indexOf(innerMatch[1], startOuter), - endInner = startInner + innerMatch[1].length; - - // We'll be returning the inner match for use in the editor itself. - returnValue = innerMatch[1]; - - // Save all data for later. - this.sourceEquation = { - // Outer match data. - startOuterPosition: startOuter, - endOuterPosition: endOuter, - outerMatch: match, - - // Inner match data. - startInnerPosition: startInner, - endInnerPosition: endInner, - innerMatch: innerMatch - }; - - // This breaks out of both Y.Array.find functions. - return true; - } - } - - // Update the startIndex to match the end of the current match so that we can continue hunting - // for further matches. - startIndex = endOuter; - } - }, this); - } - }, this); - - // We trim the equation when we load it and then add spaces when we save it. - if (returnValue !== false) { - returnValue = returnValue.trim(); - } - return returnValue; - }, - - /** - * Handle insertion of a new equation, or update of an existing one. - * - * @method _setEquation - * @param {EventFacade} e - * @private - */ - _setEquation: function(e) { - var input, - selectedNode, - text, - value, - host, - newText; - - host = this.get('host'); - - e.preventDefault(); - this.getDialogue({ - focusAfterHide: null - }).hide(); - - input = e.currentTarget.ancestor('.atto_form').one('textarea'); - - value = input.get('value'); - if (value !== '') { - host.setSelection(this._currentSelection); - - if (this.sourceEquation) { - // Replace the equation. - selectedNode = Y.one(host.getSelectionParentNode()); - text = selectedNode.get('text'); - value = ' ' + value + ' '; - newText = text.slice(0, this.sourceEquation.startInnerPosition) + - value + - text.slice(this.sourceEquation.endInnerPosition); - - selectedNode.set('text', newText); - } else { - // Insert the new equation. - value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END; - host.insertContentAtFocusPoint(value); - } - - // Clean the YUI ids from the HTML. - this.markUpdated(); - } - }, - - /** - * Smart throttle, only call a function every delay milli seconds, - * and always run the last call. Y.throttle does not work here, - * because it calls the function immediately, the first time, and then - * ignores repeated calls within X seconds. This does not guarantee - * that the last call will be executed (which is required here). - * - * @param {function} fn - * @param {Number} delay Delay in milliseconds - * @method _throttle - * @private - */ - _throttle: function(fn, delay) { - var timer = null; - return function() { - var context = this, args = arguments; - clearTimeout(timer); - timer = setTimeout(function() { - fn.apply(context, args); - }, delay); - }; - }, - - /** - * Update the preview div to match the current equation. - * - * @param {EventFacade} e - * @method _updatePreview - * @private - */ - _updatePreview: function(e) { - var textarea = this._content.one(SELECTORS.EQUATION_TEXT), - equation = textarea.get('value'), - url, - currentPos = textarea.get('selectionStart'), - prefix = '', - cursorLatex = '\\Downarrow ', - isChar, - params; - - if (e) { - e.preventDefault(); - } - - // Move the cursor so it does not break expressions. - // Start at the very beginning. - if (!currentPos) { - currentPos = 0; - } - - // First move back to the beginning of the line. - while (equation.charAt(currentPos) === '\\' && currentPos >= 0) { - currentPos -= 1; - } - isChar = /[a-zA-Z\{]/; - if (currentPos !== 0) { - if (equation.charAt(currentPos - 1) != '{') { - // Now match to the end of the line. - while (isChar.test(equation.charAt(currentPos)) && - currentPos < equation.length && - isChar.test(equation.charAt(currentPos - 1))) { - currentPos += 1; - } - } - } - // Save the cursor position - for insertion from the library. - this._lastCursorPos = currentPos; - equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos); - - equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END; - // Make an ajax request to the filter. - url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: equation - }; - - Y.io(url, { - context: this, - data: params, - timeout: 500, - on: { - complete: this._loadPreview - } - }); - }, - - /** - * Load returned preview text into preview - * - * @param {String} id - * @param {EventFacade} e - * @method _loadPreview - * @private - */ - _loadPreview: function(id, preview) { - var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW); - - if (preview.status === 200) { - previewNode.setHTML(preview.responseText); - - // Notify the filters about the modified nodes. - require(['core/event'], function(event) { - event.notifyFilterContentUpdated(previewNode.getDOMNode()); - }); - } - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} - * @private - */ - _getDialogueContent: function() { - var library = this._getLibraryContent(), - throttledUpdate = this._throttle(this._updatePreview, 500), - template = Y.Handlebars.compile(TEMPLATES.FORM); - - this._content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - component: COMPONENTNAME, - library: library, - texdocsurl: this.get('texdocsurl'), - CSS: CSS - })); - - // Sets the default focus. - this._content.all(SELECTORS.LIBRARY_GROUP).each(function(group) { - // The first button gets the focus. - this._setGroupTabFocus(group, group.one('button')); - // Sometimes the filter adds an anchor in the button, no tabindex on that. - group.all('button a').setAttribute('tabindex', '-1'); - }, this); - - // Keyboard navigation in groups. - this._content.delegate('key', this._groupNavigation, 'down:37,39', SELECTORS.LIBRARY_BUTTON, this); - - this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', throttledUpdate, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', throttledUpdate, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', throttledUpdate, this); - this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this); - - return this._content; - }, - - /** - * Callback handling the keyboard navigation in the groups of the library. - * - * @param {EventFacade} e The event. - * @method _groupNavigation - * @private - */ - _groupNavigation: function(e) { - e.preventDefault(); - - var current = e.currentTarget, - parent = current.get('parentNode'), // This must be the
                          containing all the buttons of the group. - buttons = parent.all('button'), - direction = e.keyCode !== 37 ? 1 : -1, - index = buttons.indexOf(current), - nextButton; - - if (index < 0) { - Y.log('Unable to find the current button in the list of buttons', 'debug', LOGNAME); - index = 0; - } - - index += direction; - if (index < 0) { - index = buttons.size() - 1; - } else if (index >= buttons.size()) { - index = 0; - } - nextButton = buttons.item(index); - - this._setGroupTabFocus(parent, nextButton); - nextButton.focus(); - }, - - /** - * Sets tab focus for the group. - * - * @method _setGroupTabFocus - * @param {Node} button The node that focus should now be set to. - * @private - */ - _setGroupTabFocus: function(parent, button) { - var parentId = parent.generateID(); - - // Unset the previous entry. - if (typeof this._groupFocus[parentId] !== 'undefined') { - this._groupFocus[parentId].setAttribute('tabindex', '-1'); - } - - // Set on the new entry. - this._groupFocus[parentId] = button; - button.setAttribute('tabindex', 0); - parent.setAttribute('aria-activedescendant', button.generateID()); - }, - - /** - * Reponse to button presses in the TeX library panels. - * - * @method _selectLibraryItem - * @param {EventFacade} e - * @return {string} - * @private - */ - _selectLibraryItem: function(e) { - var tex = e.currentTarget.getAttribute('data-tex'), - oldValue, - newValue, - input, - focusPoint = 0; - - e.preventDefault(); - - // Set the group focus on the button. - this._setGroupTabFocus(e.currentTarget.get('parentNode'), e.currentTarget); - - input = e.currentTarget.ancestor('.atto_form').one('textarea'); - - oldValue = input.get('value'); - - newValue = oldValue.substring(0, this._lastCursorPos); - if (newValue.charAt(newValue.length - 1) !== ' ') { - newValue += ' '; - } - newValue += tex; - focusPoint = newValue.length; - - if (oldValue.charAt(this._lastCursorPos) !== ' ') { - newValue += ' '; - } - newValue += oldValue.substring(this._lastCursorPos, oldValue.length); - - input.set('value', newValue); - input.focus(); - - var realInput = input.getDOMNode(); - if (typeof realInput.selectionStart === "number") { - // Modern browsers have selectionStart and selectionEnd to control the cursor position. - realInput.selectionStart = realInput.selectionEnd = focusPoint; - } else if (typeof realInput.createTextRange !== "undefined") { - // Legacy browsers (IE<=9) use createTextRange(). - var range = realInput.createTextRange(); - range.moveToPoint(focusPoint); - range.select(); - } - // Focus must be set before updating the preview for the cursor box to be in the correct location. - this._updatePreview(false); - }, - - /** - * Return the HTML for rendering the library of predefined buttons. - * - * @method _getLibraryContent - * @return {string} - * @private - */ - _getLibraryContent: function() { - var template = Y.Handlebars.compile(TEMPLATES.LIBRARY), - library = this.get('library'), - content = ''; - - // Helper to iterate over a newline separated string. - Y.Handlebars.registerHelper('split', function(delimiter, str, options) { - var parts, - current, - out; - if (typeof delimiter === "undefined" || typeof str === "undefined") { - Y.log('Handlebars split helper: String and delimiter are required.', 'debug', 'moodle-atto_equation-button'); - return ''; - } - - out = ''; - parts = str.trim().split(delimiter); - while (parts.length > 0) { - current = parts.shift().trim(); - out += options.fn(current); - } - - return out; - }); - content = template({ - elementid: this.get('host').get('elementid'), - elementidescaped: this._escapeQuerySelector(this.get('host').get('elementid')), - component: COMPONENTNAME, - library: library, - CSS: CSS, - DELIMITERS: DELIMITERS - }); - - var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - var params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: content - }; - - var preview = Y.io(url, { - sync: true, - data: params, - method: 'POST' - }); - - if (preview.status === 200) { - content = preview.responseText; - } - return content; - }, - - /** - * Escape special characters in string used as a JS query selector - * - * @method _excapeQuerySelector - * @param {string} selector - * @returns {string} - */ - _escapeQuerySelector: function(selector) { - - // Bootstrap requires that query selectors have special chars excaped. - // See: https://getbootstrap.com/docs/4.2/getting-started/javascript/#selectors - - return selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1'); - } - -}, { - ATTRS: { - /** - * Whether the TeX filter is currently active. - * - * @attribute texfilteractive - * @type Boolean - */ - texfilteractive: { - value: false - }, - - /** - * The contextid to use when generating this preview. - * - * @attribute contextid - * @type String - */ - contextid: { - value: null - }, - - /** - * The content of the example library. - * - * @attribute library - * @type object - */ - library: { - value: {} - }, - - /** - * The link to the Moodle Docs page about TeX. - * - * @attribute texdocsurl - * @type string - */ - texdocsurl: { - value: null - } - - } -}); diff --git a/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json b/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json deleted file mode 100644 index 144f41791d8..00000000000 --- a/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "moodle-atto_equation-button": { - "requires": [ - "moodle-editor_atto-plugin", - "moodle-core-event", - "io", - "event-valuechange", - "tabview", - "array-extras" - ] - } -} diff --git a/lib/editor/atto/plugins/fontcolor/classes/privacy/provider.php b/lib/editor/atto/plugins/fontcolor/classes/privacy/provider.php deleted file mode 100644 index e5acab98396..00000000000 --- a/lib/editor/atto/plugins/fontcolor/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_fontcolor - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_fontcolor\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_fontcolor implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/fontcolor/lang/en/atto_fontcolor.php b/lib/editor/atto/plugins/fontcolor/lang/en/atto_fontcolor.php deleted file mode 100644 index 398233c3464..00000000000 --- a/lib/editor/atto/plugins/fontcolor/lang/en/atto_fontcolor.php +++ /dev/null @@ -1,32 +0,0 @@ -. - -/** - * Strings for component 'atto_fontcolor', language 'en'. - * - * @package atto_fontcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['color_white'] = 'White'; -$string['color_red'] = 'Red'; -$string['color_yellow'] = 'Yellow'; -$string['color_green'] = 'Green'; -$string['color_blue'] = 'Blue'; -$string['color_black'] = 'Black'; -$string['pluginname'] = 'Font colour'; -$string['privacy:metadata'] = 'The atto_fontcolor plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/fontcolor/lib.php b/lib/editor/atto/plugins/fontcolor/lib.php deleted file mode 100644 index bc8cfad5b91..00000000000 --- a/lib/editor/atto/plugins/fontcolor/lib.php +++ /dev/null @@ -1,41 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_fontcolor - * @copyright 2021 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the js strings required for this module. - */ -function atto_fontcolor_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js([ - 'color_white', - 'color_red', - 'color_yellow', - 'color_green', - 'color_blue', - 'color_black' - ], 'atto_fontcolor'); -} diff --git a/lib/editor/atto/plugins/fontcolor/styles.css b/lib/editor/atto/plugins/fontcolor/styles.css deleted file mode 100644 index 2c22dc856cf..00000000000 --- a/lib/editor/atto/plugins/fontcolor/styles.css +++ /dev/null @@ -1,26 +0,0 @@ -.atto_fontcolor_button .dropdown-menu { - min-width: inherit; -} - -.atto_fontcolor_button .dropdown-menu .atto_menuentry { - padding-top: 5px; - padding-bottom: 5px; -} - -.atto_fontcolor_button .dropdown-menu .atto_menuentry a[role=menuitem] { - display: flex; -} - -.atto_fontcolor_button .dropdown-menu .atto_menuentry a[role=menuitem]:hover, -.atto_fontcolor_button .dropdown-menu .atto_menuentry a[role=menuitem]:focus { - box-shadow: #0f6fc5 0 0 3px 1px; -} - -.atto_fontcolor_button .dropdown-menu .coloroption { - display: flex; - align-items: center; - float: left; - height: 20px; - width: 20px; - border: 1px solid #ccc; -} diff --git a/lib/editor/atto/plugins/fontcolor/version.php b/lib/editor/atto/plugins/fontcolor/version.php deleted file mode 100644 index 24e8df2959b..00000000000 --- a/lib/editor/atto/plugins/fontcolor/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_fontcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_fontcolor'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-debug.js b/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-debug.js deleted file mode 100644 index 23d9b2d8ce7..00000000000 --- a/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-debug.js +++ /dev/null @@ -1,99 +0,0 @@ -YUI.add('moodle-atto_fontcolor-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_fontcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_align-button - */ - -/** - * Atto text editor fontcolor plugin. - * - * @namespace M.atto_fontcolor - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var colors = [ - { - name: 'white', - color: '#FFFFFF' - }, { - name: 'red', - color: '#EF4540' - }, { - name: 'yellow', - color: '#FFCF35' - }, { - name: 'green', - color: '#98CA3E' - }, { - name: 'blue', - color: '#7D9FD3' - }, { - name: 'black', - color: '#333333' - } - ]; - -Y.namespace('M.atto_fontcolor').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(colors, function(color) { - var colorLabel = M.util.get_string('color_' + color.name, 'atto_fontcolor'); - items.push({ - text: '
                          ', - callbackArgs: color.color, - callback: this._changeStyle - }); - }); - - this.addToolbarMenu({ - icon: 'e/text_color', - overlayWidth: '4', - menuColor: '#333333', - globalItemConfig: { - inlineFormat: true, - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the font color to the specified color. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new font color - * @private - */ - _changeStyle: function(e, color) { - this.get('host').formatSelectionInlineStyle({ - color: color - }); - } -}); - - -}, '@VERSION@'); diff --git a/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-min.js b/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-min.js deleted file mode 100644 index 8659fdce824..00000000000 --- a/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_fontcolor-button",function(o,t){var e=[{name:"white",color:"#FFFFFF"},{name:"red",color:"#EF4540"},{name:"yellow",color:"#FFCF35"},{name:"green",color:"#98CA3E"},{name:"blue",color:"#7D9FD3"},{name:"black",color:"#333333"}];o.namespace("M.atto_fontcolor").Button=o.Base.create("button",o.M.editor_atto.EditorPlugin,[],{initializer:function(){var l=[];o.Array.each(e,function(o){var t=M.util.get_string("color_"+o.name,"atto_fontcolor");l.push({text:'
                          ',callbackArgs:o.color,callback:this._changeStyle})}),this.addToolbarMenu({icon:"e/text_color",overlayWidth:"4",menuColor:"#333333",globalItemConfig:{inlineFormat:!0,callback:this._changeStyle},items:l})},_changeStyle:function(o,t){this.get("host").formatSelectionInlineStyle({color:t})}})},"@VERSION@"); \ No newline at end of file diff --git a/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button.js b/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button.js deleted file mode 100644 index 23d9b2d8ce7..00000000000 --- a/lib/editor/atto/plugins/fontcolor/yui/build/moodle-atto_fontcolor-button/moodle-atto_fontcolor-button.js +++ /dev/null @@ -1,99 +0,0 @@ -YUI.add('moodle-atto_fontcolor-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_fontcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_align-button - */ - -/** - * Atto text editor fontcolor plugin. - * - * @namespace M.atto_fontcolor - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var colors = [ - { - name: 'white', - color: '#FFFFFF' - }, { - name: 'red', - color: '#EF4540' - }, { - name: 'yellow', - color: '#FFCF35' - }, { - name: 'green', - color: '#98CA3E' - }, { - name: 'blue', - color: '#7D9FD3' - }, { - name: 'black', - color: '#333333' - } - ]; - -Y.namespace('M.atto_fontcolor').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(colors, function(color) { - var colorLabel = M.util.get_string('color_' + color.name, 'atto_fontcolor'); - items.push({ - text: '
                          ', - callbackArgs: color.color, - callback: this._changeStyle - }); - }); - - this.addToolbarMenu({ - icon: 'e/text_color', - overlayWidth: '4', - menuColor: '#333333', - globalItemConfig: { - inlineFormat: true, - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the font color to the specified color. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new font color - * @private - */ - _changeStyle: function(e, color) { - this.get('host').formatSelectionInlineStyle({ - color: color - }); - } -}); - - -}, '@VERSION@'); diff --git a/lib/editor/atto/plugins/fontcolor/yui/src/button/build.json b/lib/editor/atto/plugins/fontcolor/yui/src/button/build.json deleted file mode 100644 index 9357f86112c..00000000000 --- a/lib/editor/atto/plugins/fontcolor/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_fontcolor-button", - "builds": { - "moodle-atto_fontcolor-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/fontcolor/yui/src/button/js/button.js b/lib/editor/atto/plugins/fontcolor/yui/src/button/js/button.js deleted file mode 100644 index f8dcf6a65f8..00000000000 --- a/lib/editor/atto/plugins/fontcolor/yui/src/button/js/button.js +++ /dev/null @@ -1,94 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_fontcolor - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_align-button - */ - -/** - * Atto text editor fontcolor plugin. - * - * @namespace M.atto_fontcolor - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var colors = [ - { - name: 'white', - color: '#FFFFFF' - }, { - name: 'red', - color: '#EF4540' - }, { - name: 'yellow', - color: '#FFCF35' - }, { - name: 'green', - color: '#98CA3E' - }, { - name: 'blue', - color: '#7D9FD3' - }, { - name: 'black', - color: '#333333' - } - ]; - -Y.namespace('M.atto_fontcolor').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(colors, function(color) { - var colorLabel = M.util.get_string('color_' + color.name, 'atto_fontcolor'); - items.push({ - text: '
                          ', - callbackArgs: color.color, - callback: this._changeStyle - }); - }); - - this.addToolbarMenu({ - icon: 'e/text_color', - overlayWidth: '4', - menuColor: '#333333', - globalItemConfig: { - inlineFormat: true, - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the font color to the specified color. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new font color - * @private - */ - _changeStyle: function(e, color) { - this.get('host').formatSelectionInlineStyle({ - color: color - }); - } -}); diff --git a/lib/editor/atto/plugins/fontcolor/yui/src/button/meta/editor.js b/lib/editor/atto/plugins/fontcolor/yui/src/button/meta/editor.js deleted file mode 100644 index ebbc79e20da..00000000000 --- a/lib/editor/atto/plugins/fontcolor/yui/src/button/meta/editor.js +++ /dev/null @@ -1,5 +0,0 @@ -{ - "moodle-atto_fontcolor-button": { - "requires": ["node"] - } -} diff --git a/lib/editor/atto/plugins/h5p/classes/privacy/provider.php b/lib/editor/atto/plugins/h5p/classes/privacy/provider.php deleted file mode 100644 index 02fd75886b7..00000000000 --- a/lib/editor/atto/plugins/h5p/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for atto_h5p. - * - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_h5p\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_h5p implementing null_provider. - * - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/h5p/db/access.php b/lib/editor/atto/plugins/h5p/db/access.php deleted file mode 100644 index 76bde795338..00000000000 --- a/lib/editor/atto/plugins/h5p/db/access.php +++ /dev/null @@ -1,35 +0,0 @@ -. - -/** - * H5P Atto button capabilities. - * - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$capabilities = [ - 'atto/h5p:addembed' => [ - 'captype' => 'write', - 'contextlevel' => CONTEXT_MODULE, - 'archetypes' => [ - 'editingteacher' => CAP_ALLOW, - ], - ] -]; diff --git a/lib/editor/atto/plugins/h5p/lang/en/atto_h5p.php b/lib/editor/atto/plugins/h5p/lang/en/atto_h5p.php deleted file mode 100644 index a8eb177f3e9..00000000000 --- a/lib/editor/atto/plugins/h5p/lang/en/atto_h5p.php +++ /dev/null @@ -1,38 +0,0 @@ -. - -/** - * Strings for component 'atto_h5p', language 'en'. - * - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['browserepositories'] = 'Browse repositories...'; -$string['copyrightbutton'] = 'Copyright button'; -$string['downloadbutton'] = 'Allow download'; -$string['embedbutton'] = 'Embed button'; -$string['h5p:addembed'] = 'Add embedded H5P'; -$string['h5pfile'] = 'H5P file upload'; -$string['h5pfileorurl'] = 'H5P URL or file upload'; -$string['h5poptions'] = 'H5P options'; -$string['h5purl'] = 'H5P URL'; -$string['invalidh5purl'] = 'Invalid URL'; -$string['instructions'] = 'You can insert H5P content by either entering a URL or by uploading an H5P file.'; -$string['noh5pcontent'] = 'No H5P content added'; -$string['pluginname'] = 'Insert H5P'; -$string['privacy:metadata'] = 'The atto_h5p plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/h5p/lib.php b/lib/editor/atto/plugins/h5p/lib.php deleted file mode 100644 index 6b9da45f324..00000000000 --- a/lib/editor/atto/plugins/h5p/lib.php +++ /dev/null @@ -1,85 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -use core_h5p\local\library\autoloader; - -/** - * Set params for this button. - * - * @param string $elementid - * @param stdClass $options - the options for the editor, including the context. - * @param stdClass $fpoptions - unused. - */ -function atto_h5p_params_for_js($elementid, $options, $fpoptions) { - $context = $options['context']; - if (!$context) { - $context = context_system::instance(); - } - - $addembed = has_capability('atto/h5p:addembed', $context); - $upload = has_capability('moodle/h5p:deploy', $context); - - $allowedmethods = 'none'; - if ($addembed && $upload) { - $allowedmethods = 'both'; - } else if ($addembed) { - $allowedmethods = 'embed'; - } else if ($upload) { - $allowedmethods = 'upload'; - } - - $params = [ - 'allowedmethods' => $allowedmethods, - 'storeinrepo' => true - ]; - return $params; -} - -/** - * Initialise the strings required for js - */ -function atto_h5p_strings_for_js() { - global $PAGE; - - $strings = array( - 'browserepositories', - 'copyrightbutton', - 'downloadbutton', - 'instructions', - 'embedbutton', - 'h5pfile', - 'h5poptions', - 'h5purl', - 'h5pfileorurl', - 'invalidh5purl', - 'noh5pcontent', - 'pluginname' - ); - - $PAGE->requires->strings_for_js($strings, 'atto_h5p'); - $PAGE->requires->strings_for_js(['expand', 'collapse'], 'moodle'); - $PAGE->requires->js(autoloader::get_h5p_core_library_url('js/h5p-resizer.js')); -} diff --git a/lib/editor/atto/plugins/h5p/pix/icon-white.png b/lib/editor/atto/plugins/h5p/pix/icon-white.png deleted file mode 100644 index d2ac8b26ad680b87e7509c8d720ad7401c592de1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6257 zcmXwec|6qH|Nq-C8b(aXaIG`hx{M`dUou+ciX>!`v1V(KP_ks5ly$l)-O5(hv5!3_ zyP2Yrnk-{iQAlo#b@V;%=lA==!#U@Dme=cfUg!0CJzsOz#@c+ZprjxKL3=GupRk1> z7!87WG!Xn?q{;VS4EQH-^)w+Eg2eaj{_(t4`gII~B;+kl;O)YmE{<{SrOerTCN0u_ zo1cXr5_@C^m9*umI?DO#y}yZ!cBn>Z+-7HYoxF3Yz4;Q`fsc7m>wfC7~LJM z92BoV_fWm^1qyt`W*;PBEfX-&<6R{|3bZs(KlXB6sLkuF*JqeQfpFdLz1YZPHx4bq zK8%mxdVyLE`Ic^yj@?G>=yGgSnXu*oIV2_hi%o<{p@%Z)+TMdRKRg+_WuvyJE!F8I z6NjrxZc4(La?)l_$wZS;0n-%^3Hv=`oe|a0jIG-Is&@Zilg(Qmnj^Ea3 zf?vd=hsYSDWTRQv@+ZX4ja6U`SGq#YA0HI53;@92^(o98v4avhHtb?~);`qM~ z6!>GCRJiN#xzT^GbEZ{|_j$%DomqjoX8AR<+1QJF`3SiJVgyL%=8+Q9btmn{Q%CX8)F+Ax4VrnxUa&(s8vu#0-yZ<0>^ynq z22LW}KC#{bxI$l6Y#2ccGtP*qvgCc>d#IfUkKTQ2rDy?Ko5AL8J6tiIjsP97kMw{q zV#+TkM}r9~wUfdcRjwOBAtjI3wf(n#fr}LbLTuX9NsQKVZ|rt~7%K&#$*~w@*|UR4 z(;P2MmP0Xl3w95Hf|uiP&~g2- z%Uj^)91H8980?$JJ8WPJbM2=PkWg8WJwP2@(gUN!ow6r@Ir+!XF$a!PUjwZVf+K9J zLmR*e#lr}mnENdP*fYAua-i$03SqRRN@;O8oAaq~jCSUe>~swBBf#bKn{$Y%$gyBx zS&uPD)1*%hm*E6VS1Jm^oMh!!zM{@5GGTaabWB${NdqY2`b-?U3qY*fT|4}m1H+@k z1hGcwV}elrkCVI7)rvtBUNDMx;(_$_oNlGX;c@{I!f6jX7gQ7XCKVk7Hdy7qw3S9L zZc`&{Z(0Z$q_BslZ(35wv?#SGC??BjEpnOtb>eXk<5fpAd34$49(*USJeU5xD=ce1 zqe%Ds@v&ycx}$LW2Z^}vj36G5!>5XpD=ol!Usaza(#Bq~(-*}80;lD>lHb=1sbD{T z{gT6hWzcg;aij=#_*zWu7^7LmzJN1}>QH8=N-3|3ih1T;I$J%FdYz9Tk*@NQ2;Qlv zS=dse(pd`J&STAW8j*57H0T%-yM4fHeL+Imk^(=oG7|5HOJRGAp8P(D>KLuIemlP@ zAV9NG7aQhS3$Mn<=8yIu2lpf@>Q5jA<8b#aPu3fY5e_lvnoshVEZJbDk`%U9x6V%F zz%1dBRT>5f|KQM{?T5QxB3yGeEqZ?~+O(Z-n8QanG#LDp&kHv6QwdKYyMIgfKMQna zU3sfjwxlYKpxI>a0UH$_LnDH;<3&!nUp6wL0XWx?KCBW^$pG`?PjTivEZrSYOX^Q5WpMPRAy z(SQwuu^K;~11GfWje&dmdagb9hB?5aGYP&Z0Gx^-zp*HoKJLo?Acs7f=h}Y+h_9L6 zKp)ET1MUgK-tFfCb$}01WOB|>$XW;*SlOnYo#GG;#E4hHM-(-g1i7L{8p9QsW`6+X z&ZWXnKf)kq)>wxFtSJ9$7nSD%0WfZHxRjjwIL-|6h^aNOg9hazK2C-fllmVSl@-*%-}I$JjXH-@)2mj3WLE6UW7`ol&43ZX5vgYf zx3pzznzK8mN(?&27{!j)h6j8<%rMfKUQL>!Du+A<-Un)sU3ptRKav$4Z2LL{kURSpg5x>D;oRoz?nKRp=lz895mq2Z%vnC8I5;Tlvef} zafYe=`AA=|6Cm>xAX5@ZI6HIKVpUr%Io3f$EsA<;Nj+s9bA}VQ?=g~AKE^Q3Z`E@N z&5d%|H0^(K<+$;kCGj$#LOROwTeinZuCi48Rag7@_fqjjca~-i@aP`%W6Il$hporA z?3;P^Xx_a6N%X9J0^YU9oI;LnPF>{JvCp+^FeGK0tpRKK6OSf_r!~addw=Vw`%=%p z#=WG>>}WL7%dR@-oW(MF3uK2Wpf# zLT~IF5~Dx)nI1PI8SLl}0{qlfXjMPZMQ&7WlVXz zQsCIPMl6fn&OeBh&zD4QHGS0WjjNG(L<*zG;?bv0N8=VMzdzwxO_1IfRts(^CS1L= z>8dd2yZqxhu+hAO$g#$|EIqe++=sA*-?n6{k=D1N0G&h(a;!<*D>+D3waPw*eke*) z>t|)~Sm}T{@2QUIAN_QLzVYFtkdU|HvT6QA00Wj=eO01kLGP)W5lQVyW#SjsO)$F0 zAAVJ@gJkk{`fq~r^0`&|OZ6z5Q=hw=tSO5V7QPyKM>5XjG$i4qA8KwjSV$*gpW^7| z8au5jSN;fi=<-Em;$_qm!kjpbbD&hXZ7K^Yibb#6(l8`*XHCx9HDLw)-I~C>X zcp=E&a`I}$AlDO*{ujjK+pE$y?$92nN%tgMq0j;}impFgvxOny75k&SyoVo;rhzc# zTfBpwFhuv4Y*7C$sx4q;Yfb+5P5~H; znP#`_F1yujm}DFTJM>0oUbcwIFMi!&nYq=s6}CEk#PqeD$FHLT;I6iHaZ%FKQXAX> zM!Nc?Qw0^TiT6!VD0?+{!R^huz zuQ*)f+Q)8#-ZS^KKe#}{I1edUNA)aC6PYyA{l+Co2UlYHl|U; z@j7Z5ji-FXtapU4EykvIoC^f;ax<+FqGpdO)@27m7l&*b*POH7feU6_V5t0&5tiI2 z_;>Wm0pbPyq=u5;Ny_9Jv5Dj1Kc@Zd551pNS2hu(QAD`aolZhkOYW32Ct2Y?6>sNf zBrqtgC9iFtC8}?_ivv3l@rQRBq>GD|z=tjuRlk`s;13)KnQ63nbTd+Jv9{8MLXIqE z3VZBVw&&hxL&xci_e}h;$nOgrgJT}wuXWnGcXUbk0)AdkrbI)r|9%nV6f@o$piMH=?SCU`}^I+qf%Pssoc(*%W572 z^CxM*QD8p*m@TYAIhEev74=FCZTK1}eoZUARCFc0Xf`o$;^muDdL=wQrInvFb*gQ5U~x+uuJW29w_UcJ3`U z?viQd*Vo<6zE{gRAH-bbjx&v`&$R&tR^1rBEVg-V_F0lpR2n?C{l^@FW-8@@XwsD* zUdUAqoH=|X`IdwSk&_yW@%SKmZTWzcz~7G){Al8o zq;87T!;XMV>uCdO83&)-?)p+}^TjJh(fSUhue$<+{5() zb}T8CJZ2DwK3`0)MT7JMb#RVsw~=+1!VfI*#^E%*da;>by{I(0)Cb8opRZ74UW{zM*N}u% zpN=Tx-B6hnDiN$&nt82ANEiattSXj;++4F8L3&+H=Fu4@4ut}8_NfFtms7SOnV3h9 zdFd(R3VaOoV;1{^-5szT?|_T|M2*Rq}jSQ|ImE(!lX9~2H2S> z8%c6vi{Kxs8+Tg?RWLT2LCRnChLB{qnQ|Y~`||7Z(rSG|s}mj_LdF}=>yml`0|sJdZxo&tB3GJM|tGuz##T&}wzj}OehO{Ff-+vCQKx?1(yLjfy@ zQ6i=E=TIk>i|>o~-f;1-p}Qa|j{?>DyZ*_z68NJoIA!3xQ0eN7y84w_YlbY)FNSM` zE33QY@{<*7?`Vv{*GK29G$|}+3sBNs^NhfS_v%Oc+E_#G|1YoB*h6cv?{4xdIt>v7ZtDzjxRBIbZ&% z-Qna`-dFoPd3-w361e(mU&tLVfi(61AZeyayA9wk6~J;=Da*iBZ`;>MvO3rU@K(-j z{(W&lXOt(;kf%BmR#b9K1 z=f3~KhCSWa9dcSx)Pf(+jxZKaq0Q5a^7(!E`C-| z$GboTTKH?%-lQGmW*F~Oi5Kdw3|vM`&2?XJ%$GD2@`qQ+!7CL{~6`b(3I40%_VT- zrR}Be8K$P4M;;uoR&OD<&?mpvU;I^>5JlT)pIl*>Aps#MPpEqF%0s9|ajnbHWTE*AO`&VO-3oG*i366Qcuii^QS=F$jHJmCb5kSqj$t zl5kh6(>4+p?f)A@HI#!$X}+dYgD9ffS5G4f%2fj)^rxjzg|vf!8wanbqpw2iA4umH zrscYS$WiIrkqo4#zqx?b(HFIB!$$yDji)RQ`U^#h$cJ0WB@8KSux}d!Kbbhw_)CP_ zl-|B{{;P*cy4crJaThE+4z~aZTBP38>XN>7((5|bWN-`gB5GO8Ht!gkgJGJP;4U6} z%9cPJ^ZYk5XPU1)xSY?zu%T3X0c0wXEuV;*#j{}%J4JfFDktq(>uc)~?hlezntEXo z`#rH5){&hNDGl+_*2U2rUu+w(bzP<8-!-BCzKtLUg5=W8?en7KIz1;$7&~JIZGQ61 z#Cq5q@Pju?Mv&IhHTia8BLtz0V+@m#<7#Z}^r_VbR7bSCgw{RPvmlM)F^s_9QdcXu zU$#Z|IFc$Zqg*ZKCYgDT-91S5zq>>-H&$NY2*M9XDdD2(6niF!4Qzpw19r%FZ4Wu*9jos@S$(lhUD zR1M?y+d_ckx{W?{%#*wDkR7*6i~@=-3QbNHIv`^KdDgsj#PC)-e(cdCe3#K|Q$-ib zXN30T6+ryEjF#BEDv+AUoqBw(^Z5C*L>l*axe%RQozCm6goRUhsh;k>(X8oo%*7 z3-d@5azBU}bszNpfv-2;xO9iy1=#sBq#OEW!?2?lQVTfv-UPy5I(Hv9_LA`YpoH+i zpzkqs$|Av$nX+3zaMR`$)Dm;Y9s{MWy9G^$@O1|5bQE#}oa#?xWV9@j{*bpM;d?+y z@$O6*?bwlvDa-;C@+PQ66;d;}nPLAXjyjW3CW6%zT~K0RnfC_YtG3wYay#(}+n~lE zC0-r)NkQ|PZRMG(Q^oCiAaQVFDO8z9)p$<#z2?(20q3T_2)yofz+xzL+n6PSlm`_^ z=P>WP>idtTwq^#(NJ}W=(Q|*%Z+1M`r^s{RqJZl*5XRCxNT=~T?s$oE2siHm)B~zT z!gqumZiGCk)3oDXZXblF!1-$>eBQ|* zbWpCb4*--t_PN}pj(p8hX&X`3*i>*cVhm(PN5#wu+1EgJUKp+l#OwU8ht%1t7f6Ox zAs6(i+27b<3loA>Z8~u{3hjeqK~!2VZdi>JsT5>5%osYtEnMN@c?{5%mhQg%aOaYb zG0N}Pb=lI&-^uJ(vY95BwjbaeUB+^Kjm?vsUyg+6G|_E4msom>R-|dqcN-_;Y - - - - - - - - diff --git a/lib/editor/atto/plugins/h5p/pix/icon.png b/lib/editor/atto/plugins/h5p/pix/icon.png deleted file mode 100644 index 51a640dc9f264d0ae7dcc0dccb6e53833055527c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4541 zcmaJ_c|276-ydb0LYb0?45DPrVmC~Z-57+4Nx8PEt0QGON!1;#M=bXMJe3YJKTd#3XjBx5dl^Kbblh)k%}i1-HG^s=+IY03jkpA zfgn%saBqw=l0c_I@f$YKC@MpQ1^_H9qZoKX2r(S&Pb3G?P#Uw5Gy=oJ8Auo`GBOexX#k~%kzoikGcy=mAEvLbC$i9EM$^La zQF=6{<}VL6L?$6Dh!Gw{r-3&-;{E9n;V2DJrvE8{%J|1Ejrn(*L=A&Q;TbRl6uwc? zFGCFG|2L&l|FLF6Bkx zbPJ@1)0u&E2H4tqqibg10~kCZh_<2B`H8|{kd8EFIG#ozI@+K#M1G(_K>;&A&P86 z3=3ir1MI@+RPfKjkwO2Si}kZOR!jlRz<7q3!5HDo_TQp!LCV%gv*Yk{6G)q zNz-=DyL6|VKEvQ#B8D{JNeY_W9r%GGJDD4l??^f$cJRRM0~fYT*lU0fiAkLAKRy%Z zn>9Q7b>{TfEMEViy0`q_)aIh@@Rr~FRc+Znqpndro^+m@F@BFTzMdU?^>DX$&CG8X zzMd#LUL0c(JC(`m^P3so7 zsFeFV9(UEVvT(TpBE}Oh=q%;#$6DSfS$U)9{fAD+wFYxj-?q?u803zBB6Fc0ikrFq)&~NzhgYL@D~reODm?Rlk5m3xSlL zd}|6vtDJZ--r_u9`|jM^8rX`Rc=r3IV=sMxo9js`#YiPyyp!oRxvoQ&X^dQDo;V+r zy=AzllRmr6A@`_?ZS!d71)s76VR_Ot_`03Si{c@V28rNB2%7(Hx7J~7h1=;&yeXqe zKAY*1X3V_FA%6F(1!Xf=xV4G69-jEQ$4gK|$Bp^KV0k=X8njv<*91|zu=()RDG6Q^ zL@b+Gdl|>xF{vvSOn4StaJoCmJ3ZkkcQF3`;z09B^v567tjo>DueY_Arv-C@=|Tq~ z?MllhY2i+OnFar7anjs#*0HslOBKj<=5L|Up2Dz&I-fp%iuQqbgx|_oD)-OfeQ*EH zt#cT-WMV!Q2{%|HYrk?H&Fa4~IHY&h+`U-2rM5HcYci&BkE`-E2VxNGPG{<3&BMxt zM{K{b{oFMTHRI##+_y!2rWBJ*L&FkYV(z0HtbqmD++Q&YYQc7(s`jy3qFR$gp5 z&t+m^1a`#PIg42cEz*x2bo>2^!_*L^wr3Zqvtv@Krq?GT!Jzl*OGs+yw7C~y!{E;4 z*Z>`x*RXrU`FI&u4soic{kh!fsZGncd`HpLKO1(ph`(E7fAkkJgvFk9+=0c5t-qgI z5Dgrpd};J7&1=8&HPh5vyOQ;;ot#)4oHCGcW$vyu|6InPsEx@ajLn7~UKSeK2HxVVxC%W35ujjjO$r$bh>|)vX|#nd^+sA1q+30iiXk)U~<4 z?`UaF8T;w0T_wxct`)!9MNimwoW$y_4|_s-e%ZKRogL+`hrj#=p6W4rtZOd4xo+qg zwO5gk%a=$pKUBhOc_=TbIC2^1&vt`&VCytwjuN(-Cm}iv@meE_Qw1}cGTmVj?_n_x zcYyx)SrlmSwuV1a?(U<+ykWc9G>3p5E8)ZVm{Q9_~n(e&##`VT+hI2T*5p z+|xRdCl>1G<#1wf*#v=(VQ-frJGET`HZ!kK&UCAiZf);t%L2uuGP zCrFzmAaE*`icZd3DHGqxdQwRRW$ni|G7@Xx=5aL+Pd5vZUXP%I5sFW+tNF(!eBXSX z#vM}}&PG+Ye65H+juxx%@R$91>GuyK23u7JGcKrm*DjS4JWAg55_{Itec9AkE|^0I9$A=G9PKUIdi=G4HR~msX&{8FqxGx9SFXl2O&MzrgE5^QE%WBUN-C{j3Fgm!pP#o` z^JJGFvy{@if9JO>;|XM0mZUp;wQ$|qh$_v}E2X-wM$}jWc=0LT!hFS*Q_W9)0csvDCJJNA3wnZemshH`U- zf~+7*up_c4CA(dCQP}v_X~3m|TW$GB@k>0i1luIvv#v5RtYA0fHEvcx7R;lBN}c{| zrX-wVYC)&_>)-&Bds$lP5*??g4^R0F3gV<}@tSwHVtYOJ?D-z|3Mo!}kQ)D7 z*OmWppsMN9Bg$9oT4A@HqX5)CRA7gU@vSxt0XFwRD}w&g7VZS%3T|&90f~(tS6LwA z`PlkCg+52wshc}m^WA4U69&&_Fn)8PNr<^=^TX}XrmFA6It~R4UuuuRK0f_y(AUF! z_Uz4g6fYz(YC9j)-o~&e>1gSrSN)=_jJz74=gdGfF>fWbqFOdZhPnKrNToH#dijUm z{F#c_4zCi=1|5WXO7P(9J;9>OBiML1M5<-pvG?4V#7=9=OQ^?orFDj9U$$KhB?Mv%T6wxnxtfoA(tgbPF>Wq336#YvPL}Uz8@thk!(kQ}OO=5!a2q61`NeO-ALu+YbmpuxtYZ{ClE}35ifrgBWQch$j@yPsX(OZ+FMH+k- z1qokSzvqtX`=biq4^l~USmSi%F2{+UlzAzut#@1MU9R1I5L1;oOYh%zCvQmqJ}X+6 zbVYPKId#>xlYqBgXe=9BcmSMg77tB0_sqkm- zEyjj?_@FSnABpovsyfK)K|nnuZAt}LSW~Z<*7TP=h7US{zjeA6z54`yuxmdk;T!%Q zF($OKNHxLz=_rGo^7&GXl>l_GWNbts{-wlkZl|;0U5)q2ILb)s!x;PI*Ltwd=WAV} zT@Uc{+#aF5v~~Fp_lED0^^p61kn^968c+BAWiQ7SR)(AKqPinMg| zT%7dKHWZqF;~BaiW;%Q;_?|i0uIG&CJL1MO0;fBy%y8|8jzCFSqOMR)lWO@>S6$eFtqGDFZQ)OUxhzWM z3J&yDavFh$ks?ixKGm52NrtAH^NsTh7pwh(UxJ{n%)f)1crSR`cUy4%_vh3?o9`~P zK!VCSM4Q`>m2C~a0|=f>l?pXcUi)S+?31S%@z-Xk=@YTC;v~nMX2{)-jzF&p_6JGF zJ+xG>(Wz%6KkHG<6>>v((XTxf eztsUY1C*l24+i?JmTde`akO=@d3?n0!v6pd#WY_4 diff --git a/lib/editor/atto/plugins/h5p/pix/icon.svg b/lib/editor/atto/plugins/h5p/pix/icon.svg deleted file mode 100644 index 2aaf327ffe2..00000000000 --- a/lib/editor/atto/plugins/h5p/pix/icon.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - diff --git a/lib/editor/atto/plugins/h5p/styles.css b/lib/editor/atto/plugins/h5p/styles.css deleted file mode 100644 index 4fecf84e3ef..00000000000 --- a/lib/editor/atto/plugins/h5p/styles.css +++ /dev/null @@ -1,20 +0,0 @@ -.attoh5poverlay { - display: none; -} -.attoh5pinstructions { - max-width: 500px; -} -.editor_atto_content_wrap .h5p-placeholder + br { - display: none; -} -.editor_atto_content_wrap .h5p-placeholder { - color: #6c757d; - width: 100%; - word-break: break-all; - height: 260px; - cursor: pointer; - background: url([[pix:atto_h5p|icon-white]]) center center / 100px auto no-repeat #6c757d; -} -.atto_h5p_button .icon { - width: 24px; -} \ No newline at end of file diff --git a/lib/editor/atto/plugins/h5p/tests/behat/h5p.feature b/lib/editor/atto/plugins/h5p/tests/behat/h5p.feature deleted file mode 100644 index fc884b4f3d9..00000000000 --- a/lib/editor/atto/plugins/h5p/tests/behat/h5p.feature +++ /dev/null @@ -1,220 +0,0 @@ -@editor @editor_atto @atto @atto_h5p @core_h5p @_switch_iframe -Feature: Use the Atto editor to upload an h5p package - To write rich text - I need to add h5ps. - - Background: - Given the following "courses" exist: - | shortname | fullname | - | C1 | Course 1 | - And the following "users" exist: - | username | firstname | lastname | email | - | teacher1 | Teacher | 1 | teacher1@example.com | - And the following "course enrolments" exist: - | user | course | role | - | teacher1 | C1 | editingteacher | - And the following "activities" exist: - | activity | name | intro | introformat | course | content | contentformat | idnumber | - | page | PageName1 | PageDesc1 | 1 | C1 | H5Ptest | 1 | 1 | - And the "displayh5p" filter is "on" - And the following config values are set as admin: - | allowedsources | https://moodle.h5p.com/content/[id] | filter_displayh5p | - - @javascript @external - Scenario: Insert an embedded h5p - Given I change window size to "large" - And I am on the PageName1 "page activity editing" page logged in as admin - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1290772960722742119" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I wait until the page is ready - When I click on "Save and display" "button" - Then ".h5p-placeholder" "css_element" should exist - And I wait until the page is ready - And I switch to "h5pcontent" iframe - And I should see "Lorum ipsum" - - @javascript - Scenario: Insert an h5p file - Given the following "user private file" exists: - | user | admin | - | filepath | h5p/tests/fixtures/guess-the-answer.h5p | - And I am on the "PageName1" "page activity editing" page logged in as "admin" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "guess-the-answer.h5p" "link" - And I click on "Select this file" "button" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I wait until the page is ready - When I click on "Save and display" "button" - Then ".h5p-placeholder" "css_element" should exist - - @javascript - Scenario: Test an invalid url - Given I change window size to "large" - And I am on the PageName1 "page activity editing" page logged in as admin - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" -# This is not a real external URL, so this scenario shouldn't be labeled as external. - And I set the field with xpath "//input[@data-region='h5pfile']" to "ftp://moodle.h5p.com/content/1290772960722742119" - When I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I wait until the page is ready - Then I should see "Invalid URL" in the "Insert H5P" "dialogue" - - @javascript - Scenario: No h5p capabilities - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | atto/h5p:addembed | Prohibit | editingteacher | Course | C1 | - | moodle/h5p:deploy | Prohibit | editingteacher | Course | C1 | - When I am on the PageName1 "page activity editing" page logged in as teacher1 - Then "Insert H5P" "button" should not exist - - @javascript - Scenario: No embed h5p capabilities - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | atto/h5p:addembed | Prohibit | editingteacher | Course | C1 | - And I am on the PageName1 "page activity editing" page logged in as teacher1 - And I click on "Insert H5P" "button" - Then I should not see "H5P URL" in the "Insert H5P" "dialogue" - And I should see "H5P file upload" in the "Insert H5P" "dialogue" - And I should see "H5P options" in the "Insert H5P" "dialogue" - - @javascript - Scenario: No upload h5p capabilities - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/h5p:deploy | Prohibit | editingteacher | Course | C1 | - When I am on the PageName1 "page activity editing" page logged in as teacher1 - And I click on "Insert H5P" "button" - Then I should not see "H5P file upload" in the "Insert H5P" "dialogue" - And I should see "H5P URL" in the "Insert H5P" "dialogue" - And I should not see "H5P options" in the "Insert H5P" "dialogue" - - @javascript @external - Scenario: Edit H5P content - Given the following "user private file" exists: - | user | admin | - | filepath | h5p/tests/fixtures/drag.h5p | - And I am on the "PageName1" "page activity editing" page logged in as "admin" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" -# H5P file content - And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "drag" "link" - And I click on "Select this file" "button" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I wait until the page is ready - When I click on "Save and display" "button" - And I switch to "h5pcontent" iframe - And I switch to "h5p-iframe" class iframe - Then I should not see "reveal" - And I should see "Cloudberries" - And I switch to the main frame - And I navigate to "Settings" in current page administration - And I click on ".h5p-placeholder" "css_element" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" -# External URL - And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1290772960722742119" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I wait until the page is ready - And I click on "Save and display" "button" - And I wait until the page is ready - And I switch to "h5pcontent" iframe - And I should see "Lorum ipsum" - And I should not see "Cloudberries" - - @javascript - Scenario: Enable/disable H5P options atto - Given the following "user private file" exists: - | user | admin | - | filepath | h5p/tests/fixtures/guess-the-answer.h5p | - And I am on the "PageName1" "page activity editing" page logged in as "admin" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "guess-the-answer.h5p" "link" - And I click on "Select this file" "button" -# No display option button displayed - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - When I click on "Save and display" "button" - And I wait until the page is ready - And I switch to "h5pcontent" iframe - And I switch to "h5p-iframe" class iframe - Then ".h5p-actions" "css_element" should not exist - And I switch to the main frame - And I navigate to "Settings" in current page administration - And I click on ".h5p-placeholder" "css_element" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I click on "H5P options" "link" -# Only Allow Download button displayed - And I click on "Allow download" "checkbox" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I click on "Save and display" "button" - And I switch to "h5pcontent" iframe - And I switch to "h5p-iframe" class iframe - And "Reuse" "text" should exist in the ".h5p-actions" "css_element" - And I should not see "Embed" - And I should not see "Rights of use" - And I switch to the main frame - And I navigate to "Settings" in current page administration - And I click on ".h5p-placeholder" "css_element" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" -# Embed and copyright buttons displayed. Download not displayed - And I click on "Allow download" "checkbox" - And I click on "Embed button" "checkbox" - And I click on "Copyright button" "checkbox" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I click on "Save and display" "button" - And I switch to "h5pcontent" iframe - And I switch to "h5p-iframe" class iframe - And "Reuse" "text" should not exist in the ".h5p-actions" "css_element" - And I should see "Embed" - And I should see "Rights of use" - - @javascript @external - Scenario: H5P options are ignored for H5P URLs - Given I change window size to "large" - And I am on the PageName1 "page activity editing" page logged in as admin - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1291366510035871129" - And I click on "H5P options" "link" - And I click on "Embed button" "checkbox" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - When I click on "Save and display" "button" - Then ".h5p-placeholder" "css_element" should exist - And I switch to "h5pcontent" iframe - And I should see "Far far away" - And I should not see "Embed" - And I switch to the main frame - And I navigate to "Settings" in current page administration - And I click on ".h5p-placeholder" "css_element" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I click on "H5P options" "link" - And "input[aria-label=\"Embed button\"]:not([checked=checked])" "css_element" should exist - - @javascript - Scenario: Private H5P files are shown to students - Given the following "users" exist: - | username | firstname | lastname | email | - | student1 | Student | 1 | student1@example.com | - And the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - And the following "user private file" exists: - | user | admin | - | filepath | h5p/tests/fixtures/guess-the-answer.h5p | - And I am on the "PageName1" "page activity editing" page logged in as "admin" - And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element" - And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "guess-the-answer.h5p" "link" - And I click on "Select this file" "button" - And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue" - And I wait until the page is ready - And I click on "Save and display" "button" - And I log out - When I am on the PageName1 "page activity" page logged in as student1 - Then I switch to "h5pcontent" iframe - And I switch to "h5p-iframe" class iframe - And I should see "reveal" diff --git a/lib/editor/atto/plugins/h5p/version.php b/lib/editor/atto/plugins/h5p/version.php deleted file mode 100644 index ed23414df55..00000000000 --- a/lib/editor/atto/plugins/h5p/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_h5p'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-debug.js b/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-debug.js deleted file mode 100644 index 0355afa3f65..00000000000 --- a/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-debug.js +++ /dev/null @@ -1,605 +0,0 @@ -YUI.add('moodle-atto_h5p-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_h5p-button - */ - -/** - * Atto h5p content tool. - * - * @namespace M.atto_h5p - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var CSS = { - CONTENTWARNING: 'att_h5p_contentwarning', - H5PBROWSER: 'openh5pbrowser', - INPUTALT: 'atto_h5p_altentry', - INPUTH5PFILE: 'atto_h5p_file', - INPUTSUBMIT: 'atto_h5p_urlentrysubmit', - OPTION_DOWNLOAD_BUTTON: 'atto_h5p_option_download_button', - OPTION_COPYRIGHT_BUTTON: 'atto_h5p_option_copyright_button', - OPTION_EMBED_BUTTON: 'atto_h5p_option_embed_button', - URLWARNING: 'atto_h5p_warning' - }, - SELECTORS = { - CONTENTWARNING: '.' + CSS.CONTENTWARNING, - H5PBROWSER: '.' + CSS.H5PBROWSER, - INPUTH5PFILE: '.' + CSS.INPUTH5PFILE, - INPUTSUBMIT: '.' + CSS.INPUTSUBMIT, - OPTION_DOWNLOAD_BUTTON: '.' + CSS.OPTION_DOWNLOAD_BUTTON, - OPTION_COPYRIGHT_BUTTON: '.' + CSS.OPTION_COPYRIGHT_BUTTON, - OPTION_EMBED_BUTTON: '.' + CSS.OPTION_EMBED_BUTTON, - URLWARNING: '.' + CSS.URLWARNING - }, - - COMPONENTNAME = 'atto_h5p', - - TEMPLATE = '' + - '
                          ' + - '' + - '' + - '{{#if canUploadAndEmbed}}' + - '
                          {{{get_string "instructions" component}}}
                          ' + - '{{/if}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - - H5PTEMPLATE = '' + - '{{#if addParagraphs}}


                          {{/if}}' + - '
                          ' + - '{{{url}}}' + - '
                          ' + - '{{#if addParagraphs}}


                          {{/if}}'; - -Y.namespace('M.atto_h5p').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * A reference to the currently open form. - * - * @param _form - * @type Node - * @private - */ - _form: null, - - /** - * A reference to the currently selected H5P div. - * - * @param _form - * @type Node - * @private - */ - _H5PDiv: null, - - /** - * Allowed methods of adding H5P. - * - * @param _allowedmethods - * @type String - * @private - */ - _allowedmethods: 'none', - - initializer: function() { - this._allowedmethods = this.get('allowedmethods'); - if (this._allowedmethods === 'none') { - // Plugin not available here. - return; - } - this.addButton({ - icon: 'icon', - iconComponent: 'atto_h5p', - callback: this._displayDialogue, - tags: '.h5p-placeholder', - tagMatchRequiresAll: false - }); - - this.editor.all('.h5p-placeholder').setAttribute('contenteditable', 'false'); - this.editor.delegate('dblclick', this._handleDblClick, '.h5p-placeholder', this); - this.editor.delegate('click', this._handleClick, '.h5p-placeholder', this); - }, - - /** - * Handle a double click on a H5P Placeholder. - * - * @method _handleDblClick - * @private - */ - _handleDblClick: function() { - this._displayDialogue(); - }, - - /** - * Handle a click on a H5P Placeholder. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var selection = this.get('host').getSelectionFromNode(e.target); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Display the h5p editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection === false) { - return; - } - - this._getH5PDiv(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENTNAME), - width: 'auto', - focusAfterHide: true - }); - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_h5p_form'}); - }, - - /** - * Get the H5P iframe - * - * @method _resolveH5P - * @return {Node} The H5P iframe selected. - * @private - */ - _getH5PDiv: function() { - var selectednodes = this.get('host').getSelectedNodes(); - var H5PDiv = null; - selectednodes.each(function(selNode) { - if (selNode.hasClass('h5p-placeholder')) { - H5PDiv = selNode; - } - }); - this._H5PDiv = H5PDiv; - }, - - /** - * Get the H5P button permissions. - * - * @return {Object} H5P button permissions. - * @private - */ - _getPermissions: function() { - var permissions = { - 'canEmbed': false, - 'canUpload': false, - 'canUploadAndEmbed': false - }; - - if (this.get('host').canShowFilepicker('h5p')) { - if (this._allowedmethods === 'both') { - permissions.canUploadAndEmbed = true; - permissions.canUpload = true; - } else if (this._allowedmethods === 'upload') { - permissions.canUpload = true; - } - } - - if (this._allowedmethods === 'both' || this._allowedmethods === 'embed') { - permissions.canEmbed = true; - } - return permissions; - }, - - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} The content to place in the dialogue. - * @private - */ - _getDialogueContent: function() { - - var permissions = this._getPermissions(); - - var fileURL, - optionDownloadButton, - optionEmbedButton, - optionCopyrightButton, - showOptions = false; - - if (this._H5PDiv) { - var H5PURL = this._H5PDiv.get('innerHTML'); - var fileBaseUrl = M.cfg.wwwroot + '/draftfile.php'; - if (fileBaseUrl == H5PURL.substring(0, fileBaseUrl.length)) { - fileURL = H5PURL.split("?")[0]; - - var parameters = H5PURL.split("?")[1]; - if (parameters) { - if (parameters.match(/export=1/)) { - optionDownloadButton = 'checked'; - showOptions = true; - } - - if (parameters.match(/embed=1/)) { - optionEmbedButton = 'checked'; - showOptions = true; - } - - if (parameters.match(/copyright=1/)) { - optionCopyrightButton = 'checked'; - showOptions = true; - } - } - } else { - fileURL = H5PURL; - } - } - - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - CSS: CSS, - component: COMPONENTNAME, - canUpload: permissions.canUpload, - canEmbed: permissions.canEmbed, - canUploadAndEmbed: permissions.canUploadAndEmbed, - showOptions: showOptions, - fileURL: fileURL, - optionDownloadButton: optionDownloadButton, - optionEmbedButton: optionEmbedButton, - optionCopyrightButton: optionCopyrightButton - })); - - this._form = content; - - // Listen to and act on Dialogue content events. - this._setEventListeners(); - - return content; - }, - - /** - * Update the dialogue after an h5p was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the h5p. - * @private - */ - _filepickerCallback: function(params) { - if (params.url !== '') { - var input = this._form.one(SELECTORS.INPUTH5PFILE); - input.set('value', params.url); - this._removeWarnings(); - } - }, - - /** - * Set event Listeners for Dialogue content actions. - * - * @method _setEventListeners - * @private - */ - _setEventListeners: function() { - var form = this._form; - var permissions = this._getPermissions(); - - form.one(SELECTORS.INPUTSUBMIT).on('click', this._setH5P, this); - - if (permissions.canUpload) { - form.one(SELECTORS.H5PBROWSER).on('click', function() { - this.get('host').showFilepicker('h5p', this._filepickerCallback, this); - }, this); - } - - if (permissions.canUploadAndEmbed) { - form.one(SELECTORS.INPUTH5PFILE).on('change', function() { - this._removeWarnings(); - }, this); - } - }, - - /** - * Remove warnings shown in the dialogue. - * - * @method _removeWarnings - * @private - */ - _removeWarnings: function() { - var form = this._form; - form.one(SELECTORS.URLWARNING).setStyle('display', 'none'); - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'none'); - }, - - /** - * Update the h5p in the contenteditable. - * - * @method _setH5P - * @param {EventFacade} e - * @private - */ - _setH5P: function(e) { - var form = this._form, - h5phtml, - host = this.get('host'), - h5pfile = form.one(SELECTORS.INPUTH5PFILE).get('value'), - permissions = this._getPermissions(); - - e.preventDefault(); - - // Check if there are any issues. - if (this._updateWarning()) { - return; - } - - // Focus on the editor in preparation for inserting the H5P. - host.focus(); - - // Add an empty paragraph after new H5P container that can catch the cursor. - var addParagraphs = true; - - // If a H5P placeholder was selected we can destroy it now. - if (this._H5PDiv) { - this._H5PDiv.remove(); - addParagraphs = false; - } - - if (h5pfile !== '') { - host.setSelection(this._currentSelection); - - if (h5pfile.startsWith(M.cfg.wwwroot)) { - // It's a local file. - var params = ''; - if (permissions.canUpload) { - var options = {}; - if (form.one(SELECTORS.OPTION_DOWNLOAD_BUTTON).get('checked')) { - options['export'] = '1'; - } - if (form.one(SELECTORS.OPTION_EMBED_BUTTON).get('checked')) { - options.embed = '1'; - } - if (form.one(SELECTORS.OPTION_COPYRIGHT_BUTTON).get('checked')) { - options.copyright = '1'; - } - - for (var opt in options) { - if (params === "" && (h5pfile.indexOf("?") === -1)) { - params += "?"; - } else { - params += "&"; - } - params += opt + "=" + options[opt]; - } - } - - var h5ptemplate = Y.Handlebars.compile(H5PTEMPLATE); - - h5phtml = h5ptemplate({ - url: h5pfile + params, - addParagraphs: addParagraphs - }); - } else { - // It's a URL. - var urltemplate = Y.Handlebars.compile(H5PTEMPLATE); - h5phtml = urltemplate({ - url: h5pfile - }); - } - - host.insertContentAtFocusPoint(h5phtml); - - this.markUpdated(); - } - - this.getDialogue({ - focusAfterHide: null - }).hide(); - }, - - /** - * Check if this could be a h5p embed. - * - * @method _validEmbed - * @param {String} str - * @return {boolean} whether this is a iframe tag. - * @private - */ - _validEmbed: function(str) { - var pattern = new RegExp('^()'); // Port and path. - return !!pattern.test(str); - }, - - /** - * Check if this could be a h5p URL. - * - * @method _validURL - * @param {String} str - * @return {boolean} whether this is a valid URL. - * @private - */ - _validURL: function(str) { - var pattern = new RegExp('^(https?:\\/\\/)?' + // Protocol. - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // Domain name. - '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address. - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'); // Port and path. - return !!pattern.test(str); - }, - - /** - * Update the url warning. - * - * @method _updateWarning - * @return {boolean} whether a warning should be displayed. - * @private - */ - _updateWarning: function() { - var form = this._form, - state = true, - h5pfile, - permissions = this._getPermissions(); - - if (permissions.canUpload || permissions.canEmbed) { - h5pfile = form.one(SELECTORS.INPUTH5PFILE).get('value'); - if (h5pfile !== '') { - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'none'); - if (h5pfile.startsWith(M.cfg.wwwroot) || this._validURL(h5pfile)) { - // Only external URLs have to be validated. - form.one(SELECTORS.URLWARNING).setStyle('display', 'none'); - state = false; - } else { - form.one(SELECTORS.URLWARNING).setStyle('display', 'block'); - state = true; - } - } else { - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'block'); - state = true; - } - } - - return state; - } -}, { - ATTRS: { - /** - * The allowedmethods of adding h5p content. - * - * @attribute allowedmethods - * @type String - */ - allowedmethods: { - value: null - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-min.js b/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-min.js deleted file mode 100644 index eedfa3aef42..00000000000 --- a/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button-min.js +++ /dev/null @@ -1,3 +0,0 @@ -YUI.add("moodle-atto_h5p-button",function(c,t){var d={CONTENTWARNING:"att_h5p_contentwarning",H5PBROWSER:"openh5pbrowser",INPUTALT:"atto_h5p_altentry",INPUTH5PFILE:"atto_h5p_file",INPUTSUBMIT:"atto_h5p_urlentrysubmit",OPTION_DOWNLOAD_BUTTON:"atto_h5p_option_download_button",OPTION_COPYRIGHT_BUTTON:"atto_h5p_option_copyright_button",OPTION_EMBED_BUTTON:"atto_h5p_option_embed_button",URLWARNING:"atto_h5p_warning"},r={CONTENTWARNING:"."+d.CONTENTWARNING,H5PBROWSER:"."+d.H5PBROWSER,INPUTH5PFILE:"."+d.INPUTH5PFILE,INPUTSUBMIT:"."+d.INPUTSUBMIT,OPTION_DOWNLOAD_BUTTON:"."+d.OPTION_DOWNLOAD_BUTTON,OPTION_COPYRIGHT_BUTTON:"."+d.OPTION_COPYRIGHT_BUTTON,OPTION_EMBED_BUTTON:"."+d.OPTION_EMBED_BUTTON,URLWARNING:"."+d.URLWARNING},p="atto_h5p",h='{{#if addParagraphs}}


                          {{/if}}
                          {{{url}}}
                          {{#if addParagraphs}}


                          {{/if}}';c.namespace("M.atto_h5p").Button=c.Base.create("button",c.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_form:null,_H5PDiv:null,_allowedmethods:"none",initializer:function(){this._allowedmethods=this.get("allowedmethods"),"none"!==this._allowedmethods&&(this.addButton({icon:"icon",iconComponent:"atto_h5p",callback:this._displayDialogue,tags:".h5p-placeholder",tagMatchRequiresAll:!1}),this.editor.all(".h5p-placeholder").setAttribute("contenteditable","false"),this.editor.delegate("dblclick",this._handleDblClick,".h5p-placeholder",this),this.editor.delegate("click",this._handleClick,".h5p-placeholder",this))},_handleDblClick:function(){this._displayDialogue()},_handleClick:function(t){t=this.get("host").getSelectionFromNode(t.target);this.get("host").getSelection()!==t&&this.get("host").setSelection(t)},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&(this._getH5PDiv(),this.getDialogue({headerContent:M.util.get_string("pluginname",p),width:"auto",focusAfterHide:!0}).set("bodyContent",this._getDialogueContent()).show(),M.form.shortforms({formid:this.get("host").get("elementid")+"_atto_h5p_form"}))},_getH5PDiv:function(){var t=this.get("host").getSelectedNodes(),e=null;t.each(function(t){t.hasClass("h5p-placeholder")&&(e=t)}),this._H5PDiv=e},_getPermissions:function(){var t={canEmbed:!1,canUpload:!1,canUploadAndEmbed:!1};return this.get("host").canShowFilepicker("h5p")&&("both"===this._allowedmethods?(t.canUploadAndEmbed=!0,t.canUpload=!0):"upload"===this._allowedmethods&&(t.canUpload=!0)),"both"!==this._allowedmethods&&"embed"!==this._allowedmethods||(t.canEmbed=!0),t},_getDialogueContent:function(){var t,e,o,n,i,a,l=this._getPermissions(),s=!1;return this._H5PDiv&&(a=this._H5PDiv.get("innerHTML"),(i=M.cfg.wwwroot+"/draftfile.php")==a.substring(0,i.length)?(t=a.split("?")[0],(i=a.split("?")[1])&&(i.match(/export=1/)&&(e="checked",s=!0),i.match(/embed=1/)&&(o="checked",s=!0),i.match(/copyright=1/)&&(n="checked",s=!0))):t=a),i=c.Handlebars.compile( -'
                          {{#if canUploadAndEmbed}}
                          {{{get_string "instructions" component}}}
                          {{/if}}
                          {{#if canUpload}}{{/if}}
                          {{#if canUpload}}
                          {{/if}}
                          '),a=c.Node.create(i({elementid:this.get("host").get("elementid"),CSS:d,component:p,canUpload:l.canUpload,canEmbed:l.canEmbed,canUploadAndEmbed:l.canUploadAndEmbed,showOptions:s,fileURL:t,optionDownloadButton:e,optionEmbedButton:o,optionCopyrightButton:n})),this._form=a,this._setEventListeners(),a},_filepickerCallback:function(t){""!==t.url&&(this._form.one(r.INPUTH5PFILE).set("value",t.url),this._removeWarnings())},_setEventListeners:function(){var t=this._form,e=this._getPermissions();t.one(r.INPUTSUBMIT).on("click",this._setH5P,this),e.canUpload&&t.one(r.H5PBROWSER).on("click",function(){this.get("host").showFilepicker("h5p",this._filepickerCallback,this)},this),e.canUploadAndEmbed&&t.one(r.INPUTH5PFILE).on("change",function(){this._removeWarnings()},this)},_removeWarnings:function(){var t=this._form;t.one(r.URLWARNING).setStyle("display","none"),t.one(r.CONTENTWARNING).setStyle("display","none")},_setH5P:function(t){var e,o,n,i,a=this._form,l=this.get("host"),s=a.one(r.INPUTH5PFILE).get("value"),d=this._getPermissions();if(t.preventDefault(),!this._updateWarning()){if(l.focus(),t=!0,this._H5PDiv&&(this._H5PDiv.remove(),t=!1),""!==s){if(l.setSelection(this._currentSelection),s.startsWith(M.cfg.wwwroot)){if(o="",d.canUpload)for(i in n={},a.one(r.OPTION_DOWNLOAD_BUTTON).get("checked")&&(n["export"]="1"),a.one(r.OPTION_EMBED_BUTTON).get("checked")&&(n.embed="1"),a.one(r.OPTION_COPYRIGHT_BUTTON).get("checked")&&(n.copyright="1"),n)""===o&&-1===s.indexOf("?")?o+="?":o+="&",o+=i+"="+n[i];e=c.Handlebars.compile(h)({url:s+o,addParagraphs:t})}else e=c.Handlebars.compile(h)({url:s});l.insertContentAtFocusPoint(e),this.markUpdated()}this.getDialogue({focusAfterHide:null}).hide()}},_validEmbed:function(t){return!!new RegExp("^()").test(t)},_validURL:function(t){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*").test(t)},_updateWarning:function(){var t=this._form,e=!0,o=this._getPermissions();return e=o.canUpload||o.canEmbed?""!==(o=t.one(r.INPUTH5PFILE).get("value"))?(t.one(r.CONTENTWARNING).setStyle("display","none"),o.startsWith(M.cfg.wwwroot)||this._validURL(o)?(t.one(r.URLWARNING).setStyle("display","none"),!1):(t.one(r.URLWARNING).setStyle("display","block"),!0)):(t.one(r.CONTENTWARNING).setStyle("display","block"),!0):e}},{ATTRS:{allowedmethods:{ -value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button.js b/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button.js deleted file mode 100644 index 0355afa3f65..00000000000 --- a/lib/editor/atto/plugins/h5p/yui/build/moodle-atto_h5p-button/moodle-atto_h5p-button.js +++ /dev/null @@ -1,605 +0,0 @@ -YUI.add('moodle-atto_h5p-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_h5p-button - */ - -/** - * Atto h5p content tool. - * - * @namespace M.atto_h5p - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var CSS = { - CONTENTWARNING: 'att_h5p_contentwarning', - H5PBROWSER: 'openh5pbrowser', - INPUTALT: 'atto_h5p_altentry', - INPUTH5PFILE: 'atto_h5p_file', - INPUTSUBMIT: 'atto_h5p_urlentrysubmit', - OPTION_DOWNLOAD_BUTTON: 'atto_h5p_option_download_button', - OPTION_COPYRIGHT_BUTTON: 'atto_h5p_option_copyright_button', - OPTION_EMBED_BUTTON: 'atto_h5p_option_embed_button', - URLWARNING: 'atto_h5p_warning' - }, - SELECTORS = { - CONTENTWARNING: '.' + CSS.CONTENTWARNING, - H5PBROWSER: '.' + CSS.H5PBROWSER, - INPUTH5PFILE: '.' + CSS.INPUTH5PFILE, - INPUTSUBMIT: '.' + CSS.INPUTSUBMIT, - OPTION_DOWNLOAD_BUTTON: '.' + CSS.OPTION_DOWNLOAD_BUTTON, - OPTION_COPYRIGHT_BUTTON: '.' + CSS.OPTION_COPYRIGHT_BUTTON, - OPTION_EMBED_BUTTON: '.' + CSS.OPTION_EMBED_BUTTON, - URLWARNING: '.' + CSS.URLWARNING - }, - - COMPONENTNAME = 'atto_h5p', - - TEMPLATE = '' + - '
                          ' + - '' + - '' + - '{{#if canUploadAndEmbed}}' + - '
                          {{{get_string "instructions" component}}}
                          ' + - '{{/if}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '{{#if canUpload}}' + - '' + - '{{/if}}' + - '
                          ' + - '{{#if canUpload}}' + - '
                          ' + - '' + - '' + - '' + - '' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - - H5PTEMPLATE = '' + - '{{#if addParagraphs}}


                          {{/if}}' + - '
                          ' + - '{{{url}}}' + - '
                          ' + - '{{#if addParagraphs}}


                          {{/if}}'; - -Y.namespace('M.atto_h5p').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * A reference to the currently open form. - * - * @param _form - * @type Node - * @private - */ - _form: null, - - /** - * A reference to the currently selected H5P div. - * - * @param _form - * @type Node - * @private - */ - _H5PDiv: null, - - /** - * Allowed methods of adding H5P. - * - * @param _allowedmethods - * @type String - * @private - */ - _allowedmethods: 'none', - - initializer: function() { - this._allowedmethods = this.get('allowedmethods'); - if (this._allowedmethods === 'none') { - // Plugin not available here. - return; - } - this.addButton({ - icon: 'icon', - iconComponent: 'atto_h5p', - callback: this._displayDialogue, - tags: '.h5p-placeholder', - tagMatchRequiresAll: false - }); - - this.editor.all('.h5p-placeholder').setAttribute('contenteditable', 'false'); - this.editor.delegate('dblclick', this._handleDblClick, '.h5p-placeholder', this); - this.editor.delegate('click', this._handleClick, '.h5p-placeholder', this); - }, - - /** - * Handle a double click on a H5P Placeholder. - * - * @method _handleDblClick - * @private - */ - _handleDblClick: function() { - this._displayDialogue(); - }, - - /** - * Handle a click on a H5P Placeholder. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var selection = this.get('host').getSelectionFromNode(e.target); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Display the h5p editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection === false) { - return; - } - - this._getH5PDiv(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENTNAME), - width: 'auto', - focusAfterHide: true - }); - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_h5p_form'}); - }, - - /** - * Get the H5P iframe - * - * @method _resolveH5P - * @return {Node} The H5P iframe selected. - * @private - */ - _getH5PDiv: function() { - var selectednodes = this.get('host').getSelectedNodes(); - var H5PDiv = null; - selectednodes.each(function(selNode) { - if (selNode.hasClass('h5p-placeholder')) { - H5PDiv = selNode; - } - }); - this._H5PDiv = H5PDiv; - }, - - /** - * Get the H5P button permissions. - * - * @return {Object} H5P button permissions. - * @private - */ - _getPermissions: function() { - var permissions = { - 'canEmbed': false, - 'canUpload': false, - 'canUploadAndEmbed': false - }; - - if (this.get('host').canShowFilepicker('h5p')) { - if (this._allowedmethods === 'both') { - permissions.canUploadAndEmbed = true; - permissions.canUpload = true; - } else if (this._allowedmethods === 'upload') { - permissions.canUpload = true; - } - } - - if (this._allowedmethods === 'both' || this._allowedmethods === 'embed') { - permissions.canEmbed = true; - } - return permissions; - }, - - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} The content to place in the dialogue. - * @private - */ - _getDialogueContent: function() { - - var permissions = this._getPermissions(); - - var fileURL, - optionDownloadButton, - optionEmbedButton, - optionCopyrightButton, - showOptions = false; - - if (this._H5PDiv) { - var H5PURL = this._H5PDiv.get('innerHTML'); - var fileBaseUrl = M.cfg.wwwroot + '/draftfile.php'; - if (fileBaseUrl == H5PURL.substring(0, fileBaseUrl.length)) { - fileURL = H5PURL.split("?")[0]; - - var parameters = H5PURL.split("?")[1]; - if (parameters) { - if (parameters.match(/export=1/)) { - optionDownloadButton = 'checked'; - showOptions = true; - } - - if (parameters.match(/embed=1/)) { - optionEmbedButton = 'checked'; - showOptions = true; - } - - if (parameters.match(/copyright=1/)) { - optionCopyrightButton = 'checked'; - showOptions = true; - } - } - } else { - fileURL = H5PURL; - } - } - - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - CSS: CSS, - component: COMPONENTNAME, - canUpload: permissions.canUpload, - canEmbed: permissions.canEmbed, - canUploadAndEmbed: permissions.canUploadAndEmbed, - showOptions: showOptions, - fileURL: fileURL, - optionDownloadButton: optionDownloadButton, - optionEmbedButton: optionEmbedButton, - optionCopyrightButton: optionCopyrightButton - })); - - this._form = content; - - // Listen to and act on Dialogue content events. - this._setEventListeners(); - - return content; - }, - - /** - * Update the dialogue after an h5p was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the h5p. - * @private - */ - _filepickerCallback: function(params) { - if (params.url !== '') { - var input = this._form.one(SELECTORS.INPUTH5PFILE); - input.set('value', params.url); - this._removeWarnings(); - } - }, - - /** - * Set event Listeners for Dialogue content actions. - * - * @method _setEventListeners - * @private - */ - _setEventListeners: function() { - var form = this._form; - var permissions = this._getPermissions(); - - form.one(SELECTORS.INPUTSUBMIT).on('click', this._setH5P, this); - - if (permissions.canUpload) { - form.one(SELECTORS.H5PBROWSER).on('click', function() { - this.get('host').showFilepicker('h5p', this._filepickerCallback, this); - }, this); - } - - if (permissions.canUploadAndEmbed) { - form.one(SELECTORS.INPUTH5PFILE).on('change', function() { - this._removeWarnings(); - }, this); - } - }, - - /** - * Remove warnings shown in the dialogue. - * - * @method _removeWarnings - * @private - */ - _removeWarnings: function() { - var form = this._form; - form.one(SELECTORS.URLWARNING).setStyle('display', 'none'); - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'none'); - }, - - /** - * Update the h5p in the contenteditable. - * - * @method _setH5P - * @param {EventFacade} e - * @private - */ - _setH5P: function(e) { - var form = this._form, - h5phtml, - host = this.get('host'), - h5pfile = form.one(SELECTORS.INPUTH5PFILE).get('value'), - permissions = this._getPermissions(); - - e.preventDefault(); - - // Check if there are any issues. - if (this._updateWarning()) { - return; - } - - // Focus on the editor in preparation for inserting the H5P. - host.focus(); - - // Add an empty paragraph after new H5P container that can catch the cursor. - var addParagraphs = true; - - // If a H5P placeholder was selected we can destroy it now. - if (this._H5PDiv) { - this._H5PDiv.remove(); - addParagraphs = false; - } - - if (h5pfile !== '') { - host.setSelection(this._currentSelection); - - if (h5pfile.startsWith(M.cfg.wwwroot)) { - // It's a local file. - var params = ''; - if (permissions.canUpload) { - var options = {}; - if (form.one(SELECTORS.OPTION_DOWNLOAD_BUTTON).get('checked')) { - options['export'] = '1'; - } - if (form.one(SELECTORS.OPTION_EMBED_BUTTON).get('checked')) { - options.embed = '1'; - } - if (form.one(SELECTORS.OPTION_COPYRIGHT_BUTTON).get('checked')) { - options.copyright = '1'; - } - - for (var opt in options) { - if (params === "" && (h5pfile.indexOf("?") === -1)) { - params += "?"; - } else { - params += "&"; - } - params += opt + "=" + options[opt]; - } - } - - var h5ptemplate = Y.Handlebars.compile(H5PTEMPLATE); - - h5phtml = h5ptemplate({ - url: h5pfile + params, - addParagraphs: addParagraphs - }); - } else { - // It's a URL. - var urltemplate = Y.Handlebars.compile(H5PTEMPLATE); - h5phtml = urltemplate({ - url: h5pfile - }); - } - - host.insertContentAtFocusPoint(h5phtml); - - this.markUpdated(); - } - - this.getDialogue({ - focusAfterHide: null - }).hide(); - }, - - /** - * Check if this could be a h5p embed. - * - * @method _validEmbed - * @param {String} str - * @return {boolean} whether this is a iframe tag. - * @private - */ - _validEmbed: function(str) { - var pattern = new RegExp('^()'); // Port and path. - return !!pattern.test(str); - }, - - /** - * Check if this could be a h5p URL. - * - * @method _validURL - * @param {String} str - * @return {boolean} whether this is a valid URL. - * @private - */ - _validURL: function(str) { - var pattern = new RegExp('^(https?:\\/\\/)?' + // Protocol. - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // Domain name. - '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address. - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'); // Port and path. - return !!pattern.test(str); - }, - - /** - * Update the url warning. - * - * @method _updateWarning - * @return {boolean} whether a warning should be displayed. - * @private - */ - _updateWarning: function() { - var form = this._form, - state = true, - h5pfile, - permissions = this._getPermissions(); - - if (permissions.canUpload || permissions.canEmbed) { - h5pfile = form.one(SELECTORS.INPUTH5PFILE).get('value'); - if (h5pfile !== '') { - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'none'); - if (h5pfile.startsWith(M.cfg.wwwroot) || this._validURL(h5pfile)) { - // Only external URLs have to be validated. - form.one(SELECTORS.URLWARNING).setStyle('display', 'none'); - state = false; - } else { - form.one(SELECTORS.URLWARNING).setStyle('display', 'block'); - state = true; - } - } else { - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'block'); - state = true; - } - } - - return state; - } -}, { - ATTRS: { - /** - * The allowedmethods of adding h5p content. - * - * @attribute allowedmethods - * @type String - */ - allowedmethods: { - value: null - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/h5p/yui/src/button/build.json b/lib/editor/atto/plugins/h5p/yui/src/button/build.json deleted file mode 100644 index a7d3bda23b8..00000000000 --- a/lib/editor/atto/plugins/h5p/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_h5p-button", - "builds": { - "moodle-atto_h5p-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/h5p/yui/src/button/js/button.js b/lib/editor/atto/plugins/h5p/yui/src/button/js/button.js deleted file mode 100644 index ea81bb87b47..00000000000 --- a/lib/editor/atto/plugins/h5p/yui/src/button/js/button.js +++ /dev/null @@ -1,600 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_h5p - * @copyright 2019 Bas Brands - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_h5p-button - */ - -/** - * Atto h5p content tool. - * - * @namespace M.atto_h5p - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var CSS = { - CONTENTWARNING: 'att_h5p_contentwarning', - H5PBROWSER: 'openh5pbrowser', - INPUTALT: 'atto_h5p_altentry', - INPUTH5PFILE: 'atto_h5p_file', - INPUTSUBMIT: 'atto_h5p_urlentrysubmit', - OPTION_DOWNLOAD_BUTTON: 'atto_h5p_option_download_button', - OPTION_COPYRIGHT_BUTTON: 'atto_h5p_option_copyright_button', - OPTION_EMBED_BUTTON: 'atto_h5p_option_embed_button', - URLWARNING: 'atto_h5p_warning' - }, - SELECTORS = { - CONTENTWARNING: '.' + CSS.CONTENTWARNING, - H5PBROWSER: '.' + CSS.H5PBROWSER, - INPUTH5PFILE: '.' + CSS.INPUTH5PFILE, - INPUTSUBMIT: '.' + CSS.INPUTSUBMIT, - OPTION_DOWNLOAD_BUTTON: '.' + CSS.OPTION_DOWNLOAD_BUTTON, - OPTION_COPYRIGHT_BUTTON: '.' + CSS.OPTION_COPYRIGHT_BUTTON, - OPTION_EMBED_BUTTON: '.' + CSS.OPTION_EMBED_BUTTON, - URLWARNING: '.' + CSS.URLWARNING - }, - - COMPONENTNAME = 'atto_h5p', - - TEMPLATE = '' + - '
                          ' + - '' + - '' + - '{{#if canUploadAndEmbed}}' + - '
                          {{{get_string "instructions" component}}}
                          ' + - '{{/if}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '{{#if canUpload}}' + - '' + - '{{/if}}' + - '
                          ' + - '{{#if canUpload}}' + - '
                          ' + - '' + - '' + - '' + - '' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - - H5PTEMPLATE = '' + - '{{#if addParagraphs}}


                          {{/if}}' + - '
                          ' + - '{{{url}}}' + - '
                          ' + - '{{#if addParagraphs}}


                          {{/if}}'; - -Y.namespace('M.atto_h5p').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * A reference to the currently open form. - * - * @param _form - * @type Node - * @private - */ - _form: null, - - /** - * A reference to the currently selected H5P div. - * - * @param _form - * @type Node - * @private - */ - _H5PDiv: null, - - /** - * Allowed methods of adding H5P. - * - * @param _allowedmethods - * @type String - * @private - */ - _allowedmethods: 'none', - - initializer: function() { - this._allowedmethods = this.get('allowedmethods'); - if (this._allowedmethods === 'none') { - // Plugin not available here. - return; - } - this.addButton({ - icon: 'icon', - iconComponent: 'atto_h5p', - callback: this._displayDialogue, - tags: '.h5p-placeholder', - tagMatchRequiresAll: false - }); - - this.editor.all('.h5p-placeholder').setAttribute('contenteditable', 'false'); - this.editor.delegate('dblclick', this._handleDblClick, '.h5p-placeholder', this); - this.editor.delegate('click', this._handleClick, '.h5p-placeholder', this); - }, - - /** - * Handle a double click on a H5P Placeholder. - * - * @method _handleDblClick - * @private - */ - _handleDblClick: function() { - this._displayDialogue(); - }, - - /** - * Handle a click on a H5P Placeholder. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var selection = this.get('host').getSelectionFromNode(e.target); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Display the h5p editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection === false) { - return; - } - - this._getH5PDiv(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('pluginname', COMPONENTNAME), - width: 'auto', - focusAfterHide: true - }); - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_h5p_form'}); - }, - - /** - * Get the H5P iframe - * - * @method _resolveH5P - * @return {Node} The H5P iframe selected. - * @private - */ - _getH5PDiv: function() { - var selectednodes = this.get('host').getSelectedNodes(); - var H5PDiv = null; - selectednodes.each(function(selNode) { - if (selNode.hasClass('h5p-placeholder')) { - H5PDiv = selNode; - } - }); - this._H5PDiv = H5PDiv; - }, - - /** - * Get the H5P button permissions. - * - * @return {Object} H5P button permissions. - * @private - */ - _getPermissions: function() { - var permissions = { - 'canEmbed': false, - 'canUpload': false, - 'canUploadAndEmbed': false - }; - - if (this.get('host').canShowFilepicker('h5p')) { - if (this._allowedmethods === 'both') { - permissions.canUploadAndEmbed = true; - permissions.canUpload = true; - } else if (this._allowedmethods === 'upload') { - permissions.canUpload = true; - } - } - - if (this._allowedmethods === 'both' || this._allowedmethods === 'embed') { - permissions.canEmbed = true; - } - return permissions; - }, - - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} The content to place in the dialogue. - * @private - */ - _getDialogueContent: function() { - - var permissions = this._getPermissions(); - - var fileURL, - optionDownloadButton, - optionEmbedButton, - optionCopyrightButton, - showOptions = false; - - if (this._H5PDiv) { - var H5PURL = this._H5PDiv.get('innerHTML'); - var fileBaseUrl = M.cfg.wwwroot + '/draftfile.php'; - if (fileBaseUrl == H5PURL.substring(0, fileBaseUrl.length)) { - fileURL = H5PURL.split("?")[0]; - - var parameters = H5PURL.split("?")[1]; - if (parameters) { - if (parameters.match(/export=1/)) { - optionDownloadButton = 'checked'; - showOptions = true; - } - - if (parameters.match(/embed=1/)) { - optionEmbedButton = 'checked'; - showOptions = true; - } - - if (parameters.match(/copyright=1/)) { - optionCopyrightButton = 'checked'; - showOptions = true; - } - } - } else { - fileURL = H5PURL; - } - } - - var template = Y.Handlebars.compile(TEMPLATE), - content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - CSS: CSS, - component: COMPONENTNAME, - canUpload: permissions.canUpload, - canEmbed: permissions.canEmbed, - canUploadAndEmbed: permissions.canUploadAndEmbed, - showOptions: showOptions, - fileURL: fileURL, - optionDownloadButton: optionDownloadButton, - optionEmbedButton: optionEmbedButton, - optionCopyrightButton: optionCopyrightButton - })); - - this._form = content; - - // Listen to and act on Dialogue content events. - this._setEventListeners(); - - return content; - }, - - /** - * Update the dialogue after an h5p was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the h5p. - * @private - */ - _filepickerCallback: function(params) { - if (params.url !== '') { - var input = this._form.one(SELECTORS.INPUTH5PFILE); - input.set('value', params.url); - this._removeWarnings(); - } - }, - - /** - * Set event Listeners for Dialogue content actions. - * - * @method _setEventListeners - * @private - */ - _setEventListeners: function() { - var form = this._form; - var permissions = this._getPermissions(); - - form.one(SELECTORS.INPUTSUBMIT).on('click', this._setH5P, this); - - if (permissions.canUpload) { - form.one(SELECTORS.H5PBROWSER).on('click', function() { - this.get('host').showFilepicker('h5p', this._filepickerCallback, this); - }, this); - } - - if (permissions.canUploadAndEmbed) { - form.one(SELECTORS.INPUTH5PFILE).on('change', function() { - this._removeWarnings(); - }, this); - } - }, - - /** - * Remove warnings shown in the dialogue. - * - * @method _removeWarnings - * @private - */ - _removeWarnings: function() { - var form = this._form; - form.one(SELECTORS.URLWARNING).setStyle('display', 'none'); - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'none'); - }, - - /** - * Update the h5p in the contenteditable. - * - * @method _setH5P - * @param {EventFacade} e - * @private - */ - _setH5P: function(e) { - var form = this._form, - h5phtml, - host = this.get('host'), - h5pfile = form.one(SELECTORS.INPUTH5PFILE).get('value'), - permissions = this._getPermissions(); - - e.preventDefault(); - - // Check if there are any issues. - if (this._updateWarning()) { - return; - } - - // Focus on the editor in preparation for inserting the H5P. - host.focus(); - - // Add an empty paragraph after new H5P container that can catch the cursor. - var addParagraphs = true; - - // If a H5P placeholder was selected we can destroy it now. - if (this._H5PDiv) { - this._H5PDiv.remove(); - addParagraphs = false; - } - - if (h5pfile !== '') { - host.setSelection(this._currentSelection); - - if (h5pfile.startsWith(M.cfg.wwwroot)) { - // It's a local file. - var params = ''; - if (permissions.canUpload) { - var options = {}; - if (form.one(SELECTORS.OPTION_DOWNLOAD_BUTTON).get('checked')) { - options['export'] = '1'; - } - if (form.one(SELECTORS.OPTION_EMBED_BUTTON).get('checked')) { - options.embed = '1'; - } - if (form.one(SELECTORS.OPTION_COPYRIGHT_BUTTON).get('checked')) { - options.copyright = '1'; - } - - for (var opt in options) { - if (params === "" && (h5pfile.indexOf("?") === -1)) { - params += "?"; - } else { - params += "&"; - } - params += opt + "=" + options[opt]; - } - } - - var h5ptemplate = Y.Handlebars.compile(H5PTEMPLATE); - - h5phtml = h5ptemplate({ - url: h5pfile + params, - addParagraphs: addParagraphs - }); - } else { - // It's a URL. - var urltemplate = Y.Handlebars.compile(H5PTEMPLATE); - h5phtml = urltemplate({ - url: h5pfile - }); - } - - host.insertContentAtFocusPoint(h5phtml); - - this.markUpdated(); - } - - this.getDialogue({ - focusAfterHide: null - }).hide(); - }, - - /** - * Check if this could be a h5p embed. - * - * @method _validEmbed - * @param {String} str - * @return {boolean} whether this is a iframe tag. - * @private - */ - _validEmbed: function(str) { - var pattern = new RegExp('^()'); // Port and path. - return !!pattern.test(str); - }, - - /** - * Check if this could be a h5p URL. - * - * @method _validURL - * @param {String} str - * @return {boolean} whether this is a valid URL. - * @private - */ - _validURL: function(str) { - var pattern = new RegExp('^(https?:\\/\\/)?' + // Protocol. - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // Domain name. - '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address. - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'); // Port and path. - return !!pattern.test(str); - }, - - /** - * Update the url warning. - * - * @method _updateWarning - * @return {boolean} whether a warning should be displayed. - * @private - */ - _updateWarning: function() { - var form = this._form, - state = true, - h5pfile, - permissions = this._getPermissions(); - - if (permissions.canUpload || permissions.canEmbed) { - h5pfile = form.one(SELECTORS.INPUTH5PFILE).get('value'); - if (h5pfile !== '') { - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'none'); - if (h5pfile.startsWith(M.cfg.wwwroot) || this._validURL(h5pfile)) { - // Only external URLs have to be validated. - form.one(SELECTORS.URLWARNING).setStyle('display', 'none'); - state = false; - } else { - form.one(SELECTORS.URLWARNING).setStyle('display', 'block'); - state = true; - } - } else { - form.one(SELECTORS.CONTENTWARNING).setStyle('display', 'block'); - state = true; - } - } - - return state; - } -}, { - ATTRS: { - /** - * The allowedmethods of adding h5p content. - * - * @attribute allowedmethods - * @type String - */ - allowedmethods: { - value: null - } - } -}); diff --git a/lib/editor/atto/plugins/h5p/yui/src/button/meta/button.json b/lib/editor/atto/plugins/h5p/yui/src/button/meta/button.json deleted file mode 100644 index e1cd317e99e..00000000000 --- a/lib/editor/atto/plugins/h5p/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_h5p-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/html/classes/privacy/provider.php b/lib/editor/atto/plugins/html/classes/privacy/provider.php deleted file mode 100644 index 39f86dd5352..00000000000 --- a/lib/editor/atto/plugins/html/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_html - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_html\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_html implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/html/lang/en/atto_html.php b/lib/editor/atto/plugins/html/lang/en/atto_html.php deleted file mode 100644 index bd77efc8ce9..00000000000 --- a/lib/editor/atto/plugins/html/lang/en/atto_html.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_html', language 'en'. - * - * @package atto_html - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'HTML'; -$string['privacy:metadata'] = 'The atto_html plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/html/styles.css b/lib/editor/atto/plugins/html/styles.css deleted file mode 100644 index f6e60ce1097..00000000000 --- a/lib/editor/atto/plugins/html/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -.dir-rtl .CodeMirror { - text-align: left; - direction: ltr; -} diff --git a/lib/editor/atto/plugins/html/tests/behat/html.feature b/lib/editor/atto/plugins/html/tests/behat/html.feature deleted file mode 100644 index 83533b1b645..00000000000 --- a/lib/editor/atto/plugins/html/tests/behat/html.feature +++ /dev/null @@ -1,31 +0,0 @@ -@editor @editor_atto @atto @atto_html -Feature: Atto edit HTML - To write advanced HTML, I need to edit the HTML source code - - @javascript - Scenario: Edit the html source - Given I log in as "admin" - When I open my profile in edit mode - And I set the field "Description" to "

                          Smurf

                          " - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then the field "Description" matches value "

                          Smurf

                          " - - @javascript - Scenario: Validation of empty string when the form is submitted with HTML source mode. - Given the following "courses" exist: - | fullname | shortname | format | - | Course 1 | C1 | weeks | - And the following "question categories" exist: - | contextlevel | reference | name | - | Course | C1 | Test questions | - And the following "questions" exist: - | questioncategory | qtype | name | questiontext | - | Test questions | essay | Essay 01 new | Write about whatever you want | - And I am on the "Essay 01 new" "core_question > edit" page logged in as admin - And I click on "Show more buttons" "button" in the "Question text" "form_row" - And I click on "HTML" "button" in the "Question text" "form_row" - And I press the shift + end key - And I press the delete key - When I press "id_submitbutton" - Then I should see "You must supply a value here." in the "Question text" "form_row" diff --git a/lib/editor/atto/plugins/html/thirdpartylibs.xml b/lib/editor/atto/plugins/html/thirdpartylibs.xml deleted file mode 100644 index a4d80374716..00000000000 --- a/lib/editor/atto/plugins/html/thirdpartylibs.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - yui/src/codemirror - codemirror - CodeMirror is a versatile text editor implemented in JavaScript for the browser. - 5.65.16 - MIT - https://github.com/codemirror/codemirror5 - - - yui/src/beautify - jsbeautify - Beautify HTML code in Atto. - 1.15.1 - MIT - https://github.com/beautify-web/js-beautify - - 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - - diff --git a/lib/editor/atto/plugins/html/version.php b/lib/editor/atto/plugins/html/version.php deleted file mode 100644 index 98d69a78a95..00000000000 --- a/lib/editor/atto/plugins/html/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_html - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_html'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js deleted file mode 100644 index 4bd9ce1b025..00000000000 --- a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js +++ /dev/null @@ -1,8988 +0,0 @@ -YUI.add('moodle-atto_html-beautify', function (Y, NAME) { - -// JSBeautify adds itself to the exports object if one exists. -// Define exports here and it will work as if by magic. -// This is safe to put in a function and will not be exported to the global -// namespace. Note, we'll have to remove this when YUI supports, and we move to ES6. -var exports = {}; - -var define = null; // Remove require.js support in this context. - -// JSBeautify calls require() in order to get the existing exported modules. -var require = function() { - return exports; -}; -require(); - -// Actually define beautify in our namespace. -Y.namespace('M.atto_html').beautify = exports; -/* AUTO-GENERATED. DO NOT MODIFY. */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - JS Beautifier ---------------- - - - Written by Einar Lielmanis, - https://beautifier.io/ - - Originally converted to javascript by Vital, - "End braces on own line" added by Chris J. Shull, - Parsing improvements for brace-less statements by Liam Newman - - - Usage: - js_beautify(js_source_text); - js_beautify(js_source_text, options); - - The options are: - indent_size (default 4) - indentation size, - indent_char (default space) - character to indent with, - preserve_newlines (default true) - whether existing line breaks should be preserved, - max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk, - - jslint_happy (default false) - if true, then jslint-stricter mode is enforced. - - jslint_happy !jslint_happy - --------------------------------- - function () function() - - switch () { switch() { - case 1: case 1: - break; break; - } } - - space_after_anon_function (default false) - should the space before an anonymous function's parens be added, "function()" vs "function ()", - NOTE: This option is overridden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design) - - brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none" | any of the former + ",preserve-inline" - put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are. - preserve-inline will try to preserve inline blocks of curly braces - - space_before_conditional (default true) - should the space before conditional statement be added, "if(true)" vs "if (true)", - - unescape_strings (default false) - should printable characters in strings encoded in \xNN notation be unescaped, "example" vs "\x65\x78\x61\x6d\x70\x6c\x65" - - wrap_line_length (default unlimited) - lines should wrap at next opportunity after this number of characters. - NOTE: This is not a hard limit. Lines will continue until a point where a newline would - be preserved if it were present. - - end_with_newline (default false) - end output with a newline - - - e.g - - js_beautify(js_source_text, { - 'indent_size': 1, - 'indent_char': '\t' - }); - -*/ - -(function() { - -/* GENERATED_BUILD_OUTPUT */ -var legacy_beautify_js; -/******/ (function() { // webpackBootstrap -/******/ "use strict"; -/******/ var __webpack_modules__ = ([ -/* 0 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Beautifier = (__webpack_require__(1).Beautifier), - Options = (__webpack_require__(5).Options); - -function js_beautify(js_source_text, options) { - var beautifier = new Beautifier(js_source_text, options); - return beautifier.beautify(); -} - -module.exports = js_beautify; -module.exports.defaultOptions = function() { - return new Options(); -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Output = (__webpack_require__(2).Output); -var Token = (__webpack_require__(3).Token); -var acorn = __webpack_require__(4); -var Options = (__webpack_require__(5).Options); -var Tokenizer = (__webpack_require__(7).Tokenizer); -var line_starters = (__webpack_require__(7).line_starters); -var positionable_operators = (__webpack_require__(7).positionable_operators); -var TOKEN = (__webpack_require__(7).TOKEN); - - -function in_array(what, arr) { - return arr.indexOf(what) !== -1; -} - -function ltrim(s) { - return s.replace(/^\s+/g, ''); -} - -function generateMapFromStrings(list) { - var result = {}; - for (var x = 0; x < list.length; x++) { - // make the mapped names underscored instead of dash - result[list[x].replace(/-/g, '_')] = list[x]; - } - return result; -} - -function reserved_word(token, word) { - return token && token.type === TOKEN.RESERVED && token.text === word; -} - -function reserved_array(token, words) { - return token && token.type === TOKEN.RESERVED && in_array(token.text, words); -} -// Unsure of what they mean, but they work. Worth cleaning up in future. -var special_words = ['case', 'return', 'do', 'if', 'throw', 'else', 'await', 'break', 'continue', 'async']; - -var validPositionValues = ['before-newline', 'after-newline', 'preserve-newline']; - -// Generate map from array -var OPERATOR_POSITION = generateMapFromStrings(validPositionValues); - -var OPERATOR_POSITION_BEFORE_OR_PRESERVE = [OPERATOR_POSITION.before_newline, OPERATOR_POSITION.preserve_newline]; - -var MODE = { - BlockStatement: 'BlockStatement', // 'BLOCK' - Statement: 'Statement', // 'STATEMENT' - ObjectLiteral: 'ObjectLiteral', // 'OBJECT', - ArrayLiteral: 'ArrayLiteral', //'[EXPRESSION]', - ForInitializer: 'ForInitializer', //'(FOR-EXPRESSION)', - Conditional: 'Conditional', //'(COND-EXPRESSION)', - Expression: 'Expression' //'(EXPRESSION)' -}; - -function remove_redundant_indentation(output, frame) { - // This implementation is effective but has some issues: - // - can cause line wrap to happen too soon due to indent removal - // after wrap points are calculated - // These issues are minor compared to ugly indentation. - - if (frame.multiline_frame || - frame.mode === MODE.ForInitializer || - frame.mode === MODE.Conditional) { - return; - } - - // remove one indent from each line inside this section - output.remove_indent(frame.start_line_index); -} - -// we could use just string.split, but -// IE doesn't like returning empty strings -function split_linebreaks(s) { - //return s.split(/\x0d\x0a|\x0a/); - - s = s.replace(acorn.allLineBreaks, '\n'); - var out = [], - idx = s.indexOf("\n"); - while (idx !== -1) { - out.push(s.substring(0, idx)); - s = s.substring(idx + 1); - idx = s.indexOf("\n"); - } - if (s.length) { - out.push(s); - } - return out; -} - -function is_array(mode) { - return mode === MODE.ArrayLiteral; -} - -function is_expression(mode) { - return in_array(mode, [MODE.Expression, MODE.ForInitializer, MODE.Conditional]); -} - -function all_lines_start_with(lines, c) { - for (var i = 0; i < lines.length; i++) { - var line = lines[i].trim(); - if (line.charAt(0) !== c) { - return false; - } - } - return true; -} - -function each_line_matches_indent(lines, indent) { - var i = 0, - len = lines.length, - line; - for (; i < len; i++) { - line = lines[i]; - // allow empty lines to pass through - if (line && line.indexOf(indent) !== 0) { - return false; - } - } - return true; -} - - -function Beautifier(source_text, options) { - options = options || {}; - this._source_text = source_text || ''; - - this._output = null; - this._tokens = null; - this._last_last_text = null; - this._flags = null; - this._previous_flags = null; - - this._flag_store = null; - this._options = new Options(options); -} - -Beautifier.prototype.create_flags = function(flags_base, mode) { - var next_indent_level = 0; - if (flags_base) { - next_indent_level = flags_base.indentation_level; - if (!this._output.just_added_newline() && - flags_base.line_indent_level > next_indent_level) { - next_indent_level = flags_base.line_indent_level; - } - } - - var next_flags = { - mode: mode, - parent: flags_base, - last_token: flags_base ? flags_base.last_token : new Token(TOKEN.START_BLOCK, ''), // last token text - last_word: flags_base ? flags_base.last_word : '', // last TOKEN.WORD passed - declaration_statement: false, - declaration_assignment: false, - multiline_frame: false, - inline_frame: false, - if_block: false, - else_block: false, - class_start_block: false, // class A { INSIDE HERE } or class B extends C { INSIDE HERE } - do_block: false, - do_while: false, - import_block: false, - in_case_statement: false, // switch(..){ INSIDE HERE } - in_case: false, // we're on the exact line with "case 0:" - case_body: false, // the indented case-action block - case_block: false, // the indented case-action block is wrapped with {} - indentation_level: next_indent_level, - alignment: 0, - line_indent_level: flags_base ? flags_base.line_indent_level : next_indent_level, - start_line_index: this._output.get_line_number(), - ternary_depth: 0 - }; - return next_flags; -}; - -Beautifier.prototype._reset = function(source_text) { - var baseIndentString = source_text.match(/^[\t ]*/)[0]; - - this._last_last_text = ''; // pre-last token text - this._output = new Output(this._options, baseIndentString); - - // If testing the ignore directive, start with output disable set to true - this._output.raw = this._options.test_output_raw; - - - // Stack of parsing/formatting states, including MODE. - // We tokenize, parse, and output in an almost purely a forward-only stream of token input - // and formatted output. This makes the beautifier less accurate than full parsers - // but also far more tolerant of syntax errors. - // - // For example, the default mode is MODE.BlockStatement. If we see a '{' we push a new frame of type - // MODE.BlockStatement on the the stack, even though it could be object literal. If we later - // encounter a ":", we'll switch to to MODE.ObjectLiteral. If we then see a ";", - // most full parsers would die, but the beautifier gracefully falls back to - // MODE.BlockStatement and continues on. - this._flag_store = []; - this.set_mode(MODE.BlockStatement); - var tokenizer = new Tokenizer(source_text, this._options); - this._tokens = tokenizer.tokenize(); - return source_text; -}; - -Beautifier.prototype.beautify = function() { - // if disabled, return the input unchanged. - if (this._options.disabled) { - return this._source_text; - } - - var sweet_code; - var source_text = this._reset(this._source_text); - - var eol = this._options.eol; - if (this._options.eol === 'auto') { - eol = '\n'; - if (source_text && acorn.lineBreak.test(source_text || '')) { - eol = source_text.match(acorn.lineBreak)[0]; - } - } - - var current_token = this._tokens.next(); - while (current_token) { - this.handle_token(current_token); - - this._last_last_text = this._flags.last_token.text; - this._flags.last_token = current_token; - - current_token = this._tokens.next(); - } - - sweet_code = this._output.get_code(eol); - - return sweet_code; -}; - -Beautifier.prototype.handle_token = function(current_token, preserve_statement_flags) { - if (current_token.type === TOKEN.START_EXPR) { - this.handle_start_expr(current_token); - } else if (current_token.type === TOKEN.END_EXPR) { - this.handle_end_expr(current_token); - } else if (current_token.type === TOKEN.START_BLOCK) { - this.handle_start_block(current_token); - } else if (current_token.type === TOKEN.END_BLOCK) { - this.handle_end_block(current_token); - } else if (current_token.type === TOKEN.WORD) { - this.handle_word(current_token); - } else if (current_token.type === TOKEN.RESERVED) { - this.handle_word(current_token); - } else if (current_token.type === TOKEN.SEMICOLON) { - this.handle_semicolon(current_token); - } else if (current_token.type === TOKEN.STRING) { - this.handle_string(current_token); - } else if (current_token.type === TOKEN.EQUALS) { - this.handle_equals(current_token); - } else if (current_token.type === TOKEN.OPERATOR) { - this.handle_operator(current_token); - } else if (current_token.type === TOKEN.COMMA) { - this.handle_comma(current_token); - } else if (current_token.type === TOKEN.BLOCK_COMMENT) { - this.handle_block_comment(current_token, preserve_statement_flags); - } else if (current_token.type === TOKEN.COMMENT) { - this.handle_comment(current_token, preserve_statement_flags); - } else if (current_token.type === TOKEN.DOT) { - this.handle_dot(current_token); - } else if (current_token.type === TOKEN.EOF) { - this.handle_eof(current_token); - } else if (current_token.type === TOKEN.UNKNOWN) { - this.handle_unknown(current_token, preserve_statement_flags); - } else { - this.handle_unknown(current_token, preserve_statement_flags); - } -}; - -Beautifier.prototype.handle_whitespace_and_comments = function(current_token, preserve_statement_flags) { - var newlines = current_token.newlines; - var keep_whitespace = this._options.keep_array_indentation && is_array(this._flags.mode); - - if (current_token.comments_before) { - var comment_token = current_token.comments_before.next(); - while (comment_token) { - // The cleanest handling of inline comments is to treat them as though they aren't there. - // Just continue formatting and the behavior should be logical. - // Also ignore unknown tokens. Again, this should result in better behavior. - this.handle_whitespace_and_comments(comment_token, preserve_statement_flags); - this.handle_token(comment_token, preserve_statement_flags); - comment_token = current_token.comments_before.next(); - } - } - - if (keep_whitespace) { - for (var i = 0; i < newlines; i += 1) { - this.print_newline(i > 0, preserve_statement_flags); - } - } else { - if (this._options.max_preserve_newlines && newlines > this._options.max_preserve_newlines) { - newlines = this._options.max_preserve_newlines; - } - - if (this._options.preserve_newlines) { - if (newlines > 1) { - this.print_newline(false, preserve_statement_flags); - for (var j = 1; j < newlines; j += 1) { - this.print_newline(true, preserve_statement_flags); - } - } - } - } - -}; - -var newline_restricted_tokens = ['async', 'break', 'continue', 'return', 'throw', 'yield']; - -Beautifier.prototype.allow_wrap_or_preserved_newline = function(current_token, force_linewrap) { - force_linewrap = (force_linewrap === undefined) ? false : force_linewrap; - - // Never wrap the first token on a line - if (this._output.just_added_newline()) { - return; - } - - var shouldPreserveOrForce = (this._options.preserve_newlines && current_token.newlines) || force_linewrap; - var operatorLogicApplies = in_array(this._flags.last_token.text, positionable_operators) || - in_array(current_token.text, positionable_operators); - - if (operatorLogicApplies) { - var shouldPrintOperatorNewline = ( - in_array(this._flags.last_token.text, positionable_operators) && - in_array(this._options.operator_position, OPERATOR_POSITION_BEFORE_OR_PRESERVE) - ) || - in_array(current_token.text, positionable_operators); - shouldPreserveOrForce = shouldPreserveOrForce && shouldPrintOperatorNewline; - } - - if (shouldPreserveOrForce) { - this.print_newline(false, true); - } else if (this._options.wrap_line_length) { - if (reserved_array(this._flags.last_token, newline_restricted_tokens)) { - // These tokens should never have a newline inserted - // between them and the following expression. - return; - } - this._output.set_wrap_point(); - } -}; - -Beautifier.prototype.print_newline = function(force_newline, preserve_statement_flags) { - if (!preserve_statement_flags) { - if (this._flags.last_token.text !== ';' && this._flags.last_token.text !== ',' && this._flags.last_token.text !== '=' && (this._flags.last_token.type !== TOKEN.OPERATOR || this._flags.last_token.text === '--' || this._flags.last_token.text === '++')) { - var next_token = this._tokens.peek(); - while (this._flags.mode === MODE.Statement && - !(this._flags.if_block && reserved_word(next_token, 'else')) && - !this._flags.do_block) { - this.restore_mode(); - } - } - } - - if (this._output.add_new_line(force_newline)) { - this._flags.multiline_frame = true; - } -}; - -Beautifier.prototype.print_token_line_indentation = function(current_token) { - if (this._output.just_added_newline()) { - if (this._options.keep_array_indentation && - current_token.newlines && - (current_token.text === '[' || is_array(this._flags.mode))) { - this._output.current_line.set_indent(-1); - this._output.current_line.push(current_token.whitespace_before); - this._output.space_before_token = false; - } else if (this._output.set_indent(this._flags.indentation_level, this._flags.alignment)) { - this._flags.line_indent_level = this._flags.indentation_level; - } - } -}; - -Beautifier.prototype.print_token = function(current_token) { - if (this._output.raw) { - this._output.add_raw_token(current_token); - return; - } - - if (this._options.comma_first && current_token.previous && current_token.previous.type === TOKEN.COMMA && - this._output.just_added_newline()) { - if (this._output.previous_line.last() === ',') { - var popped = this._output.previous_line.pop(); - // if the comma was already at the start of the line, - // pull back onto that line and reprint the indentation - if (this._output.previous_line.is_empty()) { - this._output.previous_line.push(popped); - this._output.trim(true); - this._output.current_line.pop(); - this._output.trim(); - } - - // add the comma in front of the next token - this.print_token_line_indentation(current_token); - this._output.add_token(','); - this._output.space_before_token = true; - } - } - - this.print_token_line_indentation(current_token); - this._output.non_breaking_space = true; - this._output.add_token(current_token.text); - if (this._output.previous_token_wrapped) { - this._flags.multiline_frame = true; - } -}; - -Beautifier.prototype.indent = function() { - this._flags.indentation_level += 1; - this._output.set_indent(this._flags.indentation_level, this._flags.alignment); -}; - -Beautifier.prototype.deindent = function() { - if (this._flags.indentation_level > 0 && - ((!this._flags.parent) || this._flags.indentation_level > this._flags.parent.indentation_level)) { - this._flags.indentation_level -= 1; - this._output.set_indent(this._flags.indentation_level, this._flags.alignment); - } -}; - -Beautifier.prototype.set_mode = function(mode) { - if (this._flags) { - this._flag_store.push(this._flags); - this._previous_flags = this._flags; - } else { - this._previous_flags = this.create_flags(null, mode); - } - - this._flags = this.create_flags(this._previous_flags, mode); - this._output.set_indent(this._flags.indentation_level, this._flags.alignment); -}; - - -Beautifier.prototype.restore_mode = function() { - if (this._flag_store.length > 0) { - this._previous_flags = this._flags; - this._flags = this._flag_store.pop(); - if (this._previous_flags.mode === MODE.Statement) { - remove_redundant_indentation(this._output, this._previous_flags); - } - this._output.set_indent(this._flags.indentation_level, this._flags.alignment); - } -}; - -Beautifier.prototype.start_of_object_property = function() { - return this._flags.parent.mode === MODE.ObjectLiteral && this._flags.mode === MODE.Statement && ( - (this._flags.last_token.text === ':' && this._flags.ternary_depth === 0) || (reserved_array(this._flags.last_token, ['get', 'set']))); -}; - -Beautifier.prototype.start_of_statement = function(current_token) { - var start = false; - start = start || reserved_array(this._flags.last_token, ['var', 'let', 'const']) && current_token.type === TOKEN.WORD; - start = start || reserved_word(this._flags.last_token, 'do'); - start = start || (!(this._flags.parent.mode === MODE.ObjectLiteral && this._flags.mode === MODE.Statement)) && reserved_array(this._flags.last_token, newline_restricted_tokens) && !current_token.newlines; - start = start || reserved_word(this._flags.last_token, 'else') && - !(reserved_word(current_token, 'if') && !current_token.comments_before); - start = start || (this._flags.last_token.type === TOKEN.END_EXPR && (this._previous_flags.mode === MODE.ForInitializer || this._previous_flags.mode === MODE.Conditional)); - start = start || (this._flags.last_token.type === TOKEN.WORD && this._flags.mode === MODE.BlockStatement && - !this._flags.in_case && - !(current_token.text === '--' || current_token.text === '++') && - this._last_last_text !== 'function' && - current_token.type !== TOKEN.WORD && current_token.type !== TOKEN.RESERVED); - start = start || (this._flags.mode === MODE.ObjectLiteral && ( - (this._flags.last_token.text === ':' && this._flags.ternary_depth === 0) || reserved_array(this._flags.last_token, ['get', 'set']))); - - if (start) { - this.set_mode(MODE.Statement); - this.indent(); - - this.handle_whitespace_and_comments(current_token, true); - - // Issue #276: - // If starting a new statement with [if, for, while, do], push to a new line. - // if (a) if (b) if(c) d(); else e(); else f(); - if (!this.start_of_object_property()) { - this.allow_wrap_or_preserved_newline(current_token, - reserved_array(current_token, ['do', 'for', 'if', 'while'])); - } - return true; - } - return false; -}; - -Beautifier.prototype.handle_start_expr = function(current_token) { - // The conditional starts the statement if appropriate. - if (!this.start_of_statement(current_token)) { - this.handle_whitespace_and_comments(current_token); - } - - var next_mode = MODE.Expression; - if (current_token.text === '[') { - - if (this._flags.last_token.type === TOKEN.WORD || this._flags.last_token.text === ')') { - // this is array index specifier, break immediately - // a[x], fn()[x] - if (reserved_array(this._flags.last_token, line_starters)) { - this._output.space_before_token = true; - } - this.print_token(current_token); - this.set_mode(next_mode); - this.indent(); - if (this._options.space_in_paren) { - this._output.space_before_token = true; - } - return; - } - - next_mode = MODE.ArrayLiteral; - if (is_array(this._flags.mode)) { - if (this._flags.last_token.text === '[' || - (this._flags.last_token.text === ',' && (this._last_last_text === ']' || this._last_last_text === '}'))) { - // ], [ goes to new line - // }, [ goes to new line - if (!this._options.keep_array_indentation) { - this.print_newline(); - } - } - } - - if (!in_array(this._flags.last_token.type, [TOKEN.START_EXPR, TOKEN.END_EXPR, TOKEN.WORD, TOKEN.OPERATOR, TOKEN.DOT])) { - this._output.space_before_token = true; - } - } else { - if (this._flags.last_token.type === TOKEN.RESERVED) { - if (this._flags.last_token.text === 'for') { - this._output.space_before_token = this._options.space_before_conditional; - next_mode = MODE.ForInitializer; - } else if (in_array(this._flags.last_token.text, ['if', 'while', 'switch'])) { - this._output.space_before_token = this._options.space_before_conditional; - next_mode = MODE.Conditional; - } else if (in_array(this._flags.last_word, ['await', 'async'])) { - // Should be a space between await and an IIFE, or async and an arrow function - this._output.space_before_token = true; - } else if (this._flags.last_token.text === 'import' && current_token.whitespace_before === '') { - this._output.space_before_token = false; - } else if (in_array(this._flags.last_token.text, line_starters) || this._flags.last_token.text === 'catch') { - this._output.space_before_token = true; - } - } else if (this._flags.last_token.type === TOKEN.EQUALS || this._flags.last_token.type === TOKEN.OPERATOR) { - // Support of this kind of newline preservation. - // a = (b && - // (c || d)); - if (!this.start_of_object_property()) { - this.allow_wrap_or_preserved_newline(current_token); - } - } else if (this._flags.last_token.type === TOKEN.WORD) { - this._output.space_before_token = false; - - // function name() vs function name () - // function* name() vs function* name () - // async name() vs async name () - // In ES6, you can also define the method properties of an object - // var obj = {a: function() {}} - // It can be abbreviated - // var obj = {a() {}} - // var obj = { a() {}} vs var obj = { a () {}} - // var obj = { * a() {}} vs var obj = { * a () {}} - var peek_back_two = this._tokens.peek(-3); - if (this._options.space_after_named_function && peek_back_two) { - // peek starts at next character so -1 is current token - var peek_back_three = this._tokens.peek(-4); - if (reserved_array(peek_back_two, ['async', 'function']) || - (peek_back_two.text === '*' && reserved_array(peek_back_three, ['async', 'function']))) { - this._output.space_before_token = true; - } else if (this._flags.mode === MODE.ObjectLiteral) { - if ((peek_back_two.text === '{' || peek_back_two.text === ',') || - (peek_back_two.text === '*' && (peek_back_three.text === '{' || peek_back_three.text === ','))) { - this._output.space_before_token = true; - } - } else if (this._flags.parent && this._flags.parent.class_start_block) { - this._output.space_before_token = true; - } - } - } else { - // Support preserving wrapped arrow function expressions - // a.b('c', - // () => d.e - // ) - this.allow_wrap_or_preserved_newline(current_token); - } - - // function() vs function () - // yield*() vs yield* () - // function*() vs function* () - if ((this._flags.last_token.type === TOKEN.RESERVED && (this._flags.last_word === 'function' || this._flags.last_word === 'typeof')) || - (this._flags.last_token.text === '*' && - (in_array(this._last_last_text, ['function', 'yield']) || - (this._flags.mode === MODE.ObjectLiteral && in_array(this._last_last_text, ['{', ',']))))) { - this._output.space_before_token = this._options.space_after_anon_function; - } - } - - if (this._flags.last_token.text === ';' || this._flags.last_token.type === TOKEN.START_BLOCK) { - this.print_newline(); - } else if (this._flags.last_token.type === TOKEN.END_EXPR || this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.END_BLOCK || this._flags.last_token.text === '.' || this._flags.last_token.type === TOKEN.COMMA) { - // do nothing on (( and )( and ][ and ]( and .( - // TODO: Consider whether forcing this is required. Review failing tests when removed. - this.allow_wrap_or_preserved_newline(current_token, current_token.newlines); - } - - this.print_token(current_token); - this.set_mode(next_mode); - if (this._options.space_in_paren) { - this._output.space_before_token = true; - } - - // In all cases, if we newline while inside an expression it should be indented. - this.indent(); -}; - -Beautifier.prototype.handle_end_expr = function(current_token) { - // statements inside expressions are not valid syntax, but... - // statements must all be closed when their container closes - while (this._flags.mode === MODE.Statement) { - this.restore_mode(); - } - - this.handle_whitespace_and_comments(current_token); - - if (this._flags.multiline_frame) { - this.allow_wrap_or_preserved_newline(current_token, - current_token.text === ']' && is_array(this._flags.mode) && !this._options.keep_array_indentation); - } - - if (this._options.space_in_paren) { - if (this._flags.last_token.type === TOKEN.START_EXPR && !this._options.space_in_empty_paren) { - // () [] no inner space in empty parens like these, ever, ref #320 - this._output.trim(); - this._output.space_before_token = false; - } else { - this._output.space_before_token = true; - } - } - this.deindent(); - this.print_token(current_token); - this.restore_mode(); - - remove_redundant_indentation(this._output, this._previous_flags); - - // do {} while () // no statement required after - if (this._flags.do_while && this._previous_flags.mode === MODE.Conditional) { - this._previous_flags.mode = MODE.Expression; - this._flags.do_block = false; - this._flags.do_while = false; - - } -}; - -Beautifier.prototype.handle_start_block = function(current_token) { - this.handle_whitespace_and_comments(current_token); - - // Check if this is should be treated as a ObjectLiteral - var next_token = this._tokens.peek(); - var second_token = this._tokens.peek(1); - if (this._flags.last_word === 'switch' && this._flags.last_token.type === TOKEN.END_EXPR) { - this.set_mode(MODE.BlockStatement); - this._flags.in_case_statement = true; - } else if (this._flags.case_body) { - this.set_mode(MODE.BlockStatement); - } else if (second_token && ( - (in_array(second_token.text, [':', ',']) && in_array(next_token.type, [TOKEN.STRING, TOKEN.WORD, TOKEN.RESERVED])) || - (in_array(next_token.text, ['get', 'set', '...']) && in_array(second_token.type, [TOKEN.WORD, TOKEN.RESERVED])) - )) { - // We don't support TypeScript,but we didn't break it for a very long time. - // We'll try to keep not breaking it. - if (in_array(this._last_last_text, ['class', 'interface']) && !in_array(second_token.text, [':', ','])) { - this.set_mode(MODE.BlockStatement); - } else { - this.set_mode(MODE.ObjectLiteral); - } - } else if (this._flags.last_token.type === TOKEN.OPERATOR && this._flags.last_token.text === '=>') { - // arrow function: (param1, paramN) => { statements } - this.set_mode(MODE.BlockStatement); - } else if (in_array(this._flags.last_token.type, [TOKEN.EQUALS, TOKEN.START_EXPR, TOKEN.COMMA, TOKEN.OPERATOR]) || - reserved_array(this._flags.last_token, ['return', 'throw', 'import', 'default']) - ) { - // Detecting shorthand function syntax is difficult by scanning forward, - // so check the surrounding context. - // If the block is being returned, imported, export default, passed as arg, - // assigned with = or assigned in a nested object, treat as an ObjectLiteral. - this.set_mode(MODE.ObjectLiteral); - } else { - this.set_mode(MODE.BlockStatement); - } - - if (this._flags.last_token) { - if (reserved_array(this._flags.last_token.previous, ['class', 'extends'])) { - this._flags.class_start_block = true; - } - } - - var empty_braces = !next_token.comments_before && next_token.text === '}'; - var empty_anonymous_function = empty_braces && this._flags.last_word === 'function' && - this._flags.last_token.type === TOKEN.END_EXPR; - - if (this._options.brace_preserve_inline) // check for inline, set inline_frame if so - { - // search forward for a newline wanted inside this block - var index = 0; - var check_token = null; - this._flags.inline_frame = true; - do { - index += 1; - check_token = this._tokens.peek(index - 1); - if (check_token.newlines) { - this._flags.inline_frame = false; - break; - } - } while (check_token.type !== TOKEN.EOF && - !(check_token.type === TOKEN.END_BLOCK && check_token.opened === current_token)); - } - - if ((this._options.brace_style === "expand" || - (this._options.brace_style === "none" && current_token.newlines)) && - !this._flags.inline_frame) { - if (this._flags.last_token.type !== TOKEN.OPERATOR && - (empty_anonymous_function || - this._flags.last_token.type === TOKEN.EQUALS || - (reserved_array(this._flags.last_token, special_words) && this._flags.last_token.text !== 'else'))) { - this._output.space_before_token = true; - } else { - this.print_newline(false, true); - } - } else { // collapse || inline_frame - if (is_array(this._previous_flags.mode) && (this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.COMMA)) { - if (this._flags.last_token.type === TOKEN.COMMA || this._options.space_in_paren) { - this._output.space_before_token = true; - } - - if (this._flags.last_token.type === TOKEN.COMMA || (this._flags.last_token.type === TOKEN.START_EXPR && this._flags.inline_frame)) { - this.allow_wrap_or_preserved_newline(current_token); - this._previous_flags.multiline_frame = this._previous_flags.multiline_frame || this._flags.multiline_frame; - this._flags.multiline_frame = false; - } - } - if (this._flags.last_token.type !== TOKEN.OPERATOR && this._flags.last_token.type !== TOKEN.START_EXPR) { - if (in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.SEMICOLON]) && !this._flags.inline_frame) { - this.print_newline(); - } else { - this._output.space_before_token = true; - } - } - } - this.print_token(current_token); - this.indent(); - - // Except for specific cases, open braces are followed by a new line. - if (!empty_braces && !(this._options.brace_preserve_inline && this._flags.inline_frame)) { - this.print_newline(); - } -}; - -Beautifier.prototype.handle_end_block = function(current_token) { - // statements must all be closed when their container closes - this.handle_whitespace_and_comments(current_token); - - while (this._flags.mode === MODE.Statement) { - this.restore_mode(); - } - - var empty_braces = this._flags.last_token.type === TOKEN.START_BLOCK; - - if (this._flags.inline_frame && !empty_braces) { // try inline_frame (only set if this._options.braces-preserve-inline) first - this._output.space_before_token = true; - } else if (this._options.brace_style === "expand") { - if (!empty_braces) { - this.print_newline(); - } - } else { - // skip {} - if (!empty_braces) { - if (is_array(this._flags.mode) && this._options.keep_array_indentation) { - // we REALLY need a newline here, but newliner would skip that - this._options.keep_array_indentation = false; - this.print_newline(); - this._options.keep_array_indentation = true; - - } else { - this.print_newline(); - } - } - } - this.restore_mode(); - this.print_token(current_token); -}; - -Beautifier.prototype.handle_word = function(current_token) { - if (current_token.type === TOKEN.RESERVED) { - if (in_array(current_token.text, ['set', 'get']) && this._flags.mode !== MODE.ObjectLiteral) { - current_token.type = TOKEN.WORD; - } else if (current_token.text === 'import' && in_array(this._tokens.peek().text, ['(', '.'])) { - current_token.type = TOKEN.WORD; - } else if (in_array(current_token.text, ['as', 'from']) && !this._flags.import_block) { - current_token.type = TOKEN.WORD; - } else if (this._flags.mode === MODE.ObjectLiteral) { - var next_token = this._tokens.peek(); - if (next_token.text === ':') { - current_token.type = TOKEN.WORD; - } - } - } - - if (this.start_of_statement(current_token)) { - // The conditional starts the statement if appropriate. - if (reserved_array(this._flags.last_token, ['var', 'let', 'const']) && current_token.type === TOKEN.WORD) { - this._flags.declaration_statement = true; - } - } else if (current_token.newlines && !is_expression(this._flags.mode) && - (this._flags.last_token.type !== TOKEN.OPERATOR || (this._flags.last_token.text === '--' || this._flags.last_token.text === '++')) && - this._flags.last_token.type !== TOKEN.EQUALS && - (this._options.preserve_newlines || !reserved_array(this._flags.last_token, ['var', 'let', 'const', 'set', 'get']))) { - this.handle_whitespace_and_comments(current_token); - this.print_newline(); - } else { - this.handle_whitespace_and_comments(current_token); - } - - if (this._flags.do_block && !this._flags.do_while) { - if (reserved_word(current_token, 'while')) { - // do {} ## while () - this._output.space_before_token = true; - this.print_token(current_token); - this._output.space_before_token = true; - this._flags.do_while = true; - return; - } else { - // do {} should always have while as the next word. - // if we don't see the expected while, recover - this.print_newline(); - this._flags.do_block = false; - } - } - - // if may be followed by else, or not - // Bare/inline ifs are tricky - // Need to unwind the modes correctly: if (a) if (b) c(); else d(); else e(); - if (this._flags.if_block) { - if (!this._flags.else_block && reserved_word(current_token, 'else')) { - this._flags.else_block = true; - } else { - while (this._flags.mode === MODE.Statement) { - this.restore_mode(); - } - this._flags.if_block = false; - this._flags.else_block = false; - } - } - - if (this._flags.in_case_statement && reserved_array(current_token, ['case', 'default'])) { - this.print_newline(); - if (!this._flags.case_block && (this._flags.case_body || this._options.jslint_happy)) { - // switch cases following one another - this.deindent(); - } - this._flags.case_body = false; - - this.print_token(current_token); - this._flags.in_case = true; - return; - } - - if (this._flags.last_token.type === TOKEN.COMMA || this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.EQUALS || this._flags.last_token.type === TOKEN.OPERATOR) { - if (!this.start_of_object_property() && !( - // start of object property is different for numeric values with +/- prefix operators - in_array(this._flags.last_token.text, ['+', '-']) && this._last_last_text === ':' && this._flags.parent.mode === MODE.ObjectLiteral)) { - this.allow_wrap_or_preserved_newline(current_token); - } - } - - if (reserved_word(current_token, 'function')) { - if (in_array(this._flags.last_token.text, ['}', ';']) || - (this._output.just_added_newline() && !(in_array(this._flags.last_token.text, ['(', '[', '{', ':', '=', ',']) || this._flags.last_token.type === TOKEN.OPERATOR))) { - // make sure there is a nice clean space of at least one blank line - // before a new function definition - if (!this._output.just_added_blankline() && !current_token.comments_before) { - this.print_newline(); - this.print_newline(true); - } - } - if (this._flags.last_token.type === TOKEN.RESERVED || this._flags.last_token.type === TOKEN.WORD) { - if (reserved_array(this._flags.last_token, ['get', 'set', 'new', 'export']) || - reserved_array(this._flags.last_token, newline_restricted_tokens)) { - this._output.space_before_token = true; - } else if (reserved_word(this._flags.last_token, 'default') && this._last_last_text === 'export') { - this._output.space_before_token = true; - } else if (this._flags.last_token.text === 'declare') { - // accomodates Typescript declare function formatting - this._output.space_before_token = true; - } else { - this.print_newline(); - } - } else if (this._flags.last_token.type === TOKEN.OPERATOR || this._flags.last_token.text === '=') { - // foo = function - this._output.space_before_token = true; - } else if (!this._flags.multiline_frame && (is_expression(this._flags.mode) || is_array(this._flags.mode))) { - // (function - } else { - this.print_newline(); - } - - this.print_token(current_token); - this._flags.last_word = current_token.text; - return; - } - - var prefix = 'NONE'; - - if (this._flags.last_token.type === TOKEN.END_BLOCK) { - - if (this._previous_flags.inline_frame) { - prefix = 'SPACE'; - } else if (!reserved_array(current_token, ['else', 'catch', 'finally', 'from'])) { - prefix = 'NEWLINE'; - } else { - if (this._options.brace_style === "expand" || - this._options.brace_style === "end-expand" || - (this._options.brace_style === "none" && current_token.newlines)) { - prefix = 'NEWLINE'; - } else { - prefix = 'SPACE'; - this._output.space_before_token = true; - } - } - } else if (this._flags.last_token.type === TOKEN.SEMICOLON && this._flags.mode === MODE.BlockStatement) { - // TODO: Should this be for STATEMENT as well? - prefix = 'NEWLINE'; - } else if (this._flags.last_token.type === TOKEN.SEMICOLON && is_expression(this._flags.mode)) { - prefix = 'SPACE'; - } else if (this._flags.last_token.type === TOKEN.STRING) { - prefix = 'NEWLINE'; - } else if (this._flags.last_token.type === TOKEN.RESERVED || this._flags.last_token.type === TOKEN.WORD || - (this._flags.last_token.text === '*' && - (in_array(this._last_last_text, ['function', 'yield']) || - (this._flags.mode === MODE.ObjectLiteral && in_array(this._last_last_text, ['{', ',']))))) { - prefix = 'SPACE'; - } else if (this._flags.last_token.type === TOKEN.START_BLOCK) { - if (this._flags.inline_frame) { - prefix = 'SPACE'; - } else { - prefix = 'NEWLINE'; - } - } else if (this._flags.last_token.type === TOKEN.END_EXPR) { - this._output.space_before_token = true; - prefix = 'NEWLINE'; - } - - if (reserved_array(current_token, line_starters) && this._flags.last_token.text !== ')') { - if (this._flags.inline_frame || this._flags.last_token.text === 'else' || this._flags.last_token.text === 'export') { - prefix = 'SPACE'; - } else { - prefix = 'NEWLINE'; - } - - } - - if (reserved_array(current_token, ['else', 'catch', 'finally'])) { - if ((!(this._flags.last_token.type === TOKEN.END_BLOCK && this._previous_flags.mode === MODE.BlockStatement) || - this._options.brace_style === "expand" || - this._options.brace_style === "end-expand" || - (this._options.brace_style === "none" && current_token.newlines)) && - !this._flags.inline_frame) { - this.print_newline(); - } else { - this._output.trim(true); - var line = this._output.current_line; - // If we trimmed and there's something other than a close block before us - // put a newline back in. Handles '} // comment' scenario. - if (line.last() !== '}') { - this.print_newline(); - } - this._output.space_before_token = true; - } - } else if (prefix === 'NEWLINE') { - if (reserved_array(this._flags.last_token, special_words)) { - // no newline between 'return nnn' - this._output.space_before_token = true; - } else if (this._flags.last_token.text === 'declare' && reserved_array(current_token, ['var', 'let', 'const'])) { - // accomodates Typescript declare formatting - this._output.space_before_token = true; - } else if (this._flags.last_token.type !== TOKEN.END_EXPR) { - if ((this._flags.last_token.type !== TOKEN.START_EXPR || !reserved_array(current_token, ['var', 'let', 'const'])) && this._flags.last_token.text !== ':') { - // no need to force newline on 'var': for (var x = 0...) - if (reserved_word(current_token, 'if') && reserved_word(current_token.previous, 'else')) { - // no newline for } else if { - this._output.space_before_token = true; - } else { - this.print_newline(); - } - } - } else if (reserved_array(current_token, line_starters) && this._flags.last_token.text !== ')') { - this.print_newline(); - } - } else if (this._flags.multiline_frame && is_array(this._flags.mode) && this._flags.last_token.text === ',' && this._last_last_text === '}') { - this.print_newline(); // }, in lists get a newline treatment - } else if (prefix === 'SPACE') { - this._output.space_before_token = true; - } - if (current_token.previous && (current_token.previous.type === TOKEN.WORD || current_token.previous.type === TOKEN.RESERVED)) { - this._output.space_before_token = true; - } - this.print_token(current_token); - this._flags.last_word = current_token.text; - - if (current_token.type === TOKEN.RESERVED) { - if (current_token.text === 'do') { - this._flags.do_block = true; - } else if (current_token.text === 'if') { - this._flags.if_block = true; - } else if (current_token.text === 'import') { - this._flags.import_block = true; - } else if (this._flags.import_block && reserved_word(current_token, 'from')) { - this._flags.import_block = false; - } - } -}; - -Beautifier.prototype.handle_semicolon = function(current_token) { - if (this.start_of_statement(current_token)) { - // The conditional starts the statement if appropriate. - // Semicolon can be the start (and end) of a statement - this._output.space_before_token = false; - } else { - this.handle_whitespace_and_comments(current_token); - } - - var next_token = this._tokens.peek(); - while (this._flags.mode === MODE.Statement && - !(this._flags.if_block && reserved_word(next_token, 'else')) && - !this._flags.do_block) { - this.restore_mode(); - } - - // hacky but effective for the moment - if (this._flags.import_block) { - this._flags.import_block = false; - } - this.print_token(current_token); -}; - -Beautifier.prototype.handle_string = function(current_token) { - if (current_token.text.startsWith("`") && current_token.newlines === 0 && current_token.whitespace_before === '' && (current_token.previous.text === ')' || this._flags.last_token.type === TOKEN.WORD)) { - //Conditional for detectign backtick strings - } else if (this.start_of_statement(current_token)) { - // The conditional starts the statement if appropriate. - // One difference - strings want at least a space before - this._output.space_before_token = true; - } else { - this.handle_whitespace_and_comments(current_token); - if (this._flags.last_token.type === TOKEN.RESERVED || this._flags.last_token.type === TOKEN.WORD || this._flags.inline_frame) { - this._output.space_before_token = true; - } else if (this._flags.last_token.type === TOKEN.COMMA || this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.EQUALS || this._flags.last_token.type === TOKEN.OPERATOR) { - if (!this.start_of_object_property()) { - this.allow_wrap_or_preserved_newline(current_token); - } - } else if ((current_token.text.startsWith("`") && this._flags.last_token.type === TOKEN.END_EXPR && (current_token.previous.text === ']' || current_token.previous.text === ')') && current_token.newlines === 0)) { - this._output.space_before_token = true; - } else { - this.print_newline(); - } - } - this.print_token(current_token); -}; - -Beautifier.prototype.handle_equals = function(current_token) { - if (this.start_of_statement(current_token)) { - // The conditional starts the statement if appropriate. - } else { - this.handle_whitespace_and_comments(current_token); - } - - if (this._flags.declaration_statement) { - // just got an '=' in a var-line, different formatting/line-breaking, etc will now be done - this._flags.declaration_assignment = true; - } - this._output.space_before_token = true; - this.print_token(current_token); - this._output.space_before_token = true; -}; - -Beautifier.prototype.handle_comma = function(current_token) { - this.handle_whitespace_and_comments(current_token, true); - - this.print_token(current_token); - this._output.space_before_token = true; - if (this._flags.declaration_statement) { - if (is_expression(this._flags.parent.mode)) { - // do not break on comma, for(var a = 1, b = 2) - this._flags.declaration_assignment = false; - } - - if (this._flags.declaration_assignment) { - this._flags.declaration_assignment = false; - this.print_newline(false, true); - } else if (this._options.comma_first) { - // for comma-first, we want to allow a newline before the comma - // to turn into a newline after the comma, which we will fixup later - this.allow_wrap_or_preserved_newline(current_token); - } - } else if (this._flags.mode === MODE.ObjectLiteral || - (this._flags.mode === MODE.Statement && this._flags.parent.mode === MODE.ObjectLiteral)) { - if (this._flags.mode === MODE.Statement) { - this.restore_mode(); - } - - if (!this._flags.inline_frame) { - this.print_newline(); - } - } else if (this._options.comma_first) { - // EXPR or DO_BLOCK - // for comma-first, we want to allow a newline before the comma - // to turn into a newline after the comma, which we will fixup later - this.allow_wrap_or_preserved_newline(current_token); - } -}; - -Beautifier.prototype.handle_operator = function(current_token) { - var isGeneratorAsterisk = current_token.text === '*' && - (reserved_array(this._flags.last_token, ['function', 'yield']) || - (in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.COMMA, TOKEN.END_BLOCK, TOKEN.SEMICOLON])) - ); - var isUnary = in_array(current_token.text, ['-', '+']) && ( - in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.START_EXPR, TOKEN.EQUALS, TOKEN.OPERATOR]) || - in_array(this._flags.last_token.text, line_starters) || - this._flags.last_token.text === ',' - ); - - if (this.start_of_statement(current_token)) { - // The conditional starts the statement if appropriate. - } else { - var preserve_statement_flags = !isGeneratorAsterisk; - this.handle_whitespace_and_comments(current_token, preserve_statement_flags); - } - - // hack for actionscript's import .*; - if (current_token.text === '*' && this._flags.last_token.type === TOKEN.DOT) { - this.print_token(current_token); - return; - } - - if (current_token.text === '::') { - // no spaces around exotic namespacing syntax operator - this.print_token(current_token); - return; - } - - if (in_array(current_token.text, ['-', '+']) && this.start_of_object_property()) { - // numeric value with +/- symbol in front as a property - this.print_token(current_token); - return; - } - - // Allow line wrapping between operators when operator_position is - // set to before or preserve - if (this._flags.last_token.type === TOKEN.OPERATOR && in_array(this._options.operator_position, OPERATOR_POSITION_BEFORE_OR_PRESERVE)) { - this.allow_wrap_or_preserved_newline(current_token); - } - - if (current_token.text === ':' && this._flags.in_case) { - this.print_token(current_token); - - this._flags.in_case = false; - this._flags.case_body = true; - if (this._tokens.peek().type !== TOKEN.START_BLOCK) { - this.indent(); - this.print_newline(); - this._flags.case_block = false; - } else { - this._flags.case_block = true; - this._output.space_before_token = true; - } - return; - } - - var space_before = true; - var space_after = true; - var in_ternary = false; - if (current_token.text === ':') { - if (this._flags.ternary_depth === 0) { - // Colon is invalid javascript outside of ternary and object, but do our best to guess what was meant. - space_before = false; - } else { - this._flags.ternary_depth -= 1; - in_ternary = true; - } - } else if (current_token.text === '?') { - this._flags.ternary_depth += 1; - } - - // let's handle the operator_position option prior to any conflicting logic - if (!isUnary && !isGeneratorAsterisk && this._options.preserve_newlines && in_array(current_token.text, positionable_operators)) { - var isColon = current_token.text === ':'; - var isTernaryColon = (isColon && in_ternary); - var isOtherColon = (isColon && !in_ternary); - - switch (this._options.operator_position) { - case OPERATOR_POSITION.before_newline: - // if the current token is : and it's not a ternary statement then we set space_before to false - this._output.space_before_token = !isOtherColon; - - this.print_token(current_token); - - if (!isColon || isTernaryColon) { - this.allow_wrap_or_preserved_newline(current_token); - } - - this._output.space_before_token = true; - return; - - case OPERATOR_POSITION.after_newline: - // if the current token is anything but colon, or (via deduction) it's a colon and in a ternary statement, - // then print a newline. - - this._output.space_before_token = true; - - if (!isColon || isTernaryColon) { - if (this._tokens.peek().newlines) { - this.print_newline(false, true); - } else { - this.allow_wrap_or_preserved_newline(current_token); - } - } else { - this._output.space_before_token = false; - } - - this.print_token(current_token); - - this._output.space_before_token = true; - return; - - case OPERATOR_POSITION.preserve_newline: - if (!isOtherColon) { - this.allow_wrap_or_preserved_newline(current_token); - } - - // if we just added a newline, or the current token is : and it's not a ternary statement, - // then we set space_before to false - space_before = !(this._output.just_added_newline() || isOtherColon); - - this._output.space_before_token = space_before; - this.print_token(current_token); - this._output.space_before_token = true; - return; - } - } - - if (isGeneratorAsterisk) { - this.allow_wrap_or_preserved_newline(current_token); - space_before = false; - var next_token = this._tokens.peek(); - space_after = next_token && in_array(next_token.type, [TOKEN.WORD, TOKEN.RESERVED]); - } else if (current_token.text === '...') { - this.allow_wrap_or_preserved_newline(current_token); - space_before = this._flags.last_token.type === TOKEN.START_BLOCK; - space_after = false; - } else if (in_array(current_token.text, ['--', '++', '!', '~']) || isUnary) { - // unary operators (and binary +/- pretending to be unary) special cases - if (this._flags.last_token.type === TOKEN.COMMA || this._flags.last_token.type === TOKEN.START_EXPR) { - this.allow_wrap_or_preserved_newline(current_token); - } - - space_before = false; - space_after = false; - - // http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1 - // if there is a newline between -- or ++ and anything else we should preserve it. - if (current_token.newlines && (current_token.text === '--' || current_token.text === '++' || current_token.text === '~')) { - var new_line_needed = reserved_array(this._flags.last_token, special_words) && current_token.newlines; - if (new_line_needed && (this._previous_flags.if_block || this._previous_flags.else_block)) { - this.restore_mode(); - } - this.print_newline(new_line_needed, true); - } - - if (this._flags.last_token.text === ';' && is_expression(this._flags.mode)) { - // for (;; ++i) - // ^^^ - space_before = true; - } - - if (this._flags.last_token.type === TOKEN.RESERVED) { - space_before = true; - } else if (this._flags.last_token.type === TOKEN.END_EXPR) { - space_before = !(this._flags.last_token.text === ']' && (current_token.text === '--' || current_token.text === '++')); - } else if (this._flags.last_token.type === TOKEN.OPERATOR) { - // a++ + ++b; - // a - -b - space_before = in_array(current_token.text, ['--', '-', '++', '+']) && in_array(this._flags.last_token.text, ['--', '-', '++', '+']); - // + and - are not unary when preceeded by -- or ++ operator - // a-- + b - // a * +b - // a - -b - if (in_array(current_token.text, ['+', '-']) && in_array(this._flags.last_token.text, ['--', '++'])) { - space_after = true; - } - } - - - if (((this._flags.mode === MODE.BlockStatement && !this._flags.inline_frame) || this._flags.mode === MODE.Statement) && - (this._flags.last_token.text === '{' || this._flags.last_token.text === ';')) { - // { foo; --i } - // foo(); --bar; - this.print_newline(); - } - } - - this._output.space_before_token = this._output.space_before_token || space_before; - this.print_token(current_token); - this._output.space_before_token = space_after; -}; - -Beautifier.prototype.handle_block_comment = function(current_token, preserve_statement_flags) { - if (this._output.raw) { - this._output.add_raw_token(current_token); - if (current_token.directives && current_token.directives.preserve === 'end') { - // If we're testing the raw output behavior, do not allow a directive to turn it off. - this._output.raw = this._options.test_output_raw; - } - return; - } - - if (current_token.directives) { - this.print_newline(false, preserve_statement_flags); - this.print_token(current_token); - if (current_token.directives.preserve === 'start') { - this._output.raw = true; - } - this.print_newline(false, true); - return; - } - - // inline block - if (!acorn.newline.test(current_token.text) && !current_token.newlines) { - this._output.space_before_token = true; - this.print_token(current_token); - this._output.space_before_token = true; - return; - } else { - this.print_block_commment(current_token, preserve_statement_flags); - } -}; - -Beautifier.prototype.print_block_commment = function(current_token, preserve_statement_flags) { - var lines = split_linebreaks(current_token.text); - var j; // iterator for this case - var javadoc = false; - var starless = false; - var lastIndent = current_token.whitespace_before; - var lastIndentLength = lastIndent.length; - - // block comment starts with a new line - this.print_newline(false, preserve_statement_flags); - - // first line always indented - this.print_token_line_indentation(current_token); - this._output.add_token(lines[0]); - this.print_newline(false, preserve_statement_flags); - - - if (lines.length > 1) { - lines = lines.slice(1); - javadoc = all_lines_start_with(lines, '*'); - starless = each_line_matches_indent(lines, lastIndent); - - if (javadoc) { - this._flags.alignment = 1; - } - - for (j = 0; j < lines.length; j++) { - if (javadoc) { - // javadoc: reformat and re-indent - this.print_token_line_indentation(current_token); - this._output.add_token(ltrim(lines[j])); - } else if (starless && lines[j]) { - // starless: re-indent non-empty content, avoiding trim - this.print_token_line_indentation(current_token); - this._output.add_token(lines[j].substring(lastIndentLength)); - } else { - // normal comments output raw - this._output.current_line.set_indent(-1); - this._output.add_token(lines[j]); - } - - // for comments on their own line or more than one line, make sure there's a new line after - this.print_newline(false, preserve_statement_flags); - } - - this._flags.alignment = 0; - } -}; - - -Beautifier.prototype.handle_comment = function(current_token, preserve_statement_flags) { - if (current_token.newlines) { - this.print_newline(false, preserve_statement_flags); - } else { - this._output.trim(true); - } - - this._output.space_before_token = true; - this.print_token(current_token); - this.print_newline(false, preserve_statement_flags); -}; - -Beautifier.prototype.handle_dot = function(current_token) { - if (this.start_of_statement(current_token)) { - // The conditional starts the statement if appropriate. - } else { - this.handle_whitespace_and_comments(current_token, true); - } - - if (this._flags.last_token.text.match('^[0-9]+$')) { - this._output.space_before_token = true; - } - - if (reserved_array(this._flags.last_token, special_words)) { - this._output.space_before_token = false; - } else { - // allow preserved newlines before dots in general - // force newlines on dots after close paren when break_chained - for bar().baz() - this.allow_wrap_or_preserved_newline(current_token, - this._flags.last_token.text === ')' && this._options.break_chained_methods); - } - - // Only unindent chained method dot if this dot starts a new line. - // Otherwise the automatic extra indentation removal will handle the over indent - if (this._options.unindent_chained_methods && this._output.just_added_newline()) { - this.deindent(); - } - - this.print_token(current_token); -}; - -Beautifier.prototype.handle_unknown = function(current_token, preserve_statement_flags) { - this.print_token(current_token); - - if (current_token.text[current_token.text.length - 1] === '\n') { - this.print_newline(false, preserve_statement_flags); - } -}; - -Beautifier.prototype.handle_eof = function(current_token) { - // Unwind any open statements - while (this._flags.mode === MODE.Statement) { - this.restore_mode(); - } - this.handle_whitespace_and_comments(current_token); -}; - -module.exports.Beautifier = Beautifier; - - -/***/ }), -/* 2 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function OutputLine(parent) { - this.__parent = parent; - this.__character_count = 0; - // use indent_count as a marker for this.__lines that have preserved indentation - this.__indent_count = -1; - this.__alignment_count = 0; - this.__wrap_point_index = 0; - this.__wrap_point_character_count = 0; - this.__wrap_point_indent_count = -1; - this.__wrap_point_alignment_count = 0; - - this.__items = []; -} - -OutputLine.prototype.clone_empty = function() { - var line = new OutputLine(this.__parent); - line.set_indent(this.__indent_count, this.__alignment_count); - return line; -}; - -OutputLine.prototype.item = function(index) { - if (index < 0) { - return this.__items[this.__items.length + index]; - } else { - return this.__items[index]; - } -}; - -OutputLine.prototype.has_match = function(pattern) { - for (var lastCheckedOutput = this.__items.length - 1; lastCheckedOutput >= 0; lastCheckedOutput--) { - if (this.__items[lastCheckedOutput].match(pattern)) { - return true; - } - } - return false; -}; - -OutputLine.prototype.set_indent = function(indent, alignment) { - if (this.is_empty()) { - this.__indent_count = indent || 0; - this.__alignment_count = alignment || 0; - this.__character_count = this.__parent.get_indent_size(this.__indent_count, this.__alignment_count); - } -}; - -OutputLine.prototype._set_wrap_point = function() { - if (this.__parent.wrap_line_length) { - this.__wrap_point_index = this.__items.length; - this.__wrap_point_character_count = this.__character_count; - this.__wrap_point_indent_count = this.__parent.next_line.__indent_count; - this.__wrap_point_alignment_count = this.__parent.next_line.__alignment_count; - } -}; - -OutputLine.prototype._should_wrap = function() { - return this.__wrap_point_index && - this.__character_count > this.__parent.wrap_line_length && - this.__wrap_point_character_count > this.__parent.next_line.__character_count; -}; - -OutputLine.prototype._allow_wrap = function() { - if (this._should_wrap()) { - this.__parent.add_new_line(); - var next = this.__parent.current_line; - next.set_indent(this.__wrap_point_indent_count, this.__wrap_point_alignment_count); - next.__items = this.__items.slice(this.__wrap_point_index); - this.__items = this.__items.slice(0, this.__wrap_point_index); - - next.__character_count += this.__character_count - this.__wrap_point_character_count; - this.__character_count = this.__wrap_point_character_count; - - if (next.__items[0] === " ") { - next.__items.splice(0, 1); - next.__character_count -= 1; - } - return true; - } - return false; -}; - -OutputLine.prototype.is_empty = function() { - return this.__items.length === 0; -}; - -OutputLine.prototype.last = function() { - if (!this.is_empty()) { - return this.__items[this.__items.length - 1]; - } else { - return null; - } -}; - -OutputLine.prototype.push = function(item) { - this.__items.push(item); - var last_newline_index = item.lastIndexOf('\n'); - if (last_newline_index !== -1) { - this.__character_count = item.length - last_newline_index; - } else { - this.__character_count += item.length; - } -}; - -OutputLine.prototype.pop = function() { - var item = null; - if (!this.is_empty()) { - item = this.__items.pop(); - this.__character_count -= item.length; - } - return item; -}; - - -OutputLine.prototype._remove_indent = function() { - if (this.__indent_count > 0) { - this.__indent_count -= 1; - this.__character_count -= this.__parent.indent_size; - } -}; - -OutputLine.prototype._remove_wrap_indent = function() { - if (this.__wrap_point_indent_count > 0) { - this.__wrap_point_indent_count -= 1; - } -}; -OutputLine.prototype.trim = function() { - while (this.last() === ' ') { - this.__items.pop(); - this.__character_count -= 1; - } -}; - -OutputLine.prototype.toString = function() { - var result = ''; - if (this.is_empty()) { - if (this.__parent.indent_empty_lines) { - result = this.__parent.get_indent_string(this.__indent_count); - } - } else { - result = this.__parent.get_indent_string(this.__indent_count, this.__alignment_count); - result += this.__items.join(''); - } - return result; -}; - -function IndentStringCache(options, baseIndentString) { - this.__cache = ['']; - this.__indent_size = options.indent_size; - this.__indent_string = options.indent_char; - if (!options.indent_with_tabs) { - this.__indent_string = new Array(options.indent_size + 1).join(options.indent_char); - } - - // Set to null to continue support for auto detection of base indent - baseIndentString = baseIndentString || ''; - if (options.indent_level > 0) { - baseIndentString = new Array(options.indent_level + 1).join(this.__indent_string); - } - - this.__base_string = baseIndentString; - this.__base_string_length = baseIndentString.length; -} - -IndentStringCache.prototype.get_indent_size = function(indent, column) { - var result = this.__base_string_length; - column = column || 0; - if (indent < 0) { - result = 0; - } - result += indent * this.__indent_size; - result += column; - return result; -}; - -IndentStringCache.prototype.get_indent_string = function(indent_level, column) { - var result = this.__base_string; - column = column || 0; - if (indent_level < 0) { - indent_level = 0; - result = ''; - } - column += indent_level * this.__indent_size; - this.__ensure_cache(column); - result += this.__cache[column]; - return result; -}; - -IndentStringCache.prototype.__ensure_cache = function(column) { - while (column >= this.__cache.length) { - this.__add_column(); - } -}; - -IndentStringCache.prototype.__add_column = function() { - var column = this.__cache.length; - var indent = 0; - var result = ''; - if (this.__indent_size && column >= this.__indent_size) { - indent = Math.floor(column / this.__indent_size); - column -= indent * this.__indent_size; - result = new Array(indent + 1).join(this.__indent_string); - } - if (column) { - result += new Array(column + 1).join(' '); - } - - this.__cache.push(result); -}; - -function Output(options, baseIndentString) { - this.__indent_cache = new IndentStringCache(options, baseIndentString); - this.raw = false; - this._end_with_newline = options.end_with_newline; - this.indent_size = options.indent_size; - this.wrap_line_length = options.wrap_line_length; - this.indent_empty_lines = options.indent_empty_lines; - this.__lines = []; - this.previous_line = null; - this.current_line = null; - this.next_line = new OutputLine(this); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = false; - // initialize - this.__add_outputline(); -} - -Output.prototype.__add_outputline = function() { - this.previous_line = this.current_line; - this.current_line = this.next_line.clone_empty(); - this.__lines.push(this.current_line); -}; - -Output.prototype.get_line_number = function() { - return this.__lines.length; -}; - -Output.prototype.get_indent_string = function(indent, column) { - return this.__indent_cache.get_indent_string(indent, column); -}; - -Output.prototype.get_indent_size = function(indent, column) { - return this.__indent_cache.get_indent_size(indent, column); -}; - -Output.prototype.is_empty = function() { - return !this.previous_line && this.current_line.is_empty(); -}; - -Output.prototype.add_new_line = function(force_newline) { - // never newline at the start of file - // otherwise, newline only if we didn't just add one or we're forced - if (this.is_empty() || - (!force_newline && this.just_added_newline())) { - return false; - } - - // if raw output is enabled, don't print additional newlines, - // but still return True as though you had - if (!this.raw) { - this.__add_outputline(); - } - return true; -}; - -Output.prototype.get_code = function(eol) { - this.trim(true); - - // handle some edge cases where the last tokens - // has text that ends with newline(s) - var last_item = this.current_line.pop(); - if (last_item) { - if (last_item[last_item.length - 1] === '\n') { - last_item = last_item.replace(/\n+$/g, ''); - } - this.current_line.push(last_item); - } - - if (this._end_with_newline) { - this.__add_outputline(); - } - - var sweet_code = this.__lines.join('\n'); - - if (eol !== '\n') { - sweet_code = sweet_code.replace(/[\n]/g, eol); - } - return sweet_code; -}; - -Output.prototype.set_wrap_point = function() { - this.current_line._set_wrap_point(); -}; - -Output.prototype.set_indent = function(indent, alignment) { - indent = indent || 0; - alignment = alignment || 0; - - // Next line stores alignment values - this.next_line.set_indent(indent, alignment); - - // Never indent your first output indent at the start of the file - if (this.__lines.length > 1) { - this.current_line.set_indent(indent, alignment); - return true; - } - - this.current_line.set_indent(); - return false; -}; - -Output.prototype.add_raw_token = function(token) { - for (var x = 0; x < token.newlines; x++) { - this.__add_outputline(); - } - this.current_line.set_indent(-1); - this.current_line.push(token.whitespace_before); - this.current_line.push(token.text); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = false; -}; - -Output.prototype.add_token = function(printable_token) { - this.__add_space_before_token(); - this.current_line.push(printable_token); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = this.current_line._allow_wrap(); -}; - -Output.prototype.__add_space_before_token = function() { - if (this.space_before_token && !this.just_added_newline()) { - if (!this.non_breaking_space) { - this.set_wrap_point(); - } - this.current_line.push(' '); - } -}; - -Output.prototype.remove_indent = function(index) { - var output_length = this.__lines.length; - while (index < output_length) { - this.__lines[index]._remove_indent(); - index++; - } - this.current_line._remove_wrap_indent(); -}; - -Output.prototype.trim = function(eat_newlines) { - eat_newlines = (eat_newlines === undefined) ? false : eat_newlines; - - this.current_line.trim(); - - while (eat_newlines && this.__lines.length > 1 && - this.current_line.is_empty()) { - this.__lines.pop(); - this.current_line = this.__lines[this.__lines.length - 1]; - this.current_line.trim(); - } - - this.previous_line = this.__lines.length > 1 ? - this.__lines[this.__lines.length - 2] : null; -}; - -Output.prototype.just_added_newline = function() { - return this.current_line.is_empty(); -}; - -Output.prototype.just_added_blankline = function() { - return this.is_empty() || - (this.current_line.is_empty() && this.previous_line.is_empty()); -}; - -Output.prototype.ensure_empty_line_above = function(starts_with, ends_with) { - var index = this.__lines.length - 2; - while (index >= 0) { - var potentialEmptyLine = this.__lines[index]; - if (potentialEmptyLine.is_empty()) { - break; - } else if (potentialEmptyLine.item(0).indexOf(starts_with) !== 0 && - potentialEmptyLine.item(-1) !== ends_with) { - this.__lines.splice(index + 1, 0, new OutputLine(this)); - this.previous_line = this.__lines[this.__lines.length - 2]; - break; - } - index--; - } -}; - -module.exports.Output = Output; - - -/***/ }), -/* 3 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Token(type, text, newlines, whitespace_before) { - this.type = type; - this.text = text; - - // comments_before are - // comments that have a new line before them - // and may or may not have a newline after - // this is a set of comments before - this.comments_before = null; /* inline comment*/ - - - // this.comments_after = new TokenStream(); // no new line before and newline after - this.newlines = newlines || 0; - this.whitespace_before = whitespace_before || ''; - this.parent = null; - this.next = null; - this.previous = null; - this.opened = null; - this.closed = null; - this.directives = null; -} - - -module.exports.Token = Token; - - -/***/ }), -/* 4 */ -/***/ (function(__unused_webpack_module, exports) { - -/* jshint node: true, curly: false */ -// Parts of this section of code is taken from acorn. -// -// Acorn was written by Marijn Haverbeke and released under an MIT -// license. The Unicode regexps (for identifiers and whitespace) were -// taken from [Esprima](http://esprima.org) by Ariya Hidayat. -// -// Git repositories for Acorn are available at -// -// http://marijnhaverbeke.nl/git/acorn -// https://github.com/marijnh/acorn.git - -// ## Character categories - - - - -// acorn used char codes to squeeze the last bit of performance out -// Beautifier is okay without that, so we're using regex -// permit # (23), $ (36), and @ (64). @ is used in ES7 decorators. -// 65 through 91 are uppercase letters. -// permit _ (95). -// 97 through 123 are lowercase letters. -var baseASCIIidentifierStartChars = "\\x23\\x24\\x40\\x41-\\x5a\\x5f\\x61-\\x7a"; - -// inside an identifier @ is not allowed but 0-9 are. -var baseASCIIidentifierChars = "\\x24\\x30-\\x39\\x41-\\x5a\\x5f\\x61-\\x7a"; - -// Big ugly regular expressions that match characters in the -// whitespace, identifier, and identifier-start categories. These -// are only applied when a character is found to actually have a -// code point above 128. -var nonASCIIidentifierStartChars = "\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05d0-\\u05ea\\u05f0-\\u05f2\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u08a0\\u08a2-\\u08ac\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097f\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c33\\u0c35-\\u0c39\\u0c3d\\u0c58\\u0c59\\u0c60\\u0c61\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d60\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0e01-\\u0e30\\u0e32\\u0e33\\u0e40-\\u0e46\\u0e81\\u0e82\\u0e84\\u0e87\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5\\u0ea7\\u0eaa\\u0eab\\u0ead-\\u0eb0\\u0eb2\\u0eb3\\u0ebd\\u0ec0-\\u0ec4\\u0ec6\\u0edc-\\u0edf\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u1000-\\u102a\\u103f\\u1050-\\u1055\\u105a-\\u105d\\u1061\\u1065\\u1066\\u106e-\\u1070\\u1075-\\u1081\\u108e\\u10a0-\\u10c5\\u10c7\\u10cd\\u10d0-\\u10fa\\u10fc-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f4\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f0\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1780-\\u17b3\\u17d7\\u17dc\\u1820-\\u1877\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191c\\u1950-\\u196d\\u1970-\\u1974\\u1980-\\u19ab\\u19c1-\\u19c7\\u1a00-\\u1a16\\u1a20-\\u1a54\\u1aa7\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bba-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1cf5\\u1cf6\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2119-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u212d\\u212f-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2cf2\\u2cf3\\u2d00-\\u2d25\\u2d27\\u2d2d\\u2d30-\\u2d67\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u2e2f\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303c\\u3041-\\u3096\\u309d-\\u309f\\u30a1-\\u30fa\\u30fc-\\u30ff\\u3105-\\u312d\\u3131-\\u318e\\u31a0-\\u31ba\\u31f0-\\u31ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua697\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua78e\\ua790-\\ua793\\ua7a0-\\ua7aa\\ua7f8-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uaa60-\\uaa76\\uaa7a\\uaa80-\\uaaaf\\uaab1\\uaab5\\uaab6\\uaab9-\\uaabd\\uaac0\\uaac2\\uaadb-\\uaadd\\uaae0-\\uaaea\\uaaf2-\\uaaf4\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uabc0-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\uf900-\\ufa6d\\ufa70-\\ufad9\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uff66-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc"; -var nonASCIIidentifierChars = "\\u0300-\\u036f\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u0620-\\u0649\\u0672-\\u06d3\\u06e7-\\u06e8\\u06fb-\\u06fc\\u0730-\\u074a\\u0800-\\u0814\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0840-\\u0857\\u08e4-\\u08fe\\u0900-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962-\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09d7\\u09df-\\u09e0\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2-\\u0ae3\\u0ae6-\\u0aef\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b5f-\\u0b60\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c01-\\u0c03\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62-\\u0c63\\u0c66-\\u0c6f\\u0c82\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2-\\u0ce3\\u0ce6-\\u0cef\\u0d02\\u0d03\\u0d46-\\u0d48\\u0d57\\u0d62-\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0df2\\u0df3\\u0e34-\\u0e3a\\u0e40-\\u0e45\\u0e50-\\u0e59\\u0eb4-\\u0eb9\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f41-\\u0f47\\u0f71-\\u0f84\\u0f86-\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u1000-\\u1029\\u1040-\\u1049\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u170e-\\u1710\\u1720-\\u1730\\u1740-\\u1750\\u1772\\u1773\\u1780-\\u17b2\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u1920-\\u192b\\u1930-\\u193b\\u1951-\\u196d\\u19b0-\\u19c0\\u19c8-\\u19c9\\u19d0-\\u19d9\\u1a00-\\u1a15\\u1a20-\\u1a53\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1b46-\\u1b4b\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c00-\\u1c22\\u1c40-\\u1c49\\u1c5b-\\u1c7d\\u1cd0-\\u1cd2\\u1d00-\\u1dbe\\u1e01-\\u1f15\\u200c\\u200d\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2d81-\\u2d96\\u2de0-\\u2dff\\u3021-\\u3028\\u3099\\u309a\\ua640-\\ua66d\\ua674-\\ua67d\\ua69f\\ua6f0-\\ua6f1\\ua7f8-\\ua800\\ua806\\ua80b\\ua823-\\ua827\\ua880-\\ua881\\ua8b4-\\ua8c4\\ua8d0-\\ua8d9\\ua8f3-\\ua8f7\\ua900-\\ua909\\ua926-\\ua92d\\ua930-\\ua945\\ua980-\\ua983\\ua9b3-\\ua9c0\\uaa00-\\uaa27\\uaa40-\\uaa41\\uaa4c-\\uaa4d\\uaa50-\\uaa59\\uaa7b\\uaae0-\\uaae9\\uaaf2-\\uaaf3\\uabc0-\\uabe1\\uabec\\uabed\\uabf0-\\uabf9\\ufb20-\\ufb28\\ufe00-\\ufe0f\\ufe20-\\ufe26\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f"; -//var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); -//var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); - -var unicodeEscapeOrCodePoint = "\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}"; -var identifierStart = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])"; -var identifierChars = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*"; - -exports.identifier = new RegExp(identifierStart + identifierChars, 'g'); -exports.identifierStart = new RegExp(identifierStart); -exports.identifierMatch = new RegExp("(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+"); - -var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; // jshint ignore:line - -// Whether a single character denotes a newline. - -exports.newline = /[\n\r\u2028\u2029]/; - -// Matches a whole line break (where CRLF is considered a single -// line break). Used to count lines. - -// in javascript, these two differ -// in python they are the same, different methods are called on them -exports.lineBreak = new RegExp('\r\n|' + exports.newline.source); -exports.allLineBreaks = new RegExp(exports.lineBreak.source, 'g'); - - -/***/ }), -/* 5 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var BaseOptions = (__webpack_require__(6).Options); - -var validPositionValues = ['before-newline', 'after-newline', 'preserve-newline']; - -function Options(options) { - BaseOptions.call(this, options, 'js'); - - // compatibility, re - var raw_brace_style = this.raw_options.brace_style || null; - if (raw_brace_style === "expand-strict") { //graceful handling of deprecated option - this.raw_options.brace_style = "expand"; - } else if (raw_brace_style === "collapse-preserve-inline") { //graceful handling of deprecated option - this.raw_options.brace_style = "collapse,preserve-inline"; - } else if (this.raw_options.braces_on_own_line !== undefined) { //graceful handling of deprecated option - this.raw_options.brace_style = this.raw_options.braces_on_own_line ? "expand" : "collapse"; - // } else if (!raw_brace_style) { //Nothing exists to set it - // raw_brace_style = "collapse"; - } - - //preserve-inline in delimited string will trigger brace_preserve_inline, everything - //else is considered a brace_style and the last one only will have an effect - - var brace_style_split = this._get_selection_list('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline']); - - this.brace_preserve_inline = false; //Defaults in case one or other was not specified in meta-option - this.brace_style = "collapse"; - - for (var bs = 0; bs < brace_style_split.length; bs++) { - if (brace_style_split[bs] === "preserve-inline") { - this.brace_preserve_inline = true; - } else { - this.brace_style = brace_style_split[bs]; - } - } - - this.unindent_chained_methods = this._get_boolean('unindent_chained_methods'); - this.break_chained_methods = this._get_boolean('break_chained_methods'); - this.space_in_paren = this._get_boolean('space_in_paren'); - this.space_in_empty_paren = this._get_boolean('space_in_empty_paren'); - this.jslint_happy = this._get_boolean('jslint_happy'); - this.space_after_anon_function = this._get_boolean('space_after_anon_function'); - this.space_after_named_function = this._get_boolean('space_after_named_function'); - this.keep_array_indentation = this._get_boolean('keep_array_indentation'); - this.space_before_conditional = this._get_boolean('space_before_conditional', true); - this.unescape_strings = this._get_boolean('unescape_strings'); - this.e4x = this._get_boolean('e4x'); - this.comma_first = this._get_boolean('comma_first'); - this.operator_position = this._get_selection('operator_position', validPositionValues); - - // For testing of beautify preserve:start directive - this.test_output_raw = this._get_boolean('test_output_raw'); - - // force this._options.space_after_anon_function to true if this._options.jslint_happy - if (this.jslint_happy) { - this.space_after_anon_function = true; - } - -} -Options.prototype = new BaseOptions(); - - - -module.exports.Options = Options; - - -/***/ }), -/* 6 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Options(options, merge_child_field) { - this.raw_options = _mergeOpts(options, merge_child_field); - - // Support passing the source text back with no change - this.disabled = this._get_boolean('disabled'); - - this.eol = this._get_characters('eol', 'auto'); - this.end_with_newline = this._get_boolean('end_with_newline'); - this.indent_size = this._get_number('indent_size', 4); - this.indent_char = this._get_characters('indent_char', ' '); - this.indent_level = this._get_number('indent_level'); - - this.preserve_newlines = this._get_boolean('preserve_newlines', true); - this.max_preserve_newlines = this._get_number('max_preserve_newlines', 32786); - if (!this.preserve_newlines) { - this.max_preserve_newlines = 0; - } - - this.indent_with_tabs = this._get_boolean('indent_with_tabs', this.indent_char === '\t'); - if (this.indent_with_tabs) { - this.indent_char = '\t'; - - // indent_size behavior changed after 1.8.6 - // It used to be that indent_size would be - // set to 1 for indent_with_tabs. That is no longer needed and - // actually doesn't make sense - why not use spaces? Further, - // that might produce unexpected behavior - tabs being used - // for single-column alignment. So, when indent_with_tabs is true - // and indent_size is 1, reset indent_size to 4. - if (this.indent_size === 1) { - this.indent_size = 4; - } - } - - // Backwards compat with 1.3.x - this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char')); - - this.indent_empty_lines = this._get_boolean('indent_empty_lines'); - - // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular'] - // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css). - // other values ignored - this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']); -} - -Options.prototype._get_array = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = default_value || []; - if (typeof option_value === 'object') { - if (option_value !== null && typeof option_value.concat === 'function') { - result = option_value.concat(); - } - } else if (typeof option_value === 'string') { - result = option_value.split(/[^a-zA-Z0-9_\/\-]+/); - } - return result; -}; - -Options.prototype._get_boolean = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = option_value === undefined ? !!default_value : !!option_value; - return result; -}; - -Options.prototype._get_characters = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = default_value || ''; - if (typeof option_value === 'string') { - result = option_value.replace(/\\r/, '\r').replace(/\\n/, '\n').replace(/\\t/, '\t'); - } - return result; -}; - -Options.prototype._get_number = function(name, default_value) { - var option_value = this.raw_options[name]; - default_value = parseInt(default_value, 10); - if (isNaN(default_value)) { - default_value = 0; - } - var result = parseInt(option_value, 10); - if (isNaN(result)) { - result = default_value; - } - return result; -}; - -Options.prototype._get_selection = function(name, selection_list, default_value) { - var result = this._get_selection_list(name, selection_list, default_value); - if (result.length !== 1) { - throw new Error( - "Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" + - selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); - } - - return result[0]; -}; - - -Options.prototype._get_selection_list = function(name, selection_list, default_value) { - if (!selection_list || selection_list.length === 0) { - throw new Error("Selection list cannot be empty."); - } - - default_value = default_value || [selection_list[0]]; - if (!this._is_valid_selection(default_value, selection_list)) { - throw new Error("Invalid Default Value!"); - } - - var result = this._get_array(name, default_value); - if (!this._is_valid_selection(result, selection_list)) { - throw new Error( - "Invalid Option Value: The option '" + name + "' can contain only the following values:\n" + - selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); - } - - return result; -}; - -Options.prototype._is_valid_selection = function(result, selection_list) { - return result.length && selection_list.length && - !result.some(function(item) { return selection_list.indexOf(item) === -1; }); -}; - - -// merges child options up with the parent options object -// Example: obj = {a: 1, b: {a: 2}} -// mergeOpts(obj, 'b') -// -// Returns: {a: 2} -function _mergeOpts(allOptions, childFieldName) { - var finalOpts = {}; - allOptions = _normalizeOpts(allOptions); - var name; - - for (name in allOptions) { - if (name !== childFieldName) { - finalOpts[name] = allOptions[name]; - } - } - - //merge in the per type settings for the childFieldName - if (childFieldName && allOptions[childFieldName]) { - for (name in allOptions[childFieldName]) { - finalOpts[name] = allOptions[childFieldName][name]; - } - } - return finalOpts; -} - -function _normalizeOpts(options) { - var convertedOpts = {}; - var key; - - for (key in options) { - var newKey = key.replace(/-/g, "_"); - convertedOpts[newKey] = options[key]; - } - return convertedOpts; -} - -module.exports.Options = Options; -module.exports.normalizeOpts = _normalizeOpts; -module.exports.mergeOpts = _mergeOpts; - - -/***/ }), -/* 7 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var InputScanner = (__webpack_require__(8).InputScanner); -var BaseTokenizer = (__webpack_require__(9).Tokenizer); -var BASETOKEN = (__webpack_require__(9).TOKEN); -var Directives = (__webpack_require__(13).Directives); -var acorn = __webpack_require__(4); -var Pattern = (__webpack_require__(12).Pattern); -var TemplatablePattern = (__webpack_require__(14).TemplatablePattern); - - -function in_array(what, arr) { - return arr.indexOf(what) !== -1; -} - - -var TOKEN = { - START_EXPR: 'TK_START_EXPR', - END_EXPR: 'TK_END_EXPR', - START_BLOCK: 'TK_START_BLOCK', - END_BLOCK: 'TK_END_BLOCK', - WORD: 'TK_WORD', - RESERVED: 'TK_RESERVED', - SEMICOLON: 'TK_SEMICOLON', - STRING: 'TK_STRING', - EQUALS: 'TK_EQUALS', - OPERATOR: 'TK_OPERATOR', - COMMA: 'TK_COMMA', - BLOCK_COMMENT: 'TK_BLOCK_COMMENT', - COMMENT: 'TK_COMMENT', - DOT: 'TK_DOT', - UNKNOWN: 'TK_UNKNOWN', - START: BASETOKEN.START, - RAW: BASETOKEN.RAW, - EOF: BASETOKEN.EOF -}; - - -var directives_core = new Directives(/\/\*/, /\*\//); - -var number_pattern = /0[xX][0123456789abcdefABCDEF_]*n?|0[oO][01234567_]*n?|0[bB][01_]*n?|\d[\d_]*n|(?:\.\d[\d_]*|\d[\d_]*\.?[\d_]*)(?:[eE][+-]?[\d_]+)?/; - -var digit = /[0-9]/; - -// Dot "." must be distinguished from "..." and decimal -var dot_pattern = /[^\d\.]/; - -var positionable_operators = ( - ">>> === !== &&= ??= ||= " + - "<< && >= ** != == <= >> || ?? |> " + - "< / - + > : & % ? ^ | *").split(' '); - -// IMPORTANT: this must be sorted longest to shortest or tokenizing many not work. -// Also, you must update possitionable operators separately from punct -var punct = - ">>>= " + - "... >>= <<= === >>> !== **= &&= ??= ||= " + - "=> ^= :: /= << <= == && -= >= >> != -- += ** || ?? ++ %= &= *= |= |> " + - "= ! ? > < : / ^ - + * & % ~ |"; - -punct = punct.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); -// ?. but not if followed by a number -punct = '\\?\\.(?!\\d) ' + punct; -punct = punct.replace(/ /g, '|'); - -var punct_pattern = new RegExp(punct); - -// words which should always start on new line. -var line_starters = 'continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function,import,export'.split(','); -var reserved_words = line_starters.concat(['do', 'in', 'of', 'else', 'get', 'set', 'new', 'catch', 'finally', 'typeof', 'yield', 'async', 'await', 'from', 'as', 'class', 'extends']); -var reserved_word_pattern = new RegExp('^(?:' + reserved_words.join('|') + ')$'); - -// var template_pattern = /(?:(?:<\?php|<\?=)[\s\S]*?\?>)|(?:<%[\s\S]*?%>)/g; - -var in_html_comment; - -var Tokenizer = function(input_string, options) { - BaseTokenizer.call(this, input_string, options); - - this._patterns.whitespace = this._patterns.whitespace.matching( - /\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff/.source, - /\u2028\u2029/.source); - - var pattern_reader = new Pattern(this._input); - var templatable = new TemplatablePattern(this._input) - .read_options(this._options); - - this.__patterns = { - template: templatable, - identifier: templatable.starting_with(acorn.identifier).matching(acorn.identifierMatch), - number: pattern_reader.matching(number_pattern), - punct: pattern_reader.matching(punct_pattern), - // comment ends just before nearest linefeed or end of file - comment: pattern_reader.starting_with(/\/\//).until(/[\n\r\u2028\u2029]/), - // /* ... */ comment ends with nearest */ or end of file - block_comment: pattern_reader.starting_with(/\/\*/).until_after(/\*\//), - html_comment_start: pattern_reader.matching(//), - include: pattern_reader.starting_with(/#include/).until_after(acorn.lineBreak), - shebang: pattern_reader.starting_with(/#!/).until_after(acorn.lineBreak), - xml: pattern_reader.matching(/[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[^}]+?}|!\[CDATA\[[^\]]*?\]\]|)(\s*{[^}]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{([^{}]|{[^}]+?})+?}))*\s*(\/?)\s*>/), - single_quote: templatable.until(/['\\\n\r\u2028\u2029]/), - double_quote: templatable.until(/["\\\n\r\u2028\u2029]/), - template_text: templatable.until(/[`\\$]/), - template_expression: templatable.until(/[`}\\]/) - }; - -}; -Tokenizer.prototype = new BaseTokenizer(); - -Tokenizer.prototype._is_comment = function(current_token) { - return current_token.type === TOKEN.COMMENT || current_token.type === TOKEN.BLOCK_COMMENT || current_token.type === TOKEN.UNKNOWN; -}; - -Tokenizer.prototype._is_opening = function(current_token) { - return current_token.type === TOKEN.START_BLOCK || current_token.type === TOKEN.START_EXPR; -}; - -Tokenizer.prototype._is_closing = function(current_token, open_token) { - return (current_token.type === TOKEN.END_BLOCK || current_token.type === TOKEN.END_EXPR) && - (open_token && ( - (current_token.text === ']' && open_token.text === '[') || - (current_token.text === ')' && open_token.text === '(') || - (current_token.text === '}' && open_token.text === '{'))); -}; - -Tokenizer.prototype._reset = function() { - in_html_comment = false; -}; - -Tokenizer.prototype._get_next_token = function(previous_token, open_token) { // jshint unused:false - var token = null; - this._readWhitespace(); - var c = this._input.peek(); - - if (c === null) { - return this._create_token(TOKEN.EOF, ''); - } - - token = token || this._read_non_javascript(c); - token = token || this._read_string(c); - token = token || this._read_pair(c, this._input.peek(1)); // Issue #2062 hack for record type '#{' - token = token || this._read_word(previous_token); - token = token || this._read_singles(c); - token = token || this._read_comment(c); - token = token || this._read_regexp(c, previous_token); - token = token || this._read_xml(c, previous_token); - token = token || this._read_punctuation(); - token = token || this._create_token(TOKEN.UNKNOWN, this._input.next()); - - return token; -}; - -Tokenizer.prototype._read_word = function(previous_token) { - var resulting_string; - resulting_string = this.__patterns.identifier.read(); - if (resulting_string !== '') { - resulting_string = resulting_string.replace(acorn.allLineBreaks, '\n'); - if (!(previous_token.type === TOKEN.DOT || - (previous_token.type === TOKEN.RESERVED && (previous_token.text === 'set' || previous_token.text === 'get'))) && - reserved_word_pattern.test(resulting_string)) { - if ((resulting_string === 'in' || resulting_string === 'of') && - (previous_token.type === TOKEN.WORD || previous_token.type === TOKEN.STRING)) { // hack for 'in' and 'of' operators - return this._create_token(TOKEN.OPERATOR, resulting_string); - } - return this._create_token(TOKEN.RESERVED, resulting_string); - } - return this._create_token(TOKEN.WORD, resulting_string); - } - - resulting_string = this.__patterns.number.read(); - if (resulting_string !== '') { - return this._create_token(TOKEN.WORD, resulting_string); - } -}; - -Tokenizer.prototype._read_singles = function(c) { - var token = null; - if (c === '(' || c === '[') { - token = this._create_token(TOKEN.START_EXPR, c); - } else if (c === ')' || c === ']') { - token = this._create_token(TOKEN.END_EXPR, c); - } else if (c === '{') { - token = this._create_token(TOKEN.START_BLOCK, c); - } else if (c === '}') { - token = this._create_token(TOKEN.END_BLOCK, c); - } else if (c === ';') { - token = this._create_token(TOKEN.SEMICOLON, c); - } else if (c === '.' && dot_pattern.test(this._input.peek(1))) { - token = this._create_token(TOKEN.DOT, c); - } else if (c === ',') { - token = this._create_token(TOKEN.COMMA, c); - } - - if (token) { - this._input.next(); - } - return token; -}; - -Tokenizer.prototype._read_pair = function(c, d) { - var token = null; - if (c === '#' && d === '{') { - token = this._create_token(TOKEN.START_BLOCK, c + d); - } - - if (token) { - this._input.next(); - this._input.next(); - } - return token; -}; - -Tokenizer.prototype._read_punctuation = function() { - var resulting_string = this.__patterns.punct.read(); - - if (resulting_string !== '') { - if (resulting_string === '=') { - return this._create_token(TOKEN.EQUALS, resulting_string); - } else if (resulting_string === '?.') { - return this._create_token(TOKEN.DOT, resulting_string); - } else { - return this._create_token(TOKEN.OPERATOR, resulting_string); - } - } -}; - -Tokenizer.prototype._read_non_javascript = function(c) { - var resulting_string = ''; - - if (c === '#') { - if (this._is_first_token()) { - resulting_string = this.__patterns.shebang.read(); - - if (resulting_string) { - return this._create_token(TOKEN.UNKNOWN, resulting_string.trim() + '\n'); - } - } - - // handles extendscript #includes - resulting_string = this.__patterns.include.read(); - - if (resulting_string) { - return this._create_token(TOKEN.UNKNOWN, resulting_string.trim() + '\n'); - } - - c = this._input.next(); - - // Spidermonkey-specific sharp variables for circular references. Considered obsolete. - var sharp = '#'; - if (this._input.hasNext() && this._input.testChar(digit)) { - do { - c = this._input.next(); - sharp += c; - } while (this._input.hasNext() && c !== '#' && c !== '='); - if (c === '#') { - // - } else if (this._input.peek() === '[' && this._input.peek(1) === ']') { - sharp += '[]'; - this._input.next(); - this._input.next(); - } else if (this._input.peek() === '{' && this._input.peek(1) === '}') { - sharp += '{}'; - this._input.next(); - this._input.next(); - } - return this._create_token(TOKEN.WORD, sharp); - } - - this._input.back(); - - } else if (c === '<' && this._is_first_token()) { - resulting_string = this.__patterns.html_comment_start.read(); - if (resulting_string) { - while (this._input.hasNext() && !this._input.testChar(acorn.newline)) { - resulting_string += this._input.next(); - } - in_html_comment = true; - return this._create_token(TOKEN.COMMENT, resulting_string); - } - } else if (in_html_comment && c === '-') { - resulting_string = this.__patterns.html_comment_end.read(); - if (resulting_string) { - in_html_comment = false; - return this._create_token(TOKEN.COMMENT, resulting_string); - } - } - - return null; -}; - -Tokenizer.prototype._read_comment = function(c) { - var token = null; - if (c === '/') { - var comment = ''; - if (this._input.peek(1) === '*') { - // peek for comment /* ... */ - comment = this.__patterns.block_comment.read(); - var directives = directives_core.get_directives(comment); - if (directives && directives.ignore === 'start') { - comment += directives_core.readIgnored(this._input); - } - comment = comment.replace(acorn.allLineBreaks, '\n'); - token = this._create_token(TOKEN.BLOCK_COMMENT, comment); - token.directives = directives; - } else if (this._input.peek(1) === '/') { - // peek for comment // ... - comment = this.__patterns.comment.read(); - token = this._create_token(TOKEN.COMMENT, comment); - } - } - return token; -}; - -Tokenizer.prototype._read_string = function(c) { - if (c === '`' || c === "'" || c === '"') { - var resulting_string = this._input.next(); - this.has_char_escapes = false; - - if (c === '`') { - resulting_string += this._read_string_recursive('`', true, '${'); - } else { - resulting_string += this._read_string_recursive(c); - } - - if (this.has_char_escapes && this._options.unescape_strings) { - resulting_string = unescape_string(resulting_string); - } - - if (this._input.peek() === c) { - resulting_string += this._input.next(); - } - - resulting_string = resulting_string.replace(acorn.allLineBreaks, '\n'); - - return this._create_token(TOKEN.STRING, resulting_string); - } - - return null; -}; - -Tokenizer.prototype._allow_regexp_or_xml = function(previous_token) { - // regex and xml can only appear in specific locations during parsing - return (previous_token.type === TOKEN.RESERVED && in_array(previous_token.text, ['return', 'case', 'throw', 'else', 'do', 'typeof', 'yield'])) || - (previous_token.type === TOKEN.END_EXPR && previous_token.text === ')' && - previous_token.opened.previous.type === TOKEN.RESERVED && in_array(previous_token.opened.previous.text, ['if', 'while', 'for'])) || - (in_array(previous_token.type, [TOKEN.COMMENT, TOKEN.START_EXPR, TOKEN.START_BLOCK, TOKEN.START, - TOKEN.END_BLOCK, TOKEN.OPERATOR, TOKEN.EQUALS, TOKEN.EOF, TOKEN.SEMICOLON, TOKEN.COMMA - ])); -}; - -Tokenizer.prototype._read_regexp = function(c, previous_token) { - - if (c === '/' && this._allow_regexp_or_xml(previous_token)) { - // handle regexp - // - var resulting_string = this._input.next(); - var esc = false; - - var in_char_class = false; - while (this._input.hasNext() && - ((esc || in_char_class || this._input.peek() !== c) && - !this._input.testChar(acorn.newline))) { - resulting_string += this._input.peek(); - if (!esc) { - esc = this._input.peek() === '\\'; - if (this._input.peek() === '[') { - in_char_class = true; - } else if (this._input.peek() === ']') { - in_char_class = false; - } - } else { - esc = false; - } - this._input.next(); - } - - if (this._input.peek() === c) { - resulting_string += this._input.next(); - - // regexps may have modifiers /regexp/MOD , so fetch those, too - // Only [gim] are valid, but if the user puts in garbage, do what we can to take it. - resulting_string += this._input.read(acorn.identifier); - } - return this._create_token(TOKEN.STRING, resulting_string); - } - return null; -}; - -Tokenizer.prototype._read_xml = function(c, previous_token) { - - if (this._options.e4x && c === "<" && this._allow_regexp_or_xml(previous_token)) { - var xmlStr = ''; - var match = this.__patterns.xml.read_match(); - // handle e4x xml literals - // - if (match) { - // Trim root tag to attempt to - var rootTag = match[2].replace(/^{\s+/, '{').replace(/\s+}$/, '}'); - var isCurlyRoot = rootTag.indexOf('{') === 0; - var depth = 0; - while (match) { - var isEndTag = !!match[1]; - var tagName = match[2]; - var isSingletonTag = (!!match[match.length - 1]) || (tagName.slice(0, 8) === "![CDATA["); - if (!isSingletonTag && - (tagName === rootTag || (isCurlyRoot && tagName.replace(/^{\s+/, '{').replace(/\s+}$/, '}')))) { - if (isEndTag) { - --depth; - } else { - ++depth; - } - } - xmlStr += match[0]; - if (depth <= 0) { - break; - } - match = this.__patterns.xml.read_match(); - } - // if we didn't close correctly, keep unformatted. - if (!match) { - xmlStr += this._input.match(/[\s\S]*/g)[0]; - } - xmlStr = xmlStr.replace(acorn.allLineBreaks, '\n'); - return this._create_token(TOKEN.STRING, xmlStr); - } - } - - return null; -}; - -function unescape_string(s) { - // You think that a regex would work for this - // return s.replace(/\\x([0-9a-f]{2})/gi, function(match, val) { - // return String.fromCharCode(parseInt(val, 16)); - // }) - // However, dealing with '\xff', '\\xff', '\\\xff' makes this more fun. - var out = '', - escaped = 0; - - var input_scan = new InputScanner(s); - var matched = null; - - while (input_scan.hasNext()) { - // Keep any whitespace, non-slash characters - // also keep slash pairs. - matched = input_scan.match(/([\s]|[^\\]|\\\\)+/g); - - if (matched) { - out += matched[0]; - } - - if (input_scan.peek() === '\\') { - input_scan.next(); - if (input_scan.peek() === 'x') { - matched = input_scan.match(/x([0-9A-Fa-f]{2})/g); - } else if (input_scan.peek() === 'u') { - matched = input_scan.match(/u([0-9A-Fa-f]{4})/g); - if (!matched) { - matched = input_scan.match(/u\{([0-9A-Fa-f]+)\}/g); - } - } else { - out += '\\'; - if (input_scan.hasNext()) { - out += input_scan.next(); - } - continue; - } - - // If there's some error decoding, return the original string - if (!matched) { - return s; - } - - escaped = parseInt(matched[1], 16); - - if (escaped > 0x7e && escaped <= 0xff && matched[0].indexOf('x') === 0) { - // we bail out on \x7f..\xff, - // leaving whole string escaped, - // as it's probably completely binary - return s; - } else if (escaped >= 0x00 && escaped < 0x20) { - // leave 0x00...0x1f escaped - out += '\\' + matched[0]; - } else if (escaped > 0x10FFFF) { - // If the escape sequence is out of bounds, keep the original sequence and continue conversion - out += '\\' + matched[0]; - } else if (escaped === 0x22 || escaped === 0x27 || escaped === 0x5c) { - // single-quote, apostrophe, backslash - escape these - out += '\\' + String.fromCharCode(escaped); - } else { - out += String.fromCharCode(escaped); - } - } - } - - return out; -} - -// handle string -// -Tokenizer.prototype._read_string_recursive = function(delimiter, allow_unescaped_newlines, start_sub) { - var current_char; - var pattern; - if (delimiter === '\'') { - pattern = this.__patterns.single_quote; - } else if (delimiter === '"') { - pattern = this.__patterns.double_quote; - } else if (delimiter === '`') { - pattern = this.__patterns.template_text; - } else if (delimiter === '}') { - pattern = this.__patterns.template_expression; - } - - var resulting_string = pattern.read(); - var next = ''; - while (this._input.hasNext()) { - next = this._input.next(); - if (next === delimiter || - (!allow_unescaped_newlines && acorn.newline.test(next))) { - this._input.back(); - break; - } else if (next === '\\' && this._input.hasNext()) { - current_char = this._input.peek(); - - if (current_char === 'x' || current_char === 'u') { - this.has_char_escapes = true; - } else if (current_char === '\r' && this._input.peek(1) === '\n') { - this._input.next(); - } - next += this._input.next(); - } else if (start_sub) { - if (start_sub === '${' && next === '$' && this._input.peek() === '{') { - next += this._input.next(); - } - - if (start_sub === next) { - if (delimiter === '`') { - next += this._read_string_recursive('}', allow_unescaped_newlines, '`'); - } else { - next += this._read_string_recursive('`', allow_unescaped_newlines, '${'); - } - if (this._input.hasNext()) { - next += this._input.next(); - } - } - } - next += pattern.read(); - resulting_string += next; - } - - return resulting_string; -}; - -module.exports.Tokenizer = Tokenizer; -module.exports.TOKEN = TOKEN; -module.exports.positionable_operators = positionable_operators.slice(); -module.exports.line_starters = line_starters.slice(); - - -/***/ }), -/* 8 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var regexp_has_sticky = RegExp.prototype.hasOwnProperty('sticky'); - -function InputScanner(input_string) { - this.__input = input_string || ''; - this.__input_length = this.__input.length; - this.__position = 0; -} - -InputScanner.prototype.restart = function() { - this.__position = 0; -}; - -InputScanner.prototype.back = function() { - if (this.__position > 0) { - this.__position -= 1; - } -}; - -InputScanner.prototype.hasNext = function() { - return this.__position < this.__input_length; -}; - -InputScanner.prototype.next = function() { - var val = null; - if (this.hasNext()) { - val = this.__input.charAt(this.__position); - this.__position += 1; - } - return val; -}; - -InputScanner.prototype.peek = function(index) { - var val = null; - index = index || 0; - index += this.__position; - if (index >= 0 && index < this.__input_length) { - val = this.__input.charAt(index); - } - return val; -}; - -// This is a JavaScript only helper function (not in python) -// Javascript doesn't have a match method -// and not all implementation support "sticky" flag. -// If they do not support sticky then both this.match() and this.test() method -// must get the match and check the index of the match. -// If sticky is supported and set, this method will use it. -// Otherwise it will check that global is set, and fall back to the slower method. -InputScanner.prototype.__match = function(pattern, index) { - pattern.lastIndex = index; - var pattern_match = pattern.exec(this.__input); - - if (pattern_match && !(regexp_has_sticky && pattern.sticky)) { - if (pattern_match.index !== index) { - pattern_match = null; - } - } - - return pattern_match; -}; - -InputScanner.prototype.test = function(pattern, index) { - index = index || 0; - index += this.__position; - - if (index >= 0 && index < this.__input_length) { - return !!this.__match(pattern, index); - } else { - return false; - } -}; - -InputScanner.prototype.testChar = function(pattern, index) { - // test one character regex match - var val = this.peek(index); - pattern.lastIndex = 0; - return val !== null && pattern.test(val); -}; - -InputScanner.prototype.match = function(pattern) { - var pattern_match = this.__match(pattern, this.__position); - if (pattern_match) { - this.__position += pattern_match[0].length; - } else { - pattern_match = null; - } - return pattern_match; -}; - -InputScanner.prototype.read = function(starting_pattern, until_pattern, until_after) { - var val = ''; - var match; - if (starting_pattern) { - match = this.match(starting_pattern); - if (match) { - val += match[0]; - } - } - if (until_pattern && (match || !starting_pattern)) { - val += this.readUntil(until_pattern, until_after); - } - return val; -}; - -InputScanner.prototype.readUntil = function(pattern, until_after) { - var val = ''; - var match_index = this.__position; - pattern.lastIndex = this.__position; - var pattern_match = pattern.exec(this.__input); - if (pattern_match) { - match_index = pattern_match.index; - if (until_after) { - match_index += pattern_match[0].length; - } - } else { - match_index = this.__input_length; - } - - val = this.__input.substring(this.__position, match_index); - this.__position = match_index; - return val; -}; - -InputScanner.prototype.readUntilAfter = function(pattern) { - return this.readUntil(pattern, true); -}; - -InputScanner.prototype.get_regexp = function(pattern, match_from) { - var result = null; - var flags = 'g'; - if (match_from && regexp_has_sticky) { - flags = 'y'; - } - // strings are converted to regexp - if (typeof pattern === "string" && pattern !== '') { - // result = new RegExp(pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), flags); - result = new RegExp(pattern, flags); - } else if (pattern) { - result = new RegExp(pattern.source, flags); - } - return result; -}; - -InputScanner.prototype.get_literal_regexp = function(literal_string) { - return RegExp(literal_string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); -}; - -/* css beautifier legacy helpers */ -InputScanner.prototype.peekUntilAfter = function(pattern) { - var start = this.__position; - var val = this.readUntilAfter(pattern); - this.__position = start; - return val; -}; - -InputScanner.prototype.lookBack = function(testVal) { - var start = this.__position - 1; - return start >= testVal.length && this.__input.substring(start - testVal.length, start) - .toLowerCase() === testVal; -}; - -module.exports.InputScanner = InputScanner; - - -/***/ }), -/* 9 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var InputScanner = (__webpack_require__(8).InputScanner); -var Token = (__webpack_require__(3).Token); -var TokenStream = (__webpack_require__(10).TokenStream); -var WhitespacePattern = (__webpack_require__(11).WhitespacePattern); - -var TOKEN = { - START: 'TK_START', - RAW: 'TK_RAW', - EOF: 'TK_EOF' -}; - -var Tokenizer = function(input_string, options) { - this._input = new InputScanner(input_string); - this._options = options || {}; - this.__tokens = null; - - this._patterns = {}; - this._patterns.whitespace = new WhitespacePattern(this._input); -}; - -Tokenizer.prototype.tokenize = function() { - this._input.restart(); - this.__tokens = new TokenStream(); - - this._reset(); - - var current; - var previous = new Token(TOKEN.START, ''); - var open_token = null; - var open_stack = []; - var comments = new TokenStream(); - - while (previous.type !== TOKEN.EOF) { - current = this._get_next_token(previous, open_token); - while (this._is_comment(current)) { - comments.add(current); - current = this._get_next_token(previous, open_token); - } - - if (!comments.isEmpty()) { - current.comments_before = comments; - comments = new TokenStream(); - } - - current.parent = open_token; - - if (this._is_opening(current)) { - open_stack.push(open_token); - open_token = current; - } else if (open_token && this._is_closing(current, open_token)) { - current.opened = open_token; - open_token.closed = current; - open_token = open_stack.pop(); - current.parent = open_token; - } - - current.previous = previous; - previous.next = current; - - this.__tokens.add(current); - previous = current; - } - - return this.__tokens; -}; - - -Tokenizer.prototype._is_first_token = function() { - return this.__tokens.isEmpty(); -}; - -Tokenizer.prototype._reset = function() {}; - -Tokenizer.prototype._get_next_token = function(previous_token, open_token) { // jshint unused:false - this._readWhitespace(); - var resulting_string = this._input.read(/.+/g); - if (resulting_string) { - return this._create_token(TOKEN.RAW, resulting_string); - } else { - return this._create_token(TOKEN.EOF, ''); - } -}; - -Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:false - return false; -}; - -Tokenizer.prototype._is_opening = function(current_token) { // jshint unused:false - return false; -}; - -Tokenizer.prototype._is_closing = function(current_token, open_token) { // jshint unused:false - return false; -}; - -Tokenizer.prototype._create_token = function(type, text) { - var token = new Token(type, text, - this._patterns.whitespace.newline_count, - this._patterns.whitespace.whitespace_before_token); - return token; -}; - -Tokenizer.prototype._readWhitespace = function() { - return this._patterns.whitespace.read(); -}; - - - -module.exports.Tokenizer = Tokenizer; -module.exports.TOKEN = TOKEN; - - -/***/ }), -/* 10 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function TokenStream(parent_token) { - // private - this.__tokens = []; - this.__tokens_length = this.__tokens.length; - this.__position = 0; - this.__parent_token = parent_token; -} - -TokenStream.prototype.restart = function() { - this.__position = 0; -}; - -TokenStream.prototype.isEmpty = function() { - return this.__tokens_length === 0; -}; - -TokenStream.prototype.hasNext = function() { - return this.__position < this.__tokens_length; -}; - -TokenStream.prototype.next = function() { - var val = null; - if (this.hasNext()) { - val = this.__tokens[this.__position]; - this.__position += 1; - } - return val; -}; - -TokenStream.prototype.peek = function(index) { - var val = null; - index = index || 0; - index += this.__position; - if (index >= 0 && index < this.__tokens_length) { - val = this.__tokens[index]; - } - return val; -}; - -TokenStream.prototype.add = function(token) { - if (this.__parent_token) { - token.parent = this.__parent_token; - } - this.__tokens.push(token); - this.__tokens_length += 1; -}; - -module.exports.TokenStream = TokenStream; - - -/***/ }), -/* 11 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Pattern = (__webpack_require__(12).Pattern); - -function WhitespacePattern(input_scanner, parent) { - Pattern.call(this, input_scanner, parent); - if (parent) { - this._line_regexp = this._input.get_regexp(parent._line_regexp); - } else { - this.__set_whitespace_patterns('', ''); - } - - this.newline_count = 0; - this.whitespace_before_token = ''; -} -WhitespacePattern.prototype = new Pattern(); - -WhitespacePattern.prototype.__set_whitespace_patterns = function(whitespace_chars, newline_chars) { - whitespace_chars += '\\t '; - newline_chars += '\\n\\r'; - - this._match_pattern = this._input.get_regexp( - '[' + whitespace_chars + newline_chars + ']+', true); - this._newline_regexp = this._input.get_regexp( - '\\r\\n|[' + newline_chars + ']'); -}; - -WhitespacePattern.prototype.read = function() { - this.newline_count = 0; - this.whitespace_before_token = ''; - - var resulting_string = this._input.read(this._match_pattern); - if (resulting_string === ' ') { - this.whitespace_before_token = ' '; - } else if (resulting_string) { - var matches = this.__split(this._newline_regexp, resulting_string); - this.newline_count = matches.length - 1; - this.whitespace_before_token = matches[this.newline_count]; - } - - return resulting_string; -}; - -WhitespacePattern.prototype.matching = function(whitespace_chars, newline_chars) { - var result = this._create(); - result.__set_whitespace_patterns(whitespace_chars, newline_chars); - result._update(); - return result; -}; - -WhitespacePattern.prototype._create = function() { - return new WhitespacePattern(this._input, this); -}; - -WhitespacePattern.prototype.__split = function(regexp, input_string) { - regexp.lastIndex = 0; - var start_index = 0; - var result = []; - var next_match = regexp.exec(input_string); - while (next_match) { - result.push(input_string.substring(start_index, next_match.index)); - start_index = next_match.index + next_match[0].length; - next_match = regexp.exec(input_string); - } - - if (start_index < input_string.length) { - result.push(input_string.substring(start_index, input_string.length)); - } else { - result.push(''); - } - - return result; -}; - - - -module.exports.WhitespacePattern = WhitespacePattern; - - -/***/ }), -/* 12 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Pattern(input_scanner, parent) { - this._input = input_scanner; - this._starting_pattern = null; - this._match_pattern = null; - this._until_pattern = null; - this._until_after = false; - - if (parent) { - this._starting_pattern = this._input.get_regexp(parent._starting_pattern, true); - this._match_pattern = this._input.get_regexp(parent._match_pattern, true); - this._until_pattern = this._input.get_regexp(parent._until_pattern); - this._until_after = parent._until_after; - } -} - -Pattern.prototype.read = function() { - var result = this._input.read(this._starting_pattern); - if (!this._starting_pattern || result) { - result += this._input.read(this._match_pattern, this._until_pattern, this._until_after); - } - return result; -}; - -Pattern.prototype.read_match = function() { - return this._input.match(this._match_pattern); -}; - -Pattern.prototype.until_after = function(pattern) { - var result = this._create(); - result._until_after = true; - result._until_pattern = this._input.get_regexp(pattern); - result._update(); - return result; -}; - -Pattern.prototype.until = function(pattern) { - var result = this._create(); - result._until_after = false; - result._until_pattern = this._input.get_regexp(pattern); - result._update(); - return result; -}; - -Pattern.prototype.starting_with = function(pattern) { - var result = this._create(); - result._starting_pattern = this._input.get_regexp(pattern, true); - result._update(); - return result; -}; - -Pattern.prototype.matching = function(pattern) { - var result = this._create(); - result._match_pattern = this._input.get_regexp(pattern, true); - result._update(); - return result; -}; - -Pattern.prototype._create = function() { - return new Pattern(this._input, this); -}; - -Pattern.prototype._update = function() {}; - -module.exports.Pattern = Pattern; - - -/***/ }), -/* 13 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Directives(start_block_pattern, end_block_pattern) { - start_block_pattern = typeof start_block_pattern === 'string' ? start_block_pattern : start_block_pattern.source; - end_block_pattern = typeof end_block_pattern === 'string' ? end_block_pattern : end_block_pattern.source; - this.__directives_block_pattern = new RegExp(start_block_pattern + / beautify( \w+[:]\w+)+ /.source + end_block_pattern, 'g'); - this.__directive_pattern = / (\w+)[:](\w+)/g; - - this.__directives_end_ignore_pattern = new RegExp(start_block_pattern + /\sbeautify\signore:end\s/.source + end_block_pattern, 'g'); -} - -Directives.prototype.get_directives = function(text) { - if (!text.match(this.__directives_block_pattern)) { - return null; - } - - var directives = {}; - this.__directive_pattern.lastIndex = 0; - var directive_match = this.__directive_pattern.exec(text); - - while (directive_match) { - directives[directive_match[1]] = directive_match[2]; - directive_match = this.__directive_pattern.exec(text); - } - - return directives; -}; - -Directives.prototype.readIgnored = function(input) { - return input.readUntilAfter(this.__directives_end_ignore_pattern); -}; - - -module.exports.Directives = Directives; - - -/***/ }), -/* 14 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Pattern = (__webpack_require__(12).Pattern); - - -var template_names = { - django: false, - erb: false, - handlebars: false, - php: false, - smarty: false, - angular: false -}; - -// This lets templates appear anywhere we would do a readUntil -// The cost is higher but it is pay to play. -function TemplatablePattern(input_scanner, parent) { - Pattern.call(this, input_scanner, parent); - this.__template_pattern = null; - this._disabled = Object.assign({}, template_names); - this._excluded = Object.assign({}, template_names); - - if (parent) { - this.__template_pattern = this._input.get_regexp(parent.__template_pattern); - this._excluded = Object.assign(this._excluded, parent._excluded); - this._disabled = Object.assign(this._disabled, parent._disabled); - } - var pattern = new Pattern(input_scanner); - this.__patterns = { - handlebars_comment: pattern.starting_with(/{{!--/).until_after(/--}}/), - handlebars_unescaped: pattern.starting_with(/{{{/).until_after(/}}}/), - handlebars: pattern.starting_with(/{{/).until_after(/}}/), - php: pattern.starting_with(/<\?(?:[= ]|php)/).until_after(/\?>/), - erb: pattern.starting_with(/<%[^%]/).until_after(/[^%]%>/), - // django coflicts with handlebars a bit. - django: pattern.starting_with(/{%/).until_after(/%}/), - django_value: pattern.starting_with(/{{/).until_after(/}}/), - django_comment: pattern.starting_with(/{#/).until_after(/#}/), - smarty: pattern.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/), - smarty_comment: pattern.starting_with(/{\*/).until_after(/\*}/), - smarty_literal: pattern.starting_with(/{literal}/).until_after(/{\/literal}/) - }; -} -TemplatablePattern.prototype = new Pattern(); - -TemplatablePattern.prototype._create = function() { - return new TemplatablePattern(this._input, this); -}; - -TemplatablePattern.prototype._update = function() { - this.__set_templated_pattern(); -}; - -TemplatablePattern.prototype.disable = function(language) { - var result = this._create(); - result._disabled[language] = true; - result._update(); - return result; -}; - -TemplatablePattern.prototype.read_options = function(options) { - var result = this._create(); - for (var language in template_names) { - result._disabled[language] = options.templating.indexOf(language) === -1; - } - result._update(); - return result; -}; - -TemplatablePattern.prototype.exclude = function(language) { - var result = this._create(); - result._excluded[language] = true; - result._update(); - return result; -}; - -TemplatablePattern.prototype.read = function() { - var result = ''; - if (this._match_pattern) { - result = this._input.read(this._starting_pattern); - } else { - result = this._input.read(this._starting_pattern, this.__template_pattern); - } - var next = this._read_template(); - while (next) { - if (this._match_pattern) { - next += this._input.read(this._match_pattern); - } else { - next += this._input.readUntil(this.__template_pattern); - } - result += next; - next = this._read_template(); - } - - if (this._until_after) { - result += this._input.readUntilAfter(this._until_pattern); - } - return result; -}; - -TemplatablePattern.prototype.__set_templated_pattern = function() { - var items = []; - - if (!this._disabled.php) { - items.push(this.__patterns.php._starting_pattern.source); - } - if (!this._disabled.handlebars) { - items.push(this.__patterns.handlebars._starting_pattern.source); - } - if (!this._disabled.erb) { - items.push(this.__patterns.erb._starting_pattern.source); - } - if (!this._disabled.django) { - items.push(this.__patterns.django._starting_pattern.source); - // The starting pattern for django is more complex because it has different - // patterns for value, comment, and other sections - items.push(this.__patterns.django_value._starting_pattern.source); - items.push(this.__patterns.django_comment._starting_pattern.source); - } - if (!this._disabled.smarty) { - items.push(this.__patterns.smarty._starting_pattern.source); - } - - if (this._until_pattern) { - items.push(this._until_pattern.source); - } - this.__template_pattern = this._input.get_regexp('(?:' + items.join('|') + ')'); -}; - -TemplatablePattern.prototype._read_template = function() { - var resulting_string = ''; - var c = this._input.peek(); - if (c === '<') { - var peek1 = this._input.peek(1); - //if we're in a comment, do something special - // We treat all comments as literals, even more than preformatted tags - // we just look for the appropriate close tag - if (!this._disabled.php && !this._excluded.php && peek1 === '?') { - resulting_string = resulting_string || - this.__patterns.php.read(); - } - if (!this._disabled.erb && !this._excluded.erb && peek1 === '%') { - resulting_string = resulting_string || - this.__patterns.erb.read(); - } - } else if (c === '{') { - if (!this._disabled.handlebars && !this._excluded.handlebars) { - resulting_string = resulting_string || - this.__patterns.handlebars_comment.read(); - resulting_string = resulting_string || - this.__patterns.handlebars_unescaped.read(); - resulting_string = resulting_string || - this.__patterns.handlebars.read(); - } - if (!this._disabled.django) { - // django coflicts with handlebars a bit. - if (!this._excluded.django && !this._excluded.handlebars) { - resulting_string = resulting_string || - this.__patterns.django_value.read(); - } - if (!this._excluded.django) { - resulting_string = resulting_string || - this.__patterns.django_comment.read(); - resulting_string = resulting_string || - this.__patterns.django.read(); - } - } - if (!this._disabled.smarty) { - // smarty cannot be enabled with django or handlebars enabled - if (this._disabled.django && this._disabled.handlebars) { - resulting_string = resulting_string || - this.__patterns.smarty_comment.read(); - resulting_string = resulting_string || - this.__patterns.smarty_literal.read(); - resulting_string = resulting_string || - this.__patterns.smarty.read(); - } - } - } - return resulting_string; -}; - - -module.exports.TemplatablePattern = TemplatablePattern; - - -/***/ }) -/******/ ]); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module is referenced by other modules so it can't be inlined -/******/ var __webpack_exports__ = __webpack_require__(0); -/******/ legacy_beautify_js = __webpack_exports__; -/******/ -/******/ })() -; -var js_beautify = legacy_beautify_js; -/* Footer */ -if (typeof define === "function" && define.amd) { - // Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- ) - define([], function() { - return { js_beautify: js_beautify }; - }); -} else if (typeof exports !== "undefined") { - // Add support for CommonJS. Just put this file somewhere on your require.paths - // and you will be able to `var js_beautify = require("beautify").js_beautify`. - exports.js_beautify = js_beautify; -} else if (typeof window !== "undefined") { - // If we're running a web page and don't have either of the above, add our one global - window.js_beautify = js_beautify; -} else if (typeof global !== "undefined") { - // If we don't even have window, try global. - global.js_beautify = js_beautify; -} - -}()); - -/* AUTO-GENERATED. DO NOT MODIFY. */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - - CSS Beautifier ---------------- - - Written by Harutyun Amirjanyan, (amirjanyan@gmail.com) - - Based on code initially developed by: Einar Lielmanis, - https://beautifier.io/ - - Usage: - css_beautify(source_text); - css_beautify(source_text, options); - - The options are (default in brackets): - indent_size (4) — indentation size, - indent_char (space) — character to indent with, - selector_separator_newline (true) - separate selectors with newline or - not (e.g. "a,\nbr" or "a, br") - end_with_newline (false) - end with a newline - newline_between_rules (true) - add a new line after every css rule - space_around_selector_separator (false) - ensure space around selector separators: - '>', '+', '~' (e.g. "a>b" -> "a > b") - e.g - - css_beautify(css_source_text, { - 'indent_size': 1, - 'indent_char': '\t', - 'selector_separator': ' ', - 'end_with_newline': false, - 'newline_between_rules': true, - 'space_around_selector_separator': true - }); -*/ - -// http://www.w3.org/TR/CSS21/syndata.html#tokenization -// http://www.w3.org/TR/css3-syntax/ - -(function() { - -/* GENERATED_BUILD_OUTPUT */ -var legacy_beautify_css; -/******/ (function() { // webpackBootstrap -/******/ "use strict"; -/******/ var __webpack_modules__ = ([ -/* 0 */, -/* 1 */, -/* 2 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function OutputLine(parent) { - this.__parent = parent; - this.__character_count = 0; - // use indent_count as a marker for this.__lines that have preserved indentation - this.__indent_count = -1; - this.__alignment_count = 0; - this.__wrap_point_index = 0; - this.__wrap_point_character_count = 0; - this.__wrap_point_indent_count = -1; - this.__wrap_point_alignment_count = 0; - - this.__items = []; -} - -OutputLine.prototype.clone_empty = function() { - var line = new OutputLine(this.__parent); - line.set_indent(this.__indent_count, this.__alignment_count); - return line; -}; - -OutputLine.prototype.item = function(index) { - if (index < 0) { - return this.__items[this.__items.length + index]; - } else { - return this.__items[index]; - } -}; - -OutputLine.prototype.has_match = function(pattern) { - for (var lastCheckedOutput = this.__items.length - 1; lastCheckedOutput >= 0; lastCheckedOutput--) { - if (this.__items[lastCheckedOutput].match(pattern)) { - return true; - } - } - return false; -}; - -OutputLine.prototype.set_indent = function(indent, alignment) { - if (this.is_empty()) { - this.__indent_count = indent || 0; - this.__alignment_count = alignment || 0; - this.__character_count = this.__parent.get_indent_size(this.__indent_count, this.__alignment_count); - } -}; - -OutputLine.prototype._set_wrap_point = function() { - if (this.__parent.wrap_line_length) { - this.__wrap_point_index = this.__items.length; - this.__wrap_point_character_count = this.__character_count; - this.__wrap_point_indent_count = this.__parent.next_line.__indent_count; - this.__wrap_point_alignment_count = this.__parent.next_line.__alignment_count; - } -}; - -OutputLine.prototype._should_wrap = function() { - return this.__wrap_point_index && - this.__character_count > this.__parent.wrap_line_length && - this.__wrap_point_character_count > this.__parent.next_line.__character_count; -}; - -OutputLine.prototype._allow_wrap = function() { - if (this._should_wrap()) { - this.__parent.add_new_line(); - var next = this.__parent.current_line; - next.set_indent(this.__wrap_point_indent_count, this.__wrap_point_alignment_count); - next.__items = this.__items.slice(this.__wrap_point_index); - this.__items = this.__items.slice(0, this.__wrap_point_index); - - next.__character_count += this.__character_count - this.__wrap_point_character_count; - this.__character_count = this.__wrap_point_character_count; - - if (next.__items[0] === " ") { - next.__items.splice(0, 1); - next.__character_count -= 1; - } - return true; - } - return false; -}; - -OutputLine.prototype.is_empty = function() { - return this.__items.length === 0; -}; - -OutputLine.prototype.last = function() { - if (!this.is_empty()) { - return this.__items[this.__items.length - 1]; - } else { - return null; - } -}; - -OutputLine.prototype.push = function(item) { - this.__items.push(item); - var last_newline_index = item.lastIndexOf('\n'); - if (last_newline_index !== -1) { - this.__character_count = item.length - last_newline_index; - } else { - this.__character_count += item.length; - } -}; - -OutputLine.prototype.pop = function() { - var item = null; - if (!this.is_empty()) { - item = this.__items.pop(); - this.__character_count -= item.length; - } - return item; -}; - - -OutputLine.prototype._remove_indent = function() { - if (this.__indent_count > 0) { - this.__indent_count -= 1; - this.__character_count -= this.__parent.indent_size; - } -}; - -OutputLine.prototype._remove_wrap_indent = function() { - if (this.__wrap_point_indent_count > 0) { - this.__wrap_point_indent_count -= 1; - } -}; -OutputLine.prototype.trim = function() { - while (this.last() === ' ') { - this.__items.pop(); - this.__character_count -= 1; - } -}; - -OutputLine.prototype.toString = function() { - var result = ''; - if (this.is_empty()) { - if (this.__parent.indent_empty_lines) { - result = this.__parent.get_indent_string(this.__indent_count); - } - } else { - result = this.__parent.get_indent_string(this.__indent_count, this.__alignment_count); - result += this.__items.join(''); - } - return result; -}; - -function IndentStringCache(options, baseIndentString) { - this.__cache = ['']; - this.__indent_size = options.indent_size; - this.__indent_string = options.indent_char; - if (!options.indent_with_tabs) { - this.__indent_string = new Array(options.indent_size + 1).join(options.indent_char); - } - - // Set to null to continue support for auto detection of base indent - baseIndentString = baseIndentString || ''; - if (options.indent_level > 0) { - baseIndentString = new Array(options.indent_level + 1).join(this.__indent_string); - } - - this.__base_string = baseIndentString; - this.__base_string_length = baseIndentString.length; -} - -IndentStringCache.prototype.get_indent_size = function(indent, column) { - var result = this.__base_string_length; - column = column || 0; - if (indent < 0) { - result = 0; - } - result += indent * this.__indent_size; - result += column; - return result; -}; - -IndentStringCache.prototype.get_indent_string = function(indent_level, column) { - var result = this.__base_string; - column = column || 0; - if (indent_level < 0) { - indent_level = 0; - result = ''; - } - column += indent_level * this.__indent_size; - this.__ensure_cache(column); - result += this.__cache[column]; - return result; -}; - -IndentStringCache.prototype.__ensure_cache = function(column) { - while (column >= this.__cache.length) { - this.__add_column(); - } -}; - -IndentStringCache.prototype.__add_column = function() { - var column = this.__cache.length; - var indent = 0; - var result = ''; - if (this.__indent_size && column >= this.__indent_size) { - indent = Math.floor(column / this.__indent_size); - column -= indent * this.__indent_size; - result = new Array(indent + 1).join(this.__indent_string); - } - if (column) { - result += new Array(column + 1).join(' '); - } - - this.__cache.push(result); -}; - -function Output(options, baseIndentString) { - this.__indent_cache = new IndentStringCache(options, baseIndentString); - this.raw = false; - this._end_with_newline = options.end_with_newline; - this.indent_size = options.indent_size; - this.wrap_line_length = options.wrap_line_length; - this.indent_empty_lines = options.indent_empty_lines; - this.__lines = []; - this.previous_line = null; - this.current_line = null; - this.next_line = new OutputLine(this); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = false; - // initialize - this.__add_outputline(); -} - -Output.prototype.__add_outputline = function() { - this.previous_line = this.current_line; - this.current_line = this.next_line.clone_empty(); - this.__lines.push(this.current_line); -}; - -Output.prototype.get_line_number = function() { - return this.__lines.length; -}; - -Output.prototype.get_indent_string = function(indent, column) { - return this.__indent_cache.get_indent_string(indent, column); -}; - -Output.prototype.get_indent_size = function(indent, column) { - return this.__indent_cache.get_indent_size(indent, column); -}; - -Output.prototype.is_empty = function() { - return !this.previous_line && this.current_line.is_empty(); -}; - -Output.prototype.add_new_line = function(force_newline) { - // never newline at the start of file - // otherwise, newline only if we didn't just add one or we're forced - if (this.is_empty() || - (!force_newline && this.just_added_newline())) { - return false; - } - - // if raw output is enabled, don't print additional newlines, - // but still return True as though you had - if (!this.raw) { - this.__add_outputline(); - } - return true; -}; - -Output.prototype.get_code = function(eol) { - this.trim(true); - - // handle some edge cases where the last tokens - // has text that ends with newline(s) - var last_item = this.current_line.pop(); - if (last_item) { - if (last_item[last_item.length - 1] === '\n') { - last_item = last_item.replace(/\n+$/g, ''); - } - this.current_line.push(last_item); - } - - if (this._end_with_newline) { - this.__add_outputline(); - } - - var sweet_code = this.__lines.join('\n'); - - if (eol !== '\n') { - sweet_code = sweet_code.replace(/[\n]/g, eol); - } - return sweet_code; -}; - -Output.prototype.set_wrap_point = function() { - this.current_line._set_wrap_point(); -}; - -Output.prototype.set_indent = function(indent, alignment) { - indent = indent || 0; - alignment = alignment || 0; - - // Next line stores alignment values - this.next_line.set_indent(indent, alignment); - - // Never indent your first output indent at the start of the file - if (this.__lines.length > 1) { - this.current_line.set_indent(indent, alignment); - return true; - } - - this.current_line.set_indent(); - return false; -}; - -Output.prototype.add_raw_token = function(token) { - for (var x = 0; x < token.newlines; x++) { - this.__add_outputline(); - } - this.current_line.set_indent(-1); - this.current_line.push(token.whitespace_before); - this.current_line.push(token.text); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = false; -}; - -Output.prototype.add_token = function(printable_token) { - this.__add_space_before_token(); - this.current_line.push(printable_token); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = this.current_line._allow_wrap(); -}; - -Output.prototype.__add_space_before_token = function() { - if (this.space_before_token && !this.just_added_newline()) { - if (!this.non_breaking_space) { - this.set_wrap_point(); - } - this.current_line.push(' '); - } -}; - -Output.prototype.remove_indent = function(index) { - var output_length = this.__lines.length; - while (index < output_length) { - this.__lines[index]._remove_indent(); - index++; - } - this.current_line._remove_wrap_indent(); -}; - -Output.prototype.trim = function(eat_newlines) { - eat_newlines = (eat_newlines === undefined) ? false : eat_newlines; - - this.current_line.trim(); - - while (eat_newlines && this.__lines.length > 1 && - this.current_line.is_empty()) { - this.__lines.pop(); - this.current_line = this.__lines[this.__lines.length - 1]; - this.current_line.trim(); - } - - this.previous_line = this.__lines.length > 1 ? - this.__lines[this.__lines.length - 2] : null; -}; - -Output.prototype.just_added_newline = function() { - return this.current_line.is_empty(); -}; - -Output.prototype.just_added_blankline = function() { - return this.is_empty() || - (this.current_line.is_empty() && this.previous_line.is_empty()); -}; - -Output.prototype.ensure_empty_line_above = function(starts_with, ends_with) { - var index = this.__lines.length - 2; - while (index >= 0) { - var potentialEmptyLine = this.__lines[index]; - if (potentialEmptyLine.is_empty()) { - break; - } else if (potentialEmptyLine.item(0).indexOf(starts_with) !== 0 && - potentialEmptyLine.item(-1) !== ends_with) { - this.__lines.splice(index + 1, 0, new OutputLine(this)); - this.previous_line = this.__lines[this.__lines.length - 2]; - break; - } - index--; - } -}; - -module.exports.Output = Output; - - -/***/ }), -/* 3 */, -/* 4 */, -/* 5 */, -/* 6 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Options(options, merge_child_field) { - this.raw_options = _mergeOpts(options, merge_child_field); - - // Support passing the source text back with no change - this.disabled = this._get_boolean('disabled'); - - this.eol = this._get_characters('eol', 'auto'); - this.end_with_newline = this._get_boolean('end_with_newline'); - this.indent_size = this._get_number('indent_size', 4); - this.indent_char = this._get_characters('indent_char', ' '); - this.indent_level = this._get_number('indent_level'); - - this.preserve_newlines = this._get_boolean('preserve_newlines', true); - this.max_preserve_newlines = this._get_number('max_preserve_newlines', 32786); - if (!this.preserve_newlines) { - this.max_preserve_newlines = 0; - } - - this.indent_with_tabs = this._get_boolean('indent_with_tabs', this.indent_char === '\t'); - if (this.indent_with_tabs) { - this.indent_char = '\t'; - - // indent_size behavior changed after 1.8.6 - // It used to be that indent_size would be - // set to 1 for indent_with_tabs. That is no longer needed and - // actually doesn't make sense - why not use spaces? Further, - // that might produce unexpected behavior - tabs being used - // for single-column alignment. So, when indent_with_tabs is true - // and indent_size is 1, reset indent_size to 4. - if (this.indent_size === 1) { - this.indent_size = 4; - } - } - - // Backwards compat with 1.3.x - this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char')); - - this.indent_empty_lines = this._get_boolean('indent_empty_lines'); - - // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular'] - // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css). - // other values ignored - this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']); -} - -Options.prototype._get_array = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = default_value || []; - if (typeof option_value === 'object') { - if (option_value !== null && typeof option_value.concat === 'function') { - result = option_value.concat(); - } - } else if (typeof option_value === 'string') { - result = option_value.split(/[^a-zA-Z0-9_\/\-]+/); - } - return result; -}; - -Options.prototype._get_boolean = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = option_value === undefined ? !!default_value : !!option_value; - return result; -}; - -Options.prototype._get_characters = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = default_value || ''; - if (typeof option_value === 'string') { - result = option_value.replace(/\\r/, '\r').replace(/\\n/, '\n').replace(/\\t/, '\t'); - } - return result; -}; - -Options.prototype._get_number = function(name, default_value) { - var option_value = this.raw_options[name]; - default_value = parseInt(default_value, 10); - if (isNaN(default_value)) { - default_value = 0; - } - var result = parseInt(option_value, 10); - if (isNaN(result)) { - result = default_value; - } - return result; -}; - -Options.prototype._get_selection = function(name, selection_list, default_value) { - var result = this._get_selection_list(name, selection_list, default_value); - if (result.length !== 1) { - throw new Error( - "Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" + - selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); - } - - return result[0]; -}; - - -Options.prototype._get_selection_list = function(name, selection_list, default_value) { - if (!selection_list || selection_list.length === 0) { - throw new Error("Selection list cannot be empty."); - } - - default_value = default_value || [selection_list[0]]; - if (!this._is_valid_selection(default_value, selection_list)) { - throw new Error("Invalid Default Value!"); - } - - var result = this._get_array(name, default_value); - if (!this._is_valid_selection(result, selection_list)) { - throw new Error( - "Invalid Option Value: The option '" + name + "' can contain only the following values:\n" + - selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); - } - - return result; -}; - -Options.prototype._is_valid_selection = function(result, selection_list) { - return result.length && selection_list.length && - !result.some(function(item) { return selection_list.indexOf(item) === -1; }); -}; - - -// merges child options up with the parent options object -// Example: obj = {a: 1, b: {a: 2}} -// mergeOpts(obj, 'b') -// -// Returns: {a: 2} -function _mergeOpts(allOptions, childFieldName) { - var finalOpts = {}; - allOptions = _normalizeOpts(allOptions); - var name; - - for (name in allOptions) { - if (name !== childFieldName) { - finalOpts[name] = allOptions[name]; - } - } - - //merge in the per type settings for the childFieldName - if (childFieldName && allOptions[childFieldName]) { - for (name in allOptions[childFieldName]) { - finalOpts[name] = allOptions[childFieldName][name]; - } - } - return finalOpts; -} - -function _normalizeOpts(options) { - var convertedOpts = {}; - var key; - - for (key in options) { - var newKey = key.replace(/-/g, "_"); - convertedOpts[newKey] = options[key]; - } - return convertedOpts; -} - -module.exports.Options = Options; -module.exports.normalizeOpts = _normalizeOpts; -module.exports.mergeOpts = _mergeOpts; - - -/***/ }), -/* 7 */, -/* 8 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var regexp_has_sticky = RegExp.prototype.hasOwnProperty('sticky'); - -function InputScanner(input_string) { - this.__input = input_string || ''; - this.__input_length = this.__input.length; - this.__position = 0; -} - -InputScanner.prototype.restart = function() { - this.__position = 0; -}; - -InputScanner.prototype.back = function() { - if (this.__position > 0) { - this.__position -= 1; - } -}; - -InputScanner.prototype.hasNext = function() { - return this.__position < this.__input_length; -}; - -InputScanner.prototype.next = function() { - var val = null; - if (this.hasNext()) { - val = this.__input.charAt(this.__position); - this.__position += 1; - } - return val; -}; - -InputScanner.prototype.peek = function(index) { - var val = null; - index = index || 0; - index += this.__position; - if (index >= 0 && index < this.__input_length) { - val = this.__input.charAt(index); - } - return val; -}; - -// This is a JavaScript only helper function (not in python) -// Javascript doesn't have a match method -// and not all implementation support "sticky" flag. -// If they do not support sticky then both this.match() and this.test() method -// must get the match and check the index of the match. -// If sticky is supported and set, this method will use it. -// Otherwise it will check that global is set, and fall back to the slower method. -InputScanner.prototype.__match = function(pattern, index) { - pattern.lastIndex = index; - var pattern_match = pattern.exec(this.__input); - - if (pattern_match && !(regexp_has_sticky && pattern.sticky)) { - if (pattern_match.index !== index) { - pattern_match = null; - } - } - - return pattern_match; -}; - -InputScanner.prototype.test = function(pattern, index) { - index = index || 0; - index += this.__position; - - if (index >= 0 && index < this.__input_length) { - return !!this.__match(pattern, index); - } else { - return false; - } -}; - -InputScanner.prototype.testChar = function(pattern, index) { - // test one character regex match - var val = this.peek(index); - pattern.lastIndex = 0; - return val !== null && pattern.test(val); -}; - -InputScanner.prototype.match = function(pattern) { - var pattern_match = this.__match(pattern, this.__position); - if (pattern_match) { - this.__position += pattern_match[0].length; - } else { - pattern_match = null; - } - return pattern_match; -}; - -InputScanner.prototype.read = function(starting_pattern, until_pattern, until_after) { - var val = ''; - var match; - if (starting_pattern) { - match = this.match(starting_pattern); - if (match) { - val += match[0]; - } - } - if (until_pattern && (match || !starting_pattern)) { - val += this.readUntil(until_pattern, until_after); - } - return val; -}; - -InputScanner.prototype.readUntil = function(pattern, until_after) { - var val = ''; - var match_index = this.__position; - pattern.lastIndex = this.__position; - var pattern_match = pattern.exec(this.__input); - if (pattern_match) { - match_index = pattern_match.index; - if (until_after) { - match_index += pattern_match[0].length; - } - } else { - match_index = this.__input_length; - } - - val = this.__input.substring(this.__position, match_index); - this.__position = match_index; - return val; -}; - -InputScanner.prototype.readUntilAfter = function(pattern) { - return this.readUntil(pattern, true); -}; - -InputScanner.prototype.get_regexp = function(pattern, match_from) { - var result = null; - var flags = 'g'; - if (match_from && regexp_has_sticky) { - flags = 'y'; - } - // strings are converted to regexp - if (typeof pattern === "string" && pattern !== '') { - // result = new RegExp(pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), flags); - result = new RegExp(pattern, flags); - } else if (pattern) { - result = new RegExp(pattern.source, flags); - } - return result; -}; - -InputScanner.prototype.get_literal_regexp = function(literal_string) { - return RegExp(literal_string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); -}; - -/* css beautifier legacy helpers */ -InputScanner.prototype.peekUntilAfter = function(pattern) { - var start = this.__position; - var val = this.readUntilAfter(pattern); - this.__position = start; - return val; -}; - -InputScanner.prototype.lookBack = function(testVal) { - var start = this.__position - 1; - return start >= testVal.length && this.__input.substring(start - testVal.length, start) - .toLowerCase() === testVal; -}; - -module.exports.InputScanner = InputScanner; - - -/***/ }), -/* 9 */, -/* 10 */, -/* 11 */, -/* 12 */, -/* 13 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Directives(start_block_pattern, end_block_pattern) { - start_block_pattern = typeof start_block_pattern === 'string' ? start_block_pattern : start_block_pattern.source; - end_block_pattern = typeof end_block_pattern === 'string' ? end_block_pattern : end_block_pattern.source; - this.__directives_block_pattern = new RegExp(start_block_pattern + / beautify( \w+[:]\w+)+ /.source + end_block_pattern, 'g'); - this.__directive_pattern = / (\w+)[:](\w+)/g; - - this.__directives_end_ignore_pattern = new RegExp(start_block_pattern + /\sbeautify\signore:end\s/.source + end_block_pattern, 'g'); -} - -Directives.prototype.get_directives = function(text) { - if (!text.match(this.__directives_block_pattern)) { - return null; - } - - var directives = {}; - this.__directive_pattern.lastIndex = 0; - var directive_match = this.__directive_pattern.exec(text); - - while (directive_match) { - directives[directive_match[1]] = directive_match[2]; - directive_match = this.__directive_pattern.exec(text); - } - - return directives; -}; - -Directives.prototype.readIgnored = function(input) { - return input.readUntilAfter(this.__directives_end_ignore_pattern); -}; - - -module.exports.Directives = Directives; - - -/***/ }), -/* 14 */, -/* 15 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Beautifier = (__webpack_require__(16).Beautifier), - Options = (__webpack_require__(17).Options); - -function css_beautify(source_text, options) { - var beautifier = new Beautifier(source_text, options); - return beautifier.beautify(); -} - -module.exports = css_beautify; -module.exports.defaultOptions = function() { - return new Options(); -}; - - -/***/ }), -/* 16 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Options = (__webpack_require__(17).Options); -var Output = (__webpack_require__(2).Output); -var InputScanner = (__webpack_require__(8).InputScanner); -var Directives = (__webpack_require__(13).Directives); - -var directives_core = new Directives(/\/\*/, /\*\//); - -var lineBreak = /\r\n|[\r\n]/; -var allLineBreaks = /\r\n|[\r\n]/g; - -// tokenizer -var whitespaceChar = /\s/; -var whitespacePattern = /(?:\s|\n)+/g; -var block_comment_pattern = /\/\*(?:[\s\S]*?)((?:\*\/)|$)/g; -var comment_pattern = /\/\/(?:[^\n\r\u2028\u2029]*)/g; - -function Beautifier(source_text, options) { - this._source_text = source_text || ''; - // Allow the setting of language/file-type specific options - // with inheritance of overall settings - this._options = new Options(options); - this._ch = null; - this._input = null; - - // https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule - this.NESTED_AT_RULE = { - "page": true, - "font-face": true, - "keyframes": true, - // also in CONDITIONAL_GROUP_RULE below - "media": true, - "supports": true, - "document": true - }; - this.CONDITIONAL_GROUP_RULE = { - "media": true, - "supports": true, - "document": true - }; - this.NON_SEMICOLON_NEWLINE_PROPERTY = [ - "grid-template-areas", - "grid-template" - ]; - -} - -Beautifier.prototype.eatString = function(endChars) { - var result = ''; - this._ch = this._input.next(); - while (this._ch) { - result += this._ch; - if (this._ch === "\\") { - result += this._input.next(); - } else if (endChars.indexOf(this._ch) !== -1 || this._ch === "\n") { - break; - } - this._ch = this._input.next(); - } - return result; -}; - -// Skips any white space in the source text from the current position. -// When allowAtLeastOneNewLine is true, will output new lines for each -// newline character found; if the user has preserve_newlines off, only -// the first newline will be output -Beautifier.prototype.eatWhitespace = function(allowAtLeastOneNewLine) { - var result = whitespaceChar.test(this._input.peek()); - var newline_count = 0; - while (whitespaceChar.test(this._input.peek())) { - this._ch = this._input.next(); - if (allowAtLeastOneNewLine && this._ch === '\n') { - if (newline_count === 0 || newline_count < this._options.max_preserve_newlines) { - newline_count++; - this._output.add_new_line(true); - } - } - } - return result; -}; - -// Nested pseudo-class if we are insideRule -// and the next special character found opens -// a new block -Beautifier.prototype.foundNestedPseudoClass = function() { - var openParen = 0; - var i = 1; - var ch = this._input.peek(i); - while (ch) { - if (ch === "{") { - return true; - } else if (ch === '(') { - // pseudoclasses can contain () - openParen += 1; - } else if (ch === ')') { - if (openParen === 0) { - return false; - } - openParen -= 1; - } else if (ch === ";" || ch === "}") { - return false; - } - i++; - ch = this._input.peek(i); - } - return false; -}; - -Beautifier.prototype.print_string = function(output_string) { - this._output.set_indent(this._indentLevel); - this._output.non_breaking_space = true; - this._output.add_token(output_string); -}; - -Beautifier.prototype.preserveSingleSpace = function(isAfterSpace) { - if (isAfterSpace) { - this._output.space_before_token = true; - } -}; - -Beautifier.prototype.indent = function() { - this._indentLevel++; -}; - -Beautifier.prototype.outdent = function() { - if (this._indentLevel > 0) { - this._indentLevel--; - } -}; - -/*_____________________--------------------_____________________*/ - -Beautifier.prototype.beautify = function() { - if (this._options.disabled) { - return this._source_text; - } - - var source_text = this._source_text; - var eol = this._options.eol; - if (eol === 'auto') { - eol = '\n'; - if (source_text && lineBreak.test(source_text || '')) { - eol = source_text.match(lineBreak)[0]; - } - } - - - // HACK: newline parsing inconsistent. This brute force normalizes the this._input. - source_text = source_text.replace(allLineBreaks, '\n'); - - // reset - var baseIndentString = source_text.match(/^[\t ]*/)[0]; - - this._output = new Output(this._options, baseIndentString); - this._input = new InputScanner(source_text); - this._indentLevel = 0; - this._nestedLevel = 0; - - this._ch = null; - var parenLevel = 0; - - var insideRule = false; - // This is the value side of a property value pair (blue in the following ex) - // label { content: blue } - var insidePropertyValue = false; - var enteringConditionalGroup = false; - var insideNonNestedAtRule = false; - var insideScssMap = false; - var topCharacter = this._ch; - var insideNonSemiColonValues = false; - var whitespace; - var isAfterSpace; - var previous_ch; - - while (true) { - whitespace = this._input.read(whitespacePattern); - isAfterSpace = whitespace !== ''; - previous_ch = topCharacter; - this._ch = this._input.next(); - if (this._ch === '\\' && this._input.hasNext()) { - this._ch += this._input.next(); - } - topCharacter = this._ch; - - if (!this._ch) { - break; - } else if (this._ch === '/' && this._input.peek() === '*') { - // /* css comment */ - // Always start block comments on a new line. - // This handles scenarios where a block comment immediately - // follows a property definition on the same line or where - // minified code is being beautified. - this._output.add_new_line(); - this._input.back(); - - var comment = this._input.read(block_comment_pattern); - - // Handle ignore directive - var directives = directives_core.get_directives(comment); - if (directives && directives.ignore === 'start') { - comment += directives_core.readIgnored(this._input); - } - - this.print_string(comment); - - // Ensures any new lines following the comment are preserved - this.eatWhitespace(true); - - // Block comments are followed by a new line so they don't - // share a line with other properties - this._output.add_new_line(); - } else if (this._ch === '/' && this._input.peek() === '/') { - // // single line comment - // Preserves the space before a comment - // on the same line as a rule - this._output.space_before_token = true; - this._input.back(); - this.print_string(this._input.read(comment_pattern)); - - // Ensures any new lines following the comment are preserved - this.eatWhitespace(true); - } else if (this._ch === '$') { - this.preserveSingleSpace(isAfterSpace); - - this.print_string(this._ch); - - // strip trailing space, if present, for hash property checks - var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g); - - if (variable.match(/[ :]$/)) { - // we have a variable or pseudo-class, add it and insert one space before continuing - variable = this.eatString(": ").replace(/\s+$/, ''); - this.print_string(variable); - this._output.space_before_token = true; - } - - // might be sass variable - if (parenLevel === 0 && variable.indexOf(':') !== -1) { - insidePropertyValue = true; - this.indent(); - } - } else if (this._ch === '@') { - this.preserveSingleSpace(isAfterSpace); - - // deal with less property mixins @{...} - if (this._input.peek() === '{') { - this.print_string(this._ch + this.eatString('}')); - } else { - this.print_string(this._ch); - - // strip trailing space, if present, for hash property checks - var variableOrRule = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g); - - if (variableOrRule.match(/[ :]$/)) { - // we have a variable or pseudo-class, add it and insert one space before continuing - variableOrRule = this.eatString(": ").replace(/\s+$/, ''); - this.print_string(variableOrRule); - this._output.space_before_token = true; - } - - // might be less variable - if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) { - insidePropertyValue = true; - this.indent(); - - // might be a nesting at-rule - } else if (variableOrRule in this.NESTED_AT_RULE) { - this._nestedLevel += 1; - if (variableOrRule in this.CONDITIONAL_GROUP_RULE) { - enteringConditionalGroup = true; - } - - // might be a non-nested at-rule - } else if (parenLevel === 0 && !insidePropertyValue) { - insideNonNestedAtRule = true; - } - } - } else if (this._ch === '#' && this._input.peek() === '{') { - this.preserveSingleSpace(isAfterSpace); - this.print_string(this._ch + this.eatString('}')); - } else if (this._ch === '{') { - if (insidePropertyValue) { - insidePropertyValue = false; - this.outdent(); - } - - // non nested at rule becomes nested - insideNonNestedAtRule = false; - - // when entering conditional groups, only rulesets are allowed - if (enteringConditionalGroup) { - enteringConditionalGroup = false; - insideRule = (this._indentLevel >= this._nestedLevel); - } else { - // otherwise, declarations are also allowed - insideRule = (this._indentLevel >= this._nestedLevel - 1); - } - if (this._options.newline_between_rules && insideRule) { - if (this._output.previous_line && this._output.previous_line.item(-1) !== '{') { - this._output.ensure_empty_line_above('/', ','); - } - } - - this._output.space_before_token = true; - - // The difference in print_string and indent order is necessary to indent the '{' correctly - if (this._options.brace_style === 'expand') { - this._output.add_new_line(); - this.print_string(this._ch); - this.indent(); - this._output.set_indent(this._indentLevel); - } else { - // inside mixin and first param is object - if (previous_ch === '(') { - this._output.space_before_token = false; - } else if (previous_ch !== ',') { - this.indent(); - } - this.print_string(this._ch); - } - - this.eatWhitespace(true); - this._output.add_new_line(); - } else if (this._ch === '}') { - this.outdent(); - this._output.add_new_line(); - if (previous_ch === '{') { - this._output.trim(true); - } - - if (insidePropertyValue) { - this.outdent(); - insidePropertyValue = false; - } - this.print_string(this._ch); - insideRule = false; - if (this._nestedLevel) { - this._nestedLevel--; - } - - this.eatWhitespace(true); - this._output.add_new_line(); - - if (this._options.newline_between_rules && !this._output.just_added_blankline()) { - if (this._input.peek() !== '}') { - this._output.add_new_line(true); - } - } - if (this._input.peek() === ')') { - this._output.trim(true); - if (this._options.brace_style === "expand") { - this._output.add_new_line(true); - } - } - } else if (this._ch === ":") { - - for (var i = 0; i < this.NON_SEMICOLON_NEWLINE_PROPERTY.length; i++) { - if (this._input.lookBack(this.NON_SEMICOLON_NEWLINE_PROPERTY[i])) { - insideNonSemiColonValues = true; - break; - } - } - - if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) { - // 'property: value' delimiter - // which could be in a conditional group query - - this.print_string(':'); - if (!insidePropertyValue) { - insidePropertyValue = true; - this._output.space_before_token = true; - this.eatWhitespace(true); - this.indent(); - } - } else { - // sass/less parent reference don't use a space - // sass nested pseudo-class don't use a space - - // preserve space before pseudoclasses/pseudoelements, as it means "in any child" - if (this._input.lookBack(" ")) { - this._output.space_before_token = true; - } - if (this._input.peek() === ":") { - // pseudo-element - this._ch = this._input.next(); - this.print_string("::"); - } else { - // pseudo-class - this.print_string(':'); - } - } - } else if (this._ch === '"' || this._ch === '\'') { - var preserveQuoteSpace = previous_ch === '"' || previous_ch === '\''; - this.preserveSingleSpace(preserveQuoteSpace || isAfterSpace); - this.print_string(this._ch + this.eatString(this._ch)); - this.eatWhitespace(true); - } else if (this._ch === ';') { - insideNonSemiColonValues = false; - if (parenLevel === 0) { - if (insidePropertyValue) { - this.outdent(); - insidePropertyValue = false; - } - insideNonNestedAtRule = false; - this.print_string(this._ch); - this.eatWhitespace(true); - - // This maintains single line comments on the same - // line. Block comments are also affected, but - // a new line is always output before one inside - // that section - if (this._input.peek() !== '/') { - this._output.add_new_line(); - } - } else { - this.print_string(this._ch); - this.eatWhitespace(true); - this._output.space_before_token = true; - } - } else if (this._ch === '(') { // may be a url - if (this._input.lookBack("url")) { - this.print_string(this._ch); - this.eatWhitespace(); - parenLevel++; - this.indent(); - this._ch = this._input.next(); - if (this._ch === ')' || this._ch === '"' || this._ch === '\'') { - this._input.back(); - } else if (this._ch) { - this.print_string(this._ch + this.eatString(')')); - if (parenLevel) { - parenLevel--; - this.outdent(); - } - } - } else { - var space_needed = false; - if (this._input.lookBack("with")) { - // look back is not an accurate solution, we need tokens to confirm without whitespaces - space_needed = true; - } - this.preserveSingleSpace(isAfterSpace || space_needed); - this.print_string(this._ch); - - // handle scss/sass map - if (insidePropertyValue && previous_ch === "$" && this._options.selector_separator_newline) { - this._output.add_new_line(); - insideScssMap = true; - } else { - this.eatWhitespace(); - parenLevel++; - this.indent(); - } - } - } else if (this._ch === ')') { - if (parenLevel) { - parenLevel--; - this.outdent(); - } - if (insideScssMap && this._input.peek() === ";" && this._options.selector_separator_newline) { - insideScssMap = false; - this.outdent(); - this._output.add_new_line(); - } - this.print_string(this._ch); - } else if (this._ch === ',') { - this.print_string(this._ch); - this.eatWhitespace(true); - if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) { - this._output.add_new_line(); - } else { - this._output.space_before_token = true; - } - } else if ((this._ch === '>' || this._ch === '+' || this._ch === '~') && !insidePropertyValue && parenLevel === 0) { - //handle combinator spacing - if (this._options.space_around_combinator) { - this._output.space_before_token = true; - this.print_string(this._ch); - this._output.space_before_token = true; - } else { - this.print_string(this._ch); - this.eatWhitespace(); - // squash extra whitespace - if (this._ch && whitespaceChar.test(this._ch)) { - this._ch = ''; - } - } - } else if (this._ch === ']') { - this.print_string(this._ch); - } else if (this._ch === '[') { - this.preserveSingleSpace(isAfterSpace); - this.print_string(this._ch); - } else if (this._ch === '=') { // no whitespace before or after - this.eatWhitespace(); - this.print_string('='); - if (whitespaceChar.test(this._ch)) { - this._ch = ''; - } - } else if (this._ch === '!' && !this._input.lookBack("\\")) { // !important - this._output.space_before_token = true; - this.print_string(this._ch); - } else { - var preserveAfterSpace = previous_ch === '"' || previous_ch === '\''; - this.preserveSingleSpace(preserveAfterSpace || isAfterSpace); - this.print_string(this._ch); - - if (!this._output.just_added_newline() && this._input.peek() === '\n' && insideNonSemiColonValues) { - this._output.add_new_line(); - } - } - } - - var sweetCode = this._output.get_code(eol); - - return sweetCode; -}; - -module.exports.Beautifier = Beautifier; - - -/***/ }), -/* 17 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var BaseOptions = (__webpack_require__(6).Options); - -function Options(options) { - BaseOptions.call(this, options, 'css'); - - this.selector_separator_newline = this._get_boolean('selector_separator_newline', true); - this.newline_between_rules = this._get_boolean('newline_between_rules', true); - var space_around_selector_separator = this._get_boolean('space_around_selector_separator'); - this.space_around_combinator = this._get_boolean('space_around_combinator') || space_around_selector_separator; - - var brace_style_split = this._get_selection_list('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline']); - this.brace_style = 'collapse'; - for (var bs = 0; bs < brace_style_split.length; bs++) { - if (brace_style_split[bs] !== 'expand') { - // default to collapse, as only collapse|expand is implemented for now - this.brace_style = 'collapse'; - } else { - this.brace_style = brace_style_split[bs]; - } - } -} -Options.prototype = new BaseOptions(); - - - -module.exports.Options = Options; - - -/***/ }) -/******/ ]); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module is referenced by other modules so it can't be inlined -/******/ var __webpack_exports__ = __webpack_require__(15); -/******/ legacy_beautify_css = __webpack_exports__; -/******/ -/******/ })() -; -var css_beautify = legacy_beautify_css; -/* Footer */ -if (typeof define === "function" && define.amd) { - // Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- ) - define([], function() { - return { - css_beautify: css_beautify - }; - }); -} else if (typeof exports !== "undefined") { - // Add support for CommonJS. Just put this file somewhere on your require.paths - // and you will be able to `var html_beautify = require("beautify").html_beautify`. - exports.css_beautify = css_beautify; -} else if (typeof window !== "undefined") { - // If we're running a web page and don't have either of the above, add our one global - window.css_beautify = css_beautify; -} else if (typeof global !== "undefined") { - // If we don't even have window, try global. - global.css_beautify = css_beautify; -} - -}()); -/* AUTO-GENERATED. DO NOT MODIFY. */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - - Style HTML ---------------- - - Written by Nochum Sossonko, (nsossonko@hotmail.com) - - Based on code initially developed by: Einar Lielmanis, - https://beautifier.io/ - - Usage: - style_html(html_source); - - style_html(html_source, options); - - The options are: - indent_inner_html (default false) — indent and sections, - indent_size (default 4) — indentation size, - indent_char (default space) — character to indent with, - wrap_line_length (default 250) - maximum amount of characters per line (0 = disable) - brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none" - put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are. - inline (defaults to inline tags) - list of tags to be considered inline tags - unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted - content_unformatted (defaults to ["pre", "textarea"] tags) - list of tags, whose content shouldn't be reformatted - indent_scripts (default normal) - "keep"|"separate"|"normal" - preserve_newlines (default true) - whether existing line breaks before elements should be preserved - Only works before elements, not inside tags or for text. - max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk - indent_handlebars (default false) - format and indent {{#foo}} and {{/foo}} - end_with_newline (false) - end with a newline - extra_liners (default [head,body,/html]) -List of tags that should have an extra newline before them. - - e.g. - - style_html(html_source, { - 'indent_inner_html': false, - 'indent_size': 2, - 'indent_char': ' ', - 'wrap_line_length': 78, - 'brace_style': 'expand', - 'preserve_newlines': true, - 'max_preserve_newlines': 5, - 'indent_handlebars': false, - 'extra_liners': ['/html'] - }); -*/ - -(function() { - -/* GENERATED_BUILD_OUTPUT */ -var legacy_beautify_html; -/******/ (function() { // webpackBootstrap -/******/ "use strict"; -/******/ var __webpack_modules__ = ([ -/* 0 */, -/* 1 */, -/* 2 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function OutputLine(parent) { - this.__parent = parent; - this.__character_count = 0; - // use indent_count as a marker for this.__lines that have preserved indentation - this.__indent_count = -1; - this.__alignment_count = 0; - this.__wrap_point_index = 0; - this.__wrap_point_character_count = 0; - this.__wrap_point_indent_count = -1; - this.__wrap_point_alignment_count = 0; - - this.__items = []; -} - -OutputLine.prototype.clone_empty = function() { - var line = new OutputLine(this.__parent); - line.set_indent(this.__indent_count, this.__alignment_count); - return line; -}; - -OutputLine.prototype.item = function(index) { - if (index < 0) { - return this.__items[this.__items.length + index]; - } else { - return this.__items[index]; - } -}; - -OutputLine.prototype.has_match = function(pattern) { - for (var lastCheckedOutput = this.__items.length - 1; lastCheckedOutput >= 0; lastCheckedOutput--) { - if (this.__items[lastCheckedOutput].match(pattern)) { - return true; - } - } - return false; -}; - -OutputLine.prototype.set_indent = function(indent, alignment) { - if (this.is_empty()) { - this.__indent_count = indent || 0; - this.__alignment_count = alignment || 0; - this.__character_count = this.__parent.get_indent_size(this.__indent_count, this.__alignment_count); - } -}; - -OutputLine.prototype._set_wrap_point = function() { - if (this.__parent.wrap_line_length) { - this.__wrap_point_index = this.__items.length; - this.__wrap_point_character_count = this.__character_count; - this.__wrap_point_indent_count = this.__parent.next_line.__indent_count; - this.__wrap_point_alignment_count = this.__parent.next_line.__alignment_count; - } -}; - -OutputLine.prototype._should_wrap = function() { - return this.__wrap_point_index && - this.__character_count > this.__parent.wrap_line_length && - this.__wrap_point_character_count > this.__parent.next_line.__character_count; -}; - -OutputLine.prototype._allow_wrap = function() { - if (this._should_wrap()) { - this.__parent.add_new_line(); - var next = this.__parent.current_line; - next.set_indent(this.__wrap_point_indent_count, this.__wrap_point_alignment_count); - next.__items = this.__items.slice(this.__wrap_point_index); - this.__items = this.__items.slice(0, this.__wrap_point_index); - - next.__character_count += this.__character_count - this.__wrap_point_character_count; - this.__character_count = this.__wrap_point_character_count; - - if (next.__items[0] === " ") { - next.__items.splice(0, 1); - next.__character_count -= 1; - } - return true; - } - return false; -}; - -OutputLine.prototype.is_empty = function() { - return this.__items.length === 0; -}; - -OutputLine.prototype.last = function() { - if (!this.is_empty()) { - return this.__items[this.__items.length - 1]; - } else { - return null; - } -}; - -OutputLine.prototype.push = function(item) { - this.__items.push(item); - var last_newline_index = item.lastIndexOf('\n'); - if (last_newline_index !== -1) { - this.__character_count = item.length - last_newline_index; - } else { - this.__character_count += item.length; - } -}; - -OutputLine.prototype.pop = function() { - var item = null; - if (!this.is_empty()) { - item = this.__items.pop(); - this.__character_count -= item.length; - } - return item; -}; - - -OutputLine.prototype._remove_indent = function() { - if (this.__indent_count > 0) { - this.__indent_count -= 1; - this.__character_count -= this.__parent.indent_size; - } -}; - -OutputLine.prototype._remove_wrap_indent = function() { - if (this.__wrap_point_indent_count > 0) { - this.__wrap_point_indent_count -= 1; - } -}; -OutputLine.prototype.trim = function() { - while (this.last() === ' ') { - this.__items.pop(); - this.__character_count -= 1; - } -}; - -OutputLine.prototype.toString = function() { - var result = ''; - if (this.is_empty()) { - if (this.__parent.indent_empty_lines) { - result = this.__parent.get_indent_string(this.__indent_count); - } - } else { - result = this.__parent.get_indent_string(this.__indent_count, this.__alignment_count); - result += this.__items.join(''); - } - return result; -}; - -function IndentStringCache(options, baseIndentString) { - this.__cache = ['']; - this.__indent_size = options.indent_size; - this.__indent_string = options.indent_char; - if (!options.indent_with_tabs) { - this.__indent_string = new Array(options.indent_size + 1).join(options.indent_char); - } - - // Set to null to continue support for auto detection of base indent - baseIndentString = baseIndentString || ''; - if (options.indent_level > 0) { - baseIndentString = new Array(options.indent_level + 1).join(this.__indent_string); - } - - this.__base_string = baseIndentString; - this.__base_string_length = baseIndentString.length; -} - -IndentStringCache.prototype.get_indent_size = function(indent, column) { - var result = this.__base_string_length; - column = column || 0; - if (indent < 0) { - result = 0; - } - result += indent * this.__indent_size; - result += column; - return result; -}; - -IndentStringCache.prototype.get_indent_string = function(indent_level, column) { - var result = this.__base_string; - column = column || 0; - if (indent_level < 0) { - indent_level = 0; - result = ''; - } - column += indent_level * this.__indent_size; - this.__ensure_cache(column); - result += this.__cache[column]; - return result; -}; - -IndentStringCache.prototype.__ensure_cache = function(column) { - while (column >= this.__cache.length) { - this.__add_column(); - } -}; - -IndentStringCache.prototype.__add_column = function() { - var column = this.__cache.length; - var indent = 0; - var result = ''; - if (this.__indent_size && column >= this.__indent_size) { - indent = Math.floor(column / this.__indent_size); - column -= indent * this.__indent_size; - result = new Array(indent + 1).join(this.__indent_string); - } - if (column) { - result += new Array(column + 1).join(' '); - } - - this.__cache.push(result); -}; - -function Output(options, baseIndentString) { - this.__indent_cache = new IndentStringCache(options, baseIndentString); - this.raw = false; - this._end_with_newline = options.end_with_newline; - this.indent_size = options.indent_size; - this.wrap_line_length = options.wrap_line_length; - this.indent_empty_lines = options.indent_empty_lines; - this.__lines = []; - this.previous_line = null; - this.current_line = null; - this.next_line = new OutputLine(this); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = false; - // initialize - this.__add_outputline(); -} - -Output.prototype.__add_outputline = function() { - this.previous_line = this.current_line; - this.current_line = this.next_line.clone_empty(); - this.__lines.push(this.current_line); -}; - -Output.prototype.get_line_number = function() { - return this.__lines.length; -}; - -Output.prototype.get_indent_string = function(indent, column) { - return this.__indent_cache.get_indent_string(indent, column); -}; - -Output.prototype.get_indent_size = function(indent, column) { - return this.__indent_cache.get_indent_size(indent, column); -}; - -Output.prototype.is_empty = function() { - return !this.previous_line && this.current_line.is_empty(); -}; - -Output.prototype.add_new_line = function(force_newline) { - // never newline at the start of file - // otherwise, newline only if we didn't just add one or we're forced - if (this.is_empty() || - (!force_newline && this.just_added_newline())) { - return false; - } - - // if raw output is enabled, don't print additional newlines, - // but still return True as though you had - if (!this.raw) { - this.__add_outputline(); - } - return true; -}; - -Output.prototype.get_code = function(eol) { - this.trim(true); - - // handle some edge cases where the last tokens - // has text that ends with newline(s) - var last_item = this.current_line.pop(); - if (last_item) { - if (last_item[last_item.length - 1] === '\n') { - last_item = last_item.replace(/\n+$/g, ''); - } - this.current_line.push(last_item); - } - - if (this._end_with_newline) { - this.__add_outputline(); - } - - var sweet_code = this.__lines.join('\n'); - - if (eol !== '\n') { - sweet_code = sweet_code.replace(/[\n]/g, eol); - } - return sweet_code; -}; - -Output.prototype.set_wrap_point = function() { - this.current_line._set_wrap_point(); -}; - -Output.prototype.set_indent = function(indent, alignment) { - indent = indent || 0; - alignment = alignment || 0; - - // Next line stores alignment values - this.next_line.set_indent(indent, alignment); - - // Never indent your first output indent at the start of the file - if (this.__lines.length > 1) { - this.current_line.set_indent(indent, alignment); - return true; - } - - this.current_line.set_indent(); - return false; -}; - -Output.prototype.add_raw_token = function(token) { - for (var x = 0; x < token.newlines; x++) { - this.__add_outputline(); - } - this.current_line.set_indent(-1); - this.current_line.push(token.whitespace_before); - this.current_line.push(token.text); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = false; -}; - -Output.prototype.add_token = function(printable_token) { - this.__add_space_before_token(); - this.current_line.push(printable_token); - this.space_before_token = false; - this.non_breaking_space = false; - this.previous_token_wrapped = this.current_line._allow_wrap(); -}; - -Output.prototype.__add_space_before_token = function() { - if (this.space_before_token && !this.just_added_newline()) { - if (!this.non_breaking_space) { - this.set_wrap_point(); - } - this.current_line.push(' '); - } -}; - -Output.prototype.remove_indent = function(index) { - var output_length = this.__lines.length; - while (index < output_length) { - this.__lines[index]._remove_indent(); - index++; - } - this.current_line._remove_wrap_indent(); -}; - -Output.prototype.trim = function(eat_newlines) { - eat_newlines = (eat_newlines === undefined) ? false : eat_newlines; - - this.current_line.trim(); - - while (eat_newlines && this.__lines.length > 1 && - this.current_line.is_empty()) { - this.__lines.pop(); - this.current_line = this.__lines[this.__lines.length - 1]; - this.current_line.trim(); - } - - this.previous_line = this.__lines.length > 1 ? - this.__lines[this.__lines.length - 2] : null; -}; - -Output.prototype.just_added_newline = function() { - return this.current_line.is_empty(); -}; - -Output.prototype.just_added_blankline = function() { - return this.is_empty() || - (this.current_line.is_empty() && this.previous_line.is_empty()); -}; - -Output.prototype.ensure_empty_line_above = function(starts_with, ends_with) { - var index = this.__lines.length - 2; - while (index >= 0) { - var potentialEmptyLine = this.__lines[index]; - if (potentialEmptyLine.is_empty()) { - break; - } else if (potentialEmptyLine.item(0).indexOf(starts_with) !== 0 && - potentialEmptyLine.item(-1) !== ends_with) { - this.__lines.splice(index + 1, 0, new OutputLine(this)); - this.previous_line = this.__lines[this.__lines.length - 2]; - break; - } - index--; - } -}; - -module.exports.Output = Output; - - -/***/ }), -/* 3 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Token(type, text, newlines, whitespace_before) { - this.type = type; - this.text = text; - - // comments_before are - // comments that have a new line before them - // and may or may not have a newline after - // this is a set of comments before - this.comments_before = null; /* inline comment*/ - - - // this.comments_after = new TokenStream(); // no new line before and newline after - this.newlines = newlines || 0; - this.whitespace_before = whitespace_before || ''; - this.parent = null; - this.next = null; - this.previous = null; - this.opened = null; - this.closed = null; - this.directives = null; -} - - -module.exports.Token = Token; - - -/***/ }), -/* 4 */, -/* 5 */, -/* 6 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Options(options, merge_child_field) { - this.raw_options = _mergeOpts(options, merge_child_field); - - // Support passing the source text back with no change - this.disabled = this._get_boolean('disabled'); - - this.eol = this._get_characters('eol', 'auto'); - this.end_with_newline = this._get_boolean('end_with_newline'); - this.indent_size = this._get_number('indent_size', 4); - this.indent_char = this._get_characters('indent_char', ' '); - this.indent_level = this._get_number('indent_level'); - - this.preserve_newlines = this._get_boolean('preserve_newlines', true); - this.max_preserve_newlines = this._get_number('max_preserve_newlines', 32786); - if (!this.preserve_newlines) { - this.max_preserve_newlines = 0; - } - - this.indent_with_tabs = this._get_boolean('indent_with_tabs', this.indent_char === '\t'); - if (this.indent_with_tabs) { - this.indent_char = '\t'; - - // indent_size behavior changed after 1.8.6 - // It used to be that indent_size would be - // set to 1 for indent_with_tabs. That is no longer needed and - // actually doesn't make sense - why not use spaces? Further, - // that might produce unexpected behavior - tabs being used - // for single-column alignment. So, when indent_with_tabs is true - // and indent_size is 1, reset indent_size to 4. - if (this.indent_size === 1) { - this.indent_size = 4; - } - } - - // Backwards compat with 1.3.x - this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char')); - - this.indent_empty_lines = this._get_boolean('indent_empty_lines'); - - // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular'] - // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css). - // other values ignored - this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']); -} - -Options.prototype._get_array = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = default_value || []; - if (typeof option_value === 'object') { - if (option_value !== null && typeof option_value.concat === 'function') { - result = option_value.concat(); - } - } else if (typeof option_value === 'string') { - result = option_value.split(/[^a-zA-Z0-9_\/\-]+/); - } - return result; -}; - -Options.prototype._get_boolean = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = option_value === undefined ? !!default_value : !!option_value; - return result; -}; - -Options.prototype._get_characters = function(name, default_value) { - var option_value = this.raw_options[name]; - var result = default_value || ''; - if (typeof option_value === 'string') { - result = option_value.replace(/\\r/, '\r').replace(/\\n/, '\n').replace(/\\t/, '\t'); - } - return result; -}; - -Options.prototype._get_number = function(name, default_value) { - var option_value = this.raw_options[name]; - default_value = parseInt(default_value, 10); - if (isNaN(default_value)) { - default_value = 0; - } - var result = parseInt(option_value, 10); - if (isNaN(result)) { - result = default_value; - } - return result; -}; - -Options.prototype._get_selection = function(name, selection_list, default_value) { - var result = this._get_selection_list(name, selection_list, default_value); - if (result.length !== 1) { - throw new Error( - "Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" + - selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); - } - - return result[0]; -}; - - -Options.prototype._get_selection_list = function(name, selection_list, default_value) { - if (!selection_list || selection_list.length === 0) { - throw new Error("Selection list cannot be empty."); - } - - default_value = default_value || [selection_list[0]]; - if (!this._is_valid_selection(default_value, selection_list)) { - throw new Error("Invalid Default Value!"); - } - - var result = this._get_array(name, default_value); - if (!this._is_valid_selection(result, selection_list)) { - throw new Error( - "Invalid Option Value: The option '" + name + "' can contain only the following values:\n" + - selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); - } - - return result; -}; - -Options.prototype._is_valid_selection = function(result, selection_list) { - return result.length && selection_list.length && - !result.some(function(item) { return selection_list.indexOf(item) === -1; }); -}; - - -// merges child options up with the parent options object -// Example: obj = {a: 1, b: {a: 2}} -// mergeOpts(obj, 'b') -// -// Returns: {a: 2} -function _mergeOpts(allOptions, childFieldName) { - var finalOpts = {}; - allOptions = _normalizeOpts(allOptions); - var name; - - for (name in allOptions) { - if (name !== childFieldName) { - finalOpts[name] = allOptions[name]; - } - } - - //merge in the per type settings for the childFieldName - if (childFieldName && allOptions[childFieldName]) { - for (name in allOptions[childFieldName]) { - finalOpts[name] = allOptions[childFieldName][name]; - } - } - return finalOpts; -} - -function _normalizeOpts(options) { - var convertedOpts = {}; - var key; - - for (key in options) { - var newKey = key.replace(/-/g, "_"); - convertedOpts[newKey] = options[key]; - } - return convertedOpts; -} - -module.exports.Options = Options; -module.exports.normalizeOpts = _normalizeOpts; -module.exports.mergeOpts = _mergeOpts; - - -/***/ }), -/* 7 */, -/* 8 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var regexp_has_sticky = RegExp.prototype.hasOwnProperty('sticky'); - -function InputScanner(input_string) { - this.__input = input_string || ''; - this.__input_length = this.__input.length; - this.__position = 0; -} - -InputScanner.prototype.restart = function() { - this.__position = 0; -}; - -InputScanner.prototype.back = function() { - if (this.__position > 0) { - this.__position -= 1; - } -}; - -InputScanner.prototype.hasNext = function() { - return this.__position < this.__input_length; -}; - -InputScanner.prototype.next = function() { - var val = null; - if (this.hasNext()) { - val = this.__input.charAt(this.__position); - this.__position += 1; - } - return val; -}; - -InputScanner.prototype.peek = function(index) { - var val = null; - index = index || 0; - index += this.__position; - if (index >= 0 && index < this.__input_length) { - val = this.__input.charAt(index); - } - return val; -}; - -// This is a JavaScript only helper function (not in python) -// Javascript doesn't have a match method -// and not all implementation support "sticky" flag. -// If they do not support sticky then both this.match() and this.test() method -// must get the match and check the index of the match. -// If sticky is supported and set, this method will use it. -// Otherwise it will check that global is set, and fall back to the slower method. -InputScanner.prototype.__match = function(pattern, index) { - pattern.lastIndex = index; - var pattern_match = pattern.exec(this.__input); - - if (pattern_match && !(regexp_has_sticky && pattern.sticky)) { - if (pattern_match.index !== index) { - pattern_match = null; - } - } - - return pattern_match; -}; - -InputScanner.prototype.test = function(pattern, index) { - index = index || 0; - index += this.__position; - - if (index >= 0 && index < this.__input_length) { - return !!this.__match(pattern, index); - } else { - return false; - } -}; - -InputScanner.prototype.testChar = function(pattern, index) { - // test one character regex match - var val = this.peek(index); - pattern.lastIndex = 0; - return val !== null && pattern.test(val); -}; - -InputScanner.prototype.match = function(pattern) { - var pattern_match = this.__match(pattern, this.__position); - if (pattern_match) { - this.__position += pattern_match[0].length; - } else { - pattern_match = null; - } - return pattern_match; -}; - -InputScanner.prototype.read = function(starting_pattern, until_pattern, until_after) { - var val = ''; - var match; - if (starting_pattern) { - match = this.match(starting_pattern); - if (match) { - val += match[0]; - } - } - if (until_pattern && (match || !starting_pattern)) { - val += this.readUntil(until_pattern, until_after); - } - return val; -}; - -InputScanner.prototype.readUntil = function(pattern, until_after) { - var val = ''; - var match_index = this.__position; - pattern.lastIndex = this.__position; - var pattern_match = pattern.exec(this.__input); - if (pattern_match) { - match_index = pattern_match.index; - if (until_after) { - match_index += pattern_match[0].length; - } - } else { - match_index = this.__input_length; - } - - val = this.__input.substring(this.__position, match_index); - this.__position = match_index; - return val; -}; - -InputScanner.prototype.readUntilAfter = function(pattern) { - return this.readUntil(pattern, true); -}; - -InputScanner.prototype.get_regexp = function(pattern, match_from) { - var result = null; - var flags = 'g'; - if (match_from && regexp_has_sticky) { - flags = 'y'; - } - // strings are converted to regexp - if (typeof pattern === "string" && pattern !== '') { - // result = new RegExp(pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), flags); - result = new RegExp(pattern, flags); - } else if (pattern) { - result = new RegExp(pattern.source, flags); - } - return result; -}; - -InputScanner.prototype.get_literal_regexp = function(literal_string) { - return RegExp(literal_string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); -}; - -/* css beautifier legacy helpers */ -InputScanner.prototype.peekUntilAfter = function(pattern) { - var start = this.__position; - var val = this.readUntilAfter(pattern); - this.__position = start; - return val; -}; - -InputScanner.prototype.lookBack = function(testVal) { - var start = this.__position - 1; - return start >= testVal.length && this.__input.substring(start - testVal.length, start) - .toLowerCase() === testVal; -}; - -module.exports.InputScanner = InputScanner; - - -/***/ }), -/* 9 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var InputScanner = (__webpack_require__(8).InputScanner); -var Token = (__webpack_require__(3).Token); -var TokenStream = (__webpack_require__(10).TokenStream); -var WhitespacePattern = (__webpack_require__(11).WhitespacePattern); - -var TOKEN = { - START: 'TK_START', - RAW: 'TK_RAW', - EOF: 'TK_EOF' -}; - -var Tokenizer = function(input_string, options) { - this._input = new InputScanner(input_string); - this._options = options || {}; - this.__tokens = null; - - this._patterns = {}; - this._patterns.whitespace = new WhitespacePattern(this._input); -}; - -Tokenizer.prototype.tokenize = function() { - this._input.restart(); - this.__tokens = new TokenStream(); - - this._reset(); - - var current; - var previous = new Token(TOKEN.START, ''); - var open_token = null; - var open_stack = []; - var comments = new TokenStream(); - - while (previous.type !== TOKEN.EOF) { - current = this._get_next_token(previous, open_token); - while (this._is_comment(current)) { - comments.add(current); - current = this._get_next_token(previous, open_token); - } - - if (!comments.isEmpty()) { - current.comments_before = comments; - comments = new TokenStream(); - } - - current.parent = open_token; - - if (this._is_opening(current)) { - open_stack.push(open_token); - open_token = current; - } else if (open_token && this._is_closing(current, open_token)) { - current.opened = open_token; - open_token.closed = current; - open_token = open_stack.pop(); - current.parent = open_token; - } - - current.previous = previous; - previous.next = current; - - this.__tokens.add(current); - previous = current; - } - - return this.__tokens; -}; - - -Tokenizer.prototype._is_first_token = function() { - return this.__tokens.isEmpty(); -}; - -Tokenizer.prototype._reset = function() {}; - -Tokenizer.prototype._get_next_token = function(previous_token, open_token) { // jshint unused:false - this._readWhitespace(); - var resulting_string = this._input.read(/.+/g); - if (resulting_string) { - return this._create_token(TOKEN.RAW, resulting_string); - } else { - return this._create_token(TOKEN.EOF, ''); - } -}; - -Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:false - return false; -}; - -Tokenizer.prototype._is_opening = function(current_token) { // jshint unused:false - return false; -}; - -Tokenizer.prototype._is_closing = function(current_token, open_token) { // jshint unused:false - return false; -}; - -Tokenizer.prototype._create_token = function(type, text) { - var token = new Token(type, text, - this._patterns.whitespace.newline_count, - this._patterns.whitespace.whitespace_before_token); - return token; -}; - -Tokenizer.prototype._readWhitespace = function() { - return this._patterns.whitespace.read(); -}; - - - -module.exports.Tokenizer = Tokenizer; -module.exports.TOKEN = TOKEN; - - -/***/ }), -/* 10 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function TokenStream(parent_token) { - // private - this.__tokens = []; - this.__tokens_length = this.__tokens.length; - this.__position = 0; - this.__parent_token = parent_token; -} - -TokenStream.prototype.restart = function() { - this.__position = 0; -}; - -TokenStream.prototype.isEmpty = function() { - return this.__tokens_length === 0; -}; - -TokenStream.prototype.hasNext = function() { - return this.__position < this.__tokens_length; -}; - -TokenStream.prototype.next = function() { - var val = null; - if (this.hasNext()) { - val = this.__tokens[this.__position]; - this.__position += 1; - } - return val; -}; - -TokenStream.prototype.peek = function(index) { - var val = null; - index = index || 0; - index += this.__position; - if (index >= 0 && index < this.__tokens_length) { - val = this.__tokens[index]; - } - return val; -}; - -TokenStream.prototype.add = function(token) { - if (this.__parent_token) { - token.parent = this.__parent_token; - } - this.__tokens.push(token); - this.__tokens_length += 1; -}; - -module.exports.TokenStream = TokenStream; - - -/***/ }), -/* 11 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Pattern = (__webpack_require__(12).Pattern); - -function WhitespacePattern(input_scanner, parent) { - Pattern.call(this, input_scanner, parent); - if (parent) { - this._line_regexp = this._input.get_regexp(parent._line_regexp); - } else { - this.__set_whitespace_patterns('', ''); - } - - this.newline_count = 0; - this.whitespace_before_token = ''; -} -WhitespacePattern.prototype = new Pattern(); - -WhitespacePattern.prototype.__set_whitespace_patterns = function(whitespace_chars, newline_chars) { - whitespace_chars += '\\t '; - newline_chars += '\\n\\r'; - - this._match_pattern = this._input.get_regexp( - '[' + whitespace_chars + newline_chars + ']+', true); - this._newline_regexp = this._input.get_regexp( - '\\r\\n|[' + newline_chars + ']'); -}; - -WhitespacePattern.prototype.read = function() { - this.newline_count = 0; - this.whitespace_before_token = ''; - - var resulting_string = this._input.read(this._match_pattern); - if (resulting_string === ' ') { - this.whitespace_before_token = ' '; - } else if (resulting_string) { - var matches = this.__split(this._newline_regexp, resulting_string); - this.newline_count = matches.length - 1; - this.whitespace_before_token = matches[this.newline_count]; - } - - return resulting_string; -}; - -WhitespacePattern.prototype.matching = function(whitespace_chars, newline_chars) { - var result = this._create(); - result.__set_whitespace_patterns(whitespace_chars, newline_chars); - result._update(); - return result; -}; - -WhitespacePattern.prototype._create = function() { - return new WhitespacePattern(this._input, this); -}; - -WhitespacePattern.prototype.__split = function(regexp, input_string) { - regexp.lastIndex = 0; - var start_index = 0; - var result = []; - var next_match = regexp.exec(input_string); - while (next_match) { - result.push(input_string.substring(start_index, next_match.index)); - start_index = next_match.index + next_match[0].length; - next_match = regexp.exec(input_string); - } - - if (start_index < input_string.length) { - result.push(input_string.substring(start_index, input_string.length)); - } else { - result.push(''); - } - - return result; -}; - - - -module.exports.WhitespacePattern = WhitespacePattern; - - -/***/ }), -/* 12 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Pattern(input_scanner, parent) { - this._input = input_scanner; - this._starting_pattern = null; - this._match_pattern = null; - this._until_pattern = null; - this._until_after = false; - - if (parent) { - this._starting_pattern = this._input.get_regexp(parent._starting_pattern, true); - this._match_pattern = this._input.get_regexp(parent._match_pattern, true); - this._until_pattern = this._input.get_regexp(parent._until_pattern); - this._until_after = parent._until_after; - } -} - -Pattern.prototype.read = function() { - var result = this._input.read(this._starting_pattern); - if (!this._starting_pattern || result) { - result += this._input.read(this._match_pattern, this._until_pattern, this._until_after); - } - return result; -}; - -Pattern.prototype.read_match = function() { - return this._input.match(this._match_pattern); -}; - -Pattern.prototype.until_after = function(pattern) { - var result = this._create(); - result._until_after = true; - result._until_pattern = this._input.get_regexp(pattern); - result._update(); - return result; -}; - -Pattern.prototype.until = function(pattern) { - var result = this._create(); - result._until_after = false; - result._until_pattern = this._input.get_regexp(pattern); - result._update(); - return result; -}; - -Pattern.prototype.starting_with = function(pattern) { - var result = this._create(); - result._starting_pattern = this._input.get_regexp(pattern, true); - result._update(); - return result; -}; - -Pattern.prototype.matching = function(pattern) { - var result = this._create(); - result._match_pattern = this._input.get_regexp(pattern, true); - result._update(); - return result; -}; - -Pattern.prototype._create = function() { - return new Pattern(this._input, this); -}; - -Pattern.prototype._update = function() {}; - -module.exports.Pattern = Pattern; - - -/***/ }), -/* 13 */ -/***/ (function(module) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -function Directives(start_block_pattern, end_block_pattern) { - start_block_pattern = typeof start_block_pattern === 'string' ? start_block_pattern : start_block_pattern.source; - end_block_pattern = typeof end_block_pattern === 'string' ? end_block_pattern : end_block_pattern.source; - this.__directives_block_pattern = new RegExp(start_block_pattern + / beautify( \w+[:]\w+)+ /.source + end_block_pattern, 'g'); - this.__directive_pattern = / (\w+)[:](\w+)/g; - - this.__directives_end_ignore_pattern = new RegExp(start_block_pattern + /\sbeautify\signore:end\s/.source + end_block_pattern, 'g'); -} - -Directives.prototype.get_directives = function(text) { - if (!text.match(this.__directives_block_pattern)) { - return null; - } - - var directives = {}; - this.__directive_pattern.lastIndex = 0; - var directive_match = this.__directive_pattern.exec(text); - - while (directive_match) { - directives[directive_match[1]] = directive_match[2]; - directive_match = this.__directive_pattern.exec(text); - } - - return directives; -}; - -Directives.prototype.readIgnored = function(input) { - return input.readUntilAfter(this.__directives_end_ignore_pattern); -}; - - -module.exports.Directives = Directives; - - -/***/ }), -/* 14 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Pattern = (__webpack_require__(12).Pattern); - - -var template_names = { - django: false, - erb: false, - handlebars: false, - php: false, - smarty: false, - angular: false -}; - -// This lets templates appear anywhere we would do a readUntil -// The cost is higher but it is pay to play. -function TemplatablePattern(input_scanner, parent) { - Pattern.call(this, input_scanner, parent); - this.__template_pattern = null; - this._disabled = Object.assign({}, template_names); - this._excluded = Object.assign({}, template_names); - - if (parent) { - this.__template_pattern = this._input.get_regexp(parent.__template_pattern); - this._excluded = Object.assign(this._excluded, parent._excluded); - this._disabled = Object.assign(this._disabled, parent._disabled); - } - var pattern = new Pattern(input_scanner); - this.__patterns = { - handlebars_comment: pattern.starting_with(/{{!--/).until_after(/--}}/), - handlebars_unescaped: pattern.starting_with(/{{{/).until_after(/}}}/), - handlebars: pattern.starting_with(/{{/).until_after(/}}/), - php: pattern.starting_with(/<\?(?:[= ]|php)/).until_after(/\?>/), - erb: pattern.starting_with(/<%[^%]/).until_after(/[^%]%>/), - // django coflicts with handlebars a bit. - django: pattern.starting_with(/{%/).until_after(/%}/), - django_value: pattern.starting_with(/{{/).until_after(/}}/), - django_comment: pattern.starting_with(/{#/).until_after(/#}/), - smarty: pattern.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/), - smarty_comment: pattern.starting_with(/{\*/).until_after(/\*}/), - smarty_literal: pattern.starting_with(/{literal}/).until_after(/{\/literal}/) - }; -} -TemplatablePattern.prototype = new Pattern(); - -TemplatablePattern.prototype._create = function() { - return new TemplatablePattern(this._input, this); -}; - -TemplatablePattern.prototype._update = function() { - this.__set_templated_pattern(); -}; - -TemplatablePattern.prototype.disable = function(language) { - var result = this._create(); - result._disabled[language] = true; - result._update(); - return result; -}; - -TemplatablePattern.prototype.read_options = function(options) { - var result = this._create(); - for (var language in template_names) { - result._disabled[language] = options.templating.indexOf(language) === -1; - } - result._update(); - return result; -}; - -TemplatablePattern.prototype.exclude = function(language) { - var result = this._create(); - result._excluded[language] = true; - result._update(); - return result; -}; - -TemplatablePattern.prototype.read = function() { - var result = ''; - if (this._match_pattern) { - result = this._input.read(this._starting_pattern); - } else { - result = this._input.read(this._starting_pattern, this.__template_pattern); - } - var next = this._read_template(); - while (next) { - if (this._match_pattern) { - next += this._input.read(this._match_pattern); - } else { - next += this._input.readUntil(this.__template_pattern); - } - result += next; - next = this._read_template(); - } - - if (this._until_after) { - result += this._input.readUntilAfter(this._until_pattern); - } - return result; -}; - -TemplatablePattern.prototype.__set_templated_pattern = function() { - var items = []; - - if (!this._disabled.php) { - items.push(this.__patterns.php._starting_pattern.source); - } - if (!this._disabled.handlebars) { - items.push(this.__patterns.handlebars._starting_pattern.source); - } - if (!this._disabled.erb) { - items.push(this.__patterns.erb._starting_pattern.source); - } - if (!this._disabled.django) { - items.push(this.__patterns.django._starting_pattern.source); - // The starting pattern for django is more complex because it has different - // patterns for value, comment, and other sections - items.push(this.__patterns.django_value._starting_pattern.source); - items.push(this.__patterns.django_comment._starting_pattern.source); - } - if (!this._disabled.smarty) { - items.push(this.__patterns.smarty._starting_pattern.source); - } - - if (this._until_pattern) { - items.push(this._until_pattern.source); - } - this.__template_pattern = this._input.get_regexp('(?:' + items.join('|') + ')'); -}; - -TemplatablePattern.prototype._read_template = function() { - var resulting_string = ''; - var c = this._input.peek(); - if (c === '<') { - var peek1 = this._input.peek(1); - //if we're in a comment, do something special - // We treat all comments as literals, even more than preformatted tags - // we just look for the appropriate close tag - if (!this._disabled.php && !this._excluded.php && peek1 === '?') { - resulting_string = resulting_string || - this.__patterns.php.read(); - } - if (!this._disabled.erb && !this._excluded.erb && peek1 === '%') { - resulting_string = resulting_string || - this.__patterns.erb.read(); - } - } else if (c === '{') { - if (!this._disabled.handlebars && !this._excluded.handlebars) { - resulting_string = resulting_string || - this.__patterns.handlebars_comment.read(); - resulting_string = resulting_string || - this.__patterns.handlebars_unescaped.read(); - resulting_string = resulting_string || - this.__patterns.handlebars.read(); - } - if (!this._disabled.django) { - // django coflicts with handlebars a bit. - if (!this._excluded.django && !this._excluded.handlebars) { - resulting_string = resulting_string || - this.__patterns.django_value.read(); - } - if (!this._excluded.django) { - resulting_string = resulting_string || - this.__patterns.django_comment.read(); - resulting_string = resulting_string || - this.__patterns.django.read(); - } - } - if (!this._disabled.smarty) { - // smarty cannot be enabled with django or handlebars enabled - if (this._disabled.django && this._disabled.handlebars) { - resulting_string = resulting_string || - this.__patterns.smarty_comment.read(); - resulting_string = resulting_string || - this.__patterns.smarty_literal.read(); - resulting_string = resulting_string || - this.__patterns.smarty.read(); - } - } - } - return resulting_string; -}; - - -module.exports.TemplatablePattern = TemplatablePattern; - - -/***/ }), -/* 15 */, -/* 16 */, -/* 17 */, -/* 18 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Beautifier = (__webpack_require__(19).Beautifier), - Options = (__webpack_require__(20).Options); - -function style_html(html_source, options, js_beautify, css_beautify) { - var beautifier = new Beautifier(html_source, options, js_beautify, css_beautify); - return beautifier.beautify(); -} - -module.exports = style_html; -module.exports.defaultOptions = function() { - return new Options(); -}; - - -/***/ }), -/* 19 */ -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -/*jshint node:true */ -/* - - The MIT License (MIT) - - Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - - -var Options = (__webpack_require__(20).Options); -var Output = (__webpack_require__(2).Output); -var Tokenizer = (__webpack_require__(21).Tokenizer); -var TOKEN = (__webpack_require__(21).TOKEN); - -var lineBreak = /\r\n|[\r\n]/; -var allLineBreaks = /\r\n|[\r\n]/g; - -var Printer = function(options, base_indent_string) { //handles input/output and some other printing functions - - this.indent_level = 0; - this.alignment_size = 0; - this.max_preserve_newlines = options.max_preserve_newlines; - this.preserve_newlines = options.preserve_newlines; - - this._output = new Output(options, base_indent_string); - -}; - -Printer.prototype.current_line_has_match = function(pattern) { - return this._output.current_line.has_match(pattern); -}; - -Printer.prototype.set_space_before_token = function(value, non_breaking) { - this._output.space_before_token = value; - this._output.non_breaking_space = non_breaking; -}; - -Printer.prototype.set_wrap_point = function() { - this._output.set_indent(this.indent_level, this.alignment_size); - this._output.set_wrap_point(); -}; - - -Printer.prototype.add_raw_token = function(token) { - this._output.add_raw_token(token); -}; - -Printer.prototype.print_preserved_newlines = function(raw_token) { - var newlines = 0; - if (raw_token.type !== TOKEN.TEXT && raw_token.previous.type !== TOKEN.TEXT) { - newlines = raw_token.newlines ? 1 : 0; - } - - if (this.preserve_newlines) { - newlines = raw_token.newlines < this.max_preserve_newlines + 1 ? raw_token.newlines : this.max_preserve_newlines + 1; - } - for (var n = 0; n < newlines; n++) { - this.print_newline(n > 0); - } - - return newlines !== 0; -}; - -Printer.prototype.traverse_whitespace = function(raw_token) { - if (raw_token.whitespace_before || raw_token.newlines) { - if (!this.print_preserved_newlines(raw_token)) { - this._output.space_before_token = true; - } - return true; - } - return false; -}; - -Printer.prototype.previous_token_wrapped = function() { - return this._output.previous_token_wrapped; -}; - -Printer.prototype.print_newline = function(force) { - this._output.add_new_line(force); -}; - -Printer.prototype.print_token = function(token) { - if (token.text) { - this._output.set_indent(this.indent_level, this.alignment_size); - this._output.add_token(token.text); - } -}; - -Printer.prototype.indent = function() { - this.indent_level++; -}; - -Printer.prototype.deindent = function() { - if (this.indent_level > 0) { - this.indent_level--; - this._output.set_indent(this.indent_level, this.alignment_size); - } -}; - -Printer.prototype.get_full_indent = function(level) { - level = this.indent_level + (level || 0); - if (level < 1) { - return ''; - } - - return this._output.get_indent_string(level); -}; - -var get_type_attribute = function(start_token) { - var result = null; - var raw_token = start_token.next; - - // Search attributes for a type attribute - while (raw_token.type !== TOKEN.EOF && start_token.closed !== raw_token) { - if (raw_token.type === TOKEN.ATTRIBUTE && raw_token.text === 'type') { - if (raw_token.next && raw_token.next.type === TOKEN.EQUALS && - raw_token.next.next && raw_token.next.next.type === TOKEN.VALUE) { - result = raw_token.next.next.text; - } - break; - } - raw_token = raw_token.next; - } - - return result; -}; - -var get_custom_beautifier_name = function(tag_check, raw_token) { - var typeAttribute = null; - var result = null; - - if (!raw_token.closed) { - return null; - } - - if (tag_check === 'script') { - typeAttribute = 'text/javascript'; - } else if (tag_check === 'style') { - typeAttribute = 'text/css'; - } - - typeAttribute = get_type_attribute(raw_token) || typeAttribute; - - // For script and style tags that have a type attribute, only enable custom beautifiers for matching values - // For those without a type attribute use default; - if (typeAttribute.search('text/css') > -1) { - result = 'css'; - } else if (typeAttribute.search(/module|((text|application|dojo)\/(x-)?(javascript|ecmascript|jscript|livescript|(ld\+)?json|method|aspect))/) > -1) { - result = 'javascript'; - } else if (typeAttribute.search(/(text|application|dojo)\/(x-)?(html)/) > -1) { - result = 'html'; - } else if (typeAttribute.search(/test\/null/) > -1) { - // Test only mime-type for testing the beautifier when null is passed as beautifing function - result = 'null'; - } - - return result; -}; - -function in_array(what, arr) { - return arr.indexOf(what) !== -1; -} - -function TagFrame(parent, parser_token, indent_level) { - this.parent = parent || null; - this.tag = parser_token ? parser_token.tag_name : ''; - this.indent_level = indent_level || 0; - this.parser_token = parser_token || null; -} - -function TagStack(printer) { - this._printer = printer; - this._current_frame = null; -} - -TagStack.prototype.get_parser_token = function() { - return this._current_frame ? this._current_frame.parser_token : null; -}; - -TagStack.prototype.record_tag = function(parser_token) { //function to record a tag and its parent in this.tags Object - var new_frame = new TagFrame(this._current_frame, parser_token, this._printer.indent_level); - this._current_frame = new_frame; -}; - -TagStack.prototype._try_pop_frame = function(frame) { //function to retrieve the opening tag to the corresponding closer - var parser_token = null; - - if (frame) { - parser_token = frame.parser_token; - this._printer.indent_level = frame.indent_level; - this._current_frame = frame.parent; - } - - return parser_token; -}; - -TagStack.prototype._get_frame = function(tag_list, stop_list) { //function to retrieve the opening tag to the corresponding closer - var frame = this._current_frame; - - while (frame) { //till we reach '' (the initial value); - if (tag_list.indexOf(frame.tag) !== -1) { //if this is it use it - break; - } else if (stop_list && stop_list.indexOf(frame.tag) !== -1) { - frame = null; - break; - } - frame = frame.parent; - } - - return frame; -}; - -TagStack.prototype.try_pop = function(tag, stop_list) { //function to retrieve the opening tag to the corresponding closer - var frame = this._get_frame([tag], stop_list); - return this._try_pop_frame(frame); -}; - -TagStack.prototype.indent_to_tag = function(tag_list) { - var frame = this._get_frame(tag_list); - if (frame) { - this._printer.indent_level = frame.indent_level; - } -}; - -function Beautifier(source_text, options, js_beautify, css_beautify) { - //Wrapper function to invoke all the necessary constructors and deal with the output. - this._source_text = source_text || ''; - options = options || {}; - this._js_beautify = js_beautify; - this._css_beautify = css_beautify; - this._tag_stack = null; - - // Allow the setting of language/file-type specific options - // with inheritance of overall settings - var optionHtml = new Options(options, 'html'); - - this._options = optionHtml; - - this._is_wrap_attributes_force = this._options.wrap_attributes.substr(0, 'force'.length) === 'force'; - this._is_wrap_attributes_force_expand_multiline = (this._options.wrap_attributes === 'force-expand-multiline'); - this._is_wrap_attributes_force_aligned = (this._options.wrap_attributes === 'force-aligned'); - this._is_wrap_attributes_aligned_multiple = (this._options.wrap_attributes === 'aligned-multiple'); - this._is_wrap_attributes_preserve = this._options.wrap_attributes.substr(0, 'preserve'.length) === 'preserve'; - this._is_wrap_attributes_preserve_aligned = (this._options.wrap_attributes === 'preserve-aligned'); -} - -Beautifier.prototype.beautify = function() { - - // if disabled, return the input unchanged. - if (this._options.disabled) { - return this._source_text; - } - - var source_text = this._source_text; - var eol = this._options.eol; - if (this._options.eol === 'auto') { - eol = '\n'; - if (source_text && lineBreak.test(source_text)) { - eol = source_text.match(lineBreak)[0]; - } - } - - // HACK: newline parsing inconsistent. This brute force normalizes the input. - source_text = source_text.replace(allLineBreaks, '\n'); - - var baseIndentString = source_text.match(/^[\t ]*/)[0]; - - var last_token = { - text: '', - type: '' - }; - - var last_tag_token = new TagOpenParserToken(); - - var printer = new Printer(this._options, baseIndentString); - var tokens = new Tokenizer(source_text, this._options).tokenize(); - - this._tag_stack = new TagStack(printer); - - var parser_token = null; - var raw_token = tokens.next(); - while (raw_token.type !== TOKEN.EOF) { - - if (raw_token.type === TOKEN.TAG_OPEN || raw_token.type === TOKEN.COMMENT) { - parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token, tokens); - last_tag_token = parser_token; - } else if ((raw_token.type === TOKEN.ATTRIBUTE || raw_token.type === TOKEN.EQUALS || raw_token.type === TOKEN.VALUE) || - (raw_token.type === TOKEN.TEXT && !last_tag_token.tag_complete)) { - parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, last_token); - } else if (raw_token.type === TOKEN.TAG_CLOSE) { - parser_token = this._handle_tag_close(printer, raw_token, last_tag_token); - } else if (raw_token.type === TOKEN.TEXT) { - parser_token = this._handle_text(printer, raw_token, last_tag_token); - } else if (raw_token.type === TOKEN.CONTROL_FLOW_OPEN) { - parser_token = this._handle_control_flow_open(printer, raw_token); - } else if (raw_token.type === TOKEN.CONTROL_FLOW_CLOSE) { - parser_token = this._handle_control_flow_close(printer, raw_token); - } else { - // This should never happen, but if it does. Print the raw token - printer.add_raw_token(raw_token); - } - - last_token = parser_token; - - raw_token = tokens.next(); - } - var sweet_code = printer._output.get_code(eol); - - return sweet_code; -}; - -Beautifier.prototype._handle_control_flow_open = function(printer, raw_token) { - var parser_token = { - text: raw_token.text, - type: raw_token.type - }; - printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true); - if (raw_token.newlines) { - printer.print_preserved_newlines(raw_token); - } else { - printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true); - } - printer.print_token(raw_token); - printer.indent(); - return parser_token; -}; - -Beautifier.prototype._handle_control_flow_close = function(printer, raw_token) { - var parser_token = { - text: raw_token.text, - type: raw_token.type - }; - - printer.deindent(); - if (raw_token.newlines) { - printer.print_preserved_newlines(raw_token); - } else { - printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true); - } - printer.print_token(raw_token); - return parser_token; -}; - -Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_token) { - var parser_token = { - text: raw_token.text, - type: raw_token.type - }; - printer.alignment_size = 0; - last_tag_token.tag_complete = true; - - printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true); - if (last_tag_token.is_unformatted) { - printer.add_raw_token(raw_token); - } else { - if (last_tag_token.tag_start_char === '<') { - printer.set_space_before_token(raw_token.text[0] === '/', true); // space before />, no space before > - if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.has_wrapped_attrs) { - printer.print_newline(false); - } - } - printer.print_token(raw_token); - - } - - if (last_tag_token.indent_content && - !(last_tag_token.is_unformatted || last_tag_token.is_content_unformatted)) { - printer.indent(); - - // only indent once per opened tag - last_tag_token.indent_content = false; - } - - if (!last_tag_token.is_inline_element && - !(last_tag_token.is_unformatted || last_tag_token.is_content_unformatted)) { - printer.set_wrap_point(); - } - - return parser_token; -}; - -Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, last_token) { - var wrapped = last_tag_token.has_wrapped_attrs; - var parser_token = { - text: raw_token.text, - type: raw_token.type - }; - - printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true); - if (last_tag_token.is_unformatted) { - printer.add_raw_token(raw_token); - } else if (last_tag_token.tag_start_char === '{' && raw_token.type === TOKEN.TEXT) { - // For the insides of handlebars allow newlines or a single space between open and contents - if (printer.print_preserved_newlines(raw_token)) { - raw_token.newlines = 0; - printer.add_raw_token(raw_token); - } else { - printer.print_token(raw_token); - } - } else { - if (raw_token.type === TOKEN.ATTRIBUTE) { - printer.set_space_before_token(true); - } else if (raw_token.type === TOKEN.EQUALS) { //no space before = - printer.set_space_before_token(false); - } else if (raw_token.type === TOKEN.VALUE && raw_token.previous.type === TOKEN.EQUALS) { //no space before value - printer.set_space_before_token(false); - } - - if (raw_token.type === TOKEN.ATTRIBUTE && last_tag_token.tag_start_char === '<') { - if (this._is_wrap_attributes_preserve || this._is_wrap_attributes_preserve_aligned) { - printer.traverse_whitespace(raw_token); - wrapped = wrapped || raw_token.newlines !== 0; - } - - // Wrap for 'force' options, and if the number of attributes is at least that specified in 'wrap_attributes_min_attrs': - // 1. always wrap the second and beyond attributes - // 2. wrap the first attribute only if 'force-expand-multiline' is specified - if (this._is_wrap_attributes_force && - last_tag_token.attr_count >= this._options.wrap_attributes_min_attrs && - (last_token.type !== TOKEN.TAG_OPEN || // ie. second attribute and beyond - this._is_wrap_attributes_force_expand_multiline)) { - printer.print_newline(false); - wrapped = true; - } - } - printer.print_token(raw_token); - wrapped = wrapped || printer.previous_token_wrapped(); - last_tag_token.has_wrapped_attrs = wrapped; - } - return parser_token; -}; - -Beautifier.prototype._handle_text = function(printer, raw_token, last_tag_token) { - var parser_token = { - text: raw_token.text, - type: 'TK_CONTENT' - }; - if (last_tag_token.custom_beautifier_name) { //check if we need to format javascript - this._print_custom_beatifier_text(printer, raw_token, last_tag_token); - } else if (last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) { - printer.add_raw_token(raw_token); - } else { - printer.traverse_whitespace(raw_token); - printer.print_token(raw_token); - } - return parser_token; -}; - -Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token, last_tag_token) { - var local = this; - if (raw_token.text !== '') { - - var text = raw_token.text, - _beautifier, - script_indent_level = 1, - pre = '', - post = ''; - if (last_tag_token.custom_beautifier_name === 'javascript' && typeof this._js_beautify === 'function') { - _beautifier = this._js_beautify; - } else if (last_tag_token.custom_beautifier_name === 'css' && typeof this._css_beautify === 'function') { - _beautifier = this._css_beautify; - } else if (last_tag_token.custom_beautifier_name === 'html') { - _beautifier = function(html_source, options) { - var beautifier = new Beautifier(html_source, options, local._js_beautify, local._css_beautify); - return beautifier.beautify(); - }; - } - - if (this._options.indent_scripts === "keep") { - script_indent_level = 0; - } else if (this._options.indent_scripts === "separate") { - script_indent_level = -printer.indent_level; - } - - var indentation = printer.get_full_indent(script_indent_level); - - // if there is at least one empty line at the end of this text, strip it - // we'll be adding one back after the text but before the containing tag. - text = text.replace(/\n[ \t]*$/, ''); - - // Handle the case where content is wrapped in a comment or cdata. - if (last_tag_token.custom_beautifier_name !== 'html' && - text[0] === '<' && text.match(/^(|]]>)$/.exec(text); - - // if we start to wrap but don't finish, print raw - if (!matched) { - printer.add_raw_token(raw_token); - return; - } - - pre = indentation + matched[1] + '\n'; - text = matched[4]; - if (matched[5]) { - post = indentation + matched[5]; - } - - // if there is at least one empty line at the end of this text, strip it - // we'll be adding one back after the text but before the containing tag. - text = text.replace(/\n[ \t]*$/, ''); - - if (matched[2] || matched[3].indexOf('\n') !== -1) { - // if the first line of the non-comment text has spaces - // use that as the basis for indenting in null case. - matched = matched[3].match(/[ \t]+$/); - if (matched) { - raw_token.whitespace_before = matched[0]; - } - } - } - - if (text) { - if (_beautifier) { - - // call the Beautifier if avaliable - var Child_options = function() { - this.eol = '\n'; - }; - Child_options.prototype = this._options.raw_options; - var child_options = new Child_options(); - text = _beautifier(indentation + text, child_options); - } else { - // simply indent the string otherwise - var white = raw_token.whitespace_before; - if (white) { - text = text.replace(new RegExp('\n(' + white + ')?', 'g'), '\n'); - } - - text = indentation + text.replace(/\n/g, '\n' + indentation); - } - } - - if (pre) { - if (!text) { - text = pre + post; - } else { - text = pre + text + '\n' + post; - } - } - - printer.print_newline(false); - if (text) { - raw_token.text = text; - raw_token.whitespace_before = ''; - raw_token.newlines = 0; - printer.add_raw_token(raw_token); - printer.print_newline(true); - } - } -}; - -Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token, tokens) { - var parser_token = this._get_tag_open_token(raw_token); - - if ((last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) && - !last_tag_token.is_empty_element && - raw_token.type === TOKEN.TAG_OPEN && !parser_token.is_start_tag) { - // End element tags for unformatted or content_unformatted elements - // are printed raw to keep any newlines inside them exactly the same. - printer.add_raw_token(raw_token); - parser_token.start_tag_token = this._tag_stack.try_pop(parser_token.tag_name); - } else { - printer.traverse_whitespace(raw_token); - this._set_tag_position(printer, raw_token, parser_token, last_tag_token, last_token); - if (!parser_token.is_inline_element) { - printer.set_wrap_point(); - } - printer.print_token(raw_token); - } - - // count the number of attributes - if (parser_token.is_start_tag && this._is_wrap_attributes_force) { - var peek_index = 0; - var peek_token; - do { - peek_token = tokens.peek(peek_index); - if (peek_token.type === TOKEN.ATTRIBUTE) { - parser_token.attr_count += 1; - } - peek_index += 1; - } while (peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE); - } - - //indent attributes an auto, forced, aligned or forced-align line-wrap - if (this._is_wrap_attributes_force_aligned || this._is_wrap_attributes_aligned_multiple || this._is_wrap_attributes_preserve_aligned) { - parser_token.alignment_size = raw_token.text.length + 1; - } - - if (!parser_token.tag_complete && !parser_token.is_unformatted) { - printer.alignment_size = parser_token.alignment_size; - } - - return parser_token; -}; - -var TagOpenParserToken = function(parent, raw_token) { - this.parent = parent || null; - this.text = ''; - this.type = 'TK_TAG_OPEN'; - this.tag_name = ''; - this.is_inline_element = false; - this.is_unformatted = false; - this.is_content_unformatted = false; - this.is_empty_element = false; - this.is_start_tag = false; - this.is_end_tag = false; - this.indent_content = false; - this.multiline_content = false; - this.custom_beautifier_name = null; - this.start_tag_token = null; - this.attr_count = 0; - this.has_wrapped_attrs = false; - this.alignment_size = 0; - this.tag_complete = false; - this.tag_start_char = ''; - this.tag_check = ''; - - if (!raw_token) { - this.tag_complete = true; - } else { - var tag_check_match; - - this.tag_start_char = raw_token.text[0]; - this.text = raw_token.text; - - if (this.tag_start_char === '<') { - tag_check_match = raw_token.text.match(/^<([^\s>]*)/); - this.tag_check = tag_check_match ? tag_check_match[1] : ''; - } else { - tag_check_match = raw_token.text.match(/^{{~?(?:[\^]|#\*?)?([^\s}]+)/); - this.tag_check = tag_check_match ? tag_check_match[1] : ''; - - // handle "{{#> myPartial}}" or "{{~#> myPartial}}" - if ((raw_token.text.startsWith('{{#>') || raw_token.text.startsWith('{{~#>')) && this.tag_check[0] === '>') { - if (this.tag_check === '>' && raw_token.next !== null) { - this.tag_check = raw_token.next.text.split(' ')[0]; - } else { - this.tag_check = raw_token.text.split('>')[1]; - } - } - } - - this.tag_check = this.tag_check.toLowerCase(); - - if (raw_token.type === TOKEN.COMMENT) { - this.tag_complete = true; - } - - this.is_start_tag = this.tag_check.charAt(0) !== '/'; - this.tag_name = !this.is_start_tag ? this.tag_check.substr(1) : this.tag_check; - this.is_end_tag = !this.is_start_tag || - (raw_token.closed && raw_token.closed.text === '/>'); - - // if whitespace handler ~ included (i.e. {{~#if true}}), handlebars tags start at pos 3 not pos 2 - var handlebar_starts = 2; - if (this.tag_start_char === '{' && this.text.length >= 3) { - if (this.text.charAt(2) === '~') { - handlebar_starts = 3; - } - } - - // handlebars tags that don't start with # or ^ are single_tags, and so also start and end. - this.is_end_tag = this.is_end_tag || - (this.tag_start_char === '{' && (this.text.length < 3 || (/[^#\^]/.test(this.text.charAt(handlebar_starts))))); - } -}; - -Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to get a full tag and parse its type - var parser_token = new TagOpenParserToken(this._tag_stack.get_parser_token(), raw_token); - - parser_token.alignment_size = this._options.wrap_attributes_indent_size; - - parser_token.is_end_tag = parser_token.is_end_tag || - in_array(parser_token.tag_check, this._options.void_elements); - - parser_token.is_empty_element = parser_token.tag_complete || - (parser_token.is_start_tag && parser_token.is_end_tag); - - parser_token.is_unformatted = !parser_token.tag_complete && in_array(parser_token.tag_check, this._options.unformatted); - parser_token.is_content_unformatted = !parser_token.is_empty_element && in_array(parser_token.tag_check, this._options.content_unformatted); - parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || (this._options.inline_custom_elements && parser_token.tag_name.includes("-")) || parser_token.tag_start_char === '{'; - - return parser_token; -}; - -Beautifier.prototype._set_tag_position = function(printer, raw_token, parser_token, last_tag_token, last_token) { - - if (!parser_token.is_empty_element) { - if (parser_token.is_end_tag) { //this tag is a double tag so check for tag-ending - parser_token.start_tag_token = this._tag_stack.try_pop(parser_token.tag_name); //remove it and all ancestors - } else { // it's a start-tag - // check if this tag is starting an element that has optional end element - // and do an ending needed - if (this._do_optional_end_element(parser_token)) { - if (!parser_token.is_inline_element) { - printer.print_newline(false); - } - } - - this._tag_stack.record_tag(parser_token); //push it on the tag stack - - if ((parser_token.tag_name === 'script' || parser_token.tag_name === 'style') && - !(parser_token.is_unformatted || parser_token.is_content_unformatted)) { - parser_token.custom_beautifier_name = get_custom_beautifier_name(parser_token.tag_check, raw_token); - } - } - } - - if (in_array(parser_token.tag_check, this._options.extra_liners)) { //check if this double needs an extra line - printer.print_newline(false); - if (!printer._output.just_added_blankline()) { - printer.print_newline(true); - } - } - - if (parser_token.is_empty_element) { //if this tag name is a single tag type (either in the list or has a closing /) - - // if you hit an else case, reset the indent level if you are inside an: - // 'if', 'unless', or 'each' block. - if (parser_token.tag_start_char === '{' && parser_token.tag_check === 'else') { - this._tag_stack.indent_to_tag(['if', 'unless', 'each']); - parser_token.indent_content = true; - // Don't add a newline if opening {{#if}} tag is on the current line - var foundIfOnCurrentLine = printer.current_line_has_match(/{{#if/); - if (!foundIfOnCurrentLine) { - printer.print_newline(false); - } - } - - // Don't add a newline before elements that should remain where they are. - if (parser_token.tag_name === '!--' && last_token.type === TOKEN.TAG_CLOSE && - last_tag_token.is_end_tag && parser_token.text.indexOf('\n') === -1) { - //Do nothing. Leave comments on same line. - } else { - if (!(parser_token.is_inline_element || parser_token.is_unformatted)) { - printer.print_newline(false); - } - this._calcluate_parent_multiline(printer, parser_token); - } - } else if (parser_token.is_end_tag) { //this tag is a double tag so check for tag-ending - var do_end_expand = false; - - // deciding whether a block is multiline should not be this hard - do_end_expand = parser_token.start_tag_token && parser_token.start_tag_token.multiline_content; - do_end_expand = do_end_expand || (!parser_token.is_inline_element && - !(last_tag_token.is_inline_element || last_tag_token.is_unformatted) && - !(last_token.type === TOKEN.TAG_CLOSE && parser_token.start_tag_token === last_tag_token) && - last_token.type !== 'TK_CONTENT' - ); - - if (parser_token.is_content_unformatted || parser_token.is_unformatted) { - do_end_expand = false; - } - - if (do_end_expand) { - printer.print_newline(false); - } - } else { // it's a start-tag - parser_token.indent_content = !parser_token.custom_beautifier_name; - - if (parser_token.tag_start_char === '<') { - if (parser_token.tag_name === 'html') { - parser_token.indent_content = this._options.indent_inner_html; - } else if (parser_token.tag_name === 'head') { - parser_token.indent_content = this._options.indent_head_inner_html; - } else if (parser_token.tag_name === 'body') { - parser_token.indent_content = this._options.indent_body_inner_html; - } - } - - if (!(parser_token.is_inline_element || parser_token.is_unformatted) && - (last_token.type !== 'TK_CONTENT' || parser_token.is_content_unformatted)) { - printer.print_newline(false); - } - - this._calcluate_parent_multiline(printer, parser_token); - } -}; - -Beautifier.prototype._calcluate_parent_multiline = function(printer, parser_token) { - if (parser_token.parent && printer._output.just_added_newline() && - !((parser_token.is_inline_element || parser_token.is_unformatted) && parser_token.parent.is_inline_element)) { - parser_token.parent.multiline_content = true; - } -}; - -//To be used for

                          tag special case: -var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul']; -var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video']; - -Beautifier.prototype._do_optional_end_element = function(parser_token) { - var result = null; - // NOTE: cases of "if there is no more content in the parent element" - // are handled automatically by the beautifier. - // It assumes parent or ancestor close tag closes all children. - // https://www.w3.org/TR/html5/syntax.html#optional-tags - if (parser_token.is_empty_element || !parser_token.is_start_tag || !parser_token.parent) { - return; - - } - - if (parser_token.tag_name === 'body') { - // A head element’s end tag may be omitted if the head element is not immediately followed by a space character or a comment. - result = result || this._tag_stack.try_pop('head'); - - //} else if (parser_token.tag_name === 'body') { - // DONE: A body element’s end tag may be omitted if the body element is not immediately followed by a comment. - - } else if (parser_token.tag_name === 'li') { - // An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element. - result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']); - - } else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') { - // A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element. - // A dt element’s end tag may be omitted if the dt element is immediately followed by another dt element or a dd element. - result = result || this._tag_stack.try_pop('dt', ['dl']); - result = result || this._tag_stack.try_pop('dd', ['dl']); - - - } else if (parser_token.parent.tag_name === 'p' && p_closers.indexOf(parser_token.tag_name) !== -1) { - // IMPORTANT: this else-if works because p_closers has no overlap with any other element we look for in this method - // check for the parent element is an HTML element that is not an ,

                          tag special case: -var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul']; -var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video']; - -Beautifier.prototype._do_optional_end_element = function(parser_token) { - var result = null; - // NOTE: cases of "if there is no more content in the parent element" - // are handled automatically by the beautifier. - // It assumes parent or ancestor close tag closes all children. - // https://www.w3.org/TR/html5/syntax.html#optional-tags - if (parser_token.is_empty_element || !parser_token.is_start_tag || !parser_token.parent) { - return; - - } - - if (parser_token.tag_name === 'body') { - // A head element’s end tag may be omitted if the head element is not immediately followed by a space character or a comment. - result = result || this._tag_stack.try_pop('head'); - - //} else if (parser_token.tag_name === 'body') { - // DONE: A body element’s end tag may be omitted if the body element is not immediately followed by a comment. - - } else if (parser_token.tag_name === 'li') { - // An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element. - result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']); - - } else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') { - // A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element. - // A dt element’s end tag may be omitted if the dt element is immediately followed by another dt element or a dd element. - result = result || this._tag_stack.try_pop('dt', ['dl']); - result = result || this._tag_stack.try_pop('dd', ['dl']); - - - } else if (parser_token.parent.tag_name === 'p' && p_closers.indexOf(parser_token.tag_name) !== -1) { - // IMPORTANT: this else-if works because p_closers has no overlap with any other element we look for in this method - // check for the parent element is an HTML element that is not an ,

                          tag special case: -var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul']; -var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video']; - -Beautifier.prototype._do_optional_end_element = function(parser_token) { - var result = null; - // NOTE: cases of "if there is no more content in the parent element" - // are handled automatically by the beautifier. - // It assumes parent or ancestor close tag closes all children. - // https://www.w3.org/TR/html5/syntax.html#optional-tags - if (parser_token.is_empty_element || !parser_token.is_start_tag || !parser_token.parent) { - return; - - } - - if (parser_token.tag_name === 'body') { - // A head element’s end tag may be omitted if the head element is not immediately followed by a space character or a comment. - result = result || this._tag_stack.try_pop('head'); - - //} else if (parser_token.tag_name === 'body') { - // DONE: A body element’s end tag may be omitted if the body element is not immediately followed by a comment. - - } else if (parser_token.tag_name === 'li') { - // An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element. - result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']); - - } else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') { - // A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element. - // A dt element’s end tag may be omitted if the dt element is immediately followed by another dt element or a dd element. - result = result || this._tag_stack.try_pop('dt', ['dl']); - result = result || this._tag_stack.try_pop('dd', ['dl']); - - - } else if (parser_token.parent.tag_name === 'p' && p_closers.indexOf(parser_token.tag_name) !== -1) { - // IMPORTANT: this else-if works because p_closers has no overlap with any other element we look for in this method - // check for the parent element is an HTML element that is not an ,

                          Image test

                          " - And I select the text in the "Description" Atto editor - And I click on "Insert or edit image" "button" - And I click on "Browse repositories..." "button" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.png" "link" - And I click on "Select this file" "button" - And I set the field "Describe this image for someone who cannot see it" to "It's the Moodle" - # Wait for the page to "settle". - And I wait until the page is ready - And the field "Width" matches value "204" - And the field "Height" matches value "61" - And I set the field "Auto size" to "1" - And I wait until the page is ready - And I set the field "Width" to "2040" - # Trigger blur on the width field. - And I take focus off "Width" "field" - And the field "Height" matches value "610" - And I set the field "Height" to "61" - # Trigger blur on the height field. - And I take focus off "Height" "field" - And the field "Width" matches value "204" - And I set the field "Auto size" to "0" - And I wait until the page is ready - And I set the field "Width" to "123" - And I set the field "Height" to "456" - # Trigger blur on the height field. - And I take focus off "Height" "field" - And the field "Width" matches value "123" - And the field "Height" matches value "456" - And I change window size to "large" - And I press "Save image" - And I press "Update profile" - And I click on "Edit profile" "link" in the "region-main" "region" - And I select the text in the "Description" Atto editor - And I click on "Insert or edit image" "button" - Then the field "Describe this image for someone who cannot see it" matches value "It's the Moodle" - And the field "Width" matches value "123" - And the field "Height" matches value "456" - - @javascript - Scenario: Manually inserting an image - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          Image: .

                          " - And I select the text in the "Description" Atto editor - When I click on "Insert or edit image" "button" - Then the field "Enter URL" matches value "/nothing/here" - And I set the field "Describe this image for someone who cannot see it" to "Something" - And I set the field "Width" to "1" - And I set the field "Height" to "1" - And I press "Save image" - And I set the field "Description" to "

                          Image: Awesome!.

                          " - And I press "Update profile" - And I click on "Edit profile" "link" in the "region-main" "region" - And I select the text in the "Description" Atto editor - And I click on "Insert or edit image" "button" - And the field "Enter URL" matches value "/nothing/again" - And the field "Width" matches value "123" - And the field "Height" matches value "456" - And the field "Describe this image" matches value "Awesome!" - - @javascript - Scenario: Error handling when inserting an image manually - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          Image: .

                          " - And I select the text in the "Description" Atto editor - When I click on "Insert or edit image" "button" - Then the field "Enter URL" matches value "/nothing/here" - And I set the field "Describe this image for someone who cannot see it" to "" - And I take focus off "Describe this image for someone who cannot see it" "field" - And I should see "An image must have a description, unless it is marked as decorative only." - And I set the field "Describe this image for someone who cannot see it" to "Something" - And I set the field "Enter URL" to "" - And I press "Save image" - And I should see "An image must have a URL." - And I set the field "Enter URL" to "/nothing/here" - And I set the field "Width" to "1" - And I set the field "Height" to "1" - And I press "Save image" - And I press "Update profile" diff --git a/lib/editor/atto/plugins/image/version.php b/lib/editor/atto/plugins/image/version.php deleted file mode 100644 index 44ca9b32a8d..00000000000 --- a/lib/editor/atto/plugins/image/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_image - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_image'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js deleted file mode 100644 index bc43a272311..00000000000 --- a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js +++ /dev/null @@ -1,1116 +0,0 @@ -YUI.add('moodle-atto_image-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_image - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_image_alignment-button - */ - -/** - * Atto image selection tool. - * - * @namespace M.atto_image - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var CSS = { - RESPONSIVE: 'img-fluid', - INPUTALIGNMENT: 'atto_image_alignment', - INPUTALT: 'atto_image_altentry', - INPUTHEIGHT: 'atto_image_heightentry', - INPUTSUBMIT: 'atto_image_urlentrysubmit', - INPUTURL: 'atto_image_urlentry', - INPUTSIZE: 'atto_image_size', - INPUTWIDTH: 'atto_image_widthentry', - IMAGEALTWARNING: 'atto_image_altwarning', - IMAGEURLWARNING: 'atto_image_urlwarning', - IMAGEBROWSER: 'openimagebrowser', - IMAGEPRESENTATION: 'atto_image_presentation', - INPUTCONSTRAIN: 'atto_image_constrain', - INPUTCUSTOMSTYLE: 'atto_image_customstyle', - IMAGEPREVIEW: 'atto_image_preview', - IMAGEPREVIEWBOX: 'atto_image_preview_box', - ALIGNSETTINGS: 'atto_image_button' - }, - FORMNAMES = { - URL: 'urlentry', - ALT: 'altentry' - }, - SELECTORS = { - INPUTURL: '.' + CSS.INPUTURL - }, - ALIGNMENTS = [ - // Vertical alignment. - { - name: 'verticalAlign', - str: 'alignment_top', - value: 'text-top', - margin: '0 0.5em' - }, { - name: 'verticalAlign', - str: 'alignment_middle', - value: 'middle', - margin: '0 0.5em' - }, { - name: 'verticalAlign', - str: 'alignment_bottom', - value: 'text-bottom', - margin: '0 0.5em', - isDefault: true - }, - - // Floats. - { - name: 'float', - str: 'alignment_left', - value: 'left', - margin: '0 0.5em 0 0' - }, { - name: 'float', - str: 'alignment_right', - value: 'right', - margin: '0 0 0 0.5em' - } - ], - DEFAULTS = { - WIDTH: 160, - HEIGHT: 160, - }, - REGEX = { - ISPERCENT: /\d+%/ - }, - - COMPONENTNAME = 'atto_image', - - TEMPLATE = '' + - '
                          ' + - // Add the repository browser button. - '' + - '{{#if showFilepicker}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{else}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/if}}' + - - '' + - // Add the Alt box. - '
                          ' + - '' + - '' + - - // Add the character count. - '
                          ' + - '0' + - ' / 125' + - '
                          ' + - - // Add the presentation select box. - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - - // Add the size entry boxes. - '
                          ' + - '' + - '
                          ' + - '' + - ' x' + - - // Add the height entry box. - '' + - '' + - - // Add the constrain checkbox. - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - - // Add the alignment selector. - '
                          ' + - '' + - '' + - '
                          ' + - // Hidden input to store custom styles. - '' + - '
                          ' + - - // Add the image preview. - '
                          ' + - '
                          ' + - '' + - '
                          ' + - - // Add the submit button and close the form. - '' + - '
                          ' + - '
                          ', - - IMAGETEMPLATE = '' + - '{{alt}}'; - -Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * The most recently selected image. - * - * @param _selectedImage - * @type Node - * @private - */ - _selectedImage: null, - - /** - * A reference to the currently open form. - * - * @param _form - * @type Node - * @private - */ - _form: null, - - /** - * The dimensions of the raw image before we manipulate it. - * - * @param _rawImageDimensions - * @type Object - * @private - */ - _rawImageDimensions: null, - - initializer: function() { - - this.addButton({ - icon: 'e/insert_edit_image', - callback: this._displayDialogue, - tags: 'img', - tagMatchRequiresAll: false - }); - this.editor.delegate('dblclick', this._displayDialogue, 'img', this); - this.editor.delegate('click', this._handleClick, 'img', this); - this.editor.on('paste', this._handlePaste, this); - this.editor.on('drop', this._handleDragDrop, this); - - // ...e.preventDefault needed to stop the default event from clobbering the desired behaviour in some browsers. - this.editor.on('dragover', function(e) { - e.preventDefault(); - }, this); - this.editor.on('dragenter', function(e) { - e.preventDefault(); - }, this); - }, - - /** - * Handle a drag and drop event with an image. - * - * @method _handleDragDrop - * @param {EventFacade} e - * @private - */ - _handleDragDrop: function(e) { - if (!e._event || !e._event.dataTransfer) { - // Drop not fully supported in this browser. - return; - } - - this._handlePasteOrDropHelper(e, e._event.dataTransfer); - }, - - /** - * Handles paste events where - if the thing being pasted is an image. - * - * @method _handlePaste - * @param {EventFacade} e - * @return {boolean} false if we handled the event, else true. - * @private - */ - _handlePaste: function(e) { - if (!e._event || !e._event.clipboardData) { - // Paste not fully supported in this browser. - return true; - } - - return this._handlePasteOrDropHelper(e, e._event.clipboardData); - }, - - /** - * Handle a drag and drop event with an image. - * - * @method _handleDragDrop - * @param {EventFacade} e - * @param {DataTransfer} dataTransfer - * @return {boolean} false if we handled the event, else true. - * @private - */ - _handlePasteOrDropHelper: function(e, dataTransfer) { - - var items = dataTransfer.items, - didUpload = false; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.kind !== 'file') { - continue; - } - if (!this._isImage(item.type)) { - continue; - } - this._uploadImage(item.getAsFile()); - didUpload = true; - } - - if (didUpload) { - e.preventDefault(); - } - }, - - /** - * Is this file an image? - * - * @method _isImage - * @param {string} mimeType the file's mime type. - * @return {boolean} true if the file has an image mimeType. - * @private - */ - _isImage: function(mimeType) { - return mimeType.indexOf('image/') === 0; - }, - - /** - * Used by _handleDragDrop and _handlePaste to upload an image and insert it. - * - * @method _uploadImage - * @param {File} fileToSave - * @private - */ - _uploadImage: function(fileToSave) { - - var self = this, - host = this.get('host'), - template = Y.Handlebars.compile(IMAGETEMPLATE); - - host.saveSelection(); - - // Trigger form upload start events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadStarted(self.editor.get('id')); - }); - - var options = host.get('filepickeroptions').image, - savepath = (options.savepath === undefined) ? '/' : options.savepath, - formData = new FormData(), - timestamp = 0, - uploadid = "", - xhr = new XMLHttpRequest(), - imagehtml = "", - keys = Object.keys(options.repositories); - - formData.append('repo_upload_file', fileToSave); - formData.append('itemid', options.itemid); - - // List of repositories is an object rather than an array. This makes iteration more awkward. - for (var i = 0; i < keys.length; i++) { - if (options.repositories[keys[i]].type === 'upload') { - formData.append('repo_id', options.repositories[keys[i]].id); - break; - } - } - formData.append('env', options.env); - formData.append('sesskey', M.cfg.sesskey); - formData.append('client_id', options.client_id); - formData.append('savepath', savepath); - formData.append('ctx_id', options.context.id); - - // Insert spinner as a placeholder. - timestamp = new Date().getTime(); - uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp; - host.focus(); - host.restoreSelection(); - imagehtml = template({ - url: M.util.image_url("i/loading_small", 'moodle'), - alt: M.util.get_string('uploading', COMPONENTNAME), - id: uploadid - }); - host.insertContentAtFocusPoint(imagehtml); - self.markUpdated(); - - // Kick off a XMLHttpRequest. - xhr.onreadystatechange = function() { - var placeholder = self.editor.one('#' + uploadid), - result, - file, - newhtml, - newimage; - - if (xhr.readyState === 4) { - if (xhr.status === 200) { - result = JSON.parse(xhr.responseText); - if (result) { - if (result.error) { - if (placeholder) { - placeholder.remove(true); - } - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - throw new M.core.ajaxException(result); - } - - file = result; - if (result.event && result.event === 'fileexists') { - // A file with this name is already in use here - rename to avoid conflict. - // Chances are, it's a different image (stored in a different folder on the user's computer). - // If the user wants to reuse an existing image, they can copy/paste it within the editor. - file = result.newfile; - } - - // Replace placeholder with actual image. - newhtml = template({ - url: file.url, - presentation: true, - classlist: CSS.RESPONSIVE - }); - newimage = Y.Node.create(newhtml); - if (placeholder) { - placeholder.replace(newimage); - } else { - self.editor.appendChild(newimage); - } - self.markUpdated(); - } - } else { - Y.use('moodle-core-notification-alert', function() { - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); - }); - if (placeholder) { - placeholder.remove(true); - } - } - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - } - }; - xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true); - xhr.send(formData); - }, - - /** - * Handle a click on an image. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var image = e.target; - - var selection = this.get('host').getSelectionFromNode(image); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Display the image editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - // Reset the image dimensions. - this._rawImageDimensions = null; - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('imageproperties', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - focusOnShowSelector: SELECTORS.INPUTURL - }); - // Set a maximum width for the dialog. This will prevent the dialog width to extend beyond the screen width - // in cases when the uploaded image has larger width. - dialogue.get('boundingBox').setStyle('maxWidth', '90%'); - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Set the inputs for width and height if they are not set, and calculate - * if the constrain checkbox should be checked or not. - * - * @method _loadPreviewImage - * @param {String} url - * @private - */ - _loadPreviewImage: function(url) { - var image = new Image(); - var self = this; - - image.onerror = function() { - var preview = self._form.one('.' + CSS.IMAGEPREVIEW); - preview.setStyles({ - 'display': 'none' - }); - - // Centre the dialogue when clearing the image preview. - self.getDialogue().centerDialogue(); - }; - - image.onload = function() { - var input, currentwidth, currentheight, widthRatio, heightRatio; - - // Store dimensions of the raw image, falling back to defaults for images without dimensions (e.g. SVG). - self._rawImageDimensions = { - width: this.width || DEFAULTS.WIDTH, - height: this.height || DEFAULTS.HEIGHT, - }; - - input = self._form.one('.' + CSS.INPUTWIDTH); - currentwidth = input.get('value'); - if (currentwidth === '') { - input.set('value', self._rawImageDimensions.width); - currentwidth = "" + self._rawImageDimensions.width; - } - input = self._form.one('.' + CSS.INPUTHEIGHT); - currentheight = input.get('value'); - if (currentheight === '') { - input.set('value', self._rawImageDimensions.height); - currentheight = "" + self._rawImageDimensions.height; - } - input = self._form.one('.' + CSS.IMAGEPREVIEW); - input.setAttribute('src', this.src); - input.setStyles({ - 'display': 'inline' - }); - - input = self._form.one('.' + CSS.INPUTCONSTRAIN); - if (currentwidth.match(REGEX.ISPERCENT) && currentheight.match(REGEX.ISPERCENT)) { - input.set('checked', currentwidth === currentheight); - } else if (this.width === 0 || this.height === 0) { - // If we don't have both dimensions of the image, we can't auto-size it, so disable control. - input.set('disabled', 'disabled'); - } else { - // This is the same as comparing to 3 decimal places. - widthRatio = Math.round(1000 * parseInt(currentwidth, 10) / this.width); - heightRatio = Math.round(1000 * parseInt(currentheight, 10) / this.height); - input.set('checked', widthRatio === heightRatio); - } - - // Apply the image sizing. - self._autoAdjustSize(self); - - // Centre the dialogue once the preview image has loaded. - self.getDialogue().centerDialogue(); - }; - - image.src = url; - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} The content to place in the dialogue. - * @private - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - canShowFilepicker = this.get('host').canShowFilepicker('image'), - content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - CSS: CSS, - FORMNAMES: FORMNAMES, - component: COMPONENTNAME, - showFilepicker: canShowFilepicker, - alignments: ALIGNMENTS - })); - - this._form = content; - - // Configure the view of the current image. - this._applyImageProperties(this._form); - - this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this); - this._form.one('.' + CSS.INPUTURL).on('change', this._hasErrorUrlField, this); - this._form.one('.' + CSS.IMAGEPRESENTATION).on('change', this._hasErrorAltField, this); - this._form.one('.' + CSS.INPUTALT).on('blur', this._hasErrorAltField, this); - this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustSize, this); - this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustSize, this, true); - this._form.one('.' + CSS.INPUTCONSTRAIN).on('change', function(event) { - if (event.target.get('checked')) { - this._autoAdjustSize(event); - } - }, this); - this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this); - - if (canShowFilepicker) { - this._form.one('.' + CSS.IMAGEBROWSER).on('click', function() { - this.get('host').showFilepicker('image', this._filepickerCallback, this); - }, this); - } - - // Character count. - this._form.one('.' + CSS.INPUTALT).on('keyup', this._handleKeyup, this); - - return content; - }, - - _autoAdjustSize: function(e, forceHeight) { - forceHeight = forceHeight || false; - - var keyField = this._form.one('.' + CSS.INPUTWIDTH), - keyFieldType = 'width', - subField = this._form.one('.' + CSS.INPUTHEIGHT), - subFieldType = 'height', - constrainField = this._form.one('.' + CSS.INPUTCONSTRAIN), - keyFieldValue = keyField.get('value'), - subFieldValue = subField.get('value'), - imagePreview = this._form.one('.' + CSS.IMAGEPREVIEW), - rawPercentage, - rawSize; - - // If we do not know the image size, do not do anything. - if (!this._rawImageDimensions) { - return; - } - - // Set the width back to default if it is empty. - if (keyFieldValue === '') { - keyFieldValue = this._rawImageDimensions[keyFieldType]; - keyField.set('value', keyFieldValue); - keyFieldValue = keyField.get('value'); - } - - // Clear the existing preview sizes. - imagePreview.setStyles({ - width: null, - height: null - }); - - // Now update with the new values. - if (!constrainField.get('checked')) { - // We are not keeping the image proportion - update the preview accordingly. - - // Width. - if (keyFieldValue.match(REGEX.ISPERCENT)) { - rawPercentage = parseInt(keyFieldValue, 10); - rawSize = this._rawImageDimensions.width / 100 * rawPercentage; - imagePreview.setStyle('width', rawSize + 'px'); - } else { - imagePreview.setStyle('width', keyFieldValue + 'px'); - } - - // Height. - if (subFieldValue.match(REGEX.ISPERCENT)) { - rawPercentage = parseInt(subFieldValue, 10); - rawSize = this._rawImageDimensions.height / 100 * rawPercentage; - imagePreview.setStyle('height', rawSize + 'px'); - } else { - imagePreview.setStyle('height', subFieldValue + 'px'); - } - } else { - // We are keeping the image in proportion. - if (forceHeight) { - // By default we update based on width. Swap the key and sub fields around to achieve a height-based scale. - var _temporaryValue; - _temporaryValue = keyField; - keyField = subField; - subField = _temporaryValue; - - _temporaryValue = keyFieldType; - keyFieldType = subFieldType; - subFieldType = _temporaryValue; - - _temporaryValue = keyFieldValue; - keyFieldValue = subFieldValue; - subFieldValue = _temporaryValue; - } - - if (keyFieldValue.match(REGEX.ISPERCENT)) { - // This is a percentage based change. Copy it verbatim. - subFieldValue = keyFieldValue; - - // Set the width to the calculated pixel width. - rawPercentage = parseInt(keyFieldValue, 10); - rawSize = this._rawImageDimensions.width / 100 * rawPercentage; - - // And apply the width/height to the container. - imagePreview.setStyle('width', rawSize); - rawSize = this._rawImageDimensions.height / 100 * rawPercentage; - imagePreview.setStyle('height', rawSize); - } else { - // Calculate the scaled subFieldValue from the keyFieldValue. - subFieldValue = Math.round((keyFieldValue / this._rawImageDimensions[keyFieldType]) * - this._rawImageDimensions[subFieldType]); - - if (forceHeight) { - imagePreview.setStyles({ - 'width': subFieldValue, - 'height': keyFieldValue - }); - } else { - imagePreview.setStyles({ - 'width': keyFieldValue, - 'height': subFieldValue - }); - } - } - - // Update the subField's value within the form to reflect the changes. - subField.set('value', subFieldValue); - } - }, - - /** - * Update the dialogue after an image was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the image. - * @private - */ - _filepickerCallback: function(params) { - if (params.url !== '') { - var input = this._form.one('.' + CSS.INPUTURL); - input.set('value', params.url); - - // Auto set the width and height. - this._form.one('.' + CSS.INPUTWIDTH).set('value', ''); - this._form.one('.' + CSS.INPUTHEIGHT).set('value', ''); - - // Load the preview image. - this._loadPreviewImage(params.url); - } - }, - - /** - * Applies properties of an existing image to the image dialogue for editing. - * - * @method _applyImageProperties - * @param {Node} form - * @private - */ - _applyImageProperties: function(form) { - var properties = this._getSelectedImageProperties(), - img = form.one('.' + CSS.IMAGEPREVIEW); - - if (properties === false) { - img.setStyle('display', 'none'); - // Set the default alignment. - ALIGNMENTS.some(function(alignment) { - if (alignment.isDefault) { - form.one('.' + CSS.INPUTALIGNMENT).set('value', alignment.value); - return true; - } - - return false; - }, this); - - return; - } - - if (properties.align) { - form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align); - } - if (properties.customstyle) { - form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle); - } - if (properties.width) { - form.one('.' + CSS.INPUTWIDTH).set('value', properties.width); - } - if (properties.height) { - form.one('.' + CSS.INPUTHEIGHT).set('value', properties.height); - } - if (properties.alt) { - form.one('.' + CSS.INPUTALT).set('value', properties.alt); - } - if (properties.src) { - form.one('.' + CSS.INPUTURL).set('value', properties.src); - this._loadPreviewImage(properties.src); - } - if (properties.presentation) { - form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked'); - } - - // Update the image preview based on the form properties. - this._autoAdjustSize(); - }, - - /** - * Gets the properties of the currently selected image. - * - * The first image only if multiple images are selected. - * - * @method _getSelectedImageProperties - * @return {object} - * @private - */ - _getSelectedImageProperties: function() { - var properties = { - src: null, - alt: null, - width: null, - height: null, - align: '', - presentation: false - }, - - // Get the current selection. - images = this.get('host').getSelectedNodes(), - width, - height, - style, - image; - - if (images) { - images = images.filter('img'); - } - - if (images && images.size()) { - image = this._removeLegacyAlignment(images.item(0)); - this._selectedImage = image; - - style = image.getAttribute('style'); - properties.customstyle = style; - - width = image.getAttribute('width'); - if (!width.match(REGEX.ISPERCENT)) { - width = parseInt(width, 10); - } - height = image.getAttribute('height'); - if (!height.match(REGEX.ISPERCENT)) { - height = parseInt(height, 10); - } - - if (width !== 0) { - properties.width = width; - } - if (height !== 0) { - properties.height = height; - } - this._getAlignmentPropeties(image, properties); - properties.src = image.getAttribute('src'); - properties.alt = image.getAttribute('alt') || ''; - properties.presentation = (image.get('role') === 'presentation'); - return properties; - } - - // No image selected - clean up. - this._selectedImage = null; - return false; - }, - - /** - * Sets the alignment of a properties object. - * - * @method _getAlignmentPropeties - * @param {Node} image The image that the alignment properties should be found for - * @param {Object} properties The properties object that is created in _getSelectedImageProperties() - * @private - */ - _getAlignmentPropeties: function(image, properties) { - var complete = false, - defaultAlignment; - - // Check for an alignment value. - complete = ALIGNMENTS.some(function(alignment) { - var classname = this._getAlignmentClass(alignment.value); - if (image.hasClass(classname)) { - properties.align = alignment.value; - Y.log('Found alignment ' + alignment.value, 'debug', 'atto_image-button'); - - return true; - } - - if (alignment.isDefault) { - defaultAlignment = alignment.value; - } - - return false; - }, this); - - if (!complete && defaultAlignment) { - properties.align = defaultAlignment; - } - }, - - /** - * Update the form when the URL was changed. This includes updating the - * height, width, and image preview. - * - * @method _urlChanged - * @private - */ - _urlChanged: function() { - var input = this._form.one('.' + CSS.INPUTURL); - - if (input.get('value') !== '') { - // Load the preview image. - this._loadPreviewImage(input.get('value')); - } - }, - - /** - * Update the image in the contenteditable. - * - * @method _setImage - * @param {EventFacade} e - * @private - */ - _setImage: function(e) { - var form = this._form, - url = form.one('.' + CSS.INPUTURL).get('value'), - alt = form.one('.' + CSS.INPUTALT).get('value'), - width = form.one('.' + CSS.INPUTWIDTH).get('value'), - height = form.one('.' + CSS.INPUTHEIGHT).get('value'), - alignment = this._getAlignmentClass(form.one('.' + CSS.INPUTALIGNMENT).get('value')), - presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'), - constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'), - imagehtml, - customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value'), - classlist = [], - host = this.get('host'); - - e.preventDefault(); - - // Check if there are any accessibility issues. - if (this._updateWarning()) { - return; - } - - // Focus on the editor in preparation for inserting the image. - host.focus(); - if (url !== '') { - if (this._selectedImage) { - host.setSelection(host.getSelectionFromNode(this._selectedImage)); - } else { - host.setSelection(this._currentSelection); - } - - if (constrain) { - classlist.push(CSS.RESPONSIVE); - } - - // Add the alignment class for the image. - classlist.push(alignment); - - if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) { - form.one('.' + CSS.INPUTWIDTH).focus(); - return; - } - if (!height.match(REGEX.ISPERCENT) && isNaN(parseInt(height, 10))) { - form.one('.' + CSS.INPUTHEIGHT).focus(); - return; - } - - var template = Y.Handlebars.compile(IMAGETEMPLATE); - imagehtml = template({ - url: url, - alt: alt, - width: width, - height: height, - presentation: presentation, - customstyle: customstyle, - classlist: classlist.join(' ') - }); - - this.get('host').insertContentAtFocusPoint(imagehtml); - - this.markUpdated(); - } - - this.getDialogue({ - focusAfterHide: null - }).hide(); - - }, - - /** - * Removes any legacy styles added by previous versions of the atto image button. - * - * @method _removeLegacyAlignment - * @param {Y.Node} imageNode - * @return {Y.Node} - * @private - */ - _removeLegacyAlignment: function(imageNode) { - if (!imageNode.getStyle('margin')) { - // There is no margin therefore this cannot match any known alignments. - return imageNode; - } - - ALIGNMENTS.some(function(alignment) { - if (imageNode.getStyle(alignment.name) !== alignment.value) { - // The name/value do not match. Skip. - return false; - } - - var normalisedNode = Y.Node.create('
                          '); - normalisedNode.setStyle('margin', alignment.margin); - if (imageNode.getStyle('margin') !== normalisedNode.getStyle('margin')) { - // The margin does not match. - return false; - } - - Y.log('Legacy alignment found and removed.', 'info', 'atto_image-button'); - imageNode.addClass(this._getAlignmentClass(alignment.value)); - imageNode.setStyle(alignment.name, null); - imageNode.setStyle('margin', null); - - return true; - }, this); - - return imageNode; - }, - - _getAlignmentClass: function(alignment) { - return CSS.ALIGNSETTINGS + '_' + alignment; - }, - - _toggleVisibility: function(selector, predicate) { - var form = this._form; - var element = form.all(selector); - element.setStyle('display', predicate ? 'block' : 'none'); - }, - - _toggleAriaInvalid: function(selectors, predicate) { - var form = this._form; - selectors.forEach(function(selector) { - var element = form.all(selector); - element.setAttribute('aria-invalid', predicate); - }); - }, - - _hasErrorUrlField: function() { - var form = this._form; - var url = form.one('.' + CSS.INPUTURL).get('value'); - var urlerror = url === ''; - this._toggleVisibility('.' + CSS.IMAGEURLWARNING, urlerror); - this._toggleAriaInvalid(['.' + CSS.INPUTURL], urlerror); - return urlerror; - }, - - _hasErrorAltField: function() { - var form = this._form; - var alt = form.one('.' + CSS.INPUTALT).get('value'); - var presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'); - var imagealterror = alt === '' && !presentation; - this._toggleVisibility('.' + CSS.IMAGEALTWARNING, imagealterror); - this._toggleAriaInvalid(['.' + CSS.INPUTALT, '.' + CSS.IMAGEPRESENTATION], imagealterror); - return imagealterror; - }, - /** - * Update the alt text warning live. - * - * @method _updateWarning - * @return {boolean} whether a warning should be displayed. - * @private - */ - _updateWarning: function() { - var urlerror = this._hasErrorUrlField(); - var imagealterror = this._hasErrorAltField(); - var haserrors = urlerror || imagealterror; - this.getDialogue().centerDialogue(); - return haserrors; - }, - - /** - * Handle the keyup to update the character count. - */ - _handleKeyup: function() { - var form = this._form, - alt = form.one('.' + CSS.INPUTALT).get('value'), - characterCount = alt.length, - current = form.one('#currentcount'); - current.setHTML(characterCount); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js deleted file mode 100644 index e3985ea6d3d..00000000000 --- a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js +++ /dev/null @@ -1,3 +0,0 @@ -YUI.add("moodle-atto_image-button",function(m,e){var c={RESPONSIVE:"img-fluid",INPUTALIGNMENT:"atto_image_alignment",INPUTALT:"atto_image_altentry",INPUTHEIGHT:"atto_image_heightentry",INPUTSUBMIT:"atto_image_urlentrysubmit",INPUTURL:"atto_image_urlentry",INPUTSIZE:"atto_image_size",INPUTWIDTH:"atto_image_widthentry",IMAGEALTWARNING:"atto_image_altwarning",IMAGEURLWARNING:"atto_image_urlwarning",IMAGEBROWSER:"openimagebrowser",IMAGEPRESENTATION:"atto_image_presentation",INPUTCONSTRAIN:"atto_image_constrain",INPUTCUSTOMSTYLE:"atto_image_customstyle",IMAGEPREVIEW:"atto_image_preview",IMAGEPREVIEWBOX:"atto_image_preview_box",ALIGNSETTINGS:"atto_image_button"},i={URL:"urlentry",ALT:"altentry"},t={INPUTURL:"."+c.INPUTURL},s=[{name:"verticalAlign",str:"alignment_top",value:"text-top",margin:"0 0.5em"},{name:"verticalAlign",str:"alignment_middle",value:"middle",margin:"0 0.5em"},{name:"verticalAlign",str:"alignment_bottom",value:"text-bottom",margin:"0 0.5em",isDefault:!0},{name:"float",str:"alignment_left",value:"left",margin:"0 0.5em 0 0"},{name:"float",str:"alignment_right",value:"right",margin:"0 0 0 0.5em"}],a=160,o=160,u=/\d+%/,d="atto_image",I='{{alt}}';m.namespace("M.atto_image").Button=m.Base.create("button",m.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_selectedImage:null,_form:null,_rawImageDimensions:null,initializer:function(){this.addButton({icon:"e/insert_edit_image",callback:this._displayDialogue,tags:"img",tagMatchRequiresAll:!1}),this.editor.delegate("dblclick",this._displayDialogue,"img",this),this.editor.delegate("click",this._handleClick,"img",this),this.editor.on("paste",this._handlePaste,this),this.editor.on("drop",this._handleDragDrop,this),this.editor.on("dragover",function(e){e.preventDefault()},this),this.editor.on("dragenter",function(e){e.preventDefault()},this)},_handleDragDrop:function(e){e._event&&e._event.dataTransfer&&this._handlePasteOrDropHelper(e,e._event.dataTransfer)},_handlePaste:function(e){return!e._event||!e._event.clipboardData||this._handlePasteOrDropHelper(e,e._event.clipboardData)},_handlePasteOrDropHelper:function(e,t){for(var i,n=t.items,a=!1,s=0;s{{#if showFilepicker}}
                          {{else}}
                          {{/if}}
                          0 / 125
                          x

                          '),t=this.get("host").canShowFilepicker("image"),e=m.Node.create(e({elementid:this.get("host").get("elementid"),CSS:c,FORMNAMES:i,component:d,showFilepicker:t,alignments:s}));return this._form=e,this._applyImageProperties(this._form),this._form.one("."+c.INPUTURL).on("blur",this._urlChanged,this),this._form.one("."+c.INPUTURL).on("change",this._hasErrorUrlField,this),this._form.one("."+c.IMAGEPRESENTATION).on("change",this._hasErrorAltField,this),this._form.one("."+c.INPUTALT).on("blur",this._hasErrorAltField,this),this._form.one("."+c.INPUTWIDTH).on("blur",this._autoAdjustSize,this),this._form.one("."+c.INPUTHEIGHT).on("blur",this._autoAdjustSize,this,!0),this._form.one("."+c.INPUTCONSTRAIN).on("change",function(e){e.target.get("checked")&&this._autoAdjustSize(e)},this),this._form.one("."+c.INPUTSUBMIT).on("click",this._setImage,this),t&&this._form.one("."+c.IMAGEBROWSER).on("click",function(){this.get("host").showFilepicker("image",this._filepickerCallback,this)},this),this._form.one("."+c.INPUTALT).on("keyup",this._handleKeyup,this),e},_autoAdjustSize:function(g,e){var t,i,n,d,a,s,o,l,r,h;e=e||!1,t=this._form.one("."+c.INPUTWIDTH),i="width",n=this._form.one("."+c.INPUTHEIGHT),d="height",h=this._form.one("."+c.INPUTCONSTRAIN),a=t.get("value"),s=n.get("value"),o=this._form.one("."+c.IMAGEPREVIEW),this._rawImageDimensions&&(""===a&&(a=this._rawImageDimensions[i],t.set("value",a),a=t.get("value")),o.setStyles({width:null,height:null}),h.get("checked")?(e&&(h=t,t=n,n=h,h=i,i=d,d=h,h=a,a=s,s=h),a.match(u)?(s=a,l=parseInt(a,10),r=this._rawImageDimensions.width/100*l,o.setStyle("width",r),r=this._rawImageDimensions.height/100*l,o.setStyle("height",r)):(s=Math.round(a/this._rawImageDimensions[i]*this._rawImageDimensions[d]),e?o.setStyles({width:s,height:a}):o.setStyles({width:a,height:s})),n.set("value",s)):(a.match(u)?(l=parseInt(a,10),r=this._rawImageDimensions.width/100*l,o.setStyle("width",r+"px")):o.setStyle("width",a+"px"),s.match(u)?(l=parseInt(s,10),r=this._rawImageDimensions.height/100*l,o.setStyle("height",r+"px")):o.setStyle("height",s+"px")))},_filepickerCallback:function(e){""!==e.url&&(this._form.one("."+c.INPUTURL).set("value",e.url),this._form.one("."+c.INPUTWIDTH).set("value",""),this._form.one("."+c.INPUTHEIGHT).set("value",""),this._loadPreviewImage(e.url))},_applyImageProperties:function(t){var e=this._getSelectedImageProperties(),i=t.one("."+c.IMAGEPREVIEW);if(!1===e)return i.setStyle("display","none"),void s.some(function(e){return!!e.isDefault&&(t.one("."+c.INPUTALIGNMENT).set("value", -e.value),!0)},this);e.align&&t.one("."+c.INPUTALIGNMENT).set("value",e.align),e.customstyle&&t.one("."+c.INPUTCUSTOMSTYLE).set("value",e.customstyle),e.width&&t.one("."+c.INPUTWIDTH).set("value",e.width),e.height&&t.one("."+c.INPUTHEIGHT).set("value",e.height),e.alt&&t.one("."+c.INPUTALT).set("value",e.alt),e.src&&(t.one("."+c.INPUTURL).set("value",e.src),this._loadPreviewImage(e.src)),e.presentation&&t.one("."+c.IMAGEPRESENTATION).set("checked","checked"),this._autoAdjustSize()},_getSelectedImageProperties:function(){var e,t,i={src:null,alt:null,width:null,height:null,align:"",presentation:!1},n=this.get("host").getSelectedNodes();return(n=n&&n.filter("img"))&&n.size()?(n=this._removeLegacyAlignment(n.item(0)),t=(this._selectedImage=n).getAttribute("style"),i.customstyle=t,(t=n.getAttribute("width")).match(u)||(t=parseInt(t,10)),(e=n.getAttribute("height")).match(u)||(e=parseInt(e,10)),0!==t&&(i.width=t),0!==e&&(i.height=e),this._getAlignmentPropeties(n,i),i.src=n.getAttribute("src"),i.alt=n.getAttribute("alt")||"",i.presentation="presentation"===n.get("role"),i):(this._selectedImage=null,!1)},_getAlignmentPropeties:function(i,n){var a;!s.some(function(e){var t=this._getAlignmentClass(e.value);return i.hasClass(t)?(n.align=e.value,!0):(e.isDefault&&(a=e.value),!1)},this)&&a&&(n.align=a)},_urlChanged:function(){var e=this._form.one("."+c.INPUTURL);""!==e.get("value")&&this._loadPreviewImage(e.get("value"))},_setImage:function(e){var t=this._form,i=t.one("."+c.INPUTURL).get("value"),n=t.one("."+c.INPUTALT).get("value"),a=t.one("."+c.INPUTWIDTH).get("value"),s=t.one("."+c.INPUTHEIGHT).get("value"),o=this._getAlignmentClass(t.one("."+c.INPUTALIGNMENT).get("value")),l=t.one("."+c.IMAGEPRESENTATION).get("checked"),g=t.one("."+c.INPUTCONSTRAIN).get("checked"),d=t.one("."+c.INPUTCUSTOMSTYLE).get("value"),r=[],h=this.get("host");if(e.preventDefault(),!this._updateWarning()){if(h.focus(),""!==i){if(this._selectedImage?h.setSelection(h.getSelectionFromNode(this._selectedImage)):h.setSelection(this._currentSelection),g&&r.push(c.RESPONSIVE),r.push(o),!a.match(u)&&isNaN(parseInt(a,10)))return void t.one("."+c.INPUTWIDTH).focus();if(!s.match(u)&&isNaN(parseInt(s,10)))return void t.one("."+c.INPUTHEIGHT).focus();e=m.Handlebars.compile(I)({url:i,alt:n,width:a,height:s,presentation:l,customstyle:d,classlist:r.join(" ")}),this.get("host").insertContentAtFocusPoint(e),this.markUpdated()}this.getDialogue({focusAfterHide:null}).hide()}},_removeLegacyAlignment:function(i){return i.getStyle("margin")&&s.some(function(e){if(i.getStyle(e.name)!==e.value)return!1;var t=m.Node.create("
                          ");return t.setStyle("margin",e.margin),i.getStyle("margin")===t.getStyle("margin")&&(i.addClass(this._getAlignmentClass(e.value)),i.setStyle(e.name,null),i.setStyle("margin",null),!0)},this),i},_getAlignmentClass:function(e){return c.ALIGNSETTINGS+"_"+e},_toggleVisibility:function(e,t){var i=this._form,e=i.all(e);e.setStyle("display",t?"block":"none")},_toggleAriaInvalid:function(e,t){var i=this._form;e.forEach(function(e){i.all(e).setAttribute("aria-invalid",t)})},_hasErrorUrlField:function(){var e=this._form,e=e.one("."+c.INPUTURL).get("value"),e=""===e;return this._toggleVisibility("."+c.IMAGEURLWARNING,e),this._toggleAriaInvalid(["."+c.INPUTURL],e),e},_hasErrorAltField:function(){var e=this._form,t=e.one("."+c.INPUTALT).get("value"),e=e.one("."+c.IMAGEPRESENTATION).get("checked"),t=""===t&&!e;return this._toggleVisibility("."+c.IMAGEALTWARNING,t),this._toggleAriaInvalid(["."+c.INPUTALT,"."+c.IMAGEPRESENTATION],t),t},_updateWarning:function(){var e=this._hasErrorUrlField(),t=this._hasErrorAltField(),e=e||t;return this.getDialogue().centerDialogue(),e},_handleKeyup:function(){var e=this._form,t=e.one("."+c.INPUTALT).get("value").length;e.one("#currentcount").setHTML(t)}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js deleted file mode 100644 index 3b744fe905b..00000000000 --- a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js +++ /dev/null @@ -1,1114 +0,0 @@ -YUI.add('moodle-atto_image-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_image - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_image_alignment-button - */ - -/** - * Atto image selection tool. - * - * @namespace M.atto_image - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var CSS = { - RESPONSIVE: 'img-fluid', - INPUTALIGNMENT: 'atto_image_alignment', - INPUTALT: 'atto_image_altentry', - INPUTHEIGHT: 'atto_image_heightentry', - INPUTSUBMIT: 'atto_image_urlentrysubmit', - INPUTURL: 'atto_image_urlentry', - INPUTSIZE: 'atto_image_size', - INPUTWIDTH: 'atto_image_widthentry', - IMAGEALTWARNING: 'atto_image_altwarning', - IMAGEURLWARNING: 'atto_image_urlwarning', - IMAGEBROWSER: 'openimagebrowser', - IMAGEPRESENTATION: 'atto_image_presentation', - INPUTCONSTRAIN: 'atto_image_constrain', - INPUTCUSTOMSTYLE: 'atto_image_customstyle', - IMAGEPREVIEW: 'atto_image_preview', - IMAGEPREVIEWBOX: 'atto_image_preview_box', - ALIGNSETTINGS: 'atto_image_button' - }, - FORMNAMES = { - URL: 'urlentry', - ALT: 'altentry' - }, - SELECTORS = { - INPUTURL: '.' + CSS.INPUTURL - }, - ALIGNMENTS = [ - // Vertical alignment. - { - name: 'verticalAlign', - str: 'alignment_top', - value: 'text-top', - margin: '0 0.5em' - }, { - name: 'verticalAlign', - str: 'alignment_middle', - value: 'middle', - margin: '0 0.5em' - }, { - name: 'verticalAlign', - str: 'alignment_bottom', - value: 'text-bottom', - margin: '0 0.5em', - isDefault: true - }, - - // Floats. - { - name: 'float', - str: 'alignment_left', - value: 'left', - margin: '0 0.5em 0 0' - }, { - name: 'float', - str: 'alignment_right', - value: 'right', - margin: '0 0 0 0.5em' - } - ], - DEFAULTS = { - WIDTH: 160, - HEIGHT: 160, - }, - REGEX = { - ISPERCENT: /\d+%/ - }, - - COMPONENTNAME = 'atto_image', - - TEMPLATE = '' + - '
                          ' + - // Add the repository browser button. - '' + - '{{#if showFilepicker}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{else}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/if}}' + - - '' + - // Add the Alt box. - '
                          ' + - '' + - '' + - - // Add the character count. - '
                          ' + - '0' + - ' / 125' + - '
                          ' + - - // Add the presentation select box. - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - - // Add the size entry boxes. - '
                          ' + - '' + - '
                          ' + - '' + - ' x' + - - // Add the height entry box. - '' + - '' + - - // Add the constrain checkbox. - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - - // Add the alignment selector. - '
                          ' + - '' + - '' + - '
                          ' + - // Hidden input to store custom styles. - '' + - '
                          ' + - - // Add the image preview. - '
                          ' + - '
                          ' + - '' + - '
                          ' + - - // Add the submit button and close the form. - '' + - '
                          ' + - '
                          ', - - IMAGETEMPLATE = '' + - '{{alt}}'; - -Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * The most recently selected image. - * - * @param _selectedImage - * @type Node - * @private - */ - _selectedImage: null, - - /** - * A reference to the currently open form. - * - * @param _form - * @type Node - * @private - */ - _form: null, - - /** - * The dimensions of the raw image before we manipulate it. - * - * @param _rawImageDimensions - * @type Object - * @private - */ - _rawImageDimensions: null, - - initializer: function() { - - this.addButton({ - icon: 'e/insert_edit_image', - callback: this._displayDialogue, - tags: 'img', - tagMatchRequiresAll: false - }); - this.editor.delegate('dblclick', this._displayDialogue, 'img', this); - this.editor.delegate('click', this._handleClick, 'img', this); - this.editor.on('paste', this._handlePaste, this); - this.editor.on('drop', this._handleDragDrop, this); - - // ...e.preventDefault needed to stop the default event from clobbering the desired behaviour in some browsers. - this.editor.on('dragover', function(e) { - e.preventDefault(); - }, this); - this.editor.on('dragenter', function(e) { - e.preventDefault(); - }, this); - }, - - /** - * Handle a drag and drop event with an image. - * - * @method _handleDragDrop - * @param {EventFacade} e - * @private - */ - _handleDragDrop: function(e) { - if (!e._event || !e._event.dataTransfer) { - // Drop not fully supported in this browser. - return; - } - - this._handlePasteOrDropHelper(e, e._event.dataTransfer); - }, - - /** - * Handles paste events where - if the thing being pasted is an image. - * - * @method _handlePaste - * @param {EventFacade} e - * @return {boolean} false if we handled the event, else true. - * @private - */ - _handlePaste: function(e) { - if (!e._event || !e._event.clipboardData) { - // Paste not fully supported in this browser. - return true; - } - - return this._handlePasteOrDropHelper(e, e._event.clipboardData); - }, - - /** - * Handle a drag and drop event with an image. - * - * @method _handleDragDrop - * @param {EventFacade} e - * @param {DataTransfer} dataTransfer - * @return {boolean} false if we handled the event, else true. - * @private - */ - _handlePasteOrDropHelper: function(e, dataTransfer) { - - var items = dataTransfer.items, - didUpload = false; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.kind !== 'file') { - continue; - } - if (!this._isImage(item.type)) { - continue; - } - this._uploadImage(item.getAsFile()); - didUpload = true; - } - - if (didUpload) { - e.preventDefault(); - } - }, - - /** - * Is this file an image? - * - * @method _isImage - * @param {string} mimeType the file's mime type. - * @return {boolean} true if the file has an image mimeType. - * @private - */ - _isImage: function(mimeType) { - return mimeType.indexOf('image/') === 0; - }, - - /** - * Used by _handleDragDrop and _handlePaste to upload an image and insert it. - * - * @method _uploadImage - * @param {File} fileToSave - * @private - */ - _uploadImage: function(fileToSave) { - - var self = this, - host = this.get('host'), - template = Y.Handlebars.compile(IMAGETEMPLATE); - - host.saveSelection(); - - // Trigger form upload start events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadStarted(self.editor.get('id')); - }); - - var options = host.get('filepickeroptions').image, - savepath = (options.savepath === undefined) ? '/' : options.savepath, - formData = new FormData(), - timestamp = 0, - uploadid = "", - xhr = new XMLHttpRequest(), - imagehtml = "", - keys = Object.keys(options.repositories); - - formData.append('repo_upload_file', fileToSave); - formData.append('itemid', options.itemid); - - // List of repositories is an object rather than an array. This makes iteration more awkward. - for (var i = 0; i < keys.length; i++) { - if (options.repositories[keys[i]].type === 'upload') { - formData.append('repo_id', options.repositories[keys[i]].id); - break; - } - } - formData.append('env', options.env); - formData.append('sesskey', M.cfg.sesskey); - formData.append('client_id', options.client_id); - formData.append('savepath', savepath); - formData.append('ctx_id', options.context.id); - - // Insert spinner as a placeholder. - timestamp = new Date().getTime(); - uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp; - host.focus(); - host.restoreSelection(); - imagehtml = template({ - url: M.util.image_url("i/loading_small", 'moodle'), - alt: M.util.get_string('uploading', COMPONENTNAME), - id: uploadid - }); - host.insertContentAtFocusPoint(imagehtml); - self.markUpdated(); - - // Kick off a XMLHttpRequest. - xhr.onreadystatechange = function() { - var placeholder = self.editor.one('#' + uploadid), - result, - file, - newhtml, - newimage; - - if (xhr.readyState === 4) { - if (xhr.status === 200) { - result = JSON.parse(xhr.responseText); - if (result) { - if (result.error) { - if (placeholder) { - placeholder.remove(true); - } - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - throw new M.core.ajaxException(result); - } - - file = result; - if (result.event && result.event === 'fileexists') { - // A file with this name is already in use here - rename to avoid conflict. - // Chances are, it's a different image (stored in a different folder on the user's computer). - // If the user wants to reuse an existing image, they can copy/paste it within the editor. - file = result.newfile; - } - - // Replace placeholder with actual image. - newhtml = template({ - url: file.url, - presentation: true, - classlist: CSS.RESPONSIVE - }); - newimage = Y.Node.create(newhtml); - if (placeholder) { - placeholder.replace(newimage); - } else { - self.editor.appendChild(newimage); - } - self.markUpdated(); - } - } else { - Y.use('moodle-core-notification-alert', function() { - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); - }); - if (placeholder) { - placeholder.remove(true); - } - } - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - } - }; - xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true); - xhr.send(formData); - }, - - /** - * Handle a click on an image. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var image = e.target; - - var selection = this.get('host').getSelectionFromNode(image); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Display the image editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - // Reset the image dimensions. - this._rawImageDimensions = null; - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('imageproperties', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - focusOnShowSelector: SELECTORS.INPUTURL - }); - // Set a maximum width for the dialog. This will prevent the dialog width to extend beyond the screen width - // in cases when the uploaded image has larger width. - dialogue.get('boundingBox').setStyle('maxWidth', '90%'); - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Set the inputs for width and height if they are not set, and calculate - * if the constrain checkbox should be checked or not. - * - * @method _loadPreviewImage - * @param {String} url - * @private - */ - _loadPreviewImage: function(url) { - var image = new Image(); - var self = this; - - image.onerror = function() { - var preview = self._form.one('.' + CSS.IMAGEPREVIEW); - preview.setStyles({ - 'display': 'none' - }); - - // Centre the dialogue when clearing the image preview. - self.getDialogue().centerDialogue(); - }; - - image.onload = function() { - var input, currentwidth, currentheight, widthRatio, heightRatio; - - // Store dimensions of the raw image, falling back to defaults for images without dimensions (e.g. SVG). - self._rawImageDimensions = { - width: this.width || DEFAULTS.WIDTH, - height: this.height || DEFAULTS.HEIGHT, - }; - - input = self._form.one('.' + CSS.INPUTWIDTH); - currentwidth = input.get('value'); - if (currentwidth === '') { - input.set('value', self._rawImageDimensions.width); - currentwidth = "" + self._rawImageDimensions.width; - } - input = self._form.one('.' + CSS.INPUTHEIGHT); - currentheight = input.get('value'); - if (currentheight === '') { - input.set('value', self._rawImageDimensions.height); - currentheight = "" + self._rawImageDimensions.height; - } - input = self._form.one('.' + CSS.IMAGEPREVIEW); - input.setAttribute('src', this.src); - input.setStyles({ - 'display': 'inline' - }); - - input = self._form.one('.' + CSS.INPUTCONSTRAIN); - if (currentwidth.match(REGEX.ISPERCENT) && currentheight.match(REGEX.ISPERCENT)) { - input.set('checked', currentwidth === currentheight); - } else if (this.width === 0 || this.height === 0) { - // If we don't have both dimensions of the image, we can't auto-size it, so disable control. - input.set('disabled', 'disabled'); - } else { - // This is the same as comparing to 3 decimal places. - widthRatio = Math.round(1000 * parseInt(currentwidth, 10) / this.width); - heightRatio = Math.round(1000 * parseInt(currentheight, 10) / this.height); - input.set('checked', widthRatio === heightRatio); - } - - // Apply the image sizing. - self._autoAdjustSize(self); - - // Centre the dialogue once the preview image has loaded. - self.getDialogue().centerDialogue(); - }; - - image.src = url; - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} The content to place in the dialogue. - * @private - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - canShowFilepicker = this.get('host').canShowFilepicker('image'), - content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - CSS: CSS, - FORMNAMES: FORMNAMES, - component: COMPONENTNAME, - showFilepicker: canShowFilepicker, - alignments: ALIGNMENTS - })); - - this._form = content; - - // Configure the view of the current image. - this._applyImageProperties(this._form); - - this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this); - this._form.one('.' + CSS.INPUTURL).on('change', this._hasErrorUrlField, this); - this._form.one('.' + CSS.IMAGEPRESENTATION).on('change', this._hasErrorAltField, this); - this._form.one('.' + CSS.INPUTALT).on('blur', this._hasErrorAltField, this); - this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustSize, this); - this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustSize, this, true); - this._form.one('.' + CSS.INPUTCONSTRAIN).on('change', function(event) { - if (event.target.get('checked')) { - this._autoAdjustSize(event); - } - }, this); - this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this); - - if (canShowFilepicker) { - this._form.one('.' + CSS.IMAGEBROWSER).on('click', function() { - this.get('host').showFilepicker('image', this._filepickerCallback, this); - }, this); - } - - // Character count. - this._form.one('.' + CSS.INPUTALT).on('keyup', this._handleKeyup, this); - - return content; - }, - - _autoAdjustSize: function(e, forceHeight) { - forceHeight = forceHeight || false; - - var keyField = this._form.one('.' + CSS.INPUTWIDTH), - keyFieldType = 'width', - subField = this._form.one('.' + CSS.INPUTHEIGHT), - subFieldType = 'height', - constrainField = this._form.one('.' + CSS.INPUTCONSTRAIN), - keyFieldValue = keyField.get('value'), - subFieldValue = subField.get('value'), - imagePreview = this._form.one('.' + CSS.IMAGEPREVIEW), - rawPercentage, - rawSize; - - // If we do not know the image size, do not do anything. - if (!this._rawImageDimensions) { - return; - } - - // Set the width back to default if it is empty. - if (keyFieldValue === '') { - keyFieldValue = this._rawImageDimensions[keyFieldType]; - keyField.set('value', keyFieldValue); - keyFieldValue = keyField.get('value'); - } - - // Clear the existing preview sizes. - imagePreview.setStyles({ - width: null, - height: null - }); - - // Now update with the new values. - if (!constrainField.get('checked')) { - // We are not keeping the image proportion - update the preview accordingly. - - // Width. - if (keyFieldValue.match(REGEX.ISPERCENT)) { - rawPercentage = parseInt(keyFieldValue, 10); - rawSize = this._rawImageDimensions.width / 100 * rawPercentage; - imagePreview.setStyle('width', rawSize + 'px'); - } else { - imagePreview.setStyle('width', keyFieldValue + 'px'); - } - - // Height. - if (subFieldValue.match(REGEX.ISPERCENT)) { - rawPercentage = parseInt(subFieldValue, 10); - rawSize = this._rawImageDimensions.height / 100 * rawPercentage; - imagePreview.setStyle('height', rawSize + 'px'); - } else { - imagePreview.setStyle('height', subFieldValue + 'px'); - } - } else { - // We are keeping the image in proportion. - if (forceHeight) { - // By default we update based on width. Swap the key and sub fields around to achieve a height-based scale. - var _temporaryValue; - _temporaryValue = keyField; - keyField = subField; - subField = _temporaryValue; - - _temporaryValue = keyFieldType; - keyFieldType = subFieldType; - subFieldType = _temporaryValue; - - _temporaryValue = keyFieldValue; - keyFieldValue = subFieldValue; - subFieldValue = _temporaryValue; - } - - if (keyFieldValue.match(REGEX.ISPERCENT)) { - // This is a percentage based change. Copy it verbatim. - subFieldValue = keyFieldValue; - - // Set the width to the calculated pixel width. - rawPercentage = parseInt(keyFieldValue, 10); - rawSize = this._rawImageDimensions.width / 100 * rawPercentage; - - // And apply the width/height to the container. - imagePreview.setStyle('width', rawSize); - rawSize = this._rawImageDimensions.height / 100 * rawPercentage; - imagePreview.setStyle('height', rawSize); - } else { - // Calculate the scaled subFieldValue from the keyFieldValue. - subFieldValue = Math.round((keyFieldValue / this._rawImageDimensions[keyFieldType]) * - this._rawImageDimensions[subFieldType]); - - if (forceHeight) { - imagePreview.setStyles({ - 'width': subFieldValue, - 'height': keyFieldValue - }); - } else { - imagePreview.setStyles({ - 'width': keyFieldValue, - 'height': subFieldValue - }); - } - } - - // Update the subField's value within the form to reflect the changes. - subField.set('value', subFieldValue); - } - }, - - /** - * Update the dialogue after an image was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the image. - * @private - */ - _filepickerCallback: function(params) { - if (params.url !== '') { - var input = this._form.one('.' + CSS.INPUTURL); - input.set('value', params.url); - - // Auto set the width and height. - this._form.one('.' + CSS.INPUTWIDTH).set('value', ''); - this._form.one('.' + CSS.INPUTHEIGHT).set('value', ''); - - // Load the preview image. - this._loadPreviewImage(params.url); - } - }, - - /** - * Applies properties of an existing image to the image dialogue for editing. - * - * @method _applyImageProperties - * @param {Node} form - * @private - */ - _applyImageProperties: function(form) { - var properties = this._getSelectedImageProperties(), - img = form.one('.' + CSS.IMAGEPREVIEW); - - if (properties === false) { - img.setStyle('display', 'none'); - // Set the default alignment. - ALIGNMENTS.some(function(alignment) { - if (alignment.isDefault) { - form.one('.' + CSS.INPUTALIGNMENT).set('value', alignment.value); - return true; - } - - return false; - }, this); - - return; - } - - if (properties.align) { - form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align); - } - if (properties.customstyle) { - form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle); - } - if (properties.width) { - form.one('.' + CSS.INPUTWIDTH).set('value', properties.width); - } - if (properties.height) { - form.one('.' + CSS.INPUTHEIGHT).set('value', properties.height); - } - if (properties.alt) { - form.one('.' + CSS.INPUTALT).set('value', properties.alt); - } - if (properties.src) { - form.one('.' + CSS.INPUTURL).set('value', properties.src); - this._loadPreviewImage(properties.src); - } - if (properties.presentation) { - form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked'); - } - - // Update the image preview based on the form properties. - this._autoAdjustSize(); - }, - - /** - * Gets the properties of the currently selected image. - * - * The first image only if multiple images are selected. - * - * @method _getSelectedImageProperties - * @return {object} - * @private - */ - _getSelectedImageProperties: function() { - var properties = { - src: null, - alt: null, - width: null, - height: null, - align: '', - presentation: false - }, - - // Get the current selection. - images = this.get('host').getSelectedNodes(), - width, - height, - style, - image; - - if (images) { - images = images.filter('img'); - } - - if (images && images.size()) { - image = this._removeLegacyAlignment(images.item(0)); - this._selectedImage = image; - - style = image.getAttribute('style'); - properties.customstyle = style; - - width = image.getAttribute('width'); - if (!width.match(REGEX.ISPERCENT)) { - width = parseInt(width, 10); - } - height = image.getAttribute('height'); - if (!height.match(REGEX.ISPERCENT)) { - height = parseInt(height, 10); - } - - if (width !== 0) { - properties.width = width; - } - if (height !== 0) { - properties.height = height; - } - this._getAlignmentPropeties(image, properties); - properties.src = image.getAttribute('src'); - properties.alt = image.getAttribute('alt') || ''; - properties.presentation = (image.get('role') === 'presentation'); - return properties; - } - - // No image selected - clean up. - this._selectedImage = null; - return false; - }, - - /** - * Sets the alignment of a properties object. - * - * @method _getAlignmentPropeties - * @param {Node} image The image that the alignment properties should be found for - * @param {Object} properties The properties object that is created in _getSelectedImageProperties() - * @private - */ - _getAlignmentPropeties: function(image, properties) { - var complete = false, - defaultAlignment; - - // Check for an alignment value. - complete = ALIGNMENTS.some(function(alignment) { - var classname = this._getAlignmentClass(alignment.value); - if (image.hasClass(classname)) { - properties.align = alignment.value; - - return true; - } - - if (alignment.isDefault) { - defaultAlignment = alignment.value; - } - - return false; - }, this); - - if (!complete && defaultAlignment) { - properties.align = defaultAlignment; - } - }, - - /** - * Update the form when the URL was changed. This includes updating the - * height, width, and image preview. - * - * @method _urlChanged - * @private - */ - _urlChanged: function() { - var input = this._form.one('.' + CSS.INPUTURL); - - if (input.get('value') !== '') { - // Load the preview image. - this._loadPreviewImage(input.get('value')); - } - }, - - /** - * Update the image in the contenteditable. - * - * @method _setImage - * @param {EventFacade} e - * @private - */ - _setImage: function(e) { - var form = this._form, - url = form.one('.' + CSS.INPUTURL).get('value'), - alt = form.one('.' + CSS.INPUTALT).get('value'), - width = form.one('.' + CSS.INPUTWIDTH).get('value'), - height = form.one('.' + CSS.INPUTHEIGHT).get('value'), - alignment = this._getAlignmentClass(form.one('.' + CSS.INPUTALIGNMENT).get('value')), - presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'), - constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'), - imagehtml, - customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value'), - classlist = [], - host = this.get('host'); - - e.preventDefault(); - - // Check if there are any accessibility issues. - if (this._updateWarning()) { - return; - } - - // Focus on the editor in preparation for inserting the image. - host.focus(); - if (url !== '') { - if (this._selectedImage) { - host.setSelection(host.getSelectionFromNode(this._selectedImage)); - } else { - host.setSelection(this._currentSelection); - } - - if (constrain) { - classlist.push(CSS.RESPONSIVE); - } - - // Add the alignment class for the image. - classlist.push(alignment); - - if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) { - form.one('.' + CSS.INPUTWIDTH).focus(); - return; - } - if (!height.match(REGEX.ISPERCENT) && isNaN(parseInt(height, 10))) { - form.one('.' + CSS.INPUTHEIGHT).focus(); - return; - } - - var template = Y.Handlebars.compile(IMAGETEMPLATE); - imagehtml = template({ - url: url, - alt: alt, - width: width, - height: height, - presentation: presentation, - customstyle: customstyle, - classlist: classlist.join(' ') - }); - - this.get('host').insertContentAtFocusPoint(imagehtml); - - this.markUpdated(); - } - - this.getDialogue({ - focusAfterHide: null - }).hide(); - - }, - - /** - * Removes any legacy styles added by previous versions of the atto image button. - * - * @method _removeLegacyAlignment - * @param {Y.Node} imageNode - * @return {Y.Node} - * @private - */ - _removeLegacyAlignment: function(imageNode) { - if (!imageNode.getStyle('margin')) { - // There is no margin therefore this cannot match any known alignments. - return imageNode; - } - - ALIGNMENTS.some(function(alignment) { - if (imageNode.getStyle(alignment.name) !== alignment.value) { - // The name/value do not match. Skip. - return false; - } - - var normalisedNode = Y.Node.create('
                          '); - normalisedNode.setStyle('margin', alignment.margin); - if (imageNode.getStyle('margin') !== normalisedNode.getStyle('margin')) { - // The margin does not match. - return false; - } - - imageNode.addClass(this._getAlignmentClass(alignment.value)); - imageNode.setStyle(alignment.name, null); - imageNode.setStyle('margin', null); - - return true; - }, this); - - return imageNode; - }, - - _getAlignmentClass: function(alignment) { - return CSS.ALIGNSETTINGS + '_' + alignment; - }, - - _toggleVisibility: function(selector, predicate) { - var form = this._form; - var element = form.all(selector); - element.setStyle('display', predicate ? 'block' : 'none'); - }, - - _toggleAriaInvalid: function(selectors, predicate) { - var form = this._form; - selectors.forEach(function(selector) { - var element = form.all(selector); - element.setAttribute('aria-invalid', predicate); - }); - }, - - _hasErrorUrlField: function() { - var form = this._form; - var url = form.one('.' + CSS.INPUTURL).get('value'); - var urlerror = url === ''; - this._toggleVisibility('.' + CSS.IMAGEURLWARNING, urlerror); - this._toggleAriaInvalid(['.' + CSS.INPUTURL], urlerror); - return urlerror; - }, - - _hasErrorAltField: function() { - var form = this._form; - var alt = form.one('.' + CSS.INPUTALT).get('value'); - var presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'); - var imagealterror = alt === '' && !presentation; - this._toggleVisibility('.' + CSS.IMAGEALTWARNING, imagealterror); - this._toggleAriaInvalid(['.' + CSS.INPUTALT, '.' + CSS.IMAGEPRESENTATION], imagealterror); - return imagealterror; - }, - /** - * Update the alt text warning live. - * - * @method _updateWarning - * @return {boolean} whether a warning should be displayed. - * @private - */ - _updateWarning: function() { - var urlerror = this._hasErrorUrlField(); - var imagealterror = this._hasErrorAltField(); - var haserrors = urlerror || imagealterror; - this.getDialogue().centerDialogue(); - return haserrors; - }, - - /** - * Handle the keyup to update the character count. - */ - _handleKeyup: function() { - var form = this._form, - alt = form.one('.' + CSS.INPUTALT).get('value'), - characterCount = alt.length, - current = form.one('#currentcount'); - current.setHTML(characterCount); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/image/yui/src/button/build.json b/lib/editor/atto/plugins/image/yui/src/button/build.json deleted file mode 100644 index 15fda37bfd5..00000000000 --- a/lib/editor/atto/plugins/image/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_image-button", - "builds": { - "moodle-atto_image-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/image/yui/src/button/js/button.js b/lib/editor/atto/plugins/image/yui/src/button/js/button.js deleted file mode 100644 index e01836b7941..00000000000 --- a/lib/editor/atto/plugins/image/yui/src/button/js/button.js +++ /dev/null @@ -1,1111 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_image - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_image_alignment-button - */ - -/** - * Atto image selection tool. - * - * @namespace M.atto_image - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var CSS = { - RESPONSIVE: 'img-fluid', - INPUTALIGNMENT: 'atto_image_alignment', - INPUTALT: 'atto_image_altentry', - INPUTHEIGHT: 'atto_image_heightentry', - INPUTSUBMIT: 'atto_image_urlentrysubmit', - INPUTURL: 'atto_image_urlentry', - INPUTSIZE: 'atto_image_size', - INPUTWIDTH: 'atto_image_widthentry', - IMAGEALTWARNING: 'atto_image_altwarning', - IMAGEURLWARNING: 'atto_image_urlwarning', - IMAGEBROWSER: 'openimagebrowser', - IMAGEPRESENTATION: 'atto_image_presentation', - INPUTCONSTRAIN: 'atto_image_constrain', - INPUTCUSTOMSTYLE: 'atto_image_customstyle', - IMAGEPREVIEW: 'atto_image_preview', - IMAGEPREVIEWBOX: 'atto_image_preview_box', - ALIGNSETTINGS: 'atto_image_button' - }, - FORMNAMES = { - URL: 'urlentry', - ALT: 'altentry' - }, - SELECTORS = { - INPUTURL: '.' + CSS.INPUTURL - }, - ALIGNMENTS = [ - // Vertical alignment. - { - name: 'verticalAlign', - str: 'alignment_top', - value: 'text-top', - margin: '0 0.5em' - }, { - name: 'verticalAlign', - str: 'alignment_middle', - value: 'middle', - margin: '0 0.5em' - }, { - name: 'verticalAlign', - str: 'alignment_bottom', - value: 'text-bottom', - margin: '0 0.5em', - isDefault: true - }, - - // Floats. - { - name: 'float', - str: 'alignment_left', - value: 'left', - margin: '0 0.5em 0 0' - }, { - name: 'float', - str: 'alignment_right', - value: 'right', - margin: '0 0 0 0.5em' - } - ], - DEFAULTS = { - WIDTH: 160, - HEIGHT: 160, - }, - REGEX = { - ISPERCENT: /\d+%/ - }, - - COMPONENTNAME = 'atto_image', - - TEMPLATE = '' + - '
                          ' + - // Add the repository browser button. - '' + - '{{#if showFilepicker}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{else}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/if}}' + - - '' + - // Add the Alt box. - '
                          ' + - '' + - '' + - - // Add the character count. - '
                          ' + - '0' + - ' / 125' + - '
                          ' + - - // Add the presentation select box. - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - - // Add the size entry boxes. - '
                          ' + - '' + - '
                          ' + - '' + - ' x' + - - // Add the height entry box. - '' + - '' + - - // Add the constrain checkbox. - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - - // Add the alignment selector. - '
                          ' + - '' + - '' + - '
                          ' + - // Hidden input to store custom styles. - '' + - '
                          ' + - - // Add the image preview. - '
                          ' + - '
                          ' + - '' + - '
                          ' + - - // Add the submit button and close the form. - '' + - '
                          ' + - '
                          ', - - IMAGETEMPLATE = '' + - '{{alt}}'; - -Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * The most recently selected image. - * - * @param _selectedImage - * @type Node - * @private - */ - _selectedImage: null, - - /** - * A reference to the currently open form. - * - * @param _form - * @type Node - * @private - */ - _form: null, - - /** - * The dimensions of the raw image before we manipulate it. - * - * @param _rawImageDimensions - * @type Object - * @private - */ - _rawImageDimensions: null, - - initializer: function() { - - this.addButton({ - icon: 'e/insert_edit_image', - callback: this._displayDialogue, - tags: 'img', - tagMatchRequiresAll: false - }); - this.editor.delegate('dblclick', this._displayDialogue, 'img', this); - this.editor.delegate('click', this._handleClick, 'img', this); - this.editor.on('paste', this._handlePaste, this); - this.editor.on('drop', this._handleDragDrop, this); - - // ...e.preventDefault needed to stop the default event from clobbering the desired behaviour in some browsers. - this.editor.on('dragover', function(e) { - e.preventDefault(); - }, this); - this.editor.on('dragenter', function(e) { - e.preventDefault(); - }, this); - }, - - /** - * Handle a drag and drop event with an image. - * - * @method _handleDragDrop - * @param {EventFacade} e - * @private - */ - _handleDragDrop: function(e) { - if (!e._event || !e._event.dataTransfer) { - // Drop not fully supported in this browser. - return; - } - - this._handlePasteOrDropHelper(e, e._event.dataTransfer); - }, - - /** - * Handles paste events where - if the thing being pasted is an image. - * - * @method _handlePaste - * @param {EventFacade} e - * @return {boolean} false if we handled the event, else true. - * @private - */ - _handlePaste: function(e) { - if (!e._event || !e._event.clipboardData) { - // Paste not fully supported in this browser. - return true; - } - - return this._handlePasteOrDropHelper(e, e._event.clipboardData); - }, - - /** - * Handle a drag and drop event with an image. - * - * @method _handleDragDrop - * @param {EventFacade} e - * @param {DataTransfer} dataTransfer - * @return {boolean} false if we handled the event, else true. - * @private - */ - _handlePasteOrDropHelper: function(e, dataTransfer) { - - var items = dataTransfer.items, - didUpload = false; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.kind !== 'file') { - continue; - } - if (!this._isImage(item.type)) { - continue; - } - this._uploadImage(item.getAsFile()); - didUpload = true; - } - - if (didUpload) { - e.preventDefault(); - } - }, - - /** - * Is this file an image? - * - * @method _isImage - * @param {string} mimeType the file's mime type. - * @return {boolean} true if the file has an image mimeType. - * @private - */ - _isImage: function(mimeType) { - return mimeType.indexOf('image/') === 0; - }, - - /** - * Used by _handleDragDrop and _handlePaste to upload an image and insert it. - * - * @method _uploadImage - * @param {File} fileToSave - * @private - */ - _uploadImage: function(fileToSave) { - - var self = this, - host = this.get('host'), - template = Y.Handlebars.compile(IMAGETEMPLATE); - - host.saveSelection(); - - // Trigger form upload start events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadStarted(self.editor.get('id')); - }); - - var options = host.get('filepickeroptions').image, - savepath = (options.savepath === undefined) ? '/' : options.savepath, - formData = new FormData(), - timestamp = 0, - uploadid = "", - xhr = new XMLHttpRequest(), - imagehtml = "", - keys = Object.keys(options.repositories); - - formData.append('repo_upload_file', fileToSave); - formData.append('itemid', options.itemid); - - // List of repositories is an object rather than an array. This makes iteration more awkward. - for (var i = 0; i < keys.length; i++) { - if (options.repositories[keys[i]].type === 'upload') { - formData.append('repo_id', options.repositories[keys[i]].id); - break; - } - } - formData.append('env', options.env); - formData.append('sesskey', M.cfg.sesskey); - formData.append('client_id', options.client_id); - formData.append('savepath', savepath); - formData.append('ctx_id', options.context.id); - - // Insert spinner as a placeholder. - timestamp = new Date().getTime(); - uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp; - host.focus(); - host.restoreSelection(); - imagehtml = template({ - url: M.util.image_url("i/loading_small", 'moodle'), - alt: M.util.get_string('uploading', COMPONENTNAME), - id: uploadid - }); - host.insertContentAtFocusPoint(imagehtml); - self.markUpdated(); - - // Kick off a XMLHttpRequest. - xhr.onreadystatechange = function() { - var placeholder = self.editor.one('#' + uploadid), - result, - file, - newhtml, - newimage; - - if (xhr.readyState === 4) { - if (xhr.status === 200) { - result = JSON.parse(xhr.responseText); - if (result) { - if (result.error) { - if (placeholder) { - placeholder.remove(true); - } - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - throw new M.core.ajaxException(result); - } - - file = result; - if (result.event && result.event === 'fileexists') { - // A file with this name is already in use here - rename to avoid conflict. - // Chances are, it's a different image (stored in a different folder on the user's computer). - // If the user wants to reuse an existing image, they can copy/paste it within the editor. - file = result.newfile; - } - - // Replace placeholder with actual image. - newhtml = template({ - url: file.url, - presentation: true, - classlist: CSS.RESPONSIVE - }); - newimage = Y.Node.create(newhtml); - if (placeholder) { - placeholder.replace(newimage); - } else { - self.editor.appendChild(newimage); - } - self.markUpdated(); - } - } else { - Y.use('moodle-core-notification-alert', function() { - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); - }); - if (placeholder) { - placeholder.remove(true); - } - } - // Trigger form upload complete events. - require(['core_form/events'], function(FormEvent) { - FormEvent.notifyUploadCompleted(self.editor.get('id')); - }); - } - }; - xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true); - xhr.send(formData); - }, - - /** - * Handle a click on an image. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var image = e.target; - - var selection = this.get('host').getSelectionFromNode(image); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Display the image editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - // Reset the image dimensions. - this._rawImageDimensions = null; - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('imageproperties', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - focusOnShowSelector: SELECTORS.INPUTURL - }); - // Set a maximum width for the dialog. This will prevent the dialog width to extend beyond the screen width - // in cases when the uploaded image has larger width. - dialogue.get('boundingBox').setStyle('maxWidth', '90%'); - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()) - .show(); - }, - - /** - * Set the inputs for width and height if they are not set, and calculate - * if the constrain checkbox should be checked or not. - * - * @method _loadPreviewImage - * @param {String} url - * @private - */ - _loadPreviewImage: function(url) { - var image = new Image(); - var self = this; - - image.onerror = function() { - var preview = self._form.one('.' + CSS.IMAGEPREVIEW); - preview.setStyles({ - 'display': 'none' - }); - - // Centre the dialogue when clearing the image preview. - self.getDialogue().centerDialogue(); - }; - - image.onload = function() { - var input, currentwidth, currentheight, widthRatio, heightRatio; - - // Store dimensions of the raw image, falling back to defaults for images without dimensions (e.g. SVG). - self._rawImageDimensions = { - width: this.width || DEFAULTS.WIDTH, - height: this.height || DEFAULTS.HEIGHT, - }; - - input = self._form.one('.' + CSS.INPUTWIDTH); - currentwidth = input.get('value'); - if (currentwidth === '') { - input.set('value', self._rawImageDimensions.width); - currentwidth = "" + self._rawImageDimensions.width; - } - input = self._form.one('.' + CSS.INPUTHEIGHT); - currentheight = input.get('value'); - if (currentheight === '') { - input.set('value', self._rawImageDimensions.height); - currentheight = "" + self._rawImageDimensions.height; - } - input = self._form.one('.' + CSS.IMAGEPREVIEW); - input.setAttribute('src', this.src); - input.setStyles({ - 'display': 'inline' - }); - - input = self._form.one('.' + CSS.INPUTCONSTRAIN); - if (currentwidth.match(REGEX.ISPERCENT) && currentheight.match(REGEX.ISPERCENT)) { - input.set('checked', currentwidth === currentheight); - } else if (this.width === 0 || this.height === 0) { - // If we don't have both dimensions of the image, we can't auto-size it, so disable control. - input.set('disabled', 'disabled'); - } else { - // This is the same as comparing to 3 decimal places. - widthRatio = Math.round(1000 * parseInt(currentwidth, 10) / this.width); - heightRatio = Math.round(1000 * parseInt(currentheight, 10) / this.height); - input.set('checked', widthRatio === heightRatio); - } - - // Apply the image sizing. - self._autoAdjustSize(self); - - // Centre the dialogue once the preview image has loaded. - self.getDialogue().centerDialogue(); - }; - - image.src = url; - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @return {Node} The content to place in the dialogue. - * @private - */ - _getDialogueContent: function() { - var template = Y.Handlebars.compile(TEMPLATE), - canShowFilepicker = this.get('host').canShowFilepicker('image'), - content = Y.Node.create(template({ - elementid: this.get('host').get('elementid'), - CSS: CSS, - FORMNAMES: FORMNAMES, - component: COMPONENTNAME, - showFilepicker: canShowFilepicker, - alignments: ALIGNMENTS - })); - - this._form = content; - - // Configure the view of the current image. - this._applyImageProperties(this._form); - - this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this); - this._form.one('.' + CSS.INPUTURL).on('change', this._hasErrorUrlField, this); - this._form.one('.' + CSS.IMAGEPRESENTATION).on('change', this._hasErrorAltField, this); - this._form.one('.' + CSS.INPUTALT).on('blur', this._hasErrorAltField, this); - this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustSize, this); - this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustSize, this, true); - this._form.one('.' + CSS.INPUTCONSTRAIN).on('change', function(event) { - if (event.target.get('checked')) { - this._autoAdjustSize(event); - } - }, this); - this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this); - - if (canShowFilepicker) { - this._form.one('.' + CSS.IMAGEBROWSER).on('click', function() { - this.get('host').showFilepicker('image', this._filepickerCallback, this); - }, this); - } - - // Character count. - this._form.one('.' + CSS.INPUTALT).on('keyup', this._handleKeyup, this); - - return content; - }, - - _autoAdjustSize: function(e, forceHeight) { - forceHeight = forceHeight || false; - - var keyField = this._form.one('.' + CSS.INPUTWIDTH), - keyFieldType = 'width', - subField = this._form.one('.' + CSS.INPUTHEIGHT), - subFieldType = 'height', - constrainField = this._form.one('.' + CSS.INPUTCONSTRAIN), - keyFieldValue = keyField.get('value'), - subFieldValue = subField.get('value'), - imagePreview = this._form.one('.' + CSS.IMAGEPREVIEW), - rawPercentage, - rawSize; - - // If we do not know the image size, do not do anything. - if (!this._rawImageDimensions) { - return; - } - - // Set the width back to default if it is empty. - if (keyFieldValue === '') { - keyFieldValue = this._rawImageDimensions[keyFieldType]; - keyField.set('value', keyFieldValue); - keyFieldValue = keyField.get('value'); - } - - // Clear the existing preview sizes. - imagePreview.setStyles({ - width: null, - height: null - }); - - // Now update with the new values. - if (!constrainField.get('checked')) { - // We are not keeping the image proportion - update the preview accordingly. - - // Width. - if (keyFieldValue.match(REGEX.ISPERCENT)) { - rawPercentage = parseInt(keyFieldValue, 10); - rawSize = this._rawImageDimensions.width / 100 * rawPercentage; - imagePreview.setStyle('width', rawSize + 'px'); - } else { - imagePreview.setStyle('width', keyFieldValue + 'px'); - } - - // Height. - if (subFieldValue.match(REGEX.ISPERCENT)) { - rawPercentage = parseInt(subFieldValue, 10); - rawSize = this._rawImageDimensions.height / 100 * rawPercentage; - imagePreview.setStyle('height', rawSize + 'px'); - } else { - imagePreview.setStyle('height', subFieldValue + 'px'); - } - } else { - // We are keeping the image in proportion. - if (forceHeight) { - // By default we update based on width. Swap the key and sub fields around to achieve a height-based scale. - var _temporaryValue; - _temporaryValue = keyField; - keyField = subField; - subField = _temporaryValue; - - _temporaryValue = keyFieldType; - keyFieldType = subFieldType; - subFieldType = _temporaryValue; - - _temporaryValue = keyFieldValue; - keyFieldValue = subFieldValue; - subFieldValue = _temporaryValue; - } - - if (keyFieldValue.match(REGEX.ISPERCENT)) { - // This is a percentage based change. Copy it verbatim. - subFieldValue = keyFieldValue; - - // Set the width to the calculated pixel width. - rawPercentage = parseInt(keyFieldValue, 10); - rawSize = this._rawImageDimensions.width / 100 * rawPercentage; - - // And apply the width/height to the container. - imagePreview.setStyle('width', rawSize); - rawSize = this._rawImageDimensions.height / 100 * rawPercentage; - imagePreview.setStyle('height', rawSize); - } else { - // Calculate the scaled subFieldValue from the keyFieldValue. - subFieldValue = Math.round((keyFieldValue / this._rawImageDimensions[keyFieldType]) * - this._rawImageDimensions[subFieldType]); - - if (forceHeight) { - imagePreview.setStyles({ - 'width': subFieldValue, - 'height': keyFieldValue - }); - } else { - imagePreview.setStyles({ - 'width': keyFieldValue, - 'height': subFieldValue - }); - } - } - - // Update the subField's value within the form to reflect the changes. - subField.set('value', subFieldValue); - } - }, - - /** - * Update the dialogue after an image was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the image. - * @private - */ - _filepickerCallback: function(params) { - if (params.url !== '') { - var input = this._form.one('.' + CSS.INPUTURL); - input.set('value', params.url); - - // Auto set the width and height. - this._form.one('.' + CSS.INPUTWIDTH).set('value', ''); - this._form.one('.' + CSS.INPUTHEIGHT).set('value', ''); - - // Load the preview image. - this._loadPreviewImage(params.url); - } - }, - - /** - * Applies properties of an existing image to the image dialogue for editing. - * - * @method _applyImageProperties - * @param {Node} form - * @private - */ - _applyImageProperties: function(form) { - var properties = this._getSelectedImageProperties(), - img = form.one('.' + CSS.IMAGEPREVIEW); - - if (properties === false) { - img.setStyle('display', 'none'); - // Set the default alignment. - ALIGNMENTS.some(function(alignment) { - if (alignment.isDefault) { - form.one('.' + CSS.INPUTALIGNMENT).set('value', alignment.value); - return true; - } - - return false; - }, this); - - return; - } - - if (properties.align) { - form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align); - } - if (properties.customstyle) { - form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle); - } - if (properties.width) { - form.one('.' + CSS.INPUTWIDTH).set('value', properties.width); - } - if (properties.height) { - form.one('.' + CSS.INPUTHEIGHT).set('value', properties.height); - } - if (properties.alt) { - form.one('.' + CSS.INPUTALT).set('value', properties.alt); - } - if (properties.src) { - form.one('.' + CSS.INPUTURL).set('value', properties.src); - this._loadPreviewImage(properties.src); - } - if (properties.presentation) { - form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked'); - } - - // Update the image preview based on the form properties. - this._autoAdjustSize(); - }, - - /** - * Gets the properties of the currently selected image. - * - * The first image only if multiple images are selected. - * - * @method _getSelectedImageProperties - * @return {object} - * @private - */ - _getSelectedImageProperties: function() { - var properties = { - src: null, - alt: null, - width: null, - height: null, - align: '', - presentation: false - }, - - // Get the current selection. - images = this.get('host').getSelectedNodes(), - width, - height, - style, - image; - - if (images) { - images = images.filter('img'); - } - - if (images && images.size()) { - image = this._removeLegacyAlignment(images.item(0)); - this._selectedImage = image; - - style = image.getAttribute('style'); - properties.customstyle = style; - - width = image.getAttribute('width'); - if (!width.match(REGEX.ISPERCENT)) { - width = parseInt(width, 10); - } - height = image.getAttribute('height'); - if (!height.match(REGEX.ISPERCENT)) { - height = parseInt(height, 10); - } - - if (width !== 0) { - properties.width = width; - } - if (height !== 0) { - properties.height = height; - } - this._getAlignmentPropeties(image, properties); - properties.src = image.getAttribute('src'); - properties.alt = image.getAttribute('alt') || ''; - properties.presentation = (image.get('role') === 'presentation'); - return properties; - } - - // No image selected - clean up. - this._selectedImage = null; - return false; - }, - - /** - * Sets the alignment of a properties object. - * - * @method _getAlignmentPropeties - * @param {Node} image The image that the alignment properties should be found for - * @param {Object} properties The properties object that is created in _getSelectedImageProperties() - * @private - */ - _getAlignmentPropeties: function(image, properties) { - var complete = false, - defaultAlignment; - - // Check for an alignment value. - complete = ALIGNMENTS.some(function(alignment) { - var classname = this._getAlignmentClass(alignment.value); - if (image.hasClass(classname)) { - properties.align = alignment.value; - Y.log('Found alignment ' + alignment.value, 'debug', 'atto_image-button'); - - return true; - } - - if (alignment.isDefault) { - defaultAlignment = alignment.value; - } - - return false; - }, this); - - if (!complete && defaultAlignment) { - properties.align = defaultAlignment; - } - }, - - /** - * Update the form when the URL was changed. This includes updating the - * height, width, and image preview. - * - * @method _urlChanged - * @private - */ - _urlChanged: function() { - var input = this._form.one('.' + CSS.INPUTURL); - - if (input.get('value') !== '') { - // Load the preview image. - this._loadPreviewImage(input.get('value')); - } - }, - - /** - * Update the image in the contenteditable. - * - * @method _setImage - * @param {EventFacade} e - * @private - */ - _setImage: function(e) { - var form = this._form, - url = form.one('.' + CSS.INPUTURL).get('value'), - alt = form.one('.' + CSS.INPUTALT).get('value'), - width = form.one('.' + CSS.INPUTWIDTH).get('value'), - height = form.one('.' + CSS.INPUTHEIGHT).get('value'), - alignment = this._getAlignmentClass(form.one('.' + CSS.INPUTALIGNMENT).get('value')), - presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'), - constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'), - imagehtml, - customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value'), - classlist = [], - host = this.get('host'); - - e.preventDefault(); - - // Check if there are any accessibility issues. - if (this._updateWarning()) { - return; - } - - // Focus on the editor in preparation for inserting the image. - host.focus(); - if (url !== '') { - if (this._selectedImage) { - host.setSelection(host.getSelectionFromNode(this._selectedImage)); - } else { - host.setSelection(this._currentSelection); - } - - if (constrain) { - classlist.push(CSS.RESPONSIVE); - } - - // Add the alignment class for the image. - classlist.push(alignment); - - if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) { - form.one('.' + CSS.INPUTWIDTH).focus(); - return; - } - if (!height.match(REGEX.ISPERCENT) && isNaN(parseInt(height, 10))) { - form.one('.' + CSS.INPUTHEIGHT).focus(); - return; - } - - var template = Y.Handlebars.compile(IMAGETEMPLATE); - imagehtml = template({ - url: url, - alt: alt, - width: width, - height: height, - presentation: presentation, - customstyle: customstyle, - classlist: classlist.join(' ') - }); - - this.get('host').insertContentAtFocusPoint(imagehtml); - - this.markUpdated(); - } - - this.getDialogue({ - focusAfterHide: null - }).hide(); - - }, - - /** - * Removes any legacy styles added by previous versions of the atto image button. - * - * @method _removeLegacyAlignment - * @param {Y.Node} imageNode - * @return {Y.Node} - * @private - */ - _removeLegacyAlignment: function(imageNode) { - if (!imageNode.getStyle('margin')) { - // There is no margin therefore this cannot match any known alignments. - return imageNode; - } - - ALIGNMENTS.some(function(alignment) { - if (imageNode.getStyle(alignment.name) !== alignment.value) { - // The name/value do not match. Skip. - return false; - } - - var normalisedNode = Y.Node.create('
                          '); - normalisedNode.setStyle('margin', alignment.margin); - if (imageNode.getStyle('margin') !== normalisedNode.getStyle('margin')) { - // The margin does not match. - return false; - } - - Y.log('Legacy alignment found and removed.', 'info', 'atto_image-button'); - imageNode.addClass(this._getAlignmentClass(alignment.value)); - imageNode.setStyle(alignment.name, null); - imageNode.setStyle('margin', null); - - return true; - }, this); - - return imageNode; - }, - - _getAlignmentClass: function(alignment) { - return CSS.ALIGNSETTINGS + '_' + alignment; - }, - - _toggleVisibility: function(selector, predicate) { - var form = this._form; - var element = form.all(selector); - element.setStyle('display', predicate ? 'block' : 'none'); - }, - - _toggleAriaInvalid: function(selectors, predicate) { - var form = this._form; - selectors.forEach(function(selector) { - var element = form.all(selector); - element.setAttribute('aria-invalid', predicate); - }); - }, - - _hasErrorUrlField: function() { - var form = this._form; - var url = form.one('.' + CSS.INPUTURL).get('value'); - var urlerror = url === ''; - this._toggleVisibility('.' + CSS.IMAGEURLWARNING, urlerror); - this._toggleAriaInvalid(['.' + CSS.INPUTURL], urlerror); - return urlerror; - }, - - _hasErrorAltField: function() { - var form = this._form; - var alt = form.one('.' + CSS.INPUTALT).get('value'); - var presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'); - var imagealterror = alt === '' && !presentation; - this._toggleVisibility('.' + CSS.IMAGEALTWARNING, imagealterror); - this._toggleAriaInvalid(['.' + CSS.INPUTALT, '.' + CSS.IMAGEPRESENTATION], imagealterror); - return imagealterror; - }, - /** - * Update the alt text warning live. - * - * @method _updateWarning - * @return {boolean} whether a warning should be displayed. - * @private - */ - _updateWarning: function() { - var urlerror = this._hasErrorUrlField(); - var imagealterror = this._hasErrorAltField(); - var haserrors = urlerror || imagealterror; - this.getDialogue().centerDialogue(); - return haserrors; - }, - - /** - * Handle the keyup to update the character count. - */ - _handleKeyup: function() { - var form = this._form, - alt = form.one('.' + CSS.INPUTALT).get('value'), - characterCount = alt.length, - current = form.one('#currentcount'); - current.setHTML(characterCount); - } -}); diff --git a/lib/editor/atto/plugins/image/yui/src/button/meta/button.json b/lib/editor/atto/plugins/image/yui/src/button/meta/button.json deleted file mode 100644 index 4d7f220f1aa..00000000000 --- a/lib/editor/atto/plugins/image/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_image-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/indent/classes/privacy/provider.php b/lib/editor/atto/plugins/indent/classes/privacy/provider.php deleted file mode 100644 index 189f1562601..00000000000 --- a/lib/editor/atto/plugins/indent/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_indent - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_indent\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_indent implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/indent/lang/en/atto_indent.php b/lib/editor/atto/plugins/indent/lang/en/atto_indent.php deleted file mode 100644 index c0462e6f103..00000000000 --- a/lib/editor/atto/plugins/indent/lang/en/atto_indent.php +++ /dev/null @@ -1,28 +0,0 @@ -. - -/** - * Strings for component 'atto_indent', language 'en'. - * - * @package atto_indent - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Indent'; -$string['indent'] = "Indent"; -$string['outdent'] = "Outdent"; -$string['privacy:metadata'] = 'The atto_indent plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/indent/lib.php b/lib/editor/atto/plugins/indent/lib.php deleted file mode 100644 index 02c28af9837..00000000000 --- a/lib/editor/atto/plugins/indent/lib.php +++ /dev/null @@ -1,35 +0,0 @@ -. - -/** - * Atto text editor align plugin lib. - * - * @package atto_align - * @copyright 2014 Jason Fowler - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_indent_strings_for_js() { - global $PAGE; - $PAGE->requires->strings_for_js(array('indent', 'outdent'), 'atto_indent'); -} diff --git a/lib/editor/atto/plugins/indent/tests/behat/indent.feature b/lib/editor/atto/plugins/indent/tests/behat/indent.feature deleted file mode 100644 index d9d5c041de2..00000000000 --- a/lib/editor/atto/plugins/indent/tests/behat/indent.feature +++ /dev/null @@ -1,37 +0,0 @@ -@editor @editor_atto @atto @atto_indent -Feature: Indent text in Atto - To write rich text - I need to indent and outdent things. - - @javascript - Scenario: Indent - Given I log in as "admin" - And I follow "Profile" in the user menu - When I click on "Edit profile" "link" in the "region-main" "region" - And I set the field "Description" to "

                          I need some space.

                          " - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - And I click on "Indent" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "class=\"editor-indent\"" - - @javascript - Scenario: Indent and outdent - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "

                          I need some space.

                          " - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - And I click on "Indent" "button" - And I click on "Outdent" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should not see "class=\"editor-indent\"" diff --git a/lib/editor/atto/plugins/indent/version.php b/lib/editor/atto/plugins/indent/version.php deleted file mode 100644 index 0002ba9ee97..00000000000 --- a/lib/editor/atto/plugins/indent/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_indent - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_indent'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-debug.js b/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-debug.js deleted file mode 100644 index 72008e29899..00000000000 --- a/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-debug.js +++ /dev/null @@ -1,227 +0,0 @@ -YUI.add('moodle-atto_indent-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_indent - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_indent-button - */ - -/** - * Atto text editor indent plugin. - * - * @namespace M.atto_indent - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_indent').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - - this.addButton({ - icon: 'e/decrease_indent', - title: 'outdent', - buttonName: 'outdent', - callback: this.outdent - }); - - this.addButton({ - icon: 'e/increase_indent', - title: 'indent', - buttonName: 'indent', - callback: this.indent - }); - }, - - /** - * Indents the currently selected content. - * - * @method indent - */ - indent: function() { - // Save the current selection - we want to restore this. - var selection = window.rangy.saveSelection(), - blockquotes = this.editor.all('blockquote'), - count = blockquotes.size(); - - // Remove display:none from rangy markers so browser doesn't delete them. - this.editor.all('.rangySelectionBoundary').setStyle('display', null); - - // Mark all existing block quotes in case the user has actually added some. - blockquotes.addClass('pre-existing'); - - // Run the indent command. - document.execCommand('indent', false, null); - - // Fix indent list item. - this.fixupListItemsAfterIndent(); - - // Get all blockquotes, both existing and new. - blockquotes = this.editor.all('blockquote'); - - if (blockquotes.size() !== count) { - // There are new block quotes, the indent exec has wrapped some content in block quotes in order - // to indent the selected content. - // We don't want blockquotes, we're going to convert them to divs. - this.replaceBlockquote(this.editor); - // Finally restore the seelction. The content has changed - sometimes this works - but not always :( - window.rangy.restoreSelection(selection); - } else if (blockquotes.size() > 0) { - // There were no new blockquotes, this happens if the user is indenting/outdenting a list. - blockquotes.removeClass('pre-existing'); - } - - // Remove the selection markers - a clean up really. - window.rangy.removeMarkers(selection); - - // Mark the text as having been updated. - this.markUpdated(); - }, - - /** - * Outdents the currently selected content. - * - * @method outdent - */ - outdent: function() { - // Save the selection we will want to restore it. - var selection = window.rangy.saveSelection(), - blockquotes = this.editor.all('blockquote'), - count = blockquotes.size(); - - // Mark existing blockquotes so that we don't convert them later. - blockquotes.addClass('pre-existing'); - - // Replace all div indents with blockquote indents so that we can rely on the browser functionality. - this.replaceEditorIndents(this.editor); - - // Restore the users selection - otherwise the next outdent operation won't work! - window.rangy.restoreSelection(selection); - // And save it once more. - selection = window.rangy.saveSelection(); - - // Outdent. - document.execCommand('outdent', false, null); - - // Get all blockquotes so that we can work out what happened. - blockquotes = this.editor.all('blockquote'); - - if (blockquotes.size() !== count) { - // The number of blockquotes hasn't changed. - // This occurs when the user has outdented a list item. - this.replaceBlockquote(this.editor); - window.rangy.restoreSelection(selection); - } else if (blockquotes.size() > 0) { - // The number of blockquotes is the same and is more than 0 we just need to clean up the class - // we added to mark pre-existing blockquotes. - blockquotes.removeClass('pre-existing'); - } - - // Clean up any left over selection markers. - window.rangy.removeMarkers(selection); - - // Mark the text as having been updated. - this.markUpdated(); - }, - - /** - * Replaces all blockquotes within an editor with div indents. - * @method replaceBlockquote - * @param Editor editor - */ - replaceBlockquote: function(editor) { - editor.all('blockquote').setAttribute('data-iterate', true); - var blockquote = editor.one('blockquote'), - margindir = (Y.one('body.dir-ltr')) ? 'marginLeft' : 'marginRight'; - while (blockquote) { - blockquote.removeAttribute('data-iterate'); - if (blockquote.hasClass('pre-existing')) { - blockquote.removeClass('pre-existing'); - } else { - var clone = Y.Node.create('
                          ') - .setAttrs(blockquote.getAttrs()) - .setStyle(margindir, '30px') - .addClass('editor-indent'); - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = blockquote.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - blockquote.replace(clone); - } - blockquote = editor.one('blockquote[data-iterate]'); - } - }, - - /** - * Replaces all div indents with blockquotes. - * @method replaceEditorIndents - * @param Editor editor - */ - replaceEditorIndents: function(editor) { - // We use the editor-indent class because it is preserved between saves. - var indent = editor.one('.editor-indent'); - while (indent) { - var clone = Y.Node.create('
                          ') - .setAttrs(indent - .getAttrs()) - .removeClass('editor-indent'); - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = indent.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - indent.replace(clone); - indent = editor.one('.editor-indent'); - } - }, - /** - * Fixup for list item after indent. - * - * @method fixupListItemsAfterIndent - */ - fixupListItemsAfterIndent: function() { - var selection = window.rangy.getSelection(), - rootelement = this.editor.getDOMNode(), - listelement = selection.anchorNode.parentElement; - - listelement = listelement.closest('ol, ul'); - if (!(listelement && rootelement.contains(listelement))) { - return; - } - - // We will move the child list into previous list item of the parent. - var previous = listelement.previousElementSibling; - if (previous && previous.tagName === 'LI') { - previous.appendChild(listelement); - selection.collapseToEnd(); - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-min.js b/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-min.js deleted file mode 100644 index c377865be13..00000000000 --- a/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_indent-button",function(r,e){r.namespace("M.atto_indent").Button=r.Base.create("button",r.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({icon:"e/decrease_indent",title:"outdent",buttonName:"outdent",callback:this.outdent}),this.addButton({icon:"e/increase_indent",title:"indent",buttonName:"indent",callback:this.indent})},indent:function(){var e=window.rangy.saveSelection(),t=this.editor.all("blockquote"),i=t.size();this.editor.all(".rangySelectionBoundary").setStyle("display",null),t.addClass("pre-existing"),document.execCommand("indent",!1,null),this.fixupListItemsAfterIndent(),(t=this.editor.all("blockquote")).size()!==i?(this.replaceBlockquote(this.editor),window.rangy.restoreSelection(e)):0
                          ").setAttrs(t.getAttrs()).setStyle(i,"30px").addClass("editor-indent"),d=(n=t.getDOMNode().childNodes)[0];void 0!==d;)o.append(d),d=n[0];t.replace(o)}t=e.one("blockquote[data-iterate]")}},replaceEditorIndents:function(e){for(var t,i,o,n=e.one(".editor-indent");n;){for(t=r.Node.create("
                          ").setAttrs(n.getAttrs()).removeClass("editor-indent"),o=(i=n.getDOMNode().childNodes)[0];void 0!==o;)t.append(o),o=i[0];n.replace(t),n=e.one(".editor-indent")}},fixupListItemsAfterIndent:function(){var e,t=window.rangy.getSelection(),i=this.editor.getDOMNode(),o=t.anchorNode.parentElement,o=o.closest("ol, ul");o&&i.contains(o)&&(e=o.previousElementSibling)&&"LI"===e.tagName&&(e.appendChild(o),t.collapseToEnd())}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button.js b/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button.js deleted file mode 100644 index 72008e29899..00000000000 --- a/lib/editor/atto/plugins/indent/yui/build/moodle-atto_indent-button/moodle-atto_indent-button.js +++ /dev/null @@ -1,227 +0,0 @@ -YUI.add('moodle-atto_indent-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_indent - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_indent-button - */ - -/** - * Atto text editor indent plugin. - * - * @namespace M.atto_indent - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_indent').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - - this.addButton({ - icon: 'e/decrease_indent', - title: 'outdent', - buttonName: 'outdent', - callback: this.outdent - }); - - this.addButton({ - icon: 'e/increase_indent', - title: 'indent', - buttonName: 'indent', - callback: this.indent - }); - }, - - /** - * Indents the currently selected content. - * - * @method indent - */ - indent: function() { - // Save the current selection - we want to restore this. - var selection = window.rangy.saveSelection(), - blockquotes = this.editor.all('blockquote'), - count = blockquotes.size(); - - // Remove display:none from rangy markers so browser doesn't delete them. - this.editor.all('.rangySelectionBoundary').setStyle('display', null); - - // Mark all existing block quotes in case the user has actually added some. - blockquotes.addClass('pre-existing'); - - // Run the indent command. - document.execCommand('indent', false, null); - - // Fix indent list item. - this.fixupListItemsAfterIndent(); - - // Get all blockquotes, both existing and new. - blockquotes = this.editor.all('blockquote'); - - if (blockquotes.size() !== count) { - // There are new block quotes, the indent exec has wrapped some content in block quotes in order - // to indent the selected content. - // We don't want blockquotes, we're going to convert them to divs. - this.replaceBlockquote(this.editor); - // Finally restore the seelction. The content has changed - sometimes this works - but not always :( - window.rangy.restoreSelection(selection); - } else if (blockquotes.size() > 0) { - // There were no new blockquotes, this happens if the user is indenting/outdenting a list. - blockquotes.removeClass('pre-existing'); - } - - // Remove the selection markers - a clean up really. - window.rangy.removeMarkers(selection); - - // Mark the text as having been updated. - this.markUpdated(); - }, - - /** - * Outdents the currently selected content. - * - * @method outdent - */ - outdent: function() { - // Save the selection we will want to restore it. - var selection = window.rangy.saveSelection(), - blockquotes = this.editor.all('blockquote'), - count = blockquotes.size(); - - // Mark existing blockquotes so that we don't convert them later. - blockquotes.addClass('pre-existing'); - - // Replace all div indents with blockquote indents so that we can rely on the browser functionality. - this.replaceEditorIndents(this.editor); - - // Restore the users selection - otherwise the next outdent operation won't work! - window.rangy.restoreSelection(selection); - // And save it once more. - selection = window.rangy.saveSelection(); - - // Outdent. - document.execCommand('outdent', false, null); - - // Get all blockquotes so that we can work out what happened. - blockquotes = this.editor.all('blockquote'); - - if (blockquotes.size() !== count) { - // The number of blockquotes hasn't changed. - // This occurs when the user has outdented a list item. - this.replaceBlockquote(this.editor); - window.rangy.restoreSelection(selection); - } else if (blockquotes.size() > 0) { - // The number of blockquotes is the same and is more than 0 we just need to clean up the class - // we added to mark pre-existing blockquotes. - blockquotes.removeClass('pre-existing'); - } - - // Clean up any left over selection markers. - window.rangy.removeMarkers(selection); - - // Mark the text as having been updated. - this.markUpdated(); - }, - - /** - * Replaces all blockquotes within an editor with div indents. - * @method replaceBlockquote - * @param Editor editor - */ - replaceBlockquote: function(editor) { - editor.all('blockquote').setAttribute('data-iterate', true); - var blockquote = editor.one('blockquote'), - margindir = (Y.one('body.dir-ltr')) ? 'marginLeft' : 'marginRight'; - while (blockquote) { - blockquote.removeAttribute('data-iterate'); - if (blockquote.hasClass('pre-existing')) { - blockquote.removeClass('pre-existing'); - } else { - var clone = Y.Node.create('
                          ') - .setAttrs(blockquote.getAttrs()) - .setStyle(margindir, '30px') - .addClass('editor-indent'); - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = blockquote.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - blockquote.replace(clone); - } - blockquote = editor.one('blockquote[data-iterate]'); - } - }, - - /** - * Replaces all div indents with blockquotes. - * @method replaceEditorIndents - * @param Editor editor - */ - replaceEditorIndents: function(editor) { - // We use the editor-indent class because it is preserved between saves. - var indent = editor.one('.editor-indent'); - while (indent) { - var clone = Y.Node.create('
                          ') - .setAttrs(indent - .getAttrs()) - .removeClass('editor-indent'); - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = indent.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - indent.replace(clone); - indent = editor.one('.editor-indent'); - } - }, - /** - * Fixup for list item after indent. - * - * @method fixupListItemsAfterIndent - */ - fixupListItemsAfterIndent: function() { - var selection = window.rangy.getSelection(), - rootelement = this.editor.getDOMNode(), - listelement = selection.anchorNode.parentElement; - - listelement = listelement.closest('ol, ul'); - if (!(listelement && rootelement.contains(listelement))) { - return; - } - - // We will move the child list into previous list item of the parent. - var previous = listelement.previousElementSibling; - if (previous && previous.tagName === 'LI') { - previous.appendChild(listelement); - selection.collapseToEnd(); - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/indent/yui/src/button/build.json b/lib/editor/atto/plugins/indent/yui/src/button/build.json deleted file mode 100644 index 29b8001d1d0..00000000000 --- a/lib/editor/atto/plugins/indent/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_indent-button", - "builds": { - "moodle-atto_indent-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/indent/yui/src/button/js/button.js b/lib/editor/atto/plugins/indent/yui/src/button/js/button.js deleted file mode 100644 index d309ff5f78a..00000000000 --- a/lib/editor/atto/plugins/indent/yui/src/button/js/button.js +++ /dev/null @@ -1,222 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_indent - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_indent-button - */ - -/** - * Atto text editor indent plugin. - * - * @namespace M.atto_indent - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_indent').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - - this.addButton({ - icon: 'e/decrease_indent', - title: 'outdent', - buttonName: 'outdent', - callback: this.outdent - }); - - this.addButton({ - icon: 'e/increase_indent', - title: 'indent', - buttonName: 'indent', - callback: this.indent - }); - }, - - /** - * Indents the currently selected content. - * - * @method indent - */ - indent: function() { - // Save the current selection - we want to restore this. - var selection = window.rangy.saveSelection(), - blockquotes = this.editor.all('blockquote'), - count = blockquotes.size(); - - // Remove display:none from rangy markers so browser doesn't delete them. - this.editor.all('.rangySelectionBoundary').setStyle('display', null); - - // Mark all existing block quotes in case the user has actually added some. - blockquotes.addClass('pre-existing'); - - // Run the indent command. - document.execCommand('indent', false, null); - - // Fix indent list item. - this.fixupListItemsAfterIndent(); - - // Get all blockquotes, both existing and new. - blockquotes = this.editor.all('blockquote'); - - if (blockquotes.size() !== count) { - // There are new block quotes, the indent exec has wrapped some content in block quotes in order - // to indent the selected content. - // We don't want blockquotes, we're going to convert them to divs. - this.replaceBlockquote(this.editor); - // Finally restore the seelction. The content has changed - sometimes this works - but not always :( - window.rangy.restoreSelection(selection); - } else if (blockquotes.size() > 0) { - // There were no new blockquotes, this happens if the user is indenting/outdenting a list. - blockquotes.removeClass('pre-existing'); - } - - // Remove the selection markers - a clean up really. - window.rangy.removeMarkers(selection); - - // Mark the text as having been updated. - this.markUpdated(); - }, - - /** - * Outdents the currently selected content. - * - * @method outdent - */ - outdent: function() { - // Save the selection we will want to restore it. - var selection = window.rangy.saveSelection(), - blockquotes = this.editor.all('blockquote'), - count = blockquotes.size(); - - // Mark existing blockquotes so that we don't convert them later. - blockquotes.addClass('pre-existing'); - - // Replace all div indents with blockquote indents so that we can rely on the browser functionality. - this.replaceEditorIndents(this.editor); - - // Restore the users selection - otherwise the next outdent operation won't work! - window.rangy.restoreSelection(selection); - // And save it once more. - selection = window.rangy.saveSelection(); - - // Outdent. - document.execCommand('outdent', false, null); - - // Get all blockquotes so that we can work out what happened. - blockquotes = this.editor.all('blockquote'); - - if (blockquotes.size() !== count) { - // The number of blockquotes hasn't changed. - // This occurs when the user has outdented a list item. - this.replaceBlockquote(this.editor); - window.rangy.restoreSelection(selection); - } else if (blockquotes.size() > 0) { - // The number of blockquotes is the same and is more than 0 we just need to clean up the class - // we added to mark pre-existing blockquotes. - blockquotes.removeClass('pre-existing'); - } - - // Clean up any left over selection markers. - window.rangy.removeMarkers(selection); - - // Mark the text as having been updated. - this.markUpdated(); - }, - - /** - * Replaces all blockquotes within an editor with div indents. - * @method replaceBlockquote - * @param Editor editor - */ - replaceBlockquote: function(editor) { - editor.all('blockquote').setAttribute('data-iterate', true); - var blockquote = editor.one('blockquote'), - margindir = (Y.one('body.dir-ltr')) ? 'marginLeft' : 'marginRight'; - while (blockquote) { - blockquote.removeAttribute('data-iterate'); - if (blockquote.hasClass('pre-existing')) { - blockquote.removeClass('pre-existing'); - } else { - var clone = Y.Node.create('
                          ') - .setAttrs(blockquote.getAttrs()) - .setStyle(margindir, '30px') - .addClass('editor-indent'); - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = blockquote.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - blockquote.replace(clone); - } - blockquote = editor.one('blockquote[data-iterate]'); - } - }, - - /** - * Replaces all div indents with blockquotes. - * @method replaceEditorIndents - * @param Editor editor - */ - replaceEditorIndents: function(editor) { - // We use the editor-indent class because it is preserved between saves. - var indent = editor.one('.editor-indent'); - while (indent) { - var clone = Y.Node.create('
                          ') - .setAttrs(indent - .getAttrs()) - .removeClass('editor-indent'); - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = indent.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - indent.replace(clone); - indent = editor.one('.editor-indent'); - } - }, - /** - * Fixup for list item after indent. - * - * @method fixupListItemsAfterIndent - */ - fixupListItemsAfterIndent: function() { - var selection = window.rangy.getSelection(), - rootelement = this.editor.getDOMNode(), - listelement = selection.anchorNode.parentElement; - - listelement = listelement.closest('ol, ul'); - if (!(listelement && rootelement.contains(listelement))) { - return; - } - - // We will move the child list into previous list item of the parent. - var previous = listelement.previousElementSibling; - if (previous && previous.tagName === 'LI') { - previous.appendChild(listelement); - selection.collapseToEnd(); - } - } -}); diff --git a/lib/editor/atto/plugins/indent/yui/src/button/meta/button.json b/lib/editor/atto/plugins/indent/yui/src/button/meta/button.json deleted file mode 100644 index c7b92c47d82..00000000000 --- a/lib/editor/atto/plugins/indent/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_indent-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/italic/classes/privacy/provider.php b/lib/editor/atto/plugins/italic/classes/privacy/provider.php deleted file mode 100644 index 679c37b4cca..00000000000 --- a/lib/editor/atto/plugins/italic/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_italic - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_italic\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_italic implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/italic/lang/en/atto_italic.php b/lib/editor/atto/plugins/italic/lang/en/atto_italic.php deleted file mode 100644 index 55a5fe146f7..00000000000 --- a/lib/editor/atto/plugins/italic/lang/en/atto_italic.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_italic', language 'en'. - * - * @package atto_italic - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Italic'; -$string['privacy:metadata'] = 'The atto_italic plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/italic/tests/behat/italic.feature b/lib/editor/atto/plugins/italic/tests/behat/italic.feature deleted file mode 100644 index b62b3775de7..00000000000 --- a/lib/editor/atto/plugins/italic/tests/behat/italic.feature +++ /dev/null @@ -1,35 +0,0 @@ -@editor @editor_atto @atto @atto_italic @_bug_phantomjs -Feature: Atto italic button - To format text in Atto, I need to use the italic button. - - @javascript - Scenario: Italicise some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Tower of Pisa" - And I select the text in the "Description" Atto editor - When I click on "Italic" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Tower of Pisa" - - @javascript - Scenario: Toggle italics in some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "GHD - for hair" - And I select the text in the "Description" Atto editor - When I click on "Italic" "button" - And I click on "Italic" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should not see "GHD - for hair" - And I should see "GHD - for hair" diff --git a/lib/editor/atto/plugins/italic/version.php b/lib/editor/atto/plugins/italic/version.php deleted file mode 100644 index 1a991b806d7..00000000000 --- a/lib/editor/atto/plugins/italic/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_italic - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_italic'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-debug.js b/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-debug.js deleted file mode 100644 index d316663dc8d..00000000000 --- a/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-debug.js +++ /dev/null @@ -1,72 +0,0 @@ -YUI.add('moodle-atto_italic-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_italic - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_italic-button - */ - -/** - * Atto text editor italic plugin. - * - * @namespace M.atto_italic - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_italic').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var italic; - - this.addButton({ - callback: this._toggleItalic, - icon: 'e/italic', - buttonName: italic, - inlineFormat: true, - - // Key code for the keyboard shortcut which triggers this button: - keys: '73', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'em, i' - }); - }, - /** - * Toggle the italic setting. - * - * @method _toggleItalic - * @param {EventFacade} e - */ - _toggleItalic: function() { - var host = this.get('host'); - - // Use the "italic" command for simplicity. This will toggle tags off as well. - document.execCommand('italic', false, null); - - // Then change all tags to tags. This will change any existing tags as well. - host.changeToCSS('i', 'bf-editor-italic-emphasis'); - host.changeToTags('bf-editor-italic-emphasis', 'em'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-min.js b/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-min.js deleted file mode 100644 index d0fc6d5cc8d..00000000000 --- a/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_italic-button",function(t,i){t.namespace("M.atto_italic").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({callback:this._toggleItalic,icon:"e/italic",buttonName:void 0,inlineFormat:!0,keys:"73",tags:"em, i"})},_toggleItalic:function(){var t=this.get("host");document.execCommand("italic",!1,null),t.changeToCSS("i","bf-editor-italic-emphasis"),t.changeToTags("bf-editor-italic-emphasis","em")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button.js b/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button.js deleted file mode 100644 index d316663dc8d..00000000000 --- a/lib/editor/atto/plugins/italic/yui/build/moodle-atto_italic-button/moodle-atto_italic-button.js +++ /dev/null @@ -1,72 +0,0 @@ -YUI.add('moodle-atto_italic-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_italic - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_italic-button - */ - -/** - * Atto text editor italic plugin. - * - * @namespace M.atto_italic - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_italic').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var italic; - - this.addButton({ - callback: this._toggleItalic, - icon: 'e/italic', - buttonName: italic, - inlineFormat: true, - - // Key code for the keyboard shortcut which triggers this button: - keys: '73', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'em, i' - }); - }, - /** - * Toggle the italic setting. - * - * @method _toggleItalic - * @param {EventFacade} e - */ - _toggleItalic: function() { - var host = this.get('host'); - - // Use the "italic" command for simplicity. This will toggle tags off as well. - document.execCommand('italic', false, null); - - // Then change all tags to tags. This will change any existing tags as well. - host.changeToCSS('i', 'bf-editor-italic-emphasis'); - host.changeToTags('bf-editor-italic-emphasis', 'em'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/italic/yui/src/button/build.json b/lib/editor/atto/plugins/italic/yui/src/button/build.json deleted file mode 100644 index d7df4fc2ee0..00000000000 --- a/lib/editor/atto/plugins/italic/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_italic-button", - "builds": { - "moodle-atto_italic-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/italic/yui/src/button/js/button.js b/lib/editor/atto/plugins/italic/yui/src/button/js/button.js deleted file mode 100644 index fadc5e5f9b3..00000000000 --- a/lib/editor/atto/plugins/italic/yui/src/button/js/button.js +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_italic - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_italic-button - */ - -/** - * Atto text editor italic plugin. - * - * @namespace M.atto_italic - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_italic').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var italic; - - this.addButton({ - callback: this._toggleItalic, - icon: 'e/italic', - buttonName: italic, - inlineFormat: true, - - // Key code for the keyboard shortcut which triggers this button: - keys: '73', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'em, i' - }); - }, - /** - * Toggle the italic setting. - * - * @method _toggleItalic - * @param {EventFacade} e - */ - _toggleItalic: function() { - var host = this.get('host'); - - // Use the "italic" command for simplicity. This will toggle tags off as well. - document.execCommand('italic', false, null); - - // Then change all tags to tags. This will change any existing tags as well. - host.changeToCSS('i', 'bf-editor-italic-emphasis'); - host.changeToTags('bf-editor-italic-emphasis', 'em'); - } -}); diff --git a/lib/editor/atto/plugins/italic/yui/src/button/meta/button.json b/lib/editor/atto/plugins/italic/yui/src/button/meta/button.json deleted file mode 100644 index d1ba4c9bd64..00000000000 --- a/lib/editor/atto/plugins/italic/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_italic-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/link/classes/privacy/provider.php b/lib/editor/atto/plugins/link/classes/privacy/provider.php deleted file mode 100644 index aaba0c34ce8..00000000000 --- a/lib/editor/atto/plugins/link/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_link - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_link\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_link implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/link/lang/en/atto_link.php b/lib/editor/atto/plugins/link/lang/en/atto_link.php deleted file mode 100644 index 4d08af1015b..00000000000 --- a/lib/editor/atto/plugins/link/lang/en/atto_link.php +++ /dev/null @@ -1,32 +0,0 @@ -. - -/** - * Strings for component 'atto_link', language 'en'. - * - * @package atto_link - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['browserepositories'] = 'Browse repositories...'; -$string['createlink'] = 'Create link'; -$string['enterurl'] = 'Enter a URL'; -$string['openinnewwindow'] = 'Open in new window'; -$string['pluginname'] = 'Link'; -$string['unlink'] = 'Unlink'; -$string['privacy:metadata'] = 'The atto_link plugin does not store any personal data.'; -$string['texttodisplay'] = 'Text to display'; diff --git a/lib/editor/atto/plugins/link/lib.php b/lib/editor/atto/plugins/link/lib.php deleted file mode 100644 index 2a3b247c662..00000000000 --- a/lib/editor/atto/plugins/link/lib.php +++ /dev/null @@ -1,42 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_link - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise this plugin - * @param string $elementid - */ -function atto_link_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('createlink', - 'unlink', - 'enterurl', - 'browserepositories', - 'openinnewwindow', - 'texttodisplay'), - 'atto_link'); -} - diff --git a/lib/editor/atto/plugins/link/tests/behat/link.feature b/lib/editor/atto/plugins/link/tests/behat/link.feature deleted file mode 100644 index fe21267ae7c..00000000000 --- a/lib/editor/atto/plugins/link/tests/behat/link.feature +++ /dev/null @@ -1,115 +0,0 @@ -@editor @editor_atto @atto @atto_link -Feature: Add links to Atto - To write rich text - I need to add links. - - @javascript - Scenario: Insert a links - Given the following "user private file" exists: - | user | admin | - | filepath | lib/editor/atto/tests/fixtures/moodle-logo.png | - And I log in as "admin" - When I open my profile in edit mode - And I set the field "Description" to "Super cool" - And I select the text in the "Description" Atto editor - And I click on "Link" "button" - Then the field "Text to display" matches value "Super cool" - And I click on "Browse repositories..." "button" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.png" "link" - And I click on "Select this file" "button" - And I click on "Update profile" "button" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - And I should see "Super cool
                          " - - @javascript - Scenario: Insert a link without providing text to display - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Link" "button" - And I set the field "Enter a URL" to "https://moodle.org/" - Then the field "Text to display" matches value "https://moodle.org/" - And I click on "Create link" "button" - And I should see "https://moodle.org/" - And I click on "Link" "button" - And the field "Text to display" matches value "https://moodle.org/" - And the field "Enter a URL" matches value "https://moodle.org/" - And I click on "Close" "button" in the "Create link" "dialogue" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I should see "https://moodle.org/" - - @javascript - Scenario: Insert a link with providing text to display - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Link" "button" - And I set the field "Text to display" to "Moodle - Open-source learning platform" - And I set the field "Enter a URL" to "https://moodle.org/" - And I click on "Create link" "button" - Then I should see "Moodle - Open-source learning platform" - And I click on "Link" "button" - And the field "Text to display" matches value "Moodle - Open-source learning platform" - And the field "Enter a URL" matches value "https://moodle.org/" - And I click on "Close" "button" in the "Create link" "dialogue" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I should see "Moodle - Open-source learning platform" - And I should not see "https://moodle.org/" - - @javascript - Scenario: Edit a link that already had a custom text to display - Given I log in as "admin" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - And I set the field "Description" to "Moodle - Open-source learning platform" - And I click on "Update profile" "button" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Atto HTML editor" - And I press "Save changes" - When I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Moodle - Open-source learning platform" - And I click on "Link" "button" - And the field "Text to display" matches value "Moodle - Open-source learning platform" - And the field "Enter a URL" matches value "https://moodle.org/" - - @javascript - Scenario: Insert a link for an image - Given the following "user private file" exists: - | user | admin | - | filepath | lib/editor/atto/tests/fixtures/moodle-logo.png | - And I log in as "admin" - And I open my profile in edit mode - And I click on "Insert or edit image" "button" - And I click on "Browse repositories..." "button" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.png" "link" - And I click on "Select this file" "button" - And I set the field "Describe this image for someone who cannot see it" to "It's the Moodle" - And I press "Save image" - And I select the text in the "Description" Atto editor - And I press the right key - And I press the shift left key - And I click on "Link" "button" - And I set the field "Enter a URL" to "https://moodle.org/" - And I set the field "Text to display" to "Moodle - Open-source learning platform" - And I click on "Create link" "button" - When I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see ". - -/** - * Atto text editor integration version file. - * - * @package atto_link - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_link'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-debug.js b/lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-debug.js deleted file mode 100644 index 585e1557620..00000000000 --- a/lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-debug.js +++ /dev/null @@ -1,557 +0,0 @@ -YUI.add('moodle-atto_link-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_link - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_link-button - */ - -/** - * Atto text editor link plugin. - * - * @namespace M.atto_link - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENTNAME = 'atto_link', - CSS = { - NEWWINDOW: 'atto_link_openinnewwindow', - URLINPUT: 'atto_link_urlentry', - URLTEXT: 'atto_link_urltext' - }, - SELECTORS = { - NEWWINDOW: '.atto_link_openinnewwindow', - URLINPUT: '.atto_link_urlentry', - URLTEXT: '.atto_link_urltext', - SUBMIT: '.submit', - LINKBROWSER: '.openlinkbrowser' - }, - TEMPLATE = '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{#if showFilepicker}}' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{else}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          '; -Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * A reference to the dialogue content. - * - * @property _content - * @type Node - * @private - */ - _content: null, - - /** - * Text to display has value or not. - * @property _hasTextToDisplay - * @type Boolean - * @private - */ - _hasTextToDisplay: false, - - /** - * User has selected plain text or not. - * @property _hasPlainTextSelected - * @type Boolean - * @private - */ - _hasPlainTextSelected: false, - - initializer: function() { - // Add the link button first. - this.addButton({ - icon: 'e/insert_edit_link', - keys: '75', - callback: this._displayDialogue, - tags: 'a', - tagMatchRequiresAll: false - }); - - // And then the unlink button. - this.addButton({ - buttonName: 'unlink', - callback: this._unlink, - icon: 'e/remove_link', - title: 'unlink', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'a', - tagMatchRequiresAll: false - }); - }, - - /** - * Display the link editor. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createlink', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - focusOnShowSelector: SELECTORS.URLINPUT - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()); - - // Resolve anchors in the selected text. - this._resolveAnchors(); - dialogue.show(); - }, - - /** - * If there is selected text and it is part of an anchor link, - * extract the url (and target) from the link (and set them in the form). - * - * @method _resolveAnchors - * @private - */ - _resolveAnchors: function() { - // Find the first anchor tag in the selection. - var selectednode = this.get('host').getSelectionParentNode(), - anchornodes, - anchornode, - url, - target, - textToDisplay, - title; - - // Note this is a document fragment and YUI doesn't like them. - if (!selectednode) { - return; - } - - anchornodes = this._findSelectedAnchors(Y.one(selectednode)); - if (anchornodes.length > 0) { - anchornode = anchornodes[0]; - this._currentSelection = this.get('host').getSelectionFromNode(anchornode); - url = anchornode.getAttribute('href'); - target = anchornode.getAttribute('target'); - textToDisplay = anchornode.get('innerText'); - title = anchornode.getAttribute('title'); - if (url !== '') { - this._content.one(SELECTORS.URLINPUT).setAttribute('value', url); - } - if (textToDisplay !== '') { - this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay); - } else if (title !== '') { - this._content.one(SELECTORS.URLTEXT).set('value', title); - } - if (target === '_blank') { - this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked'); - } else { - this._content.one(SELECTORS.NEWWINDOW).removeAttribute('checked'); - } - } else { - // User is selecting some text before clicking on the Link button. - textToDisplay = this._getTextSelection(); - if (textToDisplay !== '') { - this._hasTextToDisplay = true; - this._hasPlainTextSelected = true; - this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay); - } else { - // Set as default. - this._hasTextToDisplay = false; - this._hasPlainTextSelected = false; - } - } - }, - - /** - * Update the dialogue after a link was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the link. - * @private - */ - _filepickerCallback: function(params) { - this.getDialogue() - .set('focusAfterHide', null) - .hide(); - - if (params.url !== '') { - // Add the link. - this._setLinkOnSelection(params.url); - - // And mark the text area as updated. - this.markUpdated(); - } - }, - - /** - * The link was inserted, so make changes to the editor source. - * - * @method _setLink - * @param {EventFacade} e - * @private - */ - _setLink: function(e) { - var input, - value; - - e.preventDefault(); - this.getDialogue({ - focusAfterHide: null - }).hide(); - - input = this._content.one(SELECTORS.URLINPUT); - - value = input.get('value'); - if (value !== '') { - - // We add a prefix if it is not already prefixed. - value = value.trim(); - var expr = new RegExp(/^[a-zA-Z]*\.*\/|^#|^[a-zA-Z]*:/); - if (!expr.test(value)) { - value = 'http://' + value; - } - - // Add the link. - this._setLinkOnSelection(value); - - this.markUpdated(); - } - }, - - /** - * Final step setting the anchor on the selection. - * - * @private - * @method _setLinkOnSelection - * @param {String} url URL the link will point to. - * @return {Node} The added Node. - */ - _setLinkOnSelection: function(url) { - var host = this.get('host'), - link, - selectednode, - target, - anchornodes, - isUpdating, - urlText, - textToDisplay; - - this.editor.focus(); - host.setSelection(this._currentSelection); - isUpdating = !this._currentSelection[0].collapsed; - urlText = this._content.one(SELECTORS.URLTEXT); - textToDisplay = urlText.get('value').replace(/(<([^>]+)>)/gi, "").trim(); - if (textToDisplay === '') { - textToDisplay = url; - } - - if (!isUpdating) { - // Firefox cannot add links when the selection is empty so we will add it manually. - link = Y.Node.create('
                          ' + textToDisplay + ''); - link.setAttribute('href', url); - - // Add the node and select it to replicate the behaviour of execCommand. - selectednode = host.insertContentAtFocusPoint(link.get('outerHTML')); - host.setSelection(host.getSelectionFromNode(selectednode)); - } else { - if (Y.UA.gecko > 0) { - // For Firefox / Gecko we need to wrap the selection in a span so we can surround it with an anchor. - // This relates to https://bugzilla.mozilla.org/show_bug.cgi?id=1906559. - var originalSelection = document.getSelection(); - var wrapper = document.createElement('span'); - wrapper.setAttribute('data-wrapper', ''); - wrapper.style.display = 'inline'; - - var i; - for (i = 0; i < originalSelection.rangeCount; i++) { - originalSelection.getRangeAt(i).surroundContents(wrapper); - } - host.setSelection(host.getSelectionFromNode(Y.one(wrapper))); - - document.execCommand('unlink', false, null); - document.execCommand('createLink', false, url); - - var anchorNode = wrapper.parentNode; - wrapper.children.forEach(function(child) { - anchorNode.appendChild(child); - }); - wrapper.remove(); - - } else { - document.execCommand('unlink', false, null); - document.execCommand('createLink', false, url); - } - - // Now set the target. - selectednode = host.getSelectionParentNode(); - } - - // Note this is a document fragment and YUI doesn't like them. - if (!selectednode) { - return; - } - - anchornodes = this._findSelectedAnchors(Y.one(selectednode)); - // Add new window attributes if requested. - Y.Array.each(anchornodes, function(anchornode) { - target = this._content.one(SELECTORS.NEWWINDOW); - if (target.get('checked')) { - anchornode.setAttribute('target', '_blank'); - } else { - anchornode.removeAttribute('target'); - } - if (isUpdating && textToDisplay) { - // The 'createLink' command do not allow to set the custom text to display. So we need to do it here. - if (this._hasPlainTextSelected) { - // Only replace the innerText if the user has not selected any element or just the plain text. - anchornode.set('innerText', textToDisplay); - } else { - // The user has selected another element to add the hyperlink, like an image. - // We should add the title attribute instead of replacing the innerText of the hyperlink. - anchornode.setAttribute('title', textToDisplay); - } - } - }, this); - - return selectednode; - }, - - /** - * Look up and down for the nearest anchor tags that are least partly contained in the selection. - * - * @method _findSelectedAnchors - * @param {Node} node The node to search under for the selected anchor. - * @return {Node|Boolean} The Node, or false if not found. - * @private - */ - _findSelectedAnchors: function(node) { - var tagname = node.get('tagName'), - hit, hits; - - // Direct hit. - if (tagname && tagname.toLowerCase() === 'a') { - return [node]; - } - - // Search down but check that each node is part of the selection. - hits = []; - node.all('a').each(function(n) { - if (!hit && this.get('host').selectionContainsNode(n)) { - hits.push(n); - } - }, this); - if (hits.length > 0) { - return hits; - } - // Search up. - hit = node.ancestor('a'); - if (hit) { - return [hit]; - } - return []; - }, - - /** - * Generates the content of the dialogue. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var canShowFilepicker = this.get('host').canShowFilepicker('link'), - template = Y.Handlebars.compile(TEMPLATE); - - this._content = Y.Node.create(template({ - showFilepicker: canShowFilepicker, - component: COMPONENTNAME, - CSS: CSS - })); - - this._content.one(SELECTORS.URLINPUT).on('keyup', this._updateTextToDisplay, this); - this._content.one(SELECTORS.URLINPUT).on('change', this._updateTextToDisplay, this); - this._content.one(SELECTORS.URLTEXT).on('keyup', this._setTextToDisplayState, this); - this._content.one(SELECTORS.SUBMIT).on('click', this._setLink, this); - if (canShowFilepicker) { - this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) { - e.preventDefault(); - this.get('host').showFilepicker('link', this._filepickerCallback, this); - }, this); - } - - return this._content; - }, - - /** - * Unlinks the current selection. - * If the selection is empty (e.g. the cursor is placed within a link), - * then the whole link is unlinked. - * - * @method _unlink - * @private - */ - _unlink: function() { - var host = this.get('host'), - range = host.getSelection(); - - if (range && range.length) { - if (range[0].startOffset === range[0].endOffset) { - // The cursor was placed in the editor but there was no selection - select the whole parent. - var nodes = host.getSelectedNodes(); - if (nodes) { - // We need to unlink each anchor individually - we cannot select a range because it may only consist of a - // fragment of an anchor. Selecting the parent would be dangerous because it may contain other links which - // would then be unlinked too. - nodes.each(function(node) { - // We need to select the whole anchor node for this to work in some browsers. - // We only need to search up because getSelectedNodes returns all Nodes in the selection. - var anchor = node.ancestor('a', true); - if (anchor) { - // Set the selection to the whole of the first anchor. - host.setSelection(host.getSelectionFromNode(anchor)); - - // Call the browser unlink. - document.execCommand('unlink', false, null); - } - }, this); - - // And mark the text area as updated. - this.markUpdated(); - } - } else { - // Call the browser unlink. - document.execCommand('unlink', false, null); - - // And mark the text area as updated. - this.markUpdated(); - } - } - }, - - /** - * Set the current text to display state. - * - * @method _setTextToDisplayState - * @private - */ - _setTextToDisplayState: function() { - var urlText, - urlTextVal; - urlText = this._content.one(SELECTORS.URLTEXT); - urlTextVal = urlText.get('value'); - if (urlTextVal !== '') { - this._hasTextToDisplay = true; - } else { - this._hasTextToDisplay = false; - } - }, - - /** - * Update the text to display if the user does not provide the custom text. - * - * @method _updateTextToDisplay - * @private - */ - _updateTextToDisplay: function() { - var urlEntry, - urlText, - urlEntryVal; - urlEntry = this._content.one(SELECTORS.URLINPUT); - urlText = this._content.one(SELECTORS.URLTEXT); - urlEntryVal = urlEntry.get('value'); - if (!this._hasTextToDisplay) { - urlText.set('value', urlEntryVal); - } - }, - - /** - * Get only the selected text. - * In some cases, window.getSelection() is not run as expected. We should only get the text value - * For ex: XYZSome text here - * window.getSelection() will return XYZSome text here - * - * @returns {string} Selected text - * @private - */ - _getTextSelection: function() { - var selText = ''; - var sel = window.getSelection(); - var rangeCount = sel.rangeCount; - if (rangeCount) { - var rangeTexts = []; - for (var i = 0; i < rangeCount; ++i) { - rangeTexts.push('' + sel.getRangeAt(i)); - } - selText = rangeTexts.join(''); - } - return selText; - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-min.js b/lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-min.js deleted file mode 100644 index 489a735970b..00000000000 --- a/lib/editor/atto/plugins/link/yui/build/moodle-atto_link-button/moodle-atto_link-button-min.js +++ /dev/null @@ -1,2 +0,0 @@ -YUI.add("moodle-atto_link-button",function(u,t){var n="atto_link",i={NEWWINDOW:"atto_link_openinnewwindow",URLINPUT:"atto_link_urlentry",URLTEXT:"atto_link_urltext"},h=".atto_link_openinnewwindow",o=".atto_link_urlentry",d=".atto_link_urltext",l=".submit",s=".openlinkbrowser";u.namespace("M.atto_link").Button=u.Base.create("button",u.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_content:null,_hasTextToDisplay:!1,_hasPlainTextSelected:!1,initializer:function(){this.addButton({icon:"e/insert_edit_link",keys:"75",callback:this._displayDialogue,tags:"a",tagMatchRequiresAll:!1}),this.addButton({buttonName:"unlink",callback:this._unlink,icon:"e/remove_link",title:"unlink",tags:"a",tagMatchRequiresAll:!1})},_displayDialogue:function(){var t;this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&((t=this.getDialogue({headerContent:M.util.get_string("createlink",n),width:"auto",focusAfterHide:!0,focusOnShowSelector:o})).set("bodyContent",this._getDialogueContent()),this._resolveAnchors(),t.show())},_resolveAnchors:function(){var t,e,n,i=this.get("host").getSelectionParentNode();i&&(0<(i=this._findSelectedAnchors(u.one(i))).length?(i=i[0],this._currentSelection=this.get("host").getSelectionFromNode(i),t=i.getAttribute("href"),e=i.getAttribute("target"),n=i.get("innerText"),i=i.getAttribute("title"),""!==t&&this._content.one(o).setAttribute("value",t),""!==n?this._content.one(d).set("value",n):""!==i&&this._content.one(d).set("value",i),"_blank"===e?this._content.one(h).setAttribute("checked","checked"):this._content.one(h).removeAttribute("checked")):""!==(n=this._getTextSelection())?(this._hasTextToDisplay=!0,this._hasPlainTextSelected=!0,this._content.one(d).set("value",n)):(this._hasTextToDisplay=!1,this._hasPlainTextSelected=!1))},_filepickerCallback:function(t){this.getDialogue().set("focusAfterHide",null).hide(),""!==t.url&&(this._setLinkOnSelection(t.url),this.markUpdated())},_setLink:function(t){t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),""!==(t=this._content.one(o).get("value"))&&(t=t.trim(),new RegExp(/^[a-zA-Z]*\.*\/|^#|^[a-zA-Z]*:/).test(t)||(t="http://"+t),this._setLinkOnSelection(t),this.markUpdated())},_setLinkOnSelection:function(t){var e,n,i,o,l,s,a,c,r=this.get("host");if(this.editor.focus(),r.setSelection(this._currentSelection),n=!this._currentSelection[0].collapsed,i=this._content.one(d),""===(o=i.get("value").replace(/(<([^>]+)>)/gi,"").trim())&&(o=t),n){if(0"+o+"")).setAttribute("href",t),e=r.insertContentAtFocusPoint(i.get("outerHTML")),r.setSelection(r.getSelectionFromNode(e));if(e)return t=this._findSelectedAnchors(u.one(e)),u.Array.each(t,function(t){this._content.one(h).get("checked")?t.setAttribute("target","_blank"):t.removeAttribute("target"),n&&o&&(this._hasPlainTextSelected?t.set("innerText",o):t.setAttribute("title",o))},this),e},_findSelectedAnchors:function(t){var e,n,i=t.get("tagName");return i&&"a"===i.toLowerCase()?[t]:(n=[],t.all("a").each(function(t){!e&&this.get("host").selectionContainsNode(t)&&n.push(t)},this),0
                          {{#if showFilepicker}}
                          {{else}}
                          {{/if}}

                          ');return this._content=u.Node.create(e({showFilepicker:t,component:n,CSS:i})),this._content.one(o).on("keyup",this._updateTextToDisplay,this),this._content.one(o).on("change",this._updateTextToDisplay,this),this._content.one(d).on("keyup",this._setTextToDisplayState,this),this._content.one(l).on("click",this._setLink,this),t&&this._content.one(s).on("click",function(t){t.preventDefault(),this.get("host").showFilepicker("link",this._filepickerCallback,this)},this),this._content},_unlink:function(){var e=this.get("host"),t=e.getSelection();t&&t.length&&(t[0].startOffset===t[0].endOffset?(t=e.getSelectedNodes())&&(t.each(function(t){t=t.ancestor("a",!0);t&&(e.setSelection(e.getSelectionFromNode(t)),document.execCommand("unlink",!1,null))},this),this.markUpdated()):(document.execCommand("unlink",!1,null),this.markUpdated()))},_setTextToDisplayState:function(){var t=this._content.one(d).get("value");this._hasTextToDisplay=""!==t}, -_updateTextToDisplay:function(){var t=this._content.one(o),e=this._content.one(d),t=t.get("value");this._hasTextToDisplay||e.set("value",t)},_getTextSelection:function(){var t,e,n="",i=window.getSelection(),o=i.rangeCount;if(o){for(t=[],e=0;e. - -/* - * @package atto_link - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_link-button - */ - -/** - * Atto text editor link plugin. - * - * @namespace M.atto_link - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENTNAME = 'atto_link', - CSS = { - NEWWINDOW: 'atto_link_openinnewwindow', - URLINPUT: 'atto_link_urlentry', - URLTEXT: 'atto_link_urltext' - }, - SELECTORS = { - NEWWINDOW: '.atto_link_openinnewwindow', - URLINPUT: '.atto_link_urlentry', - URLTEXT: '.atto_link_urltext', - SUBMIT: '.submit', - LINKBROWSER: '.openlinkbrowser' - }, - TEMPLATE = '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{#if showFilepicker}}' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{else}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          '; -Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * A reference to the dialogue content. - * - * @property _content - * @type Node - * @private - */ - _content: null, - - /** - * Text to display has value or not. - * @property _hasTextToDisplay - * @type Boolean - * @private - */ - _hasTextToDisplay: false, - - /** - * User has selected plain text or not. - * @property _hasPlainTextSelected - * @type Boolean - * @private - */ - _hasPlainTextSelected: false, - - initializer: function() { - // Add the link button first. - this.addButton({ - icon: 'e/insert_edit_link', - keys: '75', - callback: this._displayDialogue, - tags: 'a', - tagMatchRequiresAll: false - }); - - // And then the unlink button. - this.addButton({ - buttonName: 'unlink', - callback: this._unlink, - icon: 'e/remove_link', - title: 'unlink', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'a', - tagMatchRequiresAll: false - }); - }, - - /** - * Display the link editor. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createlink', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - focusOnShowSelector: SELECTORS.URLINPUT - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()); - - // Resolve anchors in the selected text. - this._resolveAnchors(); - dialogue.show(); - }, - - /** - * If there is selected text and it is part of an anchor link, - * extract the url (and target) from the link (and set them in the form). - * - * @method _resolveAnchors - * @private - */ - _resolveAnchors: function() { - // Find the first anchor tag in the selection. - var selectednode = this.get('host').getSelectionParentNode(), - anchornodes, - anchornode, - url, - target, - textToDisplay, - title; - - // Note this is a document fragment and YUI doesn't like them. - if (!selectednode) { - return; - } - - anchornodes = this._findSelectedAnchors(Y.one(selectednode)); - if (anchornodes.length > 0) { - anchornode = anchornodes[0]; - this._currentSelection = this.get('host').getSelectionFromNode(anchornode); - url = anchornode.getAttribute('href'); - target = anchornode.getAttribute('target'); - textToDisplay = anchornode.get('innerText'); - title = anchornode.getAttribute('title'); - if (url !== '') { - this._content.one(SELECTORS.URLINPUT).setAttribute('value', url); - } - if (textToDisplay !== '') { - this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay); - } else if (title !== '') { - this._content.one(SELECTORS.URLTEXT).set('value', title); - } - if (target === '_blank') { - this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked'); - } else { - this._content.one(SELECTORS.NEWWINDOW).removeAttribute('checked'); - } - } else { - // User is selecting some text before clicking on the Link button. - textToDisplay = this._getTextSelection(); - if (textToDisplay !== '') { - this._hasTextToDisplay = true; - this._hasPlainTextSelected = true; - this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay); - } else { - // Set as default. - this._hasTextToDisplay = false; - this._hasPlainTextSelected = false; - } - } - }, - - /** - * Update the dialogue after a link was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the link. - * @private - */ - _filepickerCallback: function(params) { - this.getDialogue() - .set('focusAfterHide', null) - .hide(); - - if (params.url !== '') { - // Add the link. - this._setLinkOnSelection(params.url); - - // And mark the text area as updated. - this.markUpdated(); - } - }, - - /** - * The link was inserted, so make changes to the editor source. - * - * @method _setLink - * @param {EventFacade} e - * @private - */ - _setLink: function(e) { - var input, - value; - - e.preventDefault(); - this.getDialogue({ - focusAfterHide: null - }).hide(); - - input = this._content.one(SELECTORS.URLINPUT); - - value = input.get('value'); - if (value !== '') { - - // We add a prefix if it is not already prefixed. - value = value.trim(); - var expr = new RegExp(/^[a-zA-Z]*\.*\/|^#|^[a-zA-Z]*:/); - if (!expr.test(value)) { - value = 'http://' + value; - } - - // Add the link. - this._setLinkOnSelection(value); - - this.markUpdated(); - } - }, - - /** - * Final step setting the anchor on the selection. - * - * @private - * @method _setLinkOnSelection - * @param {String} url URL the link will point to. - * @return {Node} The added Node. - */ - _setLinkOnSelection: function(url) { - var host = this.get('host'), - link, - selectednode, - target, - anchornodes, - isUpdating, - urlText, - textToDisplay; - - this.editor.focus(); - host.setSelection(this._currentSelection); - isUpdating = !this._currentSelection[0].collapsed; - urlText = this._content.one(SELECTORS.URLTEXT); - textToDisplay = urlText.get('value').replace(/(<([^>]+)>)/gi, "").trim(); - if (textToDisplay === '') { - textToDisplay = url; - } - - if (!isUpdating) { - // Firefox cannot add links when the selection is empty so we will add it manually. - link = Y.Node.create('' + textToDisplay + ''); - link.setAttribute('href', url); - - // Add the node and select it to replicate the behaviour of execCommand. - selectednode = host.insertContentAtFocusPoint(link.get('outerHTML')); - host.setSelection(host.getSelectionFromNode(selectednode)); - } else { - if (Y.UA.gecko > 0) { - // For Firefox / Gecko we need to wrap the selection in a span so we can surround it with an anchor. - // This relates to https://bugzilla.mozilla.org/show_bug.cgi?id=1906559. - var originalSelection = document.getSelection(); - var wrapper = document.createElement('span'); - wrapper.setAttribute('data-wrapper', ''); - wrapper.style.display = 'inline'; - - var i; - for (i = 0; i < originalSelection.rangeCount; i++) { - originalSelection.getRangeAt(i).surroundContents(wrapper); - } - host.setSelection(host.getSelectionFromNode(Y.one(wrapper))); - - document.execCommand('unlink', false, null); - document.execCommand('createLink', false, url); - - var anchorNode = wrapper.parentNode; - wrapper.children.forEach(function(child) { - anchorNode.appendChild(child); - }); - wrapper.remove(); - - } else { - document.execCommand('unlink', false, null); - document.execCommand('createLink', false, url); - } - - // Now set the target. - selectednode = host.getSelectionParentNode(); - } - - // Note this is a document fragment and YUI doesn't like them. - if (!selectednode) { - return; - } - - anchornodes = this._findSelectedAnchors(Y.one(selectednode)); - // Add new window attributes if requested. - Y.Array.each(anchornodes, function(anchornode) { - target = this._content.one(SELECTORS.NEWWINDOW); - if (target.get('checked')) { - anchornode.setAttribute('target', '_blank'); - } else { - anchornode.removeAttribute('target'); - } - if (isUpdating && textToDisplay) { - // The 'createLink' command do not allow to set the custom text to display. So we need to do it here. - if (this._hasPlainTextSelected) { - // Only replace the innerText if the user has not selected any element or just the plain text. - anchornode.set('innerText', textToDisplay); - } else { - // The user has selected another element to add the hyperlink, like an image. - // We should add the title attribute instead of replacing the innerText of the hyperlink. - anchornode.setAttribute('title', textToDisplay); - } - } - }, this); - - return selectednode; - }, - - /** - * Look up and down for the nearest anchor tags that are least partly contained in the selection. - * - * @method _findSelectedAnchors - * @param {Node} node The node to search under for the selected anchor. - * @return {Node|Boolean} The Node, or false if not found. - * @private - */ - _findSelectedAnchors: function(node) { - var tagname = node.get('tagName'), - hit, hits; - - // Direct hit. - if (tagname && tagname.toLowerCase() === 'a') { - return [node]; - } - - // Search down but check that each node is part of the selection. - hits = []; - node.all('a').each(function(n) { - if (!hit && this.get('host').selectionContainsNode(n)) { - hits.push(n); - } - }, this); - if (hits.length > 0) { - return hits; - } - // Search up. - hit = node.ancestor('a'); - if (hit) { - return [hit]; - } - return []; - }, - - /** - * Generates the content of the dialogue. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var canShowFilepicker = this.get('host').canShowFilepicker('link'), - template = Y.Handlebars.compile(TEMPLATE); - - this._content = Y.Node.create(template({ - showFilepicker: canShowFilepicker, - component: COMPONENTNAME, - CSS: CSS - })); - - this._content.one(SELECTORS.URLINPUT).on('keyup', this._updateTextToDisplay, this); - this._content.one(SELECTORS.URLINPUT).on('change', this._updateTextToDisplay, this); - this._content.one(SELECTORS.URLTEXT).on('keyup', this._setTextToDisplayState, this); - this._content.one(SELECTORS.SUBMIT).on('click', this._setLink, this); - if (canShowFilepicker) { - this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) { - e.preventDefault(); - this.get('host').showFilepicker('link', this._filepickerCallback, this); - }, this); - } - - return this._content; - }, - - /** - * Unlinks the current selection. - * If the selection is empty (e.g. the cursor is placed within a link), - * then the whole link is unlinked. - * - * @method _unlink - * @private - */ - _unlink: function() { - var host = this.get('host'), - range = host.getSelection(); - - if (range && range.length) { - if (range[0].startOffset === range[0].endOffset) { - // The cursor was placed in the editor but there was no selection - select the whole parent. - var nodes = host.getSelectedNodes(); - if (nodes) { - // We need to unlink each anchor individually - we cannot select a range because it may only consist of a - // fragment of an anchor. Selecting the parent would be dangerous because it may contain other links which - // would then be unlinked too. - nodes.each(function(node) { - // We need to select the whole anchor node for this to work in some browsers. - // We only need to search up because getSelectedNodes returns all Nodes in the selection. - var anchor = node.ancestor('a', true); - if (anchor) { - // Set the selection to the whole of the first anchor. - host.setSelection(host.getSelectionFromNode(anchor)); - - // Call the browser unlink. - document.execCommand('unlink', false, null); - } - }, this); - - // And mark the text area as updated. - this.markUpdated(); - } - } else { - // Call the browser unlink. - document.execCommand('unlink', false, null); - - // And mark the text area as updated. - this.markUpdated(); - } - } - }, - - /** - * Set the current text to display state. - * - * @method _setTextToDisplayState - * @private - */ - _setTextToDisplayState: function() { - var urlText, - urlTextVal; - urlText = this._content.one(SELECTORS.URLTEXT); - urlTextVal = urlText.get('value'); - if (urlTextVal !== '') { - this._hasTextToDisplay = true; - } else { - this._hasTextToDisplay = false; - } - }, - - /** - * Update the text to display if the user does not provide the custom text. - * - * @method _updateTextToDisplay - * @private - */ - _updateTextToDisplay: function() { - var urlEntry, - urlText, - urlEntryVal; - urlEntry = this._content.one(SELECTORS.URLINPUT); - urlText = this._content.one(SELECTORS.URLTEXT); - urlEntryVal = urlEntry.get('value'); - if (!this._hasTextToDisplay) { - urlText.set('value', urlEntryVal); - } - }, - - /** - * Get only the selected text. - * In some cases, window.getSelection() is not run as expected. We should only get the text value - * For ex: XYZSome text here - * window.getSelection() will return XYZSome text here - * - * @returns {string} Selected text - * @private - */ - _getTextSelection: function() { - var selText = ''; - var sel = window.getSelection(); - var rangeCount = sel.rangeCount; - if (rangeCount) { - var rangeTexts = []; - for (var i = 0; i < rangeCount; ++i) { - rangeTexts.push('' + sel.getRangeAt(i)); - } - selText = rangeTexts.join(''); - } - return selText; - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/link/yui/src/button/build.json b/lib/editor/atto/plugins/link/yui/src/button/build.json deleted file mode 100644 index 0f84aad113e..00000000000 --- a/lib/editor/atto/plugins/link/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_link-button", - "builds": { - "moodle-atto_link-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/link/yui/src/button/js/button.js b/lib/editor/atto/plugins/link/yui/src/button/js/button.js deleted file mode 100644 index 4096c1bd728..00000000000 --- a/lib/editor/atto/plugins/link/yui/src/button/js/button.js +++ /dev/null @@ -1,552 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_link - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_link-button - */ - -/** - * Atto text editor link plugin. - * - * @namespace M.atto_link - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENTNAME = 'atto_link', - CSS = { - NEWWINDOW: 'atto_link_openinnewwindow', - URLINPUT: 'atto_link_urlentry', - URLTEXT: 'atto_link_urltext' - }, - SELECTORS = { - NEWWINDOW: '.atto_link_openinnewwindow', - URLINPUT: '.atto_link_urlentry', - URLTEXT: '.atto_link_urltext', - SUBMIT: '.submit', - LINKBROWSER: '.openlinkbrowser' - }, - TEMPLATE = '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{#if showFilepicker}}' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{else}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          '; -Y.namespace('M.atto_link').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * A reference to the dialogue content. - * - * @property _content - * @type Node - * @private - */ - _content: null, - - /** - * Text to display has value or not. - * @property _hasTextToDisplay - * @type Boolean - * @private - */ - _hasTextToDisplay: false, - - /** - * User has selected plain text or not. - * @property _hasPlainTextSelected - * @type Boolean - * @private - */ - _hasPlainTextSelected: false, - - initializer: function() { - // Add the link button first. - this.addButton({ - icon: 'e/insert_edit_link', - keys: '75', - callback: this._displayDialogue, - tags: 'a', - tagMatchRequiresAll: false - }); - - // And then the unlink button. - this.addButton({ - buttonName: 'unlink', - callback: this._unlink, - icon: 'e/remove_link', - title: 'unlink', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'a', - tagMatchRequiresAll: false - }); - }, - - /** - * Display the link editor. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current selection. - this._currentSelection = this.get('host').getSelection(); - if (this._currentSelection === false) { - return; - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createlink', COMPONENTNAME), - width: 'auto', - focusAfterHide: true, - focusOnShowSelector: SELECTORS.URLINPUT - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent()); - - // Resolve anchors in the selected text. - this._resolveAnchors(); - dialogue.show(); - }, - - /** - * If there is selected text and it is part of an anchor link, - * extract the url (and target) from the link (and set them in the form). - * - * @method _resolveAnchors - * @private - */ - _resolveAnchors: function() { - // Find the first anchor tag in the selection. - var selectednode = this.get('host').getSelectionParentNode(), - anchornodes, - anchornode, - url, - target, - textToDisplay, - title; - - // Note this is a document fragment and YUI doesn't like them. - if (!selectednode) { - return; - } - - anchornodes = this._findSelectedAnchors(Y.one(selectednode)); - if (anchornodes.length > 0) { - anchornode = anchornodes[0]; - this._currentSelection = this.get('host').getSelectionFromNode(anchornode); - url = anchornode.getAttribute('href'); - target = anchornode.getAttribute('target'); - textToDisplay = anchornode.get('innerText'); - title = anchornode.getAttribute('title'); - if (url !== '') { - this._content.one(SELECTORS.URLINPUT).setAttribute('value', url); - } - if (textToDisplay !== '') { - this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay); - } else if (title !== '') { - this._content.one(SELECTORS.URLTEXT).set('value', title); - } - if (target === '_blank') { - this._content.one(SELECTORS.NEWWINDOW).setAttribute('checked', 'checked'); - } else { - this._content.one(SELECTORS.NEWWINDOW).removeAttribute('checked'); - } - } else { - // User is selecting some text before clicking on the Link button. - textToDisplay = this._getTextSelection(); - if (textToDisplay !== '') { - this._hasTextToDisplay = true; - this._hasPlainTextSelected = true; - this._content.one(SELECTORS.URLTEXT).set('value', textToDisplay); - } else { - // Set as default. - this._hasTextToDisplay = false; - this._hasPlainTextSelected = false; - } - } - }, - - /** - * Update the dialogue after a link was selected in the File Picker. - * - * @method _filepickerCallback - * @param {object} params The parameters provided by the filepicker - * containing information about the link. - * @private - */ - _filepickerCallback: function(params) { - this.getDialogue() - .set('focusAfterHide', null) - .hide(); - - if (params.url !== '') { - // Add the link. - this._setLinkOnSelection(params.url); - - // And mark the text area as updated. - this.markUpdated(); - } - }, - - /** - * The link was inserted, so make changes to the editor source. - * - * @method _setLink - * @param {EventFacade} e - * @private - */ - _setLink: function(e) { - var input, - value; - - e.preventDefault(); - this.getDialogue({ - focusAfterHide: null - }).hide(); - - input = this._content.one(SELECTORS.URLINPUT); - - value = input.get('value'); - if (value !== '') { - - // We add a prefix if it is not already prefixed. - value = value.trim(); - var expr = new RegExp(/^[a-zA-Z]*\.*\/|^#|^[a-zA-Z]*:/); - if (!expr.test(value)) { - value = 'http://' + value; - } - - // Add the link. - this._setLinkOnSelection(value); - - this.markUpdated(); - } - }, - - /** - * Final step setting the anchor on the selection. - * - * @private - * @method _setLinkOnSelection - * @param {String} url URL the link will point to. - * @return {Node} The added Node. - */ - _setLinkOnSelection: function(url) { - var host = this.get('host'), - link, - selectednode, - target, - anchornodes, - isUpdating, - urlText, - textToDisplay; - - this.editor.focus(); - host.setSelection(this._currentSelection); - isUpdating = !this._currentSelection[0].collapsed; - urlText = this._content.one(SELECTORS.URLTEXT); - textToDisplay = urlText.get('value').replace(/(<([^>]+)>)/gi, "").trim(); - if (textToDisplay === '') { - textToDisplay = url; - } - - if (!isUpdating) { - // Firefox cannot add links when the selection is empty so we will add it manually. - link = Y.Node.create('' + textToDisplay + ''); - link.setAttribute('href', url); - - // Add the node and select it to replicate the behaviour of execCommand. - selectednode = host.insertContentAtFocusPoint(link.get('outerHTML')); - host.setSelection(host.getSelectionFromNode(selectednode)); - } else { - if (Y.UA.gecko > 0) { - // For Firefox / Gecko we need to wrap the selection in a span so we can surround it with an anchor. - // This relates to https://bugzilla.mozilla.org/show_bug.cgi?id=1906559. - var originalSelection = document.getSelection(); - var wrapper = document.createElement('span'); - wrapper.setAttribute('data-wrapper', ''); - wrapper.style.display = 'inline'; - - var i; - for (i = 0; i < originalSelection.rangeCount; i++) { - originalSelection.getRangeAt(i).surroundContents(wrapper); - } - host.setSelection(host.getSelectionFromNode(Y.one(wrapper))); - - document.execCommand('unlink', false, null); - document.execCommand('createLink', false, url); - - var anchorNode = wrapper.parentNode; - wrapper.children.forEach(function(child) { - anchorNode.appendChild(child); - }); - wrapper.remove(); - - } else { - document.execCommand('unlink', false, null); - document.execCommand('createLink', false, url); - } - - // Now set the target. - selectednode = host.getSelectionParentNode(); - } - - // Note this is a document fragment and YUI doesn't like them. - if (!selectednode) { - return; - } - - anchornodes = this._findSelectedAnchors(Y.one(selectednode)); - // Add new window attributes if requested. - Y.Array.each(anchornodes, function(anchornode) { - target = this._content.one(SELECTORS.NEWWINDOW); - if (target.get('checked')) { - anchornode.setAttribute('target', '_blank'); - } else { - anchornode.removeAttribute('target'); - } - if (isUpdating && textToDisplay) { - // The 'createLink' command do not allow to set the custom text to display. So we need to do it here. - if (this._hasPlainTextSelected) { - // Only replace the innerText if the user has not selected any element or just the plain text. - anchornode.set('innerText', textToDisplay); - } else { - // The user has selected another element to add the hyperlink, like an image. - // We should add the title attribute instead of replacing the innerText of the hyperlink. - anchornode.setAttribute('title', textToDisplay); - } - } - }, this); - - return selectednode; - }, - - /** - * Look up and down for the nearest anchor tags that are least partly contained in the selection. - * - * @method _findSelectedAnchors - * @param {Node} node The node to search under for the selected anchor. - * @return {Node|Boolean} The Node, or false if not found. - * @private - */ - _findSelectedAnchors: function(node) { - var tagname = node.get('tagName'), - hit, hits; - - // Direct hit. - if (tagname && tagname.toLowerCase() === 'a') { - return [node]; - } - - // Search down but check that each node is part of the selection. - hits = []; - node.all('a').each(function(n) { - if (!hit && this.get('host').selectionContainsNode(n)) { - hits.push(n); - } - }, this); - if (hits.length > 0) { - return hits; - } - // Search up. - hit = node.ancestor('a'); - if (hit) { - return [hit]; - } - return []; - }, - - /** - * Generates the content of the dialogue. - * - * @method _getDialogueContent - * @return {Node} Node containing the dialogue content - * @private - */ - _getDialogueContent: function() { - var canShowFilepicker = this.get('host').canShowFilepicker('link'), - template = Y.Handlebars.compile(TEMPLATE); - - this._content = Y.Node.create(template({ - showFilepicker: canShowFilepicker, - component: COMPONENTNAME, - CSS: CSS - })); - - this._content.one(SELECTORS.URLINPUT).on('keyup', this._updateTextToDisplay, this); - this._content.one(SELECTORS.URLINPUT).on('change', this._updateTextToDisplay, this); - this._content.one(SELECTORS.URLTEXT).on('keyup', this._setTextToDisplayState, this); - this._content.one(SELECTORS.SUBMIT).on('click', this._setLink, this); - if (canShowFilepicker) { - this._content.one(SELECTORS.LINKBROWSER).on('click', function(e) { - e.preventDefault(); - this.get('host').showFilepicker('link', this._filepickerCallback, this); - }, this); - } - - return this._content; - }, - - /** - * Unlinks the current selection. - * If the selection is empty (e.g. the cursor is placed within a link), - * then the whole link is unlinked. - * - * @method _unlink - * @private - */ - _unlink: function() { - var host = this.get('host'), - range = host.getSelection(); - - if (range && range.length) { - if (range[0].startOffset === range[0].endOffset) { - // The cursor was placed in the editor but there was no selection - select the whole parent. - var nodes = host.getSelectedNodes(); - if (nodes) { - // We need to unlink each anchor individually - we cannot select a range because it may only consist of a - // fragment of an anchor. Selecting the parent would be dangerous because it may contain other links which - // would then be unlinked too. - nodes.each(function(node) { - // We need to select the whole anchor node for this to work in some browsers. - // We only need to search up because getSelectedNodes returns all Nodes in the selection. - var anchor = node.ancestor('a', true); - if (anchor) { - // Set the selection to the whole of the first anchor. - host.setSelection(host.getSelectionFromNode(anchor)); - - // Call the browser unlink. - document.execCommand('unlink', false, null); - } - }, this); - - // And mark the text area as updated. - this.markUpdated(); - } - } else { - // Call the browser unlink. - document.execCommand('unlink', false, null); - - // And mark the text area as updated. - this.markUpdated(); - } - } - }, - - /** - * Set the current text to display state. - * - * @method _setTextToDisplayState - * @private - */ - _setTextToDisplayState: function() { - var urlText, - urlTextVal; - urlText = this._content.one(SELECTORS.URLTEXT); - urlTextVal = urlText.get('value'); - if (urlTextVal !== '') { - this._hasTextToDisplay = true; - } else { - this._hasTextToDisplay = false; - } - }, - - /** - * Update the text to display if the user does not provide the custom text. - * - * @method _updateTextToDisplay - * @private - */ - _updateTextToDisplay: function() { - var urlEntry, - urlText, - urlEntryVal; - urlEntry = this._content.one(SELECTORS.URLINPUT); - urlText = this._content.one(SELECTORS.URLTEXT); - urlEntryVal = urlEntry.get('value'); - if (!this._hasTextToDisplay) { - urlText.set('value', urlEntryVal); - } - }, - - /** - * Get only the selected text. - * In some cases, window.getSelection() is not run as expected. We should only get the text value - * For ex: XYZSome text here - * window.getSelection() will return XYZSome text here - * - * @returns {string} Selected text - * @private - */ - _getTextSelection: function() { - var selText = ''; - var sel = window.getSelection(); - var rangeCount = sel.rangeCount; - if (rangeCount) { - var rangeTexts = []; - for (var i = 0; i < rangeCount; ++i) { - rangeTexts.push('' + sel.getRangeAt(i)); - } - selText = rangeTexts.join(''); - } - return selText; - } -}); diff --git a/lib/editor/atto/plugins/link/yui/src/button/meta/button.json b/lib/editor/atto/plugins/link/yui/src/button/meta/button.json deleted file mode 100644 index 674df029d84..00000000000 --- a/lib/editor/atto/plugins/link/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_link-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/managefiles/classes/privacy/provider.php b/lib/editor/atto/plugins/managefiles/classes/privacy/provider.php deleted file mode 100644 index 88884c99443..00000000000 --- a/lib/editor/atto/plugins/managefiles/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_managefiles - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_managefiles\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_managefiles implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/managefiles/lang/en/atto_managefiles.php b/lib/editor/atto/plugins/managefiles/lang/en/atto_managefiles.php deleted file mode 100644 index 8b74d583d59..00000000000 --- a/lib/editor/atto/plugins/managefiles/lang/en/atto_managefiles.php +++ /dev/null @@ -1,34 +0,0 @@ -. - -/** - * Strings for component 'atto_managefiles', language 'en'. - * - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['deleteselected'] = 'Delete selected files'; -$string['hasmissingfiles'] = 'Warning! The following files that are referenced in the text area appear to be missing:'; -$string['filemanager'] = 'File manager'; -$string['managefiles'] = 'Manage files'; -$string['missingfiles'] = 'Missing files'; -$string['pluginname'] = 'Manage files'; -$string['unusedfilesdesc'] = 'The following embedded files are not used in the text area:'; -$string['unusedfilesremovalnotice'] = 'Any unused files will be automatically deleted when saving changes.'; -$string['unusedfilesheader'] = 'Unused files'; -$string['privacy:metadata'] = 'The atto_managefiles plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/managefiles/lib.php b/lib/editor/atto/plugins/managefiles/lib.php deleted file mode 100644 index b6ff2a1a259..00000000000 --- a/lib/editor/atto/plugins/managefiles/lib.php +++ /dev/null @@ -1,72 +0,0 @@ -. - -/** - * Atto text editor manage files plugin lib. - * - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_managefiles_strings_for_js() { - global $PAGE; - $PAGE->requires->strings_for_js(array('managefiles'), 'atto_managefiles'); -} - -/** - * Sends the parameters to JS module. - * - * @return array - */ -function atto_managefiles_params_for_js($elementid, $options, $fpoptions) { - global $CFG, $USER; - require_once($CFG->dirroot . '/repository/lib.php'); // Load constants. - - // Disabled if: - // - Not logged in or guest. - // - Files are not allowed. - // - Only URL are supported. - $disabled = !isloggedin() || isguestuser() || - (!isset($options['maxfiles']) || $options['maxfiles'] == 0) || - (isset($options['return_types']) && !($options['return_types'] & ~FILE_EXTERNAL)); - - $params = array('disabled' => $disabled, 'area' => array(), 'usercontext' => null); - - if (!$disabled) { - $params['usercontext'] = context_user::instance($USER->id)->id; - foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types', - 'removeorphaneddrafts') as $key) { - if (isset($options[$key])) { - if ($key === 'context' && is_object($options[$key])) { - // Just context id is enough. - $params['area'][$key] = $options[$key]->id; - } else { - $params['area'][$key] = $options[$key]; - } - } - } - } - - return $params; -} diff --git a/lib/editor/atto/plugins/managefiles/manage.php b/lib/editor/atto/plugins/managefiles/manage.php deleted file mode 100644 index d22c837910e..00000000000 --- a/lib/editor/atto/plugins/managefiles/manage.php +++ /dev/null @@ -1,114 +0,0 @@ -. - -/** - * Manage files in user draft area attached to texteditor. - * - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -require(__DIR__ . '/../../../../../config.php'); -require_once(__DIR__ . '/manage_form.php'); -require_once($CFG->libdir . '/filestorage/file_storage.php'); -require_once($CFG->dirroot . '/repository/lib.php'); - -$itemid = required_param('itemid', PARAM_INT); -$maxbytes = optional_param('maxbytes', 0, PARAM_INT); -$subdirs = optional_param('subdirs', 0, PARAM_INT); -$accepted_types = optional_param('accepted_types', '*', PARAM_RAW); // TODO Not yet passed to this script. -$return_types = optional_param('return_types', null, PARAM_INT); -$areamaxbytes = optional_param('areamaxbytes', FILE_AREA_MAX_BYTES_UNLIMITED, PARAM_INT); -$contextid = optional_param('context', SYSCONTEXTID, PARAM_INT); -$elementid = optional_param('elementid', '', PARAM_TEXT); -$removeorphaneddrafts = optional_param('removeorphaneddrafts', 0, PARAM_INT); - -$context = context::instance_by_id($contextid); -if ($context->contextlevel == CONTEXT_MODULE) { - // Module context. - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - require_login($cm->course, true, $cm); -} else if (($coursecontext = $context->get_course_context(false)) && $coursecontext->id != SITEID) { - // Course context or block inside the course. - require_login($coursecontext->instanceid); - $PAGE->set_context($context); -} else { - // Block that is not inside the course, user or system context. - require_login(); - $PAGE->set_context($context); -} - -// Guests can never manage files. -if (isguestuser()) { - throw new \moodle_exception('noguest'); -} - -$title = get_string('managefiles', 'atto_managefiles'); - -$PAGE->set_url('/lib/editor/atto/plugins/managefiles/manage.php'); -$PAGE->set_title($title); -$PAGE->set_heading($title); -$PAGE->set_pagelayout('popup'); - -if ($return_types !== null) { - // Links are allowed in textarea but never allowed in filemanager. - $return_types = $return_types & ~FILE_EXTERNAL; -} - -$options = array( - 'subdirs' => $subdirs, - 'maxbytes' => $maxbytes, - 'maxfiles' => -1, - 'accepted_types' => $accepted_types, - 'areamaxbytes' => $areamaxbytes, - 'return_types' => $return_types, - 'context' => $context -); - -$usercontext = context_user::instance($USER->id); -$fs = get_file_storage(); -$files = $fs->get_directory_files($usercontext->id, 'user', 'draft', $itemid, '/', !empty($subdirs), false); -$filenames = array(); -foreach ($files as $file) { - $filenames[$file->get_pathnamehash()] = ltrim($file->get_filepath(), '/') . $file->get_filename(); -} - -$mform = new atto_managefiles_manage_form(null, - array('options' => $options, 'draftitemid' => $itemid, 'files' => $filenames, 'elementid' => $elementid, - 'removeorphaneddrafts' => $removeorphaneddrafts), 'post', '', array('id' => 'atto_managefiles_manageform')); - -if ($data = $mform->get_data()) { - if (!empty($data->deletefile)) { - foreach (array_keys($data->deletefile) as $filehash) { - if ($file = $fs->get_file_by_hash($filehash)) { - // Make sure the user didn't modify the filehash to delete another file. - if ($file->get_component() == 'user' && $file->get_filearea() == 'draft' - && $file->get_itemid() == $itemid && $file->get_contextid() == $usercontext->id) { - $file->delete(); - } - } - } - $filenames = array_diff_key($filenames, $data->deletefile); - $mform = new atto_managefiles_manage_form(null, - array('options' => $options, 'draftitemid' => $itemid, 'files' => $filenames, 'elementid' => $data->elementid), - 'post', '', array('id' => 'atto_managefiles_manageform')); - } -} - -echo $OUTPUT->header(); -$mform->display(); -echo $OUTPUT->footer(); diff --git a/lib/editor/atto/plugins/managefiles/manage_form.php b/lib/editor/atto/plugins/managefiles/manage_form.php deleted file mode 100644 index 57ed198c7ec..00000000000 --- a/lib/editor/atto/plugins/managefiles/manage_form.php +++ /dev/null @@ -1,119 +0,0 @@ -. - -/** - * Atto text editor manage files plugin form. - * - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->libdir."/formslib.php"); - -/** - * Form allowing to edit files in one draft area. - * - * No buttons are necessary since the draft area files are saved immediately using AJAX. - * - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class atto_managefiles_manage_form extends moodleform { - - function definition() { - global $PAGE, $USER; - $mform = $this->_form; - - $mform->setDisableShortforms(true); - - $itemid = $this->_customdata['draftitemid']; - $elementid = $this->_customdata['elementid']; - $options = $this->_customdata['options']; - $files = $this->_customdata['files']; - $removeorphaneddrafts = $this->_customdata['removeorphaneddrafts'] ?? false; - - $mform->addElement('header', 'filemanagerhdr', get_string('filemanager', 'atto_managefiles')); - - $mform->addElement('hidden', 'itemid'); - $mform->setType('itemid', PARAM_INT); - $mform->addElement('hidden', 'maxbytes'); - $mform->setType('maxbytes', PARAM_INT); - $mform->addElement('hidden', 'subdirs'); - $mform->setType('subdirs', PARAM_INT); - $mform->addElement('hidden', 'accepted_types'); - $mform->setType('accepted_types', PARAM_RAW); - $mform->addElement('hidden', 'return_types'); - $mform->setType('return_types', PARAM_INT); - $mform->addElement('hidden', 'context'); - $mform->setType('context', PARAM_INT); - $mform->addElement('hidden', 'areamaxbytes'); - $mform->setType('areamaxbytes', PARAM_INT); - $mform->addElement('hidden', 'elementid'); - $mform->setType('elementid', PARAM_TEXT); - - $mform->addElement('filemanager', 'files_filemanager', '', null, $options); - - // Let the user know that any drafts not referenced in the text will be removed automatically. - if ($removeorphaneddrafts) { - $mform->addElement('static', '', '', - html_writer::tag('div', get_string('unusedfilesremovalnotice', 'atto_managefiles'))); - } - - $mform->addElement('header', 'missingfileshdr', get_string('missingfiles', 'atto_managefiles')); - $mform->addElement('static', '', '', - html_writer::tag('div', - html_writer::tag('div', get_string('hasmissingfiles', 'atto_managefiles')) . - html_writer::tag('div', '', array('class' => 'missing-files') - ), - array('class' => 'file-status')) - ); - - $mform->addElement('header', 'deletefileshdr', get_string('unusedfilesheader', 'atto_managefiles')); - $mform->addElement('static', '', '', - html_writer::tag('div', get_string('unusedfilesdesc', 'atto_managefiles'))); - - foreach ($files as $hash => $file) { - $mform->addElement('checkbox', 'deletefile[' . $hash . ']', '', $file, array('data-filename' => $file)); - $mform->setType('deletefile[' . $hash . ']', PARAM_INT); - } - - $mform->addElement('submit', 'delete', get_string('deleteselected', 'atto_managefiles')); - - $PAGE->requires->yui_module('moodle-atto_managefiles-usedfiles', 'M.atto_managefiles.usedfiles.init', - array(array( - 'files' => array_flip($files), - 'usercontext' => context_user::instance($USER->id)->id, - 'itemid' => $itemid, - 'elementid' => $elementid, - ))); - - $this->set_data(array( - 'files_filemanager' => $itemid, - 'itemid' => $itemid, - 'elementid' => $elementid, - 'subdirs' => $options['subdirs'], - 'maxbytes' => $options['maxbytes'], - 'areamaxbytes' => $options['areamaxbytes'], - 'accepted_types' => $options['accepted_types'], - 'return_types' => $options['return_types'], - 'context' => $options['context']->id, - )); - } -} diff --git a/lib/editor/atto/plugins/managefiles/styles.css b/lib/editor/atto/plugins/managefiles/styles.css deleted file mode 100644 index 934f4d375de..00000000000 --- a/lib/editor/atto/plugins/managefiles/styles.css +++ /dev/null @@ -1,19 +0,0 @@ -#atto_managefiles_manageform { - padding: 1rem; -} - -#atto_managefiles_manageform #id_deletefileshdr { - display: none; -} - -#atto_managefiles_manageform.has-unused-files #id_deletefileshdr { - display: block; -} - -#atto_managefiles_manageform #id_missingfileshdr { - display: none; -} - -#atto_managefiles_manageform.has-missing-files #id_missingfileshdr { - display: block; -} diff --git a/lib/editor/atto/plugins/managefiles/version.php b/lib/editor/atto/plugins/managefiles/version.php deleted file mode 100644 index 393de7c1f19..00000000000 --- a/lib/editor/atto/plugins/managefiles/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_managefiles'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js deleted file mode 100644 index ff55e3d878e..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js +++ /dev/null @@ -1,150 +0,0 @@ -YUI.add('moodle-atto_managefiles-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto-managefiles-button - */ - -/** - * Atto text editor managefiles plugin. - * - * @namespace M.atto_link - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var LOGNAME = 'atto_managefiles', - CAN_RECEIVE_FOCUS_SELECTOR = '.fp-navbar a:not([disabled])', - FILE_MANAGER_SELECTOR = '#fitem_id_files_filemanager'; - -Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - if (this.get('disabled')) { - return; - } - - var host = this.get('host'), - area = this.get('area'), - options = host.get('filepickeroptions'); - - if (options.image && options.image.itemid) { - area.itemid = options.image.itemid; - this.set('area', area); - } else { - Y.log('Plugin managefiles not available because itemid is missing.', - 'warn', LOGNAME); - return; - } - - this.addButton({ - icon: 'e/manage_files', - callback: this._displayDialogue - }); - }, - - /** - * Display the manage files. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function(e) { - e.preventDefault(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('managefiles', LOGNAME), - width: '800px', - focusAfterHide: true - }); - - var iframe = Y.Node.create(''); - // We set the height here because otherwise it is really small. That might not look - // very nice on mobile devices, but we considered that enough for now. - iframe.setStyles({ - height: '700px', - border: 'none', - width: '100%' - }); - iframe.setAttribute('src', this._getIframeURL()); - - // Focus on the first focusable element of the file manager after it is fully loaded. - iframe.on('load', function(e, frame) { - var fileManager = frame.getDOMNode().contentDocument.querySelector(FILE_MANAGER_SELECTOR); - // The file manager component is loaded asynchronously after the page is loaded. - // We check for the presence of .fm-loaded every 200 ms to determine if the file manager is loaded yet. - var intervalId = setInterval(function() { - if (fileManager.querySelector('.fm-loaded')) { - var firstFocusableElement = fileManager.querySelector(CAN_RECEIVE_FOCUS_SELECTOR); - if (firstFocusableElement) { - firstFocusableElement.focus(); - } - clearInterval(intervalId); - } - }, 200); - }, this, iframe); - - dialogue.set('bodyContent', iframe) - .show(); - - this.markUpdated(); - }, - - /** - * Returns the URL to the file manager. - * - * @param _getIframeURL - * @return {String} URL - * @private - */ - _getIframeURL: function() { - var args = Y.mix({ - elementid: this.get('host').get('elementid') - }, - this.get('area')); - return M.cfg.wwwroot + '/lib/editor/atto/plugins/managefiles/manage.php?' + - Y.QueryString.stringify(args); - } -}, { - ATTRS: { - disabled: { - value: true - }, - area: { - value: {} - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js deleted file mode 100644 index 056d225e5b1..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_managefiles-button",function(i,e){i.namespace("M.atto_managefiles").Button=i.Base.create("button",i.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){var e,t;this.get("disabled")||(t=this.get("host"),e=this.get("area"),(t=t.get("filepickeroptions")).image&&t.image.itemid&&(e.itemid=t.image.itemid,this.set("area",e),this.addButton({icon:"e/manage_files",callback:this._displayDialogue})))},_displayDialogue:function(e){var t;e.preventDefault(),e=this.getDialogue({headerContent:M.util.get_string("managefiles","atto_managefiles"),width:"800px",focusAfterHide:!0}),(t=i.Node.create("")).setStyles({height:"700px",border:"none",width:"100%"}),t.setAttribute("src",this._getIframeURL()),t.on("load",function(e,t){var i=t.getDOMNode().contentDocument.querySelector("#fitem_id_files_filemanager"),a=setInterval(function(){var e;i.querySelector(".fm-loaded")&&((e=i.querySelector(".fp-navbar a:not([disabled])"))&&e.focus(),clearInterval(a))},200)},this,t),e.set("bodyContent",t).show(),this.markUpdated()},_getIframeURL:function(){var e=i.mix({elementid:this.get("host").get("elementid")},this.get("area"));return M.cfg.wwwroot+"/lib/editor/atto/plugins/managefiles/manage.php?"+i.QueryString.stringify(e)}},{ATTRS:{disabled:{value:!0},area:{value:{}}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js deleted file mode 100644 index 7dbc265997e..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js +++ /dev/null @@ -1,148 +0,0 @@ -YUI.add('moodle-atto_managefiles-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto-managefiles-button - */ - -/** - * Atto text editor managefiles plugin. - * - * @namespace M.atto_link - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var LOGNAME = 'atto_managefiles', - CAN_RECEIVE_FOCUS_SELECTOR = '.fp-navbar a:not([disabled])', - FILE_MANAGER_SELECTOR = '#fitem_id_files_filemanager'; - -Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - if (this.get('disabled')) { - return; - } - - var host = this.get('host'), - area = this.get('area'), - options = host.get('filepickeroptions'); - - if (options.image && options.image.itemid) { - area.itemid = options.image.itemid; - this.set('area', area); - } else { - return; - } - - this.addButton({ - icon: 'e/manage_files', - callback: this._displayDialogue - }); - }, - - /** - * Display the manage files. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function(e) { - e.preventDefault(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('managefiles', LOGNAME), - width: '800px', - focusAfterHide: true - }); - - var iframe = Y.Node.create(''); - // We set the height here because otherwise it is really small. That might not look - // very nice on mobile devices, but we considered that enough for now. - iframe.setStyles({ - height: '700px', - border: 'none', - width: '100%' - }); - iframe.setAttribute('src', this._getIframeURL()); - - // Focus on the first focusable element of the file manager after it is fully loaded. - iframe.on('load', function(e, frame) { - var fileManager = frame.getDOMNode().contentDocument.querySelector(FILE_MANAGER_SELECTOR); - // The file manager component is loaded asynchronously after the page is loaded. - // We check for the presence of .fm-loaded every 200 ms to determine if the file manager is loaded yet. - var intervalId = setInterval(function() { - if (fileManager.querySelector('.fm-loaded')) { - var firstFocusableElement = fileManager.querySelector(CAN_RECEIVE_FOCUS_SELECTOR); - if (firstFocusableElement) { - firstFocusableElement.focus(); - } - clearInterval(intervalId); - } - }, 200); - }, this, iframe); - - dialogue.set('bodyContent', iframe) - .show(); - - this.markUpdated(); - }, - - /** - * Returns the URL to the file manager. - * - * @param _getIframeURL - * @return {String} URL - * @private - */ - _getIframeURL: function() { - var args = Y.mix({ - elementid: this.get('host').get('elementid') - }, - this.get('area')); - return M.cfg.wwwroot + '/lib/editor/atto/plugins/managefiles/manage.php?' + - Y.QueryString.stringify(args); - } -}, { - ATTRS: { - disabled: { - value: true - }, - area: { - value: {} - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js deleted file mode 100644 index 1b36bece62b..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-debug.js +++ /dev/null @@ -1,206 +0,0 @@ -YUI.add('moodle-atto_managefiles-usedfiles', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_managefiles-usedfiles - */ - - -/** - * Atto text editor managefiles usedfiles plugin. - * - * @namespace M.atto_managefiles - * @class usedfiles - */ - -/** - * CSS constants. - * - * @type {Object} - */ -var CSS = { - HASMISSINGFILES: 'has-missing-files', - HASUNUSEDFILES: 'has-unused-files' -}; - -/** - * Selectors constants. - * - * @type {Object} - */ -var SELECTORS = { - FILEANCESTOR: '.fitem', - FORM: '#atto_managefiles_manageform', - MISSINGFILES: '.missing-files' -}; - -M.atto_managefiles = M.atto_managefiles || {}; -M.atto_managefiles.usedfiles = M.atto_managefiles.usedfiles || { - - /** - * The user context. - * - * @property _usercontext - * @type Number - * @private - */ - _usercontext: null, - - /** - * Area Item ID. - * - * @property _itemid - * @type String - * @private - */ - _itemid: null, - - /** - * The editor elementid - * - * @property _elementid - * @type String - * @private - */ - _elementid: null, - - /** - * Init function. - * - * @param {Object} allFiles The keys are the file names, the values are the hashes. - * @return {Void} - */ - init: function(config) { - this._usercontext = config.usercontext; - this._itemid = config.itemid; - this._elementid = config.elementid; - - var allFiles = config.files; - var form = Y.one(SELECTORS.FORM), - usedFiles, - unusedFiles, - missingFiles, - missingFilesTxt, - i; - - if (!form || !window.parent) { - Y.log("Unable to find parent window", 'warn', 'moodle-atto_managemedia-usedfiles'); - return; - } - - usedFiles = this._getUsedFiles(); - unusedFiles = this.findUnusedFiles(allFiles, usedFiles); - missingFiles = this.findMissingFiles(allFiles, usedFiles); - - // There are some unused files. - if (unusedFiles.length > 0) { - // Loop over all the files in the form. - form.all('input[type=checkbox][name^="deletefile"]').each(function(node) { - // If the file is used, remove it. - if (Y.Array.indexOf(unusedFiles, node.getData('filename')) === -1) { - node.ancestor(SELECTORS.FILEANCESTOR).remove(); - } - }); - form.addClass(CSS.HASUNUSEDFILES); - } else { - // This is needed as the init may be called twice due to the double call to $PAGE->requires->yui_module(). - form.removeClass(CSS.HASUNUSEDFILES); - } - - // There are some files missing. - if (missingFiles.length > 0) { - missingFilesTxt = '
                            '; - for (i = 0; i < missingFiles.length; i++) { - missingFilesTxt += '
                          • ' + Y.Escape.html(missingFiles[i]) + '
                          • '; - } - missingFilesTxt += '
                          '; - form.one(SELECTORS.MISSINGFILES).setHTML('').append(missingFilesTxt); - form.addClass(CSS.HASMISSINGFILES); - } else { - form.removeClass(CSS.HASMISSINGFILES); - } - }, - - /** - * Return the list of files used in the area. - * - * @method _getUsedFiles - * @return {Object} List of files used where the keys are the name of the files, the value is true. - * @private - */ - _getUsedFiles: function() { - var content = Y.one(window.parent.document.getElementById(this._elementid + 'editable')), - baseUrl = M.cfg.wwwroot + '/draftfile.php/' + this._usercontext + '/user/draft/' + this._itemid + '/', - pattern = new RegExp("[\"']" + baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + "(.+?)[\\?\"']", 'gm'), - filename = '', - match = '', - usedFiles = {}; - - // The pattern matches any draftfile URL contained within quotes, e.g. 'src=""' or 'href=""'. - while ((match = pattern.exec(content.get('innerHTML'))) !== null) { - filename = decodeURIComponent(match[1]); - usedFiles[filename] = true; - } - - return usedFiles; - }, - - /** - * Return an array of unused files. - * - * @param {Object} allFiles Where the keys are the file names. - * @param {Object} usedFiles Where the keys are the file names. - * @return {Array} Of file names. - */ - findUnusedFiles: function(allFiles, usedFiles) { - var key, - list = []; - for (key in allFiles) { - if (!usedFiles[key]) { - list.push(key); - } - } - return list; - }, - - /** - * Return an array of missing files. - * - * @param {Object} allFiles Where the keys are the file names. - * @param {Object} usedFiles Where the keys are the file names. - * @return {Array} Of file names. - */ - findMissingFiles: function(allFiles, usedFiles) { - var key, - list = []; - for (key in usedFiles) { - if (!allFiles[key]) { - list.push(key); - } - } - return list; - } -}; - - -}, '@VERSION@', {"requires": ["node", "escape"]}); diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js deleted file mode 100644 index c829ff39f08..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_managefiles-usedfiles",function(d,e){var o="has-missing-files",f="has-unused-files",r=".fitem",u="#atto_managefiles_manageform",m=".missing-files";M.atto_managefiles=M.atto_managefiles||{},M.atto_managefiles.usedfiles=M.atto_managefiles.usedfiles||{_usercontext:null,_itemid:null,_elementid:null,init:function(e){var i,n,t,s,l,a;if(this._usercontext=e.usercontext,this._itemid=e.itemid,this._elementid=e.elementid,e=e.files,(i=d.one(u))&&window.parent)if(n=this._getUsedFiles(),t=this.findUnusedFiles(e,n),s=this.findMissingFiles(e,n),0",a=0;a"+d.Escape.html(s[a])+"";l+="",i.one(m).setHTML("").append(l),i.addClass(o)}else i.removeClass(o)},_getUsedFiles:function(){for(var e,i=d.one(window.parent.document.getElementById(this._elementid+"editable")),n=M.cfg.wwwroot+"/draftfile.php/"+this._usercontext+"/user/draft/"+this._itemid+"/",t=new RegExp("[\"']"+n.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")+"(.+?)[\\?\"']","gm"),s={};null!==(e=t.exec(i.get("innerHTML")));)s[decodeURIComponent(e[1])]=!0;return s},findUnusedFiles:function(e,i){var n,t=[];for(n in e)i[n]||t.push(n);return t},findMissingFiles:function(e,i){var n,t=[];for(n in i)e[n]||t.push(n);return t}}},"@VERSION@",{requires:["node","escape"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js deleted file mode 100644 index d15f24e5a40..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-usedfiles/moodle-atto_managefiles-usedfiles.js +++ /dev/null @@ -1,205 +0,0 @@ -YUI.add('moodle-atto_managefiles-usedfiles', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_managefiles-usedfiles - */ - - -/** - * Atto text editor managefiles usedfiles plugin. - * - * @namespace M.atto_managefiles - * @class usedfiles - */ - -/** - * CSS constants. - * - * @type {Object} - */ -var CSS = { - HASMISSINGFILES: 'has-missing-files', - HASUNUSEDFILES: 'has-unused-files' -}; - -/** - * Selectors constants. - * - * @type {Object} - */ -var SELECTORS = { - FILEANCESTOR: '.fitem', - FORM: '#atto_managefiles_manageform', - MISSINGFILES: '.missing-files' -}; - -M.atto_managefiles = M.atto_managefiles || {}; -M.atto_managefiles.usedfiles = M.atto_managefiles.usedfiles || { - - /** - * The user context. - * - * @property _usercontext - * @type Number - * @private - */ - _usercontext: null, - - /** - * Area Item ID. - * - * @property _itemid - * @type String - * @private - */ - _itemid: null, - - /** - * The editor elementid - * - * @property _elementid - * @type String - * @private - */ - _elementid: null, - - /** - * Init function. - * - * @param {Object} allFiles The keys are the file names, the values are the hashes. - * @return {Void} - */ - init: function(config) { - this._usercontext = config.usercontext; - this._itemid = config.itemid; - this._elementid = config.elementid; - - var allFiles = config.files; - var form = Y.one(SELECTORS.FORM), - usedFiles, - unusedFiles, - missingFiles, - missingFilesTxt, - i; - - if (!form || !window.parent) { - return; - } - - usedFiles = this._getUsedFiles(); - unusedFiles = this.findUnusedFiles(allFiles, usedFiles); - missingFiles = this.findMissingFiles(allFiles, usedFiles); - - // There are some unused files. - if (unusedFiles.length > 0) { - // Loop over all the files in the form. - form.all('input[type=checkbox][name^="deletefile"]').each(function(node) { - // If the file is used, remove it. - if (Y.Array.indexOf(unusedFiles, node.getData('filename')) === -1) { - node.ancestor(SELECTORS.FILEANCESTOR).remove(); - } - }); - form.addClass(CSS.HASUNUSEDFILES); - } else { - // This is needed as the init may be called twice due to the double call to $PAGE->requires->yui_module(). - form.removeClass(CSS.HASUNUSEDFILES); - } - - // There are some files missing. - if (missingFiles.length > 0) { - missingFilesTxt = '
                            '; - for (i = 0; i < missingFiles.length; i++) { - missingFilesTxt += '
                          • ' + Y.Escape.html(missingFiles[i]) + '
                          • '; - } - missingFilesTxt += '
                          '; - form.one(SELECTORS.MISSINGFILES).setHTML('').append(missingFilesTxt); - form.addClass(CSS.HASMISSINGFILES); - } else { - form.removeClass(CSS.HASMISSINGFILES); - } - }, - - /** - * Return the list of files used in the area. - * - * @method _getUsedFiles - * @return {Object} List of files used where the keys are the name of the files, the value is true. - * @private - */ - _getUsedFiles: function() { - var content = Y.one(window.parent.document.getElementById(this._elementid + 'editable')), - baseUrl = M.cfg.wwwroot + '/draftfile.php/' + this._usercontext + '/user/draft/' + this._itemid + '/', - pattern = new RegExp("[\"']" + baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + "(.+?)[\\?\"']", 'gm'), - filename = '', - match = '', - usedFiles = {}; - - // The pattern matches any draftfile URL contained within quotes, e.g. 'src=""' or 'href=""'. - while ((match = pattern.exec(content.get('innerHTML'))) !== null) { - filename = decodeURIComponent(match[1]); - usedFiles[filename] = true; - } - - return usedFiles; - }, - - /** - * Return an array of unused files. - * - * @param {Object} allFiles Where the keys are the file names. - * @param {Object} usedFiles Where the keys are the file names. - * @return {Array} Of file names. - */ - findUnusedFiles: function(allFiles, usedFiles) { - var key, - list = []; - for (key in allFiles) { - if (!usedFiles[key]) { - list.push(key); - } - } - return list; - }, - - /** - * Return an array of missing files. - * - * @param {Object} allFiles Where the keys are the file names. - * @param {Object} usedFiles Where the keys are the file names. - * @return {Array} Of file names. - */ - findMissingFiles: function(allFiles, usedFiles) { - var key, - list = []; - for (key in usedFiles) { - if (!allFiles[key]) { - list.push(key); - } - } - return list; - } -}; - - -}, '@VERSION@', {"requires": ["node", "escape"]}); diff --git a/lib/editor/atto/plugins/managefiles/yui/src/button/build.json b/lib/editor/atto/plugins/managefiles/yui/src/button/build.json deleted file mode 100644 index b56a9756793..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_managefiles-button", - "builds": { - "moodle-atto_managefiles-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js b/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js deleted file mode 100644 index abf0012e3bf..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js +++ /dev/null @@ -1,145 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto-managefiles-button - */ - -/** - * Atto text editor managefiles plugin. - * - * @namespace M.atto_link - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var LOGNAME = 'atto_managefiles', - CAN_RECEIVE_FOCUS_SELECTOR = '.fp-navbar a:not([disabled])', - FILE_MANAGER_SELECTOR = '#fitem_id_files_filemanager'; - -Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - initializer: function() { - if (this.get('disabled')) { - return; - } - - var host = this.get('host'), - area = this.get('area'), - options = host.get('filepickeroptions'); - - if (options.image && options.image.itemid) { - area.itemid = options.image.itemid; - this.set('area', area); - } else { - Y.log('Plugin managefiles not available because itemid is missing.', - 'warn', LOGNAME); - return; - } - - this.addButton({ - icon: 'e/manage_files', - callback: this._displayDialogue - }); - }, - - /** - * Display the manage files. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function(e) { - e.preventDefault(); - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('managefiles', LOGNAME), - width: '800px', - focusAfterHide: true - }); - - var iframe = Y.Node.create(''); - // We set the height here because otherwise it is really small. That might not look - // very nice on mobile devices, but we considered that enough for now. - iframe.setStyles({ - height: '700px', - border: 'none', - width: '100%' - }); - iframe.setAttribute('src', this._getIframeURL()); - - // Focus on the first focusable element of the file manager after it is fully loaded. - iframe.on('load', function(e, frame) { - var fileManager = frame.getDOMNode().contentDocument.querySelector(FILE_MANAGER_SELECTOR); - // The file manager component is loaded asynchronously after the page is loaded. - // We check for the presence of .fm-loaded every 200 ms to determine if the file manager is loaded yet. - var intervalId = setInterval(function() { - if (fileManager.querySelector('.fm-loaded')) { - var firstFocusableElement = fileManager.querySelector(CAN_RECEIVE_FOCUS_SELECTOR); - if (firstFocusableElement) { - firstFocusableElement.focus(); - } - clearInterval(intervalId); - } - }, 200); - }, this, iframe); - - dialogue.set('bodyContent', iframe) - .show(); - - this.markUpdated(); - }, - - /** - * Returns the URL to the file manager. - * - * @param _getIframeURL - * @return {String} URL - * @private - */ - _getIframeURL: function() { - var args = Y.mix({ - elementid: this.get('host').get('elementid') - }, - this.get('area')); - return M.cfg.wwwroot + '/lib/editor/atto/plugins/managefiles/manage.php?' + - Y.QueryString.stringify(args); - } -}, { - ATTRS: { - disabled: { - value: true - }, - area: { - value: {} - } - } -}); diff --git a/lib/editor/atto/plugins/managefiles/yui/src/button/meta/button.json b/lib/editor/atto/plugins/managefiles/yui/src/button/meta/button.json deleted file mode 100644 index 2ae29850f11..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_managefiles-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/build.json b/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/build.json deleted file mode 100644 index d4ec929f4d5..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_managefiles-usedfiles", - "builds": { - "moodle-atto_managefiles-usedfiles": { - "jsfiles": [ - "usedfiles.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/js/usedfiles.js b/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/js/usedfiles.js deleted file mode 100644 index 863ddfef6d7..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/js/usedfiles.js +++ /dev/null @@ -1,201 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_managefiles - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_managefiles-usedfiles - */ - - -/** - * Atto text editor managefiles usedfiles plugin. - * - * @namespace M.atto_managefiles - * @class usedfiles - */ - -/** - * CSS constants. - * - * @type {Object} - */ -var CSS = { - HASMISSINGFILES: 'has-missing-files', - HASUNUSEDFILES: 'has-unused-files' -}; - -/** - * Selectors constants. - * - * @type {Object} - */ -var SELECTORS = { - FILEANCESTOR: '.fitem', - FORM: '#atto_managefiles_manageform', - MISSINGFILES: '.missing-files' -}; - -M.atto_managefiles = M.atto_managefiles || {}; -M.atto_managefiles.usedfiles = M.atto_managefiles.usedfiles || { - - /** - * The user context. - * - * @property _usercontext - * @type Number - * @private - */ - _usercontext: null, - - /** - * Area Item ID. - * - * @property _itemid - * @type String - * @private - */ - _itemid: null, - - /** - * The editor elementid - * - * @property _elementid - * @type String - * @private - */ - _elementid: null, - - /** - * Init function. - * - * @param {Object} allFiles The keys are the file names, the values are the hashes. - * @return {Void} - */ - init: function(config) { - this._usercontext = config.usercontext; - this._itemid = config.itemid; - this._elementid = config.elementid; - - var allFiles = config.files; - var form = Y.one(SELECTORS.FORM), - usedFiles, - unusedFiles, - missingFiles, - missingFilesTxt, - i; - - if (!form || !window.parent) { - Y.log("Unable to find parent window", 'warn', 'moodle-atto_managemedia-usedfiles'); - return; - } - - usedFiles = this._getUsedFiles(); - unusedFiles = this.findUnusedFiles(allFiles, usedFiles); - missingFiles = this.findMissingFiles(allFiles, usedFiles); - - // There are some unused files. - if (unusedFiles.length > 0) { - // Loop over all the files in the form. - form.all('input[type=checkbox][name^="deletefile"]').each(function(node) { - // If the file is used, remove it. - if (Y.Array.indexOf(unusedFiles, node.getData('filename')) === -1) { - node.ancestor(SELECTORS.FILEANCESTOR).remove(); - } - }); - form.addClass(CSS.HASUNUSEDFILES); - } else { - // This is needed as the init may be called twice due to the double call to $PAGE->requires->yui_module(). - form.removeClass(CSS.HASUNUSEDFILES); - } - - // There are some files missing. - if (missingFiles.length > 0) { - missingFilesTxt = '
                            '; - for (i = 0; i < missingFiles.length; i++) { - missingFilesTxt += '
                          • ' + Y.Escape.html(missingFiles[i]) + '
                          • '; - } - missingFilesTxt += '
                          '; - form.one(SELECTORS.MISSINGFILES).setHTML('').append(missingFilesTxt); - form.addClass(CSS.HASMISSINGFILES); - } else { - form.removeClass(CSS.HASMISSINGFILES); - } - }, - - /** - * Return the list of files used in the area. - * - * @method _getUsedFiles - * @return {Object} List of files used where the keys are the name of the files, the value is true. - * @private - */ - _getUsedFiles: function() { - var content = Y.one(window.parent.document.getElementById(this._elementid + 'editable')), - baseUrl = M.cfg.wwwroot + '/draftfile.php/' + this._usercontext + '/user/draft/' + this._itemid + '/', - pattern = new RegExp("[\"']" + baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + "(.+?)[\\?\"']", 'gm'), - filename = '', - match = '', - usedFiles = {}; - - // The pattern matches any draftfile URL contained within quotes, e.g. 'src=""' or 'href=""'. - while ((match = pattern.exec(content.get('innerHTML'))) !== null) { - filename = decodeURIComponent(match[1]); - usedFiles[filename] = true; - } - - return usedFiles; - }, - - /** - * Return an array of unused files. - * - * @param {Object} allFiles Where the keys are the file names. - * @param {Object} usedFiles Where the keys are the file names. - * @return {Array} Of file names. - */ - findUnusedFiles: function(allFiles, usedFiles) { - var key, - list = []; - for (key in allFiles) { - if (!usedFiles[key]) { - list.push(key); - } - } - return list; - }, - - /** - * Return an array of missing files. - * - * @param {Object} allFiles Where the keys are the file names. - * @param {Object} usedFiles Where the keys are the file names. - * @return {Array} Of file names. - */ - findMissingFiles: function(allFiles, usedFiles) { - var key, - list = []; - for (key in usedFiles) { - if (!allFiles[key]) { - list.push(key); - } - } - return list; - } -}; diff --git a/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/meta/usedfiles.json b/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/meta/usedfiles.json deleted file mode 100644 index 089a2e80dee..00000000000 --- a/lib/editor/atto/plugins/managefiles/yui/src/usedfiles/meta/usedfiles.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "moodle-atto_managefiles-usedfiles": { - "requires": [ - "node", - "escape" - ] - } -} diff --git a/lib/editor/atto/plugins/media/classes/privacy/provider.php b/lib/editor/atto/plugins/media/classes/privacy/provider.php deleted file mode 100644 index 1a6cb8bf7f3..00000000000 --- a/lib/editor/atto/plugins/media/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_media - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_media\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_media implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/media/lang/en/atto_media.php b/lib/editor/atto/plugins/media/lang/en/atto_media.php deleted file mode 100644 index 08b6c6b83cd..00000000000 --- a/lib/editor/atto/plugins/media/lang/en/atto_media.php +++ /dev/null @@ -1,84 +0,0 @@ -. - -/** - * Strings for component 'atto_media', language 'en'. - * - * @package atto_media - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['add'] = 'Add'; -$string['addcaptionstrack'] = 'Add caption track'; -$string['addchapterstrack'] = 'Add chapter track'; -$string['adddescriptionstrack'] = 'Add description track'; -$string['addmetadatatrack'] = 'Add metadata track'; -$string['addsource'] = 'Add alternative source'; -$string['addsource_help'] = 'It is recommended that an alternative media source is provided, since desktop and mobile browsers vary in which file formats they support.'; -$string['addsubtitlestrack'] = 'Add subtitle track'; -$string['addtrack'] = 'Add track'; -$string['advancedsettings'] = 'Advanced settings'; -$string['audio'] = 'Audio'; -$string['audiosourcelabel'] = 'Audio source URL'; -$string['autoplay'] = 'Play automatically'; -$string['browserepositories'] = 'Browse repositories...'; -$string['captions'] = 'Captions'; -$string['captions_help'] = 'Captions may be used to describe everything happening in the track, including non-verbal sounds such as a phone ringing.'; -$string['captionssourcelabel'] = 'Caption track URL'; -$string['chapters'] = 'Chapters'; -$string['chapters_help'] = 'Chapter titles may be provided for use in navigating the media resource.'; -$string['chapterssourcelabel'] = 'Chapter track URL'; -$string['controls'] = 'Show controls'; -$string['createmedia'] = 'Insert media'; -$string['default'] = 'Default'; -$string['descriptions'] = 'Descriptions'; -$string['descriptions_help'] = 'Audio descriptions may be used to provide a narration which explains visual details not apparent from the audio alone.'; -$string['descriptionssourcelabel'] = 'Description track URL'; -$string['displayoptions'] = 'Display options'; -$string['entername'] = 'Enter name'; -$string['entertitle'] = 'Enter title'; -$string['entersource'] = 'Source URL'; -$string['enterurl'] = 'Enter URL'; -$string['height'] = 'Height'; -$string['kind'] = 'Type'; -$string['label'] = 'Label'; -$string['languagesavailable'] = 'Languages available'; -$string['languagesinstalled'] = 'Languages installed'; -$string['link'] = 'Link'; -$string['loop'] = 'Loop'; -$string['metadata'] = 'Metadata'; -$string['metadata_help'] = 'Metadata tracks, for use from a script, may be used only if the player supports metadata.'; -$string['metadatasourcelabel'] = 'Metadata track URL'; -$string['mute'] = 'Muted'; -$string['pluginname'] = 'Insert or edit an audio/video file'; -$string['poster'] = 'Thumbnail URL'; -$string['remove'] = 'Remove'; -$string['size'] = 'Size'; -$string['srclang'] = 'Language'; -$string['subtitles'] = 'Subtitles'; -$string['subtitles_help'] = 'Subtitles may be used to provide a transcription or translation of the dialogue.'; -$string['subtitlessourcelabel'] = 'Subtitle track URL'; -$string['track'] = 'Track URL'; -$string['tracks'] = 'Subtitles and captions'; -$string['tracks_help'] = 'Subtitles, captions, chapters and descriptions can be added via a WebVTT (Web Video Text Tracks) format file. Track labels will be shown in the selection drop-down menu. For each type of track, any track set as default will be pre-selected at the start of the video.'; -$string['video'] = 'Video'; -$string['videoheight'] = 'Video height'; -$string['videosourcelabel'] = 'Video source URL'; -$string['videowidth'] = 'Video width'; -$string['width'] = 'Width'; - -$string['privacy:metadata'] = 'The atto_media plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/media/lib.php b/lib/editor/atto/plugins/media/lib.php deleted file mode 100644 index 88ee7177c3a..00000000000 --- a/lib/editor/atto/plugins/media/lib.php +++ /dev/null @@ -1,128 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_media - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Initialise the js strings required for this plugin - */ -function atto_media_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('add', - 'addcaptionstrack', - 'addchapterstrack', - 'adddescriptionstrack', - 'addmetadatatrack', - 'addsource', - 'addsubtitlestrack', - 'addtrack', - 'advancedsettings', - 'audio', - 'audiosourcelabel', - 'autoplay', - 'browserepositories', - 'browserepositories', - 'captions', - 'captionssourcelabel', - 'chapters', - 'chapterssourcelabel', - 'controls', - 'createmedia', - 'default', - 'descriptions', - 'descriptionssourcelabel', - 'displayoptions', - 'entername', - 'entertitle', - 'entersource', - 'enterurl', - 'height', - 'kind', - 'label', - 'languagesavailable', - 'languagesinstalled', - 'link', - 'loop', - 'metadata', - 'metadatasourcelabel', - 'mute', - 'poster', - 'remove', - 'size', - 'srclang', - 'subtitles', - 'subtitlessourcelabel', - 'track', - 'tracks', - 'video', - 'videoheight', - 'videosourcelabel', - 'videowidth', - 'width'), - 'atto_media'); - $PAGE->requires->strings_for_js(array('expand', 'collapse'), 'moodle'); -} - -/** - * Sends the parameters to the JS module. - * - * @return array - */ -function atto_media_params_for_js() { - global $OUTPUT; - global $PAGE; - $currentlang = current_language(); - $langsinstalled = get_string_manager()->get_list_of_translations(true); - $langsavailable = get_string_manager()->get_list_of_languages(); - $params = [ - 'langs' => ['installed' => [], 'available' => []], - 'help' => [] - ]; - - foreach ($langsinstalled as $code => $name) { - $params['langs']['installed'][] = [ - 'lang' => $name, - 'code' => $code, - 'default' => $currentlang == $code - ]; - } - - foreach ($langsavailable as $code => $name) { - // See MDL-50829 for an explanation of this lrm thing. - $lrm = json_decode('"\u200E"'); - $params['langs']['available'][] = [ - 'lang' => $name . ' ' . $lrm . '(' . $code . ')' . $lrm, 'code' => $code]; - } - - $params['help'] = [ - 'addsource' => $OUTPUT->help_icon('addsource', 'atto_media'), - 'tracks' => $OUTPUT->help_icon('tracks', 'atto_media'), - 'subtitles' => $OUTPUT->help_icon('subtitles', 'atto_media'), - 'captions' => $OUTPUT->help_icon('captions', 'atto_media'), - 'descriptions' => $OUTPUT->help_icon('descriptions', 'atto_media'), - 'chapters' => $OUTPUT->help_icon('chapters', 'atto_media'), - 'metadata' => $OUTPUT->help_icon('metadata', 'atto_media') - ]; - - return $params; -} diff --git a/lib/editor/atto/plugins/media/styles.css b/lib/editor/atto/plugins/media/styles.css deleted file mode 100644 index f1ecb10e39d..00000000000 --- a/lib/editor/atto/plugins/media/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -.atto_form.atto_media > .tab-content { - max-height: 45vh; - overflow-x: hidden; -} \ No newline at end of file diff --git a/lib/editor/atto/plugins/media/styles_clean.css b/lib/editor/atto/plugins/media/styles_clean.css deleted file mode 100644 index e947eab2000..00000000000 --- a/lib/editor/atto/plugins/media/styles_clean.css +++ /dev/null @@ -1,28 +0,0 @@ -.nav-tabs > .nav-item a.active { - color: #555; - background-color: #fff; - border: 1px solid #ddd; - border-bottom-color: transparent; - cursor: default; -} - -.atto_form.atto_media .atto_media_track_lang_entry, -.atto_form.atto_media .atto_media_track_label_entry { - width: 124px; -} - -.atto_form.atto_media .atto_media_source > label { - width: calc(100% - 168px); -} - -.langlabel { - width: 42%; -} - -.labellabel { - width: 44%; -} - -.defaultlabel { - width: 14%; -} diff --git a/lib/editor/atto/plugins/media/tests/behat/media.feature b/lib/editor/atto/plugins/media/tests/behat/media.feature deleted file mode 100644 index 352c6a39617..00000000000 --- a/lib/editor/atto/plugins/media/tests/behat/media.feature +++ /dev/null @@ -1,206 +0,0 @@ -@editor @editor_atto @atto @atto_media -Feature: Add media to Atto - To write rich text - I need to add media. - - Background: - Given the following "user private files" exist: - | user | filepath | - | admin | lib/editor/atto/tests/fixtures/moodle-logo.webm | - | admin | lib/editor/atto/tests/fixtures/moodle-logo.mp4 | - | admin | lib/editor/atto/tests/fixtures/moodle-logo.png | - | admin | lib/editor/atto/tests/fixtures/pretty-good-en.vtt | - | admin | lib/editor/atto/tests/fixtures/pretty-good-sv.vtt | - And I log in as "admin" - And I change window size to "large" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Blog entry body" to "

                          Media test

                          " - And I select the text in the "Blog entry body" Atto editor - And I set the field "Entry title" to "The best video in the entire world (not really)" - And I click on "Insert or edit an audio/video file" "button" - - @javascript - Scenario: Insert some media as a link - # We need to disable the media plugin filter to be able to insert a link to a video file. - # Otherwise, the media plugin filter will try to render the video player instead of the link. - Given the "mediaplugin" filter is "off" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_link .atto_media_source.atto_media_link_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.webm" "link" - And I click on "Select this file" "button" - And the field "Enter name" matches value "moodle-logo.webm" - And I wait until the page is ready - And I click on "Insert media" "button" - When I click on "Save changes" "button" - Then "//a[. = 'moodle-logo.webm']" "xpath_element" should exist - - @javascript @atto_media_video - Scenario: Insert some media as a plain video - Given I click on "Video" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.webm" "link" - And I click on "Select this file" "button" - And I click on "Add alternative source" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video .atto_media_source.atto_media_media_source:nth-of-type(2)" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.mp4" "link" - And I click on "Select this file" "button" - When I click on "Insert media" "button" - Then "//video[descendant::source[contains(@src, 'moodle-logo.webm')]][descendant::source[contains(@src, 'moodle-logo.mp4')]]" "xpath_element" should exist - - @javascript @atto_media_video - Scenario: Insert some media as a video with display settings - Given I click on "Video" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.webm" "link" - And I click on "Select this file" "button" - And I click on "Display options" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video .atto_media_source.atto_media_poster_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "moodle-logo.png" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I set the field with xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_width_entry ')]" to "420" - And I set the field with xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_height_entry ')]" to "69" - And I set the field "Enter title" to "VideoTitle" - And I click on "Display options" "link" - When I click on "Insert media" "button" - Then "//video[descendant::source[contains(@src, 'moodle-logo.webm')]][contains(@poster, 'moodle-logo.png')][@width=420][@height=69][@title='VideoTitle']" "xpath_element" should exist - - @javascript @atto_media_video - Scenario: Insert some media as a video with advanced settings - Given I click on "Video" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.webm" "link" - And I click on "Select this file" "button" - And I click on "Advanced settings" "link" - And the field "Show controls" matches value "1" - And I set the field "Play automatically" to "1" - And I set the field "Muted" to "1" - And I set the field "Loop" to "1" - When I click on "Insert media" "button" - Then "//video[descendant::source[contains(@src, 'moodle-logo.webm')]][@controls='true'][@loop='true'][@autoplay='true'][@autoplay='true']" "xpath_element" should exist - - @javascript @atto_media_video - Scenario: Insert some media as a video with tracks - Given I click on "Video" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.webm" "link" - And I click on "Select this file" "button" - And I click on "Subtitles and captions" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_subtitles .atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-sv.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And the field "Label" matches value "Swedish" - And the field "Language" matches value "sv" - And I click on "Add subtitle track" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_subtitles .atto_media_track~.atto_media_track .atto_media_source.atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-en.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[2]" matches value "English" - And I set the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_default ')])[1]" to "1" - And I click on "Captions" "link" in the ".nav-item[data-track-kind='captions']" "css_element" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_captions .atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-sv.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[3]" matches value "Swedish" - And I click on "Add caption track" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_captions .atto_media_track~.atto_media_track .atto_media_source.atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-en.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[4]" matches value "English" - And I set the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_default ')])[4]" to "1" - And I click on "Descriptions" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_descriptions .atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-sv.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[5]" matches value "Swedish" - And I click on "Add description track" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_descriptions .atto_media_track~.atto_media_track .atto_media_source.atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-en.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[6]" matches value "English" - And I set the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_default ')])[5]" to "1" - And I click on "Chapters" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_chapters .atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-sv.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[7]" matches value "Swedish" - And I click on "Add chapter track" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_chapters .atto_media_track~.atto_media_track .atto_media_source.atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-en.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[8]" matches value "English" - And I set the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_default ')])[8]" to "1" - And I click on "Metadata" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_metadata .atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-sv.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[9]" matches value "Swedish" - And I click on "Add metadata track" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_video_metadata .atto_media_track~.atto_media_track .atto_media_source.atto_media_track_source" "css_element" - And I click on "Private files" "link" in the ".moodle-dialogue-base[aria-hidden='false'] .fp-repo-area" "css_element" - And I click on "pretty-good-en.vtt" "link" - And I click on "Select this file" "button" in the ".moodle-dialogue-base[aria-hidden='false']" "css_element" - And I click on "Overwrite" "button" - And the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_label_entry ')])[10]" matches value "English" - And I set the field with xpath "(//*[contains(concat(' ', normalize-space(@class), ' '), ' atto_media_track_default ')])[9]" to "1" - When I click on "Insert media" "button" - Then "//video[descendant::source[contains(@src, 'moodle-logo.webm')]][descendant::track[contains(@src, 'pretty-good-sv.vtt')][@kind='subtitles'][@label='Swedish'][@srclang='sv'][@default='true']][descendant::track[contains(@src, 'pretty-good-en.vtt')][@kind='subtitles'][@label='English'][@srclang='en'][not(@default)]][descendant::track[contains(@src, 'pretty-good-sv.vtt')][@kind='captions'][@label='Swedish'][@srclang='sv'][not(@default)]][descendant::track[contains(@src, 'pretty-good-en.vtt')][@kind='captions'][@label='English'][@srclang='en'][@default='true']][descendant::track[contains(@src, 'pretty-good-sv.vtt')][@kind='descriptions'][@label='Swedish'][@srclang='sv'][@default='true']][descendant::track[contains(@src, 'pretty-good-en.vtt')][@kind='descriptions'][@label='English'][@srclang='en'][not(@default)]][descendant::track[contains(@src, 'pretty-good-sv.vtt')][@kind='chapters'][@label='Swedish'][@srclang='sv'][not(@default)]][descendant::track[contains(@src, 'pretty-good-en.vtt')][@kind='chapters'][@label='English'][@srclang='en'][@default='true']][descendant::track[contains(@src, 'pretty-good-sv.vtt')][@kind='metadata'][@label='Swedish'][@srclang='sv'][@default='true']][descendant::track[contains(@src, 'pretty-good-en.vtt')][@kind='metadata'][@label='English'][@srclang='en'][not(@default)]]" "xpath_element" should exist - - @javascript @atto_media_audio - Scenario: Insert some media as a plain audio - Given I click on "Audio" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_audio .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.mp4" "link" - And I click on "Select this file" "button" - When I click on "Insert media" "button" - Then "//audio[descendant::source[contains(@src, 'moodle-logo.mp4')]]" "xpath_element" should exist - - @javascript @atto_media_audio - Scenario: Insert some media as an audio with display settings - Given I click on "Audio" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_audio .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.mp4" "link" - And I click on "Select this file" "button" - And I click on "Display options" "link" in the "#id_summary_editor_audio" "css_element" - And I set the field "audio_media-title-entry" to "AudioTitle" - When I click on "Insert media" "button" - Then "//audio[descendant::source[contains(@src, 'moodle-logo.mp4')]][@title='AudioTitle']" "xpath_element" should exist - - @javascript @atto_media_audio - Scenario: Insert some media as an audio with advanced settings - Given I click on "Audio" "link" - And I click on "Browse repositories..." "button" in the "#id_summary_editor_audio .atto_media_source.atto_media_media_source" "css_element" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.mp4" "link" - And I click on "Select this file" "button" - And I click on "Advanced settings" "link" in the "#id_summary_editor_audio" "css_element" - And the field "audio_media-controls-toggle" matches value "1" - And I set the field "audio_media-autoplay-toggle" to "1" - And I set the field "audio_media-mute-toggle" to "1" - And I set the field "audio_media-loop-toggle" to "1" - When I click on "Insert media" "button" - Then "//audio[descendant::source[contains(@src, 'moodle-logo.mp4')]][@controls='true'][@loop='true'][@autoplay='true'][@autoplay='true']" "xpath_element" should exist diff --git a/lib/editor/atto/plugins/media/version.php b/lib/editor/atto/plugins/media/version.php deleted file mode 100644 index 7f39576f56b..00000000000 --- a/lib/editor/atto/plugins/media/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_media - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_media'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-debug.js b/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-debug.js deleted file mode 100644 index 57af4cf3e72..00000000000 --- a/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-debug.js +++ /dev/null @@ -1,1066 +0,0 @@ -YUI.add('moodle-atto_media-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_media - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_media-button - */ - -/** - * Atto media selection tool. - * - * @namespace M.atto_media - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENTNAME = 'atto_media', - MEDIA_TYPES = {LINK: 'LINK', VIDEO: 'VIDEO', AUDIO: 'AUDIO'}, - TRACK_KINDS = { - SUBTITLES: 'SUBTITLES', - CAPTIONS: 'CAPTIONS', - DESCRIPTIONS: 'DESCRIPTIONS', - CHAPTERS: 'CHAPTERS', - METADATA: 'METADATA' - }, - CSS = { - SOURCE: 'atto_media_source', - TRACK: 'atto_media_track', - MEDIA_SOURCE: 'atto_media_media_source', - LINK_SOURCE: 'atto_media_link_source', - POSTER_SOURCE: 'atto_media_poster_source', - TRACK_SOURCE: 'atto_media_track_source', - DISPLAY_OPTIONS: 'atto_media_display_options', - NAME_INPUT: 'atto_media_name_entry', - TITLE_INPUT: 'atto_media_title_entry', - URL_INPUT: 'atto_media_url_entry', - POSTER_SIZE: 'atto_media_poster_size', - LINK_SIZE: 'atto_media_link_size', - WIDTH_INPUT: 'atto_media_width_entry', - HEIGHT_INPUT: 'atto_media_height_entry', - TRACK_KIND_INPUT: 'atto_media_track_kind_entry', - TRACK_LABEL_INPUT: 'atto_media_track_label_entry', - TRACK_LANG_INPUT: 'atto_media_track_lang_entry', - TRACK_DEFAULT_SELECT: 'atto_media_track_default', - MEDIA_CONTROLS_TOGGLE: 'atto_media_controls', - MEDIA_AUTOPLAY_TOGGLE: 'atto_media_autoplay', - MEDIA_MUTE_TOGGLE: 'atto_media_mute', - MEDIA_LOOP_TOGGLE: 'atto_media_loop', - ADVANCED_SETTINGS: 'atto_media_advancedsettings', - LINK: MEDIA_TYPES.LINK.toLowerCase(), - VIDEO: MEDIA_TYPES.VIDEO.toLowerCase(), - AUDIO: MEDIA_TYPES.AUDIO.toLowerCase(), - TRACK_SUBTITLES: TRACK_KINDS.SUBTITLES.toLowerCase(), - TRACK_CAPTIONS: TRACK_KINDS.CAPTIONS.toLowerCase(), - TRACK_DESCRIPTIONS: TRACK_KINDS.DESCRIPTIONS.toLowerCase(), - TRACK_CHAPTERS: TRACK_KINDS.CHAPTERS.toLowerCase(), - TRACK_METADATA: TRACK_KINDS.METADATA.toLowerCase() - }, - SELECTORS = { - SOURCE: '.' + CSS.SOURCE, - TRACK: '.' + CSS.TRACK, - MEDIA_SOURCE: '.' + CSS.MEDIA_SOURCE, - POSTER_SOURCE: '.' + CSS.POSTER_SOURCE, - TRACK_SOURCE: '.' + CSS.TRACK_SOURCE, - DISPLAY_OPTIONS: '.' + CSS.DISPLAY_OPTIONS, - NAME_INPUT: '.' + CSS.NAME_INPUT, - TITLE_INPUT: '.' + CSS.TITLE_INPUT, - URL_INPUT: '.' + CSS.URL_INPUT, - POSTER_SIZE: '.' + CSS.POSTER_SIZE, - LINK_SIZE: '.' + CSS.LINK_SIZE, - WIDTH_INPUT: '.' + CSS.WIDTH_INPUT, - HEIGHT_INPUT: '.' + CSS.HEIGHT_INPUT, - TRACK_KIND_INPUT: '.' + CSS.TRACK_KIND_INPUT, - TRACK_LABEL_INPUT: '.' + CSS.TRACK_LABEL_INPUT, - TRACK_LANG_INPUT: '.' + CSS.TRACK_LANG_INPUT, - TRACK_DEFAULT_SELECT: '.' + CSS.TRACK_DEFAULT_SELECT, - MEDIA_CONTROLS_TOGGLE: '.' + CSS.MEDIA_CONTROLS_TOGGLE, - MEDIA_AUTOPLAY_TOGGLE: '.' + CSS.MEDIA_AUTOPLAY_TOGGLE, - MEDIA_MUTE_TOGGLE: '.' + CSS.MEDIA_MUTE_TOGGLE, - MEDIA_LOOP_TOGGLE: '.' + CSS.MEDIA_LOOP_TOGGLE, - ADVANCED_SETTINGS: '.' + CSS.ADVANCED_SETTINGS, - LINK_TAB: 'li[data-medium-type="' + CSS.LINK + '"]', - LINK_PANE: '.tab-pane[data-medium-type="' + CSS.LINK + '"]', - VIDEO_TAB: 'li[data-medium-type="' + CSS.VIDEO + '"]', - VIDEO_PANE: '.tab-pane[data-medium-type="' + CSS.VIDEO + '"]', - AUDIO_TAB: 'li[data-medium-type="' + CSS.AUDIO + '"]', - AUDIO_PANE: '.tab-pane[data-medium-type="' + CSS.AUDIO + '"]', - TRACK_SUBTITLES_TAB: 'li[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]', - TRACK_SUBTITLES_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]', - TRACK_CAPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]', - TRACK_CAPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]', - TRACK_DESCRIPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]', - TRACK_DESCRIPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]', - TRACK_CHAPTERS_TAB: 'li[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]', - TRACK_CHAPTERS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]', - TRACK_METADATA_TAB: 'li[data-track-kind="' + CSS.TRACK_METADATA + '"]', - TRACK_METADATA_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_METADATA + '"]' - }, - TEMPLATES = { - ROOT: '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{> tab_panes.link}}' + - '
                          ' + - '
                          ' + - '{{> tab_panes.video}}' + - '
                          ' + - '
                          ' + - '{{> tab_panes.audio}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - TAB_PANES: { - LINK: '' + - '{{renderPartial "form_components.source" context=this id=CSS.LINK_SOURCE}}' + - '' + - '', - VIDEO: '' + - '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="videosourcelabel"' + - ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' + - '' + - '' + - '', - AUDIO: '' + - '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="audiosourcelabel"' + - ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' + - '' + - '' + - '' - }, - FORM_COMPONENTS: { - SOURCE: '' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{#multisource}}' + - '{{renderPartial "form_components.add_component" context=../this label=../addcomponentlabel ' + - ' help=../addsourcehelp}}' + - '{{/multisource}}' + - '
                          ', - ADD_COMPONENT: '' + - '', - REMOVE_COMPONENT: '' + - '', - DISPLAY_OPTIONS: '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{#mediatype_video}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - ' x ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{renderPartial "form_components.source" context=this id=CSS.POSTER_SOURCE entersourcelabel="poster"}}' + - '{{/mediatype_video}}' + - '
                          ', - ADVANCED_SETTINGS: '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ', - TRACK_TABS: '' + - '' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.subtitles}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="subtitlessourcelabel"' + - ' addcomponentlabel="addsubtitlestrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.captions}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="captionssourcelabel"' + - ' addcomponentlabel="addcaptionstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.descriptions}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="descriptionssourcelabel"' + - ' addcomponentlabel="adddescriptionstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.chapters}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="chapterssourcelabel"' + - ' addcomponentlabel="addchapterstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.metadata}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="metadatasourcelabel"' + - ' addcomponentlabel="addmetadatatrack"}}' + - '
                          ' + - '
                          ', - TRACK: '' + - '
                          ' + - '{{renderPartial "form_components.source" context=this id=CSS.TRACK_SOURCE entersourcelabel=sourcelabel}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{renderPartial "form_components.add_component" context=this label=addcomponentlabel}}' + - '
                          ', - SECTION: '' + - '' + - '' + - '{{#help}}{{{../help}}}{{/help}}' + - '' - }, - HTML_MEDIA: { - VIDEO: '' + - '  ', - AUDIO: '' + - '  ', - LINK: '' + - '{{#name}}{{../name}}{{/name}}{{^name}}{{../url}}{{/name}}' - } - }; - -Y.namespace('M.atto_media').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - if (this.get('host').canShowFilepicker('media')) { - this.editor.delegate('dblclick', this._displayDialogue, 'video', this); - this.editor.delegate('click', this._handleClick, 'video', this); - - // For some reason, clicking the video on Firefox does not trigger the click event, while in Chrome it does. - // We also need to handle the play/pause instead. - this._attachPlayPauseEvents(); - var changeHandler = this._attachPlayPauseEvents.bind(this); - this.get('host').on('change', changeHandler, null); - - this.addButton({ - icon: 'e/insert_edit_video', - callback: this._displayDialogue, - tags: 'video, audio', - tagMatchRequiresAll: false - }); - } - }, - - /** - * Attaches Play/Pause events to the video nodes. - * - * @private - */ - _attachPlayPauseEvents: function() { - if (this._handlePlayEndBound === undefined) { - this._handlePlayEndBound = this._handlePlayEnd.bind(this); - } - var videos = this.editor.getDOMNode().querySelectorAll('video'); - videos.forEach(function(video) { - // Prevent duplicated event listeners. - video.removeEventListener('play', this._handlePlayEndBound); - video.removeEventListener('pause', this._handlePlayEndBound); - // Add event listeners. - video.addEventListener('play', this._handlePlayEndBound); - video.addEventListener('pause', this._handlePlayEndBound); - }.bind(this)); - }, - - /** - * Gets the root context for all templates, with extra supplied context. - * - * @method _getContext - * @param {Object} extra The extra context to add - * @return {Object} - * @private - */ - _getContext: function(extra) { - return Y.merge({ - elementid: this.get('host').get('elementid'), - component: COMPONENTNAME, - langsinstalled: this.get('langs').installed, - langsavailable: this.get('langs').available, - helpStrings: this.get('help'), - CSS: CSS - }, extra); - }, - - /** - * Handles a click on a media element. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var medium = e.target; - - var selection = this.get('host').getSelectionFromNode(medium); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Handles a play/end on a media element. - * - * @method _handlePlayEnd - * @param {Event} e - * @private - */ - _handlePlayEnd: function(e) { - var medium = Y.one(e.target); - - var selection = this.get('host').getSelectionFromNode(medium); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - this.get('host')._hasSelectionChanged(e); - } - }, - - /** - * Display the media editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - if (this.get('host').getSelection() === false) { - return; - } - - if (!('renderPartial' in Y.Handlebars.helpers)) { - (function smashPartials(chain, obj) { - Y.each(obj, function(value, index) { - chain.push(index); - if (typeof value !== "object") { - Y.Handlebars.registerPartial(chain.join('.').toLowerCase(), value); - } else { - smashPartials(chain, value); - } - chain.pop(); - }); - })([], TEMPLATES); - - Y.Handlebars.registerHelper('renderPartial', function(partialName, options) { - if (!partialName) { - return ''; - } - - var partial = Y.Handlebars.partials[partialName]; - var parentContext = options.hash.context ? Y.clone(options.hash.context) : {}; - var context = Y.merge(parentContext, options.hash); - delete context.context; - - if (!partial) { - return ''; - } - return new Y.Handlebars.SafeString(Y.Handlebars.compile(partial)(context)); - }); - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createmedia', COMPONENTNAME), - focusAfterHide: true, - width: 660, - focusOnShowSelector: SELECTORS.URL_INPUT - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent(this.get('host').getSelection())).show(); - M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_media_form'}); - }, - - /** - * Returns the dialogue content for the tool. - * - * @method _getDialogueContent - * @param {WrappedRange[]} selection Current editor selection - * @return {Y.Node} - * @private - */ - _getDialogueContent: function(selection) { - var content = Y.Node.create( - Y.Handlebars.compile(TEMPLATES.ROOT)(this._getContext()) - ); - - var medium = this.get('host').getSelectedNodes().filter('video,audio').shift(); - var mediumProperties = medium ? this._getMediumProperties(medium) : false; - return this._attachEvents(this._applyMediumProperties(content, mediumProperties), selection); - }, - - /** - * Attaches required events to the content node. - * - * @method _attachEvents - * @param {Y.Node} content The content to which events will be attached - * @param {WrappedRange[]} selection Current editor selection - * @return {Y.Node} - * @private - */ - _attachEvents: function(content, selection) { - // Delegate add component link for media source fields. - content.delegate('click', function(e) { - e.preventDefault(); - this._addMediaSourceComponent(e.currentTarget); - }, SELECTORS.MEDIA_SOURCE + ' .addcomponent', this); - - // Delegate add component link for track fields. - content.delegate('click', function(e) { - e.preventDefault(); - this._addTrackComponent(e.currentTarget); - }, SELECTORS.TRACK + ' .addcomponent', this); - - // Only allow one track per tab to be selected as "default". - content.delegate('click', function(e) { - var element = e.currentTarget; - if (element.get('checked')) { - var getKind = function(el) { - return this._getTrackTypeFromTabPane(el.ancestor('.tab-pane')); - }.bind(this); - - element.ancestor('.root.tab-content').all(SELECTORS.TRACK_DEFAULT_SELECT).each(function(select) { - if (select !== element && getKind(element) === getKind(select)) { - select.set('checked', false); - } - }); - } - }, SELECTORS.TRACK_DEFAULT_SELECT, this); - - // Set up filepicker click event. - content.delegate('click', function(e) { - var element = e.currentTarget; - var fptype = (element.ancestor(SELECTORS.POSTER_SOURCE) && 'image') || - (element.ancestor(SELECTORS.TRACK_SOURCE) && 'subtitle') || - 'media'; - e.preventDefault(); - this.get('host').showFilepicker(fptype, this._getFilepickerCallback(element, fptype), this); - }, '.openmediabrowser', this); - - // This is a nasty hack. Basically we are using BS4 markup for the tabs - // but it isn't completely backwards compatible with BS2. The main problem is - // that the "active" class goes on a different node. So the idea is to put it - // the node for BS4, and then use CSS to make it look right in BS2. However, - // once another tab is clicked, everything sorts itself out, more or less. Except - // that the original "active" tab hasn't had the BS4 "active" class removed - // (so the styles will still apply to it). So we need to remove the "active" - // class on the BS4 node so that BS2 is happy. - // - // This doesn't upset BS4 since it removes this class anyway when clicking on - // another tab. - content.all('.nav-item').on('click', function(elem) { - elem.currentTarget.get('parentNode').all('.active').removeClass('active'); - }); - - content.one('.submit').on('click', function(e) { - e.preventDefault(); - var mediaHTML = this._getMediaHTML(e.currentTarget.ancestor('.atto_form')), - host = this.get('host'); - this.getDialogue({ - focusAfterHide: null - }).hide(); - if (mediaHTML) { - host.setSelection(selection); - host.insertContentAtFocusPoint(mediaHTML); - this.markUpdated(); - } - }, this); - - return content; - }, - - /** - * Applies medium properties to the content node. - * - * @method _applyMediumProperties - * @param {Y.Node} content The content to apply the properties to - * @param {object} properties The medium properties to apply - * @return {Y.Node} - * @private - */ - _applyMediumProperties: function(content, properties) { - if (!properties) { - return content; - } - - var applyTrackProperties = function(track, properties) { - track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.src); - track.one(SELECTORS.TRACK_LANG_INPUT).set('value', properties.srclang); - track.one(SELECTORS.TRACK_LABEL_INPUT).set('value', properties.label); - track.one(SELECTORS.TRACK_DEFAULT_SELECT).set('checked', properties.defaultTrack); - }; - - var tabPane = content.one('.root.tab-content > .tab-pane#' + this.get('host').get('elementid') + - '_' + properties.type.toLowerCase()); - - // Populate sources. - tabPane.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.sources[0]); - Y.Array.each(properties.sources.slice(1), function(source) { - this._addMediaSourceComponent(tabPane.one(SELECTORS.MEDIA_SOURCE + ' .addcomponent'), function(newComponent) { - newComponent.one(SELECTORS.URL_INPUT).set('value', source); - }); - }, this); - - // Populate tracks. - Y.Object.each(properties.tracks, function(value, key) { - var trackData = value.length ? value : [{src: '', srclang: '', label: '', defaultTrack: false}]; - var paneSelector = SELECTORS['TRACK_' + key.toUpperCase() + '_PANE']; - - applyTrackProperties(tabPane.one(paneSelector + ' ' + SELECTORS.TRACK), trackData[0]); - Y.Array.each(trackData.slice(1), function(track) { - this._addTrackComponent( - tabPane.one(paneSelector + ' ' + SELECTORS.TRACK + ' .addcomponent'), function(newComponent) { - applyTrackProperties(newComponent, track); - }); - }, this); - }, this); - - // Populate values. - tabPane.one(SELECTORS.TITLE_INPUT).set('value', properties.title); - tabPane.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).set('checked', properties.controls); - tabPane.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).set('checked', properties.autoplay); - tabPane.one(SELECTORS.MEDIA_MUTE_TOGGLE).set('checked', properties.muted); - tabPane.one(SELECTORS.MEDIA_LOOP_TOGGLE).set('checked', properties.loop); - - // Determine medium type. - var mediumType = this._getMediumTypeFromTabPane(tabPane); - - if (mediumType === 'video') { - // Populate values unique for video. - tabPane.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).setAttribute('value', properties.poster); - tabPane.one(SELECTORS.WIDTH_INPUT).set('value', properties.width); - tabPane.one(SELECTORS.HEIGHT_INPUT).set('value', properties.height); - } - - // Switch to the correct tab. - // Remove active class from all tabs + tab panes. - tabPane.siblings('.active').removeClass('active'); - content.all('.root.nav-tabs .nav-item a').removeClass('active'); - - // Add active class to the desired tab and tab pane. - tabPane.addClass('active'); - content.one(SELECTORS[mediumType.toUpperCase() + '_TAB'] + ' a').addClass('active'); - - return content; - }, - - /** - * Extracts medium properties. - * - * @method _getMediumProperties - * @param {Y.Node} medium The medium node from which to extract - * @return {Object} - * @private - */ - _getMediumProperties: function(medium) { - var boolAttr = function(elem, attr) { - // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes. - // So in order to check if attr="true", we need to check if the attribute exists and if the value is empty or true. - return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === '')); - }; - - var tracks = { - subtitles: [], - captions: [], - descriptions: [], - chapters: [], - metadata: [] - }; - - medium.all('track').each(function(track) { - tracks[track.getAttribute('kind')].push({ - src: track.getAttribute('src'), - srclang: track.getAttribute('srclang'), - label: track.getAttribute('label'), - defaultTrack: boolAttr(track, 'default') - }); - }); - - return { - type: medium.test('video') ? MEDIA_TYPES.VIDEO : MEDIA_TYPES.AUDIO, - sources: medium.all('source').get('src'), - poster: medium.getAttribute('poster'), - title: medium.getAttribute('title'), - width: medium.getAttribute('width'), - height: medium.getAttribute('height'), - autoplay: boolAttr(medium, 'autoplay'), - loop: boolAttr(medium, 'loop'), - muted: boolAttr(medium, 'muted'), - controls: boolAttr(medium, 'controls'), - tracks: tracks - }; - }, - - /** - * Adds a track form component. - * - * @method _addTrackComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addTrackComponent: function(element, callback) { - var trackType = this._getTrackTypeFromTabPane(element.ancestor('.tab-pane')); - var context = this._getContext({ - sourcelabel: trackType + 'sourcelabel', - addcomponentlabel: 'add' + trackType + 'track' - }); - - this._addComponent(element, TEMPLATES.FORM_COMPONENTS.TRACK, SELECTORS.TRACK, context, callback); - }, - - /** - * Adds a media source form component. - * - * @method _addMediaSourceComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addMediaSourceComponent: function(element, callback) { - var mediumType = this._getMediumTypeFromTabPane(element.ancestor('.tab-pane')); - var context = this._getContext({ - multisource: true, - id: CSS.MEDIA_SOURCE, - entersourcelabel: mediumType + 'sourcelabel', - addcomponentlabel: 'addsource', - addsourcehelp: this.get('help').addsource - }); - this._addComponent(element, TEMPLATES.FORM_COMPONENTS.SOURCE, SELECTORS.MEDIA_SOURCE, context, callback); - }, - - /** - * Adds an arbitrary form component. - * - * This function Compiles and adds the provided component in the supplied 'ancestor' container. - * It will also add links to add/remove the relevant components, attaching the - * necessary events. - * - * @method _addComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {String} component The component to compile and add - * @param {String} ancestor A selector used to find an ancestor of 'component', to which - * the compiled component will be appended - * @param {Object} context The context with which to render the component - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addComponent: function(element, component, ancestor, context, callback) { - var currentComponent = element.ancestor(ancestor), - newComponent = Y.Node.create(Y.Handlebars.compile(component)(context)), - removeNodeContext = this._getContext(context); - - removeNodeContext.label = "remove"; - var removeNode = Y.Node.create(Y.Handlebars.compile(TEMPLATES.FORM_COMPONENTS.REMOVE_COMPONENT)(removeNodeContext)); - - removeNode.one('.removecomponent').on('click', function(e) { - e.preventDefault(); - currentComponent.remove(true); - }); - - currentComponent.insert(newComponent, 'after'); - element.ancestor().insert(removeNode, 'after'); - element.ancestor().remove(true); - - if (callback) { - callback.call(this, newComponent); - } - }, - - /** - * Returns the callback for the file picker to call after a file has been selected. - * - * @method _getFilepickerCallback - * @param {Y.Node} element The element which triggered the callback - * @param {String} fptype The file pickertype (as would be passed to `showFilePicker`) - * @return {Function} The function to be used as a callback when the file picker returns the file - * @private - */ - _getFilepickerCallback: function(element, fptype) { - return function(params) { - if (params.url !== '') { - var tabPane = element.ancestor('.tab-pane'); - element.ancestor(SELECTORS.SOURCE).one(SELECTORS.URL_INPUT).set('value', params.url); - - // Links (and only links) have a name field. - if (tabPane.get('id') === this.get('host').get('elementid') + '_' + CSS.LINK) { - tabPane.one(SELECTORS.NAME_INPUT).set('value', params.file); - } - - if (fptype === 'subtitle') { - var subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0]; - var langObj = this.get('langs').available.reduce(function(carry, lang) { - return lang.code === subtitleLang ? lang : carry; - }, false); - if (langObj) { - element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LABEL_INPUT).set('value', - langObj.lang.substr(0, langObj.lang.lastIndexOf(' '))); - element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LANG_INPUT).set('value', langObj.code); - } - } - } - }; - }, - - /** - * Given a "medium" tab pane, returns what kind of medium it contains. - * - * @method _getMediumTypeFromTabPane - * @param {Y.Node} tabPane The tab pane - * @return {String} The type of medium in the pane - */ - _getMediumTypeFromTabPane: function(tabPane) { - return tabPane.getAttribute('data-medium-type'); - }, - - /** - * Given a "track" tab pane, returns what kind of track it contains. - * - * @method _getTrackTypeFromTabPane - * @param {Y.Node} tabPane The tab pane - * @return {String} The type of track in the pane - */ - _getTrackTypeFromTabPane: function(tabPane) { - return tabPane.getAttribute('data-track-kind'); - }, - - /** - * Returns the HTML to be inserted to the text area. - * - * @method _getMediaHTML - * @param {Y.Node} form The form from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTML: function(form) { - var mediumType = this._getMediumTypeFromTabPane(form.one('.root.tab-content > .tab-pane.active')); - var tabContent = form.one(SELECTORS[mediumType.toUpperCase() + '_PANE']); - - return this['_getMediaHTML' + mediumType[0].toUpperCase() + mediumType.substr(1)](tabContent); - }, - - /** - * Returns the HTML to be inserted to the text area for the link tab. - * - * @method _getMediaHTMLLink - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLLink: function(tab) { - var context = { - url: tab.one(SELECTORS.URL_INPUT).get('value'), - name: tab.one(SELECTORS.NAME_INPUT).get('value') || false - }; - - return context.url ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.LINK)(context) : ''; - }, - - /** - * Returns the HTML to be inserted to the text area for the video tab. - * - * @method _getMediaHTMLVideo - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLVideo: function(tab) { - var context = this._getContextForMediaHTML(tab); - context.width = tab.one(SELECTORS.WIDTH_INPUT).get('value') || false; - context.height = tab.one(SELECTORS.HEIGHT_INPUT).get('value') || false; - context.poster = tab.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false; - - return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.VIDEO)(context) : ''; - }, - - /** - * Returns the HTML to be inserted to the text area for the audio tab. - * - * @method _getMediaHTMLAudio - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLAudio: function(tab) { - var context = this._getContextForMediaHTML(tab); - - return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.AUDIO)(context) : ''; - }, - - /** - * Returns the context with which to render a media template. - * - * @method _getContextForMediaHTML - * @param {Y.Node} tab The tab from which to extract data - * @return {Object} - * @private - */ - _getContextForMediaHTML: function(tab) { - var tracks = []; - - tab.all(SELECTORS.TRACK).each(function(track) { - tracks.push({ - track: track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value'), - kind: this._getTrackTypeFromTabPane(track.ancestor('.tab-pane')), - label: track.one(SELECTORS.TRACK_LABEL_INPUT).get('value') || - track.one(SELECTORS.TRACK_LANG_INPUT).get('value'), - srclang: track.one(SELECTORS.TRACK_LANG_INPUT).get('value'), - defaultTrack: track.one(SELECTORS.TRACK_DEFAULT_SELECT).get('checked') ? "true" : null - }); - }, this); - - return { - sources: tab.all(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value').filter(function(source) { - return !!source; - }).map(function(source) { - return {source: source}; - }), - description: tab.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false, - tracks: tracks.filter(function(track) { - return !!track.track; - }), - showControls: tab.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).get('checked'), - autoplay: tab.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).get('checked'), - muted: tab.one(SELECTORS.MEDIA_MUTE_TOGGLE).get('checked'), - loop: tab.one(SELECTORS.MEDIA_LOOP_TOGGLE).get('checked'), - title: tab.one(SELECTORS.TITLE_INPUT).get('value') || false - }; - } -}, { - ATTRS: { - langs: {}, - help: {} - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-form-shortforms"]}); diff --git a/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-min.js b/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-min.js deleted file mode 100644 index 5be2c934569..00000000000 --- a/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button-min.js +++ /dev/null @@ -1,5 +0,0 @@ -YUI.add("moodle-atto_media-button",function(l,e){var t="atto_media",i={LINK:"LINK",VIDEO:"VIDEO",AUDIO:"AUDIO"},a={SUBTITLES:"SUBTITLES",CAPTIONS:"CAPTIONS",DESCRIPTIONS:"DESCRIPTIONS",CHAPTERS:"CHAPTERS",METADATA:"METADATA"},o={SOURCE:"atto_media_source",TRACK:"atto_media_track",MEDIA_SOURCE:"atto_media_media_source",LINK_SOURCE:"atto_media_link_source",POSTER_SOURCE:"atto_media_poster_source",TRACK_SOURCE:"atto_media_track_source",DISPLAY_OPTIONS:"atto_media_display_options",NAME_INPUT:"atto_media_name_entry",TITLE_INPUT:"atto_media_title_entry",URL_INPUT:"atto_media_url_entry",POSTER_SIZE:"atto_media_poster_size",LINK_SIZE:"atto_media_link_size",WIDTH_INPUT:"atto_media_width_entry",HEIGHT_INPUT:"atto_media_height_entry",TRACK_KIND_INPUT:"atto_media_track_kind_entry",TRACK_LABEL_INPUT:"atto_media_track_label_entry",TRACK_LANG_INPUT:"atto_media_track_lang_entry",TRACK_DEFAULT_SELECT:"atto_media_track_default",MEDIA_CONTROLS_TOGGLE:"atto_media_controls",MEDIA_AUTOPLAY_TOGGLE:"atto_media_autoplay",MEDIA_MUTE_TOGGLE:"atto_media_mute",MEDIA_LOOP_TOGGLE:"atto_media_loop",ADVANCED_SETTINGS:"atto_media_advancedsettings",LINK:i.LINK.toLowerCase(),VIDEO:i.VIDEO.toLowerCase(),AUDIO:i.AUDIO.toLowerCase(),TRACK_SUBTITLES:a.SUBTITLES.toLowerCase(),TRACK_CAPTIONS:a.CAPTIONS.toLowerCase(),TRACK_DESCRIPTIONS:a.DESCRIPTIONS.toLowerCase(),TRACK_CHAPTERS:a.CHAPTERS.toLowerCase(),TRACK_METADATA:a.METADATA.toLowerCase()},s={SOURCE:"."+o.SOURCE,TRACK:"."+o.TRACK,MEDIA_SOURCE:"."+o.MEDIA_SOURCE,POSTER_SOURCE:"."+o.POSTER_SOURCE,TRACK_SOURCE:"."+o.TRACK_SOURCE,DISPLAY_OPTIONS:"."+o.DISPLAY_OPTIONS,NAME_INPUT:"."+o.NAME_INPUT,TITLE_INPUT:"."+o.TITLE_INPUT,URL_INPUT:"."+o.URL_INPUT,POSTER_SIZE:"."+o.POSTER_SIZE,LINK_SIZE:"."+o.LINK_SIZE,WIDTH_INPUT:"."+o.WIDTH_INPUT,HEIGHT_INPUT:"."+o.HEIGHT_INPUT,TRACK_KIND_INPUT:"."+o.TRACK_KIND_INPUT,TRACK_LABEL_INPUT:"."+o.TRACK_LABEL_INPUT,TRACK_LANG_INPUT:"."+o.TRACK_LANG_INPUT,TRACK_DEFAULT_SELECT:"."+o.TRACK_DEFAULT_SELECT,MEDIA_CONTROLS_TOGGLE:"."+o.MEDIA_CONTROLS_TOGGLE,MEDIA_AUTOPLAY_TOGGLE:"."+o.MEDIA_AUTOPLAY_TOGGLE,MEDIA_MUTE_TOGGLE:"."+o.MEDIA_MUTE_TOGGLE,MEDIA_LOOP_TOGGLE:"."+o.MEDIA_LOOP_TOGGLE,ADVANCED_SETTINGS:"."+o.ADVANCED_SETTINGS,LINK_TAB:'li[data-medium-type="'+o.LINK+'"]',LINK_PANE:'.tab-pane[data-medium-type="'+o.LINK+'"]',VIDEO_TAB:'li[data-medium-type="'+o.VIDEO+'"]',VIDEO_PANE:'.tab-pane[data-medium-type="'+o.VIDEO+'"]',AUDIO_TAB:'li[data-medium-type="'+o.AUDIO+'"]',AUDIO_PANE:'.tab-pane[data-medium-type="'+o.AUDIO+'"]',TRACK_SUBTITLES_TAB:'li[data-track-kind="'+o.TRACK_SUBTITLES+'"]',TRACK_SUBTITLES_PANE:'.tab-pane[data-track-kind="'+o.TRACK_SUBTITLES+'"]',TRACK_CAPTIONS_TAB:'li[data-track-kind="'+o.TRACK_CAPTIONS+'"]',TRACK_CAPTIONS_PANE:'.tab-pane[data-track-kind="'+o.TRACK_CAPTIONS+'"]',TRACK_DESCRIPTIONS_TAB:'li[data-track-kind="'+o.TRACK_DESCRIPTIONS+'"]',TRACK_DESCRIPTIONS_PANE:'.tab-pane[data-track-kind="'+o.TRACK_DESCRIPTIONS+'"]',TRACK_CHAPTERS_TAB:'li[data-track-kind="'+o.TRACK_CHAPTERS+'"]',TRACK_CHAPTERS_PANE:'.tab-pane[data-track-kind="'+o.TRACK_CHAPTERS+'"]',TRACK_METADATA_TAB:'li[data-track-kind="'+o.TRACK_METADATA+'"]',TRACK_METADATA_PANE:'.tab-pane[data-track-kind="'+o.TRACK_METADATA+'"]'},d={ROOT:'
                          {{> tab_panes.link}}
                          {{> tab_panes.video}}
                          {{> tab_panes.audio}}

                          ',TAB_PANES:{LINK:'{{renderPartial "form_components.source" context=this id=CSS.LINK_SOURCE}}', -VIDEO:'{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="videosourcelabel" addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}',AUDIO:'{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="audiosourcelabel" addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}'},FORM_COMPONENTS:{SOURCE:'
                          {{#multisource}}{{renderPartial "form_components.add_component" context=../this label=../addcomponentlabel help=../addsourcehelp}}{{/multisource}}
                          ',ADD_COMPONENT:'',REMOVE_COMPONENT:'',DISPLAY_OPTIONS:'
                          {{#mediatype_video}}
                          x
                          {{renderPartial "form_components.source" context=this id=CSS.POSTER_SOURCE entersourcelabel="poster"}}{{/mediatype_video}}
                          ', -ADVANCED_SETTINGS:'
                          ',TRACK_TABS:'
                          {{{helpStrings.subtitles}}}
                          {{renderPartial "form_components.track" context=this sourcelabel="subtitlessourcelabel" addcomponentlabel="addsubtitlestrack"}}
                          {{{helpStrings.captions}}}
                          {{renderPartial "form_components.track" context=this sourcelabel="captionssourcelabel" addcomponentlabel="addcaptionstrack"}}
                          {{{helpStrings.descriptions}}}
                          {{renderPartial "form_components.track" context=this sourcelabel="descriptionssourcelabel" addcomponentlabel="adddescriptionstrack"}}
                          {{{helpStrings.chapters}}}
                          {{renderPartial "form_components.track" context=this sourcelabel="chapterssourcelabel" addcomponentlabel="addchapterstrack"}}
                          {{{helpStrings.metadata}}}
                          {{renderPartial "form_components.track" context=this sourcelabel="metadatasourcelabel" addcomponentlabel="addmetadatatrack"}}
                          ',TRACK:'
                          {{renderPartial "form_components.source" context=this id=CSS.TRACK_SOURCE entersourcelabel=sourcelabel}}
                          {{renderPartial "form_components.add_component" context=this label=addcomponentlabel}}
                          ',SECTION:'
                          {{#help}}{{{../help}}}{{/help}}
                          '},HTML_MEDIA:{ -VIDEO:'  ',AUDIO:'  ',LINK:'{{#name}}{{../name}}{{/name}}{{^name}}{{../url}}{{/name}}'}};l.namespace("M.atto_media").Button=l.Base.create("button",l.M.editor_atto.EditorPlugin,[],{initializer:function(){var e;this.get("host").canShowFilepicker("media")&&(this.editor.delegate("dblclick",this._displayDialogue,"video",this),this.editor.delegate("click",this._handleClick,"video",this),this._attachPlayPauseEvents(),e=this._attachPlayPauseEvents.bind(this),this.get("host").on("change",e,null),this.addButton({icon:"e/insert_edit_video",callback:this._displayDialogue,tags:"video, audio",tagMatchRequiresAll:!1}))},_attachPlayPauseEvents:function(){this._handlePlayEndBound===undefined&&(this._handlePlayEndBound=this._handlePlayEnd.bind(this)),this.editor.getDOMNode().querySelectorAll("video").forEach(function(e){e.removeEventListener("play",this._handlePlayEndBound),e.removeEventListener("pause",this._handlePlayEndBound),e.addEventListener("play",this._handlePlayEndBound),e.addEventListener("pause",this._handlePlayEndBound)}.bind(this))},_getContext:function(e){return l.merge({elementid:this.get("host").get("elementid"),component:t,langsinstalled:this.get("langs").installed,langsavailable:this.get("langs").available,helpStrings:this.get("help"),CSS:o},e)},_handleClick:function(e){e=e.target,e=this.get("host").getSelectionFromNode(e);this.get("host").getSelection()!==e&&this.get("host").setSelection(e)},_handlePlayEnd:function(e){var t=l.one(e.target),t=this.get("host").getSelectionFromNode(t);this.get("host").getSelection()!==t&&(this.get("host").setSelection(t),this.get("host")._hasSelectionChanged(e))},_displayDialogue:function(){!1!==this.get("host").getSelection()&&("renderPartial"in l.Handlebars.helpers||(function i(a,e){l.each(e,function(e,t){a.push(t),"object"!=typeof e?l.Handlebars.registerPartial(a.join(".").toLowerCase(),e):i(a,e),a.pop()})}([],d),l.Handlebars.registerHelper("renderPartial",function(e,t){var a;return e?(e=l.Handlebars.partials[e],a=t.hash.context?l.clone(t.hash.context):{},delete(a=l.merge(a,t.hash)).context,e?new l.Handlebars.SafeString(l.Handlebars.compile(e)(a)):""):""})),this.getDialogue({headerContent:M.util.get_string("createmedia",t),focusAfterHide:!0,width:660,focusOnShowSelector:s.URL_INPUT}).set("bodyContent",this._getDialogueContent(this.get("host").getSelection())).show(),M.form.shortforms({formid:this.get("host").get("elementid")+"_atto_media_form"}))},_getDialogueContent:function(e){var t=l.Node.create(l.Handlebars.compile(d.ROOT)(this._getContext())),a=this.get("host").getSelectedNodes().filter("video,audio").shift(),a=!!a&&this._getMediumProperties(a);return this._attachEvents(this._applyMediumProperties(t,a),e)},_attachEvents:function(e,a){return e.delegate("click",function(e){e.preventDefault(),this._addMediaSourceComponent(e.currentTarget)},s.MEDIA_SOURCE+" .addcomponent",this),e.delegate("click",function(e){e.preventDefault(),this._addTrackComponent(e.currentTarget)},s.TRACK+" .addcomponent",this),e.delegate("click",function(e){var t,a=e.currentTarget;a.get("checked")&&(t=function(e){return this._getTrackTypeFromTabPane(e.ancestor(".tab-pane"))}.bind(this),a.ancestor(".root.tab-content").all(s.TRACK_DEFAULT_SELECT).each(function(e){e!==a&&t(a)===t(e)&&e.set("checked",!1)}))},s.TRACK_DEFAULT_SELECT,this),e.delegate("click",function(e){var t=e.currentTarget,a=(t.ancestor(s.POSTER_SOURCE)?"image":t.ancestor(s.TRACK_SOURCE)&&"subtitle")||"media";e.preventDefault(),this.get("host").showFilepicker(a,this._getFilepickerCallback(t,a),this)},".openmediabrowser",this),e.all(".nav-item").on("click",function(e){e.currentTarget.get("parentNode").all(".active").removeClass("active")}),e.one(".submit").on("click",function(e){e.preventDefault();var e=this._getMediaHTML(e.currentTarget.ancestor(".atto_form")),t=this.get("host");this.getDialogue({focusAfterHide:null}).hide(),e&&(t.setSelection(a),t.insertContentAtFocusPoint(e),this.markUpdated())},this),e},_applyMediumProperties:function(e,t){var i,n,a;return t&&(i=function(e,t){e.one(s.TRACK_SOURCE+" "+s.URL_INPUT).set("value",t.src),e.one(s.TRACK_LANG_INPUT).set("value",t.srclang),e.one(s.TRACK_LABEL_INPUT).set("value",t.label),e.one(s.TRACK_DEFAULT_SELECT).set("checked",t.defaultTrack)},(n=e.one(".root.tab-content > .tab-pane#"+this.get("host").get("elementid")+"_"+t.type.toLowerCase())).one(s.MEDIA_SOURCE+" "+s.URL_INPUT).set("value",t.sources[0]),l.Array.each(t.sources.slice(1),function(t){this._addMediaSourceComponent(n.one(s.MEDIA_SOURCE+" .addcomponent"),function(e){e.one(s.URL_INPUT).set("value",t)})},this),l.Object.each(t.tracks,function(e,t){var e=e.length?e:[{src:"",srclang:"",label:"",defaultTrack:!1}],a=s["TRACK_"+t.toUpperCase()+"_PANE"];i(n.one(a+" "+s.TRACK),e[0]),l.Array.each(e.slice(1),function(t){this._addTrackComponent(n.one( -a+" "+s.TRACK+" .addcomponent"),function(e){i(e,t)})},this)},this),n.one(s.TITLE_INPUT).set("value",t.title),n.one(s.MEDIA_CONTROLS_TOGGLE).set("checked",t.controls),n.one(s.MEDIA_AUTOPLAY_TOGGLE).set("checked",t.autoplay),n.one(s.MEDIA_MUTE_TOGGLE).set("checked",t.muted),n.one(s.MEDIA_LOOP_TOGGLE).set("checked",t.loop),"video"===(a=this._getMediumTypeFromTabPane(n))&&(n.one(s.POSTER_SOURCE+" "+s.URL_INPUT).setAttribute("value",t.poster),n.one(s.WIDTH_INPUT).set("value",t.width),n.one(s.HEIGHT_INPUT).set("value",t.height)),n.siblings(".active").removeClass("active"),e.all(".root.nav-tabs .nav-item a").removeClass("active"),n.addClass("active"),e.one(s[a.toUpperCase()+"_TAB"]+" a").addClass("active")),e},_getMediumProperties:function(e){var t=function(e,t){return e.hasAttribute(t)&&(e.getAttribute(t)||""===e.getAttribute(t))},a={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]};return e.all("track").each(function(e){a[e.getAttribute("kind")].push({src:e.getAttribute("src"),srclang:e.getAttribute("srclang"),label:e.getAttribute("label"),defaultTrack:t(e,"default")})}),{type:e.test("video")?i.VIDEO:i.AUDIO,sources:e.all("source").get("src"),poster:e.getAttribute("poster"),title:e.getAttribute("title"),width:e.getAttribute("width"),height:e.getAttribute("height"),autoplay:t(e,"autoplay"),loop:t(e,"loop"),muted:t(e,"muted"),controls:t(e,"controls"),tracks:a}},_addTrackComponent:function(e,t){var a=this._getTrackTypeFromTabPane(e.ancestor(".tab-pane")),a=this._getContext({sourcelabel:a+"sourcelabel",addcomponentlabel:"add"+a+"track"});this._addComponent(e,d.FORM_COMPONENTS.TRACK,s.TRACK,a,t)},_addMediaSourceComponent:function(e,t){var a=this._getMediumTypeFromTabPane(e.ancestor(".tab-pane")),a=this._getContext({multisource:!0,id:o.MEDIA_SOURCE,entersourcelabel:a+"sourcelabel",addcomponentlabel:"addsource",addsourcehelp:this.get("help").addsource});this._addComponent(e,d.FORM_COMPONENTS.SOURCE,s.MEDIA_SOURCE,a,t)},_addComponent:function(e,t,a,i,n){var o=e.ancestor(a),a=l.Node.create(l.Handlebars.compile(t)(i)),t=this._getContext(i);t.label="remove",(i=l.Node.create(l.Handlebars.compile(d.FORM_COMPONENTS.REMOVE_COMPONENT)(t))).one(".removecomponent").on("click",function(e){e.preventDefault(),o.remove(!0)}),o.insert(a,"after"),e.ancestor().insert(i,"after"),e.ancestor().remove(!0),n&&n.call(this,a)},_getFilepickerCallback:function(i,n){return function(e){var a,t;""!==e.url&&(t=i.ancestor(".tab-pane"),i.ancestor(s.SOURCE).one(s.URL_INPUT).set("value",e.url),t.get("id")===this.get("host").get("elementid")+"_"+o.LINK&&t.one(s.NAME_INPUT).set("value",e.file),"subtitle"===n&&(a=e.file.split(".vtt")[0].split("-").slice(-1)[0],(t=this.get("langs").available.reduce(function(e,t){return t.code===a?t:e},!1))&&(i.ancestor(s.TRACK).one(s.TRACK_LABEL_INPUT).set("value",t.lang.substr(0,t.lang.lastIndexOf(" "))),i.ancestor(s.TRACK).one(s.TRACK_LANG_INPUT).set("value",t.code))))}},_getMediumTypeFromTabPane:function(e){return e.getAttribute("data-medium-type")},_getTrackTypeFromTabPane:function(e){return e.getAttribute("data-track-kind")},_getMediaHTML:function(e){var t=this._getMediumTypeFromTabPane(e.one(".root.tab-content > .tab-pane.active")),e=e.one(s[t.toUpperCase()+"_PANE"]);return this["_getMediaHTML"+t[0].toUpperCase()+t.substr(1)](e)},_getMediaHTMLLink:function(e){e={url:e.one(s.URL_INPUT).get("value"),name:e.one(s.NAME_INPUT).get("value")||!1};return e.url?l.Handlebars.compile(d.HTML_MEDIA.LINK)(e):""},_getMediaHTMLVideo:function(e){var t=this._getContextForMediaHTML(e);return t.width=e.one(s.WIDTH_INPUT).get("value")||!1,t.height=e.one(s.HEIGHT_INPUT).get("value")||!1,t.poster=e.one(s.POSTER_SOURCE+" "+s.URL_INPUT).get("value")||!1,t.sources.length?l.Handlebars.compile(d.HTML_MEDIA.VIDEO)(t):""},_getMediaHTMLAudio:function(e){e=this._getContextForMediaHTML(e);return e.sources.length?l.Handlebars.compile(d.HTML_MEDIA.AUDIO)(e):""},_getContextForMediaHTML:function(e){var t=[];return e.all(s.TRACK).each(function(e){t.push({track:e.one(s.TRACK_SOURCE+" "+s.URL_INPUT).get("value"),kind:this._getTrackTypeFromTabPane(e.ancestor(".tab-pane")),label:e.one(s.TRACK_LABEL_INPUT).get("value")||e.one(s.TRACK_LANG_INPUT).get("value"),srclang:e.one(s.TRACK_LANG_INPUT).get("value"),defaultTrack:e.one(s.TRACK_DEFAULT_SELECT).get("checked")?"true":null})},this),{sources:e.all(s.MEDIA_SOURCE+" "+s.URL_INPUT).get("value").filter(function(e){return!!e}).map(function(e){return{source:e}}),description:e.one(s.MEDIA_SOURCE+" "+s.URL_INPUT).get("value")||!1,tracks:t.filter(function(e){return!!e.track}),showControls:e.one(s.MEDIA_CONTROLS_TOGGLE).get("checked"),autoplay:e.one(s.MEDIA_AUTOPLAY_TOGGLE).get("checked"),muted:e.one(s.MEDIA_MUTE_TOGGLE).get("checked"),loop:e.one(s.MEDIA_LOOP_TOGGLE).get("checked"),title:e.one(s.TITLE_INPUT).get("value")||!1}}},{ATTRS:{langs:{},help:{}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-form-shortforms"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button.js b/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button.js deleted file mode 100644 index 57af4cf3e72..00000000000 --- a/lib/editor/atto/plugins/media/yui/build/moodle-atto_media-button/moodle-atto_media-button.js +++ /dev/null @@ -1,1066 +0,0 @@ -YUI.add('moodle-atto_media-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_media - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_media-button - */ - -/** - * Atto media selection tool. - * - * @namespace M.atto_media - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENTNAME = 'atto_media', - MEDIA_TYPES = {LINK: 'LINK', VIDEO: 'VIDEO', AUDIO: 'AUDIO'}, - TRACK_KINDS = { - SUBTITLES: 'SUBTITLES', - CAPTIONS: 'CAPTIONS', - DESCRIPTIONS: 'DESCRIPTIONS', - CHAPTERS: 'CHAPTERS', - METADATA: 'METADATA' - }, - CSS = { - SOURCE: 'atto_media_source', - TRACK: 'atto_media_track', - MEDIA_SOURCE: 'atto_media_media_source', - LINK_SOURCE: 'atto_media_link_source', - POSTER_SOURCE: 'atto_media_poster_source', - TRACK_SOURCE: 'atto_media_track_source', - DISPLAY_OPTIONS: 'atto_media_display_options', - NAME_INPUT: 'atto_media_name_entry', - TITLE_INPUT: 'atto_media_title_entry', - URL_INPUT: 'atto_media_url_entry', - POSTER_SIZE: 'atto_media_poster_size', - LINK_SIZE: 'atto_media_link_size', - WIDTH_INPUT: 'atto_media_width_entry', - HEIGHT_INPUT: 'atto_media_height_entry', - TRACK_KIND_INPUT: 'atto_media_track_kind_entry', - TRACK_LABEL_INPUT: 'atto_media_track_label_entry', - TRACK_LANG_INPUT: 'atto_media_track_lang_entry', - TRACK_DEFAULT_SELECT: 'atto_media_track_default', - MEDIA_CONTROLS_TOGGLE: 'atto_media_controls', - MEDIA_AUTOPLAY_TOGGLE: 'atto_media_autoplay', - MEDIA_MUTE_TOGGLE: 'atto_media_mute', - MEDIA_LOOP_TOGGLE: 'atto_media_loop', - ADVANCED_SETTINGS: 'atto_media_advancedsettings', - LINK: MEDIA_TYPES.LINK.toLowerCase(), - VIDEO: MEDIA_TYPES.VIDEO.toLowerCase(), - AUDIO: MEDIA_TYPES.AUDIO.toLowerCase(), - TRACK_SUBTITLES: TRACK_KINDS.SUBTITLES.toLowerCase(), - TRACK_CAPTIONS: TRACK_KINDS.CAPTIONS.toLowerCase(), - TRACK_DESCRIPTIONS: TRACK_KINDS.DESCRIPTIONS.toLowerCase(), - TRACK_CHAPTERS: TRACK_KINDS.CHAPTERS.toLowerCase(), - TRACK_METADATA: TRACK_KINDS.METADATA.toLowerCase() - }, - SELECTORS = { - SOURCE: '.' + CSS.SOURCE, - TRACK: '.' + CSS.TRACK, - MEDIA_SOURCE: '.' + CSS.MEDIA_SOURCE, - POSTER_SOURCE: '.' + CSS.POSTER_SOURCE, - TRACK_SOURCE: '.' + CSS.TRACK_SOURCE, - DISPLAY_OPTIONS: '.' + CSS.DISPLAY_OPTIONS, - NAME_INPUT: '.' + CSS.NAME_INPUT, - TITLE_INPUT: '.' + CSS.TITLE_INPUT, - URL_INPUT: '.' + CSS.URL_INPUT, - POSTER_SIZE: '.' + CSS.POSTER_SIZE, - LINK_SIZE: '.' + CSS.LINK_SIZE, - WIDTH_INPUT: '.' + CSS.WIDTH_INPUT, - HEIGHT_INPUT: '.' + CSS.HEIGHT_INPUT, - TRACK_KIND_INPUT: '.' + CSS.TRACK_KIND_INPUT, - TRACK_LABEL_INPUT: '.' + CSS.TRACK_LABEL_INPUT, - TRACK_LANG_INPUT: '.' + CSS.TRACK_LANG_INPUT, - TRACK_DEFAULT_SELECT: '.' + CSS.TRACK_DEFAULT_SELECT, - MEDIA_CONTROLS_TOGGLE: '.' + CSS.MEDIA_CONTROLS_TOGGLE, - MEDIA_AUTOPLAY_TOGGLE: '.' + CSS.MEDIA_AUTOPLAY_TOGGLE, - MEDIA_MUTE_TOGGLE: '.' + CSS.MEDIA_MUTE_TOGGLE, - MEDIA_LOOP_TOGGLE: '.' + CSS.MEDIA_LOOP_TOGGLE, - ADVANCED_SETTINGS: '.' + CSS.ADVANCED_SETTINGS, - LINK_TAB: 'li[data-medium-type="' + CSS.LINK + '"]', - LINK_PANE: '.tab-pane[data-medium-type="' + CSS.LINK + '"]', - VIDEO_TAB: 'li[data-medium-type="' + CSS.VIDEO + '"]', - VIDEO_PANE: '.tab-pane[data-medium-type="' + CSS.VIDEO + '"]', - AUDIO_TAB: 'li[data-medium-type="' + CSS.AUDIO + '"]', - AUDIO_PANE: '.tab-pane[data-medium-type="' + CSS.AUDIO + '"]', - TRACK_SUBTITLES_TAB: 'li[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]', - TRACK_SUBTITLES_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]', - TRACK_CAPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]', - TRACK_CAPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]', - TRACK_DESCRIPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]', - TRACK_DESCRIPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]', - TRACK_CHAPTERS_TAB: 'li[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]', - TRACK_CHAPTERS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]', - TRACK_METADATA_TAB: 'li[data-track-kind="' + CSS.TRACK_METADATA + '"]', - TRACK_METADATA_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_METADATA + '"]' - }, - TEMPLATES = { - ROOT: '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{> tab_panes.link}}' + - '
                          ' + - '
                          ' + - '{{> tab_panes.video}}' + - '
                          ' + - '
                          ' + - '{{> tab_panes.audio}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - TAB_PANES: { - LINK: '' + - '{{renderPartial "form_components.source" context=this id=CSS.LINK_SOURCE}}' + - '' + - '', - VIDEO: '' + - '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="videosourcelabel"' + - ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' + - '' + - '' + - '', - AUDIO: '' + - '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="audiosourcelabel"' + - ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' + - '' + - '' + - '' - }, - FORM_COMPONENTS: { - SOURCE: '' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{#multisource}}' + - '{{renderPartial "form_components.add_component" context=../this label=../addcomponentlabel ' + - ' help=../addsourcehelp}}' + - '{{/multisource}}' + - '
                          ', - ADD_COMPONENT: '' + - '', - REMOVE_COMPONENT: '' + - '', - DISPLAY_OPTIONS: '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{#mediatype_video}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - ' x ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{renderPartial "form_components.source" context=this id=CSS.POSTER_SOURCE entersourcelabel="poster"}}' + - '{{/mediatype_video}}' + - '
                          ', - ADVANCED_SETTINGS: '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ', - TRACK_TABS: '' + - '' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.subtitles}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="subtitlessourcelabel"' + - ' addcomponentlabel="addsubtitlestrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.captions}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="captionssourcelabel"' + - ' addcomponentlabel="addcaptionstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.descriptions}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="descriptionssourcelabel"' + - ' addcomponentlabel="adddescriptionstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.chapters}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="chapterssourcelabel"' + - ' addcomponentlabel="addchapterstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.metadata}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="metadatasourcelabel"' + - ' addcomponentlabel="addmetadatatrack"}}' + - '
                          ' + - '
                          ', - TRACK: '' + - '
                          ' + - '{{renderPartial "form_components.source" context=this id=CSS.TRACK_SOURCE entersourcelabel=sourcelabel}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{renderPartial "form_components.add_component" context=this label=addcomponentlabel}}' + - '
                          ', - SECTION: '' + - '' + - '' + - '{{#help}}{{{../help}}}{{/help}}' + - '' - }, - HTML_MEDIA: { - VIDEO: '' + - '  ', - AUDIO: '' + - '  ', - LINK: '' + - '{{#name}}{{../name}}{{/name}}{{^name}}{{../url}}{{/name}}' - } - }; - -Y.namespace('M.atto_media').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - if (this.get('host').canShowFilepicker('media')) { - this.editor.delegate('dblclick', this._displayDialogue, 'video', this); - this.editor.delegate('click', this._handleClick, 'video', this); - - // For some reason, clicking the video on Firefox does not trigger the click event, while in Chrome it does. - // We also need to handle the play/pause instead. - this._attachPlayPauseEvents(); - var changeHandler = this._attachPlayPauseEvents.bind(this); - this.get('host').on('change', changeHandler, null); - - this.addButton({ - icon: 'e/insert_edit_video', - callback: this._displayDialogue, - tags: 'video, audio', - tagMatchRequiresAll: false - }); - } - }, - - /** - * Attaches Play/Pause events to the video nodes. - * - * @private - */ - _attachPlayPauseEvents: function() { - if (this._handlePlayEndBound === undefined) { - this._handlePlayEndBound = this._handlePlayEnd.bind(this); - } - var videos = this.editor.getDOMNode().querySelectorAll('video'); - videos.forEach(function(video) { - // Prevent duplicated event listeners. - video.removeEventListener('play', this._handlePlayEndBound); - video.removeEventListener('pause', this._handlePlayEndBound); - // Add event listeners. - video.addEventListener('play', this._handlePlayEndBound); - video.addEventListener('pause', this._handlePlayEndBound); - }.bind(this)); - }, - - /** - * Gets the root context for all templates, with extra supplied context. - * - * @method _getContext - * @param {Object} extra The extra context to add - * @return {Object} - * @private - */ - _getContext: function(extra) { - return Y.merge({ - elementid: this.get('host').get('elementid'), - component: COMPONENTNAME, - langsinstalled: this.get('langs').installed, - langsavailable: this.get('langs').available, - helpStrings: this.get('help'), - CSS: CSS - }, extra); - }, - - /** - * Handles a click on a media element. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var medium = e.target; - - var selection = this.get('host').getSelectionFromNode(medium); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Handles a play/end on a media element. - * - * @method _handlePlayEnd - * @param {Event} e - * @private - */ - _handlePlayEnd: function(e) { - var medium = Y.one(e.target); - - var selection = this.get('host').getSelectionFromNode(medium); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - this.get('host')._hasSelectionChanged(e); - } - }, - - /** - * Display the media editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - if (this.get('host').getSelection() === false) { - return; - } - - if (!('renderPartial' in Y.Handlebars.helpers)) { - (function smashPartials(chain, obj) { - Y.each(obj, function(value, index) { - chain.push(index); - if (typeof value !== "object") { - Y.Handlebars.registerPartial(chain.join('.').toLowerCase(), value); - } else { - smashPartials(chain, value); - } - chain.pop(); - }); - })([], TEMPLATES); - - Y.Handlebars.registerHelper('renderPartial', function(partialName, options) { - if (!partialName) { - return ''; - } - - var partial = Y.Handlebars.partials[partialName]; - var parentContext = options.hash.context ? Y.clone(options.hash.context) : {}; - var context = Y.merge(parentContext, options.hash); - delete context.context; - - if (!partial) { - return ''; - } - return new Y.Handlebars.SafeString(Y.Handlebars.compile(partial)(context)); - }); - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createmedia', COMPONENTNAME), - focusAfterHide: true, - width: 660, - focusOnShowSelector: SELECTORS.URL_INPUT - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent(this.get('host').getSelection())).show(); - M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_media_form'}); - }, - - /** - * Returns the dialogue content for the tool. - * - * @method _getDialogueContent - * @param {WrappedRange[]} selection Current editor selection - * @return {Y.Node} - * @private - */ - _getDialogueContent: function(selection) { - var content = Y.Node.create( - Y.Handlebars.compile(TEMPLATES.ROOT)(this._getContext()) - ); - - var medium = this.get('host').getSelectedNodes().filter('video,audio').shift(); - var mediumProperties = medium ? this._getMediumProperties(medium) : false; - return this._attachEvents(this._applyMediumProperties(content, mediumProperties), selection); - }, - - /** - * Attaches required events to the content node. - * - * @method _attachEvents - * @param {Y.Node} content The content to which events will be attached - * @param {WrappedRange[]} selection Current editor selection - * @return {Y.Node} - * @private - */ - _attachEvents: function(content, selection) { - // Delegate add component link for media source fields. - content.delegate('click', function(e) { - e.preventDefault(); - this._addMediaSourceComponent(e.currentTarget); - }, SELECTORS.MEDIA_SOURCE + ' .addcomponent', this); - - // Delegate add component link for track fields. - content.delegate('click', function(e) { - e.preventDefault(); - this._addTrackComponent(e.currentTarget); - }, SELECTORS.TRACK + ' .addcomponent', this); - - // Only allow one track per tab to be selected as "default". - content.delegate('click', function(e) { - var element = e.currentTarget; - if (element.get('checked')) { - var getKind = function(el) { - return this._getTrackTypeFromTabPane(el.ancestor('.tab-pane')); - }.bind(this); - - element.ancestor('.root.tab-content').all(SELECTORS.TRACK_DEFAULT_SELECT).each(function(select) { - if (select !== element && getKind(element) === getKind(select)) { - select.set('checked', false); - } - }); - } - }, SELECTORS.TRACK_DEFAULT_SELECT, this); - - // Set up filepicker click event. - content.delegate('click', function(e) { - var element = e.currentTarget; - var fptype = (element.ancestor(SELECTORS.POSTER_SOURCE) && 'image') || - (element.ancestor(SELECTORS.TRACK_SOURCE) && 'subtitle') || - 'media'; - e.preventDefault(); - this.get('host').showFilepicker(fptype, this._getFilepickerCallback(element, fptype), this); - }, '.openmediabrowser', this); - - // This is a nasty hack. Basically we are using BS4 markup for the tabs - // but it isn't completely backwards compatible with BS2. The main problem is - // that the "active" class goes on a different node. So the idea is to put it - // the node for BS4, and then use CSS to make it look right in BS2. However, - // once another tab is clicked, everything sorts itself out, more or less. Except - // that the original "active" tab hasn't had the BS4 "active" class removed - // (so the styles will still apply to it). So we need to remove the "active" - // class on the BS4 node so that BS2 is happy. - // - // This doesn't upset BS4 since it removes this class anyway when clicking on - // another tab. - content.all('.nav-item').on('click', function(elem) { - elem.currentTarget.get('parentNode').all('.active').removeClass('active'); - }); - - content.one('.submit').on('click', function(e) { - e.preventDefault(); - var mediaHTML = this._getMediaHTML(e.currentTarget.ancestor('.atto_form')), - host = this.get('host'); - this.getDialogue({ - focusAfterHide: null - }).hide(); - if (mediaHTML) { - host.setSelection(selection); - host.insertContentAtFocusPoint(mediaHTML); - this.markUpdated(); - } - }, this); - - return content; - }, - - /** - * Applies medium properties to the content node. - * - * @method _applyMediumProperties - * @param {Y.Node} content The content to apply the properties to - * @param {object} properties The medium properties to apply - * @return {Y.Node} - * @private - */ - _applyMediumProperties: function(content, properties) { - if (!properties) { - return content; - } - - var applyTrackProperties = function(track, properties) { - track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.src); - track.one(SELECTORS.TRACK_LANG_INPUT).set('value', properties.srclang); - track.one(SELECTORS.TRACK_LABEL_INPUT).set('value', properties.label); - track.one(SELECTORS.TRACK_DEFAULT_SELECT).set('checked', properties.defaultTrack); - }; - - var tabPane = content.one('.root.tab-content > .tab-pane#' + this.get('host').get('elementid') + - '_' + properties.type.toLowerCase()); - - // Populate sources. - tabPane.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.sources[0]); - Y.Array.each(properties.sources.slice(1), function(source) { - this._addMediaSourceComponent(tabPane.one(SELECTORS.MEDIA_SOURCE + ' .addcomponent'), function(newComponent) { - newComponent.one(SELECTORS.URL_INPUT).set('value', source); - }); - }, this); - - // Populate tracks. - Y.Object.each(properties.tracks, function(value, key) { - var trackData = value.length ? value : [{src: '', srclang: '', label: '', defaultTrack: false}]; - var paneSelector = SELECTORS['TRACK_' + key.toUpperCase() + '_PANE']; - - applyTrackProperties(tabPane.one(paneSelector + ' ' + SELECTORS.TRACK), trackData[0]); - Y.Array.each(trackData.slice(1), function(track) { - this._addTrackComponent( - tabPane.one(paneSelector + ' ' + SELECTORS.TRACK + ' .addcomponent'), function(newComponent) { - applyTrackProperties(newComponent, track); - }); - }, this); - }, this); - - // Populate values. - tabPane.one(SELECTORS.TITLE_INPUT).set('value', properties.title); - tabPane.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).set('checked', properties.controls); - tabPane.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).set('checked', properties.autoplay); - tabPane.one(SELECTORS.MEDIA_MUTE_TOGGLE).set('checked', properties.muted); - tabPane.one(SELECTORS.MEDIA_LOOP_TOGGLE).set('checked', properties.loop); - - // Determine medium type. - var mediumType = this._getMediumTypeFromTabPane(tabPane); - - if (mediumType === 'video') { - // Populate values unique for video. - tabPane.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).setAttribute('value', properties.poster); - tabPane.one(SELECTORS.WIDTH_INPUT).set('value', properties.width); - tabPane.one(SELECTORS.HEIGHT_INPUT).set('value', properties.height); - } - - // Switch to the correct tab. - // Remove active class from all tabs + tab panes. - tabPane.siblings('.active').removeClass('active'); - content.all('.root.nav-tabs .nav-item a').removeClass('active'); - - // Add active class to the desired tab and tab pane. - tabPane.addClass('active'); - content.one(SELECTORS[mediumType.toUpperCase() + '_TAB'] + ' a').addClass('active'); - - return content; - }, - - /** - * Extracts medium properties. - * - * @method _getMediumProperties - * @param {Y.Node} medium The medium node from which to extract - * @return {Object} - * @private - */ - _getMediumProperties: function(medium) { - var boolAttr = function(elem, attr) { - // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes. - // So in order to check if attr="true", we need to check if the attribute exists and if the value is empty or true. - return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === '')); - }; - - var tracks = { - subtitles: [], - captions: [], - descriptions: [], - chapters: [], - metadata: [] - }; - - medium.all('track').each(function(track) { - tracks[track.getAttribute('kind')].push({ - src: track.getAttribute('src'), - srclang: track.getAttribute('srclang'), - label: track.getAttribute('label'), - defaultTrack: boolAttr(track, 'default') - }); - }); - - return { - type: medium.test('video') ? MEDIA_TYPES.VIDEO : MEDIA_TYPES.AUDIO, - sources: medium.all('source').get('src'), - poster: medium.getAttribute('poster'), - title: medium.getAttribute('title'), - width: medium.getAttribute('width'), - height: medium.getAttribute('height'), - autoplay: boolAttr(medium, 'autoplay'), - loop: boolAttr(medium, 'loop'), - muted: boolAttr(medium, 'muted'), - controls: boolAttr(medium, 'controls'), - tracks: tracks - }; - }, - - /** - * Adds a track form component. - * - * @method _addTrackComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addTrackComponent: function(element, callback) { - var trackType = this._getTrackTypeFromTabPane(element.ancestor('.tab-pane')); - var context = this._getContext({ - sourcelabel: trackType + 'sourcelabel', - addcomponentlabel: 'add' + trackType + 'track' - }); - - this._addComponent(element, TEMPLATES.FORM_COMPONENTS.TRACK, SELECTORS.TRACK, context, callback); - }, - - /** - * Adds a media source form component. - * - * @method _addMediaSourceComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addMediaSourceComponent: function(element, callback) { - var mediumType = this._getMediumTypeFromTabPane(element.ancestor('.tab-pane')); - var context = this._getContext({ - multisource: true, - id: CSS.MEDIA_SOURCE, - entersourcelabel: mediumType + 'sourcelabel', - addcomponentlabel: 'addsource', - addsourcehelp: this.get('help').addsource - }); - this._addComponent(element, TEMPLATES.FORM_COMPONENTS.SOURCE, SELECTORS.MEDIA_SOURCE, context, callback); - }, - - /** - * Adds an arbitrary form component. - * - * This function Compiles and adds the provided component in the supplied 'ancestor' container. - * It will also add links to add/remove the relevant components, attaching the - * necessary events. - * - * @method _addComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {String} component The component to compile and add - * @param {String} ancestor A selector used to find an ancestor of 'component', to which - * the compiled component will be appended - * @param {Object} context The context with which to render the component - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addComponent: function(element, component, ancestor, context, callback) { - var currentComponent = element.ancestor(ancestor), - newComponent = Y.Node.create(Y.Handlebars.compile(component)(context)), - removeNodeContext = this._getContext(context); - - removeNodeContext.label = "remove"; - var removeNode = Y.Node.create(Y.Handlebars.compile(TEMPLATES.FORM_COMPONENTS.REMOVE_COMPONENT)(removeNodeContext)); - - removeNode.one('.removecomponent').on('click', function(e) { - e.preventDefault(); - currentComponent.remove(true); - }); - - currentComponent.insert(newComponent, 'after'); - element.ancestor().insert(removeNode, 'after'); - element.ancestor().remove(true); - - if (callback) { - callback.call(this, newComponent); - } - }, - - /** - * Returns the callback for the file picker to call after a file has been selected. - * - * @method _getFilepickerCallback - * @param {Y.Node} element The element which triggered the callback - * @param {String} fptype The file pickertype (as would be passed to `showFilePicker`) - * @return {Function} The function to be used as a callback when the file picker returns the file - * @private - */ - _getFilepickerCallback: function(element, fptype) { - return function(params) { - if (params.url !== '') { - var tabPane = element.ancestor('.tab-pane'); - element.ancestor(SELECTORS.SOURCE).one(SELECTORS.URL_INPUT).set('value', params.url); - - // Links (and only links) have a name field. - if (tabPane.get('id') === this.get('host').get('elementid') + '_' + CSS.LINK) { - tabPane.one(SELECTORS.NAME_INPUT).set('value', params.file); - } - - if (fptype === 'subtitle') { - var subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0]; - var langObj = this.get('langs').available.reduce(function(carry, lang) { - return lang.code === subtitleLang ? lang : carry; - }, false); - if (langObj) { - element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LABEL_INPUT).set('value', - langObj.lang.substr(0, langObj.lang.lastIndexOf(' '))); - element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LANG_INPUT).set('value', langObj.code); - } - } - } - }; - }, - - /** - * Given a "medium" tab pane, returns what kind of medium it contains. - * - * @method _getMediumTypeFromTabPane - * @param {Y.Node} tabPane The tab pane - * @return {String} The type of medium in the pane - */ - _getMediumTypeFromTabPane: function(tabPane) { - return tabPane.getAttribute('data-medium-type'); - }, - - /** - * Given a "track" tab pane, returns what kind of track it contains. - * - * @method _getTrackTypeFromTabPane - * @param {Y.Node} tabPane The tab pane - * @return {String} The type of track in the pane - */ - _getTrackTypeFromTabPane: function(tabPane) { - return tabPane.getAttribute('data-track-kind'); - }, - - /** - * Returns the HTML to be inserted to the text area. - * - * @method _getMediaHTML - * @param {Y.Node} form The form from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTML: function(form) { - var mediumType = this._getMediumTypeFromTabPane(form.one('.root.tab-content > .tab-pane.active')); - var tabContent = form.one(SELECTORS[mediumType.toUpperCase() + '_PANE']); - - return this['_getMediaHTML' + mediumType[0].toUpperCase() + mediumType.substr(1)](tabContent); - }, - - /** - * Returns the HTML to be inserted to the text area for the link tab. - * - * @method _getMediaHTMLLink - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLLink: function(tab) { - var context = { - url: tab.one(SELECTORS.URL_INPUT).get('value'), - name: tab.one(SELECTORS.NAME_INPUT).get('value') || false - }; - - return context.url ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.LINK)(context) : ''; - }, - - /** - * Returns the HTML to be inserted to the text area for the video tab. - * - * @method _getMediaHTMLVideo - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLVideo: function(tab) { - var context = this._getContextForMediaHTML(tab); - context.width = tab.one(SELECTORS.WIDTH_INPUT).get('value') || false; - context.height = tab.one(SELECTORS.HEIGHT_INPUT).get('value') || false; - context.poster = tab.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false; - - return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.VIDEO)(context) : ''; - }, - - /** - * Returns the HTML to be inserted to the text area for the audio tab. - * - * @method _getMediaHTMLAudio - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLAudio: function(tab) { - var context = this._getContextForMediaHTML(tab); - - return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.AUDIO)(context) : ''; - }, - - /** - * Returns the context with which to render a media template. - * - * @method _getContextForMediaHTML - * @param {Y.Node} tab The tab from which to extract data - * @return {Object} - * @private - */ - _getContextForMediaHTML: function(tab) { - var tracks = []; - - tab.all(SELECTORS.TRACK).each(function(track) { - tracks.push({ - track: track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value'), - kind: this._getTrackTypeFromTabPane(track.ancestor('.tab-pane')), - label: track.one(SELECTORS.TRACK_LABEL_INPUT).get('value') || - track.one(SELECTORS.TRACK_LANG_INPUT).get('value'), - srclang: track.one(SELECTORS.TRACK_LANG_INPUT).get('value'), - defaultTrack: track.one(SELECTORS.TRACK_DEFAULT_SELECT).get('checked') ? "true" : null - }); - }, this); - - return { - sources: tab.all(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value').filter(function(source) { - return !!source; - }).map(function(source) { - return {source: source}; - }), - description: tab.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false, - tracks: tracks.filter(function(track) { - return !!track.track; - }), - showControls: tab.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).get('checked'), - autoplay: tab.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).get('checked'), - muted: tab.one(SELECTORS.MEDIA_MUTE_TOGGLE).get('checked'), - loop: tab.one(SELECTORS.MEDIA_LOOP_TOGGLE).get('checked'), - title: tab.one(SELECTORS.TITLE_INPUT).get('value') || false - }; - } -}, { - ATTRS: { - langs: {}, - help: {} - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-form-shortforms"]}); diff --git a/lib/editor/atto/plugins/media/yui/src/button/build.json b/lib/editor/atto/plugins/media/yui/src/button/build.json deleted file mode 100644 index b20a6f5c438..00000000000 --- a/lib/editor/atto/plugins/media/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_media-button", - "builds": { - "moodle-atto_media-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/media/yui/src/button/js/button.js b/lib/editor/atto/plugins/media/yui/src/button/js/button.js deleted file mode 100644 index 1d7efa22e15..00000000000 --- a/lib/editor/atto/plugins/media/yui/src/button/js/button.js +++ /dev/null @@ -1,1061 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_media - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_media-button - */ - -/** - * Atto media selection tool. - * - * @namespace M.atto_media - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENTNAME = 'atto_media', - MEDIA_TYPES = {LINK: 'LINK', VIDEO: 'VIDEO', AUDIO: 'AUDIO'}, - TRACK_KINDS = { - SUBTITLES: 'SUBTITLES', - CAPTIONS: 'CAPTIONS', - DESCRIPTIONS: 'DESCRIPTIONS', - CHAPTERS: 'CHAPTERS', - METADATA: 'METADATA' - }, - CSS = { - SOURCE: 'atto_media_source', - TRACK: 'atto_media_track', - MEDIA_SOURCE: 'atto_media_media_source', - LINK_SOURCE: 'atto_media_link_source', - POSTER_SOURCE: 'atto_media_poster_source', - TRACK_SOURCE: 'atto_media_track_source', - DISPLAY_OPTIONS: 'atto_media_display_options', - NAME_INPUT: 'atto_media_name_entry', - TITLE_INPUT: 'atto_media_title_entry', - URL_INPUT: 'atto_media_url_entry', - POSTER_SIZE: 'atto_media_poster_size', - LINK_SIZE: 'atto_media_link_size', - WIDTH_INPUT: 'atto_media_width_entry', - HEIGHT_INPUT: 'atto_media_height_entry', - TRACK_KIND_INPUT: 'atto_media_track_kind_entry', - TRACK_LABEL_INPUT: 'atto_media_track_label_entry', - TRACK_LANG_INPUT: 'atto_media_track_lang_entry', - TRACK_DEFAULT_SELECT: 'atto_media_track_default', - MEDIA_CONTROLS_TOGGLE: 'atto_media_controls', - MEDIA_AUTOPLAY_TOGGLE: 'atto_media_autoplay', - MEDIA_MUTE_TOGGLE: 'atto_media_mute', - MEDIA_LOOP_TOGGLE: 'atto_media_loop', - ADVANCED_SETTINGS: 'atto_media_advancedsettings', - LINK: MEDIA_TYPES.LINK.toLowerCase(), - VIDEO: MEDIA_TYPES.VIDEO.toLowerCase(), - AUDIO: MEDIA_TYPES.AUDIO.toLowerCase(), - TRACK_SUBTITLES: TRACK_KINDS.SUBTITLES.toLowerCase(), - TRACK_CAPTIONS: TRACK_KINDS.CAPTIONS.toLowerCase(), - TRACK_DESCRIPTIONS: TRACK_KINDS.DESCRIPTIONS.toLowerCase(), - TRACK_CHAPTERS: TRACK_KINDS.CHAPTERS.toLowerCase(), - TRACK_METADATA: TRACK_KINDS.METADATA.toLowerCase() - }, - SELECTORS = { - SOURCE: '.' + CSS.SOURCE, - TRACK: '.' + CSS.TRACK, - MEDIA_SOURCE: '.' + CSS.MEDIA_SOURCE, - POSTER_SOURCE: '.' + CSS.POSTER_SOURCE, - TRACK_SOURCE: '.' + CSS.TRACK_SOURCE, - DISPLAY_OPTIONS: '.' + CSS.DISPLAY_OPTIONS, - NAME_INPUT: '.' + CSS.NAME_INPUT, - TITLE_INPUT: '.' + CSS.TITLE_INPUT, - URL_INPUT: '.' + CSS.URL_INPUT, - POSTER_SIZE: '.' + CSS.POSTER_SIZE, - LINK_SIZE: '.' + CSS.LINK_SIZE, - WIDTH_INPUT: '.' + CSS.WIDTH_INPUT, - HEIGHT_INPUT: '.' + CSS.HEIGHT_INPUT, - TRACK_KIND_INPUT: '.' + CSS.TRACK_KIND_INPUT, - TRACK_LABEL_INPUT: '.' + CSS.TRACK_LABEL_INPUT, - TRACK_LANG_INPUT: '.' + CSS.TRACK_LANG_INPUT, - TRACK_DEFAULT_SELECT: '.' + CSS.TRACK_DEFAULT_SELECT, - MEDIA_CONTROLS_TOGGLE: '.' + CSS.MEDIA_CONTROLS_TOGGLE, - MEDIA_AUTOPLAY_TOGGLE: '.' + CSS.MEDIA_AUTOPLAY_TOGGLE, - MEDIA_MUTE_TOGGLE: '.' + CSS.MEDIA_MUTE_TOGGLE, - MEDIA_LOOP_TOGGLE: '.' + CSS.MEDIA_LOOP_TOGGLE, - ADVANCED_SETTINGS: '.' + CSS.ADVANCED_SETTINGS, - LINK_TAB: 'li[data-medium-type="' + CSS.LINK + '"]', - LINK_PANE: '.tab-pane[data-medium-type="' + CSS.LINK + '"]', - VIDEO_TAB: 'li[data-medium-type="' + CSS.VIDEO + '"]', - VIDEO_PANE: '.tab-pane[data-medium-type="' + CSS.VIDEO + '"]', - AUDIO_TAB: 'li[data-medium-type="' + CSS.AUDIO + '"]', - AUDIO_PANE: '.tab-pane[data-medium-type="' + CSS.AUDIO + '"]', - TRACK_SUBTITLES_TAB: 'li[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]', - TRACK_SUBTITLES_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]', - TRACK_CAPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]', - TRACK_CAPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]', - TRACK_DESCRIPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]', - TRACK_DESCRIPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]', - TRACK_CHAPTERS_TAB: 'li[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]', - TRACK_CHAPTERS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]', - TRACK_METADATA_TAB: 'li[data-track-kind="' + CSS.TRACK_METADATA + '"]', - TRACK_METADATA_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_METADATA + '"]' - }, - TEMPLATES = { - ROOT: '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{> tab_panes.link}}' + - '
                          ' + - '
                          ' + - '{{> tab_panes.video}}' + - '
                          ' + - '
                          ' + - '{{> tab_panes.audio}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ', - TAB_PANES: { - LINK: '' + - '{{renderPartial "form_components.source" context=this id=CSS.LINK_SOURCE}}' + - '' + - '', - VIDEO: '' + - '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="videosourcelabel"' + - ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' + - '' + - '' + - '', - AUDIO: '' + - '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="audiosourcelabel"' + - ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' + - '' + - '' + - '' - }, - FORM_COMPONENTS: { - SOURCE: '' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{#multisource}}' + - '{{renderPartial "form_components.add_component" context=../this label=../addcomponentlabel ' + - ' help=../addsourcehelp}}' + - '{{/multisource}}' + - '
                          ', - ADD_COMPONENT: '' + - '', - REMOVE_COMPONENT: '' + - '', - DISPLAY_OPTIONS: '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '{{#mediatype_video}}' + - '
                          ' + - '' + - '
                          ' + - '' + - '' + - ' x ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{renderPartial "form_components.source" context=this id=CSS.POSTER_SOURCE entersourcelabel="poster"}}' + - '{{/mediatype_video}}' + - '
                          ', - ADVANCED_SETTINGS: '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ', - TRACK_TABS: '' + - '' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.subtitles}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="subtitlessourcelabel"' + - ' addcomponentlabel="addsubtitlestrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.captions}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="captionssourcelabel"' + - ' addcomponentlabel="addcaptionstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.descriptions}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="descriptionssourcelabel"' + - ' addcomponentlabel="adddescriptionstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.chapters}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="chapterssourcelabel"' + - ' addcomponentlabel="addchapterstrack"}}' + - '
                          ' + - '
                          ' + - '
                          {{{helpStrings.metadata}}}
                          ' + - '{{renderPartial "form_components.track" context=this sourcelabel="metadatasourcelabel"' + - ' addcomponentlabel="addmetadatatrack"}}' + - '
                          ' + - '
                          ', - TRACK: '' + - '
                          ' + - '{{renderPartial "form_components.source" context=this id=CSS.TRACK_SOURCE entersourcelabel=sourcelabel}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{renderPartial "form_components.add_component" context=this label=addcomponentlabel}}' + - '
                          ', - SECTION: '' + - '' + - '' + - '{{#help}}{{{../help}}}{{/help}}' + - '' - }, - HTML_MEDIA: { - VIDEO: '' + - '  ', - AUDIO: '' + - '  ', - LINK: '' + - '{{#name}}{{../name}}{{/name}}{{^name}}{{../url}}{{/name}}' - } - }; - -Y.namespace('M.atto_media').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - initializer: function() { - if (this.get('host').canShowFilepicker('media')) { - this.editor.delegate('dblclick', this._displayDialogue, 'video', this); - this.editor.delegate('click', this._handleClick, 'video', this); - - // For some reason, clicking the video on Firefox does not trigger the click event, while in Chrome it does. - // We also need to handle the play/pause instead. - this._attachPlayPauseEvents(); - var changeHandler = this._attachPlayPauseEvents.bind(this); - this.get('host').on('change', changeHandler, null); - - this.addButton({ - icon: 'e/insert_edit_video', - callback: this._displayDialogue, - tags: 'video, audio', - tagMatchRequiresAll: false - }); - } - }, - - /** - * Attaches Play/Pause events to the video nodes. - * - * @private - */ - _attachPlayPauseEvents: function() { - if (this._handlePlayEndBound === undefined) { - this._handlePlayEndBound = this._handlePlayEnd.bind(this); - } - var videos = this.editor.getDOMNode().querySelectorAll('video'); - videos.forEach(function(video) { - // Prevent duplicated event listeners. - video.removeEventListener('play', this._handlePlayEndBound); - video.removeEventListener('pause', this._handlePlayEndBound); - // Add event listeners. - video.addEventListener('play', this._handlePlayEndBound); - video.addEventListener('pause', this._handlePlayEndBound); - }.bind(this)); - }, - - /** - * Gets the root context for all templates, with extra supplied context. - * - * @method _getContext - * @param {Object} extra The extra context to add - * @return {Object} - * @private - */ - _getContext: function(extra) { - return Y.merge({ - elementid: this.get('host').get('elementid'), - component: COMPONENTNAME, - langsinstalled: this.get('langs').installed, - langsavailable: this.get('langs').available, - helpStrings: this.get('help'), - CSS: CSS - }, extra); - }, - - /** - * Handles a click on a media element. - * - * @method _handleClick - * @param {EventFacade} e - * @private - */ - _handleClick: function(e) { - var medium = e.target; - - var selection = this.get('host').getSelectionFromNode(medium); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - } - }, - - /** - * Handles a play/end on a media element. - * - * @method _handlePlayEnd - * @param {Event} e - * @private - */ - _handlePlayEnd: function(e) { - var medium = Y.one(e.target); - - var selection = this.get('host').getSelectionFromNode(medium); - if (this.get('host').getSelection() !== selection) { - this.get('host').setSelection(selection); - this.get('host')._hasSelectionChanged(e); - } - }, - - /** - * Display the media editing tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - if (this.get('host').getSelection() === false) { - return; - } - - if (!('renderPartial' in Y.Handlebars.helpers)) { - (function smashPartials(chain, obj) { - Y.each(obj, function(value, index) { - chain.push(index); - if (typeof value !== "object") { - Y.Handlebars.registerPartial(chain.join('.').toLowerCase(), value); - } else { - smashPartials(chain, value); - } - chain.pop(); - }); - })([], TEMPLATES); - - Y.Handlebars.registerHelper('renderPartial', function(partialName, options) { - if (!partialName) { - return ''; - } - - var partial = Y.Handlebars.partials[partialName]; - var parentContext = options.hash.context ? Y.clone(options.hash.context) : {}; - var context = Y.merge(parentContext, options.hash); - delete context.context; - - if (!partial) { - return ''; - } - return new Y.Handlebars.SafeString(Y.Handlebars.compile(partial)(context)); - }); - } - - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createmedia', COMPONENTNAME), - focusAfterHide: true, - width: 660, - focusOnShowSelector: SELECTORS.URL_INPUT - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent(this.get('host').getSelection())).show(); - M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_media_form'}); - }, - - /** - * Returns the dialogue content for the tool. - * - * @method _getDialogueContent - * @param {WrappedRange[]} selection Current editor selection - * @return {Y.Node} - * @private - */ - _getDialogueContent: function(selection) { - var content = Y.Node.create( - Y.Handlebars.compile(TEMPLATES.ROOT)(this._getContext()) - ); - - var medium = this.get('host').getSelectedNodes().filter('video,audio').shift(); - var mediumProperties = medium ? this._getMediumProperties(medium) : false; - return this._attachEvents(this._applyMediumProperties(content, mediumProperties), selection); - }, - - /** - * Attaches required events to the content node. - * - * @method _attachEvents - * @param {Y.Node} content The content to which events will be attached - * @param {WrappedRange[]} selection Current editor selection - * @return {Y.Node} - * @private - */ - _attachEvents: function(content, selection) { - // Delegate add component link for media source fields. - content.delegate('click', function(e) { - e.preventDefault(); - this._addMediaSourceComponent(e.currentTarget); - }, SELECTORS.MEDIA_SOURCE + ' .addcomponent', this); - - // Delegate add component link for track fields. - content.delegate('click', function(e) { - e.preventDefault(); - this._addTrackComponent(e.currentTarget); - }, SELECTORS.TRACK + ' .addcomponent', this); - - // Only allow one track per tab to be selected as "default". - content.delegate('click', function(e) { - var element = e.currentTarget; - if (element.get('checked')) { - var getKind = function(el) { - return this._getTrackTypeFromTabPane(el.ancestor('.tab-pane')); - }.bind(this); - - element.ancestor('.root.tab-content').all(SELECTORS.TRACK_DEFAULT_SELECT).each(function(select) { - if (select !== element && getKind(element) === getKind(select)) { - select.set('checked', false); - } - }); - } - }, SELECTORS.TRACK_DEFAULT_SELECT, this); - - // Set up filepicker click event. - content.delegate('click', function(e) { - var element = e.currentTarget; - var fptype = (element.ancestor(SELECTORS.POSTER_SOURCE) && 'image') || - (element.ancestor(SELECTORS.TRACK_SOURCE) && 'subtitle') || - 'media'; - e.preventDefault(); - this.get('host').showFilepicker(fptype, this._getFilepickerCallback(element, fptype), this); - }, '.openmediabrowser', this); - - // This is a nasty hack. Basically we are using BS4 markup for the tabs - // but it isn't completely backwards compatible with BS2. The main problem is - // that the "active" class goes on a different node. So the idea is to put it - // the node for BS4, and then use CSS to make it look right in BS2. However, - // once another tab is clicked, everything sorts itself out, more or less. Except - // that the original "active" tab hasn't had the BS4 "active" class removed - // (so the styles will still apply to it). So we need to remove the "active" - // class on the BS4 node so that BS2 is happy. - // - // This doesn't upset BS4 since it removes this class anyway when clicking on - // another tab. - content.all('.nav-item').on('click', function(elem) { - elem.currentTarget.get('parentNode').all('.active').removeClass('active'); - }); - - content.one('.submit').on('click', function(e) { - e.preventDefault(); - var mediaHTML = this._getMediaHTML(e.currentTarget.ancestor('.atto_form')), - host = this.get('host'); - this.getDialogue({ - focusAfterHide: null - }).hide(); - if (mediaHTML) { - host.setSelection(selection); - host.insertContentAtFocusPoint(mediaHTML); - this.markUpdated(); - } - }, this); - - return content; - }, - - /** - * Applies medium properties to the content node. - * - * @method _applyMediumProperties - * @param {Y.Node} content The content to apply the properties to - * @param {object} properties The medium properties to apply - * @return {Y.Node} - * @private - */ - _applyMediumProperties: function(content, properties) { - if (!properties) { - return content; - } - - var applyTrackProperties = function(track, properties) { - track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.src); - track.one(SELECTORS.TRACK_LANG_INPUT).set('value', properties.srclang); - track.one(SELECTORS.TRACK_LABEL_INPUT).set('value', properties.label); - track.one(SELECTORS.TRACK_DEFAULT_SELECT).set('checked', properties.defaultTrack); - }; - - var tabPane = content.one('.root.tab-content > .tab-pane#' + this.get('host').get('elementid') + - '_' + properties.type.toLowerCase()); - - // Populate sources. - tabPane.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.sources[0]); - Y.Array.each(properties.sources.slice(1), function(source) { - this._addMediaSourceComponent(tabPane.one(SELECTORS.MEDIA_SOURCE + ' .addcomponent'), function(newComponent) { - newComponent.one(SELECTORS.URL_INPUT).set('value', source); - }); - }, this); - - // Populate tracks. - Y.Object.each(properties.tracks, function(value, key) { - var trackData = value.length ? value : [{src: '', srclang: '', label: '', defaultTrack: false}]; - var paneSelector = SELECTORS['TRACK_' + key.toUpperCase() + '_PANE']; - - applyTrackProperties(tabPane.one(paneSelector + ' ' + SELECTORS.TRACK), trackData[0]); - Y.Array.each(trackData.slice(1), function(track) { - this._addTrackComponent( - tabPane.one(paneSelector + ' ' + SELECTORS.TRACK + ' .addcomponent'), function(newComponent) { - applyTrackProperties(newComponent, track); - }); - }, this); - }, this); - - // Populate values. - tabPane.one(SELECTORS.TITLE_INPUT).set('value', properties.title); - tabPane.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).set('checked', properties.controls); - tabPane.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).set('checked', properties.autoplay); - tabPane.one(SELECTORS.MEDIA_MUTE_TOGGLE).set('checked', properties.muted); - tabPane.one(SELECTORS.MEDIA_LOOP_TOGGLE).set('checked', properties.loop); - - // Determine medium type. - var mediumType = this._getMediumTypeFromTabPane(tabPane); - - if (mediumType === 'video') { - // Populate values unique for video. - tabPane.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).setAttribute('value', properties.poster); - tabPane.one(SELECTORS.WIDTH_INPUT).set('value', properties.width); - tabPane.one(SELECTORS.HEIGHT_INPUT).set('value', properties.height); - } - - // Switch to the correct tab. - // Remove active class from all tabs + tab panes. - tabPane.siblings('.active').removeClass('active'); - content.all('.root.nav-tabs .nav-item a').removeClass('active'); - - // Add active class to the desired tab and tab pane. - tabPane.addClass('active'); - content.one(SELECTORS[mediumType.toUpperCase() + '_TAB'] + ' a').addClass('active'); - - return content; - }, - - /** - * Extracts medium properties. - * - * @method _getMediumProperties - * @param {Y.Node} medium The medium node from which to extract - * @return {Object} - * @private - */ - _getMediumProperties: function(medium) { - var boolAttr = function(elem, attr) { - // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes. - // So in order to check if attr="true", we need to check if the attribute exists and if the value is empty or true. - return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === '')); - }; - - var tracks = { - subtitles: [], - captions: [], - descriptions: [], - chapters: [], - metadata: [] - }; - - medium.all('track').each(function(track) { - tracks[track.getAttribute('kind')].push({ - src: track.getAttribute('src'), - srclang: track.getAttribute('srclang'), - label: track.getAttribute('label'), - defaultTrack: boolAttr(track, 'default') - }); - }); - - return { - type: medium.test('video') ? MEDIA_TYPES.VIDEO : MEDIA_TYPES.AUDIO, - sources: medium.all('source').get('src'), - poster: medium.getAttribute('poster'), - title: medium.getAttribute('title'), - width: medium.getAttribute('width'), - height: medium.getAttribute('height'), - autoplay: boolAttr(medium, 'autoplay'), - loop: boolAttr(medium, 'loop'), - muted: boolAttr(medium, 'muted'), - controls: boolAttr(medium, 'controls'), - tracks: tracks - }; - }, - - /** - * Adds a track form component. - * - * @method _addTrackComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addTrackComponent: function(element, callback) { - var trackType = this._getTrackTypeFromTabPane(element.ancestor('.tab-pane')); - var context = this._getContext({ - sourcelabel: trackType + 'sourcelabel', - addcomponentlabel: 'add' + trackType + 'track' - }); - - this._addComponent(element, TEMPLATES.FORM_COMPONENTS.TRACK, SELECTORS.TRACK, context, callback); - }, - - /** - * Adds a media source form component. - * - * @method _addMediaSourceComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addMediaSourceComponent: function(element, callback) { - var mediumType = this._getMediumTypeFromTabPane(element.ancestor('.tab-pane')); - var context = this._getContext({ - multisource: true, - id: CSS.MEDIA_SOURCE, - entersourcelabel: mediumType + 'sourcelabel', - addcomponentlabel: 'addsource', - addsourcehelp: this.get('help').addsource - }); - this._addComponent(element, TEMPLATES.FORM_COMPONENTS.SOURCE, SELECTORS.MEDIA_SOURCE, context, callback); - }, - - /** - * Adds an arbitrary form component. - * - * This function Compiles and adds the provided component in the supplied 'ancestor' container. - * It will also add links to add/remove the relevant components, attaching the - * necessary events. - * - * @method _addComponent - * @param {Y.Node} element The element which was used to trigger this function - * @param {String} component The component to compile and add - * @param {String} ancestor A selector used to find an ancestor of 'component', to which - * the compiled component will be appended - * @param {Object} context The context with which to render the component - * @param {Function} [callback] Function to be called when the new component is added - * @param {Y.Node} callback.newComponent The compiled component - * @private - */ - _addComponent: function(element, component, ancestor, context, callback) { - var currentComponent = element.ancestor(ancestor), - newComponent = Y.Node.create(Y.Handlebars.compile(component)(context)), - removeNodeContext = this._getContext(context); - - removeNodeContext.label = "remove"; - var removeNode = Y.Node.create(Y.Handlebars.compile(TEMPLATES.FORM_COMPONENTS.REMOVE_COMPONENT)(removeNodeContext)); - - removeNode.one('.removecomponent').on('click', function(e) { - e.preventDefault(); - currentComponent.remove(true); - }); - - currentComponent.insert(newComponent, 'after'); - element.ancestor().insert(removeNode, 'after'); - element.ancestor().remove(true); - - if (callback) { - callback.call(this, newComponent); - } - }, - - /** - * Returns the callback for the file picker to call after a file has been selected. - * - * @method _getFilepickerCallback - * @param {Y.Node} element The element which triggered the callback - * @param {String} fptype The file pickertype (as would be passed to `showFilePicker`) - * @return {Function} The function to be used as a callback when the file picker returns the file - * @private - */ - _getFilepickerCallback: function(element, fptype) { - return function(params) { - if (params.url !== '') { - var tabPane = element.ancestor('.tab-pane'); - element.ancestor(SELECTORS.SOURCE).one(SELECTORS.URL_INPUT).set('value', params.url); - - // Links (and only links) have a name field. - if (tabPane.get('id') === this.get('host').get('elementid') + '_' + CSS.LINK) { - tabPane.one(SELECTORS.NAME_INPUT).set('value', params.file); - } - - if (fptype === 'subtitle') { - var subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0]; - var langObj = this.get('langs').available.reduce(function(carry, lang) { - return lang.code === subtitleLang ? lang : carry; - }, false); - if (langObj) { - element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LABEL_INPUT).set('value', - langObj.lang.substr(0, langObj.lang.lastIndexOf(' '))); - element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LANG_INPUT).set('value', langObj.code); - } - } - } - }; - }, - - /** - * Given a "medium" tab pane, returns what kind of medium it contains. - * - * @method _getMediumTypeFromTabPane - * @param {Y.Node} tabPane The tab pane - * @return {String} The type of medium in the pane - */ - _getMediumTypeFromTabPane: function(tabPane) { - return tabPane.getAttribute('data-medium-type'); - }, - - /** - * Given a "track" tab pane, returns what kind of track it contains. - * - * @method _getTrackTypeFromTabPane - * @param {Y.Node} tabPane The tab pane - * @return {String} The type of track in the pane - */ - _getTrackTypeFromTabPane: function(tabPane) { - return tabPane.getAttribute('data-track-kind'); - }, - - /** - * Returns the HTML to be inserted to the text area. - * - * @method _getMediaHTML - * @param {Y.Node} form The form from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTML: function(form) { - var mediumType = this._getMediumTypeFromTabPane(form.one('.root.tab-content > .tab-pane.active')); - var tabContent = form.one(SELECTORS[mediumType.toUpperCase() + '_PANE']); - - return this['_getMediaHTML' + mediumType[0].toUpperCase() + mediumType.substr(1)](tabContent); - }, - - /** - * Returns the HTML to be inserted to the text area for the link tab. - * - * @method _getMediaHTMLLink - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLLink: function(tab) { - var context = { - url: tab.one(SELECTORS.URL_INPUT).get('value'), - name: tab.one(SELECTORS.NAME_INPUT).get('value') || false - }; - - return context.url ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.LINK)(context) : ''; - }, - - /** - * Returns the HTML to be inserted to the text area for the video tab. - * - * @method _getMediaHTMLVideo - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLVideo: function(tab) { - var context = this._getContextForMediaHTML(tab); - context.width = tab.one(SELECTORS.WIDTH_INPUT).get('value') || false; - context.height = tab.one(SELECTORS.HEIGHT_INPUT).get('value') || false; - context.poster = tab.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false; - - return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.VIDEO)(context) : ''; - }, - - /** - * Returns the HTML to be inserted to the text area for the audio tab. - * - * @method _getMediaHTMLAudio - * @param {Y.Node} tab The tab from which to extract data - * @return {String} The compiled markup - * @private - */ - _getMediaHTMLAudio: function(tab) { - var context = this._getContextForMediaHTML(tab); - - return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.AUDIO)(context) : ''; - }, - - /** - * Returns the context with which to render a media template. - * - * @method _getContextForMediaHTML - * @param {Y.Node} tab The tab from which to extract data - * @return {Object} - * @private - */ - _getContextForMediaHTML: function(tab) { - var tracks = []; - - tab.all(SELECTORS.TRACK).each(function(track) { - tracks.push({ - track: track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value'), - kind: this._getTrackTypeFromTabPane(track.ancestor('.tab-pane')), - label: track.one(SELECTORS.TRACK_LABEL_INPUT).get('value') || - track.one(SELECTORS.TRACK_LANG_INPUT).get('value'), - srclang: track.one(SELECTORS.TRACK_LANG_INPUT).get('value'), - defaultTrack: track.one(SELECTORS.TRACK_DEFAULT_SELECT).get('checked') ? "true" : null - }); - }, this); - - return { - sources: tab.all(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value').filter(function(source) { - return !!source; - }).map(function(source) { - return {source: source}; - }), - description: tab.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false, - tracks: tracks.filter(function(track) { - return !!track.track; - }), - showControls: tab.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).get('checked'), - autoplay: tab.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).get('checked'), - muted: tab.one(SELECTORS.MEDIA_MUTE_TOGGLE).get('checked'), - loop: tab.one(SELECTORS.MEDIA_LOOP_TOGGLE).get('checked'), - title: tab.one(SELECTORS.TITLE_INPUT).get('value') || false - }; - } -}, { - ATTRS: { - langs: {}, - help: {} - } -}); diff --git a/lib/editor/atto/plugins/media/yui/src/button/meta/button.json b/lib/editor/atto/plugins/media/yui/src/button/meta/button.json deleted file mode 100644 index da1fa3faea3..00000000000 --- a/lib/editor/atto/plugins/media/yui/src/button/meta/button.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "moodle-atto_media-button": { - "requires": [ - "moodle-editor_atto-plugin", - "moodle-form-shortforms" - ] - } -} diff --git a/lib/editor/atto/plugins/noautolink/classes/privacy/provider.php b/lib/editor/atto/plugins/noautolink/classes/privacy/provider.php deleted file mode 100644 index 9713f815781..00000000000 --- a/lib/editor/atto/plugins/noautolink/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_noautolink - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_noautolink\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_noautolink implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/noautolink/lang/en/atto_noautolink.php b/lib/editor/atto/plugins/noautolink/lang/en/atto_noautolink.php deleted file mode 100644 index a09f77e132f..00000000000 --- a/lib/editor/atto/plugins/noautolink/lang/en/atto_noautolink.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_noautolink', language 'en'. - * - * @package atto_noautolink - * @copyright 2014 Andrew Davis - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Prevent auto-link'; -$string['privacy:metadata'] = 'The atto_noautolink plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/noautolink/version.php b/lib/editor/atto/plugins/noautolink/version.php deleted file mode 100644 index 0e4e5223161..00000000000 --- a/lib/editor/atto/plugins/noautolink/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_noautolink - * @copyright 2014 Andrew Davis - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_noautolink'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-debug.js b/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-debug.js deleted file mode 100644 index d1fbd24168a..00000000000 --- a/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-debug.js +++ /dev/null @@ -1,60 +0,0 @@ -YUI.add('moodle-atto_noautolink-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_noautolink - * @copyright 2014 Andrew Davis - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_noautolink-button - */ - -/** - * Atto text editor noautolink plugin. - * - * @namespace M.atto_noautolink - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_noautolink').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addButton({ - icon: 'e/prevent_autolink', - callback: this._preventAutoLink, - inlineFormat: true, - tags: '.nolink' - }); - }, - - /** - * Prevent autolinking of the selected region. - * - * @method _preventAutoLink - * @param {EventFacade} e - * @private - */ - _preventAutoLink: function() { - // Toggle inline selection class - this.get('host').toggleInlineSelectionClass(['nolink']); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-min.js b/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-min.js deleted file mode 100644 index 289d6ed8945..00000000000 --- a/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_noautolink-button",function(t,n){t.namespace("M.atto_noautolink").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({icon:"e/prevent_autolink",callback:this._preventAutoLink,inlineFormat:!0,tags:".nolink"})},_preventAutoLink:function(){this.get("host").toggleInlineSelectionClass(["nolink"])}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button.js b/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button.js deleted file mode 100644 index d1fbd24168a..00000000000 --- a/lib/editor/atto/plugins/noautolink/yui/build/moodle-atto_noautolink-button/moodle-atto_noautolink-button.js +++ /dev/null @@ -1,60 +0,0 @@ -YUI.add('moodle-atto_noautolink-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_noautolink - * @copyright 2014 Andrew Davis - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_noautolink-button - */ - -/** - * Atto text editor noautolink plugin. - * - * @namespace M.atto_noautolink - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_noautolink').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addButton({ - icon: 'e/prevent_autolink', - callback: this._preventAutoLink, - inlineFormat: true, - tags: '.nolink' - }); - }, - - /** - * Prevent autolinking of the selected region. - * - * @method _preventAutoLink - * @param {EventFacade} e - * @private - */ - _preventAutoLink: function() { - // Toggle inline selection class - this.get('host').toggleInlineSelectionClass(['nolink']); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/noautolink/yui/src/button/build.json b/lib/editor/atto/plugins/noautolink/yui/src/button/build.json deleted file mode 100644 index dfa4d50da49..00000000000 --- a/lib/editor/atto/plugins/noautolink/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_noautolink-button", - "builds": { - "moodle-atto_noautolink-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/noautolink/yui/src/button/js/button.js b/lib/editor/atto/plugins/noautolink/yui/src/button/js/button.js deleted file mode 100644 index 1f6db9d7cd4..00000000000 --- a/lib/editor/atto/plugins/noautolink/yui/src/button/js/button.js +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_noautolink - * @copyright 2014 Andrew Davis - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_noautolink-button - */ - -/** - * Atto text editor noautolink plugin. - * - * @namespace M.atto_noautolink - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_noautolink').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addButton({ - icon: 'e/prevent_autolink', - callback: this._preventAutoLink, - inlineFormat: true, - tags: '.nolink' - }); - }, - - /** - * Prevent autolinking of the selected region. - * - * @method _preventAutoLink - * @param {EventFacade} e - * @private - */ - _preventAutoLink: function() { - // Toggle inline selection class - this.get('host').toggleInlineSelectionClass(['nolink']); - } -}); diff --git a/lib/editor/atto/plugins/noautolink/yui/src/button/meta/button.json b/lib/editor/atto/plugins/noautolink/yui/src/button/meta/button.json deleted file mode 100644 index 0c1ce68ded2..00000000000 --- a/lib/editor/atto/plugins/noautolink/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_noautolink-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/orderedlist/classes/privacy/provider.php b/lib/editor/atto/plugins/orderedlist/classes/privacy/provider.php deleted file mode 100644 index 345db74f162..00000000000 --- a/lib/editor/atto/plugins/orderedlist/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_orderedlist - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_orderedlist\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_orderedlist implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/orderedlist/lang/en/atto_orderedlist.php b/lib/editor/atto/plugins/orderedlist/lang/en/atto_orderedlist.php deleted file mode 100644 index 30dbb701670..00000000000 --- a/lib/editor/atto/plugins/orderedlist/lang/en/atto_orderedlist.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_orderedlist', language 'en'. - * - * @package atto_orderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Ordered list'; -$string['privacy:metadata'] = 'The atto_orderedlist plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/orderedlist/tests/behat/orderedlist.feature b/lib/editor/atto/plugins/orderedlist/tests/behat/orderedlist.feature deleted file mode 100644 index 9660494e094..00000000000 --- a/lib/editor/atto/plugins/orderedlist/tests/behat/orderedlist.feature +++ /dev/null @@ -1,18 +0,0 @@ -@editor @editor_atto @atto @atto_orderedlist @_bug_phantomjs -Feature: Atto ordered list button - To format text in Atto, I need to use the ordered list button. - - @javascript - Scenario: Make a list from some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Have you heard the news everyone's talking
                          Life is good 'cause everything's awesome
                          " - And I select the text in the "Description" Atto editor - When I click on "Ordered list" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then "//textarea[@id='id_description_editor'][starts-with(text(), '
                          1. ') and contains(normalize-space(.), 'Have you heard the news everyone')]" "xpath_element" should exist diff --git a/lib/editor/atto/plugins/orderedlist/version.php b/lib/editor/atto/plugins/orderedlist/version.php deleted file mode 100644 index b15988eb2cb..00000000000 --- a/lib/editor/atto/plugins/orderedlist/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_orderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_orderedlist'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-debug.js b/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-debug.js deleted file mode 100644 index 73d85dc57bd..00000000000 --- a/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-debug.js +++ /dev/null @@ -1,49 +0,0 @@ -YUI.add('moodle-atto_orderedlist-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_orderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_orderedlist-button - */ - -/** - * Atto text editor orderedlist plugin. - * - * @namespace M.atto_orderedlist - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_orderedlist').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'insertOrderedList', - icon: 'e/numbered_list', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'ol' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-min.js b/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-min.js deleted file mode 100644 index 469e958d0df..00000000000 --- a/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_orderedlist-button",function(t,e){t.namespace("M.atto_orderedlist").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addBasicButton({exec:"insertOrderedList",icon:"e/numbered_list",tags:"ol"})}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button.js b/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button.js deleted file mode 100644 index 73d85dc57bd..00000000000 --- a/lib/editor/atto/plugins/orderedlist/yui/build/moodle-atto_orderedlist-button/moodle-atto_orderedlist-button.js +++ /dev/null @@ -1,49 +0,0 @@ -YUI.add('moodle-atto_orderedlist-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_orderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_orderedlist-button - */ - -/** - * Atto text editor orderedlist plugin. - * - * @namespace M.atto_orderedlist - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_orderedlist').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'insertOrderedList', - icon: 'e/numbered_list', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'ol' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/orderedlist/yui/src/button/build.json b/lib/editor/atto/plugins/orderedlist/yui/src/button/build.json deleted file mode 100644 index 2326ff6dcb1..00000000000 --- a/lib/editor/atto/plugins/orderedlist/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_orderedlist-button", - "builds": { - "moodle-atto_orderedlist-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/orderedlist/yui/src/button/js/button.js b/lib/editor/atto/plugins/orderedlist/yui/src/button/js/button.js deleted file mode 100644 index ba9b415dc10..00000000000 --- a/lib/editor/atto/plugins/orderedlist/yui/src/button/js/button.js +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_orderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_orderedlist-button - */ - -/** - * Atto text editor orderedlist plugin. - * - * @namespace M.atto_orderedlist - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_orderedlist').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'insertOrderedList', - icon: 'e/numbered_list', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'ol' - }); - } -}); diff --git a/lib/editor/atto/plugins/orderedlist/yui/src/button/meta/button.json b/lib/editor/atto/plugins/orderedlist/yui/src/button/meta/button.json deleted file mode 100644 index eebb905ca43..00000000000 --- a/lib/editor/atto/plugins/orderedlist/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_orderedlist-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/recordrtc/classes/privacy/provider.php b/lib/editor/atto/plugins/recordrtc/classes/privacy/provider.php deleted file mode 100644 index af274ca0464..00000000000 --- a/lib/editor/atto/plugins/recordrtc/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for atto_recordrtc. - * - * @package atto_recordrtc - * @copyright 2018 Mark Nelson - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_recordrtc\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_recordrtc implementing null_provider. - * - * @copyright 2018 Mark Nelson - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/recordrtc/db/access.php b/lib/editor/atto/plugins/recordrtc/db/access.php deleted file mode 100644 index 27adfb324b4..00000000000 --- a/lib/editor/atto/plugins/recordrtc/db/access.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Atto text editor recordrtc capabilities. - * - * @package atto_recordrtc - * @copyright 2018 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$capabilities = [ - // Capability to record audio using this plugin. - 'atto/recordrtc:recordaudio' => [ - 'captype' => 'write', - 'contextlevel' => CONTEXT_MODULE, - 'archetypes' => [ - 'user' => CAP_ALLOW, - ], - ], - // Capability to record video using this plugin. - 'atto/recordrtc:recordvideo' => [ - 'captype' => 'write', - 'contextlevel' => CONTEXT_MODULE, - 'archetypes' => [ - 'user' => CAP_ALLOW, - ], - ], -]; diff --git a/lib/editor/atto/plugins/recordrtc/db/upgrade.php b/lib/editor/atto/plugins/recordrtc/db/upgrade.php deleted file mode 100644 index f1289b8848a..00000000000 --- a/lib/editor/atto/plugins/recordrtc/db/upgrade.php +++ /dev/null @@ -1,45 +0,0 @@ -. - -/** - * Atto text editor recordrtc upgrade script. - * - * @package atto_recordrtc - * @copyright 2021 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Upgrade code for the recordrtc atto text editor. - * - * @param int $oldversion the version we are upgrading from. - * @return bool - */ -function xmldb_atto_recordrtc_upgrade($oldversion) { - // Automatically generated Moodle v4.2.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.3.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.4.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.5.0 release upgrade line. - // Put any upgrade step following this. - - return true; -} diff --git a/lib/editor/atto/plugins/recordrtc/lang/en/atto_recordrtc.php b/lib/editor/atto/plugins/recordrtc/lang/en/atto_recordrtc.php deleted file mode 100644 index 8d7cd19080f..00000000000 --- a/lib/editor/atto/plugins/recordrtc/lang/en/atto_recordrtc.php +++ /dev/null @@ -1,80 +0,0 @@ -. - -/** - * Strings for component 'atto_recordrtc', language 'en'. - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['allowedtypes'] = 'Allowed types'; -$string['allowedtypes_desc'] = 'Which recording buttons should appear in Atto. In addition to this setting, there are also capabilities which can control access to the buttons to particular users in particular contexts.'; -$string['attachrecording'] = 'Attach recording'; -$string['audioandvideo'] = 'Audio and video'; -$string['audiobitrate'] = 'Audio bitrate'; -$string['audiobitrate_desc'] = 'Quality of audio recording (larger number means higher quality)'; -$string['audiortc'] = 'Record audio'; -$string['gumabort'] = 'Something strange happened which prevented the webcam/microphone from being used'; -$string['gumabort_title'] = 'Something happened'; -$string['gumnotallowed'] = 'The user must allow the browser access to the webcam/microphone'; -$string['gumnotallowed_title'] = 'Wrong permissions'; -$string['gumnotfound'] = 'There is no input device connected or enabled'; -$string['gumnotfound_title'] = 'Device missing'; -$string['gumnotreadable'] = 'Something is preventing the browser from accessing the webcam/microphone'; -$string['gumnotreadable_title'] = 'Hardware error'; -$string['gumnotsupported'] = 'Your browser does not support recording over an insecure connection and must close the plugin'; -$string['gumnotsupported_title'] = 'No support for insecure connection'; -$string['gumoverconstrained'] = 'The current webcam/microphone can not produce a stream with the required constraints'; -$string['gumoverconstrained_title'] = 'Problem with constraints'; -$string['gumsecurity'] = 'Your browser does not support recording over an insecure connection and must close the plugin'; -$string['gumsecurity_title'] = 'No support for insecure connection'; -$string['gumtype'] = 'Tried to get stream from the webcam/microphone, but no constraints were specified'; -$string['gumtype_title'] = 'No constraints specified'; -$string['insecurealert'] = 'Your browser might not allow this plugin to work unless it is used either over HTTPS or from localhost'; -$string['insecurealert_title'] = 'Insecure connection!'; -$string['nearingmaxsize'] = 'You have attained the maximum size limit for file uploads'; -$string['nearingmaxsize_title'] = 'Recording stopped'; -$string['norecordingfound'] = 'Something appears to have gone wrong, it seems nothing has been recorded'; -$string['norecordingfound_title'] = 'No recording found'; -$string['nowebrtc'] = 'Your browser offers limited or no support for WebRTC technologies yet, and cannot be used with this plugin. Please switch or upgrade your browser'; -$string['nowebrtc_title'] = 'WebRTC not supported'; -$string['onlyaudio'] = 'Audio only'; -$string['onlyvideo'] = 'Video only'; -$string['pluginname'] = 'RecordRTC'; -$string['privacy:metadata'] = 'The RecordRTC plugin does not store any personal data.'; -$string['recordagain'] = 'Record again'; -$string['recordingfailed'] = 'Recording failed, try again'; -$string['recordrtc:recordaudio'] = 'Record audio directly into the text editor'; -$string['recordrtc:recordvideo'] = 'Record video directly into the text editor'; -$string['settings'] = 'RecordRTC settings'; -$string['startrecording'] = 'Start recording'; -$string['stoprecording'] = 'Stop recording'; -$string['audiotimelimit'] = 'Audio time limit in seconds'; -$string['audiotimelimit_desc'] = 'Maximum recording length allowed for the audio clips'; -$string['videotimelimit'] = 'Video time limit in seconds'; -$string['videotimelimit_desc'] = 'Maximum recording length allowed for the video clips'; -$string['timelimitwarning'] = 'You must enter a number that is greater than 0.'; -$string['uploadaborted'] = 'Upload aborted:'; -$string['uploadfailed'] = 'Upload failed:'; -$string['uploadfailed404'] = 'Upload failed: file too large'; -$string['uploadprogress'] = 'completed'; -$string['videobitrate'] = 'Video bitrate'; -$string['videobitrate_desc'] = 'Quality of video recording (larger number means higher quality)'; -$string['videortc'] = 'Record video'; diff --git a/lib/editor/atto/plugins/recordrtc/lib.php b/lib/editor/atto/plugins/recordrtc/lib.php deleted file mode 100644 index ed6f4162438..00000000000 --- a/lib/editor/atto/plugins/recordrtc/lib.php +++ /dev/null @@ -1,145 +0,0 @@ -. - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Default maximum recording length allowed for the audio/video clips. - */ -define('DEFAULT_TIME_LIMIT', 120); - -/** - * Set params for this plugin. - * - * @param string $elementid - * @param stdClass $options - the options for the editor, including the context. - * @param stdClass $fpoptions - unused. - */ -function atto_recordrtc_params_for_js($elementid, $options, $fpoptions) { - $context = $options['context']; - if (!$context) { - $context = context_system::instance(); - } - - $sesskey = sesskey(); - $allowedtypes = get_config('atto_recordrtc', 'allowedtypes'); - $audiobitrate = get_config('atto_recordrtc', 'audiobitrate'); - $videobitrate = get_config('atto_recordrtc', 'videobitrate'); - $audiotimelimit = get_config('atto_recordrtc', 'audiotimelimit'); - $videotimelimit = get_config('atto_recordrtc', 'videotimelimit'); - - // Update $allowedtypes to account for capabilities. - $audioallowed = $allowedtypes === 'audio' || $allowedtypes === 'both'; - $videoallowed = $allowedtypes === 'video' || $allowedtypes === 'both'; - $audioallowed = $audioallowed && has_capability('atto/recordrtc:recordaudio', $context); - $videoallowed = $videoallowed && has_capability('atto/recordrtc:recordvideo', $context); - if ($audioallowed && $videoallowed) { - $allowedtypes = 'both'; - } else if ($audioallowed) { - $allowedtypes = 'audio'; - } else if ($videoallowed) { - $allowedtypes = 'video'; - } else { - $allowedtypes = ''; - } - - $maxrecsize = get_max_upload_file_size(); - if (!empty($options['maxbytes'])) { - $maxrecsize = min($maxrecsize, $options['maxbytes']); - } - $audiortcicon = 'i/audiortc'; - $videortcicon = 'i/videortc'; - $params = array('contextid' => $context->id, - 'sesskey' => $sesskey, - 'allowedtypes' => $allowedtypes, - 'audiobitrate' => $audiobitrate, - 'videobitrate' => $videobitrate, - 'audiotimelimit' => $audiotimelimit, - 'videotimelimit' => $videotimelimit, - 'defaulttimelimit' => DEFAULT_TIME_LIMIT, - 'audiortcicon' => $audiortcicon, - 'videortcicon' => $videortcicon, - 'maxrecsize' => $maxrecsize - ); - - return $params; -} - -/** - * Initialise the js strings required for this module. - */ -function atto_recordrtc_strings_for_js() { - global $PAGE; - - $strings = array('audiortc', - 'videortc', - 'nowebrtc_title', - 'nowebrtc', - 'gumabort_title', - 'gumabort', - 'gumnotallowed_title', - 'gumnotallowed', - 'gumnotfound_title', - 'gumnotfound', - 'gumnotreadable_title', - 'gumnotreadable', - 'gumnotsupported', - 'gumnotsupported_title', - 'gumoverconstrained_title', - 'gumoverconstrained', - 'gumsecurity_title', - 'gumsecurity', - 'gumtype_title', - 'gumtype', - 'insecurealert_title', - 'insecurealert', - 'startrecording', - 'recordagain', - 'stoprecording', - 'recordingfailed', - 'attachrecording', - 'norecordingfound_title', - 'norecordingfound', - 'nearingmaxsize_title', - 'nearingmaxsize', - 'uploadprogress', - 'uploadfailed', - 'uploadfailed404', - 'uploadaborted' - ); - - $PAGE->requires->strings_for_js($strings, 'atto_recordrtc'); -} - -/** - * Map icons for font-awesome themes. - */ -function atto_recordrtc_get_fontawesome_icon_map() { - return [ - 'atto_recordrtc:i/audiortc' => 'fa-microphone', - 'atto_recordrtc:i/videortc' => 'fa-video', - ]; -} diff --git a/lib/editor/atto/plugins/recordrtc/pix/i/audiortc.svg b/lib/editor/atto/plugins/recordrtc/pix/i/audiortc.svg deleted file mode 100644 index abcbd05aae3..00000000000 --- a/lib/editor/atto/plugins/recordrtc/pix/i/audiortc.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/editor/atto/plugins/recordrtc/pix/i/videortc.svg b/lib/editor/atto/plugins/recordrtc/pix/i/videortc.svg deleted file mode 100644 index d4d6804471d..00000000000 --- a/lib/editor/atto/plugins/recordrtc/pix/i/videortc.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/editor/atto/plugins/recordrtc/pix/icon.png b/lib/editor/atto/plugins/recordrtc/pix/icon.png deleted file mode 100644 index 8f36cef00e72600ad3d0b755519e79fd1dc79f6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 644 zcmV-~0(Jw&M&w?{)XXibUa>0n)b6_`a6YfKt7Ce`x2d4FuFjb; zQ$fJUyIL+e@X2|+pWMcx0npypXN!M!w`!zna(ZyN{@ufT7-0L}gNKj)>~icfwR~_L z8Jz-<_Uq4!V~O05K(pOY9P{qc6_Hul8T#@E?W(bBS9ONuLa%^{hC9xNu`@<2k-H?& z3{dTMaI&dVpb}`Yd~Q1O1T*;^fzy#!P2);I>pwrlGS<69RGTug%D$}6^8Tns< zi5gdCrr;{@cB{~Ez=mE;-zR0|h8pT_T#99~-j?J@e`D&!rh;cd1OJ@epOBchykRnK z0E~9GB=2?}s+ZXk5??(Ome(NmBC?C~L=~jeD!jN7Cb$$}!BiDz+b83&VcRs6=~SHX zfR9p78xMS~>EIlp0Uz0D2!J1j7E3Am^M~p#~EG0000z#?q` diff --git a/lib/editor/atto/plugins/recordrtc/settings.php b/lib/editor/atto/plugins/recordrtc/settings.php deleted file mode 100644 index c730474e406..00000000000 --- a/lib/editor/atto/plugins/recordrtc/settings.php +++ /dev/null @@ -1,86 +0,0 @@ -. - -/** - * Settings that allow turning on and off recordrtc features - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -// Needed for constants. -require_once($CFG->dirroot . '/lib/editor/atto/plugins/recordrtc/lib.php'); - -$ADMIN->add('editoratto', new admin_category('atto_recordrtc', new lang_string('pluginname', 'atto_recordrtc'))); - -if ($ADMIN->fulltree) { - // Types allowed. - $options = array( - 'both' => new lang_string('audioandvideo', 'atto_recordrtc'), - 'audio' => new lang_string('onlyaudio', 'atto_recordrtc'), - 'video' => new lang_string('onlyvideo', 'atto_recordrtc') - ); - $name = get_string('allowedtypes', 'atto_recordrtc'); - $desc = get_string('allowedtypes_desc', 'atto_recordrtc'); - $default = 'both'; - $setting = new admin_setting_configselect('atto_recordrtc/allowedtypes', $name, $desc, $default, $options); - $settings->add($setting); - - // Audio bitrate. - $name = get_string('audiobitrate', 'atto_recordrtc'); - $desc = get_string('audiobitrate_desc', 'atto_recordrtc'); - $default = '128000'; - $setting = new admin_setting_configtext('atto_recordrtc/audiobitrate', $name, $desc, $default, PARAM_INT, 8); - $settings->add($setting); - - // Video bitrate. - $name = get_string('videobitrate', 'atto_recordrtc'); - $desc = get_string('videobitrate_desc', 'atto_recordrtc'); - $default = '2500000'; - $setting = new admin_setting_configtext('atto_recordrtc/videobitrate', $name, $desc, $default, PARAM_INT, 8); - $settings->add($setting); - - // Audio recording time limit. - $name = get_string('audiotimelimit', 'atto_recordrtc'); - $desc = get_string('audiotimelimit_desc', 'atto_recordrtc'); - // Validate audiotimelimit greater than 0. - $setting = new admin_setting_configduration('atto_recordrtc/audiotimelimit', $name, $desc, DEFAULT_TIME_LIMIT); - $setting->set_validate_function(function(int $value): string { - if ($value <= 0) { - return get_string('timelimitwarning', 'atto_recordrtc'); - } - return ''; - }); - $settings->add($setting); - - // Video recording time limit. - $name = get_string('videotimelimit', 'atto_recordrtc'); - $desc = get_string('videotimelimit_desc', 'atto_recordrtc'); - // Validate videotimelimit greater than 0. - $setting = new admin_setting_configduration('atto_recordrtc/videotimelimit', $name, $desc, DEFAULT_TIME_LIMIT); - $setting->set_validate_function(function(int $value): string { - if ($value <= 0) { - return get_string('timelimitwarning', 'atto_recordrtc'); - } - return ''; - }); - $settings->add($setting); -} diff --git a/lib/editor/atto/plugins/recordrtc/styles.css b/lib/editor/atto/plugins/recordrtc/styles.css deleted file mode 100644 index 202e0eb00d7..00000000000 --- a/lib/editor/atto/plugins/recordrtc/styles.css +++ /dev/null @@ -1,39 +0,0 @@ -.atto_recordrtc, -.atto_recordrtc div { - font-weight: normal; - line-height: 40px; - padding: 3px 0 3px 0; -} - -.atto_recordrtc .alert { - line-height: 40px; - text-align: center; -} - -.atto_recordrtc audio { - display: block; - width: 100%; -} - -@media screen and (max-width: 670px) { - .atto_recordrtc video { - display: block; - height: auto; - margin: 0 auto; - width: 100%; - } -} - -@media screen and (min-width: 671px) { - .atto_recordrtc video { - display: block; - height: 480px; - margin: 0 auto; - width: 640px; - } -} - -.atto_recordrtc #start-stop, -.atto_recordrtc #upload { - white-space: normal; -} diff --git a/lib/editor/atto/plugins/recordrtc/version.php b/lib/editor/atto/plugins/recordrtc/version.php deleted file mode 100644 index 5a45f487d39..00000000000 --- a/lib/editor/atto/plugins/recordrtc/version.php +++ /dev/null @@ -1,32 +0,0 @@ -. - -/** - * Atto text editor recordrtc version file. - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; -$plugin->requires = 2024100100; -$plugin->component = 'atto_recordrtc'; -$plugin->maturity = MATURITY_STABLE; diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js deleted file mode 100644 index 818f76a2333..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js +++ /dev/null @@ -1,394 +0,0 @@ -YUI.add('moodle-atto_recordrtc-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_recordrtc-button - */ - -/** - * Atto text editor recordrtc plugin. - * - * @namespace M.atto_recordrtc - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// JSHint directives. -/*global M */ -/*jshint onevar: false */ - -// Scrutinizer CI directives. -/** global: Y */ -/** global: M */ - -var PLUGINNAME = 'atto_recordrtc', - TEMPLATE = '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{insecurealert_title}} {{insecurealert}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{#if isAudio}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '{{else}}' + - '
                            ' + - '' + - '
                            ' + - '{{/if}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            '; - -Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * The current language by default. - */ - _lang: 'en', - - initializer: function() { - if (this.get('host').canShowFilepicker('media')) { - // Add audio and/or video buttons depending on the settings. - var allowedtypes = this.get('allowedtypes'), - buttonadded = false; - if (allowedtypes === 'both' || allowedtypes === 'audio') { - this._addButton('audio', this._audio); - buttonadded = true; - } - if (allowedtypes === 'both' || allowedtypes === 'video') { - this._addButton('video', this._video); - buttonadded = true; - } - if (!buttonadded) { - // Plugin not available here. - return; - } - - // Initialize the dialogue box. - var dialogue = this.getDialogue({ - width: 1000, - focusAfterHide: null - }); - - dialogue.after('visibleChange', function() { - var closed = !dialogue.get('visible'), - m = M.atto_recordrtc.commonmodule; - - if (closed) { - // If dialogue is closed during recording, do the following. - window.clearInterval(m.countdownTicker); - - if (m.mediaRecorder && m.mediaRecorder.state !== 'inactive') { - m.mediaRecorder.stop(); - } - - if (m.stream) { - m.stream.getTracks().forEach(function(track) { - if (track.readyState !== 'ended') { - track.stop(); - } - }); - } - - // Because the player uses ids to identify things (this should be fixed) - // we must make sure the dialogue contents only exist once in the DOM. - // Therefore, when a dialogue is closed, we must remove its contents. - this.getDialogue().set('bodyContent', ''); - } - - }, this); - - dialogue.on('click', function() { - this.centered(); - }); - - // Require adapter.js library. - window.require(['core/adapter'], function(adapter) { - window.adapter = adapter; - }); - } - }, - - /** - * Add the buttons to the Atto toolbar. - * - * @method _addButton - * @param {string} type - * @param {callback} callback - * @private - */ - _addButton: function(type, callback) { - this.addButton({ - buttonName: type, - icon: this.get(type + 'rtcicon'), - iconComponent: PLUGINNAME, - callback: callback, - title: type + 'rtc', - tags: type + 'rtc', - tagMatchRequiresAll: false - }); - }, - - /** - * Toggle audiortc and normal display mode - * - * @method _audio - * @private - */ - _audio: function() { - var dialogue = this.getDialogue({ - focusAfterHide: 'audio' - }); - - dialogue.set('headerContent', M.util.get_string('audiortc', 'atto_recordrtc')); - dialogue.set('bodyContent', this._createContent('audio')); - - dialogue.show(); - - M.atto_recordrtc.audiomodule.init(this); - }, - - /** - * Toggle videortc and normal display mode - * - * @method _video - * @private - */ - _video: function() { - var dialogue = this.getDialogue({ - focusAfterHide: 'video' - }); - - dialogue.set('headerContent', M.util.get_string('videortc', 'atto_recordrtc')); - dialogue.set('bodyContent', this._createContent('video')); - - dialogue.show(); - - M.atto_recordrtc.videomodule.init(this); - }, - - /** - * Create the HTML to be displayed in the dialogue box - * - * @method _createContent - * @param {string} type - * @returns {Object} - * @private - */ - _createContent: function(type) { - var isAudio = (type === 'audio'), - bsRow = 'row', - bsCol = 'col-', - bsAlDang = 'alert-danger', - bsSsBtn = 'btn btn-lg btn-outline-danger w-100'; - - var bodyContent = Y.Handlebars.compile(TEMPLATE)({ - PLUGINNAME: PLUGINNAME, - isAudio: isAudio, - bs_row: bsRow, - bs_col: bsCol, - bs_al_dang: bsAlDang, - bs_ss_btn: bsSsBtn, - insecurealert_title: M.util.get_string('insecurealert_title', 'atto_recordrtc'), - insecurealert: M.util.get_string('insecurealert', 'atto_recordrtc'), - startrecording: M.util.get_string('startrecording', 'atto_recordrtc'), - attachrecording: M.util.get_string('attachrecording', 'atto_recordrtc') - }); - - return bodyContent; - }, - - /** - * Close the dialogue without further action. - * - * @method closeDialogue - * @param {Object} scope The "this" context of the editor. - */ - closeDialogue: function(scope) { - scope.getDialogue().hide({ - focusAfterHide: null - }); - - scope.editor.focus(); - }, - - /** - * Insert the annotation link in the editor. - * - * @method setLink - * @param {Object} scope The "this" context of the editor. - * @param {string} annotation The HTML link to the recording. - */ - setLink: function(scope, annotation) { - scope.getDialogue().hide({ - focusAfterHide: null - }); - - scope.editor.focus(); - scope.get('host').insertContentAtFocusPoint(annotation); - scope.markUpdated(); - } -}, { - ATTRS: { - /** - * The contextid to use when generating this recordrtc. - * - * @attribute contextid - * @type String - */ - contextid: { - value: null - }, - - /** - * The sesskey to use when generating this recordrtc. - * - * @attribute sesskey - * @type String - */ - sesskey: { - value: null - }, - - /** - * The allowedtypes to use when generating this recordrtc. - * - * @attribute allowedtypes - * @type String - */ - allowedtypes: { - value: null - }, - - /** - * The audiobitrate to use when generating this recordrtc. - * - * @attribute audiobitrate - * @type String - */ - audiobitrate: { - value: null - }, - - /** - * The videobitrate to use when generating this recordrtc. - * - * @attribute videobitrate - * @type String - */ - videobitrate: { - value: null - }, - - /** - * The audiotimelimit to use when generating this recordrtc. - * - * @attribute audiotimelimit - * @type String - */ - audiotimelimit: { - value: null - }, - - /** - * The videotimelimit to use when generating this recordrtc. - * - * @attribute videotimelimit - * @type String - */ - videotimelimit: { - value: null - }, - - /** - * The defaulttimelimit to use when generating this recordrtc. - * - * @attribute defaulttimelimit - * @type String - */ - defaulttimelimit: { - value: null - }, - - /** - * The audiortcicon to use when generating this recordrtc. - * - * @attribute audiortcicon - * @type String - */ - audiortcicon: { - value: null - }, - - /** - * The videortcicon to use when generating this recordrtc. - * - * @attribute videortcicon - * @type String - */ - videortcicon: { - value: null - }, - - /** - * Maximum upload size set on server, in bytes. - * - * @attribute maxrecsize - * @type String - */ - maxrecsize: { - value: null - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-atto_recordrtc-recording"]}); diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js deleted file mode 100644 index 7ba4ccefc2e..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_recordrtc-button",function(e,t){var i="atto_recordrtc";e.namespace("M.atto_recordrtc").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_lang:"en",initializer:function(){var t,e,i;this.get("host").canShowFilepicker("media")&&(e=!1,"both"!==(t=this.get("allowedtypes"))&&"audio"!==t||(this._addButton("audio",this._audio),e=!0),"both"!==t&&"video"!==t||(this._addButton("video",this._video),e=!0),e&&((i=this.getDialogue({width:1e3,focusAfterHide:null})).after("visibleChange",function(){var t=!i.get("visible"),e=M.atto_recordrtc.commonmodule;t&&(window.clearInterval(e.countdownTicker),e.mediaRecorder&&"inactive"!==e.mediaRecorder.state&&e.mediaRecorder.stop(),e.stream&&e.stream.getTracks().forEach(function(t){"ended"!==t.readyState&&t.stop()}),this.getDialogue().set("bodyContent",""))},this),i.on("click",function(){this.centered()}),window.require(["core/adapter"],function(t){window.adapter=t})))},_addButton:function(t,e){this.addButton({buttonName:t,icon:this.get(t+"rtcicon"),iconComponent:i,callback:e,title:t+"rtc",tags:t+"rtc",tagMatchRequiresAll:!1})},_audio:function(){var t=this.getDialogue({focusAfterHide:"audio"});t.set("headerContent",M.util.get_string("audiortc","atto_recordrtc")),t.set("bodyContent",this._createContent("audio")),t.show(),M.atto_recordrtc.audiomodule.init(this)},_video:function(){var t=this.getDialogue({focusAfterHide:"video"});t.set("headerContent",M.util.get_string("videortc","atto_recordrtc")),t.set("bodyContent",this._createContent("video")),t.show(),M.atto_recordrtc.videomodule.init(this)},_createContent:function(t){t="audio"===t,t=e.Handlebars.compile('
                            {{insecurealert_title}} {{insecurealert}}
                            {{#if isAudio}}
                            {{else}}
                            {{/if}}
                            ')({PLUGINNAME:i,isAudio:t,bs_row:"row",bs_col:"col-",bs_al_dang:"alert-danger",bs_ss_btn:"btn btn-lg btn-outline-danger w-100",insecurealert_title:M.util.get_string("insecurealert_title","atto_recordrtc"),insecurealert:M.util.get_string("insecurealert","atto_recordrtc"),startrecording:M.util.get_string("startrecording","atto_recordrtc"),attachrecording:M.util.get_string("attachrecording","atto_recordrtc")});return t},closeDialogue:function(t){t.getDialogue().hide({focusAfterHide:null}),t.editor.focus()},setLink:function(t,e){t.getDialogue().hide({focusAfterHide:null}),t.editor.focus(),t.get("host").insertContentAtFocusPoint(e),t.markUpdated()}},{ATTRS:{contextid:{value:null},sesskey:{value:null},allowedtypes:{value:null},audiobitrate:{value:null},videobitrate:{value:null},audiotimelimit:{value:null},videotimelimit:{value:null},defaulttimelimit:{value:null},audiortcicon:{value:null},videortcicon:{value:null},maxrecsize:{value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-atto_recordrtc-recording"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js deleted file mode 100644 index 818f76a2333..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js +++ /dev/null @@ -1,394 +0,0 @@ -YUI.add('moodle-atto_recordrtc-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_recordrtc-button - */ - -/** - * Atto text editor recordrtc plugin. - * - * @namespace M.atto_recordrtc - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// JSHint directives. -/*global M */ -/*jshint onevar: false */ - -// Scrutinizer CI directives. -/** global: Y */ -/** global: M */ - -var PLUGINNAME = 'atto_recordrtc', - TEMPLATE = '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{insecurealert_title}} {{insecurealert}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{#if isAudio}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '{{else}}' + - '
                            ' + - '' + - '
                            ' + - '{{/if}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            '; - -Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * The current language by default. - */ - _lang: 'en', - - initializer: function() { - if (this.get('host').canShowFilepicker('media')) { - // Add audio and/or video buttons depending on the settings. - var allowedtypes = this.get('allowedtypes'), - buttonadded = false; - if (allowedtypes === 'both' || allowedtypes === 'audio') { - this._addButton('audio', this._audio); - buttonadded = true; - } - if (allowedtypes === 'both' || allowedtypes === 'video') { - this._addButton('video', this._video); - buttonadded = true; - } - if (!buttonadded) { - // Plugin not available here. - return; - } - - // Initialize the dialogue box. - var dialogue = this.getDialogue({ - width: 1000, - focusAfterHide: null - }); - - dialogue.after('visibleChange', function() { - var closed = !dialogue.get('visible'), - m = M.atto_recordrtc.commonmodule; - - if (closed) { - // If dialogue is closed during recording, do the following. - window.clearInterval(m.countdownTicker); - - if (m.mediaRecorder && m.mediaRecorder.state !== 'inactive') { - m.mediaRecorder.stop(); - } - - if (m.stream) { - m.stream.getTracks().forEach(function(track) { - if (track.readyState !== 'ended') { - track.stop(); - } - }); - } - - // Because the player uses ids to identify things (this should be fixed) - // we must make sure the dialogue contents only exist once in the DOM. - // Therefore, when a dialogue is closed, we must remove its contents. - this.getDialogue().set('bodyContent', ''); - } - - }, this); - - dialogue.on('click', function() { - this.centered(); - }); - - // Require adapter.js library. - window.require(['core/adapter'], function(adapter) { - window.adapter = adapter; - }); - } - }, - - /** - * Add the buttons to the Atto toolbar. - * - * @method _addButton - * @param {string} type - * @param {callback} callback - * @private - */ - _addButton: function(type, callback) { - this.addButton({ - buttonName: type, - icon: this.get(type + 'rtcicon'), - iconComponent: PLUGINNAME, - callback: callback, - title: type + 'rtc', - tags: type + 'rtc', - tagMatchRequiresAll: false - }); - }, - - /** - * Toggle audiortc and normal display mode - * - * @method _audio - * @private - */ - _audio: function() { - var dialogue = this.getDialogue({ - focusAfterHide: 'audio' - }); - - dialogue.set('headerContent', M.util.get_string('audiortc', 'atto_recordrtc')); - dialogue.set('bodyContent', this._createContent('audio')); - - dialogue.show(); - - M.atto_recordrtc.audiomodule.init(this); - }, - - /** - * Toggle videortc and normal display mode - * - * @method _video - * @private - */ - _video: function() { - var dialogue = this.getDialogue({ - focusAfterHide: 'video' - }); - - dialogue.set('headerContent', M.util.get_string('videortc', 'atto_recordrtc')); - dialogue.set('bodyContent', this._createContent('video')); - - dialogue.show(); - - M.atto_recordrtc.videomodule.init(this); - }, - - /** - * Create the HTML to be displayed in the dialogue box - * - * @method _createContent - * @param {string} type - * @returns {Object} - * @private - */ - _createContent: function(type) { - var isAudio = (type === 'audio'), - bsRow = 'row', - bsCol = 'col-', - bsAlDang = 'alert-danger', - bsSsBtn = 'btn btn-lg btn-outline-danger w-100'; - - var bodyContent = Y.Handlebars.compile(TEMPLATE)({ - PLUGINNAME: PLUGINNAME, - isAudio: isAudio, - bs_row: bsRow, - bs_col: bsCol, - bs_al_dang: bsAlDang, - bs_ss_btn: bsSsBtn, - insecurealert_title: M.util.get_string('insecurealert_title', 'atto_recordrtc'), - insecurealert: M.util.get_string('insecurealert', 'atto_recordrtc'), - startrecording: M.util.get_string('startrecording', 'atto_recordrtc'), - attachrecording: M.util.get_string('attachrecording', 'atto_recordrtc') - }); - - return bodyContent; - }, - - /** - * Close the dialogue without further action. - * - * @method closeDialogue - * @param {Object} scope The "this" context of the editor. - */ - closeDialogue: function(scope) { - scope.getDialogue().hide({ - focusAfterHide: null - }); - - scope.editor.focus(); - }, - - /** - * Insert the annotation link in the editor. - * - * @method setLink - * @param {Object} scope The "this" context of the editor. - * @param {string} annotation The HTML link to the recording. - */ - setLink: function(scope, annotation) { - scope.getDialogue().hide({ - focusAfterHide: null - }); - - scope.editor.focus(); - scope.get('host').insertContentAtFocusPoint(annotation); - scope.markUpdated(); - } -}, { - ATTRS: { - /** - * The contextid to use when generating this recordrtc. - * - * @attribute contextid - * @type String - */ - contextid: { - value: null - }, - - /** - * The sesskey to use when generating this recordrtc. - * - * @attribute sesskey - * @type String - */ - sesskey: { - value: null - }, - - /** - * The allowedtypes to use when generating this recordrtc. - * - * @attribute allowedtypes - * @type String - */ - allowedtypes: { - value: null - }, - - /** - * The audiobitrate to use when generating this recordrtc. - * - * @attribute audiobitrate - * @type String - */ - audiobitrate: { - value: null - }, - - /** - * The videobitrate to use when generating this recordrtc. - * - * @attribute videobitrate - * @type String - */ - videobitrate: { - value: null - }, - - /** - * The audiotimelimit to use when generating this recordrtc. - * - * @attribute audiotimelimit - * @type String - */ - audiotimelimit: { - value: null - }, - - /** - * The videotimelimit to use when generating this recordrtc. - * - * @attribute videotimelimit - * @type String - */ - videotimelimit: { - value: null - }, - - /** - * The defaulttimelimit to use when generating this recordrtc. - * - * @attribute defaulttimelimit - * @type String - */ - defaulttimelimit: { - value: null - }, - - /** - * The audiortcicon to use when generating this recordrtc. - * - * @attribute audiortcicon - * @type String - */ - audiortcicon: { - value: null - }, - - /** - * The videortcicon to use when generating this recordrtc. - * - * @attribute videortcicon - * @type String - */ - videortcicon: { - value: null - }, - - /** - * Maximum upload size set on server, in bytes. - * - * @attribute maxrecsize - * @type String - */ - maxrecsize: { - value: null - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-atto_recordrtc-recording"]}); diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-debug.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-debug.js deleted file mode 100644 index 691a99c55da..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-debug.js +++ /dev/null @@ -1,855 +0,0 @@ -YUI.add('moodle-atto_recordrtc-recording', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, no-alert, spaced-comment */ - -// JSHint directives. -/*global M */ -/*jshint es5: true */ -/*jshint onevar: false */ -/*jshint shadow: true */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to M.atto_recordrtc.commonmodule namespace. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.commonmodule = { - // Unitialized variables to be used by the other modules. - editorScope: null, - alertWarning: null, - alertDanger: null, - player: null, - playerDOM: null, // Used to manipulate DOM directly. - startStopBtn: null, - uploadBtn: null, - countdownSeconds: null, - countdownTicker: null, - recType: null, - stream: null, - mediaRecorder: null, - chunks: null, - blobSize: null, - maxUploadSize: null, - - // Capture webcam/microphone stream. - capture_user_media: function(mediaConstraints, successCallback, errorCallback) { - window.navigator.mediaDevices.getUserMedia(mediaConstraints).then(successCallback).catch(errorCallback); - }, - - // Add chunks of audio/video to array when made available. - handle_data_available: function(event) { - // Push recording slice to array. - cm.chunks.push(event.data); - // Size of all recorded data so far. - cm.blobSize += event.data.size; - - // If total size of recording so far exceeds max upload limit, stop recording. - // An extra condition exists to avoid displaying alert twice. - if (cm.blobSize >= cm.maxUploadSize) { - if (!window.localStorage.getItem('alerted')) { - window.localStorage.setItem('alerted', 'true'); - - cm.startStopBtn.simulate('click'); - am.show_alert('nearingmaxsize'); - } else { - window.localStorage.removeItem('alerted'); - } - - cm.chunks.pop(); - } - }, - - // Handle recording end. - handle_stop: function() { - // Set source of audio player. - var blob = new window.Blob(cm.chunks, {type: cm.mediaRecorder.mimeType}); - cm.player.set('srcObject', null); - cm.player.set('src', window.URL.createObjectURL(blob)); - - // Show audio player with controls enabled, and unmute. - cm.player.set('muted', false); - cm.player.set('controls', true); - cm.player.ancestor().ancestor().removeClass('hide'); - - // Show upload button. - cm.uploadBtn.ancestor().ancestor().removeClass('hide'); - cm.uploadBtn.set('textContent', M.util.get_string('attachrecording', 'atto_recordrtc')); - cm.uploadBtn.set('disabled', false); - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - - // Handle when upload button is clicked. - cm.uploadBtn.on('click', function() { - // Trigger error if no recording has been made. - if (cm.chunks.length === 0) { - am.show_alert('norecordingfound'); - } else { - cm.uploadBtn.set('disabled', true); - - // Upload recording to server. - cm.upload_to_server(cm.recType, function(progress, fileURLOrError) { - if (progress === 'ended') { // Insert annotation in text. - cm.uploadBtn.set('disabled', false); - cm.insert_annotation(cm.recType, fileURLOrError); - } else if (progress === 'upload-failed') { // Show error message in upload button. - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', - M.util.get_string('uploadfailed', 'atto_recordrtc') + ' ' + fileURLOrError); - } else if (progress === 'upload-failed-404') { // 404 error = File too large in Moodle. - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', M.util.get_string('uploadfailed404', 'atto_recordrtc')); - } else if (progress === 'upload-aborted') { - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', - M.util.get_string('uploadaborted', 'atto_recordrtc') + ' ' + fileURLOrError); - } else { - cm.uploadBtn.set('textContent', progress); - } - }); - } - }); - }, - - // Get everything set up to start recording. - start_recording: function(type, stream) { - // The options for the recording codecs and bitrates. - var options = am.select_rec_options(type); - cm.mediaRecorder = new window.MediaRecorder(stream, options); - - // Initialize MediaRecorder events and start recording. - cm.mediaRecorder.ondataavailable = cm.handle_data_available; - cm.mediaRecorder.onstop = cm.handle_stop; - cm.mediaRecorder.start(1000); // Capture in 1s chunks. Must be set to work with Firefox. - - // Mute audio, distracting while recording. - cm.player.set('muted', true); - - // Set recording timer to the time specified in the settings. - if (type === 'audio') { - cm.countdownSeconds = cm.editorScope.get('audiotimelimit'); - } else if (type === 'video') { - cm.countdownSeconds = cm.editorScope.get('videotimelimit'); - } else { - // Default timer. - cm.countdownSeconds = cm.editorScope.get('defaulttimelimit'); - } - cm.countdownSeconds++; - var timerText = M.util.get_string('stoprecording', 'atto_recordrtc'); - timerText += ' (:)'; - cm.startStopBtn.setHTML(timerText); - cm.set_time(); - cm.countdownTicker = window.setInterval(cm.set_time, 1000); - - // Make button clickable again, to allow stopping recording. - cm.startStopBtn.set('disabled', false); - }, - - // Get everything set up to stop recording. - stop_recording: function(stream) { - // Stop recording stream. - cm.mediaRecorder.stop(); - - // Stop each individual MediaTrack. - var tracks = stream.getTracks(); - for (var i = 0; i < tracks.length; i++) { - tracks[i].stop(); - } - }, - - getFileExtension: function(type) { - if (type === 'audio') { - if (window.MediaRecorder.isTypeSupported('audio/ogg')) { - return 'ogg'; - } else if (window.MediaRecorder.isTypeSupported('audio/mp4')) { - return 'mp4'; - } - } else { - if (window.MediaRecorder.isTypeSupported('audio/webm')) { - return 'webm'; - } else if (window.MediaRecorder.isTypeSupported('audio/mp4')) { - return 'mp4'; - } - } - - window.console.warn('Unknown file type for MediaRecorder API'); - return ''; - }, - - // Upload recorded audio/video to server. - upload_to_server: function(type, callback) { - var xhr = new window.XMLHttpRequest(); - var fileExtension = this.getFileExtension(type); - - // Get src media of audio/video tag. - xhr.open('GET', cm.player.get('src'), true); - xhr.responseType = 'blob'; - - xhr.onload = function() { - if (xhr.status === 200) { // If src media was successfully retrieved. - // blob is now the media that the audio/video tag's src pointed to. - var blob = this.response; - - // Generate filename with random ID and file extension. - var fileName = (Math.random() * 1000).toString().replace('.', ''); - fileName += (type === 'audio') ? '-audio.' + fileExtension - : '-video.' + fileExtension; - - // Create FormData to send to PHP filepicker-upload script. - var formData = new window.FormData(), - filepickerOptions = cm.editorScope.get('host').get('filepickeroptions').link, - repositoryKeys = window.Object.keys(filepickerOptions.repositories); - - formData.append('repo_upload_file', blob, fileName); - formData.append('itemid', filepickerOptions.itemid); - - for (var i = 0; i < repositoryKeys.length; i++) { - if (filepickerOptions.repositories[repositoryKeys[i]].type === 'upload') { - formData.append('repo_id', filepickerOptions.repositories[repositoryKeys[i]].id); - break; - } - } - - formData.append('env', filepickerOptions.env); - formData.append('sesskey', M.cfg.sesskey); - formData.append('client_id', filepickerOptions.client_id); - formData.append('savepath', '/'); - formData.append('ctx_id', filepickerOptions.context.id); - - // Pass FormData to PHP script using XHR. - var uploadEndpoint = M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload'; - cm.make_xmlhttprequest(uploadEndpoint, formData, - function(progress, responseText) { - if (progress === 'upload-ended') { - callback('ended', window.JSON.parse(responseText).url); - } else { - callback(progress); - } - } - ); - } - }; - - xhr.send(); - }, - - // Handle XHR sending/receiving/status. - make_xmlhttprequest: function(url, data, callback) { - var xhr = new window.XMLHttpRequest(); - - xhr.onreadystatechange = function() { - if ((xhr.readyState === 4) && (xhr.status === 200)) { // When request is finished and successful. - callback('upload-ended', xhr.responseText); - } else if (xhr.status === 404) { // When request returns 404 Not Found. - callback('upload-failed-404'); - } - }; - - xhr.upload.onprogress = function(event) { - callback(Math.round(event.loaded / event.total * 100) + "% " + M.util.get_string('uploadprogress', 'atto_recordrtc')); - }; - - xhr.upload.onerror = function(error) { - callback('upload-failed', error); - }; - - xhr.upload.onabort = function(error) { - callback('upload-aborted', error); - }; - - // POST FormData to PHP script that handles uploading/saving. - xhr.open('POST', url); - xhr.send(data); - }, - - // Makes 1min and 2s display as 1:02 on timer instead of 1:2, for example. - pad: function(val) { - var valString = val + ""; - - if (valString.length < 2) { - return "0" + valString; - } else { - return valString; - } - }, - - // Functionality to make recording timer count down. - // Also makes recording stop when time limit is hit. - set_time: function() { - cm.countdownSeconds--; - - cm.startStopBtn.one('span#seconds').set('textContent', cm.pad(cm.countdownSeconds % 60)); - cm.startStopBtn.one('span#minutes').set('textContent', cm.pad(window.parseInt(cm.countdownSeconds / 60, 10))); - - if (cm.countdownSeconds === 0) { - cm.startStopBtn.simulate('click'); - } - }, - - // Generates link to recorded annotation to be inserted. - create_annotation: function(type, recording_url) { - var html = ''; - if (type == 'audio') { - html = ""; - } else { // Must be video. - html += ""; - } - - return html; - }, - - // Inserts link to annotation in editor text area. - insert_annotation: function(type, recording_url) { - var annotation = cm.create_annotation(type, recording_url); - - // Insert annotation link. - // If user pressed "Cancel", just go back to main recording screen. - if (!annotation) { - cm.uploadBtn.set('textContent', M.util.get_string('attachrecording', 'atto_recordrtc')); - } else { - cm.editorScope.setLink(cm.editorScope, annotation); - } - } -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions for checking browser compatibility - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase */ - -// Scrutinizer CI directives. -/** global: M */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.compatcheckmodule = { - // Show alert and close plugin if browser does not support WebRTC at all. - check_has_gum: function() { - if (!(navigator.mediaDevices && window.MediaRecorder)) { - am.show_alert('nowebrtc', function() { - cm.editorScope.closeDialogue(cm.editorScope); - }); - } - }, - - // Notify and redirect user if plugin is used from insecure location. - check_secure: function() { - var isSecureOrigin = (window.location.protocol === 'https:') || - (window.location.host.indexOf('localhost') !== -1); - - if (!isSecureOrigin) { - cm.alertDanger.ancestor().ancestor().removeClass('hide'); - } - }, -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions for function abstractions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.abstractmodule = { - // A helper for making a Moodle alert appear. - // Subject is the content of the alert (which error ther alert is for). - // Possibility to add on-alert-close event. - show_alert: function(subject, onCloseEvent) { - Y.use('moodle-core-notification-alert', function() { - var dialogue = new M.core.alert({ - title: M.util.get_string(subject + '_title', 'atto_recordrtc'), - message: M.util.get_string(subject, 'atto_recordrtc') - }); - - if (onCloseEvent) { - dialogue.after('complete', onCloseEvent); - } - }); - }, - - // Handle getUserMedia errors. - handle_gum_errors: function(error, commonConfig) { - var btnLabel = M.util.get_string('recordingfailed', 'atto_recordrtc'), - treatAsStopped = function() { - commonConfig.onMediaStopped(btnLabel); - }; - - // Changes 'CertainError' -> 'gumcertain' to match language string names. - var stringName = 'gum' + error.name.replace('Error', '').toLowerCase(); - - // After alert, proceed to treat as stopped recording, or close dialogue. - if (stringName !== 'gumsecurity') { - am.show_alert(stringName, treatAsStopped); - } else { - am.show_alert(stringName, function() { - cm.editorScope.closeDialogue(cm.editorScope); - }); - } - }, - - // Select best options for the recording codec. - select_rec_options: function(recType) { - var types, options; - - if (recType === 'audio') { - types = [ - // Firefox supports webm and ogg but Chrome only supports ogg. - // So we use ogg to maximize the compatibility. - 'audio/ogg;codecs=opus', - - // Safari supports mp4. - 'audio/mp4;codecs=opus', - 'audio/mp4;codecs=wav', - 'audio/mp4;codecs=mp3', - ]; - options = { - audioBitsPerSecond: window.parseInt(cm.editorScope.get('audiobitrate')) - }; - } else { - types = [ - // Support webm as a preference. - // This container supports both vp9, and vp8. - // It does not support AVC1/h264 at all. - // It is supported by Chromium, and Firefox browsers, but not Safari. - 'video/webm;codecs=vp9,opus', - 'video/webm;codecs=vp8,opus', - - // Fall back to mp4 if webm is not available. - // The mp4 container supports v9, and h264 but neither of these are supported for recording on other - // browsers. - // In addition to this, we can record in v9, but VideoJS does not support an mp4 containern with v9 codec - // for playback. We leave it as a final option as a just-in-case. - 'video/mp4;codecs=h264,opus', - 'video/mp4;codecs=h264,wav', - 'video/mp4;codecs=v9,opus', - ]; - options = { - audioBitsPerSecond: window.parseInt(cm.editorScope.get('audiobitrate')), - videoBitsPerSecond: window.parseInt(cm.editorScope.get('videobitrate')) - }; - } - - var possibleTypes = types.reduce(function(result, type) { - result.push(type); - // Safari seems to use codecs: instead of codecs=. - // It is safe to add both, so we do, but we want them to remain in order. - result.push(type.replace('=', ':')); - return result; - }, []); - - var compatTypes = possibleTypes.filter(function(type) { - return window.MediaRecorder.isTypeSupported(type); - }); - - if (compatTypes.length !== 0) { - options.mimeType = compatTypes[0]; - } - - return options; - } -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule, - ccm = M.atto_recordrtc.compatcheckmodule; - -M.atto_recordrtc.audiomodule = { - init: function(scope) { - // Assignment of global variables. - cm.editorScope = scope; // Allows access to the editor's "this" context. - cm.alertWarning = Y.one('div#alert-warning'); - cm.alertDanger = Y.one('div#alert-danger'); - cm.player = Y.one('audio#player'); - cm.playerDOM = document.querySelector('audio#player'); - cm.startStopBtn = Y.one('button#start-stop'); - cm.uploadBtn = Y.one('button#upload'); - cm.recType = 'audio'; - cm.maxUploadSize = scope.get('maxrecsize'); - - // Show alert and close plugin if WebRTC is not supported. - ccm.check_has_gum(); - // Show alert and redirect user if connection is not secure. - ccm.check_secure(); - - // Run when user clicks on "record" button. - cm.startStopBtn.on('click', function() { - cm.startStopBtn.set('disabled', true); - - // If button is displaying "Start Recording" or "Record Again". - if ((cm.startStopBtn.get('textContent') === M.util.get_string('startrecording', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordagain', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'atto_recordrtc'))) { - // Make sure the audio player and upload button are not shown. - cm.player.ancestor().ancestor().addClass('hide'); - cm.uploadBtn.ancestor().ancestor().addClass('hide'); - - // Change look of recording button. - cm.startStopBtn.replaceClass('btn-outline-danger', 'btn-danger'); - - // Empty the array containing the previously recorded chunks. - cm.chunks = []; - cm.blobSize = 0; - cm.uploadBtn.detach('click'); - - // Initialize common configurations. - var commonConfig = { - // When the stream is captured from the microphone/webcam. - onMediaCaptured: function(stream) { - // Make audio stream available at a higher level by making it a property of the common module. - cm.stream = stream; - - cm.start_recording(cm.recType, cm.stream); - }, - - // Revert button to "Record Again" when recording is stopped. - onMediaStopped: function(btnLabel) { - cm.startStopBtn.set('textContent', btnLabel); - cm.startStopBtn.set('disabled', false); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - }, - - // Handle recording errors. - onMediaCapturingFailed: function(error) { - am.handle_gum_errors(error, commonConfig); - } - }; - - // Capture audio stream from microphone. - M.atto_recordrtc.audiomodule.capture_audio(commonConfig); - } else { // If button is displaying "Stop Recording". - // First of all clears the countdownTicker. - window.clearInterval(cm.countdownTicker); - - // Disable "Record Again" button for 1s to allow background processing (closing streams). - window.setTimeout(function() { - cm.startStopBtn.set('disabled', false); - }, 1000); - - // Stop recording. - cm.stop_recording(cm.stream); - - // Change button to offer to record again. - cm.startStopBtn.set('textContent', M.util.get_string('recordagain', 'atto_recordrtc')); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - } - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - }); - }, - - // Setup to get audio stream from microphone. - capture_audio: function(config) { - cm.capture_user_media( - // Media constraints. - { - audio: true - }, - - // Success callback. - function(audioStream) { - // Set audio player source to microphone stream. - cm.playerDOM.srcObject = audioStream; - - config.onMediaCaptured(audioStream); - }, - - // Error callback. - function(error) { - config.onMediaCapturingFailed(error); - } - ); - } -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule, - ccm = M.atto_recordrtc.compatcheckmodule; - -M.atto_recordrtc.videomodule = { - init: function(scope) { - // Assignment of global variables. - cm.editorScope = scope; // Allows access to the editor's "this" context. - cm.alertWarning = Y.one('div#alert-warning'); - cm.alertDanger = Y.one('div#alert-danger'); - cm.player = Y.one('video#player'); - cm.playerDOM = document.querySelector('video#player'); - cm.startStopBtn = Y.one('button#start-stop'); - cm.uploadBtn = Y.one('button#upload'); - cm.recType = 'video'; - cm.maxUploadSize = scope.get('maxrecsize'); - - // Show alert and close plugin if WebRTC is not supported. - ccm.check_has_gum(); - // Show alert and redirect user if connection is not secure. - ccm.check_secure(); - - // Run when user clicks on "record" button. - cm.startStopBtn.on('click', function() { - cm.startStopBtn.set('disabled', true); - - // If button is displaying "Start Recording" or "Record Again". - if ((cm.startStopBtn.get('textContent') === M.util.get_string('startrecording', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordagain', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'atto_recordrtc'))) { - // Make sure the upload button is not shown. - cm.uploadBtn.ancestor().ancestor().addClass('hide'); - - // Change look of recording button. - cm.startStopBtn.replaceClass('btn-outline-danger', 'btn-danger'); - - // Empty the array containing the previously recorded chunks. - cm.chunks = []; - cm.blobSize = 0; - cm.uploadBtn.detach('click'); - - // Initialize common configurations. - var commonConfig = { - // When the stream is captured from the microphone/webcam. - onMediaCaptured: function(stream) { - // Make video stream available at a higher level by making it a property of the common module. - cm.stream = stream; - - cm.start_recording(cm.recType, cm.stream); - }, - - // Revert button to "Record Again" when recording is stopped. - onMediaStopped: function(btnLabel) { - cm.startStopBtn.set('textContent', btnLabel); - cm.startStopBtn.set('disabled', false); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - }, - - // Handle recording errors. - onMediaCapturingFailed: function(error) { - am.handle_gum_errors(error, commonConfig); - } - }; - - // Show video tag without controls to view webcam stream. - cm.player.ancestor().ancestor().removeClass('hide'); - cm.player.set('controls', false); - - // Capture audio+video stream from webcam/microphone. - M.atto_recordrtc.videomodule.capture_audio_video(commonConfig); - } else { // If button is displaying "Stop Recording". - // First of all clears the countdownTicker. - window.clearInterval(cm.countdownTicker); - - // Disable "Record Again" button for 1s to allow background processing (closing streams). - window.setTimeout(function() { - cm.startStopBtn.set('disabled', false); - }, 1000); - - // Stop recording. - cm.stop_recording(cm.stream); - - // Change button to offer to record again. - cm.startStopBtn.set('textContent', M.util.get_string('recordagain', 'atto_recordrtc')); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - } - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - }); - }, - - // Setup to get audio+video stream from microphone/webcam. - capture_audio_video: function(config) { - cm.capture_user_media( - // Media constraints. - { - audio: true, - video: { - width: {ideal: 640}, - height: {ideal: 480} - } - }, - - // Success callback. - function(audioVideoStream) { - // Set video player source to microphone+webcam stream, and play it back as it's recording. - cm.playerDOM.srcObject = audioVideoStream; - cm.playerDOM.play(); - - config.onMediaCaptured(audioVideoStream); - }, - - // Error callback. - function(error) { - config.onMediaCapturingFailed(error); - } - ); - } -}; - - -}, '@VERSION@', {"requires": ["moodle-atto_recordrtc-button"]}); diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-min.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-min.js deleted file mode 100644 index 27b3cf0fc92..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording-min.js +++ /dev/null @@ -1,2 +0,0 @@ -YUI.add("moodle-atto_recordrtc-recording",function(r,t){var l,n,e;M.atto_recordrtc=M.atto_recordrtc||{},l=M.atto_recordrtc.commonmodule,n=M.atto_recordrtc.abstractmodule,M.atto_recordrtc.commonmodule={editorScope:null,alertWarning:null,alertDanger:null,player:null,playerDOM:null,startStopBtn:null,uploadBtn:null,countdownSeconds:null,countdownTicker:null,recType:null,stream:null,mediaRecorder:null,chunks:null,blobSize:null,maxUploadSize:null,capture_user_media:function(t,e,o){window.navigator.mediaDevices.getUserMedia(t).then(e)["catch"](o)},handle_data_available:function(t){l.chunks.push(t.data),l.blobSize+=t.data.size,l.blobSize>=l.maxUploadSize&&(window.localStorage.getItem("alerted")?window.localStorage.removeItem("alerted"):(window.localStorage.setItem("alerted","true"),l.startStopBtn.simulate("click"),n.show_alert("nearingmaxsize")),l.chunks.pop())},handle_stop:function(){var t=new window.Blob(l.chunks,{type:l.mediaRecorder.mimeType});l.player.set("srcObject",null),l.player.set("src",window.URL.createObjectURL(t)),l.player.set("muted",!1),l.player.set("controls",!0),l.player.ancestor().ancestor().removeClass("hide"),l.uploadBtn.ancestor().ancestor().removeClass("hide"),l.uploadBtn.set("textContent",M.util.get_string("attachrecording","atto_recordrtc")),l.uploadBtn.set("disabled",!1),l.editorScope.getDialogue().centered(),l.uploadBtn.on("click",function(){0===l.chunks.length?n.show_alert("norecordingfound"):(l.uploadBtn.set("disabled",!0),l.upload_to_server(l.recType,function(t,e){"ended"===t?(l.uploadBtn.set("disabled",!1),l.insert_annotation(l.recType,e)):"upload-failed"===t?(l.uploadBtn.set("disabled",!1),l.uploadBtn.set("textContent",M.util.get_string("uploadfailed","atto_recordrtc")+" "+e)):"upload-failed-404"===t?(l.uploadBtn.set("disabled",!1),l.uploadBtn.set("textContent",M.util.get_string("uploadfailed404","atto_recordrtc"))):"upload-aborted"===t?(l.uploadBtn.set("disabled",!1),l.uploadBtn.set("textContent",M.util.get_string("uploadaborted","atto_recordrtc")+" "+e)):l.uploadBtn.set("textContent",t)}))})},start_recording:function(t,e){var o=n.select_rec_options(t);l.mediaRecorder=new window.MediaRecorder(e,o),l.mediaRecorder.ondataavailable=l.handle_data_available,l.mediaRecorder.onstop=l.handle_stop,l.mediaRecorder.start(1e3),l.player.set("muted",!0),l.countdownSeconds="audio"===t?l.editorScope.get("audiotimelimit"):"video"===t?l.editorScope.get("videotimelimit"):l.editorScope.get("defaulttimelimit"),l.countdownSeconds++,e=M.util.get_string("stoprecording","atto_recordrtc"),l.startStopBtn.setHTML(e+=' (:)'),l.set_time(),l.countdownTicker=window.setInterval(l.set_time,1e3),l.startStopBtn.set("disabled",!1)},stop_recording:function(t){var e,o;for(l.mediaRecorder.stop(),e=t.getTracks(),o=0;o":"")},insert_annotation:function(t,e){t=l.create_annotation(t,e);t?l.editorScope.setLink(l.editorScope,t):l.uploadBtn.set("textContent",M.util.get_string("attachrecording","atto_recordrtc"))}},M.atto_recordrtc=M.atto_recordrtc||{},l=M.atto_recordrtc.commonmodule,n=M.atto_recordrtc.abstractmodule,M.atto_recordrtc.compatcheckmodule={check_has_gum:function(){navigator.mediaDevices&&window.MediaRecorder||n.show_alert("nowebrtc",function(){l.editorScope.closeDialogue(l.editorScope)})},check_secure:function(){"https:"===window.location.protocol||-1!==window.location.host.indexOf("localhost")||l.alertDanger.ancestor().ancestor().removeClass("hide")}},M.atto_recordrtc=M.atto_recordrtc||{},l=M.atto_recordrtc.commonmodule,n=M.atto_recordrtc.abstractmodule,M.atto_recordrtc.abstractmodule={show_alert:function(e,o){r.use("moodle-core-notification-alert",function(){var t=new M.core.alert({ -title:M.util.get_string(e+"_title","atto_recordrtc"),message:M.util.get_string(e,"atto_recordrtc")});o&&t.after("complete",o)})},handle_gum_errors:function(t,e){var o=M.util.get_string("recordingfailed","atto_recordrtc"),r=function(){e.onMediaStopped(o)},t="gum"+t.name.replace("Error","").toLowerCase();"gumsecurity"!=t?n.show_alert(t,r):n.show_alert(t,function(){l.editorScope.closeDialogue(l.editorScope)})},select_rec_options:function(t){var t="audio"===t?(e=["audio/ogg;codecs=opus","audio/mp4;codecs=opus","audio/mp4;codecs=wav","audio/mp4;codecs=mp3"],{audioBitsPerSecond:window.parseInt(l.editorScope.get("audiobitrate"))}):(e=["video/webm;codecs=vp9,opus","video/webm;codecs=vp8,opus","video/mp4;codecs=h264,opus","video/mp4;codecs=h264,wav","video/mp4;codecs=v9,opus"],{audioBitsPerSecond:window.parseInt(l.editorScope.get("audiobitrate")),videoBitsPerSecond:window.parseInt(l.editorScope.get("videobitrate"))}),e=e.reduce(function(t,e){return t.push(e),t.push(e.replace("=",":")),t},[]).filter(function(t){return window.MediaRecorder.isTypeSupported(t)});return 0!==e.length&&(t.mimeType=e[0]),t}},M.atto_recordrtc=M.atto_recordrtc||{},l=M.atto_recordrtc.commonmodule,n=M.atto_recordrtc.abstractmodule,e=M.atto_recordrtc.compatcheckmodule,M.atto_recordrtc.audiomodule={init:function(t){l.editorScope=t,l.alertWarning=r.one("div#alert-warning"),l.alertDanger=r.one("div#alert-danger"),l.player=r.one("audio#player"),l.playerDOM=document.querySelector("audio#player"),l.startStopBtn=r.one("button#start-stop"),l.uploadBtn=r.one("button#upload"),l.recType="audio",l.maxUploadSize=t.get("maxrecsize"),e.check_has_gum(),e.check_secure(),l.startStopBtn.on("click",function(){var e;l.startStopBtn.set("disabled",!0),l.startStopBtn.get("textContent")===M.util.get_string("startrecording","atto_recordrtc")||l.startStopBtn.get("textContent")===M.util.get_string("recordagain","atto_recordrtc")||l.startStopBtn.get("textContent")===M.util.get_string("recordingfailed","atto_recordrtc")?(l.player.ancestor().ancestor().addClass("hide"),l.uploadBtn.ancestor().ancestor().addClass("hide"),l.startStopBtn.replaceClass("btn-outline-danger","btn-danger"),l.chunks=[],l.blobSize=0,l.uploadBtn.detach("click"),e={onMediaCaptured:function(t){l.stream=t,l.start_recording(l.recType,l.stream)},onMediaStopped:function(t){l.startStopBtn.set("textContent",t),l.startStopBtn.set("disabled",!1),l.startStopBtn.replaceClass("btn-danger","btn-outline-danger")},onMediaCapturingFailed:function(t){n.handle_gum_errors(t,e)}},M.atto_recordrtc.audiomodule.capture_audio(e)):(window.clearInterval(l.countdownTicker),window.setTimeout(function(){l.startStopBtn.set("disabled",!1)},1e3),l.stop_recording(l.stream),l.startStopBtn.set("textContent",M.util.get_string("recordagain","atto_recordrtc")),l.startStopBtn.replaceClass("btn-danger","btn-outline-danger")),l.editorScope.getDialogue().centered()})},capture_audio:function(e){l.capture_user_media({audio:!0},function(t){l.playerDOM.srcObject=t,e.onMediaCaptured(t)},function(t){e.onMediaCapturingFailed(t)})}},M.atto_recordrtc=M.atto_recordrtc||{},l=M.atto_recordrtc.commonmodule,n=M.atto_recordrtc.abstractmodule,e=M.atto_recordrtc.compatcheckmodule,M.atto_recordrtc.videomodule={init:function(t){l.editorScope=t,l.alertWarning=r.one("div#alert-warning"),l.alertDanger=r.one("div#alert-danger"),l.player=r.one("video#player"),l.playerDOM=document.querySelector("video#player"),l.startStopBtn=r.one("button#start-stop"),l.uploadBtn=r.one("button#upload"),l.recType="video",l.maxUploadSize=t.get("maxrecsize"),e.check_has_gum(),e.check_secure(),l.startStopBtn.on("click",function(){var e;l.startStopBtn.set("disabled",!0),l.startStopBtn.get("textContent")===M.util.get_string("startrecording","atto_recordrtc")||l.startStopBtn.get("textContent")===M.util.get_string("recordagain","atto_recordrtc")||l.startStopBtn.get("textContent")===M.util.get_string("recordingfailed","atto_recordrtc")?(l.uploadBtn.ancestor().ancestor().addClass("hide"),l.startStopBtn.replaceClass("btn-outline-danger","btn-danger"),l.chunks=[],l.blobSize=0,l.uploadBtn.detach("click"),e={onMediaCaptured:function(t){l.stream=t,l.start_recording(l.recType,l.stream)},onMediaStopped:function(t){l.startStopBtn.set("textContent",t),l.startStopBtn.set("disabled",!1),l.startStopBtn.replaceClass("btn-danger","btn-outline-danger")},onMediaCapturingFailed:function(t){n.handle_gum_errors(t,e)}},l.player.ancestor().ancestor().removeClass("hide"),l.player.set("controls",!1),M.atto_recordrtc.videomodule.capture_audio_video(e)):(window.clearInterval(l.countdownTicker),window.setTimeout(function(){l.startStopBtn.set("disabled",!1)},1e3),l.stop_recording(l.stream),l.startStopBtn.set("textContent",M.util.get_string("recordagain","atto_recordrtc")),l.startStopBtn.replaceClass("btn-danger","btn-outline-danger")),l.editorScope.getDialogue().centered()})},capture_audio_video:function(e){l.capture_user_media({audio:!0,video:{width:{ideal:640},height:{ideal:480}}},function(t){l.playerDOM.srcObject=t,l.playerDOM.play(),e.onMediaCaptured(t)},function(t){e.onMediaCapturingFailed(t)})}}},"@VERSION@",{requires:["moodle-atto_recordrtc-button"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording.js deleted file mode 100644 index 691a99c55da..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-recording/moodle-atto_recordrtc-recording.js +++ /dev/null @@ -1,855 +0,0 @@ -YUI.add('moodle-atto_recordrtc-recording', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, no-alert, spaced-comment */ - -// JSHint directives. -/*global M */ -/*jshint es5: true */ -/*jshint onevar: false */ -/*jshint shadow: true */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to M.atto_recordrtc.commonmodule namespace. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.commonmodule = { - // Unitialized variables to be used by the other modules. - editorScope: null, - alertWarning: null, - alertDanger: null, - player: null, - playerDOM: null, // Used to manipulate DOM directly. - startStopBtn: null, - uploadBtn: null, - countdownSeconds: null, - countdownTicker: null, - recType: null, - stream: null, - mediaRecorder: null, - chunks: null, - blobSize: null, - maxUploadSize: null, - - // Capture webcam/microphone stream. - capture_user_media: function(mediaConstraints, successCallback, errorCallback) { - window.navigator.mediaDevices.getUserMedia(mediaConstraints).then(successCallback).catch(errorCallback); - }, - - // Add chunks of audio/video to array when made available. - handle_data_available: function(event) { - // Push recording slice to array. - cm.chunks.push(event.data); - // Size of all recorded data so far. - cm.blobSize += event.data.size; - - // If total size of recording so far exceeds max upload limit, stop recording. - // An extra condition exists to avoid displaying alert twice. - if (cm.blobSize >= cm.maxUploadSize) { - if (!window.localStorage.getItem('alerted')) { - window.localStorage.setItem('alerted', 'true'); - - cm.startStopBtn.simulate('click'); - am.show_alert('nearingmaxsize'); - } else { - window.localStorage.removeItem('alerted'); - } - - cm.chunks.pop(); - } - }, - - // Handle recording end. - handle_stop: function() { - // Set source of audio player. - var blob = new window.Blob(cm.chunks, {type: cm.mediaRecorder.mimeType}); - cm.player.set('srcObject', null); - cm.player.set('src', window.URL.createObjectURL(blob)); - - // Show audio player with controls enabled, and unmute. - cm.player.set('muted', false); - cm.player.set('controls', true); - cm.player.ancestor().ancestor().removeClass('hide'); - - // Show upload button. - cm.uploadBtn.ancestor().ancestor().removeClass('hide'); - cm.uploadBtn.set('textContent', M.util.get_string('attachrecording', 'atto_recordrtc')); - cm.uploadBtn.set('disabled', false); - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - - // Handle when upload button is clicked. - cm.uploadBtn.on('click', function() { - // Trigger error if no recording has been made. - if (cm.chunks.length === 0) { - am.show_alert('norecordingfound'); - } else { - cm.uploadBtn.set('disabled', true); - - // Upload recording to server. - cm.upload_to_server(cm.recType, function(progress, fileURLOrError) { - if (progress === 'ended') { // Insert annotation in text. - cm.uploadBtn.set('disabled', false); - cm.insert_annotation(cm.recType, fileURLOrError); - } else if (progress === 'upload-failed') { // Show error message in upload button. - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', - M.util.get_string('uploadfailed', 'atto_recordrtc') + ' ' + fileURLOrError); - } else if (progress === 'upload-failed-404') { // 404 error = File too large in Moodle. - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', M.util.get_string('uploadfailed404', 'atto_recordrtc')); - } else if (progress === 'upload-aborted') { - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', - M.util.get_string('uploadaborted', 'atto_recordrtc') + ' ' + fileURLOrError); - } else { - cm.uploadBtn.set('textContent', progress); - } - }); - } - }); - }, - - // Get everything set up to start recording. - start_recording: function(type, stream) { - // The options for the recording codecs and bitrates. - var options = am.select_rec_options(type); - cm.mediaRecorder = new window.MediaRecorder(stream, options); - - // Initialize MediaRecorder events and start recording. - cm.mediaRecorder.ondataavailable = cm.handle_data_available; - cm.mediaRecorder.onstop = cm.handle_stop; - cm.mediaRecorder.start(1000); // Capture in 1s chunks. Must be set to work with Firefox. - - // Mute audio, distracting while recording. - cm.player.set('muted', true); - - // Set recording timer to the time specified in the settings. - if (type === 'audio') { - cm.countdownSeconds = cm.editorScope.get('audiotimelimit'); - } else if (type === 'video') { - cm.countdownSeconds = cm.editorScope.get('videotimelimit'); - } else { - // Default timer. - cm.countdownSeconds = cm.editorScope.get('defaulttimelimit'); - } - cm.countdownSeconds++; - var timerText = M.util.get_string('stoprecording', 'atto_recordrtc'); - timerText += ' (:)'; - cm.startStopBtn.setHTML(timerText); - cm.set_time(); - cm.countdownTicker = window.setInterval(cm.set_time, 1000); - - // Make button clickable again, to allow stopping recording. - cm.startStopBtn.set('disabled', false); - }, - - // Get everything set up to stop recording. - stop_recording: function(stream) { - // Stop recording stream. - cm.mediaRecorder.stop(); - - // Stop each individual MediaTrack. - var tracks = stream.getTracks(); - for (var i = 0; i < tracks.length; i++) { - tracks[i].stop(); - } - }, - - getFileExtension: function(type) { - if (type === 'audio') { - if (window.MediaRecorder.isTypeSupported('audio/ogg')) { - return 'ogg'; - } else if (window.MediaRecorder.isTypeSupported('audio/mp4')) { - return 'mp4'; - } - } else { - if (window.MediaRecorder.isTypeSupported('audio/webm')) { - return 'webm'; - } else if (window.MediaRecorder.isTypeSupported('audio/mp4')) { - return 'mp4'; - } - } - - window.console.warn('Unknown file type for MediaRecorder API'); - return ''; - }, - - // Upload recorded audio/video to server. - upload_to_server: function(type, callback) { - var xhr = new window.XMLHttpRequest(); - var fileExtension = this.getFileExtension(type); - - // Get src media of audio/video tag. - xhr.open('GET', cm.player.get('src'), true); - xhr.responseType = 'blob'; - - xhr.onload = function() { - if (xhr.status === 200) { // If src media was successfully retrieved. - // blob is now the media that the audio/video tag's src pointed to. - var blob = this.response; - - // Generate filename with random ID and file extension. - var fileName = (Math.random() * 1000).toString().replace('.', ''); - fileName += (type === 'audio') ? '-audio.' + fileExtension - : '-video.' + fileExtension; - - // Create FormData to send to PHP filepicker-upload script. - var formData = new window.FormData(), - filepickerOptions = cm.editorScope.get('host').get('filepickeroptions').link, - repositoryKeys = window.Object.keys(filepickerOptions.repositories); - - formData.append('repo_upload_file', blob, fileName); - formData.append('itemid', filepickerOptions.itemid); - - for (var i = 0; i < repositoryKeys.length; i++) { - if (filepickerOptions.repositories[repositoryKeys[i]].type === 'upload') { - formData.append('repo_id', filepickerOptions.repositories[repositoryKeys[i]].id); - break; - } - } - - formData.append('env', filepickerOptions.env); - formData.append('sesskey', M.cfg.sesskey); - formData.append('client_id', filepickerOptions.client_id); - formData.append('savepath', '/'); - formData.append('ctx_id', filepickerOptions.context.id); - - // Pass FormData to PHP script using XHR. - var uploadEndpoint = M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload'; - cm.make_xmlhttprequest(uploadEndpoint, formData, - function(progress, responseText) { - if (progress === 'upload-ended') { - callback('ended', window.JSON.parse(responseText).url); - } else { - callback(progress); - } - } - ); - } - }; - - xhr.send(); - }, - - // Handle XHR sending/receiving/status. - make_xmlhttprequest: function(url, data, callback) { - var xhr = new window.XMLHttpRequest(); - - xhr.onreadystatechange = function() { - if ((xhr.readyState === 4) && (xhr.status === 200)) { // When request is finished and successful. - callback('upload-ended', xhr.responseText); - } else if (xhr.status === 404) { // When request returns 404 Not Found. - callback('upload-failed-404'); - } - }; - - xhr.upload.onprogress = function(event) { - callback(Math.round(event.loaded / event.total * 100) + "% " + M.util.get_string('uploadprogress', 'atto_recordrtc')); - }; - - xhr.upload.onerror = function(error) { - callback('upload-failed', error); - }; - - xhr.upload.onabort = function(error) { - callback('upload-aborted', error); - }; - - // POST FormData to PHP script that handles uploading/saving. - xhr.open('POST', url); - xhr.send(data); - }, - - // Makes 1min and 2s display as 1:02 on timer instead of 1:2, for example. - pad: function(val) { - var valString = val + ""; - - if (valString.length < 2) { - return "0" + valString; - } else { - return valString; - } - }, - - // Functionality to make recording timer count down. - // Also makes recording stop when time limit is hit. - set_time: function() { - cm.countdownSeconds--; - - cm.startStopBtn.one('span#seconds').set('textContent', cm.pad(cm.countdownSeconds % 60)); - cm.startStopBtn.one('span#minutes').set('textContent', cm.pad(window.parseInt(cm.countdownSeconds / 60, 10))); - - if (cm.countdownSeconds === 0) { - cm.startStopBtn.simulate('click'); - } - }, - - // Generates link to recorded annotation to be inserted. - create_annotation: function(type, recording_url) { - var html = ''; - if (type == 'audio') { - html = ""; - } else { // Must be video. - html += ""; - } - - return html; - }, - - // Inserts link to annotation in editor text area. - insert_annotation: function(type, recording_url) { - var annotation = cm.create_annotation(type, recording_url); - - // Insert annotation link. - // If user pressed "Cancel", just go back to main recording screen. - if (!annotation) { - cm.uploadBtn.set('textContent', M.util.get_string('attachrecording', 'atto_recordrtc')); - } else { - cm.editorScope.setLink(cm.editorScope, annotation); - } - } -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions for checking browser compatibility - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase */ - -// Scrutinizer CI directives. -/** global: M */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.compatcheckmodule = { - // Show alert and close plugin if browser does not support WebRTC at all. - check_has_gum: function() { - if (!(navigator.mediaDevices && window.MediaRecorder)) { - am.show_alert('nowebrtc', function() { - cm.editorScope.closeDialogue(cm.editorScope); - }); - } - }, - - // Notify and redirect user if plugin is used from insecure location. - check_secure: function() { - var isSecureOrigin = (window.location.protocol === 'https:') || - (window.location.host.indexOf('localhost') !== -1); - - if (!isSecureOrigin) { - cm.alertDanger.ancestor().ancestor().removeClass('hide'); - } - }, -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions for function abstractions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.abstractmodule = { - // A helper for making a Moodle alert appear. - // Subject is the content of the alert (which error ther alert is for). - // Possibility to add on-alert-close event. - show_alert: function(subject, onCloseEvent) { - Y.use('moodle-core-notification-alert', function() { - var dialogue = new M.core.alert({ - title: M.util.get_string(subject + '_title', 'atto_recordrtc'), - message: M.util.get_string(subject, 'atto_recordrtc') - }); - - if (onCloseEvent) { - dialogue.after('complete', onCloseEvent); - } - }); - }, - - // Handle getUserMedia errors. - handle_gum_errors: function(error, commonConfig) { - var btnLabel = M.util.get_string('recordingfailed', 'atto_recordrtc'), - treatAsStopped = function() { - commonConfig.onMediaStopped(btnLabel); - }; - - // Changes 'CertainError' -> 'gumcertain' to match language string names. - var stringName = 'gum' + error.name.replace('Error', '').toLowerCase(); - - // After alert, proceed to treat as stopped recording, or close dialogue. - if (stringName !== 'gumsecurity') { - am.show_alert(stringName, treatAsStopped); - } else { - am.show_alert(stringName, function() { - cm.editorScope.closeDialogue(cm.editorScope); - }); - } - }, - - // Select best options for the recording codec. - select_rec_options: function(recType) { - var types, options; - - if (recType === 'audio') { - types = [ - // Firefox supports webm and ogg but Chrome only supports ogg. - // So we use ogg to maximize the compatibility. - 'audio/ogg;codecs=opus', - - // Safari supports mp4. - 'audio/mp4;codecs=opus', - 'audio/mp4;codecs=wav', - 'audio/mp4;codecs=mp3', - ]; - options = { - audioBitsPerSecond: window.parseInt(cm.editorScope.get('audiobitrate')) - }; - } else { - types = [ - // Support webm as a preference. - // This container supports both vp9, and vp8. - // It does not support AVC1/h264 at all. - // It is supported by Chromium, and Firefox browsers, but not Safari. - 'video/webm;codecs=vp9,opus', - 'video/webm;codecs=vp8,opus', - - // Fall back to mp4 if webm is not available. - // The mp4 container supports v9, and h264 but neither of these are supported for recording on other - // browsers. - // In addition to this, we can record in v9, but VideoJS does not support an mp4 containern with v9 codec - // for playback. We leave it as a final option as a just-in-case. - 'video/mp4;codecs=h264,opus', - 'video/mp4;codecs=h264,wav', - 'video/mp4;codecs=v9,opus', - ]; - options = { - audioBitsPerSecond: window.parseInt(cm.editorScope.get('audiobitrate')), - videoBitsPerSecond: window.parseInt(cm.editorScope.get('videobitrate')) - }; - } - - var possibleTypes = types.reduce(function(result, type) { - result.push(type); - // Safari seems to use codecs: instead of codecs=. - // It is safe to add both, so we do, but we want them to remain in order. - result.push(type.replace('=', ':')); - return result; - }, []); - - var compatTypes = possibleTypes.filter(function(type) { - return window.MediaRecorder.isTypeSupported(type); - }); - - if (compatTypes.length !== 0) { - options.mimeType = compatTypes[0]; - } - - return options; - } -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule, - ccm = M.atto_recordrtc.compatcheckmodule; - -M.atto_recordrtc.audiomodule = { - init: function(scope) { - // Assignment of global variables. - cm.editorScope = scope; // Allows access to the editor's "this" context. - cm.alertWarning = Y.one('div#alert-warning'); - cm.alertDanger = Y.one('div#alert-danger'); - cm.player = Y.one('audio#player'); - cm.playerDOM = document.querySelector('audio#player'); - cm.startStopBtn = Y.one('button#start-stop'); - cm.uploadBtn = Y.one('button#upload'); - cm.recType = 'audio'; - cm.maxUploadSize = scope.get('maxrecsize'); - - // Show alert and close plugin if WebRTC is not supported. - ccm.check_has_gum(); - // Show alert and redirect user if connection is not secure. - ccm.check_secure(); - - // Run when user clicks on "record" button. - cm.startStopBtn.on('click', function() { - cm.startStopBtn.set('disabled', true); - - // If button is displaying "Start Recording" or "Record Again". - if ((cm.startStopBtn.get('textContent') === M.util.get_string('startrecording', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordagain', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'atto_recordrtc'))) { - // Make sure the audio player and upload button are not shown. - cm.player.ancestor().ancestor().addClass('hide'); - cm.uploadBtn.ancestor().ancestor().addClass('hide'); - - // Change look of recording button. - cm.startStopBtn.replaceClass('btn-outline-danger', 'btn-danger'); - - // Empty the array containing the previously recorded chunks. - cm.chunks = []; - cm.blobSize = 0; - cm.uploadBtn.detach('click'); - - // Initialize common configurations. - var commonConfig = { - // When the stream is captured from the microphone/webcam. - onMediaCaptured: function(stream) { - // Make audio stream available at a higher level by making it a property of the common module. - cm.stream = stream; - - cm.start_recording(cm.recType, cm.stream); - }, - - // Revert button to "Record Again" when recording is stopped. - onMediaStopped: function(btnLabel) { - cm.startStopBtn.set('textContent', btnLabel); - cm.startStopBtn.set('disabled', false); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - }, - - // Handle recording errors. - onMediaCapturingFailed: function(error) { - am.handle_gum_errors(error, commonConfig); - } - }; - - // Capture audio stream from microphone. - M.atto_recordrtc.audiomodule.capture_audio(commonConfig); - } else { // If button is displaying "Stop Recording". - // First of all clears the countdownTicker. - window.clearInterval(cm.countdownTicker); - - // Disable "Record Again" button for 1s to allow background processing (closing streams). - window.setTimeout(function() { - cm.startStopBtn.set('disabled', false); - }, 1000); - - // Stop recording. - cm.stop_recording(cm.stream); - - // Change button to offer to record again. - cm.startStopBtn.set('textContent', M.util.get_string('recordagain', 'atto_recordrtc')); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - } - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - }); - }, - - // Setup to get audio stream from microphone. - capture_audio: function(config) { - cm.capture_user_media( - // Media constraints. - { - audio: true - }, - - // Success callback. - function(audioStream) { - // Set audio player source to microphone stream. - cm.playerDOM.srcObject = audioStream; - - config.onMediaCaptured(audioStream); - }, - - // Error callback. - function(error) { - config.onMediaCapturingFailed(error); - } - ); - } -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule, - ccm = M.atto_recordrtc.compatcheckmodule; - -M.atto_recordrtc.videomodule = { - init: function(scope) { - // Assignment of global variables. - cm.editorScope = scope; // Allows access to the editor's "this" context. - cm.alertWarning = Y.one('div#alert-warning'); - cm.alertDanger = Y.one('div#alert-danger'); - cm.player = Y.one('video#player'); - cm.playerDOM = document.querySelector('video#player'); - cm.startStopBtn = Y.one('button#start-stop'); - cm.uploadBtn = Y.one('button#upload'); - cm.recType = 'video'; - cm.maxUploadSize = scope.get('maxrecsize'); - - // Show alert and close plugin if WebRTC is not supported. - ccm.check_has_gum(); - // Show alert and redirect user if connection is not secure. - ccm.check_secure(); - - // Run when user clicks on "record" button. - cm.startStopBtn.on('click', function() { - cm.startStopBtn.set('disabled', true); - - // If button is displaying "Start Recording" or "Record Again". - if ((cm.startStopBtn.get('textContent') === M.util.get_string('startrecording', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordagain', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'atto_recordrtc'))) { - // Make sure the upload button is not shown. - cm.uploadBtn.ancestor().ancestor().addClass('hide'); - - // Change look of recording button. - cm.startStopBtn.replaceClass('btn-outline-danger', 'btn-danger'); - - // Empty the array containing the previously recorded chunks. - cm.chunks = []; - cm.blobSize = 0; - cm.uploadBtn.detach('click'); - - // Initialize common configurations. - var commonConfig = { - // When the stream is captured from the microphone/webcam. - onMediaCaptured: function(stream) { - // Make video stream available at a higher level by making it a property of the common module. - cm.stream = stream; - - cm.start_recording(cm.recType, cm.stream); - }, - - // Revert button to "Record Again" when recording is stopped. - onMediaStopped: function(btnLabel) { - cm.startStopBtn.set('textContent', btnLabel); - cm.startStopBtn.set('disabled', false); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - }, - - // Handle recording errors. - onMediaCapturingFailed: function(error) { - am.handle_gum_errors(error, commonConfig); - } - }; - - // Show video tag without controls to view webcam stream. - cm.player.ancestor().ancestor().removeClass('hide'); - cm.player.set('controls', false); - - // Capture audio+video stream from webcam/microphone. - M.atto_recordrtc.videomodule.capture_audio_video(commonConfig); - } else { // If button is displaying "Stop Recording". - // First of all clears the countdownTicker. - window.clearInterval(cm.countdownTicker); - - // Disable "Record Again" button for 1s to allow background processing (closing streams). - window.setTimeout(function() { - cm.startStopBtn.set('disabled', false); - }, 1000); - - // Stop recording. - cm.stop_recording(cm.stream); - - // Change button to offer to record again. - cm.startStopBtn.set('textContent', M.util.get_string('recordagain', 'atto_recordrtc')); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - } - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - }); - }, - - // Setup to get audio+video stream from microphone/webcam. - capture_audio_video: function(config) { - cm.capture_user_media( - // Media constraints. - { - audio: true, - video: { - width: {ideal: 640}, - height: {ideal: 480} - } - }, - - // Success callback. - function(audioVideoStream) { - // Set video player source to microphone+webcam stream, and play it back as it's recording. - cm.playerDOM.srcObject = audioVideoStream; - cm.playerDOM.play(); - - config.onMediaCaptured(audioVideoStream); - }, - - // Error callback. - function(error) { - config.onMediaCapturingFailed(error); - } - ); - } -}; - - -}, '@VERSION@', {"requires": ["moodle-atto_recordrtc-button"]}); diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/button/build.json b/lib/editor/atto/plugins/recordrtc/yui/src/button/build.json deleted file mode 100644 index d6abd5d86ce..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_recordrtc-button", - "builds": { - "moodle-atto_recordrtc-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js b/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js deleted file mode 100644 index 156d6676c70..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js +++ /dev/null @@ -1,389 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_recordrtc-button - */ - -/** - * Atto text editor recordrtc plugin. - * - * @namespace M.atto_recordrtc - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// JSHint directives. -/*global M */ -/*jshint onevar: false */ - -// Scrutinizer CI directives. -/** global: Y */ -/** global: M */ - -var PLUGINNAME = 'atto_recordrtc', - TEMPLATE = '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{insecurealert_title}} {{insecurealert}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{#if isAudio}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '{{else}}' + - '
                            ' + - '' + - '
                            ' + - '{{/if}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            '; - -Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * The current language by default. - */ - _lang: 'en', - - initializer: function() { - if (this.get('host').canShowFilepicker('media')) { - // Add audio and/or video buttons depending on the settings. - var allowedtypes = this.get('allowedtypes'), - buttonadded = false; - if (allowedtypes === 'both' || allowedtypes === 'audio') { - this._addButton('audio', this._audio); - buttonadded = true; - } - if (allowedtypes === 'both' || allowedtypes === 'video') { - this._addButton('video', this._video); - buttonadded = true; - } - if (!buttonadded) { - // Plugin not available here. - return; - } - - // Initialize the dialogue box. - var dialogue = this.getDialogue({ - width: 1000, - focusAfterHide: null - }); - - dialogue.after('visibleChange', function() { - var closed = !dialogue.get('visible'), - m = M.atto_recordrtc.commonmodule; - - if (closed) { - // If dialogue is closed during recording, do the following. - window.clearInterval(m.countdownTicker); - - if (m.mediaRecorder && m.mediaRecorder.state !== 'inactive') { - m.mediaRecorder.stop(); - } - - if (m.stream) { - m.stream.getTracks().forEach(function(track) { - if (track.readyState !== 'ended') { - track.stop(); - } - }); - } - - // Because the player uses ids to identify things (this should be fixed) - // we must make sure the dialogue contents only exist once in the DOM. - // Therefore, when a dialogue is closed, we must remove its contents. - this.getDialogue().set('bodyContent', ''); - } - - }, this); - - dialogue.on('click', function() { - this.centered(); - }); - - // Require adapter.js library. - window.require(['core/adapter'], function(adapter) { - window.adapter = adapter; - }); - } - }, - - /** - * Add the buttons to the Atto toolbar. - * - * @method _addButton - * @param {string} type - * @param {callback} callback - * @private - */ - _addButton: function(type, callback) { - this.addButton({ - buttonName: type, - icon: this.get(type + 'rtcicon'), - iconComponent: PLUGINNAME, - callback: callback, - title: type + 'rtc', - tags: type + 'rtc', - tagMatchRequiresAll: false - }); - }, - - /** - * Toggle audiortc and normal display mode - * - * @method _audio - * @private - */ - _audio: function() { - var dialogue = this.getDialogue({ - focusAfterHide: 'audio' - }); - - dialogue.set('headerContent', M.util.get_string('audiortc', 'atto_recordrtc')); - dialogue.set('bodyContent', this._createContent('audio')); - - dialogue.show(); - - M.atto_recordrtc.audiomodule.init(this); - }, - - /** - * Toggle videortc and normal display mode - * - * @method _video - * @private - */ - _video: function() { - var dialogue = this.getDialogue({ - focusAfterHide: 'video' - }); - - dialogue.set('headerContent', M.util.get_string('videortc', 'atto_recordrtc')); - dialogue.set('bodyContent', this._createContent('video')); - - dialogue.show(); - - M.atto_recordrtc.videomodule.init(this); - }, - - /** - * Create the HTML to be displayed in the dialogue box - * - * @method _createContent - * @param {string} type - * @returns {Object} - * @private - */ - _createContent: function(type) { - var isAudio = (type === 'audio'), - bsRow = 'row', - bsCol = 'col-', - bsAlDang = 'alert-danger', - bsSsBtn = 'btn btn-lg btn-outline-danger w-100'; - - var bodyContent = Y.Handlebars.compile(TEMPLATE)({ - PLUGINNAME: PLUGINNAME, - isAudio: isAudio, - bs_row: bsRow, - bs_col: bsCol, - bs_al_dang: bsAlDang, - bs_ss_btn: bsSsBtn, - insecurealert_title: M.util.get_string('insecurealert_title', 'atto_recordrtc'), - insecurealert: M.util.get_string('insecurealert', 'atto_recordrtc'), - startrecording: M.util.get_string('startrecording', 'atto_recordrtc'), - attachrecording: M.util.get_string('attachrecording', 'atto_recordrtc') - }); - - return bodyContent; - }, - - /** - * Close the dialogue without further action. - * - * @method closeDialogue - * @param {Object} scope The "this" context of the editor. - */ - closeDialogue: function(scope) { - scope.getDialogue().hide({ - focusAfterHide: null - }); - - scope.editor.focus(); - }, - - /** - * Insert the annotation link in the editor. - * - * @method setLink - * @param {Object} scope The "this" context of the editor. - * @param {string} annotation The HTML link to the recording. - */ - setLink: function(scope, annotation) { - scope.getDialogue().hide({ - focusAfterHide: null - }); - - scope.editor.focus(); - scope.get('host').insertContentAtFocusPoint(annotation); - scope.markUpdated(); - } -}, { - ATTRS: { - /** - * The contextid to use when generating this recordrtc. - * - * @attribute contextid - * @type String - */ - contextid: { - value: null - }, - - /** - * The sesskey to use when generating this recordrtc. - * - * @attribute sesskey - * @type String - */ - sesskey: { - value: null - }, - - /** - * The allowedtypes to use when generating this recordrtc. - * - * @attribute allowedtypes - * @type String - */ - allowedtypes: { - value: null - }, - - /** - * The audiobitrate to use when generating this recordrtc. - * - * @attribute audiobitrate - * @type String - */ - audiobitrate: { - value: null - }, - - /** - * The videobitrate to use when generating this recordrtc. - * - * @attribute videobitrate - * @type String - */ - videobitrate: { - value: null - }, - - /** - * The audiotimelimit to use when generating this recordrtc. - * - * @attribute audiotimelimit - * @type String - */ - audiotimelimit: { - value: null - }, - - /** - * The videotimelimit to use when generating this recordrtc. - * - * @attribute videotimelimit - * @type String - */ - videotimelimit: { - value: null - }, - - /** - * The defaulttimelimit to use when generating this recordrtc. - * - * @attribute defaulttimelimit - * @type String - */ - defaulttimelimit: { - value: null - }, - - /** - * The audiortcicon to use when generating this recordrtc. - * - * @attribute audiortcicon - * @type String - */ - audiortcicon: { - value: null - }, - - /** - * The videortcicon to use when generating this recordrtc. - * - * @attribute videortcicon - * @type String - */ - videortcicon: { - value: null - }, - - /** - * Maximum upload size set on server, in bytes. - * - * @attribute maxrecsize - * @type String - */ - maxrecsize: { - value: null - } - } -}); diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/button/meta/button.json b/lib/editor/atto/plugins/recordrtc/yui/src/button/meta/button.json deleted file mode 100644 index 3aa48266a85..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/button/meta/button.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "moodle-atto_recordrtc-button": { - "requires": [ - "moodle-editor_atto-plugin", - "moodle-atto_recordrtc-recording" - ] - } -} diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/build.json b/lib/editor/atto/plugins/recordrtc/yui/src/recording/build.json deleted file mode 100644 index 8fbac694c74..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/build.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "moodle-atto_recordrtc-recording", - "builds": { - "moodle-atto_recordrtc-recording": { - "jsfiles": [ - "commonmodule.js", - "compatcheckmodule.js", - "abstractmodule.js", - "audiomodule.js", - "videomodule.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/abstractmodule.js b/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/abstractmodule.js deleted file mode 100644 index b3969cfb280..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/abstractmodule.js +++ /dev/null @@ -1,137 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions for function abstractions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.abstractmodule = { - // A helper for making a Moodle alert appear. - // Subject is the content of the alert (which error ther alert is for). - // Possibility to add on-alert-close event. - show_alert: function(subject, onCloseEvent) { - Y.use('moodle-core-notification-alert', function() { - var dialogue = new M.core.alert({ - title: M.util.get_string(subject + '_title', 'atto_recordrtc'), - message: M.util.get_string(subject, 'atto_recordrtc') - }); - - if (onCloseEvent) { - dialogue.after('complete', onCloseEvent); - } - }); - }, - - // Handle getUserMedia errors. - handle_gum_errors: function(error, commonConfig) { - var btnLabel = M.util.get_string('recordingfailed', 'atto_recordrtc'), - treatAsStopped = function() { - commonConfig.onMediaStopped(btnLabel); - }; - - // Changes 'CertainError' -> 'gumcertain' to match language string names. - var stringName = 'gum' + error.name.replace('Error', '').toLowerCase(); - - // After alert, proceed to treat as stopped recording, or close dialogue. - if (stringName !== 'gumsecurity') { - am.show_alert(stringName, treatAsStopped); - } else { - am.show_alert(stringName, function() { - cm.editorScope.closeDialogue(cm.editorScope); - }); - } - }, - - // Select best options for the recording codec. - select_rec_options: function(recType) { - var types, options; - - if (recType === 'audio') { - types = [ - // Firefox supports webm and ogg but Chrome only supports ogg. - // So we use ogg to maximize the compatibility. - 'audio/ogg;codecs=opus', - - // Safari supports mp4. - 'audio/mp4;codecs=opus', - 'audio/mp4;codecs=wav', - 'audio/mp4;codecs=mp3', - ]; - options = { - audioBitsPerSecond: window.parseInt(cm.editorScope.get('audiobitrate')) - }; - } else { - types = [ - // Support webm as a preference. - // This container supports both vp9, and vp8. - // It does not support AVC1/h264 at all. - // It is supported by Chromium, and Firefox browsers, but not Safari. - 'video/webm;codecs=vp9,opus', - 'video/webm;codecs=vp8,opus', - - // Fall back to mp4 if webm is not available. - // The mp4 container supports v9, and h264 but neither of these are supported for recording on other - // browsers. - // In addition to this, we can record in v9, but VideoJS does not support an mp4 containern with v9 codec - // for playback. We leave it as a final option as a just-in-case. - 'video/mp4;codecs=h264,opus', - 'video/mp4;codecs=h264,wav', - 'video/mp4;codecs=v9,opus', - ]; - options = { - audioBitsPerSecond: window.parseInt(cm.editorScope.get('audiobitrate')), - videoBitsPerSecond: window.parseInt(cm.editorScope.get('videobitrate')) - }; - } - - var possibleTypes = types.reduce(function(result, type) { - result.push(type); - // Safari seems to use codecs: instead of codecs=. - // It is safe to add both, so we do, but we want them to remain in order. - result.push(type.replace('=', ':')); - return result; - }, []); - - var compatTypes = possibleTypes.filter(function(type) { - return window.MediaRecorder.isTypeSupported(type); - }); - - if (compatTypes.length !== 0) { - options.mimeType = compatTypes[0]; - } - - return options; - } -}; diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/audiomodule.js b/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/audiomodule.js deleted file mode 100644 index 6424b5a2b63..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/audiomodule.js +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule, - ccm = M.atto_recordrtc.compatcheckmodule; - -M.atto_recordrtc.audiomodule = { - init: function(scope) { - // Assignment of global variables. - cm.editorScope = scope; // Allows access to the editor's "this" context. - cm.alertWarning = Y.one('div#alert-warning'); - cm.alertDanger = Y.one('div#alert-danger'); - cm.player = Y.one('audio#player'); - cm.playerDOM = document.querySelector('audio#player'); - cm.startStopBtn = Y.one('button#start-stop'); - cm.uploadBtn = Y.one('button#upload'); - cm.recType = 'audio'; - cm.maxUploadSize = scope.get('maxrecsize'); - - // Show alert and close plugin if WebRTC is not supported. - ccm.check_has_gum(); - // Show alert and redirect user if connection is not secure. - ccm.check_secure(); - - // Run when user clicks on "record" button. - cm.startStopBtn.on('click', function() { - cm.startStopBtn.set('disabled', true); - - // If button is displaying "Start Recording" or "Record Again". - if ((cm.startStopBtn.get('textContent') === M.util.get_string('startrecording', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordagain', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'atto_recordrtc'))) { - // Make sure the audio player and upload button are not shown. - cm.player.ancestor().ancestor().addClass('hide'); - cm.uploadBtn.ancestor().ancestor().addClass('hide'); - - // Change look of recording button. - cm.startStopBtn.replaceClass('btn-outline-danger', 'btn-danger'); - - // Empty the array containing the previously recorded chunks. - cm.chunks = []; - cm.blobSize = 0; - cm.uploadBtn.detach('click'); - - // Initialize common configurations. - var commonConfig = { - // When the stream is captured from the microphone/webcam. - onMediaCaptured: function(stream) { - // Make audio stream available at a higher level by making it a property of the common module. - cm.stream = stream; - - cm.start_recording(cm.recType, cm.stream); - }, - - // Revert button to "Record Again" when recording is stopped. - onMediaStopped: function(btnLabel) { - cm.startStopBtn.set('textContent', btnLabel); - cm.startStopBtn.set('disabled', false); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - }, - - // Handle recording errors. - onMediaCapturingFailed: function(error) { - am.handle_gum_errors(error, commonConfig); - } - }; - - // Capture audio stream from microphone. - M.atto_recordrtc.audiomodule.capture_audio(commonConfig); - } else { // If button is displaying "Stop Recording". - // First of all clears the countdownTicker. - window.clearInterval(cm.countdownTicker); - - // Disable "Record Again" button for 1s to allow background processing (closing streams). - window.setTimeout(function() { - cm.startStopBtn.set('disabled', false); - }, 1000); - - // Stop recording. - cm.stop_recording(cm.stream); - - // Change button to offer to record again. - cm.startStopBtn.set('textContent', M.util.get_string('recordagain', 'atto_recordrtc')); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - } - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - }); - }, - - // Setup to get audio stream from microphone. - capture_audio: function(config) { - cm.capture_user_media( - // Media constraints. - { - audio: true - }, - - // Success callback. - function(audioStream) { - // Set audio player source to microphone stream. - cm.playerDOM.srcObject = audioStream; - - config.onMediaCaptured(audioStream); - }, - - // Error callback. - function(error) { - config.onMediaCapturingFailed(error); - } - ); - } -}; diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/commonmodule.js b/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/commonmodule.js deleted file mode 100644 index 73a82fb144a..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/commonmodule.js +++ /dev/null @@ -1,351 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, no-alert, spaced-comment */ - -// JSHint directives. -/*global M */ -/*jshint es5: true */ -/*jshint onevar: false */ -/*jshint shadow: true */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to M.atto_recordrtc.commonmodule namespace. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.commonmodule = { - // Unitialized variables to be used by the other modules. - editorScope: null, - alertWarning: null, - alertDanger: null, - player: null, - playerDOM: null, // Used to manipulate DOM directly. - startStopBtn: null, - uploadBtn: null, - countdownSeconds: null, - countdownTicker: null, - recType: null, - stream: null, - mediaRecorder: null, - chunks: null, - blobSize: null, - maxUploadSize: null, - - // Capture webcam/microphone stream. - capture_user_media: function(mediaConstraints, successCallback, errorCallback) { - window.navigator.mediaDevices.getUserMedia(mediaConstraints).then(successCallback).catch(errorCallback); - }, - - // Add chunks of audio/video to array when made available. - handle_data_available: function(event) { - // Push recording slice to array. - cm.chunks.push(event.data); - // Size of all recorded data so far. - cm.blobSize += event.data.size; - - // If total size of recording so far exceeds max upload limit, stop recording. - // An extra condition exists to avoid displaying alert twice. - if (cm.blobSize >= cm.maxUploadSize) { - if (!window.localStorage.getItem('alerted')) { - window.localStorage.setItem('alerted', 'true'); - - cm.startStopBtn.simulate('click'); - am.show_alert('nearingmaxsize'); - } else { - window.localStorage.removeItem('alerted'); - } - - cm.chunks.pop(); - } - }, - - // Handle recording end. - handle_stop: function() { - // Set source of audio player. - var blob = new window.Blob(cm.chunks, {type: cm.mediaRecorder.mimeType}); - cm.player.set('srcObject', null); - cm.player.set('src', window.URL.createObjectURL(blob)); - - // Show audio player with controls enabled, and unmute. - cm.player.set('muted', false); - cm.player.set('controls', true); - cm.player.ancestor().ancestor().removeClass('hide'); - - // Show upload button. - cm.uploadBtn.ancestor().ancestor().removeClass('hide'); - cm.uploadBtn.set('textContent', M.util.get_string('attachrecording', 'atto_recordrtc')); - cm.uploadBtn.set('disabled', false); - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - - // Handle when upload button is clicked. - cm.uploadBtn.on('click', function() { - // Trigger error if no recording has been made. - if (cm.chunks.length === 0) { - am.show_alert('norecordingfound'); - } else { - cm.uploadBtn.set('disabled', true); - - // Upload recording to server. - cm.upload_to_server(cm.recType, function(progress, fileURLOrError) { - if (progress === 'ended') { // Insert annotation in text. - cm.uploadBtn.set('disabled', false); - cm.insert_annotation(cm.recType, fileURLOrError); - } else if (progress === 'upload-failed') { // Show error message in upload button. - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', - M.util.get_string('uploadfailed', 'atto_recordrtc') + ' ' + fileURLOrError); - } else if (progress === 'upload-failed-404') { // 404 error = File too large in Moodle. - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', M.util.get_string('uploadfailed404', 'atto_recordrtc')); - } else if (progress === 'upload-aborted') { - cm.uploadBtn.set('disabled', false); - cm.uploadBtn.set('textContent', - M.util.get_string('uploadaborted', 'atto_recordrtc') + ' ' + fileURLOrError); - } else { - cm.uploadBtn.set('textContent', progress); - } - }); - } - }); - }, - - // Get everything set up to start recording. - start_recording: function(type, stream) { - // The options for the recording codecs and bitrates. - var options = am.select_rec_options(type); - cm.mediaRecorder = new window.MediaRecorder(stream, options); - - // Initialize MediaRecorder events and start recording. - cm.mediaRecorder.ondataavailable = cm.handle_data_available; - cm.mediaRecorder.onstop = cm.handle_stop; - cm.mediaRecorder.start(1000); // Capture in 1s chunks. Must be set to work with Firefox. - - // Mute audio, distracting while recording. - cm.player.set('muted', true); - - // Set recording timer to the time specified in the settings. - if (type === 'audio') { - cm.countdownSeconds = cm.editorScope.get('audiotimelimit'); - } else if (type === 'video') { - cm.countdownSeconds = cm.editorScope.get('videotimelimit'); - } else { - // Default timer. - cm.countdownSeconds = cm.editorScope.get('defaulttimelimit'); - } - cm.countdownSeconds++; - var timerText = M.util.get_string('stoprecording', 'atto_recordrtc'); - timerText += ' (:)'; - cm.startStopBtn.setHTML(timerText); - cm.set_time(); - cm.countdownTicker = window.setInterval(cm.set_time, 1000); - - // Make button clickable again, to allow stopping recording. - cm.startStopBtn.set('disabled', false); - }, - - // Get everything set up to stop recording. - stop_recording: function(stream) { - // Stop recording stream. - cm.mediaRecorder.stop(); - - // Stop each individual MediaTrack. - var tracks = stream.getTracks(); - for (var i = 0; i < tracks.length; i++) { - tracks[i].stop(); - } - }, - - getFileExtension: function(type) { - if (type === 'audio') { - if (window.MediaRecorder.isTypeSupported('audio/ogg')) { - return 'ogg'; - } else if (window.MediaRecorder.isTypeSupported('audio/mp4')) { - return 'mp4'; - } - } else { - if (window.MediaRecorder.isTypeSupported('audio/webm')) { - return 'webm'; - } else if (window.MediaRecorder.isTypeSupported('audio/mp4')) { - return 'mp4'; - } - } - - window.console.warn('Unknown file type for MediaRecorder API'); - return ''; - }, - - // Upload recorded audio/video to server. - upload_to_server: function(type, callback) { - var xhr = new window.XMLHttpRequest(); - var fileExtension = this.getFileExtension(type); - - // Get src media of audio/video tag. - xhr.open('GET', cm.player.get('src'), true); - xhr.responseType = 'blob'; - - xhr.onload = function() { - if (xhr.status === 200) { // If src media was successfully retrieved. - // blob is now the media that the audio/video tag's src pointed to. - var blob = this.response; - - // Generate filename with random ID and file extension. - var fileName = (Math.random() * 1000).toString().replace('.', ''); - fileName += (type === 'audio') ? '-audio.' + fileExtension - : '-video.' + fileExtension; - - // Create FormData to send to PHP filepicker-upload script. - var formData = new window.FormData(), - filepickerOptions = cm.editorScope.get('host').get('filepickeroptions').link, - repositoryKeys = window.Object.keys(filepickerOptions.repositories); - - formData.append('repo_upload_file', blob, fileName); - formData.append('itemid', filepickerOptions.itemid); - - for (var i = 0; i < repositoryKeys.length; i++) { - if (filepickerOptions.repositories[repositoryKeys[i]].type === 'upload') { - formData.append('repo_id', filepickerOptions.repositories[repositoryKeys[i]].id); - break; - } - } - - formData.append('env', filepickerOptions.env); - formData.append('sesskey', M.cfg.sesskey); - formData.append('client_id', filepickerOptions.client_id); - formData.append('savepath', '/'); - formData.append('ctx_id', filepickerOptions.context.id); - - // Pass FormData to PHP script using XHR. - var uploadEndpoint = M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload'; - cm.make_xmlhttprequest(uploadEndpoint, formData, - function(progress, responseText) { - if (progress === 'upload-ended') { - callback('ended', window.JSON.parse(responseText).url); - } else { - callback(progress); - } - } - ); - } - }; - - xhr.send(); - }, - - // Handle XHR sending/receiving/status. - make_xmlhttprequest: function(url, data, callback) { - var xhr = new window.XMLHttpRequest(); - - xhr.onreadystatechange = function() { - if ((xhr.readyState === 4) && (xhr.status === 200)) { // When request is finished and successful. - callback('upload-ended', xhr.responseText); - } else if (xhr.status === 404) { // When request returns 404 Not Found. - callback('upload-failed-404'); - } - }; - - xhr.upload.onprogress = function(event) { - callback(Math.round(event.loaded / event.total * 100) + "% " + M.util.get_string('uploadprogress', 'atto_recordrtc')); - }; - - xhr.upload.onerror = function(error) { - callback('upload-failed', error); - }; - - xhr.upload.onabort = function(error) { - callback('upload-aborted', error); - }; - - // POST FormData to PHP script that handles uploading/saving. - xhr.open('POST', url); - xhr.send(data); - }, - - // Makes 1min and 2s display as 1:02 on timer instead of 1:2, for example. - pad: function(val) { - var valString = val + ""; - - if (valString.length < 2) { - return "0" + valString; - } else { - return valString; - } - }, - - // Functionality to make recording timer count down. - // Also makes recording stop when time limit is hit. - set_time: function() { - cm.countdownSeconds--; - - cm.startStopBtn.one('span#seconds').set('textContent', cm.pad(cm.countdownSeconds % 60)); - cm.startStopBtn.one('span#minutes').set('textContent', cm.pad(window.parseInt(cm.countdownSeconds / 60, 10))); - - if (cm.countdownSeconds === 0) { - cm.startStopBtn.simulate('click'); - } - }, - - // Generates link to recorded annotation to be inserted. - create_annotation: function(type, recording_url) { - var html = ''; - if (type == 'audio') { - html = ""; - } else { // Must be video. - html += ""; - } - - return html; - }, - - // Inserts link to annotation in editor text area. - insert_annotation: function(type, recording_url) { - var annotation = cm.create_annotation(type, recording_url); - - // Insert annotation link. - // If user pressed "Cancel", just go back to main recording screen. - if (!annotation) { - cm.uploadBtn.set('textContent', M.util.get_string('attachrecording', 'atto_recordrtc')); - } else { - cm.editorScope.setLink(cm.editorScope, annotation); - } - } -}; diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/compatcheckmodule.js b/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/compatcheckmodule.js deleted file mode 100644 index ecacdfa8dbe..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/compatcheckmodule.js +++ /dev/null @@ -1,58 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions for checking browser compatibility - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase */ - -// Scrutinizer CI directives. -/** global: M */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule; - -M.atto_recordrtc.compatcheckmodule = { - // Show alert and close plugin if browser does not support WebRTC at all. - check_has_gum: function() { - if (!(navigator.mediaDevices && window.MediaRecorder)) { - am.show_alert('nowebrtc', function() { - cm.editorScope.closeDialogue(cm.editorScope); - }); - } - }, - - // Notify and redirect user if plugin is used from insecure location. - check_secure: function() { - var isSecureOrigin = (window.location.protocol === 'https:') || - (window.location.host.indexOf('localhost') !== -1); - - if (!isSecureOrigin) { - cm.alertDanger.ancestor().ancestor().removeClass('hide'); - } - }, -}; diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/videomodule.js b/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/videomodule.js deleted file mode 100644 index 6d34cf7f0c8..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/js/videomodule.js +++ /dev/null @@ -1,156 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -// - -/** - * Atto recordrtc library functions - * - * @package atto_recordrtc - * @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) - * @author Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com) - * @copyright 2017 Blindside Networks Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -// ESLint directives. -/* eslint-disable camelcase, spaced-comment */ - -// Scrutinizer CI directives. -/** global: M */ -/** global: Y */ - -M.atto_recordrtc = M.atto_recordrtc || {}; - -// Shorten access to module namespaces. -var cm = M.atto_recordrtc.commonmodule, - am = M.atto_recordrtc.abstractmodule, - ccm = M.atto_recordrtc.compatcheckmodule; - -M.atto_recordrtc.videomodule = { - init: function(scope) { - // Assignment of global variables. - cm.editorScope = scope; // Allows access to the editor's "this" context. - cm.alertWarning = Y.one('div#alert-warning'); - cm.alertDanger = Y.one('div#alert-danger'); - cm.player = Y.one('video#player'); - cm.playerDOM = document.querySelector('video#player'); - cm.startStopBtn = Y.one('button#start-stop'); - cm.uploadBtn = Y.one('button#upload'); - cm.recType = 'video'; - cm.maxUploadSize = scope.get('maxrecsize'); - - // Show alert and close plugin if WebRTC is not supported. - ccm.check_has_gum(); - // Show alert and redirect user if connection is not secure. - ccm.check_secure(); - - // Run when user clicks on "record" button. - cm.startStopBtn.on('click', function() { - cm.startStopBtn.set('disabled', true); - - // If button is displaying "Start Recording" or "Record Again". - if ((cm.startStopBtn.get('textContent') === M.util.get_string('startrecording', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordagain', 'atto_recordrtc')) || - (cm.startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'atto_recordrtc'))) { - // Make sure the upload button is not shown. - cm.uploadBtn.ancestor().ancestor().addClass('hide'); - - // Change look of recording button. - cm.startStopBtn.replaceClass('btn-outline-danger', 'btn-danger'); - - // Empty the array containing the previously recorded chunks. - cm.chunks = []; - cm.blobSize = 0; - cm.uploadBtn.detach('click'); - - // Initialize common configurations. - var commonConfig = { - // When the stream is captured from the microphone/webcam. - onMediaCaptured: function(stream) { - // Make video stream available at a higher level by making it a property of the common module. - cm.stream = stream; - - cm.start_recording(cm.recType, cm.stream); - }, - - // Revert button to "Record Again" when recording is stopped. - onMediaStopped: function(btnLabel) { - cm.startStopBtn.set('textContent', btnLabel); - cm.startStopBtn.set('disabled', false); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - }, - - // Handle recording errors. - onMediaCapturingFailed: function(error) { - am.handle_gum_errors(error, commonConfig); - } - }; - - // Show video tag without controls to view webcam stream. - cm.player.ancestor().ancestor().removeClass('hide'); - cm.player.set('controls', false); - - // Capture audio+video stream from webcam/microphone. - M.atto_recordrtc.videomodule.capture_audio_video(commonConfig); - } else { // If button is displaying "Stop Recording". - // First of all clears the countdownTicker. - window.clearInterval(cm.countdownTicker); - - // Disable "Record Again" button for 1s to allow background processing (closing streams). - window.setTimeout(function() { - cm.startStopBtn.set('disabled', false); - }, 1000); - - // Stop recording. - cm.stop_recording(cm.stream); - - // Change button to offer to record again. - cm.startStopBtn.set('textContent', M.util.get_string('recordagain', 'atto_recordrtc')); - cm.startStopBtn.replaceClass('btn-danger', 'btn-outline-danger'); - } - - // Get dialogue centered. - cm.editorScope.getDialogue().centered(); - }); - }, - - // Setup to get audio+video stream from microphone/webcam. - capture_audio_video: function(config) { - cm.capture_user_media( - // Media constraints. - { - audio: true, - video: { - width: {ideal: 640}, - height: {ideal: 480} - } - }, - - // Success callback. - function(audioVideoStream) { - // Set video player source to microphone+webcam stream, and play it back as it's recording. - cm.playerDOM.srcObject = audioVideoStream; - cm.playerDOM.play(); - - config.onMediaCaptured(audioVideoStream); - }, - - // Error callback. - function(error) { - config.onMediaCapturingFailed(error); - } - ); - } -}; diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/recording/meta/recording.json b/lib/editor/atto/plugins/recordrtc/yui/src/recording/meta/recording.json deleted file mode 100644 index 4aa79cddb75..00000000000 --- a/lib/editor/atto/plugins/recordrtc/yui/src/recording/meta/recording.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_recordrtc-recording": { - "requires": [ - "moodle-atto_recordrtc-button" - ] - } -} diff --git a/lib/editor/atto/plugins/rtl/classes/privacy/provider.php b/lib/editor/atto/plugins/rtl/classes/privacy/provider.php deleted file mode 100644 index 64adb906bf5..00000000000 --- a/lib/editor/atto/plugins/rtl/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_rtl - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_rtl\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_rtl implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/rtl/lang/en/atto_rtl.php b/lib/editor/atto/plugins/rtl/lang/en/atto_rtl.php deleted file mode 100644 index 3645465ce39..00000000000 --- a/lib/editor/atto/plugins/rtl/lang/en/atto_rtl.php +++ /dev/null @@ -1,28 +0,0 @@ -. - -/** - * Strings for component 'atto_rtl', language 'en'. - * - * @package atto_rtl - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'RTL/LTR'; -$string['rtl'] = 'Right to left'; -$string['ltr'] = 'Left to right'; -$string['privacy:metadata'] = 'The atto_rtl plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/rtl/lib.php b/lib/editor/atto/plugins/rtl/lib.php deleted file mode 100644 index 134cfa32070..00000000000 --- a/lib/editor/atto/plugins/rtl/lib.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Atto text editor rtl plugin lib. - * - * @package atto_rtl - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_rtl_strings_for_js() { - global $PAGE; - - // In order to prevent extra strings to be imported, comment/uncomment the characters - // which are enabled in the JavaScript part of this plugin. - $PAGE->requires->strings_for_js( - array( - 'rtl', - 'ltr' - ), - 'atto_rtl' - ); -} diff --git a/lib/editor/atto/plugins/rtl/version.php b/lib/editor/atto/plugins/rtl/version.php deleted file mode 100644 index db1b8288053..00000000000 --- a/lib/editor/atto/plugins/rtl/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_rtl - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_rtl'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-debug.js b/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-debug.js deleted file mode 100644 index 1a7e8f1f0ec..00000000000 --- a/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-debug.js +++ /dev/null @@ -1,103 +0,0 @@ -YUI.add('moodle-atto_rtl-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_rtl - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_rtl-button - */ - -/** - * Atto text editor rtl plugin. - * - * @namespace M.atto_rtl - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_rtl').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var direction; - - direction = 'ltr'; - this.addButton({ - icon: 'e/left_to_right', - title: direction, - buttonName: direction, - callback: this._toggleRTL, - callbackArgs: direction, - tags: '[dir=ltr]' - }); - - direction = 'rtl'; - this.addButton({ - icon: 'e/right_to_left', - title: direction, - buttonName: direction, - callback: this._toggleRTL, - callbackArgs: direction, - tags: '[dir=rtl]' - }); - }, - - /** - * Toggle the RTL/LTR values based on the supplied direction. - * - * @method _toggleRTL - * @param {EventFacade} e - * @param {String} direction - */ - _toggleRTL: function(e, direction) { - var host = this.get('host'), - sourceSelection = window.rangy.saveSelection(), - selection = host.getSelection(), - newDirection = { - rtl: 'ltr', - ltr: 'rtl' - }, - directionAlignment = { - rtl: 'right', - ltr: 'left' - }; - if (selection) { - // Format the selection to be sure it has a tag parent (not the contenteditable). - var parentNode = host.formatSelectionBlock(), - parentDOMNode = parentNode.getDOMNode(); - - var currentDirection = parentDOMNode.getAttribute('dir'); - if (currentDirection === direction) { - parentDOMNode.setAttribute("dir", newDirection[direction]); - parentDOMNode.style.textAlign = directionAlignment[newDirection[direction]]; - } else { - parentDOMNode.setAttribute("dir", direction); - parentDOMNode.style.textAlign = directionAlignment[direction]; - } - - // Change selection from the containing paragraph to the original one. - window.rangy.restoreSelection(sourceSelection); - // Mark the text as having been updated. - this.markUpdated(); - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-min.js b/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-min.js deleted file mode 100644 index 910e6f5eba1..00000000000 --- a/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_rtl-button",function(t,e){t.namespace("M.atto_rtl").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){var t="ltr";this.addButton({icon:"e/left_to_right",title:t,buttonName:t,callback:this._toggleRTL,callbackArgs:t,tags:"[dir=ltr]"}),this.addButton({icon:"e/right_to_left",title:t="rtl",buttonName:t,callback:this._toggleRTL,callbackArgs:t,tags:"[dir=rtl]"})},_toggleRTL:function(t,e){var i=this.get("host"),l=window.rangy.saveSelection(),r=i.getSelection(),o={rtl:"ltr",ltr:"rtl"},a={rtl:"right",ltr:"left"};r&&((r=i.formatSelectionBlock().getDOMNode()).getAttribute("dir")===e?(r.setAttribute("dir",o[e]),r.style.textAlign=a[o[e]]):(r.setAttribute("dir",e),r.style.textAlign=a[e]),window.rangy.restoreSelection(l),this.markUpdated())}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button.js b/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button.js deleted file mode 100644 index 1a7e8f1f0ec..00000000000 --- a/lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button.js +++ /dev/null @@ -1,103 +0,0 @@ -YUI.add('moodle-atto_rtl-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_rtl - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_rtl-button - */ - -/** - * Atto text editor rtl plugin. - * - * @namespace M.atto_rtl - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_rtl').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var direction; - - direction = 'ltr'; - this.addButton({ - icon: 'e/left_to_right', - title: direction, - buttonName: direction, - callback: this._toggleRTL, - callbackArgs: direction, - tags: '[dir=ltr]' - }); - - direction = 'rtl'; - this.addButton({ - icon: 'e/right_to_left', - title: direction, - buttonName: direction, - callback: this._toggleRTL, - callbackArgs: direction, - tags: '[dir=rtl]' - }); - }, - - /** - * Toggle the RTL/LTR values based on the supplied direction. - * - * @method _toggleRTL - * @param {EventFacade} e - * @param {String} direction - */ - _toggleRTL: function(e, direction) { - var host = this.get('host'), - sourceSelection = window.rangy.saveSelection(), - selection = host.getSelection(), - newDirection = { - rtl: 'ltr', - ltr: 'rtl' - }, - directionAlignment = { - rtl: 'right', - ltr: 'left' - }; - if (selection) { - // Format the selection to be sure it has a tag parent (not the contenteditable). - var parentNode = host.formatSelectionBlock(), - parentDOMNode = parentNode.getDOMNode(); - - var currentDirection = parentDOMNode.getAttribute('dir'); - if (currentDirection === direction) { - parentDOMNode.setAttribute("dir", newDirection[direction]); - parentDOMNode.style.textAlign = directionAlignment[newDirection[direction]]; - } else { - parentDOMNode.setAttribute("dir", direction); - parentDOMNode.style.textAlign = directionAlignment[direction]; - } - - // Change selection from the containing paragraph to the original one. - window.rangy.restoreSelection(sourceSelection); - // Mark the text as having been updated. - this.markUpdated(); - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/rtl/yui/src/button/build.json b/lib/editor/atto/plugins/rtl/yui/src/button/build.json deleted file mode 100644 index dd12c749869..00000000000 --- a/lib/editor/atto/plugins/rtl/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_rtl-button", - "builds": { - "moodle-atto_rtl-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/rtl/yui/src/button/js/button.js b/lib/editor/atto/plugins/rtl/yui/src/button/js/button.js deleted file mode 100644 index 7cca17ced50..00000000000 --- a/lib/editor/atto/plugins/rtl/yui/src/button/js/button.js +++ /dev/null @@ -1,98 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_rtl - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_rtl-button - */ - -/** - * Atto text editor rtl plugin. - * - * @namespace M.atto_rtl - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_rtl').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var direction; - - direction = 'ltr'; - this.addButton({ - icon: 'e/left_to_right', - title: direction, - buttonName: direction, - callback: this._toggleRTL, - callbackArgs: direction, - tags: '[dir=ltr]' - }); - - direction = 'rtl'; - this.addButton({ - icon: 'e/right_to_left', - title: direction, - buttonName: direction, - callback: this._toggleRTL, - callbackArgs: direction, - tags: '[dir=rtl]' - }); - }, - - /** - * Toggle the RTL/LTR values based on the supplied direction. - * - * @method _toggleRTL - * @param {EventFacade} e - * @param {String} direction - */ - _toggleRTL: function(e, direction) { - var host = this.get('host'), - sourceSelection = window.rangy.saveSelection(), - selection = host.getSelection(), - newDirection = { - rtl: 'ltr', - ltr: 'rtl' - }, - directionAlignment = { - rtl: 'right', - ltr: 'left' - }; - if (selection) { - // Format the selection to be sure it has a tag parent (not the contenteditable). - var parentNode = host.formatSelectionBlock(), - parentDOMNode = parentNode.getDOMNode(); - - var currentDirection = parentDOMNode.getAttribute('dir'); - if (currentDirection === direction) { - parentDOMNode.setAttribute("dir", newDirection[direction]); - parentDOMNode.style.textAlign = directionAlignment[newDirection[direction]]; - } else { - parentDOMNode.setAttribute("dir", direction); - parentDOMNode.style.textAlign = directionAlignment[direction]; - } - - // Change selection from the containing paragraph to the original one. - window.rangy.restoreSelection(sourceSelection); - // Mark the text as having been updated. - this.markUpdated(); - } - } -}); diff --git a/lib/editor/atto/plugins/rtl/yui/src/button/meta/button.json b/lib/editor/atto/plugins/rtl/yui/src/button/meta/button.json deleted file mode 100644 index 3a85a64a0cf..00000000000 --- a/lib/editor/atto/plugins/rtl/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_rtl-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/strike/classes/privacy/provider.php b/lib/editor/atto/plugins/strike/classes/privacy/provider.php deleted file mode 100644 index dc2dd6b5230..00000000000 --- a/lib/editor/atto/plugins/strike/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_strike - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_strike\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_strike implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/strike/lang/en/atto_strike.php b/lib/editor/atto/plugins/strike/lang/en/atto_strike.php deleted file mode 100644 index fe11c9b58eb..00000000000 --- a/lib/editor/atto/plugins/strike/lang/en/atto_strike.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_strike', language 'en'. - * - * @package atto_strike - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Strike through'; -$string['privacy:metadata'] = 'The atto_strike plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/strike/tests/behat/strike.feature b/lib/editor/atto/plugins/strike/tests/behat/strike.feature deleted file mode 100644 index c4eb9734e4c..00000000000 --- a/lib/editor/atto/plugins/strike/tests/behat/strike.feature +++ /dev/null @@ -1,19 +0,0 @@ -@editor @editor_atto @atto @atto_strike @_bug_phantomjs -Feature: Atto strike button - To format text in Atto, I need to use the strike button. - - @javascript - Scenario: Strike some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "MUA" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - When I click on "Strike through" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "MUA" diff --git a/lib/editor/atto/plugins/strike/version.php b/lib/editor/atto/plugins/strike/version.php deleted file mode 100644 index cd08a416624..00000000000 --- a/lib/editor/atto/plugins/strike/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_strike - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_strike'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-debug.js b/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-debug.js deleted file mode 100644 index 2f2bcaec51b..00000000000 --- a/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-debug.js +++ /dev/null @@ -1,72 +0,0 @@ -YUI.add('moodle-atto_strike-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_strike - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_strike-button - */ - -/** - * Atto text editor strike plugin. - * - * @namespace M.atto_strike - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_strike').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var strike; - - this.addButton({ - callback: this._toggleStrike, - icon: 'e/strikethrough', - buttonName: strike, - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'del, strike' - }); - this._strikeApplier = window.rangy.createClassApplier("bf-editor-strike-del"); - }, - /** - * Toggle the strikethrough setting. - * - * @method _toggleStrike - */ - _toggleStrike: function() { - var host = this.get('host'); - - // Change all and tags to applier class. - host.changeToCSS('del', 'bf-editor-strike-del'); - host.changeToCSS('strike', 'bf-editor-strike-del'); - - // Use the applier toggle selection. - this._strikeApplier.toggleSelection(); - - // Then change the applier class back to tags. - host.changeToTags('bf-editor-strike-del', 'del'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-min.js b/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-min.js deleted file mode 100644 index 8c27c2a0d5e..00000000000 --- a/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_strike-button",function(t,e){t.namespace("M.atto_strike").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addButton({callback:this._toggleStrike,icon:"e/strikethrough",buttonName:void 0,inlineFormat:!0,tags:"del, strike"}),this._strikeApplier=window.rangy.createClassApplier("bf-editor-strike-del")},_toggleStrike:function(){var t=this.get("host");t.changeToCSS("del","bf-editor-strike-del"),t.changeToCSS("strike","bf-editor-strike-del"),this._strikeApplier.toggleSelection(),t.changeToTags("bf-editor-strike-del","del")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button.js b/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button.js deleted file mode 100644 index 2f2bcaec51b..00000000000 --- a/lib/editor/atto/plugins/strike/yui/build/moodle-atto_strike-button/moodle-atto_strike-button.js +++ /dev/null @@ -1,72 +0,0 @@ -YUI.add('moodle-atto_strike-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_strike - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_strike-button - */ - -/** - * Atto text editor strike plugin. - * - * @namespace M.atto_strike - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_strike').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var strike; - - this.addButton({ - callback: this._toggleStrike, - icon: 'e/strikethrough', - buttonName: strike, - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'del, strike' - }); - this._strikeApplier = window.rangy.createClassApplier("bf-editor-strike-del"); - }, - /** - * Toggle the strikethrough setting. - * - * @method _toggleStrike - */ - _toggleStrike: function() { - var host = this.get('host'); - - // Change all and tags to applier class. - host.changeToCSS('del', 'bf-editor-strike-del'); - host.changeToCSS('strike', 'bf-editor-strike-del'); - - // Use the applier toggle selection. - this._strikeApplier.toggleSelection(); - - // Then change the applier class back to tags. - host.changeToTags('bf-editor-strike-del', 'del'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/strike/yui/src/button/build.json b/lib/editor/atto/plugins/strike/yui/src/button/build.json deleted file mode 100644 index b24dfb52af7..00000000000 --- a/lib/editor/atto/plugins/strike/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_strike-button", - "builds": { - "moodle-atto_strike-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/strike/yui/src/button/js/button.js b/lib/editor/atto/plugins/strike/yui/src/button/js/button.js deleted file mode 100644 index a19b5f15470..00000000000 --- a/lib/editor/atto/plugins/strike/yui/src/button/js/button.js +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_strike - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_strike-button - */ - -/** - * Atto text editor strike plugin. - * - * @namespace M.atto_strike - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_strike').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var strike; - - this.addButton({ - callback: this._toggleStrike, - icon: 'e/strikethrough', - buttonName: strike, - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'del, strike' - }); - this._strikeApplier = window.rangy.createClassApplier("bf-editor-strike-del"); - }, - /** - * Toggle the strikethrough setting. - * - * @method _toggleStrike - */ - _toggleStrike: function() { - var host = this.get('host'); - - // Change all and tags to applier class. - host.changeToCSS('del', 'bf-editor-strike-del'); - host.changeToCSS('strike', 'bf-editor-strike-del'); - - // Use the applier toggle selection. - this._strikeApplier.toggleSelection(); - - // Then change the applier class back to tags. - host.changeToTags('bf-editor-strike-del', 'del'); - } -}); diff --git a/lib/editor/atto/plugins/strike/yui/src/button/meta/button.json b/lib/editor/atto/plugins/strike/yui/src/button/meta/button.json deleted file mode 100644 index 478fd801e4d..00000000000 --- a/lib/editor/atto/plugins/strike/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_strike-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/subscript/classes/privacy/provider.php b/lib/editor/atto/plugins/subscript/classes/privacy/provider.php deleted file mode 100644 index 72eae49e118..00000000000 --- a/lib/editor/atto/plugins/subscript/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_subscript - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_subscript\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_subscript implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/subscript/lang/en/atto_subscript.php b/lib/editor/atto/plugins/subscript/lang/en/atto_subscript.php deleted file mode 100644 index 04683cb72ee..00000000000 --- a/lib/editor/atto/plugins/subscript/lang/en/atto_subscript.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_subscript', language 'en'. - * - * @package atto_subscript - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Subscript'; -$string['privacy:metadata'] = 'The atto_subscript plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/subscript/tests/behat/subscript.feature b/lib/editor/atto/plugins/subscript/tests/behat/subscript.feature deleted file mode 100644 index bce4211ed7f..00000000000 --- a/lib/editor/atto/plugins/subscript/tests/behat/subscript.feature +++ /dev/null @@ -1,35 +0,0 @@ -@editor @editor_atto @atto @atto_subscript @_bug_phantomjs -Feature: Atto subscript button - To format text in Atto, I need to use the subscript button. - - @javascript - Scenario: Subscript some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Submarine" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - When I click on "Subscript" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Submarine" - - @javascript - Scenario: Subscript some text in enclosed in superscript - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Submarine" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - When I click on "Subscript" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Submarine" diff --git a/lib/editor/atto/plugins/subscript/version.php b/lib/editor/atto/plugins/subscript/version.php deleted file mode 100644 index 6300ff019f9..00000000000 --- a/lib/editor/atto/plugins/subscript/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_subscript - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_subscript'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-debug.js b/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-debug.js deleted file mode 100644 index cf1939e7168..00000000000 --- a/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-debug.js +++ /dev/null @@ -1,90 +0,0 @@ -YUI.add('moodle-atto_subscript-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_subscript - * @copyright 2014 Rosiana Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_subscript-button - */ - -/** - * Atto text editor subscript plugin. - * - * @namespace M.atto_subscript - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_subscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A rangy object to alter CSS classes. - * - * @property _subscriptApplier - * @type Object - * @private - */ - _subscriptApplier: null, - - /** - * A rangy object to alter CSS classes. - * - * @property _superscriptApplier - * @type Object - * @private - */ - _superscriptApplier: null, - - initializer: function() { - this.addButton({ - buttonName: 'subscript', - callback: this.toggleSubscript, - icon: 'e/subscript', - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'sub' - }); - this._subscriptApplier = window.rangy.createClassApplier("editor-subscript"); - this._superscriptApplier = window.rangy.createClassApplier("editor-superscript"); - }, - - /** - * Toggle subscripts in selection - * - * @method toggleSubscript - */ - toggleSubscript: function() { - // Replace all the sub and sup tags. - this.get('host').changeToCSS('sup', 'editor-superscript'); - this.get('host').changeToCSS('sub', 'editor-subscript'); - - // Remove all superscripts inselection and toggle subscript. - this._superscriptApplier.undoToSelection(); - this._subscriptApplier.toggleSelection(); - - // Replace CSS classes with tags. - this.get('host').changeToTags('editor-subscript', 'sub'); - this.get('host').changeToTags('editor-superscript', 'sup'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-min.js b/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-min.js deleted file mode 100644 index 52752fca7ef..00000000000 --- a/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_subscript-button",function(t,s){t.namespace("M.atto_subscript").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{_subscriptApplier:null,_superscriptApplier:null,initializer:function(){this.addButton({buttonName:"subscript",callback:this.toggleSubscript,icon:"e/subscript",inlineFormat:!0,tags:"sub"}),this._subscriptApplier=window.rangy.createClassApplier("editor-subscript"),this._superscriptApplier=window.rangy.createClassApplier("editor-superscript")},toggleSubscript:function(){this.get("host").changeToCSS("sup","editor-superscript"),this.get("host").changeToCSS("sub","editor-subscript"),this._superscriptApplier.undoToSelection(),this._subscriptApplier.toggleSelection(),this.get("host").changeToTags("editor-subscript","sub"),this.get("host").changeToTags("editor-superscript","sup")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button.js b/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button.js deleted file mode 100644 index cf1939e7168..00000000000 --- a/lib/editor/atto/plugins/subscript/yui/build/moodle-atto_subscript-button/moodle-atto_subscript-button.js +++ /dev/null @@ -1,90 +0,0 @@ -YUI.add('moodle-atto_subscript-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_subscript - * @copyright 2014 Rosiana Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_subscript-button - */ - -/** - * Atto text editor subscript plugin. - * - * @namespace M.atto_subscript - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_subscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A rangy object to alter CSS classes. - * - * @property _subscriptApplier - * @type Object - * @private - */ - _subscriptApplier: null, - - /** - * A rangy object to alter CSS classes. - * - * @property _superscriptApplier - * @type Object - * @private - */ - _superscriptApplier: null, - - initializer: function() { - this.addButton({ - buttonName: 'subscript', - callback: this.toggleSubscript, - icon: 'e/subscript', - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'sub' - }); - this._subscriptApplier = window.rangy.createClassApplier("editor-subscript"); - this._superscriptApplier = window.rangy.createClassApplier("editor-superscript"); - }, - - /** - * Toggle subscripts in selection - * - * @method toggleSubscript - */ - toggleSubscript: function() { - // Replace all the sub and sup tags. - this.get('host').changeToCSS('sup', 'editor-superscript'); - this.get('host').changeToCSS('sub', 'editor-subscript'); - - // Remove all superscripts inselection and toggle subscript. - this._superscriptApplier.undoToSelection(); - this._subscriptApplier.toggleSelection(); - - // Replace CSS classes with tags. - this.get('host').changeToTags('editor-subscript', 'sub'); - this.get('host').changeToTags('editor-superscript', 'sup'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/subscript/yui/src/button/build.json b/lib/editor/atto/plugins/subscript/yui/src/button/build.json deleted file mode 100644 index 8e302cf52a3..00000000000 --- a/lib/editor/atto/plugins/subscript/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_subscript-button", - "builds": { - "moodle-atto_subscript-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/subscript/yui/src/button/js/button.js b/lib/editor/atto/plugins/subscript/yui/src/button/js/button.js deleted file mode 100644 index 880db8e5183..00000000000 --- a/lib/editor/atto/plugins/subscript/yui/src/button/js/button.js +++ /dev/null @@ -1,85 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_subscript - * @copyright 2014 Rosiana Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_subscript-button - */ - -/** - * Atto text editor subscript plugin. - * - * @namespace M.atto_subscript - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_subscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A rangy object to alter CSS classes. - * - * @property _subscriptApplier - * @type Object - * @private - */ - _subscriptApplier: null, - - /** - * A rangy object to alter CSS classes. - * - * @property _superscriptApplier - * @type Object - * @private - */ - _superscriptApplier: null, - - initializer: function() { - this.addButton({ - buttonName: 'subscript', - callback: this.toggleSubscript, - icon: 'e/subscript', - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'sub' - }); - this._subscriptApplier = window.rangy.createClassApplier("editor-subscript"); - this._superscriptApplier = window.rangy.createClassApplier("editor-superscript"); - }, - - /** - * Toggle subscripts in selection - * - * @method toggleSubscript - */ - toggleSubscript: function() { - // Replace all the sub and sup tags. - this.get('host').changeToCSS('sup', 'editor-superscript'); - this.get('host').changeToCSS('sub', 'editor-subscript'); - - // Remove all superscripts inselection and toggle subscript. - this._superscriptApplier.undoToSelection(); - this._subscriptApplier.toggleSelection(); - - // Replace CSS classes with tags. - this.get('host').changeToTags('editor-subscript', 'sub'); - this.get('host').changeToTags('editor-superscript', 'sup'); - } -}); diff --git a/lib/editor/atto/plugins/subscript/yui/src/button/meta/button.json b/lib/editor/atto/plugins/subscript/yui/src/button/meta/button.json deleted file mode 100644 index 5489a1bed9f..00000000000 --- a/lib/editor/atto/plugins/subscript/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_subscript-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/superscript/classes/privacy/provider.php b/lib/editor/atto/plugins/superscript/classes/privacy/provider.php deleted file mode 100644 index 562e4a145ca..00000000000 --- a/lib/editor/atto/plugins/superscript/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_superscript - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_superscript\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_superscript implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/superscript/lang/en/atto_superscript.php b/lib/editor/atto/plugins/superscript/lang/en/atto_superscript.php deleted file mode 100644 index a269a04eb93..00000000000 --- a/lib/editor/atto/plugins/superscript/lang/en/atto_superscript.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_superscript', language 'en'. - * - * @package atto_superscript - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Superscript'; -$string['privacy:metadata'] = 'The atto_superscript plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/superscript/tests/behat/superscript.feature b/lib/editor/atto/plugins/superscript/tests/behat/superscript.feature deleted file mode 100644 index ecf294ffb93..00000000000 --- a/lib/editor/atto/plugins/superscript/tests/behat/superscript.feature +++ /dev/null @@ -1,35 +0,0 @@ -@editor @editor_atto @atto @atto_superscript @_bug_phantomjs -Feature: Atto superscript button - To format text in Atto, I need to use the superscript button. - - @javascript - Scenario: Subscript some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Helicopter" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - When I click on "Superscript" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Helicopter" - - @javascript - Scenario: Superscript some text that is enclosed in subscript - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Helicopter" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - When I click on "Superscript" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Helicopter" diff --git a/lib/editor/atto/plugins/superscript/version.php b/lib/editor/atto/plugins/superscript/version.php deleted file mode 100644 index 1b2dc04fd07..00000000000 --- a/lib/editor/atto/plugins/superscript/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_superscript - * @copyright 2014 Rossiani Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_superscript'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-debug.js b/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-debug.js deleted file mode 100644 index 890f2d69af1..00000000000 --- a/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-debug.js +++ /dev/null @@ -1,90 +0,0 @@ -YUI.add('moodle-atto_superscript-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_superscript - * @copyright 2014 Rosiana Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_superscript-button - */ - -/** - * Atto text editor superscript plugin. - * - * @namespace M.atto_superscript - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_superscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A rangy object to alter CSS classes. - * - * @property _subscriptApplier - * @type Object - * @private - */ - _subscriptApplier: null, - - /** - * A rangy object to alter CSS classes. - * - * @property _superscriptApplier - * @type Object - * @private - */ - _superscriptApplier: null, - - initializer: function() { - this.addButton({ - buttonName: 'superscript', - callback: this.toggleSuperscript, - icon: 'e/superscript', - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'sup' - }); - this._subscriptApplier = window.rangy.createClassApplier("editor-subscript"); - this._superscriptApplier = window.rangy.createClassApplier("editor-superscript"); - }, - - /** - * Toggle superscripts in selection - * - * @method toggleSuperscript - */ - toggleSuperscript: function() { - // Replace all the sub and sup tags. - this.get('host').changeToCSS('sub', 'editor-subscript'); - this.get('host').changeToCSS('sup', 'editor-superscript'); - - // Remove all subscripts inselection and toggle superscript. - this._superscriptApplier.toggleSelection(); - this._subscriptApplier.undoToSelection(); - - // Replace CSS classes with tags. - this.get('host').changeToTags('editor-superscript', 'sup'); - this.get('host').changeToTags('editor-subscript', 'sub'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-min.js b/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-min.js deleted file mode 100644 index 5c24cc7ba0c..00000000000 --- a/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_superscript-button",function(t,s){t.namespace("M.atto_superscript").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{_subscriptApplier:null,_superscriptApplier:null,initializer:function(){this.addButton({buttonName:"superscript",callback:this.toggleSuperscript,icon:"e/superscript",inlineFormat:!0,tags:"sup"}),this._subscriptApplier=window.rangy.createClassApplier("editor-subscript"),this._superscriptApplier=window.rangy.createClassApplier("editor-superscript")},toggleSuperscript:function(){this.get("host").changeToCSS("sub","editor-subscript"),this.get("host").changeToCSS("sup","editor-superscript"),this._superscriptApplier.toggleSelection(),this._subscriptApplier.undoToSelection(),this.get("host").changeToTags("editor-superscript","sup"),this.get("host").changeToTags("editor-subscript","sub")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button.js b/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button.js deleted file mode 100644 index 890f2d69af1..00000000000 --- a/lib/editor/atto/plugins/superscript/yui/build/moodle-atto_superscript-button/moodle-atto_superscript-button.js +++ /dev/null @@ -1,90 +0,0 @@ -YUI.add('moodle-atto_superscript-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_superscript - * @copyright 2014 Rosiana Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_superscript-button - */ - -/** - * Atto text editor superscript plugin. - * - * @namespace M.atto_superscript - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_superscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A rangy object to alter CSS classes. - * - * @property _subscriptApplier - * @type Object - * @private - */ - _subscriptApplier: null, - - /** - * A rangy object to alter CSS classes. - * - * @property _superscriptApplier - * @type Object - * @private - */ - _superscriptApplier: null, - - initializer: function() { - this.addButton({ - buttonName: 'superscript', - callback: this.toggleSuperscript, - icon: 'e/superscript', - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'sup' - }); - this._subscriptApplier = window.rangy.createClassApplier("editor-subscript"); - this._superscriptApplier = window.rangy.createClassApplier("editor-superscript"); - }, - - /** - * Toggle superscripts in selection - * - * @method toggleSuperscript - */ - toggleSuperscript: function() { - // Replace all the sub and sup tags. - this.get('host').changeToCSS('sub', 'editor-subscript'); - this.get('host').changeToCSS('sup', 'editor-superscript'); - - // Remove all subscripts inselection and toggle superscript. - this._superscriptApplier.toggleSelection(); - this._subscriptApplier.undoToSelection(); - - // Replace CSS classes with tags. - this.get('host').changeToTags('editor-superscript', 'sup'); - this.get('host').changeToTags('editor-subscript', 'sub'); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/superscript/yui/src/button/build.json b/lib/editor/atto/plugins/superscript/yui/src/button/build.json deleted file mode 100644 index 616de6f5788..00000000000 --- a/lib/editor/atto/plugins/superscript/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_superscript-button", - "builds": { - "moodle-atto_superscript-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/superscript/yui/src/button/js/button.js b/lib/editor/atto/plugins/superscript/yui/src/button/js/button.js deleted file mode 100644 index 9e36f4a58b2..00000000000 --- a/lib/editor/atto/plugins/superscript/yui/src/button/js/button.js +++ /dev/null @@ -1,85 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_superscript - * @copyright 2014 Rosiana Wijaya - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_superscript-button - */ - -/** - * Atto text editor superscript plugin. - * - * @namespace M.atto_superscript - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_superscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * A rangy object to alter CSS classes. - * - * @property _subscriptApplier - * @type Object - * @private - */ - _subscriptApplier: null, - - /** - * A rangy object to alter CSS classes. - * - * @property _superscriptApplier - * @type Object - * @private - */ - _superscriptApplier: null, - - initializer: function() { - this.addButton({ - buttonName: 'superscript', - callback: this.toggleSuperscript, - icon: 'e/superscript', - inlineFormat: true, - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'sup' - }); - this._subscriptApplier = window.rangy.createClassApplier("editor-subscript"); - this._superscriptApplier = window.rangy.createClassApplier("editor-superscript"); - }, - - /** - * Toggle superscripts in selection - * - * @method toggleSuperscript - */ - toggleSuperscript: function() { - // Replace all the sub and sup tags. - this.get('host').changeToCSS('sub', 'editor-subscript'); - this.get('host').changeToCSS('sup', 'editor-superscript'); - - // Remove all subscripts inselection and toggle superscript. - this._superscriptApplier.toggleSelection(); - this._subscriptApplier.undoToSelection(); - - // Replace CSS classes with tags. - this.get('host').changeToTags('editor-superscript', 'sup'); - this.get('host').changeToTags('editor-subscript', 'sub'); - } -}); diff --git a/lib/editor/atto/plugins/superscript/yui/src/button/meta/button.json b/lib/editor/atto/plugins/superscript/yui/src/button/meta/button.json deleted file mode 100644 index f1c3071b536..00000000000 --- a/lib/editor/atto/plugins/superscript/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_superscript-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/table/classes/privacy/provider.php b/lib/editor/atto/plugins/table/classes/privacy/provider.php deleted file mode 100644 index 2c8399a3a44..00000000000 --- a/lib/editor/atto/plugins/table/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_table - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_table\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_table implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/table/lang/en/atto_table.php b/lib/editor/atto/plugins/table/lang/en/atto_table.php deleted file mode 100644 index c62471d80e0..00000000000 --- a/lib/editor/atto/plugins/table/lang/en/atto_table.php +++ /dev/null @@ -1,66 +0,0 @@ -. - -/** - * Strings for component 'atto_table', language 'en'. - * - * @package atto_table - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['addcolumnafter'] = 'Insert column after'; -$string['addrowafter'] = 'Insert row after'; -$string['all'] = 'Around each cell'; -$string['allowbackgroundcolour'] = 'Allow background colour'; -$string['allowborder'] = 'Allow border styling'; -$string['allowborder_desc'] = 'If enabled, table and cell borders can be customised.'; -$string['allowwidth'] = 'Allow width'; -$string['appearance'] = 'Appearance'; -$string['backgroundcolour'] = 'Background colour'; -$string['both'] = 'Both'; -$string['bordercolour'] = 'Border colour'; -$string['borders'] = 'Borders'; -$string['bordersize'] = 'Size of borders'; -$string['borderstyles'] = 'Style of borders'; -$string['caption'] = 'Caption'; -$string['captionposition'] = 'Caption position'; -$string['columns'] = 'Columns'; -$string['createtable'] = 'Create table'; -$string['deletecolumn'] = 'Delete column'; -$string['deleterow'] = 'Delete row'; -$string['dashed'] = 'Dashed'; -$string['dotted'] = 'Dotted'; -$string['edittable'] = 'Edit table'; -$string['headers'] = 'Define headers on'; -$string['movecolumnleft'] = 'Move column left'; -$string['movecolumnright'] = 'Move column right'; -$string['moverowdown'] = 'Move row down'; -$string['moverowup'] = 'Move row up'; -$string['noborder'] = 'No border'; -$string['none'] = 'None'; -$string['numberofcolumns'] = 'Number of columns'; -$string['numberofrows'] = 'Number of rows'; -$string['outer'] = 'Around table'; -$string['pluginname'] = 'Table'; -$string['rows'] = 'Rows'; -$string['settings'] = 'Table settings'; -$string['solid'] = 'Solid'; -$string['themedefault'] = 'Theme default'; -$string['transparent'] = 'Transparent'; -$string['updatetable'] = 'Update table'; -$string['width'] = 'Table width (in %)'; -$string['privacy:metadata'] = 'The atto_table plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/table/lib.php b/lib/editor/atto/plugins/table/lib.php deleted file mode 100644 index 4d177aee70d..00000000000 --- a/lib/editor/atto/plugins/table/lib.php +++ /dev/null @@ -1,85 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_table - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the js strings required for this module. - */ -function atto_table_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('createtable', - 'updatetable', - 'appearance', - 'headers', - 'caption', - 'columns', - 'rows', - 'numberofcolumns', - 'numberofrows', - 'both', - 'edittable', - 'addcolumnafter', - 'addrowafter', - 'movecolumnright', - 'movecolumnleft', - 'moverowdown', - 'moverowup', - 'deleterow', - 'deletecolumn', - 'captionposition', - 'borders', - 'bordersize', - 'bordercolour', - 'borderstyles', - 'none', - 'all', - 'backgroundcolour', - 'width', - 'outer', - 'noborder', - 'themedefault', - 'dotted', - 'dashed', - 'solid'), - 'atto_table'); - - $PAGE->requires->strings_for_js(array('top', - 'bottom'), - 'editor'); -} - -/** - * Set params for this plugin - * @param string $elementid - * @param string $options - * @param string $foptions - */ -function atto_table_params_for_js($elementid, $options, $foptions) { - $params = array('allowBorders' => (bool) get_config('atto_table', 'allowborders'), - 'allowWidth' => (bool) get_config('atto_table', 'allowwidth'), - 'allowBackgroundColour' => (bool) get_config('atto_table', 'allowbackgroundcolour')); - return $params; -} diff --git a/lib/editor/atto/plugins/table/settings.php b/lib/editor/atto/plugins/table/settings.php deleted file mode 100644 index df0448d3931..00000000000 --- a/lib/editor/atto/plugins/table/settings.php +++ /dev/null @@ -1,58 +0,0 @@ -. - -/** - * Settings that allow turning on and off various table features - * - * @package atto_table - * @copyright 2015 Joseph Inhofer - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$ADMIN->add('editoratto', new admin_category('atto_table', new lang_string('pluginname', 'atto_table'))); - -$settings = new admin_settingpage('atto_table_settings', new lang_string('settings', 'atto_table')); -if ($ADMIN->fulltree) { - $name = new lang_string('allowborder', 'atto_table'); - $desc = new lang_string('allowborder_desc', 'atto_table'); - $default = 0; - - $setting = new admin_setting_configcheckbox('atto_table/allowborders', - $name, - $desc, - $default); - $settings->add($setting); - - $name = new lang_string('allowbackgroundcolour', 'atto_table'); - $default = 0; - - $setting = new admin_setting_configcheckbox('atto_table/allowbackgroundcolour', - $name, - '', - $default); - $settings->add($setting); - - $name = new lang_string('allowwidth', 'atto_table'); - $default = 0; - - $setting = new admin_setting_configcheckbox('atto_table/allowwidth', - $name, - '', - $default); - $settings->add($setting); -} diff --git a/lib/editor/atto/plugins/table/styles.css b/lib/editor/atto/plugins/table/styles.css deleted file mode 100644 index 1c68da3477f..00000000000 --- a/lib/editor/atto/plugins/table/styles.css +++ /dev/null @@ -1,29 +0,0 @@ -div.editor_atto_content td, -div.editor_atto_content th, -div.editor_atto_content caption { - border: 1px dashed #bbb; - position: relative; - min-width: 2rem; - height: 2rem; -} - -div.editor_atto_content caption { - height: auto; -} - -div.availablecolors { - background-color: #eee; - padding: 0.5rem; -} -div.availablecolors .tablebordercolor, -div.availablecolors .tablebackgroundcolor { - display: inline-flex; - justify-content: center; - align-items: center; - width: 2rem; - height: 2rem; - text-align: center; - vertical-align: sub; - border-radius: 25%; - margin-right: 0.2rem; -} diff --git a/lib/editor/atto/plugins/table/tests/behat/table.feature b/lib/editor/atto/plugins/table/tests/behat/table.feature deleted file mode 100644 index 1f3e5d4e0e3..00000000000 --- a/lib/editor/atto/plugins/table/tests/behat/table.feature +++ /dev/null @@ -1,404 +0,0 @@ -@editor @editor_atto @atto @atto_table @_bug_phantomjs -Feature: Atto tables - To format text in Atto, I need to create tables - - @javascript - Scenario: Create a table - Given I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - And I set the field "Caption" to "Dinner" - And I press "Create table" - And I press "Save changes" - Then ".blog_entry table caption" "css_element" should be visible - - @javascript - Scenario: Edit a table - Given I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - And I click on "Edit table" "link" - And I set the field "Caption" to "Dinner" - And I press "Update table" - And I press "Save changes" - Then ".blog_entry table caption" "css_element" should be visible - - @javascript - Scenario: Check table setting defaults on new table - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - Then the ".moodle-dialogue-base .atto_form .borderstyle" "css_element" should be disabled - And the ".moodle-dialogue-base .atto_form .bordersize" "css_element" should be disabled - And the "borderColour" "radio" should be disabled - And the field "borders" matches value "default" - And the field "Theme default" matches value "1" - And the field "Table width (in %)" matches value "" - - @javascript - Scenario: Edit a table restores settings - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - And I click on "Edit table" "link" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I set the field "Size of borders" to "2" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .bordercolour" "css_element" - And I press "Update table" - And I select the text in the "Blog entry body" Atto editor - And I click on "Table" "button" - When I click on "Edit table" "link" - # Check that the background colour is set correctly. - Then the field with xpath "//div[@class='tablebackgroundcolor']/input[@name='backgroundColour' and @value='#FFFFFF']" matches value "1" - And the field "Table width (in %)" matches value "100" - And the field "Borders" matches value "Around table" - And the field "Style of borders" matches value "dashed" - And the field "Size of borders" matches value "2" - # Check that the border colour is set correctly. - And the field with xpath "//div[@class='tablebordercolor']/input[@name='borderColour' and @value='#FFFFFF']" matches value "1" - - @javascript - Scenario: Create a table with background colour and width with border settings off - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 0 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - Then ".moodle-dialogue-base .atto_form .borders" "css_element" should not exist - Then ".moodle-dialogue-base .atto_form .borderstyle" "css_element" should not exist - Then ".moodle-dialogue-base .atto_form .bordersize" "css_element" should not exist - Then ".moodle-dialogue-base .atto_form .bordercolour" "css_element" should not exist - Then ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" should exist - Then ".moodle-dialogue-base .atto_form .customwidth" "css_element" should exist - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I press "Create table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - - @javascript - Scenario: Edit a table with background colour and width with border settings off - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 0 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - When I click on "Edit table" "link" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I press "Update table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - - @javascript - Scenario: Create a table with background colour and width with borders on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - Then ".moodle-dialogue-base .atto_form .borders" "css_element" should exist - Then ".moodle-dialogue-base .atto_form .borderstyle" "css_element" should exist - Then ".moodle-dialogue-base .atto_form .bordersize" "css_element" should exist - Then ".moodle-dialogue-base .atto_form .bordercolour" "css_element" should exist - Then ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" should exist - Then ".moodle-dialogue-base .atto_form .customwidth" "css_element" should exist - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I press "Create table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - - @javascript - Scenario: Edit a table with background colour and width with borders on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - When I click on "Edit table" "link" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around each cell" - And I press "Update table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - - @javascript - Scenario: Create a table with background colour and width with borders and border styling on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I press "Create table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - And I should see "border-style:dashed;" - - @javascript - Scenario: Edit a table with background colour and width with borders and border styling on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - When I click on "Edit table" "link" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I press "Update table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - And I should see "border-style:dashed;" - - @javascript - Scenario: Create a table with background colour and width with borders, border styling, and border size on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I set the field "Size of borders" to "2" - And I press "Create table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - And I should see "border-style:dashed;" - And I should see "border-width:2px;" - - @javascript - Scenario: Edit a table with background colour and width with borders, border styling, and border size on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - When I click on "Edit table" "link" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I set the field "Size of borders" to "2" - And I press "Update table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - And I should see "border-style:dashed;" - And I should see "border-width:2px;" - - @javascript - Scenario: Create a table with all settings on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "Table test" - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - When I click on "Table" "button" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I set the field "Size of borders" to "2" - And I click on "#FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .bordercolour" "css_element" - And I press "Create table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - And I should see "dashed" - And I should see "2px" - And I should see "rgb(255,255,255)" - - @javascript - Scenario: Edit a table with background colour and width with borders, border styling, and border size on - Given the following config values are set as admin: - | config | value | plugin | - | allowborders | 1 | atto_table | - | allowbackgroundcolour | 1 | atto_table | - | allowwidth | 1 | atto_table | - And I log in as "admin" - And I follow "Profile" in the user menu - And I follow "Blog entries" - And I follow "Add a new entry" - And I set the field "Entry title" to "How to make a table" - And I set the field "Blog entry body" to "
                            Cell
                            " - And I select the text in the "Blog entry body" Atto editor - And I click on "Show more buttons" "button" - And I click on "Table" "button" - When I click on "Edit table" "link" - And I click on "FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .backgroundcolour" "css_element" - And I set the field "Table width (in %)" to "100" - And I set the field "Borders" to "Around table" - And I set the field "Style of borders" to "Dashed" - And I set the field "Size of borders" to "2" - And I click on "FFFFFF" "radio" in the ".moodle-dialogue-base .atto_form .bordercolour" "css_element" - And I press "Update table" - And I press "Save changes" - And I follow "Edit" - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - Then I should see "background-color:rgb(255,255,255);" - And I should see "width:100%;" - And I should see "dashed" - And I should see "2px" - And I should see "rgb(255,255,255)" diff --git a/lib/editor/atto/plugins/table/version.php b/lib/editor/atto/plugins/table/version.php deleted file mode 100644 index 35efa74cbc6..00000000000 --- a/lib/editor/atto/plugins/table/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_table - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_table'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-debug.js b/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-debug.js deleted file mode 100644 index 42217618ec9..00000000000 --- a/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-debug.js +++ /dev/null @@ -1,1557 +0,0 @@ -YUI.add('moodle-atto_table-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_table - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_table-button - */ - -/** - * Atto text editor table plugin. - * - * @namespace M.atto_table - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_table', - DEFAULT = { - BORDERSTYLE: 'none', - BORDERWIDTH: '1' - }, - DIALOGUE = { - WIDTH: '480px' - }, - TEMPLATE = '' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '{{#if nonedit}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '{{/if}}' + - '{{#if allowStyling}}' + - '
                            ' + - '{{get_string "appearance" component}}' + - '{{#if allowBorders}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '' + - '
                            ' + - '{{#each availableColours}}' + - '
                            ' + - '' + - '' + - '
                            ' + - '{{/each}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{/if}}' + - '{{#if allowBackgroundColour}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '' + - '' + - '
                            ' + - - '{{#each availableColours}}' + - '
                            ' + - '' + - '' + - '
                            ' + - '{{/each}}' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{/if}}' + - '{{#if allowWidth}}' + - '
                            ' + - '
                            ' + - '' + - '
                            ' + - '
                            ' + - '' + - '' + - '
                            ' + - '
                            ' + - '
                            ' + - '{{/if}}' + - '
                            ' + - '{{/if}}' + - '
                            ' + - '
                            ' + - '{{#if edit}}' + - '' + - '{{/if}}' + - '{{#if nonedit}}' + - '' + - '{{/if}}' + - '
                            ' + - '
                            ', - CSS = { - CAPTION: 'caption', - CAPTIONPOSITION: 'captionposition', - HEADERS: 'headers', - ROWS: 'rows', - COLUMNS: 'columns', - SUBMIT: 'submit', - FORM: 'atto_form', - BORDERS: 'borders', - BORDERSIZE: 'bordersize', - BORDERSIZEUNIT: 'px', - BORDERCOLOUR: 'bordercolour', - BORDERSTYLE: 'borderstyle', - BACKGROUNDCOLOUR: 'backgroundcolour', - WIDTH: 'customwidth', - WIDTHUNIT: '%', - AVAILABLECOLORS: 'availablecolors', - COLOURROW: 'colourrow' - }, - SELECTORS = { - CAPTION: '.' + CSS.CAPTION, - CAPTIONPOSITION: '.' + CSS.CAPTIONPOSITION, - HEADERS: '.' + CSS.HEADERS, - ROWS: '.' + CSS.ROWS, - COLUMNS: '.' + CSS.COLUMNS, - SUBMIT: '.' + CSS.SUBMIT, - BORDERS: '.' + CSS.BORDERS, - BORDERSIZE: '.' + CSS.BORDERSIZE, - BORDERCOLOURS: '.' + CSS.BORDERCOLOUR + ' input[name="borderColour"]', - SELECTEDBORDERCOLOUR: '.' + CSS.BORDERCOLOUR + ' input[name="borderColour"]:checked', - BORDERSTYLE: '.' + CSS.BORDERSTYLE, - BACKGROUNDCOLOURS: '.' + CSS.BACKGROUNDCOLOUR + ' input[name="backgroundColour"]', - SELECTEDBACKGROUNDCOLOUR: '.' + CSS.BACKGROUNDCOLOUR + ' input[name="backgroundColour"]:checked', - FORM: '.atto_form', - WIDTH: '.' + CSS.WIDTH, - AVAILABLECOLORS: '.' + CSS.AVAILABLECOLORS - }; - -Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * The contextual menu that we can open. - * - * @property _contextMenu - * @type M.editor_atto.Menu - * @private - */ - _contextMenu: null, - - /** - * The last modified target. - * - * @property _lastTarget - * @type Node - * @private - */ - _lastTarget: null, - - /** - * The list of menu items. - * - * @property _menuOptions - * @type Object - * @private - */ - _menuOptions: null, - - initializer: function() { - var button = this.addButton({ - icon: 'e/table', - callback: this._displayTableEditor, - tags: 'table' - }); - - // Listen for toggled highlighting. - require(['editor_atto/events'], function(attoEvents) { - var domButton = button.getDOMNode(); - domButton.addEventListener(attoEvents.eventTypes.attoButtonHighlightToggled, function(e) { - this._setAriaAttributes(e.detail.buttonName, e.detail.highlight); - }.bind(this)); - }.bind(this)); - - // Disable mozilla table controls. - if (Y.UA.gecko) { - document.execCommand("enableInlineTableEditing", false, false); - document.execCommand("enableObjectResizing", false, false); - } - }, - - /** - * Sets the appropriate ARIA attributes for the table button when it switches roles between a button and a menu button. - * - * @param {String} buttonName The button name. - * @param {Boolean} highlight True when the button was highlighted. False, otherwise. - * @private - */ - _setAriaAttributes: function(buttonName, highlight) { - var menuButton = this.buttons[buttonName]; - if (menuButton) { - if (highlight) { - // This button becomes a menu button. Add appropriate ARIA attributes. - var id = menuButton.getAttribute('id'); - menuButton.setAttribute('aria-haspopup', true); - menuButton.setAttribute('aria-controls', id + '_menu'); - menuButton.setAttribute('aria-expanded', true); - } else { - menuButton.removeAttribute('aria-haspopup'); - menuButton.removeAttribute('aria-controls'); - menuButton.removeAttribute('aria-expanded'); - } - } - }, - - /** - * Display the table tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current cursor position. - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection !== false && (!this._currentSelection.collapsed)) { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createtable', COMPONENT), - focusAfterHide: true, - focusOnShowSelector: SELECTORS.CAPTION, - width: DIALOGUE.WIDTH - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent(false)) - .show(); - - this._updateAvailableSettings(); - } - }, - - /** - * Display the appropriate table editor. - * - * If the current selection includes a table, then we show the - * contextual menu, otherwise show the table creation dialogue. - * - * @method _displayTableEditor - * @param {EventFacade} e - * @private - */ - _displayTableEditor: function(e) { - var cell = this._getSuitableTableCell(); - var menuButton = e.currentTarget.ancestor('button', true); - if (cell) { - var id = menuButton.getAttribute('id'); - - // Indicate that the menu is expanded. - menuButton.setAttribute('aria-expanded', true); - - // Add the cell to the EventFacade to save duplication in when showing the menu. - e.tableCell = cell; - return this._showTableMenu(e, id); - } else { - // Dialog mode. Remove aria-expanded attribute. - menuButton.removeAttribute('aria-expanded'); - } - return this._displayDialogue(e); - }, - - /** - * Returns whether or not the parameter node exists within the editor. - * - * @method _stopAtContentEditableFilter - * @param {Node} node - * @private - * @return {boolean} whether or not the parameter node exists within the editor. - */ - _stopAtContentEditableFilter: function(node) { - return this.editor.contains(node); - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function(edit) { - var template = Y.Handlebars.compile(TEMPLATE); - var allowBorders = this.get('allowBorders'); - - this._content = Y.Node.create(template({ - CSS: CSS, - elementid: this.get('host').get('elementid'), - component: COMPONENT, - edit: edit, - nonedit: !edit, - allowStyling: this.get('allowStyling'), - allowBorders: allowBorders, - borderStyles: this.get('borderStyles'), - allowBackgroundColour: this.get('allowBackgroundColour'), - availableColours: this.get('availableColors'), - allowWidth: this.get('allowWidth') - })); - - // Handle table setting. - if (edit) { - this._content.one('.submit').on('click', this._updateTable, this); - } else { - this._content.one('.submit').on('click', this._setTable, this); - } - - if (allowBorders) { - this._content.one('[name="borders"]').on('change', this._updateAvailableSettings, this); - } - - return this._content; - }, - - /** - * Disables options within the dialogue if they shouldn't be available. - * E.g. - * If borders are set to "Theme default" then the border size, style and - * colour options are disabled. - * - * @method _updateAvailableSettings - * @private - */ - _updateAvailableSettings: function() { - var tableForm = this._content, - enableBorders = tableForm.one('[name="borders"]'), - borderStyle = tableForm.one('[name="borderstyles"]'), - borderSize = tableForm.one('[name="bordersize"]'), - borderColour = tableForm.all('[name="borderColour"]'), - disabledValue = 'removeAttribute'; - - if (!enableBorders) { - return; - } - - if (enableBorders.get('value') === 'default') { - disabledValue = 'setAttribute'; - } - - if (borderStyle) { - borderStyle[disabledValue]('disabled'); - } - - if (borderSize) { - borderSize[disabledValue]('disabled'); - } - - if (borderColour) { - borderColour[disabledValue]('disabled'); - } - - }, - - /** - * Given the current selection, return a table cell suitable for table editing - * purposes, i.e. the first table cell selected, or the first cell in the table - * that the selection exists in, or null if not within a table. - * - * @method _getSuitableTableCell - * @private - * @return {Node} suitable target cell, or null if not within a table - */ - _getSuitableTableCell: function() { - var targetcell = null, - host = this.get('host'); - var stopAtContentEditableFilter = Y.bind(this._stopAtContentEditableFilter, this); - - host.getSelectedNodes().some(function(node) { - if (node.ancestor('td, th, caption', true, stopAtContentEditableFilter)) { - targetcell = node; - - var caption = node.ancestor('caption', true, stopAtContentEditableFilter); - if (caption) { - var table = caption.get('parentNode'); - if (table) { - targetcell = table.one('td, th'); - } - } - - // Once we've found a cell to target, we shouldn't need to keep looking. - return true; - } - }); - - if (targetcell) { - var selection = host.getSelectionFromNode(targetcell); - host.setSelection(selection); - } - - return targetcell; - }, - - /** - * Change a node from one type to another, copying all attributes and children. - * - * @method _changeNodeType - * @param {Y.Node} node - * @param {String} new node type - * @private - * @chainable - */ - _changeNodeType: function(node, newType) { - var newNode = Y.Node.create('<' + newType + '>'); - newNode.setAttrs(node.getAttrs()); - node.get('childNodes').each(function(child) { - newNode.append(child.remove()); - }); - node.replace(newNode); - return newNode; - }, - - /** - * Handle updating an existing table. - * - * @method _updateTable - * @param {EventFacade} e - * @private - */ - _updateTable: function(e) { - var caption, - captionposition, - headers, - borders, - bordersize, - borderstyle, - bordercolour, - backgroundcolour, - table, - width, - captionnode; - - e.preventDefault(); - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Add/update the caption. - caption = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTION); - captionposition = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTIONPOSITION); - headers = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.HEADERS); - borders = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERS); - bordersize = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSIZE); - bordercolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBORDERCOLOUR); - borderstyle = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSTYLE); - backgroundcolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBACKGROUNDCOLOUR); - width = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.WIDTH); - - table = this._lastTarget.ancestor('table'); - this._setAppearance(table, { - width: width, - borders: borders, - borderColour: bordercolour, - borderSize: bordersize, - borderStyle: borderstyle, - backgroundColour: backgroundcolour - }); - - captionnode = table.one('caption'); - if (!captionnode) { - captionnode = Y.Node.create(''); - table.insert(captionnode, 0); - } - captionnode.setHTML(caption.get('value')); - captionnode.setStyle('caption-side', captionposition.get('value')); - if (!captionnode.getAttribute('style')) { - captionnode.removeAttribute('style'); - } - - // Add the row headers. - if (headers.get('value') === 'rows' || headers.get('value') === 'both') { - table.all('tr').each(function(row) { - var cells = row.all('th, td'), - firstCell = cells.shift(), - newCell; - - if (firstCell.get('tagName') === 'TD') { - // Cell is a td but should be a th - change it. - newCell = this._changeNodeType(firstCell, 'th'); - newCell.setAttribute('scope', 'row'); - } else { - firstCell.setAttribute('scope', 'row'); - } - - // Now make sure all other cells in the row are td. - cells.each(function(cell) { - if (cell.get('tagName') === 'TH') { - newCell = this._changeNodeType(cell, 'td'); - newCell.removeAttribute('scope'); - } - }, this); - - }, this); - } - // Add the col headers. These may overrule the row headers in the first cell. - if (headers.get('value') === 'columns' || headers.get('value') === 'both') { - var rows = table.all('tr'), - firstRow = rows.shift(), - newCell; - - firstRow.all('td, th').each(function(cell) { - if (cell.get('tagName') === 'TD') { - // Cell is a td but should be a th - change it. - newCell = this._changeNodeType(cell, 'th'); - newCell.setAttribute('scope', 'col'); - } else { - cell.setAttribute('scope', 'col'); - } - }, this); - // Change all the cells in the rest of the table to tds (unless they are row headers). - rows.each(function(row) { - var cells = row.all('th, td'); - - if (headers.get('value') === 'both') { - // Ignore the first cell because it's a row header. - cells.shift(); - } - cells.each(function(cell) { - if (cell.get('tagName') === 'TH') { - newCell = this._changeNodeType(cell, 'td'); - newCell.removeAttribute('scope'); - } - }, this); - - }, this); - } - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Handle creation of a new table. - * - * @method _setTable - * @param {EventFacade} e - * @private - */ - _setTable: function(e) { - var caption, - captionposition, - borders, - bordersize, - borderstyle, - bordercolour, - rows, - cols, - headers, - tablehtml, - backgroundcolour, - width, - i, j; - - e.preventDefault(); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - caption = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTION); - captionposition = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTIONPOSITION); - borders = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERS); - bordersize = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSIZE); - bordercolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBORDERCOLOUR); - borderstyle = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSTYLE); - backgroundcolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBACKGROUNDCOLOUR); - rows = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.ROWS); - cols = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.COLUMNS); - headers = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.HEADERS); - width = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.WIDTH); - - // Set the selection. - this.get('host').setSelection(this._currentSelection); - - // Note there are some spaces inserted in the cells and before and after, so that users have somewhere to click. - var nl = "\n"; - var tableId = Y.guid(); - tablehtml = '
                            ' + nl + '' + nl; - - var captionstyle = ''; - if (captionposition.get('value')) { - captionstyle = ' style="caption-side: ' + captionposition.get('value') + '"'; - } - tablehtml += '' + Y.Escape.html(caption.get('value')) + '' + nl; - i = 0; - if (headers.get('value') === 'columns' || headers.get('value') === 'both') { - i = 1; - tablehtml += '' + nl + '' + nl; - for (j = 0; j < parseInt(cols.get('value'), 10); j++) { - tablehtml += '' + nl; - } - tablehtml += '' + nl + '' + nl; - } - tablehtml += '' + nl; - for (; i < parseInt(rows.get('value'), 10); i++) { - tablehtml += '' + nl; - for (j = 0; j < parseInt(cols.get('value'), 10); j++) { - if (j === 0 && (headers.get('value') === 'rows' || headers.get('value') === 'both')) { - tablehtml += '' + nl; - } else { - tablehtml += '' + nl; - } - } - tablehtml += '' + nl; - } - tablehtml += '' + nl; - tablehtml += '
                            ' + nl + '
                            '; - - this.get('host').insertContentAtFocusPoint(tablehtml); - - var tableNode = Y.one('#' + tableId); - this._setAppearance(tableNode, { - width: width, - borders: borders, - borderColour: bordercolour, - borderSize: bordersize, - borderStyle: borderstyle, - backgroundColour: backgroundcolour - }); - tableNode.removeAttribute('id'); - - // Mark the content as updated. - this.markUpdated(); - }, - - /** - * Search for all the cells in the current, next and previous columns. - * - * @method _findColumnCells - * @private - * @return {Object} containing current, prev and next {Y.NodeList}s - */ - _findColumnCells: function() { - var columnindex = this._getColumnIndex(this._lastTarget), - rows = this._lastTarget.ancestor('table').all('tr'), - currentcells = new Y.NodeList(), - prevcells = new Y.NodeList(), - nextcells = new Y.NodeList(); - - rows.each(function(row) { - var cells = row.all('td, th'), - cell = cells.item(columnindex), - cellprev = cells.item(columnindex - 1), - cellnext = cells.item(columnindex + 1); - currentcells.push(cell); - if (cellprev) { - prevcells.push(cellprev); - } - if (cellnext) { - nextcells.push(cellnext); - } - }); - - return { - current: currentcells, - prev: prevcells, - next: nextcells - }; - }, - - /** - * Hide the entries in the context menu that don't make sense with the - * current selection. - * - * @method _hideInvalidEntries - * @param {Y.Node} node - The node containing the menu. - * @private - */ - _hideInvalidEntries: function(node) { - // Moving rows. - var table = this._lastTarget.ancestor('table'), - row = this._lastTarget.ancestor('tr'), - rows = table.all('tr'), - rowindex = rows.indexOf(row), - prevrow = rows.item(rowindex - 1), - prevrowhascells = prevrow ? prevrow.one('td') : null; - - if (!row || !prevrowhascells) { - node.one('[data-change="moverowup"]').hide(); - } else { - node.one('[data-change="moverowup"]').show(); - } - - var nextrow = rows.item(rowindex + 1), - rowhascell = row ? row.one('td') : false; - - if (!row || !nextrow || !rowhascell) { - node.one('[data-change="moverowdown"]').hide(); - } else { - node.one('[data-change="moverowdown"]').show(); - } - - // Moving columns. - var cells = this._findColumnCells(); - if (cells.prev.filter('td').size() > 0) { - node.one('[data-change="movecolumnleft"]').show(); - } else { - node.one('[data-change="movecolumnleft"]').hide(); - } - - var colhascell = cells.current.filter('td').size() > 0; - if ((cells.next.size() > 0) && colhascell) { - node.one('[data-change="movecolumnright"]').show(); - } else { - node.one('[data-change="movecolumnright"]').hide(); - } - - // Delete col - if (cells.current.filter('td').size() > 0) { - node.one('[data-change="deletecolumn"]').show(); - } else { - node.one('[data-change="deletecolumn"]').hide(); - } - // Delete row - if (!row || !row.one('td')) { - node.one('[data-change="deleterow"]').hide(); - } else { - node.one('[data-change="deleterow"]').show(); - } - }, - - /** - * Display the table menu. - * - * @method _showTableMenu - * @param {EventFacade} e - * @param {String} buttonId The ID of the menu button associated with this menu. - * @private - */ - _showTableMenu: function(e, buttonId) { - e.preventDefault(); - - var boundingBox; - var creatorButton = this.buttons[this.name]; - - if (!this._contextMenu) { - this._menuOptions = [ - { - text: M.util.get_string("addcolumnafter", COMPONENT), - data: { - change: "addcolumnafter" - } - }, { - text: M.util.get_string("addrowafter", COMPONENT), - data: { - change: "addrowafter" - } - }, { - text: M.util.get_string("moverowup", COMPONENT), - data: { - change: "moverowup" - } - }, { - text: M.util.get_string("moverowdown", COMPONENT), - data: { - change: "moverowdown" - } - }, { - text: M.util.get_string("movecolumnleft", COMPONENT), - data: { - change: "movecolumnleft" - } - }, { - text: M.util.get_string("movecolumnright", COMPONENT), - data: { - change: "movecolumnright" - } - }, { - text: M.util.get_string("deleterow", COMPONENT), - data: { - change: "deleterow" - } - }, { - text: M.util.get_string("deletecolumn", COMPONENT), - data: { - change: "deletecolumn" - } - }, { - text: M.util.get_string("edittable", COMPONENT), - data: { - change: "edittable" - } - } - ]; - - creatorButton.insert(Y.Node.create(''), 'after'); - this._contextMenu = new Y.M.editor_atto.Menu({ - items: this._menuOptions, - buttonId: buttonId, - attachmentPoint: '#' + buttonId + '_menu' - }); - - // Add event handlers for table control menus. - boundingBox = this._contextMenu.get('boundingBox'); - boundingBox.delegate('click', this._handleTableChange, 'a', this); - } - - boundingBox = this._contextMenu.get('boundingBox'); - - // We store the cell of the last click (the control node is transient). - this._lastTarget = e.tableCell.ancestor('.editor_atto_content td, .editor_atto_content th', true); - - this._hideInvalidEntries(boundingBox); - - // Clear the focusAfterHide for any other menus which may be open. - Y.Array.each(this.get('host').openMenus, function(menu) { - menu.set('focusAfterHide', null); - }); - - // Ensure that we focus on the button in the toolbar when we tab back to the menu. - this.get('host')._setTabFocus(creatorButton); - - // Show the context menu, and align to the current position. - this._contextMenu.show(); - this._contextMenu.align(this.buttons.table, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]); - this._contextMenu.set('focusAfterHide', creatorButton); - - // If there are any anchors in the bounding box, focus on the first. - if (boundingBox.one('a')) { - boundingBox.one('a').focus(); - } - - // Add this menu to the list of open menus. - this.get('host').openMenus = [this._contextMenu]; - }, - - /** - * Handle a selection from the table control menu. - * - * @method _handleTableChange - * @param {EventFacade} e - * @private - */ - _handleTableChange: function(e) { - e.preventDefault(); - - this._contextMenu.set('focusAfterHide', this.get('host').editor); - // Hide the context menu. - this._contextMenu.hide(e); - - // Make our changes. - switch (e.target.getData('change')) { - case 'addcolumnafter': - this._addColumnAfter(); - break; - case 'addrowafter': - this._addRowAfter(); - break; - case 'deleterow': - this._deleteRow(); - break; - case 'deletecolumn': - this._deleteColumn(); - break; - case 'edittable': - this._editTable(); - break; - case 'moverowdown': - this._moveRowDown(); - break; - case 'moverowup': - this._moveRowUp(); - break; - case 'movecolumnleft': - this._moveColumnLeft(); - break; - case 'movecolumnright': - this._moveColumnRight(); - break; - } - }, - - /** - * Determine the index of a row in a table column. - * - * @method _getRowIndex - * @param {Node} cell - * @private - */ - _getRowIndex: function(cell) { - var tablenode = cell.ancestor('table'), - rownode = cell.ancestor('tr'); - - if (!tablenode || !rownode) { - return; - } - - var rows = tablenode.all('tr'); - - return rows.indexOf(rownode); - }, - - /** - * Determine the index of a column in a table row. - * - * @method _getColumnIndex - * @param {Node} cellnode - * @private - */ - _getColumnIndex: function(cellnode) { - var rownode = cellnode.ancestor('tr'); - - if (!rownode) { - return; - } - - var cells = rownode.all('td, th'); - - return cells.indexOf(cellnode); - }, - - /** - * Delete the current row. - * - * @method _deleteRow - * @private - */ - _deleteRow: function() { - var row = this._lastTarget.ancestor('tr'); - - if (row && row.one('td')) { - // Only delete rows with at least one non-header cell. - row.remove(true); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Move row up - * - * @method _moveRowUp - * @private - */ - _moveRowUp: function() { - var row = this._lastTarget.ancestor('tr'), - prevrow = row.previous('tr'); - if (!row || !prevrow) { - return; - } - - row.swap(prevrow); - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Move column left - * - * @method _moveColumnLeft - * @private - */ - _moveColumnLeft: function() { - var cells = this._findColumnCells(); - - if (cells.current.size() > 0 && cells.prev.size() > 0 && cells.current.size() === cells.prev.size()) { - var i = 0; - for (i = 0; i < cells.current.size(); i++) { - var cell = cells.current.item(i), - prevcell = cells.prev.item(i); - - cell.swap(prevcell); - } - } - // Cleanup. - this.markUpdated(); - }, - - /** - * Add a caption to the table if it doesn't have one. - * - * @method _addCaption - * @private - */ - _addCaption: function() { - var table = this._lastTarget.ancestor('table'), - caption = table.one('caption'); - - if (!caption) { - table.insert(Y.Node.create(' '), 1); - } - }, - - /** - * Remove a caption from the table if has one. - * - * @method _removeCaption - * @private - */ - _removeCaption: function() { - var table = this._lastTarget.ancestor('table'), - caption = table.one('caption'); - - if (caption) { - caption.remove(true); - } - }, - - /** - * Move column right. - * - * @method _moveColumnRight - * @private - */ - _moveColumnRight: function() { - var cells = this._findColumnCells(); - - // Check we have some tds in this column, and one exists to the right. - if ((cells.next.size() > 0) && - (cells.current.size() === cells.next.size()) && - (cells.current.filter('td').size() > 0)) { - var i = 0; - for (i = 0; i < cells.current.size(); i++) { - var cell = cells.current.item(i), - nextcell = cells.next.item(i); - - cell.swap(nextcell); - } - } - // Cleanup. - this.markUpdated(); - }, - - /** - * Move row down. - * - * @method _moveRowDown - * @private - */ - _moveRowDown: function() { - var row = this._lastTarget.ancestor('tr'), - nextrow = row.next('tr'); - if (!row || !nextrow || !row.one('td')) { - return; - } - - row.swap(nextrow); - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Obtain values for the table borders - * - * @method _getBorderConfiguration - * @param {Node} node - * @private - * @return {Array} or {Boolean} Returns the settings, if presents, or else returns false - */ - _getBorderConfiguration: function(node) { - // We need to make a clone of the node in order to avoid grabbing any - // of the computed styles from the DOM. We only want inline styles set by us. - var shadowNode = node.cloneNode(true); - var borderStyle = shadowNode.getStyle('borderStyle'), - borderColor = shadowNode.getStyle('borderColor'), - borderWidth = shadowNode.getStyle('borderWidth'); - - if (borderStyle || borderColor || borderWidth) { - var hexColour = Y.Color.toHex(borderColor); - var width = parseInt(borderWidth, 10); - return { - borderStyle: borderStyle, - borderColor: hexColour === "#" ? null : hexColour, - borderWidth: isNaN(width) ? null : width - }; - } - - return false; - }, - - /** - * Set the appropriate styles on the given table node according to - * the provided configuration. - * - * @method _setAppearance - * @param {Node} The table node to be modified. - * @param {Object} Configuration object (associative array) containing the form nodes for - * border styling. - * @private - */ - _setAppearance: function(tableNode, configuration) { - var borderhex, - borderSizeValue, - borderStyleValue, - backgroundcolourvalue; - - if (configuration.borderColour) { - borderhex = configuration.borderColour.get('value'); - } - - if (configuration.borderSize) { - borderSizeValue = configuration.borderSize.get('value'); - } - - if (configuration.borderStyle) { - borderStyleValue = configuration.borderStyle.get('value'); - } - - if (configuration.backgroundColour) { - backgroundcolourvalue = configuration.backgroundColour.get('value'); - } - - // Clear the inline border styling - tableNode.removeAttribute('style'); - tableNode.all('td, th').each(function(cell) { - cell.removeAttribute('style'); - }, this); - - if (configuration.borders) { - if (configuration.borders.get('value') === 'outer') { - tableNode.setStyle('borderWidth', borderSizeValue + CSS.BORDERSIZEUNIT); - tableNode.setStyle('borderStyle', borderStyleValue); - - if (borderhex !== 'none') { - tableNode.setStyle('borderColor', borderhex); - } - } else if (configuration.borders.get('value') === 'all') { - tableNode.all('td, th').each(function(cell) { - cell.setStyle('borderWidth', borderSizeValue + CSS.BORDERSIZEUNIT); - cell.setStyle('borderStyle', borderStyleValue); - - if (borderhex !== 'none') { - cell.setStyle('borderColor', borderhex); - } - }, this); - } - } - - if (backgroundcolourvalue !== 'none') { - tableNode.setStyle('backgroundColor', backgroundcolourvalue); - } - - if (configuration.width && configuration.width.get('value')) { - tableNode.setStyle('width', configuration.width.get('value') + CSS.WIDTHUNIT); - } - }, - - /** - * Edit table (show the dialogue). - * - * @method _editTable - * @private - */ - _editTable: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('edittable', COMPONENT), - focusAfterHide: false, - focusOnShowSelector: SELECTORS.CAPTION, - width: DIALOGUE.WIDTH - }); - - // Set the dialogue content, and then show the dialogue. - var node = this._getDialogueContent(true), - captioninput = node.one(SELECTORS.CAPTION), - captionpositioninput = node.one(SELECTORS.CAPTIONPOSITION), - headersinput = node.one(SELECTORS.HEADERS), - borderinput = node.one(SELECTORS.BORDERS), - borderstyle = node.one(SELECTORS.BORDERSTYLE), - bordercolours = node.all(SELECTORS.BORDERCOLOURS), - bordersize = node.one(SELECTORS.BORDERSIZE), - backgroundcolours = node.all(SELECTORS.BACKGROUNDCOLOURS), - width = node.one(SELECTORS.WIDTH), - table = this._lastTarget.ancestor('table'), - captionnode = table.one('caption'), - hexColour, - matchedInput; - - if (captionnode) { - captioninput.set('value', captionnode.getHTML()); - } else { - captioninput.set('value', ''); - } - - if (width && table.getStyle('width').indexOf('px') === -1) { - width.set('value', parseInt(table.getStyle('width'), 10)); - } - - if (captionpositioninput && captionnode && captionnode.getAttribute('style')) { - captionpositioninput.set('value', captionnode.getStyle('caption-side')); - } else { - // Default to none. - captionpositioninput.set('value', ''); - } - - if (table.getStyle('backgroundColor') && this.get('allowBackgroundColour')) { - hexColour = Y.Color.toHex(table.getStyle('backgroundColor')); - matchedInput = backgroundcolours.filter('[value="' + hexColour + '"]'); - - if (matchedInput) { - matchedInput.set("checked", true); - } - } - - if (this.get('allowBorders')) { - var borderValue = 'default', - borderConfiguration = this._getBorderConfiguration(table); - - if (borderConfiguration) { - borderValue = 'outer'; - } else { - borderConfiguration = this._getBorderConfiguration(table.one('td')); - if (borderConfiguration) { - borderValue = 'all'; - } - } - - if (borderConfiguration) { - var borderStyle = borderConfiguration.borderStyle || DEFAULT.BORDERSTYLE; - var borderSize = borderConfiguration.borderWidth || DEFAULT.BORDERWIDTH; - borderstyle.set('value', borderStyle); - bordersize.set('value', borderSize); - borderinput.set('value', borderValue); - - hexColour = borderConfiguration.borderColor; - matchedInput = bordercolours.filter('[value="' + hexColour + '"]'); - - if (matchedInput) { - matchedInput.set("checked", true); - } - } - } - - var headersvalue = 'columns'; - if (table.one('th[scope="row"]')) { - headersvalue = 'rows'; - if (table.one('th[scope="col"]')) { - headersvalue = 'both'; - } - } - headersinput.set('value', headersvalue); - dialogue.set('bodyContent', node).show(); - this._updateAvailableSettings(); - }, - - - /** - * Delete the current column. - * - * @method _deleteColumn - * @private - */ - _deleteColumn: function() { - var columnindex = this._getColumnIndex(this._lastTarget), - table = this._lastTarget.ancestor('table'), - rows = table.all('tr'), - columncells = new Y.NodeList(), - hastd = false; - - rows.each(function(row) { - var cells = row.all('td, th'); - var cell = cells.item(columnindex); - if (cell.get('tagName') === 'TD') { - hastd = true; - } - columncells.push(cell); - }); - - // Do not delete all the headers. - if (hastd) { - columncells.remove(true); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Add a row after the current row. - * - * @method _addRowAfter - * @private - */ - _addRowAfter: function() { - var target = this._lastTarget.ancestor('tr'), - tablebody = this._lastTarget.ancestor('table').one('tbody'); - if (!tablebody) { - // Not all tables have tbody. - tablebody = this._lastTarget.ancestor('table'); - } - - var firstrow = tablebody.one('tr'); - if (!firstrow) { - firstrow = this._lastTarget.ancestor('table').one('tr'); - } - if (!firstrow) { - // Table has no rows. Boo. - return; - } - var newrow = firstrow.cloneNode(true); - newrow.all('th, td').each(function(tablecell) { - if (tablecell.get('tagName') === 'TH') { - if (tablecell.getAttribute('scope') !== 'row') { - var newcell = Y.Node.create(''); - tablecell.replace(newcell); - tablecell = newcell; - } - } - tablecell.setHTML(' '); - }); - - if (target.ancestor('thead')) { - target = firstrow; - tablebody.insert(newrow, target); - } else { - target.insert(newrow, 'after'); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Add a column after the current column. - * - * @method _addColumnAfter - * @private - */ - _addColumnAfter: function() { - var cells = this._findColumnCells(), - before = true, - clonecells = cells.next; - if (cells.next.size() <= 0) { - before = false; - clonecells = cells.current; - } - - Y.each(clonecells, function(cell) { - var newcell = cell.cloneNode(); - // Clear the content of the cell. - newcell.setHTML(' '); - - if (before) { - cell.get('parentNode').insert(newcell, cell); - } else { - cell.get('parentNode').insert(newcell, cell); - cell.swap(newcell); - } - }, this); - - // Clean the HTML. - this.markUpdated(); - } - -}, { - ATTRS: { - /** - * Whether or not to allow borders - * - * @attribute allowBorder - * @type Boolean - */ - allowBorders: { - value: true - }, - - /** - * What border styles to allow - * - * @attribute borderStyles - * @type Array - */ - borderStyles: { - value: [ - 'none', - 'solid', - 'dashed', - 'dotted' - ] - }, - - /** - * Whether or not to allow colourizing the background - * - * @attribute allowBackgroundColour - * @type Boolean - */ - allowBackgroundColour: { - value: true - }, - - /** - * Whether or not to allow setting the table width - * - * @attribute allowWidth - * @type Boolean - */ - allowWidth: { - value: true - }, - - /** - * Whether we allow styling - * @attribute allowStyling - * @type Boolean - */ - allowStyling: { - readOnly: true, - getter: function() { - return this.get('allowBorders') || this.get('allowBackgroundColour') || this.get('allowWidth'); - } - }, - - /** - * Available colors - * @attribute availableColors - * @type Array - */ - availableColors: { - value: [ - '#FFFFFF', - '#EF4540', - '#FFCF35', - '#98CA3E', - '#7D9FD3', - '#333333' - ], - readOnly: true - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-editor_atto-menu", "event", "event-valuechange"]}); diff --git a/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-min.js b/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-min.js deleted file mode 100644 index df6fa83cb2a..00000000000 --- a/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button-min.js +++ /dev/null @@ -1,5 +0,0 @@ -YUI.add("moodle-atto_table-button",function(v,e){var m="atto_table",_="none",p="1",f="480px",l={CAPTION:"caption",CAPTIONPOSITION:"captionposition",HEADERS:"headers",ROWS:"rows",COLUMNS:"columns",SUBMIT:"submit",FORM:"atto_form",BORDERS:"borders",BORDERSIZE:"bordersize",BORDERSIZEUNIT:"px",BORDERCOLOUR:"bordercolour",BORDERSTYLE:"borderstyle",BACKGROUNDCOLOUR:"backgroundcolour",WIDTH:"customwidth",WIDTHUNIT:"%",AVAILABLECOLORS:"availablecolors",COLOURROW:"colourrow"},O={CAPTION:"."+l.CAPTION,CAPTIONPOSITION:"."+l.CAPTIONPOSITION,HEADERS:"."+l.HEADERS,ROWS:"."+l.ROWS,COLUMNS:"."+l.COLUMNS,SUBMIT:"."+l.SUBMIT,BORDERS:"."+l.BORDERS,BORDERSIZE:"."+l.BORDERSIZE,BORDERCOLOURS:"."+l.BORDERCOLOUR+' input[name="borderColour"]',SELECTEDBORDERCOLOUR:"."+l.BORDERCOLOUR+' input[name="borderColour"]:checked',BORDERSTYLE:"."+l.BORDERSTYLE,BACKGROUNDCOLOURS:"."+l.BACKGROUNDCOLOUR+' input[name="backgroundColour"]',SELECTEDBACKGROUNDCOLOUR:"."+l.BACKGROUNDCOLOUR+' input[name="backgroundColour"]:checked',FORM:".atto_form",WIDTH:"."+l.WIDTH,AVAILABLECOLORS:"."+l.AVAILABLECOLORS};v.namespace("M.atto_table").Button=v.Base.create("button",v.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_contextMenu:null,_lastTarget:null,_menuOptions:null,initializer:function(){var t=this.addButton({icon:"e/table",callback:this._displayTableEditor,tags:"table"});require(["editor_atto/events"],function(e){t.getDOMNode().addEventListener(e.eventTypes.attoButtonHighlightToggled,function(e){this._setAriaAttributes(e.detail.buttonName,e.detail.highlight)}.bind(this))}.bind(this)),v.UA.gecko&&(document.execCommand("enableInlineTableEditing",!1,!1),document.execCommand("enableObjectResizing",!1,!1))},_setAriaAttributes:function(e,t){e=this.buttons[e];e&&(t?(t=e.getAttribute("id"),e.setAttribute("aria-haspopup",!0),e.setAttribute("aria-controls",t+"_menu"),e.setAttribute("aria-expanded",!0)):(e.removeAttribute("aria-haspopup"),e.removeAttribute("aria-controls"),e.removeAttribute("aria-expanded")))},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1===this._currentSelection||this._currentSelection.collapsed||(this.getDialogue({headerContent:M.util.get_string("createtable",m),focusAfterHide:!0,focusOnShowSelector:O.CAPTION,width:f}).set("bodyContent",this._getDialogueContent(!1)).show(),this._updateAvailableSettings())},_displayTableEditor:function(e){var t,o=this._getSuitableTableCell(),a=e.currentTarget.ancestor("button",!0);return o?(t=a.getAttribute("id"),a.setAttribute("aria-expanded",!0),e.tableCell=o,this._showTableMenu(e,t)):(a.removeAttribute("aria-expanded"),this._displayDialogue(e))},_stopAtContentEditableFilter:function(e){return this.editor.contains(e)},_getDialogueContent:function(e){var t=v.Handlebars.compile( -'
                            {{#if nonedit}}
                            {{/if}}{{#if allowStyling}}
                            {{get_string "appearance" component}}{{#if allowBorders}}
                            {{#each availableColours}}
                            {{/each}}
                            {{/if}}{{#if allowBackgroundColour}}
                            {{#each availableColours}}
                            {{/each}}
                            {{/if}}{{#if allowWidth}}
                            {{/if}}
                            {{/if}}

                            {{#if edit}}{{/if}}{{#if nonedit}}{{/if}}
                            ' -),o=this.get("allowBorders");return this._content=v.Node.create(t({CSS:l,elementid:this.get("host").get("elementid"),component:m,edit:e,nonedit:!e,allowStyling:this.get("allowStyling"),allowBorders:o,borderStyles:this.get("borderStyles"),allowBackgroundColour:this.get("allowBackgroundColour"),availableColours:this.get("availableColors"),allowWidth:this.get("allowWidth")})),e?this._content.one(".submit").on("click",this._updateTable,this):this._content.one(".submit").on("click",this._setTable,this),o&&this._content.one('[name="borders"]').on("change",this._updateAvailableSettings,this),this._content},_updateAvailableSettings:function(){var e=this._content,t=e.one('[name="borders"]'),o=e.one('[name="borderstyles"]'),a=e.one('[name="bordersize"]'),e=e.all('[name="borderColour"]'),n="removeAttribute";t&&("default"===t.get("value")&&(n="setAttribute"),o&&o[n]("disabled"),a&&a[n]("disabled"),e&&e[n]("disabled"))},_getSuitableTableCell:function(){var e,o=null,t=this.get("host"),a=v.bind(this._stopAtContentEditableFilter,this);return t.getSelectedNodes().some(function(e){var t;if(e.ancestor("td, th, caption",!0,a))return(e=(o=e).ancestor("caption",!0,a))&&(t=e.get("parentNode"))&&(o=t.one("td, th")),!0}),o&&(e=t.getSelectionFromNode(o),t.setSelection(e)),o},_changeNodeType:function(e,t){var o=v.Node.create("<"+t+">");return o.setAttrs(e.getAttrs()),e.get("childNodes").each(function(e){o.append(e.remove())}),e.replace(o),o},_updateTable:function(e){var t,o,a,n,r,l,i,s,d;e.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),t=e.currentTarget.ancestor(O.FORM).one(O.CAPTION),o=e.currentTarget.ancestor(O.FORM).one(O.CAPTIONPOSITION),a=e.currentTarget.ancestor(O.FORM).one(O.HEADERS),d=e.currentTarget.ancestor(O.FORM).one(O.BORDERS),n=e.currentTarget.ancestor(O.FORM).one(O.BORDERSIZE),l=e.currentTarget.ancestor(O.FORM).one(O.SELECTEDBORDERCOLOUR),r=e.currentTarget.ancestor(O.FORM).one(O.BORDERSTYLE),i=e.currentTarget.ancestor(O.FORM).one(O.SELECTEDBACKGROUNDCOLOUR),e=e.currentTarget.ancestor(O.FORM).one(O.WIDTH),s=this._lastTarget.ancestor("table"),this._setAppearance(s,{width:e,borders:d,borderColour:l,borderSize:n,borderStyle:r,backgroundColour:i}),(e=s.one("caption"))||(e=v.Node.create(""),s.insert(e,0)),e.setHTML(t.get("value")),e.setStyle("caption-side",o.get("value")),e.getAttribute("style")||e.removeAttribute("style"),"rows"!==a.get("value")&&"both"!==a.get("value")||s.all("tr").each(function(e){var e=e.all("th, td"),t=e.shift();("TD"===t.get("tagName")?this._changeNodeType(t,"th"):t).setAttribute("scope","row"),e.each(function(e){"TH"===e.get("tagName")&&this._changeNodeType(e,"td").removeAttribute("scope")},this)},this),"columns"!==a.get("value")&&"both"!==a.get("value")||((d=s.all("tr")).shift().all("td, th").each(function(e){("TD"===e.get("tagName")?this._changeNodeType(e,"th"):e).setAttribute("scope","col")},this),d.each(function(e){e=e.all("th, td");"both"===a.get("value")&&e.shift(),e.each(function(e){"TH"===e.get("tagName")&&this._changeNodeType(e,"td").removeAttribute("scope")},this)},this)),this.markUpdated()},_setTable:function(e){var t,c,u,b,g,h,o,a,n,m,r,l,i,_,s,d;if(e.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),t=e.currentTarget.ancestor(O.FORM).one(O.CAPTION),d=e.currentTarget.ancestor(O.FORM).one(O.CAPTIONPOSITION),c=e.currentTarget.ancestor(O.FORM).one(O.BORDERS),u=e.currentTarget.ancestor(O.FORM).one(O.BORDERSIZE),g=e.currentTarget.ancestor(O.FORM).one(O.SELECTEDBORDERCOLOUR),b=e.currentTarget.ancestor(O.FORM).one(O.BORDERSTYLE),m=e.currentTarget.ancestor(O.FORM).one(O.SELECTEDBACKGROUNDCOLOUR),h=e.currentTarget.ancestor(O.FORM).one(O.ROWS),o=e.currentTarget.ancestor(O.FORM).one(O.COLUMNS),a=e.currentTarget.ancestor(O.FORM).one(O.HEADERS),e=e.currentTarget.ancestor(O.FORM).one(O.WIDTH),this.get("host").setSelection(this._currentSelection),i="\n",n='
                            \n'+i,s="",n+=""+v.Escape.html(t.get("value"))+""+i,r=0,"columns"===a.get("value")||"both"===a.get("value")){for(r=1,n+="\n\n",l=0;l\n';n+="\n\n"}for(n+="\n";r\n",l=0;l\n":n+='\n';n+="\n"}n+="\n
                            \n
                            ",this.get("host").insertContentAtFocusPoint(n),d=v.one("#"+_),this._setAppearance(d,{width:e,borders:c,borderColour:g,borderSize:u,borderStyle:b,backgroundColour:m}),d.removeAttribute("id"),this.markUpdated()},_findColumnCells:function(){var a=this._getColumnIndex(this._lastTarget),e=this._lastTarget.ancestor("table").all("tr"),n=new v.NodeList,r=new v.NodeList,l=new v.NodeList;return e.each(function(e){var e=e.all("td, th"),t=e.item(a),o=e.item(a-1),e=e.item(a+1);n.push(t),o&&r.push(o),e&&l.push(e)}),{current:n,prev:r,next:l}},_hideInvalidEntries:function(e){var t=this._lastTarget.ancestor("table"),o=this._lastTarget.ancestor("tr"),t=t.all("tr"),a=t.indexOf(o),n=t.item(a-1),n=n?n.one("td"):null;o&&n?e.one('[data-change="moverowup"]').show():e.one('[data-change="moverowup"]').hide(),n=t.item(a+1),a=!!o&&o.one("td"),o&&n&&a?e.one('[data-change="moverowdown"]').show():e.one('[data-change="moverowdown"]').hide(),0<(t=this._findColumnCells()).prev.filter("td").size()?e.one('[data-change="movecolumnleft"]').show():e.one('[data-change="movecolumnleft"]').hide(),n=0
                          '),"after"),this._contextMenu=new v.M.editor_atto.Menu({items:this._menuOptions,buttonId:t,attachmentPoint:"#"+t+"_menu"}),(o=this._contextMenu.get("boundingBox")).delegate("click",this._handleTableChange,"a",this)),o=this._contextMenu.get("boundingBox"),this._lastTarget=e.tableCell.ancestor(".editor_atto_content td, .editor_atto_content th",!0),this._hideInvalidEntries(o),v.Array.each(this.get("host").openMenus,function(e){e.set("focusAfterHide",null)}),this.get("host")._setTabFocus(a),this._contextMenu.show(),this._contextMenu.align(this.buttons.table,[v.WidgetPositionAlign.TL,v.WidgetPositionAlign.BL]),this._contextMenu.set("focusAfterHide",a),o.one("a")&&o.one("a").focus(),this.get("host").openMenus=[this._contextMenu]},_handleTableChange:function(e){switch(e.preventDefault(),this._contextMenu.set("focusAfterHide",this.get("host").editor),this._contextMenu.hide(e),e.target.getData("change")){case"addcolumnafter":this._addColumnAfter();break;case"addrowafter":this._addRowAfter();break;case"deleterow":this._deleteRow();break;case"deletecolumn":this._deleteColumn();break;case"edittable":this._editTable();break;case"moverowdown":this._moveRowDown();break;case"moverowup":this._moveRowUp();break;case"movecolumnleft":this._moveColumnLeft();break;case"movecolumnright":this._moveColumnRight()}},_getRowIndex:function(e){var t=e.ancestor("table"),e=e.ancestor("tr");if(t&&e)return t.all("tr").indexOf(e)},_getColumnIndex:function(e){var t=e.ancestor("tr");if(t)return t.all("td, th").indexOf(e)},_deleteRow:function(){var e=this._lastTarget.ancestor("tr");e&&e.one("td")&&e.remove(!0),this.markUpdated()},_moveRowUp:function(){var e=this._lastTarget.ancestor("tr"),t=e.previous("tr");e&&t&&(e.swap(t),this.markUpdated())},_moveColumnLeft:function(){var e,t,o,a=this._findColumnCells();if(0 "),1)},_removeCaption:function(){var e=this._lastTarget.ancestor("table").one("caption");e&&e.remove(!0)},_moveColumnRight:function(){var e,t,o,a=this._findColumnCells();if(0"),e.replace(t),e=t),e.setHTML(" ")}),t.ancestor("thead")?(t=a,o.insert(e,t)):t.insert(e,"after"),this.markUpdated())},_addColumnAfter:function(){var e=this._findColumnCells(),o=!0,t=e.next;e.next.size()<=0&&(o=!1,t=e.current),v.each(t,function(e){var t=e.cloneNode();t.setHTML(" "),o?e.get("parentNode").insert(t,e):(e.get("parentNode").insert(t,e),e.swap(t))},this),this.markUpdated()}},{ATTRS:{allowBorders:{value:!0},borderStyles:{value:["none","solid","dashed","dotted"]},allowBackgroundColour:{value:!0},allowWidth:{value:!0},allowStyling:{readOnly:!0,getter:function(){return this.get("allowBorders")||this.get("allowBackgroundColour")||this.get("allowWidth")}},availableColors:{value:["#FFFFFF","#EF4540","#FFCF35","#98CA3E","#7D9FD3","#333333"],readOnly:!0}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-editor_atto-menu","event","event-valuechange"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button.js b/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button.js deleted file mode 100644 index 42217618ec9..00000000000 --- a/lib/editor/atto/plugins/table/yui/build/moodle-atto_table-button/moodle-atto_table-button.js +++ /dev/null @@ -1,1557 +0,0 @@ -YUI.add('moodle-atto_table-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_table - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_table-button - */ - -/** - * Atto text editor table plugin. - * - * @namespace M.atto_table - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_table', - DEFAULT = { - BORDERSTYLE: 'none', - BORDERWIDTH: '1' - }, - DIALOGUE = { - WIDTH: '480px' - }, - TEMPLATE = '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{#if nonedit}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '{{#if allowStyling}}' + - '
                          ' + - '{{get_string "appearance" component}}' + - '{{#if allowBorders}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{#each availableColours}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '{{#if allowBackgroundColour}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - - '{{#each availableColours}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '{{#if allowWidth}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '
                          ' + - '{{#if edit}}' + - '' + - '{{/if}}' + - '{{#if nonedit}}' + - '' + - '{{/if}}' + - '
                          ' + - '
                          ', - CSS = { - CAPTION: 'caption', - CAPTIONPOSITION: 'captionposition', - HEADERS: 'headers', - ROWS: 'rows', - COLUMNS: 'columns', - SUBMIT: 'submit', - FORM: 'atto_form', - BORDERS: 'borders', - BORDERSIZE: 'bordersize', - BORDERSIZEUNIT: 'px', - BORDERCOLOUR: 'bordercolour', - BORDERSTYLE: 'borderstyle', - BACKGROUNDCOLOUR: 'backgroundcolour', - WIDTH: 'customwidth', - WIDTHUNIT: '%', - AVAILABLECOLORS: 'availablecolors', - COLOURROW: 'colourrow' - }, - SELECTORS = { - CAPTION: '.' + CSS.CAPTION, - CAPTIONPOSITION: '.' + CSS.CAPTIONPOSITION, - HEADERS: '.' + CSS.HEADERS, - ROWS: '.' + CSS.ROWS, - COLUMNS: '.' + CSS.COLUMNS, - SUBMIT: '.' + CSS.SUBMIT, - BORDERS: '.' + CSS.BORDERS, - BORDERSIZE: '.' + CSS.BORDERSIZE, - BORDERCOLOURS: '.' + CSS.BORDERCOLOUR + ' input[name="borderColour"]', - SELECTEDBORDERCOLOUR: '.' + CSS.BORDERCOLOUR + ' input[name="borderColour"]:checked', - BORDERSTYLE: '.' + CSS.BORDERSTYLE, - BACKGROUNDCOLOURS: '.' + CSS.BACKGROUNDCOLOUR + ' input[name="backgroundColour"]', - SELECTEDBACKGROUNDCOLOUR: '.' + CSS.BACKGROUNDCOLOUR + ' input[name="backgroundColour"]:checked', - FORM: '.atto_form', - WIDTH: '.' + CSS.WIDTH, - AVAILABLECOLORS: '.' + CSS.AVAILABLECOLORS - }; - -Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * The contextual menu that we can open. - * - * @property _contextMenu - * @type M.editor_atto.Menu - * @private - */ - _contextMenu: null, - - /** - * The last modified target. - * - * @property _lastTarget - * @type Node - * @private - */ - _lastTarget: null, - - /** - * The list of menu items. - * - * @property _menuOptions - * @type Object - * @private - */ - _menuOptions: null, - - initializer: function() { - var button = this.addButton({ - icon: 'e/table', - callback: this._displayTableEditor, - tags: 'table' - }); - - // Listen for toggled highlighting. - require(['editor_atto/events'], function(attoEvents) { - var domButton = button.getDOMNode(); - domButton.addEventListener(attoEvents.eventTypes.attoButtonHighlightToggled, function(e) { - this._setAriaAttributes(e.detail.buttonName, e.detail.highlight); - }.bind(this)); - }.bind(this)); - - // Disable mozilla table controls. - if (Y.UA.gecko) { - document.execCommand("enableInlineTableEditing", false, false); - document.execCommand("enableObjectResizing", false, false); - } - }, - - /** - * Sets the appropriate ARIA attributes for the table button when it switches roles between a button and a menu button. - * - * @param {String} buttonName The button name. - * @param {Boolean} highlight True when the button was highlighted. False, otherwise. - * @private - */ - _setAriaAttributes: function(buttonName, highlight) { - var menuButton = this.buttons[buttonName]; - if (menuButton) { - if (highlight) { - // This button becomes a menu button. Add appropriate ARIA attributes. - var id = menuButton.getAttribute('id'); - menuButton.setAttribute('aria-haspopup', true); - menuButton.setAttribute('aria-controls', id + '_menu'); - menuButton.setAttribute('aria-expanded', true); - } else { - menuButton.removeAttribute('aria-haspopup'); - menuButton.removeAttribute('aria-controls'); - menuButton.removeAttribute('aria-expanded'); - } - } - }, - - /** - * Display the table tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current cursor position. - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection !== false && (!this._currentSelection.collapsed)) { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createtable', COMPONENT), - focusAfterHide: true, - focusOnShowSelector: SELECTORS.CAPTION, - width: DIALOGUE.WIDTH - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent(false)) - .show(); - - this._updateAvailableSettings(); - } - }, - - /** - * Display the appropriate table editor. - * - * If the current selection includes a table, then we show the - * contextual menu, otherwise show the table creation dialogue. - * - * @method _displayTableEditor - * @param {EventFacade} e - * @private - */ - _displayTableEditor: function(e) { - var cell = this._getSuitableTableCell(); - var menuButton = e.currentTarget.ancestor('button', true); - if (cell) { - var id = menuButton.getAttribute('id'); - - // Indicate that the menu is expanded. - menuButton.setAttribute('aria-expanded', true); - - // Add the cell to the EventFacade to save duplication in when showing the menu. - e.tableCell = cell; - return this._showTableMenu(e, id); - } else { - // Dialog mode. Remove aria-expanded attribute. - menuButton.removeAttribute('aria-expanded'); - } - return this._displayDialogue(e); - }, - - /** - * Returns whether or not the parameter node exists within the editor. - * - * @method _stopAtContentEditableFilter - * @param {Node} node - * @private - * @return {boolean} whether or not the parameter node exists within the editor. - */ - _stopAtContentEditableFilter: function(node) { - return this.editor.contains(node); - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function(edit) { - var template = Y.Handlebars.compile(TEMPLATE); - var allowBorders = this.get('allowBorders'); - - this._content = Y.Node.create(template({ - CSS: CSS, - elementid: this.get('host').get('elementid'), - component: COMPONENT, - edit: edit, - nonedit: !edit, - allowStyling: this.get('allowStyling'), - allowBorders: allowBorders, - borderStyles: this.get('borderStyles'), - allowBackgroundColour: this.get('allowBackgroundColour'), - availableColours: this.get('availableColors'), - allowWidth: this.get('allowWidth') - })); - - // Handle table setting. - if (edit) { - this._content.one('.submit').on('click', this._updateTable, this); - } else { - this._content.one('.submit').on('click', this._setTable, this); - } - - if (allowBorders) { - this._content.one('[name="borders"]').on('change', this._updateAvailableSettings, this); - } - - return this._content; - }, - - /** - * Disables options within the dialogue if they shouldn't be available. - * E.g. - * If borders are set to "Theme default" then the border size, style and - * colour options are disabled. - * - * @method _updateAvailableSettings - * @private - */ - _updateAvailableSettings: function() { - var tableForm = this._content, - enableBorders = tableForm.one('[name="borders"]'), - borderStyle = tableForm.one('[name="borderstyles"]'), - borderSize = tableForm.one('[name="bordersize"]'), - borderColour = tableForm.all('[name="borderColour"]'), - disabledValue = 'removeAttribute'; - - if (!enableBorders) { - return; - } - - if (enableBorders.get('value') === 'default') { - disabledValue = 'setAttribute'; - } - - if (borderStyle) { - borderStyle[disabledValue]('disabled'); - } - - if (borderSize) { - borderSize[disabledValue]('disabled'); - } - - if (borderColour) { - borderColour[disabledValue]('disabled'); - } - - }, - - /** - * Given the current selection, return a table cell suitable for table editing - * purposes, i.e. the first table cell selected, or the first cell in the table - * that the selection exists in, or null if not within a table. - * - * @method _getSuitableTableCell - * @private - * @return {Node} suitable target cell, or null if not within a table - */ - _getSuitableTableCell: function() { - var targetcell = null, - host = this.get('host'); - var stopAtContentEditableFilter = Y.bind(this._stopAtContentEditableFilter, this); - - host.getSelectedNodes().some(function(node) { - if (node.ancestor('td, th, caption', true, stopAtContentEditableFilter)) { - targetcell = node; - - var caption = node.ancestor('caption', true, stopAtContentEditableFilter); - if (caption) { - var table = caption.get('parentNode'); - if (table) { - targetcell = table.one('td, th'); - } - } - - // Once we've found a cell to target, we shouldn't need to keep looking. - return true; - } - }); - - if (targetcell) { - var selection = host.getSelectionFromNode(targetcell); - host.setSelection(selection); - } - - return targetcell; - }, - - /** - * Change a node from one type to another, copying all attributes and children. - * - * @method _changeNodeType - * @param {Y.Node} node - * @param {String} new node type - * @private - * @chainable - */ - _changeNodeType: function(node, newType) { - var newNode = Y.Node.create('<' + newType + '>'); - newNode.setAttrs(node.getAttrs()); - node.get('childNodes').each(function(child) { - newNode.append(child.remove()); - }); - node.replace(newNode); - return newNode; - }, - - /** - * Handle updating an existing table. - * - * @method _updateTable - * @param {EventFacade} e - * @private - */ - _updateTable: function(e) { - var caption, - captionposition, - headers, - borders, - bordersize, - borderstyle, - bordercolour, - backgroundcolour, - table, - width, - captionnode; - - e.preventDefault(); - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Add/update the caption. - caption = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTION); - captionposition = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTIONPOSITION); - headers = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.HEADERS); - borders = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERS); - bordersize = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSIZE); - bordercolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBORDERCOLOUR); - borderstyle = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSTYLE); - backgroundcolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBACKGROUNDCOLOUR); - width = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.WIDTH); - - table = this._lastTarget.ancestor('table'); - this._setAppearance(table, { - width: width, - borders: borders, - borderColour: bordercolour, - borderSize: bordersize, - borderStyle: borderstyle, - backgroundColour: backgroundcolour - }); - - captionnode = table.one('caption'); - if (!captionnode) { - captionnode = Y.Node.create(''); - table.insert(captionnode, 0); - } - captionnode.setHTML(caption.get('value')); - captionnode.setStyle('caption-side', captionposition.get('value')); - if (!captionnode.getAttribute('style')) { - captionnode.removeAttribute('style'); - } - - // Add the row headers. - if (headers.get('value') === 'rows' || headers.get('value') === 'both') { - table.all('tr').each(function(row) { - var cells = row.all('th, td'), - firstCell = cells.shift(), - newCell; - - if (firstCell.get('tagName') === 'TD') { - // Cell is a td but should be a th - change it. - newCell = this._changeNodeType(firstCell, 'th'); - newCell.setAttribute('scope', 'row'); - } else { - firstCell.setAttribute('scope', 'row'); - } - - // Now make sure all other cells in the row are td. - cells.each(function(cell) { - if (cell.get('tagName') === 'TH') { - newCell = this._changeNodeType(cell, 'td'); - newCell.removeAttribute('scope'); - } - }, this); - - }, this); - } - // Add the col headers. These may overrule the row headers in the first cell. - if (headers.get('value') === 'columns' || headers.get('value') === 'both') { - var rows = table.all('tr'), - firstRow = rows.shift(), - newCell; - - firstRow.all('td, th').each(function(cell) { - if (cell.get('tagName') === 'TD') { - // Cell is a td but should be a th - change it. - newCell = this._changeNodeType(cell, 'th'); - newCell.setAttribute('scope', 'col'); - } else { - cell.setAttribute('scope', 'col'); - } - }, this); - // Change all the cells in the rest of the table to tds (unless they are row headers). - rows.each(function(row) { - var cells = row.all('th, td'); - - if (headers.get('value') === 'both') { - // Ignore the first cell because it's a row header. - cells.shift(); - } - cells.each(function(cell) { - if (cell.get('tagName') === 'TH') { - newCell = this._changeNodeType(cell, 'td'); - newCell.removeAttribute('scope'); - } - }, this); - - }, this); - } - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Handle creation of a new table. - * - * @method _setTable - * @param {EventFacade} e - * @private - */ - _setTable: function(e) { - var caption, - captionposition, - borders, - bordersize, - borderstyle, - bordercolour, - rows, - cols, - headers, - tablehtml, - backgroundcolour, - width, - i, j; - - e.preventDefault(); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - caption = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTION); - captionposition = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTIONPOSITION); - borders = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERS); - bordersize = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSIZE); - bordercolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBORDERCOLOUR); - borderstyle = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSTYLE); - backgroundcolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBACKGROUNDCOLOUR); - rows = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.ROWS); - cols = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.COLUMNS); - headers = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.HEADERS); - width = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.WIDTH); - - // Set the selection. - this.get('host').setSelection(this._currentSelection); - - // Note there are some spaces inserted in the cells and before and after, so that users have somewhere to click. - var nl = "\n"; - var tableId = Y.guid(); - tablehtml = '
                          ' + nl + '' + nl; - - var captionstyle = ''; - if (captionposition.get('value')) { - captionstyle = ' style="caption-side: ' + captionposition.get('value') + '"'; - } - tablehtml += '' + Y.Escape.html(caption.get('value')) + '' + nl; - i = 0; - if (headers.get('value') === 'columns' || headers.get('value') === 'both') { - i = 1; - tablehtml += '' + nl + '' + nl; - for (j = 0; j < parseInt(cols.get('value'), 10); j++) { - tablehtml += '' + nl; - } - tablehtml += '' + nl + '' + nl; - } - tablehtml += '' + nl; - for (; i < parseInt(rows.get('value'), 10); i++) { - tablehtml += '' + nl; - for (j = 0; j < parseInt(cols.get('value'), 10); j++) { - if (j === 0 && (headers.get('value') === 'rows' || headers.get('value') === 'both')) { - tablehtml += '' + nl; - } else { - tablehtml += '' + nl; - } - } - tablehtml += '' + nl; - } - tablehtml += '' + nl; - tablehtml += '
                          ' + nl + '
                          '; - - this.get('host').insertContentAtFocusPoint(tablehtml); - - var tableNode = Y.one('#' + tableId); - this._setAppearance(tableNode, { - width: width, - borders: borders, - borderColour: bordercolour, - borderSize: bordersize, - borderStyle: borderstyle, - backgroundColour: backgroundcolour - }); - tableNode.removeAttribute('id'); - - // Mark the content as updated. - this.markUpdated(); - }, - - /** - * Search for all the cells in the current, next and previous columns. - * - * @method _findColumnCells - * @private - * @return {Object} containing current, prev and next {Y.NodeList}s - */ - _findColumnCells: function() { - var columnindex = this._getColumnIndex(this._lastTarget), - rows = this._lastTarget.ancestor('table').all('tr'), - currentcells = new Y.NodeList(), - prevcells = new Y.NodeList(), - nextcells = new Y.NodeList(); - - rows.each(function(row) { - var cells = row.all('td, th'), - cell = cells.item(columnindex), - cellprev = cells.item(columnindex - 1), - cellnext = cells.item(columnindex + 1); - currentcells.push(cell); - if (cellprev) { - prevcells.push(cellprev); - } - if (cellnext) { - nextcells.push(cellnext); - } - }); - - return { - current: currentcells, - prev: prevcells, - next: nextcells - }; - }, - - /** - * Hide the entries in the context menu that don't make sense with the - * current selection. - * - * @method _hideInvalidEntries - * @param {Y.Node} node - The node containing the menu. - * @private - */ - _hideInvalidEntries: function(node) { - // Moving rows. - var table = this._lastTarget.ancestor('table'), - row = this._lastTarget.ancestor('tr'), - rows = table.all('tr'), - rowindex = rows.indexOf(row), - prevrow = rows.item(rowindex - 1), - prevrowhascells = prevrow ? prevrow.one('td') : null; - - if (!row || !prevrowhascells) { - node.one('[data-change="moverowup"]').hide(); - } else { - node.one('[data-change="moverowup"]').show(); - } - - var nextrow = rows.item(rowindex + 1), - rowhascell = row ? row.one('td') : false; - - if (!row || !nextrow || !rowhascell) { - node.one('[data-change="moverowdown"]').hide(); - } else { - node.one('[data-change="moverowdown"]').show(); - } - - // Moving columns. - var cells = this._findColumnCells(); - if (cells.prev.filter('td').size() > 0) { - node.one('[data-change="movecolumnleft"]').show(); - } else { - node.one('[data-change="movecolumnleft"]').hide(); - } - - var colhascell = cells.current.filter('td').size() > 0; - if ((cells.next.size() > 0) && colhascell) { - node.one('[data-change="movecolumnright"]').show(); - } else { - node.one('[data-change="movecolumnright"]').hide(); - } - - // Delete col - if (cells.current.filter('td').size() > 0) { - node.one('[data-change="deletecolumn"]').show(); - } else { - node.one('[data-change="deletecolumn"]').hide(); - } - // Delete row - if (!row || !row.one('td')) { - node.one('[data-change="deleterow"]').hide(); - } else { - node.one('[data-change="deleterow"]').show(); - } - }, - - /** - * Display the table menu. - * - * @method _showTableMenu - * @param {EventFacade} e - * @param {String} buttonId The ID of the menu button associated with this menu. - * @private - */ - _showTableMenu: function(e, buttonId) { - e.preventDefault(); - - var boundingBox; - var creatorButton = this.buttons[this.name]; - - if (!this._contextMenu) { - this._menuOptions = [ - { - text: M.util.get_string("addcolumnafter", COMPONENT), - data: { - change: "addcolumnafter" - } - }, { - text: M.util.get_string("addrowafter", COMPONENT), - data: { - change: "addrowafter" - } - }, { - text: M.util.get_string("moverowup", COMPONENT), - data: { - change: "moverowup" - } - }, { - text: M.util.get_string("moverowdown", COMPONENT), - data: { - change: "moverowdown" - } - }, { - text: M.util.get_string("movecolumnleft", COMPONENT), - data: { - change: "movecolumnleft" - } - }, { - text: M.util.get_string("movecolumnright", COMPONENT), - data: { - change: "movecolumnright" - } - }, { - text: M.util.get_string("deleterow", COMPONENT), - data: { - change: "deleterow" - } - }, { - text: M.util.get_string("deletecolumn", COMPONENT), - data: { - change: "deletecolumn" - } - }, { - text: M.util.get_string("edittable", COMPONENT), - data: { - change: "edittable" - } - } - ]; - - creatorButton.insert(Y.Node.create(''), 'after'); - this._contextMenu = new Y.M.editor_atto.Menu({ - items: this._menuOptions, - buttonId: buttonId, - attachmentPoint: '#' + buttonId + '_menu' - }); - - // Add event handlers for table control menus. - boundingBox = this._contextMenu.get('boundingBox'); - boundingBox.delegate('click', this._handleTableChange, 'a', this); - } - - boundingBox = this._contextMenu.get('boundingBox'); - - // We store the cell of the last click (the control node is transient). - this._lastTarget = e.tableCell.ancestor('.editor_atto_content td, .editor_atto_content th', true); - - this._hideInvalidEntries(boundingBox); - - // Clear the focusAfterHide for any other menus which may be open. - Y.Array.each(this.get('host').openMenus, function(menu) { - menu.set('focusAfterHide', null); - }); - - // Ensure that we focus on the button in the toolbar when we tab back to the menu. - this.get('host')._setTabFocus(creatorButton); - - // Show the context menu, and align to the current position. - this._contextMenu.show(); - this._contextMenu.align(this.buttons.table, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]); - this._contextMenu.set('focusAfterHide', creatorButton); - - // If there are any anchors in the bounding box, focus on the first. - if (boundingBox.one('a')) { - boundingBox.one('a').focus(); - } - - // Add this menu to the list of open menus. - this.get('host').openMenus = [this._contextMenu]; - }, - - /** - * Handle a selection from the table control menu. - * - * @method _handleTableChange - * @param {EventFacade} e - * @private - */ - _handleTableChange: function(e) { - e.preventDefault(); - - this._contextMenu.set('focusAfterHide', this.get('host').editor); - // Hide the context menu. - this._contextMenu.hide(e); - - // Make our changes. - switch (e.target.getData('change')) { - case 'addcolumnafter': - this._addColumnAfter(); - break; - case 'addrowafter': - this._addRowAfter(); - break; - case 'deleterow': - this._deleteRow(); - break; - case 'deletecolumn': - this._deleteColumn(); - break; - case 'edittable': - this._editTable(); - break; - case 'moverowdown': - this._moveRowDown(); - break; - case 'moverowup': - this._moveRowUp(); - break; - case 'movecolumnleft': - this._moveColumnLeft(); - break; - case 'movecolumnright': - this._moveColumnRight(); - break; - } - }, - - /** - * Determine the index of a row in a table column. - * - * @method _getRowIndex - * @param {Node} cell - * @private - */ - _getRowIndex: function(cell) { - var tablenode = cell.ancestor('table'), - rownode = cell.ancestor('tr'); - - if (!tablenode || !rownode) { - return; - } - - var rows = tablenode.all('tr'); - - return rows.indexOf(rownode); - }, - - /** - * Determine the index of a column in a table row. - * - * @method _getColumnIndex - * @param {Node} cellnode - * @private - */ - _getColumnIndex: function(cellnode) { - var rownode = cellnode.ancestor('tr'); - - if (!rownode) { - return; - } - - var cells = rownode.all('td, th'); - - return cells.indexOf(cellnode); - }, - - /** - * Delete the current row. - * - * @method _deleteRow - * @private - */ - _deleteRow: function() { - var row = this._lastTarget.ancestor('tr'); - - if (row && row.one('td')) { - // Only delete rows with at least one non-header cell. - row.remove(true); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Move row up - * - * @method _moveRowUp - * @private - */ - _moveRowUp: function() { - var row = this._lastTarget.ancestor('tr'), - prevrow = row.previous('tr'); - if (!row || !prevrow) { - return; - } - - row.swap(prevrow); - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Move column left - * - * @method _moveColumnLeft - * @private - */ - _moveColumnLeft: function() { - var cells = this._findColumnCells(); - - if (cells.current.size() > 0 && cells.prev.size() > 0 && cells.current.size() === cells.prev.size()) { - var i = 0; - for (i = 0; i < cells.current.size(); i++) { - var cell = cells.current.item(i), - prevcell = cells.prev.item(i); - - cell.swap(prevcell); - } - } - // Cleanup. - this.markUpdated(); - }, - - /** - * Add a caption to the table if it doesn't have one. - * - * @method _addCaption - * @private - */ - _addCaption: function() { - var table = this._lastTarget.ancestor('table'), - caption = table.one('caption'); - - if (!caption) { - table.insert(Y.Node.create(' '), 1); - } - }, - - /** - * Remove a caption from the table if has one. - * - * @method _removeCaption - * @private - */ - _removeCaption: function() { - var table = this._lastTarget.ancestor('table'), - caption = table.one('caption'); - - if (caption) { - caption.remove(true); - } - }, - - /** - * Move column right. - * - * @method _moveColumnRight - * @private - */ - _moveColumnRight: function() { - var cells = this._findColumnCells(); - - // Check we have some tds in this column, and one exists to the right. - if ((cells.next.size() > 0) && - (cells.current.size() === cells.next.size()) && - (cells.current.filter('td').size() > 0)) { - var i = 0; - for (i = 0; i < cells.current.size(); i++) { - var cell = cells.current.item(i), - nextcell = cells.next.item(i); - - cell.swap(nextcell); - } - } - // Cleanup. - this.markUpdated(); - }, - - /** - * Move row down. - * - * @method _moveRowDown - * @private - */ - _moveRowDown: function() { - var row = this._lastTarget.ancestor('tr'), - nextrow = row.next('tr'); - if (!row || !nextrow || !row.one('td')) { - return; - } - - row.swap(nextrow); - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Obtain values for the table borders - * - * @method _getBorderConfiguration - * @param {Node} node - * @private - * @return {Array} or {Boolean} Returns the settings, if presents, or else returns false - */ - _getBorderConfiguration: function(node) { - // We need to make a clone of the node in order to avoid grabbing any - // of the computed styles from the DOM. We only want inline styles set by us. - var shadowNode = node.cloneNode(true); - var borderStyle = shadowNode.getStyle('borderStyle'), - borderColor = shadowNode.getStyle('borderColor'), - borderWidth = shadowNode.getStyle('borderWidth'); - - if (borderStyle || borderColor || borderWidth) { - var hexColour = Y.Color.toHex(borderColor); - var width = parseInt(borderWidth, 10); - return { - borderStyle: borderStyle, - borderColor: hexColour === "#" ? null : hexColour, - borderWidth: isNaN(width) ? null : width - }; - } - - return false; - }, - - /** - * Set the appropriate styles on the given table node according to - * the provided configuration. - * - * @method _setAppearance - * @param {Node} The table node to be modified. - * @param {Object} Configuration object (associative array) containing the form nodes for - * border styling. - * @private - */ - _setAppearance: function(tableNode, configuration) { - var borderhex, - borderSizeValue, - borderStyleValue, - backgroundcolourvalue; - - if (configuration.borderColour) { - borderhex = configuration.borderColour.get('value'); - } - - if (configuration.borderSize) { - borderSizeValue = configuration.borderSize.get('value'); - } - - if (configuration.borderStyle) { - borderStyleValue = configuration.borderStyle.get('value'); - } - - if (configuration.backgroundColour) { - backgroundcolourvalue = configuration.backgroundColour.get('value'); - } - - // Clear the inline border styling - tableNode.removeAttribute('style'); - tableNode.all('td, th').each(function(cell) { - cell.removeAttribute('style'); - }, this); - - if (configuration.borders) { - if (configuration.borders.get('value') === 'outer') { - tableNode.setStyle('borderWidth', borderSizeValue + CSS.BORDERSIZEUNIT); - tableNode.setStyle('borderStyle', borderStyleValue); - - if (borderhex !== 'none') { - tableNode.setStyle('borderColor', borderhex); - } - } else if (configuration.borders.get('value') === 'all') { - tableNode.all('td, th').each(function(cell) { - cell.setStyle('borderWidth', borderSizeValue + CSS.BORDERSIZEUNIT); - cell.setStyle('borderStyle', borderStyleValue); - - if (borderhex !== 'none') { - cell.setStyle('borderColor', borderhex); - } - }, this); - } - } - - if (backgroundcolourvalue !== 'none') { - tableNode.setStyle('backgroundColor', backgroundcolourvalue); - } - - if (configuration.width && configuration.width.get('value')) { - tableNode.setStyle('width', configuration.width.get('value') + CSS.WIDTHUNIT); - } - }, - - /** - * Edit table (show the dialogue). - * - * @method _editTable - * @private - */ - _editTable: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('edittable', COMPONENT), - focusAfterHide: false, - focusOnShowSelector: SELECTORS.CAPTION, - width: DIALOGUE.WIDTH - }); - - // Set the dialogue content, and then show the dialogue. - var node = this._getDialogueContent(true), - captioninput = node.one(SELECTORS.CAPTION), - captionpositioninput = node.one(SELECTORS.CAPTIONPOSITION), - headersinput = node.one(SELECTORS.HEADERS), - borderinput = node.one(SELECTORS.BORDERS), - borderstyle = node.one(SELECTORS.BORDERSTYLE), - bordercolours = node.all(SELECTORS.BORDERCOLOURS), - bordersize = node.one(SELECTORS.BORDERSIZE), - backgroundcolours = node.all(SELECTORS.BACKGROUNDCOLOURS), - width = node.one(SELECTORS.WIDTH), - table = this._lastTarget.ancestor('table'), - captionnode = table.one('caption'), - hexColour, - matchedInput; - - if (captionnode) { - captioninput.set('value', captionnode.getHTML()); - } else { - captioninput.set('value', ''); - } - - if (width && table.getStyle('width').indexOf('px') === -1) { - width.set('value', parseInt(table.getStyle('width'), 10)); - } - - if (captionpositioninput && captionnode && captionnode.getAttribute('style')) { - captionpositioninput.set('value', captionnode.getStyle('caption-side')); - } else { - // Default to none. - captionpositioninput.set('value', ''); - } - - if (table.getStyle('backgroundColor') && this.get('allowBackgroundColour')) { - hexColour = Y.Color.toHex(table.getStyle('backgroundColor')); - matchedInput = backgroundcolours.filter('[value="' + hexColour + '"]'); - - if (matchedInput) { - matchedInput.set("checked", true); - } - } - - if (this.get('allowBorders')) { - var borderValue = 'default', - borderConfiguration = this._getBorderConfiguration(table); - - if (borderConfiguration) { - borderValue = 'outer'; - } else { - borderConfiguration = this._getBorderConfiguration(table.one('td')); - if (borderConfiguration) { - borderValue = 'all'; - } - } - - if (borderConfiguration) { - var borderStyle = borderConfiguration.borderStyle || DEFAULT.BORDERSTYLE; - var borderSize = borderConfiguration.borderWidth || DEFAULT.BORDERWIDTH; - borderstyle.set('value', borderStyle); - bordersize.set('value', borderSize); - borderinput.set('value', borderValue); - - hexColour = borderConfiguration.borderColor; - matchedInput = bordercolours.filter('[value="' + hexColour + '"]'); - - if (matchedInput) { - matchedInput.set("checked", true); - } - } - } - - var headersvalue = 'columns'; - if (table.one('th[scope="row"]')) { - headersvalue = 'rows'; - if (table.one('th[scope="col"]')) { - headersvalue = 'both'; - } - } - headersinput.set('value', headersvalue); - dialogue.set('bodyContent', node).show(); - this._updateAvailableSettings(); - }, - - - /** - * Delete the current column. - * - * @method _deleteColumn - * @private - */ - _deleteColumn: function() { - var columnindex = this._getColumnIndex(this._lastTarget), - table = this._lastTarget.ancestor('table'), - rows = table.all('tr'), - columncells = new Y.NodeList(), - hastd = false; - - rows.each(function(row) { - var cells = row.all('td, th'); - var cell = cells.item(columnindex); - if (cell.get('tagName') === 'TD') { - hastd = true; - } - columncells.push(cell); - }); - - // Do not delete all the headers. - if (hastd) { - columncells.remove(true); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Add a row after the current row. - * - * @method _addRowAfter - * @private - */ - _addRowAfter: function() { - var target = this._lastTarget.ancestor('tr'), - tablebody = this._lastTarget.ancestor('table').one('tbody'); - if (!tablebody) { - // Not all tables have tbody. - tablebody = this._lastTarget.ancestor('table'); - } - - var firstrow = tablebody.one('tr'); - if (!firstrow) { - firstrow = this._lastTarget.ancestor('table').one('tr'); - } - if (!firstrow) { - // Table has no rows. Boo. - return; - } - var newrow = firstrow.cloneNode(true); - newrow.all('th, td').each(function(tablecell) { - if (tablecell.get('tagName') === 'TH') { - if (tablecell.getAttribute('scope') !== 'row') { - var newcell = Y.Node.create(''); - tablecell.replace(newcell); - tablecell = newcell; - } - } - tablecell.setHTML(' '); - }); - - if (target.ancestor('thead')) { - target = firstrow; - tablebody.insert(newrow, target); - } else { - target.insert(newrow, 'after'); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Add a column after the current column. - * - * @method _addColumnAfter - * @private - */ - _addColumnAfter: function() { - var cells = this._findColumnCells(), - before = true, - clonecells = cells.next; - if (cells.next.size() <= 0) { - before = false; - clonecells = cells.current; - } - - Y.each(clonecells, function(cell) { - var newcell = cell.cloneNode(); - // Clear the content of the cell. - newcell.setHTML(' '); - - if (before) { - cell.get('parentNode').insert(newcell, cell); - } else { - cell.get('parentNode').insert(newcell, cell); - cell.swap(newcell); - } - }, this); - - // Clean the HTML. - this.markUpdated(); - } - -}, { - ATTRS: { - /** - * Whether or not to allow borders - * - * @attribute allowBorder - * @type Boolean - */ - allowBorders: { - value: true - }, - - /** - * What border styles to allow - * - * @attribute borderStyles - * @type Array - */ - borderStyles: { - value: [ - 'none', - 'solid', - 'dashed', - 'dotted' - ] - }, - - /** - * Whether or not to allow colourizing the background - * - * @attribute allowBackgroundColour - * @type Boolean - */ - allowBackgroundColour: { - value: true - }, - - /** - * Whether or not to allow setting the table width - * - * @attribute allowWidth - * @type Boolean - */ - allowWidth: { - value: true - }, - - /** - * Whether we allow styling - * @attribute allowStyling - * @type Boolean - */ - allowStyling: { - readOnly: true, - getter: function() { - return this.get('allowBorders') || this.get('allowBackgroundColour') || this.get('allowWidth'); - } - }, - - /** - * Available colors - * @attribute availableColors - * @type Array - */ - availableColors: { - value: [ - '#FFFFFF', - '#EF4540', - '#FFCF35', - '#98CA3E', - '#7D9FD3', - '#333333' - ], - readOnly: true - } - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-editor_atto-menu", "event", "event-valuechange"]}); diff --git a/lib/editor/atto/plugins/table/yui/src/button/build.json b/lib/editor/atto/plugins/table/yui/src/button/build.json deleted file mode 100644 index 4eef4d2c514..00000000000 --- a/lib/editor/atto/plugins/table/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_table-button", - "builds": { - "moodle-atto_table-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/table/yui/src/button/js/button.js b/lib/editor/atto/plugins/table/yui/src/button/js/button.js deleted file mode 100644 index d4e1d6c1417..00000000000 --- a/lib/editor/atto/plugins/table/yui/src/button/js/button.js +++ /dev/null @@ -1,1552 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @package atto_table - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_table-button - */ - -/** - * Atto text editor table plugin. - * - * @namespace M.atto_table - * @class Button - * @extends M.editor_atto.EditorPlugin - */ - -var COMPONENT = 'atto_table', - DEFAULT = { - BORDERSTYLE: 'none', - BORDERWIDTH: '1' - }, - DIALOGUE = { - WIDTH: '480px' - }, - TEMPLATE = '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{#if nonedit}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '{{#if allowStyling}}' + - '
                          ' + - '{{get_string "appearance" component}}' + - '{{#if allowBorders}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{#each availableColours}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '{{#if allowBackgroundColour}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - - '{{#each availableColours}}' + - '
                          ' + - '' + - '' + - '
                          ' + - '{{/each}}' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '{{#if allowWidth}}' + - '
                          ' + - '
                          ' + - '' + - '
                          ' + - '
                          ' + - '' + - '' + - '
                          ' + - '
                          ' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '{{/if}}' + - '
                          ' + - '
                          ' + - '{{#if edit}}' + - '' + - '{{/if}}' + - '{{#if nonedit}}' + - '' + - '{{/if}}' + - '
                          ' + - '
                          ', - CSS = { - CAPTION: 'caption', - CAPTIONPOSITION: 'captionposition', - HEADERS: 'headers', - ROWS: 'rows', - COLUMNS: 'columns', - SUBMIT: 'submit', - FORM: 'atto_form', - BORDERS: 'borders', - BORDERSIZE: 'bordersize', - BORDERSIZEUNIT: 'px', - BORDERCOLOUR: 'bordercolour', - BORDERSTYLE: 'borderstyle', - BACKGROUNDCOLOUR: 'backgroundcolour', - WIDTH: 'customwidth', - WIDTHUNIT: '%', - AVAILABLECOLORS: 'availablecolors', - COLOURROW: 'colourrow' - }, - SELECTORS = { - CAPTION: '.' + CSS.CAPTION, - CAPTIONPOSITION: '.' + CSS.CAPTIONPOSITION, - HEADERS: '.' + CSS.HEADERS, - ROWS: '.' + CSS.ROWS, - COLUMNS: '.' + CSS.COLUMNS, - SUBMIT: '.' + CSS.SUBMIT, - BORDERS: '.' + CSS.BORDERS, - BORDERSIZE: '.' + CSS.BORDERSIZE, - BORDERCOLOURS: '.' + CSS.BORDERCOLOUR + ' input[name="borderColour"]', - SELECTEDBORDERCOLOUR: '.' + CSS.BORDERCOLOUR + ' input[name="borderColour"]:checked', - BORDERSTYLE: '.' + CSS.BORDERSTYLE, - BACKGROUNDCOLOURS: '.' + CSS.BACKGROUNDCOLOUR + ' input[name="backgroundColour"]', - SELECTEDBACKGROUNDCOLOUR: '.' + CSS.BACKGROUNDCOLOUR + ' input[name="backgroundColour"]:checked', - FORM: '.atto_form', - WIDTH: '.' + CSS.WIDTH, - AVAILABLECOLORS: '.' + CSS.AVAILABLECOLORS - }; - -Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - - /** - * A reference to the current selection at the time that the dialogue - * was opened. - * - * @property _currentSelection - * @type Range - * @private - */ - _currentSelection: null, - - /** - * The contextual menu that we can open. - * - * @property _contextMenu - * @type M.editor_atto.Menu - * @private - */ - _contextMenu: null, - - /** - * The last modified target. - * - * @property _lastTarget - * @type Node - * @private - */ - _lastTarget: null, - - /** - * The list of menu items. - * - * @property _menuOptions - * @type Object - * @private - */ - _menuOptions: null, - - initializer: function() { - var button = this.addButton({ - icon: 'e/table', - callback: this._displayTableEditor, - tags: 'table' - }); - - // Listen for toggled highlighting. - require(['editor_atto/events'], function(attoEvents) { - var domButton = button.getDOMNode(); - domButton.addEventListener(attoEvents.eventTypes.attoButtonHighlightToggled, function(e) { - this._setAriaAttributes(e.detail.buttonName, e.detail.highlight); - }.bind(this)); - }.bind(this)); - - // Disable mozilla table controls. - if (Y.UA.gecko) { - document.execCommand("enableInlineTableEditing", false, false); - document.execCommand("enableObjectResizing", false, false); - } - }, - - /** - * Sets the appropriate ARIA attributes for the table button when it switches roles between a button and a menu button. - * - * @param {String} buttonName The button name. - * @param {Boolean} highlight True when the button was highlighted. False, otherwise. - * @private - */ - _setAriaAttributes: function(buttonName, highlight) { - var menuButton = this.buttons[buttonName]; - if (menuButton) { - if (highlight) { - // This button becomes a menu button. Add appropriate ARIA attributes. - var id = menuButton.getAttribute('id'); - menuButton.setAttribute('aria-haspopup', true); - menuButton.setAttribute('aria-controls', id + '_menu'); - menuButton.setAttribute('aria-expanded', true); - } else { - menuButton.removeAttribute('aria-haspopup'); - menuButton.removeAttribute('aria-controls'); - menuButton.removeAttribute('aria-expanded'); - } - } - }, - - /** - * Display the table tool. - * - * @method _displayDialogue - * @private - */ - _displayDialogue: function() { - // Store the current cursor position. - this._currentSelection = this.get('host').getSelection(); - - if (this._currentSelection !== false && (!this._currentSelection.collapsed)) { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('createtable', COMPONENT), - focusAfterHide: true, - focusOnShowSelector: SELECTORS.CAPTION, - width: DIALOGUE.WIDTH - }); - - // Set the dialogue content, and then show the dialogue. - dialogue.set('bodyContent', this._getDialogueContent(false)) - .show(); - - this._updateAvailableSettings(); - } - }, - - /** - * Display the appropriate table editor. - * - * If the current selection includes a table, then we show the - * contextual menu, otherwise show the table creation dialogue. - * - * @method _displayTableEditor - * @param {EventFacade} e - * @private - */ - _displayTableEditor: function(e) { - var cell = this._getSuitableTableCell(); - var menuButton = e.currentTarget.ancestor('button', true); - if (cell) { - var id = menuButton.getAttribute('id'); - - // Indicate that the menu is expanded. - menuButton.setAttribute('aria-expanded', true); - - // Add the cell to the EventFacade to save duplication in when showing the menu. - e.tableCell = cell; - return this._showTableMenu(e, id); - } else { - // Dialog mode. Remove aria-expanded attribute. - menuButton.removeAttribute('aria-expanded'); - } - return this._displayDialogue(e); - }, - - /** - * Returns whether or not the parameter node exists within the editor. - * - * @method _stopAtContentEditableFilter - * @param {Node} node - * @private - * @return {boolean} whether or not the parameter node exists within the editor. - */ - _stopAtContentEditableFilter: function(node) { - return this.editor.contains(node); - }, - - /** - * Return the dialogue content for the tool, attaching any required - * events. - * - * @method _getDialogueContent - * @private - * @return {Node} The content to place in the dialogue. - */ - _getDialogueContent: function(edit) { - var template = Y.Handlebars.compile(TEMPLATE); - var allowBorders = this.get('allowBorders'); - - this._content = Y.Node.create(template({ - CSS: CSS, - elementid: this.get('host').get('elementid'), - component: COMPONENT, - edit: edit, - nonedit: !edit, - allowStyling: this.get('allowStyling'), - allowBorders: allowBorders, - borderStyles: this.get('borderStyles'), - allowBackgroundColour: this.get('allowBackgroundColour'), - availableColours: this.get('availableColors'), - allowWidth: this.get('allowWidth') - })); - - // Handle table setting. - if (edit) { - this._content.one('.submit').on('click', this._updateTable, this); - } else { - this._content.one('.submit').on('click', this._setTable, this); - } - - if (allowBorders) { - this._content.one('[name="borders"]').on('change', this._updateAvailableSettings, this); - } - - return this._content; - }, - - /** - * Disables options within the dialogue if they shouldn't be available. - * E.g. - * If borders are set to "Theme default" then the border size, style and - * colour options are disabled. - * - * @method _updateAvailableSettings - * @private - */ - _updateAvailableSettings: function() { - var tableForm = this._content, - enableBorders = tableForm.one('[name="borders"]'), - borderStyle = tableForm.one('[name="borderstyles"]'), - borderSize = tableForm.one('[name="bordersize"]'), - borderColour = tableForm.all('[name="borderColour"]'), - disabledValue = 'removeAttribute'; - - if (!enableBorders) { - return; - } - - if (enableBorders.get('value') === 'default') { - disabledValue = 'setAttribute'; - } - - if (borderStyle) { - borderStyle[disabledValue]('disabled'); - } - - if (borderSize) { - borderSize[disabledValue]('disabled'); - } - - if (borderColour) { - borderColour[disabledValue]('disabled'); - } - - }, - - /** - * Given the current selection, return a table cell suitable for table editing - * purposes, i.e. the first table cell selected, or the first cell in the table - * that the selection exists in, or null if not within a table. - * - * @method _getSuitableTableCell - * @private - * @return {Node} suitable target cell, or null if not within a table - */ - _getSuitableTableCell: function() { - var targetcell = null, - host = this.get('host'); - var stopAtContentEditableFilter = Y.bind(this._stopAtContentEditableFilter, this); - - host.getSelectedNodes().some(function(node) { - if (node.ancestor('td, th, caption', true, stopAtContentEditableFilter)) { - targetcell = node; - - var caption = node.ancestor('caption', true, stopAtContentEditableFilter); - if (caption) { - var table = caption.get('parentNode'); - if (table) { - targetcell = table.one('td, th'); - } - } - - // Once we've found a cell to target, we shouldn't need to keep looking. - return true; - } - }); - - if (targetcell) { - var selection = host.getSelectionFromNode(targetcell); - host.setSelection(selection); - } - - return targetcell; - }, - - /** - * Change a node from one type to another, copying all attributes and children. - * - * @method _changeNodeType - * @param {Y.Node} node - * @param {String} new node type - * @private - * @chainable - */ - _changeNodeType: function(node, newType) { - var newNode = Y.Node.create('<' + newType + '>'); - newNode.setAttrs(node.getAttrs()); - node.get('childNodes').each(function(child) { - newNode.append(child.remove()); - }); - node.replace(newNode); - return newNode; - }, - - /** - * Handle updating an existing table. - * - * @method _updateTable - * @param {EventFacade} e - * @private - */ - _updateTable: function(e) { - var caption, - captionposition, - headers, - borders, - bordersize, - borderstyle, - bordercolour, - backgroundcolour, - table, - width, - captionnode; - - e.preventDefault(); - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - // Add/update the caption. - caption = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTION); - captionposition = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTIONPOSITION); - headers = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.HEADERS); - borders = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERS); - bordersize = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSIZE); - bordercolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBORDERCOLOUR); - borderstyle = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSTYLE); - backgroundcolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBACKGROUNDCOLOUR); - width = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.WIDTH); - - table = this._lastTarget.ancestor('table'); - this._setAppearance(table, { - width: width, - borders: borders, - borderColour: bordercolour, - borderSize: bordersize, - borderStyle: borderstyle, - backgroundColour: backgroundcolour - }); - - captionnode = table.one('caption'); - if (!captionnode) { - captionnode = Y.Node.create(''); - table.insert(captionnode, 0); - } - captionnode.setHTML(caption.get('value')); - captionnode.setStyle('caption-side', captionposition.get('value')); - if (!captionnode.getAttribute('style')) { - captionnode.removeAttribute('style'); - } - - // Add the row headers. - if (headers.get('value') === 'rows' || headers.get('value') === 'both') { - table.all('tr').each(function(row) { - var cells = row.all('th, td'), - firstCell = cells.shift(), - newCell; - - if (firstCell.get('tagName') === 'TD') { - // Cell is a td but should be a th - change it. - newCell = this._changeNodeType(firstCell, 'th'); - newCell.setAttribute('scope', 'row'); - } else { - firstCell.setAttribute('scope', 'row'); - } - - // Now make sure all other cells in the row are td. - cells.each(function(cell) { - if (cell.get('tagName') === 'TH') { - newCell = this._changeNodeType(cell, 'td'); - newCell.removeAttribute('scope'); - } - }, this); - - }, this); - } - // Add the col headers. These may overrule the row headers in the first cell. - if (headers.get('value') === 'columns' || headers.get('value') === 'both') { - var rows = table.all('tr'), - firstRow = rows.shift(), - newCell; - - firstRow.all('td, th').each(function(cell) { - if (cell.get('tagName') === 'TD') { - // Cell is a td but should be a th - change it. - newCell = this._changeNodeType(cell, 'th'); - newCell.setAttribute('scope', 'col'); - } else { - cell.setAttribute('scope', 'col'); - } - }, this); - // Change all the cells in the rest of the table to tds (unless they are row headers). - rows.each(function(row) { - var cells = row.all('th, td'); - - if (headers.get('value') === 'both') { - // Ignore the first cell because it's a row header. - cells.shift(); - } - cells.each(function(cell) { - if (cell.get('tagName') === 'TH') { - newCell = this._changeNodeType(cell, 'td'); - newCell.removeAttribute('scope'); - } - }, this); - - }, this); - } - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Handle creation of a new table. - * - * @method _setTable - * @param {EventFacade} e - * @private - */ - _setTable: function(e) { - var caption, - captionposition, - borders, - bordersize, - borderstyle, - bordercolour, - rows, - cols, - headers, - tablehtml, - backgroundcolour, - width, - i, j; - - e.preventDefault(); - - // Hide the dialogue. - this.getDialogue({ - focusAfterHide: null - }).hide(); - - caption = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTION); - captionposition = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.CAPTIONPOSITION); - borders = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERS); - bordersize = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSIZE); - bordercolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBORDERCOLOUR); - borderstyle = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.BORDERSTYLE); - backgroundcolour = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.SELECTEDBACKGROUNDCOLOUR); - rows = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.ROWS); - cols = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.COLUMNS); - headers = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.HEADERS); - width = e.currentTarget.ancestor(SELECTORS.FORM).one(SELECTORS.WIDTH); - - // Set the selection. - this.get('host').setSelection(this._currentSelection); - - // Note there are some spaces inserted in the cells and before and after, so that users have somewhere to click. - var nl = "\n"; - var tableId = Y.guid(); - tablehtml = '
                          ' + nl + '' + nl; - - var captionstyle = ''; - if (captionposition.get('value')) { - captionstyle = ' style="caption-side: ' + captionposition.get('value') + '"'; - } - tablehtml += '' + Y.Escape.html(caption.get('value')) + '' + nl; - i = 0; - if (headers.get('value') === 'columns' || headers.get('value') === 'both') { - i = 1; - tablehtml += '' + nl + '' + nl; - for (j = 0; j < parseInt(cols.get('value'), 10); j++) { - tablehtml += '' + nl; - } - tablehtml += '' + nl + '' + nl; - } - tablehtml += '' + nl; - for (; i < parseInt(rows.get('value'), 10); i++) { - tablehtml += '' + nl; - for (j = 0; j < parseInt(cols.get('value'), 10); j++) { - if (j === 0 && (headers.get('value') === 'rows' || headers.get('value') === 'both')) { - tablehtml += '' + nl; - } else { - tablehtml += '' + nl; - } - } - tablehtml += '' + nl; - } - tablehtml += '' + nl; - tablehtml += '
                          ' + nl + '
                          '; - - this.get('host').insertContentAtFocusPoint(tablehtml); - - var tableNode = Y.one('#' + tableId); - this._setAppearance(tableNode, { - width: width, - borders: borders, - borderColour: bordercolour, - borderSize: bordersize, - borderStyle: borderstyle, - backgroundColour: backgroundcolour - }); - tableNode.removeAttribute('id'); - - // Mark the content as updated. - this.markUpdated(); - }, - - /** - * Search for all the cells in the current, next and previous columns. - * - * @method _findColumnCells - * @private - * @return {Object} containing current, prev and next {Y.NodeList}s - */ - _findColumnCells: function() { - var columnindex = this._getColumnIndex(this._lastTarget), - rows = this._lastTarget.ancestor('table').all('tr'), - currentcells = new Y.NodeList(), - prevcells = new Y.NodeList(), - nextcells = new Y.NodeList(); - - rows.each(function(row) { - var cells = row.all('td, th'), - cell = cells.item(columnindex), - cellprev = cells.item(columnindex - 1), - cellnext = cells.item(columnindex + 1); - currentcells.push(cell); - if (cellprev) { - prevcells.push(cellprev); - } - if (cellnext) { - nextcells.push(cellnext); - } - }); - - return { - current: currentcells, - prev: prevcells, - next: nextcells - }; - }, - - /** - * Hide the entries in the context menu that don't make sense with the - * current selection. - * - * @method _hideInvalidEntries - * @param {Y.Node} node - The node containing the menu. - * @private - */ - _hideInvalidEntries: function(node) { - // Moving rows. - var table = this._lastTarget.ancestor('table'), - row = this._lastTarget.ancestor('tr'), - rows = table.all('tr'), - rowindex = rows.indexOf(row), - prevrow = rows.item(rowindex - 1), - prevrowhascells = prevrow ? prevrow.one('td') : null; - - if (!row || !prevrowhascells) { - node.one('[data-change="moverowup"]').hide(); - } else { - node.one('[data-change="moverowup"]').show(); - } - - var nextrow = rows.item(rowindex + 1), - rowhascell = row ? row.one('td') : false; - - if (!row || !nextrow || !rowhascell) { - node.one('[data-change="moverowdown"]').hide(); - } else { - node.one('[data-change="moverowdown"]').show(); - } - - // Moving columns. - var cells = this._findColumnCells(); - if (cells.prev.filter('td').size() > 0) { - node.one('[data-change="movecolumnleft"]').show(); - } else { - node.one('[data-change="movecolumnleft"]').hide(); - } - - var colhascell = cells.current.filter('td').size() > 0; - if ((cells.next.size() > 0) && colhascell) { - node.one('[data-change="movecolumnright"]').show(); - } else { - node.one('[data-change="movecolumnright"]').hide(); - } - - // Delete col - if (cells.current.filter('td').size() > 0) { - node.one('[data-change="deletecolumn"]').show(); - } else { - node.one('[data-change="deletecolumn"]').hide(); - } - // Delete row - if (!row || !row.one('td')) { - node.one('[data-change="deleterow"]').hide(); - } else { - node.one('[data-change="deleterow"]').show(); - } - }, - - /** - * Display the table menu. - * - * @method _showTableMenu - * @param {EventFacade} e - * @param {String} buttonId The ID of the menu button associated with this menu. - * @private - */ - _showTableMenu: function(e, buttonId) { - e.preventDefault(); - - var boundingBox; - var creatorButton = this.buttons[this.name]; - - if (!this._contextMenu) { - this._menuOptions = [ - { - text: M.util.get_string("addcolumnafter", COMPONENT), - data: { - change: "addcolumnafter" - } - }, { - text: M.util.get_string("addrowafter", COMPONENT), - data: { - change: "addrowafter" - } - }, { - text: M.util.get_string("moverowup", COMPONENT), - data: { - change: "moverowup" - } - }, { - text: M.util.get_string("moverowdown", COMPONENT), - data: { - change: "moverowdown" - } - }, { - text: M.util.get_string("movecolumnleft", COMPONENT), - data: { - change: "movecolumnleft" - } - }, { - text: M.util.get_string("movecolumnright", COMPONENT), - data: { - change: "movecolumnright" - } - }, { - text: M.util.get_string("deleterow", COMPONENT), - data: { - change: "deleterow" - } - }, { - text: M.util.get_string("deletecolumn", COMPONENT), - data: { - change: "deletecolumn" - } - }, { - text: M.util.get_string("edittable", COMPONENT), - data: { - change: "edittable" - } - } - ]; - - creatorButton.insert(Y.Node.create(''), 'after'); - this._contextMenu = new Y.M.editor_atto.Menu({ - items: this._menuOptions, - buttonId: buttonId, - attachmentPoint: '#' + buttonId + '_menu' - }); - - // Add event handlers for table control menus. - boundingBox = this._contextMenu.get('boundingBox'); - boundingBox.delegate('click', this._handleTableChange, 'a', this); - } - - boundingBox = this._contextMenu.get('boundingBox'); - - // We store the cell of the last click (the control node is transient). - this._lastTarget = e.tableCell.ancestor('.editor_atto_content td, .editor_atto_content th', true); - - this._hideInvalidEntries(boundingBox); - - // Clear the focusAfterHide for any other menus which may be open. - Y.Array.each(this.get('host').openMenus, function(menu) { - menu.set('focusAfterHide', null); - }); - - // Ensure that we focus on the button in the toolbar when we tab back to the menu. - this.get('host')._setTabFocus(creatorButton); - - // Show the context menu, and align to the current position. - this._contextMenu.show(); - this._contextMenu.align(this.buttons.table, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]); - this._contextMenu.set('focusAfterHide', creatorButton); - - // If there are any anchors in the bounding box, focus on the first. - if (boundingBox.one('a')) { - boundingBox.one('a').focus(); - } - - // Add this menu to the list of open menus. - this.get('host').openMenus = [this._contextMenu]; - }, - - /** - * Handle a selection from the table control menu. - * - * @method _handleTableChange - * @param {EventFacade} e - * @private - */ - _handleTableChange: function(e) { - e.preventDefault(); - - this._contextMenu.set('focusAfterHide', this.get('host').editor); - // Hide the context menu. - this._contextMenu.hide(e); - - // Make our changes. - switch (e.target.getData('change')) { - case 'addcolumnafter': - this._addColumnAfter(); - break; - case 'addrowafter': - this._addRowAfter(); - break; - case 'deleterow': - this._deleteRow(); - break; - case 'deletecolumn': - this._deleteColumn(); - break; - case 'edittable': - this._editTable(); - break; - case 'moverowdown': - this._moveRowDown(); - break; - case 'moverowup': - this._moveRowUp(); - break; - case 'movecolumnleft': - this._moveColumnLeft(); - break; - case 'movecolumnright': - this._moveColumnRight(); - break; - } - }, - - /** - * Determine the index of a row in a table column. - * - * @method _getRowIndex - * @param {Node} cell - * @private - */ - _getRowIndex: function(cell) { - var tablenode = cell.ancestor('table'), - rownode = cell.ancestor('tr'); - - if (!tablenode || !rownode) { - return; - } - - var rows = tablenode.all('tr'); - - return rows.indexOf(rownode); - }, - - /** - * Determine the index of a column in a table row. - * - * @method _getColumnIndex - * @param {Node} cellnode - * @private - */ - _getColumnIndex: function(cellnode) { - var rownode = cellnode.ancestor('tr'); - - if (!rownode) { - return; - } - - var cells = rownode.all('td, th'); - - return cells.indexOf(cellnode); - }, - - /** - * Delete the current row. - * - * @method _deleteRow - * @private - */ - _deleteRow: function() { - var row = this._lastTarget.ancestor('tr'); - - if (row && row.one('td')) { - // Only delete rows with at least one non-header cell. - row.remove(true); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Move row up - * - * @method _moveRowUp - * @private - */ - _moveRowUp: function() { - var row = this._lastTarget.ancestor('tr'), - prevrow = row.previous('tr'); - if (!row || !prevrow) { - return; - } - - row.swap(prevrow); - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Move column left - * - * @method _moveColumnLeft - * @private - */ - _moveColumnLeft: function() { - var cells = this._findColumnCells(); - - if (cells.current.size() > 0 && cells.prev.size() > 0 && cells.current.size() === cells.prev.size()) { - var i = 0; - for (i = 0; i < cells.current.size(); i++) { - var cell = cells.current.item(i), - prevcell = cells.prev.item(i); - - cell.swap(prevcell); - } - } - // Cleanup. - this.markUpdated(); - }, - - /** - * Add a caption to the table if it doesn't have one. - * - * @method _addCaption - * @private - */ - _addCaption: function() { - var table = this._lastTarget.ancestor('table'), - caption = table.one('caption'); - - if (!caption) { - table.insert(Y.Node.create(' '), 1); - } - }, - - /** - * Remove a caption from the table if has one. - * - * @method _removeCaption - * @private - */ - _removeCaption: function() { - var table = this._lastTarget.ancestor('table'), - caption = table.one('caption'); - - if (caption) { - caption.remove(true); - } - }, - - /** - * Move column right. - * - * @method _moveColumnRight - * @private - */ - _moveColumnRight: function() { - var cells = this._findColumnCells(); - - // Check we have some tds in this column, and one exists to the right. - if ((cells.next.size() > 0) && - (cells.current.size() === cells.next.size()) && - (cells.current.filter('td').size() > 0)) { - var i = 0; - for (i = 0; i < cells.current.size(); i++) { - var cell = cells.current.item(i), - nextcell = cells.next.item(i); - - cell.swap(nextcell); - } - } - // Cleanup. - this.markUpdated(); - }, - - /** - * Move row down. - * - * @method _moveRowDown - * @private - */ - _moveRowDown: function() { - var row = this._lastTarget.ancestor('tr'), - nextrow = row.next('tr'); - if (!row || !nextrow || !row.one('td')) { - return; - } - - row.swap(nextrow); - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Obtain values for the table borders - * - * @method _getBorderConfiguration - * @param {Node} node - * @private - * @return {Array} or {Boolean} Returns the settings, if presents, or else returns false - */ - _getBorderConfiguration: function(node) { - // We need to make a clone of the node in order to avoid grabbing any - // of the computed styles from the DOM. We only want inline styles set by us. - var shadowNode = node.cloneNode(true); - var borderStyle = shadowNode.getStyle('borderStyle'), - borderColor = shadowNode.getStyle('borderColor'), - borderWidth = shadowNode.getStyle('borderWidth'); - - if (borderStyle || borderColor || borderWidth) { - var hexColour = Y.Color.toHex(borderColor); - var width = parseInt(borderWidth, 10); - return { - borderStyle: borderStyle, - borderColor: hexColour === "#" ? null : hexColour, - borderWidth: isNaN(width) ? null : width - }; - } - - return false; - }, - - /** - * Set the appropriate styles on the given table node according to - * the provided configuration. - * - * @method _setAppearance - * @param {Node} The table node to be modified. - * @param {Object} Configuration object (associative array) containing the form nodes for - * border styling. - * @private - */ - _setAppearance: function(tableNode, configuration) { - var borderhex, - borderSizeValue, - borderStyleValue, - backgroundcolourvalue; - - if (configuration.borderColour) { - borderhex = configuration.borderColour.get('value'); - } - - if (configuration.borderSize) { - borderSizeValue = configuration.borderSize.get('value'); - } - - if (configuration.borderStyle) { - borderStyleValue = configuration.borderStyle.get('value'); - } - - if (configuration.backgroundColour) { - backgroundcolourvalue = configuration.backgroundColour.get('value'); - } - - // Clear the inline border styling - tableNode.removeAttribute('style'); - tableNode.all('td, th').each(function(cell) { - cell.removeAttribute('style'); - }, this); - - if (configuration.borders) { - if (configuration.borders.get('value') === 'outer') { - tableNode.setStyle('borderWidth', borderSizeValue + CSS.BORDERSIZEUNIT); - tableNode.setStyle('borderStyle', borderStyleValue); - - if (borderhex !== 'none') { - tableNode.setStyle('borderColor', borderhex); - } - } else if (configuration.borders.get('value') === 'all') { - tableNode.all('td, th').each(function(cell) { - cell.setStyle('borderWidth', borderSizeValue + CSS.BORDERSIZEUNIT); - cell.setStyle('borderStyle', borderStyleValue); - - if (borderhex !== 'none') { - cell.setStyle('borderColor', borderhex); - } - }, this); - } - } - - if (backgroundcolourvalue !== 'none') { - tableNode.setStyle('backgroundColor', backgroundcolourvalue); - } - - if (configuration.width && configuration.width.get('value')) { - tableNode.setStyle('width', configuration.width.get('value') + CSS.WIDTHUNIT); - } - }, - - /** - * Edit table (show the dialogue). - * - * @method _editTable - * @private - */ - _editTable: function() { - var dialogue = this.getDialogue({ - headerContent: M.util.get_string('edittable', COMPONENT), - focusAfterHide: false, - focusOnShowSelector: SELECTORS.CAPTION, - width: DIALOGUE.WIDTH - }); - - // Set the dialogue content, and then show the dialogue. - var node = this._getDialogueContent(true), - captioninput = node.one(SELECTORS.CAPTION), - captionpositioninput = node.one(SELECTORS.CAPTIONPOSITION), - headersinput = node.one(SELECTORS.HEADERS), - borderinput = node.one(SELECTORS.BORDERS), - borderstyle = node.one(SELECTORS.BORDERSTYLE), - bordercolours = node.all(SELECTORS.BORDERCOLOURS), - bordersize = node.one(SELECTORS.BORDERSIZE), - backgroundcolours = node.all(SELECTORS.BACKGROUNDCOLOURS), - width = node.one(SELECTORS.WIDTH), - table = this._lastTarget.ancestor('table'), - captionnode = table.one('caption'), - hexColour, - matchedInput; - - if (captionnode) { - captioninput.set('value', captionnode.getHTML()); - } else { - captioninput.set('value', ''); - } - - if (width && table.getStyle('width').indexOf('px') === -1) { - width.set('value', parseInt(table.getStyle('width'), 10)); - } - - if (captionpositioninput && captionnode && captionnode.getAttribute('style')) { - captionpositioninput.set('value', captionnode.getStyle('caption-side')); - } else { - // Default to none. - captionpositioninput.set('value', ''); - } - - if (table.getStyle('backgroundColor') && this.get('allowBackgroundColour')) { - hexColour = Y.Color.toHex(table.getStyle('backgroundColor')); - matchedInput = backgroundcolours.filter('[value="' + hexColour + '"]'); - - if (matchedInput) { - matchedInput.set("checked", true); - } - } - - if (this.get('allowBorders')) { - var borderValue = 'default', - borderConfiguration = this._getBorderConfiguration(table); - - if (borderConfiguration) { - borderValue = 'outer'; - } else { - borderConfiguration = this._getBorderConfiguration(table.one('td')); - if (borderConfiguration) { - borderValue = 'all'; - } - } - - if (borderConfiguration) { - var borderStyle = borderConfiguration.borderStyle || DEFAULT.BORDERSTYLE; - var borderSize = borderConfiguration.borderWidth || DEFAULT.BORDERWIDTH; - borderstyle.set('value', borderStyle); - bordersize.set('value', borderSize); - borderinput.set('value', borderValue); - - hexColour = borderConfiguration.borderColor; - matchedInput = bordercolours.filter('[value="' + hexColour + '"]'); - - if (matchedInput) { - matchedInput.set("checked", true); - } - } - } - - var headersvalue = 'columns'; - if (table.one('th[scope="row"]')) { - headersvalue = 'rows'; - if (table.one('th[scope="col"]')) { - headersvalue = 'both'; - } - } - headersinput.set('value', headersvalue); - dialogue.set('bodyContent', node).show(); - this._updateAvailableSettings(); - }, - - - /** - * Delete the current column. - * - * @method _deleteColumn - * @private - */ - _deleteColumn: function() { - var columnindex = this._getColumnIndex(this._lastTarget), - table = this._lastTarget.ancestor('table'), - rows = table.all('tr'), - columncells = new Y.NodeList(), - hastd = false; - - rows.each(function(row) { - var cells = row.all('td, th'); - var cell = cells.item(columnindex); - if (cell.get('tagName') === 'TD') { - hastd = true; - } - columncells.push(cell); - }); - - // Do not delete all the headers. - if (hastd) { - columncells.remove(true); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Add a row after the current row. - * - * @method _addRowAfter - * @private - */ - _addRowAfter: function() { - var target = this._lastTarget.ancestor('tr'), - tablebody = this._lastTarget.ancestor('table').one('tbody'); - if (!tablebody) { - // Not all tables have tbody. - tablebody = this._lastTarget.ancestor('table'); - } - - var firstrow = tablebody.one('tr'); - if (!firstrow) { - firstrow = this._lastTarget.ancestor('table').one('tr'); - } - if (!firstrow) { - // Table has no rows. Boo. - return; - } - var newrow = firstrow.cloneNode(true); - newrow.all('th, td').each(function(tablecell) { - if (tablecell.get('tagName') === 'TH') { - if (tablecell.getAttribute('scope') !== 'row') { - var newcell = Y.Node.create(''); - tablecell.replace(newcell); - tablecell = newcell; - } - } - tablecell.setHTML(' '); - }); - - if (target.ancestor('thead')) { - target = firstrow; - tablebody.insert(newrow, target); - } else { - target.insert(newrow, 'after'); - } - - // Clean the HTML. - this.markUpdated(); - }, - - /** - * Add a column after the current column. - * - * @method _addColumnAfter - * @private - */ - _addColumnAfter: function() { - var cells = this._findColumnCells(), - before = true, - clonecells = cells.next; - if (cells.next.size() <= 0) { - before = false; - clonecells = cells.current; - } - - Y.each(clonecells, function(cell) { - var newcell = cell.cloneNode(); - // Clear the content of the cell. - newcell.setHTML(' '); - - if (before) { - cell.get('parentNode').insert(newcell, cell); - } else { - cell.get('parentNode').insert(newcell, cell); - cell.swap(newcell); - } - }, this); - - // Clean the HTML. - this.markUpdated(); - } - -}, { - ATTRS: { - /** - * Whether or not to allow borders - * - * @attribute allowBorder - * @type Boolean - */ - allowBorders: { - value: true - }, - - /** - * What border styles to allow - * - * @attribute borderStyles - * @type Array - */ - borderStyles: { - value: [ - 'none', - 'solid', - 'dashed', - 'dotted' - ] - }, - - /** - * Whether or not to allow colourizing the background - * - * @attribute allowBackgroundColour - * @type Boolean - */ - allowBackgroundColour: { - value: true - }, - - /** - * Whether or not to allow setting the table width - * - * @attribute allowWidth - * @type Boolean - */ - allowWidth: { - value: true - }, - - /** - * Whether we allow styling - * @attribute allowStyling - * @type Boolean - */ - allowStyling: { - readOnly: true, - getter: function() { - return this.get('allowBorders') || this.get('allowBackgroundColour') || this.get('allowWidth'); - } - }, - - /** - * Available colors - * @attribute availableColors - * @type Array - */ - availableColors: { - value: [ - '#FFFFFF', - '#EF4540', - '#FFCF35', - '#98CA3E', - '#7D9FD3', - '#333333' - ], - readOnly: true - } - } -}); diff --git a/lib/editor/atto/plugins/table/yui/src/button/meta/button.json b/lib/editor/atto/plugins/table/yui/src/button/meta/button.json deleted file mode 100644 index f3130f23c99..00000000000 --- a/lib/editor/atto/plugins/table/yui/src/button/meta/button.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "moodle-atto_table-button": { - "requires": [ - "moodle-editor_atto-plugin", - "moodle-editor_atto-menu", - "event", - "event-valuechange" - ] - } -} diff --git a/lib/editor/atto/plugins/title/classes/privacy/provider.php b/lib/editor/atto/plugins/title/classes/privacy/provider.php deleted file mode 100644 index 67f1198f64f..00000000000 --- a/lib/editor/atto/plugins/title/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_title - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_title\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_title implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/title/lang/en/atto_title.php b/lib/editor/atto/plugins/title/lang/en/atto_title.php deleted file mode 100644 index 7c9109a52a9..00000000000 --- a/lib/editor/atto/plugins/title/lang/en/atto_title.php +++ /dev/null @@ -1,32 +0,0 @@ -. - -/** - * Strings for component 'atto_title', language 'en'. - * - * @package atto_title - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['h3'] = 'Heading (large)'; -$string['h4'] = 'Heading (medium)'; -$string['h5'] = 'Heading (small)'; -$string['p'] = 'Paragraph'; -$string['pluginname'] = 'Paragraph styles'; -$string['pre'] = 'Pre-formatted'; -$string['title'] = 'Paragraph styles'; -$string['privacy:metadata'] = 'The atto_title plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/title/lib.php b/lib/editor/atto/plugins/title/lib.php deleted file mode 100644 index ae51a037e1c..00000000000 --- a/lib/editor/atto/plugins/title/lib.php +++ /dev/null @@ -1,36 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_title - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -function atto_title_strings_for_js() { - global $PAGE; - - $PAGE->requires->strings_for_js(array('h3', - 'h4', - 'h5', - 'pre', - 'p'), 'atto_title'); -} - diff --git a/lib/editor/atto/plugins/title/tests/behat/title.feature b/lib/editor/atto/plugins/title/tests/behat/title.feature deleted file mode 100644 index 1a62aad9a70..00000000000 --- a/lib/editor/atto/plugins/title/tests/behat/title.feature +++ /dev/null @@ -1,19 +0,0 @@ -@editor @editor_atto @atto @atto_title -Feature: Atto title - To format text in Atto, I need to add headings - - @javascript - Scenario: Create a heading - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "How The Rock Has Made the WWE World Heavyweight Title More Important Than Ever" - And I select the text in the "Description" Atto editor - When I click on "Paragraph styles" "button" - When I click on "Heading (large)" "link" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "

                          How The Rock" diff --git a/lib/editor/atto/plugins/title/version.php b/lib/editor/atto/plugins/title/version.php deleted file mode 100644 index edc61ba2d9c..00000000000 --- a/lib/editor/atto/plugins/title/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_title - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_title'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-debug.js b/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-debug.js deleted file mode 100644 index 818a5e3c0d1..00000000000 --- a/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-debug.js +++ /dev/null @@ -1,95 +0,0 @@ -YUI.add('moodle-atto_title-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_title - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_title-button - */ - -/** - * Atto text editor title plugin. - * - * @namespace M.atto_title - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var component = 'atto_title', - styles = [ - { - text: 'h3', - callbackArgs: '

                          ' - }, - { - text: 'h4', - callbackArgs: '

                          ' - }, - { - text: 'h5', - callbackArgs: '

                          ' - }, - { - text: 'pre', - callbackArgs: '
                          '
                          -        },
                          -        {
                          -            text: 'p',
                          -            callbackArgs: '

                          ' - } - ]; - -Y.namespace('M.atto_title').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(styles, function(style) { - items.push({ - text: M.util.get_string(style.text, component), - callbackArgs: style.callbackArgs - }); - }); - this.addToolbarMenu({ - icon: 'e/styleparagraph', - globalItemConfig: { - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the title to the specified style. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new style - * @private - */ - _changeStyle: function(e, style) { - document.execCommand('formatBlock', false, style); - - // Mark as updated - this.markUpdated(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-min.js b/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-min.js deleted file mode 100644 index d6a3fe8c9f7..00000000000 --- a/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_title-button",function(t,a){var e=[{text:"h3",callbackArgs:"

                          "},{text:"h4",callbackArgs:"

                          "},{text:"h5",callbackArgs:"

                          "},{text:"pre",callbackArgs:"
                          "},{text:"p",callbackArgs:"

                          "}];t.namespace("M.atto_title").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){var a=[];t.Array.each(e,function(t){a.push({text:M.util.get_string(t.text,"atto_title"),callbackArgs:t.callbackArgs})}),this.addToolbarMenu({icon:"e/styleparagraph",globalItemConfig:{callback:this._changeStyle},items:a})},_changeStyle:function(t,a){document.execCommand("formatBlock",!1,a),this.markUpdated()}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button.js b/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button.js deleted file mode 100644 index 818a5e3c0d1..00000000000 --- a/lib/editor/atto/plugins/title/yui/build/moodle-atto_title-button/moodle-atto_title-button.js +++ /dev/null @@ -1,95 +0,0 @@ -YUI.add('moodle-atto_title-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_title - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_title-button - */ - -/** - * Atto text editor title plugin. - * - * @namespace M.atto_title - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var component = 'atto_title', - styles = [ - { - text: 'h3', - callbackArgs: '

                          ' - }, - { - text: 'h4', - callbackArgs: '

                          ' - }, - { - text: 'h5', - callbackArgs: '

                          ' - }, - { - text: 'pre', - callbackArgs: '
                          '
                          -        },
                          -        {
                          -            text: 'p',
                          -            callbackArgs: '

                          ' - } - ]; - -Y.namespace('M.atto_title').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(styles, function(style) { - items.push({ - text: M.util.get_string(style.text, component), - callbackArgs: style.callbackArgs - }); - }); - this.addToolbarMenu({ - icon: 'e/styleparagraph', - globalItemConfig: { - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the title to the specified style. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new style - * @private - */ - _changeStyle: function(e, style) { - document.execCommand('formatBlock', false, style); - - // Mark as updated - this.markUpdated(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/title/yui/src/button/build.json b/lib/editor/atto/plugins/title/yui/src/button/build.json deleted file mode 100644 index 8ee3ce0e4b8..00000000000 --- a/lib/editor/atto/plugins/title/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_title-button", - "builds": { - "moodle-atto_title-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/title/yui/src/button/js/button.js b/lib/editor/atto/plugins/title/yui/src/button/js/button.js deleted file mode 100644 index d2d90274347..00000000000 --- a/lib/editor/atto/plugins/title/yui/src/button/js/button.js +++ /dev/null @@ -1,90 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_title - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_title-button - */ - -/** - * Atto text editor title plugin. - * - * @namespace M.atto_title - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -var component = 'atto_title', - styles = [ - { - text: 'h3', - callbackArgs: '

                          ' - }, - { - text: 'h4', - callbackArgs: '

                          ' - }, - { - text: 'h5', - callbackArgs: '

                          ' - }, - { - text: 'pre', - callbackArgs: '
                          '
                          -        },
                          -        {
                          -            text: 'p',
                          -            callbackArgs: '

                          ' - } - ]; - -Y.namespace('M.atto_title').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - var items = []; - Y.Array.each(styles, function(style) { - items.push({ - text: M.util.get_string(style.text, component), - callbackArgs: style.callbackArgs - }); - }); - this.addToolbarMenu({ - icon: 'e/styleparagraph', - globalItemConfig: { - callback: this._changeStyle - }, - items: items - }); - }, - - /** - * Change the title to the specified style. - * - * @method _changeStyle - * @param {EventFacade} e - * @param {string} color The new style - * @private - */ - _changeStyle: function(e, style) { - document.execCommand('formatBlock', false, style); - - // Mark as updated - this.markUpdated(); - } -}); diff --git a/lib/editor/atto/plugins/title/yui/src/button/meta/button.json b/lib/editor/atto/plugins/title/yui/src/button/meta/button.json deleted file mode 100644 index 18e0aab9659..00000000000 --- a/lib/editor/atto/plugins/title/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_title-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/underline/classes/privacy/provider.php b/lib/editor/atto/plugins/underline/classes/privacy/provider.php deleted file mode 100644 index f4ac5df3220..00000000000 --- a/lib/editor/atto/plugins/underline/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_underline - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_underline\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_underline implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/underline/lang/en/atto_underline.php b/lib/editor/atto/plugins/underline/lang/en/atto_underline.php deleted file mode 100644 index 49b733b314f..00000000000 --- a/lib/editor/atto/plugins/underline/lang/en/atto_underline.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_underline', language 'en'. - * - * @package atto_underline - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Underline'; -$string['privacy:metadata'] = 'The atto_underline plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/underline/tests/behat/underline.feature b/lib/editor/atto/plugins/underline/tests/behat/underline.feature deleted file mode 100644 index 2a09ba11b79..00000000000 --- a/lib/editor/atto/plugins/underline/tests/behat/underline.feature +++ /dev/null @@ -1,19 +0,0 @@ -@editor @editor_atto @atto @atto_underline @_bug_phantomjs -Feature: Atto underline button - To format text in Atto, I need to use the underline button. - - @javascript - Scenario: Underline some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Deprecated HTML Tag" - And I select the text in the "Description" Atto editor - And I click on "Show more buttons" "button" - When I click on "Underline" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then I should see "Deprecated HTML Tag" diff --git a/lib/editor/atto/plugins/underline/version.php b/lib/editor/atto/plugins/underline/version.php deleted file mode 100644 index ceae13eff5d..00000000000 --- a/lib/editor/atto/plugins/underline/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_underline - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_underline'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-debug.js b/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-debug.js deleted file mode 100644 index 91894955151..00000000000 --- a/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-debug.js +++ /dev/null @@ -1,51 +0,0 @@ -YUI.add('moodle-atto_underline-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_underline - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_underline-button - */ - -/** - * Atto text editor underline plugin. - * - * @namespace M.atto_underline - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_underline').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'underline', - - // Key code for the keyboard shortcut which triggers this button: - keys: '85', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'u' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-min.js b/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-min.js deleted file mode 100644 index c14cfc89188..00000000000 --- a/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_underline-button",function(t,e){t.namespace("M.atto_underline").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addBasicButton({exec:"underline",keys:"85",tags:"u"})}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button.js b/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button.js deleted file mode 100644 index 91894955151..00000000000 --- a/lib/editor/atto/plugins/underline/yui/build/moodle-atto_underline-button/moodle-atto_underline-button.js +++ /dev/null @@ -1,51 +0,0 @@ -YUI.add('moodle-atto_underline-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_underline - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_underline-button - */ - -/** - * Atto text editor underline plugin. - * - * @namespace M.atto_underline - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_underline').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'underline', - - // Key code for the keyboard shortcut which triggers this button: - keys: '85', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'u' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/underline/yui/src/button/build.json b/lib/editor/atto/plugins/underline/yui/src/button/build.json deleted file mode 100644 index 761727315e1..00000000000 --- a/lib/editor/atto/plugins/underline/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_underline-button", - "builds": { - "moodle-atto_underline-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/underline/yui/src/button/js/button.js b/lib/editor/atto/plugins/underline/yui/src/button/js/button.js deleted file mode 100644 index cb27d25d653..00000000000 --- a/lib/editor/atto/plugins/underline/yui/src/button/js/button.js +++ /dev/null @@ -1,46 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_underline - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_underline-button - */ - -/** - * Atto text editor underline plugin. - * - * @namespace M.atto_underline - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_underline').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'underline', - - // Key code for the keyboard shortcut which triggers this button: - keys: '85', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'u' - }); - } -}); diff --git a/lib/editor/atto/plugins/underline/yui/src/button/meta/button.json b/lib/editor/atto/plugins/underline/yui/src/button/meta/button.json deleted file mode 100644 index 27420341a90..00000000000 --- a/lib/editor/atto/plugins/underline/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_underline-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/undo/classes/privacy/provider.php b/lib/editor/atto/plugins/undo/classes/privacy/provider.php deleted file mode 100644 index 3990d701d84..00000000000 --- a/lib/editor/atto/plugins/undo/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_undo - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_undo\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_undo implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/undo/lang/en/atto_undo.php b/lib/editor/atto/plugins/undo/lang/en/atto_undo.php deleted file mode 100644 index 3f03740fc97..00000000000 --- a/lib/editor/atto/plugins/undo/lang/en/atto_undo.php +++ /dev/null @@ -1,28 +0,0 @@ -. - -/** - * Strings for component 'atto_undo', language 'en'. - * - * @package atto_undo - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Undo/Redo'; -$string['privacy:metadata'] = 'The atto_undo plugin does not store any personal data.'; -$string['redo'] = 'Redo'; -$string['undo'] = 'Undo'; diff --git a/lib/editor/atto/plugins/undo/lib.php b/lib/editor/atto/plugins/undo/lib.php deleted file mode 100644 index 5e0a60b8dcd..00000000000 --- a/lib/editor/atto/plugins/undo/lib.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Atto text editor undo plugin lib. - * - * @package atto_undo - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Initialise the strings required for JS. - * - * @return void - */ -function atto_undo_strings_for_js() { - global $PAGE; - - // In order to prevent extra strings to be imported, comment/uncomment the characters - // which are enabled in the JavaScript part of this plugin. - $PAGE->requires->strings_for_js( - array( - 'redo', - 'undo' - ), - 'atto_undo' - ); -} diff --git a/lib/editor/atto/plugins/undo/version.php b/lib/editor/atto/plugins/undo/version.php deleted file mode 100644 index 4832b65cc47..00000000000 --- a/lib/editor/atto/plugins/undo/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_undo - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_undo'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js b/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js deleted file mode 100644 index 81c39d1c627..00000000000 --- a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js +++ /dev/null @@ -1,306 +0,0 @@ -YUI.add('moodle-atto_undo-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @component atto_undo - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_undo-button - */ - -/** - * Atto text editor undo plugin. - * - * @namespace M.atto_undo - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * The maximum saved number of undo steps. - * - * @property _maxUndos - * @type {Number} The maximum number of saved undos. - * @default 40 - * @private - */ - _maxUndos: 40, - - /** - * History of edits. - * - * @property _undoStack - * @type {Array} The elements of the array are the html strings that make a snapshot - * @private - */ - _undoStack: null, - - /** - * History of edits. - * - * @property _redoStack - * @type {Array} The elements of the array are the html strings that make a snapshot - * @private - */ - _redoStack: null, - - /** - * Add the buttons to the toolbar - * - * @method initializer - */ - initializer: function() { - // Initialise the undo and redo stacks. - this._undoStack = []; - this._redoStack = []; - - this.addButton({ - title: 'undo', - icon: 'e/undo', - callback: this._undoHandler, - buttonName: 'undo', - keys: 90 - }); - - this.addButton({ - title: 'redo', - icon: 'e/redo', - callback: this._redoHandler, - buttonName: 'redo', - keys: 89 - }); - - // Enable the undo once everything has loaded. - this.get('host').on('pluginsloaded', function() { - // Adds the current value to the stack. - this._addToUndo(this._getHTML()); - this.get('host').on('atto:selectionchanged', this._changeListener, this); - }, this); - - this._updateButtonsStates(); - }, - - /** - * Adds an element to the redo stack. - * - * @method _addToRedo - * @private - * @param {String} html The HTML content to save. - */ - _addToRedo: function(html) { - this._redoStack.push(html); - }, - - /** - * Adds an element to the undo stack. - * - * @method _addToUndo - * @private - * @param {String} html The HTML content to save. - * @param {Boolean} [clearRedo=false] Whether or not we should clear the redo stack. - */ - _addToUndo: function(html, clearRedo) { - var last = this._undoStack[this._undoStack.length - 1]; - - if (typeof clearRedo === 'undefined') { - clearRedo = false; - } - - if (last !== html) { - this._undoStack.push(html); - if (clearRedo) { - this._redoStack = []; - } - } - - while (this._undoStack.length > this._maxUndos) { - this._undoStack.shift(); - } - }, - - /** - * Get the editor HTML. - * - * @method _getHTML - * @private - * @return {String} The HTML. - */ - _getHTML: function() { - return this.get('host').getCleanHTML(); - }, - - /** - * Get an element on the redo stack. - * - * @method _getRedo - * @private - * @return {String} The HTML to restore, or undefined. - */ - _getRedo: function() { - return this._redoStack.pop(); - }, - - /** - * Get an element on the undo stack. - * - * @method _getUndo - * @private - * @param {String} current The current HTML. - * @return {String} The HTML to restore. - */ - _getUndo: function(current) { - if (this._undoStack.length === 1) { - return this._undoStack[0]; - } - - var last = this._undoStack.pop(); - if (last === current) { - // Oops, the latest undo step is the current content, we should unstack once more. - // There is no need to do that in a loop as the same stack should never contain duplicates. - last = this._undoStack.pop(); - } - - // We always need to keep the first element of the stack. - if (this._undoStack.length === 0) { - this._addToUndo(last); - } - - return last; - }, - - /** - * Restore a value from a stack. - * - * @method _restoreValue - * @private - * @param {String} html The HTML to restore in the editor. - */ - _restoreValue: function(html) { - this.editor.setHTML(html); - // We always add the restored value to the stack, otherwise an event could think that - // the content has changed and clear the redo stack. - this._addToUndo(html); - }, - - /** - * Update the states of the buttons. - * - * @method _updateButtonsStates - * @private - */ - _updateButtonsStates: function() { - if (this._undoStack.length > 1) { - this.enableButtons('undo'); - } else { - this.disableButtons('undo'); - } - - if (this._redoStack.length > 0) { - this.enableButtons('redo'); - } else { - this.disableButtons('redo'); - } - }, - - /** - * Handle a click on undo - * - * @method _undoHandler - * @param {Event} The click event - * @private - */ - _undoHandler: function(e) { - e.preventDefault(); - var html = this._getHTML(), - undo = this._getUndo(html); - - // Edge case, but that could happen. We do nothing when the content equals the undo step. - if (html === undo) { - this._updateButtonsStates(); - return; - } - - // Restore the value. - this._restoreValue(undo); - - // Add to the redo stack. - this._addToRedo(html); - - // Update the button states. - this._updateButtonsStates(); - }, - - /** - * Handle a click on redo - * - * @method _redoHandler - * @param {Event} The click event - * @private - */ - _redoHandler: function(e) { - e.preventDefault(); - - // Don't do anything if redo stack is empty. - if (this._redoStack.length === 0) { - return; - } - - var html = this._getHTML(), - redo = this._getRedo(); - - // Edge case, but that could happen. We do nothing when the content equals the redo step. - if (html === redo) { - this._updateButtonsStates(); - return; - } - // Restore the value. - this._restoreValue(redo); - - // Update the button states. - this._updateButtonsStates(); - }, - - /** - * If we are significantly different from the last saved version, save a new version. - * - * @method _changeListener - * @param {EventFacade} The click event - * @private - */ - _changeListener: function(e) { - if (e.event && e.event.type.indexOf('key') !== -1) { - // These are the 4 arrow keys. - if ((e.event.keyCode !== 39) && - (e.event.keyCode !== 37) && - (e.event.keyCode !== 40) && - (e.event.keyCode !== 38)) { - // Skip this event type. We only want focus/mouse/arrow events. - return; - } - } - - this._addToUndo(this._getHTML(), true); - this._updateButtonsStates(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js b/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js deleted file mode 100644 index b78787e0582..00000000000 --- a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_undo-button",function(t,e){t.namespace("M.atto_undo").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{_maxUndos:40,_undoStack:null,_redoStack:null,initializer:function(){this._undoStack=[],this._redoStack=[],this.addButton({title:"undo",icon:"e/undo",callback:this._undoHandler,buttonName:"undo",keys:90}),this.addButton({title:"redo",icon:"e/redo",callback:this._redoHandler,buttonName:"redo",keys:89}),this.get("host").on("pluginsloaded",function(){this._addToUndo(this._getHTML()),this.get("host").on("atto:selectionchanged",this._changeListener,this)},this),this._updateButtonsStates()},_addToRedo:function(t){this._redoStack.push(t)},_addToUndo:function(t,e){for(void 0===e&&(e=!1),this._undoStack[this._undoStack.length-1]!==t&&(this._undoStack.push(t),e&&(this._redoStack=[]));this._undoStack.length>this._maxUndos;)this._undoStack.shift()},_getHTML:function(){return this.get("host").getCleanHTML()},_getRedo:function(){return this._redoStack.pop()},_getUndo:function(t){if(1===this._undoStack.length)return this._undoStack[0];var e=this._undoStack.pop();return e===t&&(e=this._undoStack.pop()),0===this._undoStack.length&&this._addToUndo(e),e},_restoreValue:function(t){this.editor.setHTML(t),this._addToUndo(t)},_updateButtonsStates:function(){1. - -/** - * @component atto_undo - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_undo-button - */ - -/** - * Atto text editor undo plugin. - * - * @namespace M.atto_undo - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * The maximum saved number of undo steps. - * - * @property _maxUndos - * @type {Number} The maximum number of saved undos. - * @default 40 - * @private - */ - _maxUndos: 40, - - /** - * History of edits. - * - * @property _undoStack - * @type {Array} The elements of the array are the html strings that make a snapshot - * @private - */ - _undoStack: null, - - /** - * History of edits. - * - * @property _redoStack - * @type {Array} The elements of the array are the html strings that make a snapshot - * @private - */ - _redoStack: null, - - /** - * Add the buttons to the toolbar - * - * @method initializer - */ - initializer: function() { - // Initialise the undo and redo stacks. - this._undoStack = []; - this._redoStack = []; - - this.addButton({ - title: 'undo', - icon: 'e/undo', - callback: this._undoHandler, - buttonName: 'undo', - keys: 90 - }); - - this.addButton({ - title: 'redo', - icon: 'e/redo', - callback: this._redoHandler, - buttonName: 'redo', - keys: 89 - }); - - // Enable the undo once everything has loaded. - this.get('host').on('pluginsloaded', function() { - // Adds the current value to the stack. - this._addToUndo(this._getHTML()); - this.get('host').on('atto:selectionchanged', this._changeListener, this); - }, this); - - this._updateButtonsStates(); - }, - - /** - * Adds an element to the redo stack. - * - * @method _addToRedo - * @private - * @param {String} html The HTML content to save. - */ - _addToRedo: function(html) { - this._redoStack.push(html); - }, - - /** - * Adds an element to the undo stack. - * - * @method _addToUndo - * @private - * @param {String} html The HTML content to save. - * @param {Boolean} [clearRedo=false] Whether or not we should clear the redo stack. - */ - _addToUndo: function(html, clearRedo) { - var last = this._undoStack[this._undoStack.length - 1]; - - if (typeof clearRedo === 'undefined') { - clearRedo = false; - } - - if (last !== html) { - this._undoStack.push(html); - if (clearRedo) { - this._redoStack = []; - } - } - - while (this._undoStack.length > this._maxUndos) { - this._undoStack.shift(); - } - }, - - /** - * Get the editor HTML. - * - * @method _getHTML - * @private - * @return {String} The HTML. - */ - _getHTML: function() { - return this.get('host').getCleanHTML(); - }, - - /** - * Get an element on the redo stack. - * - * @method _getRedo - * @private - * @return {String} The HTML to restore, or undefined. - */ - _getRedo: function() { - return this._redoStack.pop(); - }, - - /** - * Get an element on the undo stack. - * - * @method _getUndo - * @private - * @param {String} current The current HTML. - * @return {String} The HTML to restore. - */ - _getUndo: function(current) { - if (this._undoStack.length === 1) { - return this._undoStack[0]; - } - - var last = this._undoStack.pop(); - if (last === current) { - // Oops, the latest undo step is the current content, we should unstack once more. - // There is no need to do that in a loop as the same stack should never contain duplicates. - last = this._undoStack.pop(); - } - - // We always need to keep the first element of the stack. - if (this._undoStack.length === 0) { - this._addToUndo(last); - } - - return last; - }, - - /** - * Restore a value from a stack. - * - * @method _restoreValue - * @private - * @param {String} html The HTML to restore in the editor. - */ - _restoreValue: function(html) { - this.editor.setHTML(html); - // We always add the restored value to the stack, otherwise an event could think that - // the content has changed and clear the redo stack. - this._addToUndo(html); - }, - - /** - * Update the states of the buttons. - * - * @method _updateButtonsStates - * @private - */ - _updateButtonsStates: function() { - if (this._undoStack.length > 1) { - this.enableButtons('undo'); - } else { - this.disableButtons('undo'); - } - - if (this._redoStack.length > 0) { - this.enableButtons('redo'); - } else { - this.disableButtons('redo'); - } - }, - - /** - * Handle a click on undo - * - * @method _undoHandler - * @param {Event} The click event - * @private - */ - _undoHandler: function(e) { - e.preventDefault(); - var html = this._getHTML(), - undo = this._getUndo(html); - - // Edge case, but that could happen. We do nothing when the content equals the undo step. - if (html === undo) { - this._updateButtonsStates(); - return; - } - - // Restore the value. - this._restoreValue(undo); - - // Add to the redo stack. - this._addToRedo(html); - - // Update the button states. - this._updateButtonsStates(); - }, - - /** - * Handle a click on redo - * - * @method _redoHandler - * @param {Event} The click event - * @private - */ - _redoHandler: function(e) { - e.preventDefault(); - - // Don't do anything if redo stack is empty. - if (this._redoStack.length === 0) { - return; - } - - var html = this._getHTML(), - redo = this._getRedo(); - - // Edge case, but that could happen. We do nothing when the content equals the redo step. - if (html === redo) { - this._updateButtonsStates(); - return; - } - // Restore the value. - this._restoreValue(redo); - - // Update the button states. - this._updateButtonsStates(); - }, - - /** - * If we are significantly different from the last saved version, save a new version. - * - * @method _changeListener - * @param {EventFacade} The click event - * @private - */ - _changeListener: function(e) { - if (e.event && e.event.type.indexOf('key') !== -1) { - // These are the 4 arrow keys. - if ((e.event.keyCode !== 39) && - (e.event.keyCode !== 37) && - (e.event.keyCode !== 40) && - (e.event.keyCode !== 38)) { - // Skip this event type. We only want focus/mouse/arrow events. - return; - } - } - - this._addToUndo(this._getHTML(), true); - this._updateButtonsStates(); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/undo/yui/src/button/build.json b/lib/editor/atto/plugins/undo/yui/src/button/build.json deleted file mode 100644 index b16703f4422..00000000000 --- a/lib/editor/atto/plugins/undo/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_undo-button", - "builds": { - "moodle-atto_undo-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/undo/yui/src/button/js/button.js b/lib/editor/atto/plugins/undo/yui/src/button/js/button.js deleted file mode 100644 index aa3ce8a1a41..00000000000 --- a/lib/editor/atto/plugins/undo/yui/src/button/js/button.js +++ /dev/null @@ -1,301 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @component atto_undo - * @copyright 2014 Jerome Mouneyrac - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_undo-button - */ - -/** - * Atto text editor undo plugin. - * - * @namespace M.atto_undo - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - /** - * The maximum saved number of undo steps. - * - * @property _maxUndos - * @type {Number} The maximum number of saved undos. - * @default 40 - * @private - */ - _maxUndos: 40, - - /** - * History of edits. - * - * @property _undoStack - * @type {Array} The elements of the array are the html strings that make a snapshot - * @private - */ - _undoStack: null, - - /** - * History of edits. - * - * @property _redoStack - * @type {Array} The elements of the array are the html strings that make a snapshot - * @private - */ - _redoStack: null, - - /** - * Add the buttons to the toolbar - * - * @method initializer - */ - initializer: function() { - // Initialise the undo and redo stacks. - this._undoStack = []; - this._redoStack = []; - - this.addButton({ - title: 'undo', - icon: 'e/undo', - callback: this._undoHandler, - buttonName: 'undo', - keys: 90 - }); - - this.addButton({ - title: 'redo', - icon: 'e/redo', - callback: this._redoHandler, - buttonName: 'redo', - keys: 89 - }); - - // Enable the undo once everything has loaded. - this.get('host').on('pluginsloaded', function() { - // Adds the current value to the stack. - this._addToUndo(this._getHTML()); - this.get('host').on('atto:selectionchanged', this._changeListener, this); - }, this); - - this._updateButtonsStates(); - }, - - /** - * Adds an element to the redo stack. - * - * @method _addToRedo - * @private - * @param {String} html The HTML content to save. - */ - _addToRedo: function(html) { - this._redoStack.push(html); - }, - - /** - * Adds an element to the undo stack. - * - * @method _addToUndo - * @private - * @param {String} html The HTML content to save. - * @param {Boolean} [clearRedo=false] Whether or not we should clear the redo stack. - */ - _addToUndo: function(html, clearRedo) { - var last = this._undoStack[this._undoStack.length - 1]; - - if (typeof clearRedo === 'undefined') { - clearRedo = false; - } - - if (last !== html) { - this._undoStack.push(html); - if (clearRedo) { - this._redoStack = []; - } - } - - while (this._undoStack.length > this._maxUndos) { - this._undoStack.shift(); - } - }, - - /** - * Get the editor HTML. - * - * @method _getHTML - * @private - * @return {String} The HTML. - */ - _getHTML: function() { - return this.get('host').getCleanHTML(); - }, - - /** - * Get an element on the redo stack. - * - * @method _getRedo - * @private - * @return {String} The HTML to restore, or undefined. - */ - _getRedo: function() { - return this._redoStack.pop(); - }, - - /** - * Get an element on the undo stack. - * - * @method _getUndo - * @private - * @param {String} current The current HTML. - * @return {String} The HTML to restore. - */ - _getUndo: function(current) { - if (this._undoStack.length === 1) { - return this._undoStack[0]; - } - - var last = this._undoStack.pop(); - if (last === current) { - // Oops, the latest undo step is the current content, we should unstack once more. - // There is no need to do that in a loop as the same stack should never contain duplicates. - last = this._undoStack.pop(); - } - - // We always need to keep the first element of the stack. - if (this._undoStack.length === 0) { - this._addToUndo(last); - } - - return last; - }, - - /** - * Restore a value from a stack. - * - * @method _restoreValue - * @private - * @param {String} html The HTML to restore in the editor. - */ - _restoreValue: function(html) { - this.editor.setHTML(html); - // We always add the restored value to the stack, otherwise an event could think that - // the content has changed and clear the redo stack. - this._addToUndo(html); - }, - - /** - * Update the states of the buttons. - * - * @method _updateButtonsStates - * @private - */ - _updateButtonsStates: function() { - if (this._undoStack.length > 1) { - this.enableButtons('undo'); - } else { - this.disableButtons('undo'); - } - - if (this._redoStack.length > 0) { - this.enableButtons('redo'); - } else { - this.disableButtons('redo'); - } - }, - - /** - * Handle a click on undo - * - * @method _undoHandler - * @param {Event} The click event - * @private - */ - _undoHandler: function(e) { - e.preventDefault(); - var html = this._getHTML(), - undo = this._getUndo(html); - - // Edge case, but that could happen. We do nothing when the content equals the undo step. - if (html === undo) { - this._updateButtonsStates(); - return; - } - - // Restore the value. - this._restoreValue(undo); - - // Add to the redo stack. - this._addToRedo(html); - - // Update the button states. - this._updateButtonsStates(); - }, - - /** - * Handle a click on redo - * - * @method _redoHandler - * @param {Event} The click event - * @private - */ - _redoHandler: function(e) { - e.preventDefault(); - - // Don't do anything if redo stack is empty. - if (this._redoStack.length === 0) { - return; - } - - var html = this._getHTML(), - redo = this._getRedo(); - - // Edge case, but that could happen. We do nothing when the content equals the redo step. - if (html === redo) { - this._updateButtonsStates(); - return; - } - // Restore the value. - this._restoreValue(redo); - - // Update the button states. - this._updateButtonsStates(); - }, - - /** - * If we are significantly different from the last saved version, save a new version. - * - * @method _changeListener - * @param {EventFacade} The click event - * @private - */ - _changeListener: function(e) { - if (e.event && e.event.type.indexOf('key') !== -1) { - // These are the 4 arrow keys. - if ((e.event.keyCode !== 39) && - (e.event.keyCode !== 37) && - (e.event.keyCode !== 40) && - (e.event.keyCode !== 38)) { - // Skip this event type. We only want focus/mouse/arrow events. - return; - } - } - - this._addToUndo(this._getHTML(), true); - this._updateButtonsStates(); - } -}); diff --git a/lib/editor/atto/plugins/undo/yui/src/button/meta/button.json b/lib/editor/atto/plugins/undo/yui/src/button/meta/button.json deleted file mode 100644 index 520e0b82e20..00000000000 --- a/lib/editor/atto/plugins/undo/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_undo-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/plugins/unorderedlist/classes/privacy/provider.php b/lib/editor/atto/plugins/unorderedlist/classes/privacy/provider.php deleted file mode 100644 index 346d492921b..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/classes/privacy/provider.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Privacy Subsystem implementation for block_activity_modules. - * - * @package atto_unorderedlist - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace atto_unorderedlist\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy Subsystem for atto_unorderedlist implementing null_provider. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/lib/editor/atto/plugins/unorderedlist/lang/en/atto_unorderedlist.php b/lib/editor/atto/plugins/unorderedlist/lang/en/atto_unorderedlist.php deleted file mode 100644 index 178612c1647..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/lang/en/atto_unorderedlist.php +++ /dev/null @@ -1,26 +0,0 @@ -. - -/** - * Strings for component 'atto_unorderedlist', language 'en'. - * - * @package atto_unorderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['pluginname'] = 'Unordered list'; -$string['privacy:metadata'] = 'The atto_unorderedlist plugin does not store any personal data.'; diff --git a/lib/editor/atto/plugins/unorderedlist/tests/behat/unorderedlist.feature b/lib/editor/atto/plugins/unorderedlist/tests/behat/unorderedlist.feature deleted file mode 100644 index 16d4fe4a0dc..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/tests/behat/unorderedlist.feature +++ /dev/null @@ -1,18 +0,0 @@ -@editor @editor_atto @atto @atto_unorderedlist @_bug_phantomjs -Feature: Atto unordered list button - To format text in Atto, I need to use the unordered list button. - - @javascript - Scenario: Make a list from some text - Given I log in as "admin" - And I open my profile in edit mode - And I set the field "Description" to "Things, dogs, clogs, they're awesome
                          Rocks, clocks, and socks, they're awesome
                          Figs, and wigs, and twigs, that's awesome
                          Everything you see or think or say is awesome" - And I select the text in the "Description" Atto editor - When I click on "Unordered list" "button" - And I press "Update profile" - And I follow "Preferences" in the user menu - And I follow "Editor preferences" - And I set the field "Text editor" to "Plain text area" - And I press "Save changes" - And I click on "Edit profile" "link" in the "region-main" "region" - Then "//textarea[@id='id_description_editor'][starts-with(text(), '

                          • ') and contains(normalize-space(.), 'Things, dogs, clogs')]" "xpath_element" should exist diff --git a/lib/editor/atto/plugins/unorderedlist/version.php b/lib/editor/atto/plugins/unorderedlist/version.php deleted file mode 100644 index a2c8172f8d3..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package atto_unorderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'atto_unorderedlist'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-debug.js b/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-debug.js deleted file mode 100644 index db223b63dd7..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-debug.js +++ /dev/null @@ -1,49 +0,0 @@ -YUI.add('moodle-atto_unorderedlist-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_unorderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_unorderedlist-button - */ - -/** - * Atto text editor unorderedlist plugin. - * - * @namespace M.atto_unorderedlist - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_unorderedlist').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'insertUnorderedList', - icon: 'e/bullet_list', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'ul' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-min.js b/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-min.js deleted file mode 100644 index 66fa01c4459..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button-min.js +++ /dev/null @@ -1 +0,0 @@ -YUI.add("moodle-atto_unorderedlist-button",function(t,e){t.namespace("M.atto_unorderedlist").Button=t.Base.create("button",t.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addBasicButton({exec:"insertUnorderedList",icon:"e/bullet_list",tags:"ul"})}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button.js b/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button.js deleted file mode 100644 index db223b63dd7..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/yui/build/moodle-atto_unorderedlist-button/moodle-atto_unorderedlist-button.js +++ /dev/null @@ -1,49 +0,0 @@ -YUI.add('moodle-atto_unorderedlist-button', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_unorderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_unorderedlist-button - */ - -/** - * Atto text editor unorderedlist plugin. - * - * @namespace M.atto_unorderedlist - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_unorderedlist').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'insertUnorderedList', - icon: 'e/bullet_list', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'ul' - }); - } -}); - - -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/lib/editor/atto/plugins/unorderedlist/yui/src/button/build.json b/lib/editor/atto/plugins/unorderedlist/yui/src/button/build.json deleted file mode 100644 index eced221fea8..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/yui/src/button/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-atto_unorderedlist-button", - "builds": { - "moodle-atto_unorderedlist-button": { - "jsfiles": [ - "button.js" - ] - } - } -} diff --git a/lib/editor/atto/plugins/unorderedlist/yui/src/button/js/button.js b/lib/editor/atto/plugins/unorderedlist/yui/src/button/js/button.js deleted file mode 100644 index 7997bcba676..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/yui/src/button/js/button.js +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/* - * @package atto_unorderedlist - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * @module moodle-atto_unorderedlist-button - */ - -/** - * Atto text editor unorderedlist plugin. - * - * @namespace M.atto_unorderedlist - * @class button - * @extends M.editor_atto.EditorPlugin - */ - -Y.namespace('M.atto_unorderedlist').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { - initializer: function() { - this.addBasicButton({ - exec: 'insertUnorderedList', - icon: 'e/bullet_list', - - // Watch the following tags and add/remove highlighting as appropriate: - tags: 'ul' - }); - } -}); diff --git a/lib/editor/atto/plugins/unorderedlist/yui/src/button/meta/button.json b/lib/editor/atto/plugins/unorderedlist/yui/src/button/meta/button.json deleted file mode 100644 index e680e5494eb..00000000000 --- a/lib/editor/atto/plugins/unorderedlist/yui/src/button/meta/button.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "moodle-atto_unorderedlist-button": { - "requires": [ - "moodle-editor_atto-plugin" - ] - } -} diff --git a/lib/editor/atto/readme_moodle.txt b/lib/editor/atto/readme_moodle.txt deleted file mode 100644 index 9dd3bb960e6..00000000000 --- a/lib/editor/atto/readme_moodle.txt +++ /dev/null @@ -1,22 +0,0 @@ -Description of the import of libraries associated with the Atto editor. - - * Download the latest stable release from https://github.com/timdown/rangy/releases ("rangy-X.Z.Y" - rather than the "Source code" version) - * Delete all files in yui/src/rangy/js - * Copy the content of the 'currentrelease/uncompressed' folder into yui/src/rangy/js - * Patch out the AMD / module support from rangy (because we are loading it with YUI) - To do this - change the code start of each js file except rangy-core.js to look like (just delete the other lines): - -(function(factory, root) { - // No AMD or CommonJS support so we use the rangy property of root (probably the global variable) - factory(root.rangy); -})(function(rangy) { - - * rangy-core.js should look like this: - -(function(factory, root) { - // No AMD or CommonJS support so we place Rangy in (probably) the global variable - root.rangy = factory(); -})(function() { - - * Run shifter against yui/src/rangy diff --git a/lib/editor/atto/settings.php b/lib/editor/atto/settings.php deleted file mode 100644 index bcbe9a360d8..00000000000 --- a/lib/editor/atto/settings.php +++ /dev/null @@ -1,67 +0,0 @@ -. - -/** - * Atto admin settings - * - * @package editor_atto - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$ADMIN->add('editorsettings', new admin_category('editoratto', $editor->displayname, $editor->is_enabled() === false)); - -$settings = new admin_settingpage('editorsettingsatto', new lang_string('settings', 'editor_atto')); -if ($ADMIN->fulltree) { - require_once(__DIR__ . '/adminlib.php'); - $settings->add(new editor_atto_subplugins_setting()); - $name = new lang_string('toolbarconfig', 'editor_atto'); - $desc = new lang_string('toolbarconfig_desc', 'editor_atto'); - $default = 'collapse = collapse -style1 = title, bold, italic -list = unorderedlist, orderedlist, indent -links = link -files = emojipicker, image, media, recordrtc, managefiles, h5p -accessibility = accessibilitychecker, accessibilityhelper -style2 = underline, strike, subscript, superscript -align = align -insert = equation, charmap, table, clear -undo = undo -other = html'; - $setting = new editor_atto_toolbar_setting('editor_atto/toolbar', $name, $desc, $default); - - $settings->add($setting); -} - -$name = new lang_string('autosavefrequency', 'editor_atto'); -$desc = new lang_string('autosavefrequency_desc', 'editor_atto'); -$default = 60; -$setting = new admin_setting_configduration('editor_atto/autosavefrequency', $name, $desc, $default); -$settings->add($setting); - -$ADMIN->add('editoratto', $settings); - -foreach (core_plugin_manager::instance()->get_plugins_of_type('atto') as $plugin) { - /** @var \editor_atto\plugininfo\atto $plugin */ - $plugin->load_settings($ADMIN, 'editoratto', $hassiteconfig); -} - -// Required or the editor plugininfo will add this section twice. -unset($settings); -$settings = null; - diff --git a/lib/editor/atto/tests/behat/autosave.feature b/lib/editor/atto/tests/behat/autosave.feature deleted file mode 100644 index d0a3b249c7c..00000000000 --- a/lib/editor/atto/tests/behat/autosave.feature +++ /dev/null @@ -1,94 +0,0 @@ -@editor @editor_atto @atto -Feature: Atto Autosave - To reduce frustration, atto should save drafts of my work. - - Background: - Given the following "courses" exist: - | fullname | shortname | category | groupmode | - | Course 1 | C1 | 0 | 1 | - And the following "users" exist: - | username | firstname | lastname | email | - | teacher1 | Teacher | 1 | teacher1@example.com | - | teacher2 | Teacher | 2 | teacher2@example.com | - And the following "course enrolments" exist: - | user | course | role | - | teacher1 | C1 | editingteacher | - | teacher2 | C1 | editingteacher | - And I log in as "admin" - And I navigate to "Plugins > Text editors > Atto HTML editor > Atto toolbar settings" in site administration - And I set the field "Autosave frequency" to "3" - And I set the field with xpath "//select[@name='s_editor_atto_autosavefrequency[u]']" to "seconds" - And I click on "Save changes" "button" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - And I set the field "Course summary format" to "1" - And I click on "Save and display" "button" - And I log out - - @javascript - Scenario: Restore a draft - Given I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - And I set the field "Course summary" to "This is my draft" - # Wait for the autosave - And I wait "5" seconds - And I log out - When I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - # Wait for the autorestore - And I wait "2" seconds - Then I should see "This is my draft" - - @javascript - Scenario: Do not restore a draft if files have been modified - Given the following "user private file" exists: - | user | teacher2 | - | filepath | lib/editor/atto/tests/fixtures/moodle-logo.png | - And I am on the "Course 1" course page logged in as teacher1 - And I navigate to "Settings" in current page administration - And I set the field "Course summary" to "This is my draft" - # Wait for the autosave - And I wait "5" seconds - And I log out - And I am on the "Course 1" course page logged in as teacher2 - And I navigate to "Settings" in current page administration - And I set the field "Course summary" to "

                            Image test

                            " - And I select the text in the "Course summary" Atto editor - And I click on "Insert or edit image" "button" - And I click on "Browse repositories..." "button" - And I click on "Private files" "link" in the ".fp-repo-area" "css_element" - And I click on "moodle-logo.png" "link" - And I click on "Select this file" "button" - And I set the field "Describe this image" to "It's the Moodle" - # Wait for the page to "settle". - And I wait until the page is ready - And I click on "Save image" "button" - And I click on "Save and display" "button" - And I log out - When I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - Then I should not see "This is my draft" - - @javascript - Scenario: Do not restore a draft if text has been modified - Given I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - And I set the field "Course summary" to "This is my draft" - # Wait for the autosave - And I wait "5" seconds - And I log out - And I log in as "teacher2" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - And I set the field "Course summary" to "Modified text" - And I click on "Save and display" "button" - And I log out - When I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Settings" in current page administration - Then I should not see "This is my draft" - And I should see "Modified text" diff --git a/lib/editor/atto/tests/behat/behat_editor_atto.php b/lib/editor/atto/tests/behat/behat_editor_atto.php deleted file mode 100644 index c4969f09555..00000000000 --- a/lib/editor/atto/tests/behat/behat_editor_atto.php +++ /dev/null @@ -1,108 +0,0 @@ -. - -/** - * Atto custom steps definitions. - * - * @package editor_atto - * @category test - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use Behat\Behat\Hook\Scope\BeforeScenarioScope; - -// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. - -require_once(__DIR__ . '/../../../../behat/behat_base.php'); -require_once(__DIR__ . '/../../../../behat/classes/settable_editor.php'); - -/** - * Steps definitions to deal with the atto text editor - * - * @package editor_atto - * @category test - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class behat_editor_atto extends behat_base implements \core_behat\settable_editor { - - /** - * Set the value for the editor. - * - * @param string $editorid - * @param string $value - */ - public function set_editor_value(string $editorid, string $value): void { - $js = <<execute_script($js); - } - - /** - * Select the text in an Atto field. - * - * @Given /^I select the text in the "([^"]*)" Atto editor$/ - * @throws ElementNotFoundException Thrown by behat_base::find - * @param string $field - * @return void - */ - public function select_the_text_in_the_atto_editor($fieldlocator) { - if (!$this->running_javascript()) { - throw new coding_exception('Selecting text requires javascript.'); - } - // We delegate to behat_form_field class, it will - // guess the type properly. - $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this); - - if (!method_exists($field, 'select_text')) { - throw new coding_exception('Field does not support the select_text function.'); - } - $field->select_text(); - } - - /** - * Ensure that the Atto editor is used for all tests using the editor_atto, or atto_* tags. - * - * This ensures, whatever the default editor, that the Atto editor is used for these tests. - * - * @BeforeScenario - * @param BeforeScenarioScope $scope The Behat Scope - */ - public function set_default_editor_flag(BeforeScenarioScope $scope): void { - // This only applies to a scenario which matches the editor_atto, or an atto subplugin. - $callback = function (string $tag): bool { - return $tag === 'editor_atto' || substr($tag, 0, 5) === 'atto_'; - }; - - if (!self::scope_tags_match($scope, $callback)) { - return; - } - - $this->execute('behat_general::the_default_editor_is_set_to', ['atto']); - } -} diff --git a/lib/editor/atto/tests/behat/clean.feature b/lib/editor/atto/tests/behat/clean.feature deleted file mode 100644 index aea3fee77bd..00000000000 --- a/lib/editor/atto/tests/behat/clean.feature +++ /dev/null @@ -1,169 +0,0 @@ -@editor @editor_atto @atto @editor_moodleform -Feature: Atto HTML cleanup. - In order to test html cleaning functionality, I write in a HTML atto text field. - - @javascript - Scenario: Extra UL close and orphan LI items - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I set the field "Description" to multiline: - """ -
                          • A
                          • -
                          • B
                          • -

                        -
                          -
                        • C
                        • -
                        -
                      4. D
                      5. -
                      6. E
                      7. - """ - And I click on "HTML" "button" - Then the field "Description" matches multiline: - """ -
                        1. A
                        2. -
                        3. B
                        4. -
                        -
                          -
                        • C
                        • -
                        -
                        • D
                        • -
                        • E
                        - """ - - @javascript - Scenario: Missing LI close tags, extra closing OL, missing closing UL tag - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I set the field "Description" to multiline: - """ -
                          -
                        1. A
                        2. -
                        3. B -
                        -
                          -
                        • C -
                        • D
                        • -
                      - """ - And I click on "HTML" "button" - Then the field "Description" matches multiline: - """ -
                        -
                      1. A
                      2. -
                      3. B -
                      -
                        -
                      • C -
                      • D
                      - - """ - - @javascript - Scenario: Missing beginning OL tag, empty LI close tag - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I set the field "Description" to multiline: - """ -

                      Before

                      -
                    4. A
                    5. -
                    6. B
                    7. -
                    -

                    After

                    -
                      -
                        - C -
                      • D
                      • -
                      • E -
                      -
                      -

                      After 2

                      - """ - And I click on "HTML" "button" - Then the field "Description" matches multiline: - """ -

                      Before

                      -
                      1. A
                      2. -
                      3. B
                      4. -
                      -

                      After

                      -
                        -
                        • - C
                        • -
                        • D
                        • -
                        • E -
                        -
                      -

                      After 2

                      - """ - - @javascript - Scenario: Random close LI tag, extra LI open tag, missing OL tag - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I set the field "Description" to multiline: - """ -

                      Before

                        -
                          -
                        • A
                        • - B -
                        • C
                        • -
                            -
                          1. D
                          2. -
                          3. E -

                            After

                            - """ - And I click on "HTML" "button" - Then the field "Description" matches multiline: - """ -

                            Before

                            -
                              -
                            • A
                            • - B
                            • -
                            • C
                            -
                              -
                            1. D
                            - E -

                            After

                            - """ - - @javascript - Scenario: Missing opening LI tags, missing closing UL tag - Given I log in as "admin" - When I open my profile in edit mode - And I click on "Show more buttons" "button" - And I click on "HTML" "button" - And I set the field "Description" to multiline: - """ -
                          4. Before
                          5. -
                              -
                            • A
                            • - B -
                                - 1 -
                              -
                            • C -
                            • D
                            • -

                              After

                              - """ - And I click on "HTML" "button" - Then the field "Description" matches multiline: - """ -
                              • Before
                              -
                                -
                              • A
                              • - B
                              • -
                                1. - 1
                                2. -
                                -
                              • C -
                              • D
                              -

                              After

                              - """ diff --git a/lib/editor/atto/tests/behat/customtoolbar.feature b/lib/editor/atto/tests/behat/customtoolbar.feature deleted file mode 100644 index dfecd22fec9..00000000000 --- a/lib/editor/atto/tests/behat/customtoolbar.feature +++ /dev/null @@ -1,26 +0,0 @@ -@editor @editor_atto @atto -Feature: Atto editor with customised toolbar - In order to develop plugins that use Atto for specialised purposes - As a developer - I need to be able to configure Atto toolbar per-instance to include different plugins - - Background: - # Get to the fixture page. - Given the following "courses" exist: - | fullname | shortname | format | - | Course 1 | C1 | topics | - And the following "activities" exist: - | activity | name | intro | course | idnumber | - | label | L1 | FixtureLink | C1 | label1 | - When I log in as "admin" - And I am on "Course 1" course homepage - And I click on "FixtureLink" "link" in the "region-main" "region" - - @javascript - Scenario: Confirm that both editors have different toolbars but still function - Then ".atto_link_button" "css_element" should exist in the ".normaldiv" "css_element" - And ".atto_link_button" "css_element" should not exist in the ".specialdiv" "css_element" - And ".atto_bold_button" "css_element" should exist in the ".normaldiv" "css_element" - And ".atto_italic_button" "css_element" should exist in the ".normaldiv" "css_element" - And ".atto_bold_button" "css_element" should exist in the ".specialdiv" "css_element" - And ".atto_italic_button" "css_element" should exist in the ".specialdiv" "css_element" diff --git a/lib/editor/atto/tests/behat/direction.feature b/lib/editor/atto/tests/behat/direction.feature deleted file mode 100644 index 28f3e6e92c8..00000000000 --- a/lib/editor/atto/tests/behat/direction.feature +++ /dev/null @@ -1,49 +0,0 @@ -@editor @editor_atto @atto -Feature: Add text direction and alignment - In order to generate a content that can be displayed in the proper direction to everyone - As a user - I should see the Atto editor with explicit direction and alignment being set - - Background: - Given the following "user preferences" exist: - | user | preference | value | - | admin | htmleditor | atto | - And I log in as "admin" - And I navigate to "Plugins > Text editors > Atto HTML editor > Atto toolbar settings" in site administration - And I set the field "Toolbar config" to multiline: - """ - collapse = collapse - style1 = title, bold, italic - list = unorderedlist, orderedlist - links = link - files = image, media, recordrtc, managefiles, h5p - style2 = underline, strike, subscript, superscript - align = align,rtl - indent = indent - insert = equation, charmap, table, clear - undo = undo - accessibility = accessibilitychecker, accessibilityhelper - other = html - """ - And I press "Save changes" - And I log out - - @javascript - Scenario Outline: Atto should apply user's direction and alignment by default - Given the following "courses" exist: - | fullname | shortname | summary | summaryformat | - | Course 1 | C1 | | 1 | - And the following "language customisations" exist: - | component | stringid | value | - | | | | - And I log in as "admin" - And I am on "Course 1" course homepage - When I navigate to "Settings" in current page administration - And I press "Show more buttons" - And I press "HTML" - Then I should see "" - - Examples: - | component | stringid | localstring | partialtext | - | core_langconfig | thisdirection | ltr | dir=\"ltr\" style=\"text-align: left;\" | - | core_langconfig | thisdirection | rtl | dir=\"rtl\" style=\"text-align: right;\" | diff --git a/lib/editor/atto/tests/behat/disablecontrol.feature b/lib/editor/atto/tests/behat/disablecontrol.feature deleted file mode 100644 index b7a6678157e..00000000000 --- a/lib/editor/atto/tests/behat/disablecontrol.feature +++ /dev/null @@ -1,45 +0,0 @@ -@editor @editor_atto @atto @editor_moodleform -Feature: Atto with enable/disable function. - In order to test enable/disable function - I create a sample page to test this feature. - As a user - I need to enable/disable all buttons/plugins and content of editor if "enable/disable" feature enabled. - - Background: - Given the following "courses" exist: - | fullname | shortname | format | - | Course 1 | C1 | topics | - And the following "activities" exist: - | activity | name | intro | course | idnumber | - | label | L1 | Control Enable/Disable Atto | C1 | label1 | - And I log in as "admin" - And I am on "Course 1" course homepage - And I click on "Control Enable/Disable Atto" "link" in the "region-main" "region" - - @javascript - Scenario: Check disable Atto editor. - When I set the field "mycontrol" to "Disable" - Then the "disabled" attribute of "button.atto_collapse_button" "css_element" should be set - And the "disabled" attribute of "button.atto_title_button" "css_element" should be set - And the "disabled" attribute of "button.atto_bold_button" "css_element" should be set - And the "disabled" attribute of "button.atto_italic_button" "css_element" should be set - And the "disabled" attribute of "button.atto_unorderedlist_button_insertUnorderedList" "css_element" should be set - And the "disabled" attribute of "button.atto_orderedlist_button_insertOrderedList" "css_element" should be set - And the "disabled" attribute of "button.atto_link_button" "css_element" should be set - And the "disabled" attribute of "button.atto_link_button_unlink" "css_element" should be set - And the "disabled" attribute of "button.atto_image_button" "css_element" should be set - And the "contenteditable" attribute of "div#id_myeditoreditable" "css_element" should contain "false" - - @javascript - Scenario: Check enable Atto editor. - When I set the field "mycontrol" to "Enable" - Then the "disabled" attribute of "button.atto_collapse_button" "css_element" should not be set - And the "disabled" attribute of "button.atto_title_button" "css_element" should not be set - And the "disabled" attribute of "button.atto_bold_button" "css_element" should not be set - And the "disabled" attribute of "button.atto_italic_button" "css_element" should not be set - And the "disabled" attribute of "button.atto_unorderedlist_button_insertUnorderedList" "css_element" should not be set - And the "disabled" attribute of "button.atto_orderedlist_button_insertOrderedList" "css_element" should not be set - And the "disabled" attribute of "button.atto_link_button" "css_element" should not be set - And the "disabled" attribute of "button.atto_link_button_unlink" "css_element" should not be set - And the "disabled" attribute of "button.atto_image_button" "css_element" should not be set - And the "contenteditable" attribute of "div#id_myeditoreditable" "css_element" should contain "true" diff --git a/lib/editor/atto/tests/fixtures/custom_toolbar_example.php b/lib/editor/atto/tests/fixtures/custom_toolbar_example.php deleted file mode 100644 index 683c2f9bc6a..00000000000 --- a/lib/editor/atto/tests/fixtures/custom_toolbar_example.php +++ /dev/null @@ -1,86 +0,0 @@ -. - -/** - * Demonstrates use of Atto editor with overridden toolbar setting. - * - * This fixture is only used by the Behat test. - * - * @package editor_atto - * @copyright 2016 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -require(__DIR__ . '/../../../../../config.php'); -require_once($CFG->dirroot . '/lib/editor/atto/lib.php'); - -// Behat test fixture only. -defined('BEHAT_SITE_RUNNING') || die('Only available on Behat test server'); - -$PAGE->set_url('/lib/editor/atto/tests/fixtures/override_plugins_example.php'); -$PAGE->set_context(context_system::instance()); - -echo $OUTPUT->header(); - -// If this was sending some input, display it. -$normal = optional_param('normaleditor', '', PARAM_RAW); -$special = optional_param('specialeditor', '', PARAM_RAW); -if ($normal !== '' || $special !== '') { - echo html_writer::start_div('normalresult'); - echo s($normal); - echo html_writer::end_div(); - echo html_writer::start_div('specialresult'); - echo s($special); - echo html_writer::end_div(); -} else { - // Create a form. - echo html_writer::start_tag('form', array('method' => 'post', 'action' => 'custom_toolbar_example.php')); - echo html_writer::start_div(); - - // Basic editor options. - $options = array(); - $atto = new atto_texteditor(); - - // Normal Atto. - echo html_writer::start_div('normaldiv'); - echo $OUTPUT->heading('Normal Atto'); - echo html_writer::div(html_writer::tag('textarea', '', - array('id' => 'normaleditor', 'name' => 'normaleditor', 'rows' => 10))); - $atto->use_editor('normaleditor', $options); - echo html_writer::end_div(); - - // Second Atto with custom options. - echo html_writer::start_div('specialdiv'); - $options['atto:toolbar'] = <<heading('Special Atto'); - echo html_writer::div(html_writer::tag('textarea', '', - array('id' => 'specialeditor', 'name' => 'specialeditor', 'rows' => 10))); - $atto->use_editor('specialeditor', $options); - echo html_writer::end_div(); - - // Button to submit form. - echo html_writer::start_div('', array('style' => 'margin-top: 20px')); - echo html_writer::tag('button', 'Submit and see the HTML'); - echo html_writer::end_div(); - - echo html_writer::end_div(); - echo html_writer::end_tag('form'); -} - -echo $OUTPUT->footer(); diff --git a/lib/editor/atto/tests/fixtures/moodle-logo.mp4 b/lib/editor/atto/tests/fixtures/moodle-logo.mp4 deleted file mode 100644 index db475919fc8d966f8e4ee5f40daaebb872db534f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6930 zcmZ`-2|SeB`#Bw7Ew^q`DTWzKS;h>a#5KljdrZi>LV`k$I6!R%1p-!?!@2%GZ@OGhs_k8o#&vqL#j z8RS4%NO&Lw)R?fJM*r!y0sAkW7MsVB%1E1(Pmbn=qJLpzB|pkP6ykIIDE_a6NM&-R zNrR)b{nO@Olm~Fz?hs15wEbU+zv%yd(j*c%v4mEg5hsznq#I}j!LbAH@mVs27vWoB zaY)VJ0Zv(UjynQmf|~`rMyNyKviMv$N&{^VJB=UpGt?0NTvq`ArW8}*4x}lNHmN_- zt_5iUQUYwhXi)wqWe|z(Lb6U z#e(C;FwW0W%G3L2I$;U$SX{0&;{R$UA%E43VQEx^)Sxz-^;22uFz{r>1X|gcTH2a2 z=u(eJfjkZ@h?%8fPzqKJOIAiA+5Fmd;P(3t_dkvrx1$~Up9f>jtu0X#G$4YQ z!x*j@$l^!&a{1drxKQ+O1CdNTC(7Q$9E}R*K@GmWIT{)fv5gfBC%(UE43r-l z5&(VqMWCbMyq{|XgoLr8q<(~iM{#(eEGPu&{-M!4R-A7@L>QO#(<2xnc>aWhLlaPt z$CAnf@>pRUK1AC&Awj`WT!^-D;vn1J;urFT?=`f|58#Az0-~erE$PyAcr0m5cpQE( zRN)2q{>xvfA}_!`fES2{`NP0S{elx10aH2}DfPylZfXr7S8Dg?$cnYMUI+>NC=S=& z5)I+PD8r1xB*3*;kuZVMbN~zhwH=)F6oQ=|Mp*i1jSy(oN~VF5|GeU?TGe|UovMFH{*ZSfQC$ffL|nJ*ks_(X8Qlb@r*Zjgf_-Ier`Qyo79pT=ToeKl?m*`6>kX5DL$JkTw<-6S zl`B_Tly&QWo!c#`nZ(tM8fe!+1U7`s}F< z9$SwkAxCNCI;SsnO(zK*}BhN6KBRX3+31#uw~&!jk=Wg@&ai2!NUhQ(ub}`<(Mt+YU+smAgmsy%*mGHa9c#ZfSFUBbcp~jW3P=M- zLa!K3Cmf#jCA0Buz5`IBKl#mO<=QFb?Ka@S6|bxoKqAc0B3;aVHac8jAk+Q5Iw31<1w6`iF-CToMEZG`*vvt4UnkL5e^3~qR7y90v!o3@L9U2<@ZY|RP zA*6cPS1s;+mL&#*KMD>%YSDkOhI(+40C0FF=&M2jMFYq#0!sB$e5XubCxD>9gAI!V zG~#U`Ke0ihBgF+LsznrD1x`Mir%`AtR7H`t@!u)e*i zK`{{rFFp~Vs9EVj*Ngy3MrD(doav>;m!I`u7V*6=-Xtvkou`Z2qdn?a3iE!pQSr3Y>cljMWwfDLnC`yvt zqPn=JUh$NSwIot!Zru%(^wyRiCS`0-Ie3JLpOYcDxuwow-Js`ftrPbN4y-+2yBx157is04c(aoIctcH*u5+)4(W+emn?~*}Hn`DXt!w80EQ80kz0UR(xk1h3=?<`7G1;kSC{Q7>VI)-XTx%E{{rgz=Q`g@pBEnj>w3k% zit&QV*I}=El#&@V7NSDAV(ro-iML>apr*hb24VOu{_FI6vNE^Sw;0j?%k^wfyo58O%t zGMH$Xi-8g&7G}2@z4XQD=2xypSM z_qEX_?Rna5BBUd;5}zQp8s;brfej`%R_?d&qxx>tQ_=LWxRoVg8ojdFIkv zyL-`f#~EdKjG%R|IW}lgzE>loz~jfO*f&4sJ?g6t2e=id=U7b~dQOVGGMus|y~?mN zY4w>FKedlV0+_K45W81#+koz`D$)<#Eabln;1V!hF=$+KF*mk7}9 z{-c+Y>C5&#LL8iOWWHm_z{B(OcJ{_j2c-DbI}%Y|@lp$u_WHK>DZzl_!L;%TP#c*x z%G`sG5zJC{I(**FY|0oF8hWnPuUP*zCSz+O<+fSb2Vx0bsq5P1snk=-+nDfO2?2;V z6JDyTL5qT|i-VY8NuEYfcW$?4X&r_yy>e}W3IP+<<|c6xVMHR z1?9G7*x$92pLZ^9eN!MZIh#hDzPFQ6E92Rnd-+U)a<;$^p!0zd22f*=?Wbp4Rp%%3 z+zuu9hf|Obk>3d>ti8kK2zwiebjAmju@YU?KQ?ZgI4-zc;43M5GmS{Bwd}g&--+>O zD7Z6xH&u@D;upzZ=YZoIL~E8(ua=d+8ol~biGVG&oV~a4{`XZ~@R~%JM0GKYoIH|h zZAxfqyxu?>sIQUC6r0u-TDHoke{=T!o!Inb**l#-gttVkjX&@@OuhJ=1JA&~j7Y6~ z3%j6qx*JDM;62rjw|f<5{`PQ?I1S|XP>UT^PChHp70XfCX4WmGY6grNnW5(EGnCvU zhojZ*7`a4D*Otscy^0!G;H=KjyVf-@JS%(q+UU zzmsY*L5U4X#%C2sUm&DcQ7Wah`;tS&T+qsWjiPW>om(8|I*R$-0Jbup@Q*XSQry>-&YgZw z$2%0X%T69MA3t-*(yiHhT;e*tk5GrEePBBGe9LD%_I=3G(BBLY0q$v9mS0Z?r^=3dLfvixKvRis`*iMzig(>qo3*?BYA98coPu>xb38!oq-`6l)&!hzf0!2`g`aMPypR;6OB}(D5 zb}cjd7>jFI{2b|RRO;E?6hj@G9R2YJ1_XVwk2^Rg&YzY@FUoX4RYl<`E{{=InOaW^ zXRAe7i(0p$l+uUWz8xp@3=YV9S6q?Boy+x57RogYV&`^g&U!chmFd%==of8Et}qG? z2}>P4LIpG9Yu(EiEUtc;x|y84RP2O;3b8@)dciMudZL-`oVVR#P`#u=c|StRH6VKg1>&2_HX>YEC8AxAUaGtT7D^n{2Z~)a37W zeK}TL{GM3L0K2MYI9Hz@W=!cmjLB~k!k=42$V*+G$<@j-CJZ^i9bL@?@dUouYyD9_ z2Yk)6K%6&E6qHgYyZVo-1GNS>)Jm*Qka0KIytU_*$$y@E_vaa2i#8w&QD6-m$2Y}& zIO%<_6*%j^irhCDw;daCnx~L|zxRVALG%^5JaA}^qq4%w!Q0mjM@#oaP5}iNNLYyg zi$zP|`63IC8o?QpLmTQIX|Z}gyoH88*?O}$y}NKL{4xt+tZxOi>7qAP5_MW{`Ed*{}tbDXC& z_50g->=N4XuszF{b9b2>QrIDrX^@^bK4mKlmH>s_4sGQth!kzNTbP`y+NR*s^U>eR zHyfMf2a@~N&Db8Ys!Jk&;KD^5;L#RnV=cxQyf! zv7HvAhV7o7#y~6)f28T$j3!U?pqjIy0Y~$!huZO)ZSBV@b1cwB%3T=_;_@Ns$36mW zKbqHCD?M{Txhe_B?S?@>HOaUOgfowI29Yr@;0J(QLygl8w>P7tU@uIsn#&9>RIpq4>; zPI63`(<=CsOqOxeo0XcgQ$gdJSC86(qJ6I6MH882dTBboKV&atH`Y{`Np~!yS!Tji z5dgQ4-RaE*bod6$_uXTU$B<0G1(gYUHzoa6@Sky%3R%kcD&m1I9V|m#g(K-XtqEeb zmb6qN17S%6SxT@i&;)o)@mL-G?vBty3s-cWtEO>*F*F)gJ)5%Eh3ZdIxqG;-WNdnt zA_bTsBv$Ok6KhN#4^G~ZdE=OR&8MxD;815g4&JGk5RX46neZGYt8LyE6{=Yyh_puyTmhfy^w2N($}tnAS1&t&dgliN~h7AV-BF zXtt{em1s(c-+U!4!I(n3?i=N~S0_6uH3pQA_v1@Hox+m=#Xr#a1tZ~}iNQGr3&2EE zF*kM1y5Xwfl71Co=u#Oi*A7Hi2=IyVuh@3@6U)C0+K9P?FYZZW&oT(f5MY?_R^HqQ?pio z?}U#jdfGI`Ty-ub`LV9Vv8w2F14fPo0CQcF-_-HoZdmF}MNFN70~&sQ zWL1*24tOwxy-Y&j;@QvR70}G*XtWLP-Fjy zw=-O&Rj_9HplF`(xA^Rjr>kH5b}tRwah^`z>|RY~I<0(K@v;PZiWw0UrPl-i-OA}2 zWhAfw01@8o?6^%_Iru09LR`S$QGG}uT2;+T>pxjcoj=od_L)@kvMq@05IX0YfFm7GBziY@^WA23u@CMj~-ky`}byvsZ`yzpV|^iHeqKQ2?ID?bcx z84o@~ZkYSgFDUNh$yUdwL%q5(bx)cGt*7Un3LhWZ{PkOEF*>z*Q-hrf1 zmYY{m>tCKfNgN&=YS@;oTBQEr?CHpY4XOGE9qc|Yi6nQmtCua|8O|d+=iN74P?y-3 z9Xa#;$`!+}UT&w2X)62H9mX`A^dgQbS2(6rUFaeQfu)8QgxeEjyxzUCjEEI_k@z4HL&)KZn}rE}WkdHdY4KRDv%v>F^4;81x;^ma0vMW=fj^t!!f1k|k}wy*tVGzCAq>$G&goeDd9CcW?Lm?f1Bc zFd+n4Vo5b*YR?*8nMmnRX(fCfZo2z;fIIf_)pUJCyuYN2q;x!T{%8cxrE{#ahS`$Z z2rmCHY_13k7)#~}D_E-ZSRWLO@ti+33m8kP#|dVD#;ldGfU#u3cw$D-s2n@jt&9bX zCDrEzo3Ipmu9+3XSh8@#eQXTU+z(+aU@WN(DVp(&Su0}!W68pcVN6(*Ic{YvU@WN_ zG`L*Q=CGBqfU%^u?94MOV*z8y*>}hA+y|v74RfIpmn{E+2UdRJUZOy2TYFEF%at7d zW9%MF3(rAli1f2~Q(5IKL||60>h=~$!AlAS3WgUJy7s{06Cc;LbSbjg>~9{49sZ7` zee)Eg;s#8VP|Q(KY6{F%SFZII3VDA%U+}{^Kp}z6ZoTi=Y&O)nWJxxc%WVT#9!hV|^Tv!A0C4VE znTmk9?wi*I^Z8sbm*XIDo6b1Y*Q1WEF6bZp=fg+d_==@)^Ut!#t&E{Xnd6UVnFi*@ z@80O0$<2gwGr5o$66#VR8%Cc`OfZ#WcQ{aMdq*~#$!vV{=$p@3+O|Nf3}Uo0=Q=Q< z4Sj)`nVEk0*el-N(U?Q4T$9M{UWBG{1iiw*i+gb^a=M%!O;1f-`O7M0#L&6k;`Va)o0MfjVW|ta~c&21#~J~kB*(Tq4z(WK@h{}UY)J0t3&PQ zEg=BPpAH{6+-qsq0HCp#gkP-6v?d?Nj7v%%YQ72O6DjLa~V! zl*{E1#4xbV!(ll?7tFnQF*^0}KXEpjy>`{b7oVER<-hTM^24~+chW!Y3BZbG*gVjY zURZktAmi|V3f3uD$D8gx9;;@jOz-p2I{CW!dS|@{{u6C;68?$VZ%f3hJt&!H{GL+% z{8}z4p$&A2*>8!bs#^ckT>Vft2}qu~Fa1HZzvGULiB!c_rpj(vdUuaUXgBRUFCoJC z&Aul9`i!Jt9dm6PGp#pR{t}FV9S;Q>rYCkSn>u+-$INHQR>+`Z`F8Z~v>Sn?K{;3; zhJkfX0t{W}xi!BO3UpoI)-7((_c{!)e9XP*pt#i6*O9MZ>V9?aYwz4pI^l(?E zF$in7IJ+XTUec?>y`zD-Va*|XPy z{?S<>A_qkQjNWY(7!AXpP*eC=(gZA2N&C4ZhR*FBiY$-hes<`57%=;-@kkkM6?{bzp=3qO;1mA|5F8j@%iUDxCkk5`>D`1-A`kh@YgOt88diEUF92&)0xe!4%N-njq?17qw$~rM;C+X#tjyV4>Wqu8nGAl(WA` zD7ZmZYXkNBse7WRpQzVE)b^8-mD?cQF8Aj|!2E0tb(@Z;Dlr2v=|?%M66GLQz#wb0 zc)K<*T;IXwQ1if8R2P`v{Pq>kw+?R&x9t0%U%Yek<}DtuDt@trd2e*&V6)rp#hiuU z-zAj?Yf{J;N>EUksDzi&F%PuCMA@jt+eJ-@HC(yIbV|Q{1)=powY20*ZpM zPs^gnKQjVDB>~$4Ml-zt%RzNe%wFbJz|#lyM+{*>=v~#=!HkvB{Y+GWnFe5p92gb1 zObr--h4(}VpNKLAObHxSV2WSs185?;F4@GU75#Ex)TH~;RU_>k9o<+MP-=rofy~0e zfl`DhF9D_q3SD=vT!x;x=2PTs$V;bhBUto+!3yoBmd4w3*Rhl;EC^s>xx*Hlf~B}U zK?8OzXjEY_0)-`jmd2#lL;X=5H!xnZEG*FIyJgDHtib5RF>+w09$QWCKa6v6rYb0m zz!dkZ14F-bee;eJioP>_d%wf(u-R;O)M&Gz25`UV14t*E`T19f(Fq1LuGw5X*8 zIh&fmeQS^?dhv75N-x^Ib^k_ZL57(SCV3v)dv97-|wlW!#-n<~UTd{3v3-^@=8B_Q0}*T3q4tNyd62r?;*0 zn!XMrmqm+Q9tsIv+B!Or-EK$ebQ(>;l7ZMoJaF{@43_}F1r8P(vjlt>p@G$>kgLHo zEQf>{5eeyD)=W|{py#d2UhthU_}c7)J}#;k38`LIMcV)htCqcrC}Gh}C?tebGU8I~ z6hxayKUyvX!E487LOEYG#xqx*En@Ego zao#_wHerP)cXmTL7<7W@j3b79MA3Jqf$8k*Y;HeqDQau)K+{uG0L!HA@f4E!hI-WA z+L2k@);{p4f9$Bq*^SN!!KQnTORjfJJ+a!)#~?c8@H*wD=HGFb5X)fH&sZ;)^>W;v zh^Snr-~)B67pP0%@MC!LP!0=MKWu{~K#x%bSXk9^^^1VjzMC8?CaQoO7RmT-Lb;dg-E8|adB0=cvQL7jL4UDT98 zE8GNK+TMt+xWIY(f@R);CFfso`Rjjpz4eusU)uWOuU|-Mx+FR?9KfQP9tCJ3rNLs$ zEQJh*i{BguWzfBX4~i5Q29ZSrf}%j%r}_nH;vxY+7!Ibr500Vk8pcNNGwv0|GC|gf ziX}BJ^i!~6DvXZ{$zx$PZ^U`;2=ip@+Qy}ihYi|6t&CUAC0jYMX@$3C-v>#firN~p z=<3GL(AD^}(g0y32||DA+CHY)aOVS~sq{~}6AC|CDJ<6#;#yWiI^voU}y7T^`FST{=_M9UcSXsv(|eoKZ)@6r$V1Qe-b zqvVw~eBb>4du&Ae_ z{KCCzEZMAB8RHN)J>Kkk;$_Sm9AwrzV(J*bB!&T3%&)3c3sAtlNSZlb@bg)Me~+*r zgZB=l%222zMw09rV)~g0?Q@FPy5CGf!x*z^r(b8U>U(O^_h)r{=8tl4z_jf9 zAdW1lM0^a##F_m3s#y8T6f|?d@3DqdUBp3uf^p!_Rbh$^rl0cpjjqASl&jiqY&rhA ztPMo#{8`T{fJ|n}pxmVg1>( zd=YMg8n3JkRd&fBj)_fdT5%R$d2~iiQ+dm>dJkK?%YJ)`jlhU;ATd+~MN)vmd_`n!VVSKr!#Rc+V4?kRutwu$RyQf= zQSL=5>_R7o?c#;dHIZx!7h{+@l^OHQD>u>TyeiLF5XaD&XNa-vC#U!OV)WS$2`Eqd zgRs!q?n%aKhX9nMWPsEj<1IZlTe_FS2TKy53B%%@1!b)lmVOEp;=xkRhRR@gP!vn0 zbjMj*#zBClUwG}3bi&y0^V0q?(GL}kXVVXkQ_xvFAR33q(z|G)}u2o z)Z!gsgeIQe-A&&n6LH=@S~~y9UEM*!1!MINhMRYu7*q@T%QT~NIzD`&H^!_JOghvw?%0cU9JtYK)7? z$T z3PA!;nL0E?WHm%!NFkBAaY|UAY@(T>7TPvoc<$tEkCqIYdya>pABLD*_{!SOJwyoB zB{jc*A?57@XlM}GSEFGze8mwr%M%S~BmjxwKvIY#Z$6R3f&$=*r3~88UyA7}?R!!s z4}{@x=hl&sq}|nzeQE!Bn|GX0T#u_e<5R>O636$s2gTMIWsL~?z|iMX))~Q~0?i>w znQ|CpmPWE25jiY-zzy@ml45K_NSHXrD;RA0-RsY!%@Lp(s9Ig5bRGlE17rT?9b>Bf zH$Q(xnV5ox`o;8livd-oVJmA~7(Bn3Cl!m(fF%IeiL8@kfh1WojfF_wtwk@&t^-g^ zU%cZ0=L7j678i#|&zpY7@7R=xnjRBU*%&&1$UTmHIWo8)O^kPz&cijJ{iLuWOU5X1 zwMvQf@rxvbQj2bh*GxGj8QPQ7>oB3@qyaQ^HtC<<=NsgLVZyx#y;r-yQhN_^uPenU z%KBX2E2nG= z7)vZMA$3+4SYn9z*u651&k$@Sio3fi3N-$mRP`8U0{hN7BH4rQWN>V00RJ^ WSS*Y=W-Lem0000^k2$yS}x)wL{fjEUNQpFzC<50gpn0;U~YI zeIz0L07(K5i|}`}cZWwKA@E2fgvl`U;a@`;B&oGCpD5nau8%c*7eTLH>|}^V&TH4l z{fZcjO5F^xVc=gse}`;_^}j=gYukULVEzL8|K0yC>2JPD0+S!Yp>Rd*&{!=yKPT}! zLZTu`#ydU6=`B)q9+xO1amKkN62RMf)@TBOH_{Rt3%3jC|CLZ^@Zka9SK6~ zwj)8HP+=ud7FeJUBo6`+lSD?wq({U+AOunq#0yYMF~T*4nC1qXS-jyUv?pW}&;tf9 zw~})U&%s;wM}eY{uLuhOI0`?_*=ufTex(qHz?_HTlMvh&R`^o@_(m|RyE(Z++`_TM z(c9byL|(3)s^Srs4yX5V{M{U%p`IKo^8<|{^3MUUMkJ5`m>&8A&o2j0fDM}?0B`ye zm{-WVy*@voFclIQ3k_A4A2c!0`mA({QUVm0EExe11b2j^Rh#- z3-r&_6OQi+wTKl309ZQ*AApZ3FRjk^*Q-|>`*Q|adoFd}XYUydzvwudc@hwHm99@7 z0}ZiPRH%w=)O~s_m5|4|YptCzESI<9$QvuaV9ugRq>ZXr!0+!NGeovDi!*ul}%@mSB7mcu3)TiujiqA+keVz7n5nJu15irBm!- zW%66E+wI;J^dzvga?RM=wJ`6^9+u+HD&@5AO}FYhH@pxw3)vv8-eRpB|JfJ;TdE1! z@u_Ge0O0}j+zmOSYP-oCiKHF+dPCM2lkIwpFK@uXO%FP*ArY^cRuxOuvm_oYe9?2_rZ~l|Dy!pZbK`sMuM>Xnf1E$pk-+Iw%wh!)00>x zdh$gH__)r@COg3k&$>sIID4nBmFi47Hhcr8xb}u6lNU7ypE|CQeiaxtW%ol{mR%I& zKJ3cYtFw&i+zZ1}m)#_iFo3O+T|o0GKZteBecb?Nq_c_k4Ztq`J5Th}T(^^HD7>vs zUjJ~z@Jpy}pjf)m_eZAzsARsSiTh&sUAM{bC;V)$$PtgV;roI$$~xzxb#^8~*2L&& z(?_lwc~>u2-W{R;ILee^i=3C!mZf~%-qxkw-OCQ(OtMZtG9&YwV0j1kI zn62PHP7>7Y%O56KI@}SmAT)CM97V)pBy_0)earomV|8cw@XC%?guXbD@rEkno86^G=! zK3GHX)zZXSh0n}%C@g=}YA`BrxVPr(J6?C|SkHJ-#T)cLZIM!qr2>7*9|vXmMU7vu zr`zNq5;cWSm<_&FQ^~!VzuUBXsu;(bDBj9&=HC{Vy7W$lBy|rXdt&qy51lHw6ZW`{ zgo3Q=z4uXr8aLz}-iqzf2CZDkz8ZCU14U6){G3+9J4ar)WWg+3o3NY6y#sgp{%F!w z5{QNIoh;kbePxlNQ#zggH3DiI#SfBhAl`yTE6d@s*`J~+eBrEmu`^X?CSR85{3XE- zBE*m!=5c8DYrhXk*^udpN&4!H&wevkT|7<;fi3F0n?8Zh1B4u2S>vX%qsM9uZW=!u z5i})Xd3M&aL=;qjz{cFBKvWy{DEB$#&dbDHm|I#3srK1>_(~X!9K#G}H*WOwWge*a zZ+bs-rX?V?2D&ZChM(k}Ny)pEjZC_VR%_GYZl#NO->|TpOCr5t%Zpg)76O@G*-X3( zMUOsXxaMsEd*MYiQJf;qYr#Fj>ZS71gyqbVqQZfI62&1d{CG8 z^lB$9F-%NVuvx}Voip2VPq-tw(y4P;?8;u3;G#yb;-azg8Dd~Ruw{z%kK`YLyKi!G zjkg>0S4UggYQmos3EHNJmz#C&rZ~m@0F+YUJ zX*EzYB0564^HsY**#id7_4d%99Rh~OM@(*vN52lpH_Lg=rBOmmh8=&PjIgFH(q7@f zQU*82frh6mA+708c$lEJuBo@R6{AT-nEt_oHY`=atLIG@Y@ulLKKTj73ZN+7;iG2W zw2=hl5RcAQ+p^9qS}VWyqlC@;po#p)oTwVCb!2`A1AM<9a`djdN?7>$5Wj0??*sqw z2&%WLj+0g<(N6aA*X)%ZAFDcDTCkNflF75~39L{ED^GHqCKzTkNUPDfW^Tmy<$2|M z@hc~N$?q!Eof>_bEwdLoE`^YR^cUga<^^n4cSnFl;lL4@Gk}DY{4)PxsMd$)5>8zW~&P? zWXyKg3EBI5fCx>@`uTMo-RBuoR5PDy$3hxBucRUW1BE-Tu$HM4S^vbY79F%tq}J}vQ(IP)5e#(-3O z!}@+W38&{Rz{O|pDh>v@;b{RDRm8@Uzjb7U?tR8ZJeU0g2W>M={U9(Mx;#$>&eONT zLdzLXpH|iHMp$xq9j%bp>ILLAT~7cc7WHNW>zc@79zOj1>~d%p<>{14uYP7lOZQP< zOJP^sqciu4>c+n;myMjN5&h zG8j6Yg&%hYi@HeTr8oRyu`yPw8&uxhz)=2eP+YV2x^$Ycpg+ zs!+6Hl_tB|WEyu(9E4!!9**1w%npI!kxe*HhF#Y!#ILQwUip^OGN>dsXI28(Ua${u zY}DO++Ah_XA0?X8$LQiw+fUJ8NJ@7X)jO~>nv=KxN$)9pu#KXuHcNAv(M#m}5f8R~>Lv@&g@smcz zSJ>+0F}UO&jAE5IFX!w*!0z=~9olHYqwMmI*S>c|mpTqse3m8kP!#w+gEpqNMG379 zf`G5y`%BLU`RV!fHDXWM8$WVH0^PdvM_eC7uo zp)M`QH7%my_p)qVNmpb$g5GGy*FKb^D|y!5HaFjpaAGhC*-JJ_^Dq_6G`BSiN!#%}fIl@0I#x-$XZ~Il zJFEI7Sp7&!MuK^f5<9{tlV_yqem!6d+tUz{gDA%3%!I_Jx{5FfNG877L`DRmn^y~M zyd-I?e(V^RRFsT&E#K34mS)^Y?A8F-(~$d39~@|fp^P87Evk`D`e-*Wzf{#?IiJuH z8vEhGy`GJq`;@}_?A=!*sZ0f~#@ya)6K#F&lJLZr`YtlE zi)zQh!V_g*kKDkPa66s;`t!wv@rUT;jcNYQ?W4j01j~;VQ(xV4g4~IR3vq79akmmH z@^W4t4d!&CZv?ib+AX+y`EI<(o8-FuOK|p-VzkaJ=A76K$j2xaUOXia$&Aznk~_Iy zI3|1VBra3zI+ku^ni{E;lCVAqW1Z7#sSahcpoZ}JJy)6K-mQ~eCpqkWwmtlv&>%=L zcLL`-2&%Pw#H?gk!XpWLg-IS@RErv0>wo{2<eoVmnZq+SRF3&sFExPA7b%;Jk1`AeSK*<_kByTT0OFy3S>to%V9MI6&0!a6z`5 zO-XI{4Y^|z%9`dQaYM(#@S-Am4vQj9J7+4^DWkE^V!&8IKARIR)JN}IW0mX;2z0Zl z-UZr8%F!4e7mtzMY2As;Ot+dk>~>}`wsRM9ZpIwk^4m35{h1wQLUp?*CUWP?%Fc88 zok>U=xLirAo&NsyB)^fVh!*xea(H>p9ba!xW;?<4*Av~yb#^HDRdsBP0)0G5t3o~N z%+B)hIWSB`V)(Ms&+h$|-n^_i$dm(ERU`3xnn5j*)AhaYEZk1E3x6C*nk!lg4t=|| zPUl|YVz&oAo$0&enbXhojO`xGzOKWgc?i=wc9#nk^io7tMJ{D0EgLkKs;AR9=!bIW zhumo4XugT_5WTaRIJoX2d+5Tsn;e9a)=Q}GyGp9}Y4m;K@o;!q2Eno^n5^SHZ67@N$V>1`xn1L1?9DB*6yAix>o=q5`p(S_ck&XXYf= zw-OU5+G0I^0uP!~7db!x$FB!RJ>HI`+srze_ z={K5_6sB%?}Q#b|3XI!V!r%&`esWrIx?^N_{n0OG9E@rNI9A?^+an7F9Sd6P~T_FaJ;AG zEMD(@Rs=#T<{*iOKwboY&BXWxqCFM=re6ssCtT7n=WWu7^(#p1My2U%!Cww1o_inn zX306QdUK7QBSOr>y3_YNUk2ht+S)ly$bhAgw#d+W9WtVC^(FpR%IAfiGq;$Sgc2V6 zkhM7#QjD@cd3XU#r?8{e*5cv1)NyCXvY|7lT}cb1byu!5l1nV=uvZ{;sz?DOX0vtQ zq9E9$eS8dro=1|^fQBJ|5@Z7L&^l(RaTQ2V Ob@VS+`9~Po=idO8ZlC1< diff --git a/lib/editor/atto/tests/fixtures/pretty-good-en.vtt b/lib/editor/atto/tests/fixtures/pretty-good-en.vtt deleted file mode 100644 index 6898d3efdef..00000000000 --- a/lib/editor/atto/tests/fixtures/pretty-good-en.vtt +++ /dev/null @@ -1,54 +0,0 @@ -WEBVTT - -1 -00:00:00.530 --> 00:00:00.620 -Hey! - -2 -00:00:00.620 --> 00:00:00.710 -Heey! - -3 -00:00:00.710 --> 00:00:00.800 -Heeey! - -4 -00:00:00.800 --> 00:00:00.890 -Heeeey! - -5 -00:00:00.890 --> 00:00:00.980 -Heeeeey! - -6 -00:00:00.980 --> 00:00:01.070 -Heeeeeey! - -7 -00:00:01.070 --> 00:00:01.160 -Heeeeeeey! - -8 -00:00:01.160 --> 00:00:01.250 -Heeeeeeeey! - -9 -00:00:01.250 --> 00:00:01.340 -Heeeeeeeey! - -1 -00:00:01.340 --> 00:00:01.430 -Heeeeeeeeey! - -1 -00:00:01.430 --> 00:00:01.510 -That's - -1 -00:00:01.510 --> 00:00:01.770 -Pretty - -1 -00:00:01.770 --> 00:00:03.970 -Good! - diff --git a/lib/editor/atto/tests/fixtures/pretty-good-sv.vtt b/lib/editor/atto/tests/fixtures/pretty-good-sv.vtt deleted file mode 100644 index 32c8f367f1c..00000000000 --- a/lib/editor/atto/tests/fixtures/pretty-good-sv.vtt +++ /dev/null @@ -1,54 +0,0 @@ -WEBVTT - -1 -00:00:00.530 --> 00:00:00.620 -Hej! - -2 -00:00:00.620 --> 00:00:00.710 -Heej! - -3 -00:00:00.710 --> 00:00:00.800 -Heeej! - -4 -00:00:00.800 --> 00:00:00.890 -Heeeej! - -5 -00:00:00.890 --> 00:00:00.980 -Heeeeej! - -6 -00:00:00.980 --> 00:00:01.070 -Heeeeeej! - -7 -00:00:01.070 --> 00:00:01.160 -Heeeeeeej! - -8 -00:00:01.160 --> 00:00:01.250 -Heeeeeeeej! - -9 -00:00:01.250 --> 00:00:01.340 -Heeeeeeeej! - -1 -00:00:01.340 --> 00:00:01.430 -Heeeeeeeeej! - -1 -00:00:01.430 --> 00:00:01.510 -Det är - -1 -00:00:01.510 --> 00:00:01.770 -Ganska - -1 -00:00:01.770 --> 00:00:03.970 -Bra! - diff --git a/lib/editor/atto/tests/privacy/provider_test.php b/lib/editor/atto/tests/privacy/provider_test.php deleted file mode 100644 index 61f7fa8207b..00000000000 --- a/lib/editor/atto/tests/privacy/provider_test.php +++ /dev/null @@ -1,655 +0,0 @@ -. - -/** - * Unit tests for the editor_atto implementation of the privacy API. - * - * @package editor_atto - * @category test - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace editor_atto\privacy; - -defined('MOODLE_INTERNAL') || die(); - -use core_privacy\local\request\writer; -use core_privacy\local\request\approved_contextlist; -use editor_atto\privacy\provider; -use core_privacy\local\request\approved_userlist; - -/** - * Unit tests for the editor_atto implementation of the privacy API. - * - * @copyright 2018 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class provider_test extends \core_privacy\tests\provider_testcase { - /** - * One test to check fetch and export of all drafts. - */ - public function test_fetch_and_exports_drafts(): void { - global $USER; - $this->resetAfterTest(); - - // Create editor drafts in: - // - the system; and - // - a course; and - // - current user context; and - // - another user. - - $systemcontext = \context_system::instance(); - $course = $this->getDataGenerator()->create_course(); - $coursecontext = \context_course::instance($course->id); - - $usercontextids = []; - $user = $this->getDataGenerator()->create_user(); - $this->setUser($user); - - $usercontext = \context_user::instance($user->id); - $usercontextids[] = $usercontext->id; - $usercontextids[] = $systemcontext->id; - $usercontextids[] = $coursecontext->id; - - // Add a fake inline image to the original post. - - $userdraftintro = $this->create_editor_draft($usercontext, $user->id, - 'id_user_intro', 'text for test user at own context'); - $userdraftdescription = $this->create_editor_draft($usercontext, $user->id, - 'id_user_description', 'text for test user at own context'); - $systemuserdraftintro = $this->create_editor_draft($systemcontext, $user->id, - 'id_system_intro', 'text for test user at system context', 2); - $systemuserdraftdescription = $this->create_editor_draft($systemcontext, $user->id, - 'id_system_description', 'text for test user at system context', 4); - $coursedraftintro = $this->create_editor_draft($coursecontext, $user->id, - 'id_course_intro', 'text for test user at course context'); - $coursedraftdescription = $this->create_editor_draft($coursecontext, $user->id, - 'id_course_description', 'text for test user at course context'); - - // Create some data as the other user too. - $otherusercontextids = []; - $otheruser = $this->getDataGenerator()->create_user(); - $this->setUser($otheruser); - - $otherusercontext = \context_user::instance($otheruser->id); - $otherusercontextids[] = $otherusercontext->id; - $otherusercontextids[] = $systemcontext->id; - $otherusercontextids[] = $coursecontext->id; - - $otheruserdraftintro = $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_intro', 'text for other user at own context'); - $otheruserdraftdescription = $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_description', 'text for other user at own context'); - $systemotheruserdraftintro = $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_intro', 'text for other user at system context'); - $systemotheruserdraftdescription = $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_description', 'text for other user at system context'); - $courseotheruserdraftintro = $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_intro', 'text for other user at course context'); - $courseotheruserdraftdescription = $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_description', 'text for other user at course context'); - - // Test as the original user. - // Get all context data for the original user. - $this->setUser($user); - $contextlist = provider::get_contexts_for_userid($user->id); - - // There are three contexts in the list. - $this->assertCount(3, $contextlist); - - // Check the list against the expected list of contexts. - foreach ($contextlist as $context) { - $this->assertContains($context->id, $usercontextids); - } - - // Export the data for the system context. - // There should be two. - $this->export_context_data_for_user($user->id, $systemcontext, 'editor_atto'); - /** @var \core_privacy\tests\request\content_writer $writer */ - $writer = \core_privacy\local\request\writer::with_context($systemcontext); - $this->assertTrue($writer->has_any_data()); - - $subcontextbase = [get_string('autosaves', 'editor_atto')]; - - // There should be an intro and description. - $intro = $writer->get_data(array_merge($subcontextbase, [$systemuserdraftintro->id])); - $fs = get_file_storage(); - $this->assertEquals( - format_text($systemuserdraftintro->drafttext, FORMAT_HTML, provider::get_filter_options()), - $intro->drafttext - ); - $this->assertCount(2, $writer->get_files(array_merge($subcontextbase, [$systemuserdraftintro->id]))); - - $description = $writer->get_data(array_merge($subcontextbase, [$systemuserdraftdescription->id])); - $this->assertEquals( - format_text($systemuserdraftdescription->drafttext, FORMAT_HTML, provider::get_filter_options()), - $description->drafttext - ); - $this->assertCount(4, $writer->get_files(array_merge($subcontextbase, [$systemuserdraftdescription->id]))); - } - - /** - * Test delete_for_all_users_in_context. - */ - public function test_delete_for_all_users_in_context(): void { - global $USER, $DB; - $this->resetAfterTest(); - - // Create editor drafts in: - // - the system; and - // - a course; and - // - current user context; and - // - another user. - - $systemcontext = \context_system::instance(); - $course = $this->getDataGenerator()->create_course(); - $coursecontext = \context_course::instance($course->id); - - $usercontextids = []; - $user = $this->getDataGenerator()->create_user(); - $this->setUser($user); - - $usercontext = \context_user::instance($user->id); - $usercontextids[] = $usercontext->id; - $usercontextids[] = $systemcontext->id; - $usercontextids[] = $coursecontext->id; - - // Add a fake inline image to the original post. - - $userdraftintro = $this->create_editor_draft($usercontext, $user->id, - 'id_user_intro', 'text for test user at own context'); - $userdraftdescription = $this->create_editor_draft($usercontext, $user->id, - 'id_user_description', 'text for test user at own context'); - $systemuserdraftintro = $this->create_editor_draft($systemcontext, $user->id, - 'id_system_intro', 'text for test user at system context', 2); - $systemuserdraftdescription = $this->create_editor_draft($systemcontext, $user->id, - 'id_system_description', 'text for test user at system context', 4); - $coursedraftintro = $this->create_editor_draft($coursecontext, $user->id, - 'id_course_intro', 'text for test user at course context'); - $coursedraftdescription = $this->create_editor_draft($coursecontext, $user->id, - 'id_course_description', 'text for test user at course context'); - - // Create some data as the other user too. - $otherusercontextids = []; - $otheruser = $this->getDataGenerator()->create_user(); - $this->setUser($otheruser); - - $otherusercontext = \context_user::instance($otheruser->id); - $otherusercontextids[] = $otherusercontext->id; - $otherusercontextids[] = $systemcontext->id; - $otherusercontextids[] = $coursecontext->id; - - $otheruserdraftintro = $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_intro', 'text for other user at own context'); - $otheruserdraftdescription = $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_description', 'text for other user at own context'); - $systemotheruserdraftintro = $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_intro', 'text for other user at system context'); - $systemotheruserdraftdescription = $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_description', 'text for other user at system context'); - $courseotheruserdraftintro = $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_intro', 'text for other user at course context'); - $courseotheruserdraftdescription = $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_description', 'text for other user at course context'); - - // Test deletion of the user context. - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $usercontext->id])); - provider::delete_data_for_all_users_in_context($usercontext); - $this->assertCount(0, $DB->get_records('editor_atto_autosave', ['contextid' => $usercontext->id])); - - // No other contexts should be removed. - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $otherusercontext->id])); - $this->assertCount(4, $DB->get_records('editor_atto_autosave', ['contextid' => $systemcontext->id])); - $this->assertCount(4, $DB->get_records('editor_atto_autosave', ['contextid' => $coursecontext->id])); - - // Test deletion of the course contexts. - provider::delete_data_for_all_users_in_context($coursecontext); - $this->assertCount(0, $DB->get_records('editor_atto_autosave', ['contextid' => $coursecontext->id])); - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $otherusercontext->id])); - $this->assertCount(4, $DB->get_records('editor_atto_autosave', ['contextid' => $systemcontext->id])); - - // Test deletion of the system contexts. - provider::delete_data_for_all_users_in_context($systemcontext); - $this->assertCount(0, $DB->get_records('editor_atto_autosave', ['contextid' => $systemcontext->id])); - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $otherusercontext->id])); - } - - /** - * Test delete_for_all_users_in_context. - */ - public function test_delete_for_user_in_contexts(): void { - global $USER, $DB; - $this->resetAfterTest(); - - // Create editor drafts in: - // - the system; and - // - a course; and - // - current user context; and - // - another user. - - $systemcontext = \context_system::instance(); - $course = $this->getDataGenerator()->create_course(); - $coursecontext = \context_course::instance($course->id); - - $usercontextids = []; - $user = $this->getDataGenerator()->create_user(); - $this->setUser($user); - - $usercontext = \context_user::instance($user->id); - $usercontextids[] = $usercontext->id; - $usercontextids[] = $systemcontext->id; - $usercontextids[] = $coursecontext->id; - - // Add a fake inline image to the original post. - - $userdraftintro = $this->create_editor_draft($usercontext, $user->id, - 'id_user_intro', 'text for test user at own context'); - $userdraftdescription = $this->create_editor_draft($usercontext, $user->id, - 'id_user_description', 'text for test user at own context'); - $systemuserdraftintro = $this->create_editor_draft($systemcontext, $user->id, - 'id_system_intro', 'text for test user at system context', 2); - $systemuserdraftdescription = $this->create_editor_draft($systemcontext, $user->id, - 'id_system_description', 'text for test user at system context', 4); - $coursedraftintro = $this->create_editor_draft($coursecontext, $user->id, - 'id_course_intro', 'text for test user at course context'); - $coursedraftdescription = $this->create_editor_draft($coursecontext, $user->id, - 'id_course_description', 'text for test user at course context'); - - // Create some data as the other user too. - $otherusercontextids = []; - $otheruser = $this->getDataGenerator()->create_user(); - $this->setUser($otheruser); - - $otherusercontext = \context_user::instance($otheruser->id); - $otherusercontextids[] = $otherusercontext->id; - $otherusercontextids[] = $systemcontext->id; - $otherusercontextids[] = $coursecontext->id; - - $otheruserdraftintro = $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_intro', 'text for other user at own context'); - $otheruserdraftdescription = $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_description', 'text for other user at own context'); - $systemotheruserdraftintro = $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_intro', 'text for other user at system context'); - $systemotheruserdraftdescription = $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_description', 'text for other user at system context'); - $courseotheruserdraftintro = $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_intro', 'text for other user at course context'); - $courseotheruserdraftdescription = $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_description', 'text for other user at course context'); - - // Test deletion of all data for user in usercontext only. - $contextlist = new \core_privacy\tests\request\approved_contextlist( - \core_user::get_user($user->id), - 'editor_atto', - [$usercontext->id] - ); - provider::delete_data_for_user($contextlist); - $this->assertCount(0, $DB->get_records('editor_atto_autosave', ['contextid' => $usercontext->id])); - - // No other contexts should be removed. - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $otherusercontext->id])); - $this->assertCount(4, $DB->get_records('editor_atto_autosave', ['contextid' => $systemcontext->id])); - $this->assertCount(4, $DB->get_records('editor_atto_autosave', ['contextid' => $coursecontext->id])); - - // Test deletion of all data for user in course and system. - $contextlist = new \core_privacy\tests\request\approved_contextlist( - \core_user::get_user($user->id), - 'editor_atto', - [$coursecontext->id, $systemcontext->id] - ); - provider::delete_data_for_user($contextlist); - $this->assertCount(0, $DB->get_records('editor_atto_autosave', ['contextid' => $usercontext->id])); - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $otherusercontext->id])); - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $systemcontext->id])); - $this->assertCount(2, $DB->get_records('editor_atto_autosave', ['contextid' => $coursecontext->id])); - - // Data for the other user should remain. - $this->assertCount(2, $DB->get_records('editor_atto_autosave', [ - 'contextid' => $coursecontext->id, - 'userid' => $otheruser->id, - ])); - - $this->assertCount(2, $DB->get_records('editor_atto_autosave', [ - 'contextid' => $systemcontext->id, - 'userid' => $otheruser->id, - ])); - } - - /** - * Test that user data with different contexts is fetched. - */ - public function test_get_users_in_context(): void { - $this->resetAfterTest(); - - $component = 'editor_atto'; - - // Create editor drafts in: - // - the system; and - // - a course; and - // - current user context; and - // - another user. - - $systemcontext = \context_system::instance(); - // Create a course. - $course = $this->getDataGenerator()->create_course(); - $coursecontext = \context_course::instance($course->id); - - // Create a user. - $user = $this->getDataGenerator()->create_user(); - $usercontext = \context_user::instance($user->id); - $this->setUser($user); - - // Add a fake inline image to the original post. - $this->create_editor_draft($usercontext, $user->id, - 'id_user_intro', 'text for test user at own context'); - $this->create_editor_draft($systemcontext, $user->id, - 'id_system_intro', 'text for test user at system context', 2); - $this->create_editor_draft($systemcontext, $user->id, - 'id_system_description', 'text for test user at system context', 4); - $this->create_editor_draft($coursecontext, $user->id, - 'id_course_intro', 'text for test user at course context'); - - // Create user2. - $user2 = $this->getDataGenerator()->create_user(); - $this->setUser($user2); - - $this->create_editor_draft($coursecontext, $user2->id, - 'id_course_description', 'text for test user2 at course context'); - - // The list of users in usercontext should return user. - $userlist = new \core_privacy\local\request\userlist($usercontext, $component); - provider::get_users_in_context($userlist); - $this->assertCount(1, $userlist); - $this->assertTrue(in_array($user->id, $userlist->get_userids())); - - // The list of users in systemcontext should return user. - $userlist = new \core_privacy\local\request\userlist($systemcontext, $component); - provider::get_users_in_context($userlist); - $this->assertCount(1, $userlist); - $this->assertTrue(in_array($user->id, $userlist->get_userids())); - - // The list of users in coursecontext should return user and user2. - $userlist = new \core_privacy\local\request\userlist($coursecontext, $component); - provider::get_users_in_context($userlist); - $this->assertCount(2, $userlist); - $this->assertTrue(in_array($user->id, $userlist->get_userids())); - $this->assertTrue(in_array($user2->id, $userlist->get_userids())); - } - - /** - * Test that data for users in approved userlist is deleted. - */ - public function test_delete_data_for_users(): void { - $this->resetAfterTest(); - - $component = 'editor_atto'; - - // Create editor drafts in: - // - the system; and - // - a course; and - // - current user context; and - // - another user. - - $systemcontext = \context_system::instance(); - // Create a course. - $course = $this->getDataGenerator()->create_course(); - $coursecontext = \context_course::instance($course->id); - - // Create a user. - $user = $this->getDataGenerator()->create_user(); - $usercontext = \context_user::instance($user->id); - $this->setUser($user); - - // Add a fake inline image to the original post. - $this->create_editor_draft($usercontext, $user->id, - 'id_user_intro', 'text for test user at own context'); - $this->create_editor_draft($usercontext, $user->id, - 'id_user_description', 'text for test user at own context'); - $this->create_editor_draft($systemcontext, $user->id, - 'id_system_intro', 'text for test user at system context', 2); - $this->create_editor_draft($systemcontext, $user->id, - 'id_system_description', 'text for test user at system context', 4); - $this->create_editor_draft($coursecontext, $user->id, - 'id_course_intro', 'text for test user at course context'); - $this->create_editor_draft($coursecontext, $user->id, - 'id_course_description', 'text for test user at course context'); - - // Create some data as the other user too. - $otheruser = $this->getDataGenerator()->create_user(); - $otherusercontext = \context_user::instance($otheruser->id); - $this->setUser($otheruser); - - $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_intro', 'text for other user at own context'); - $this->create_editor_draft($otherusercontext, $otheruser->id, - 'id_user_description', 'text for other user at own context'); - $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_intro', 'text for other user at system context'); - $this->create_editor_draft($systemcontext, $otheruser->id, - 'id_system_description', 'text for other user at system context'); - $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_intro', 'text for other user at course context'); - $this->create_editor_draft($coursecontext, $otheruser->id, - 'id_course_description', 'text for other user at course context'); - - // The list of users for usercontext should return user. - $userlist1 = new \core_privacy\local\request\userlist($usercontext, $component); - provider::get_users_in_context($userlist1); - $this->assertCount(1, $userlist1); - $this->assertTrue(in_array($user->id, $userlist1->get_userids())); - - // The list of users for otherusercontext should return otheruser. - $userlist2 = new \core_privacy\local\request\userlist($otherusercontext, $component); - provider::get_users_in_context($userlist2); - $this->assertCount(1, $userlist2); - $this->assertTrue(in_array($otheruser->id, $userlist2->get_userids())); - - // Add userlist1 to the approved user list. - $approvedlist = new approved_userlist($usercontext, $component, $userlist1->get_userids()); - // Delete user data using delete_data_for_user for usercontext. - provider::delete_data_for_users($approvedlist); - - // Re-fetch users in usercontext - The user list should now be empty. - $userlist1 = new \core_privacy\local\request\userlist($usercontext, $component); - provider::get_users_in_context($userlist1); - $this->assertCount(0, $userlist1); - // Re-fetch users in otherusercontext - The user list should not be empty (otheruser). - $userlist2 = new \core_privacy\local\request\userlist($otherusercontext, $component); - provider::get_users_in_context($userlist2); - $this->assertCount(1, $userlist2); - $this->assertTrue(in_array($otheruser->id, $userlist2->get_userids())); - - // The list of users for systemcontext should return user and otheruser. - $userlist3 = new \core_privacy\local\request\userlist($systemcontext, $component); - provider::get_users_in_context($userlist3); - $this->assertCount(2, $userlist3); - $this->assertTrue(in_array($user->id, $userlist3->get_userids())); - $this->assertTrue(in_array($otheruser->id, $userlist3->get_userids())); - - // Add $userlist3 to the approved user list in the system context. - $approvedlist = new approved_userlist($systemcontext, $component, $userlist3->get_userids()); - // Delete user and otheruser data using delete_data_for_user. - provider::delete_data_for_users($approvedlist); - - // Re-fetch users in systemcontext - The user list should be empty. - $userlist3 = new \core_privacy\local\request\userlist($systemcontext, $component); - provider::get_users_in_context($userlist3); - $this->assertCount(0, $userlist3); - - // The list of users for coursecontext should return user and otheruser. - $userlist4 = new \core_privacy\local\request\userlist($coursecontext, $component); - provider::get_users_in_context($userlist4); - $this->assertCount(2, $userlist4); - $this->assertTrue(in_array($user->id, $userlist4->get_userids())); - $this->assertTrue(in_array($otheruser->id, $userlist4->get_userids())); - - // Add user to the approved user list in the course context. - $approvedlist = new approved_userlist($coursecontext, $component, [$user->id]); - // Delete user data using delete_data_for_user. - provider::delete_data_for_users($approvedlist); - - // Re-fetch users in coursecontext - The user list should return otheruser. - $userlist4 = new \core_privacy\local\request\userlist($coursecontext, $component); - provider::get_users_in_context($userlist4); - $this->assertCount(1, $userlist4); - $this->assertTrue(in_array($otheruser->id, $userlist4->get_userids())); - } - - /** - * Test fetch and delete when another user has editted a draft in your - * user context. Edge case. - */ - public function test_another_user_edits_you(): void { - global $USER, $DB; - $this->resetAfterTest(); - - $user = $this->getDataGenerator()->create_user(); - $usercontext = \context_user::instance($user->id); - $otheruser = $this->getDataGenerator()->create_user(); - $otherusercontext = \context_user::instance($otheruser->id); - $this->setUser($user); - - $userdraftintro = $this->create_editor_draft($usercontext, $otheruser->id, - 'id_user_intro', 'text for test user at other context'); - - // Test as the owning user. - $this->setUser($user); - $contextlist = provider::get_contexts_for_userid($user->id); - $contexts = $contextlist->get_contexts(); - $this->assertCount(1, $contexts); - $firstcontext = reset($contexts); - $this->assertEquals($usercontext, $firstcontext); - - // Should have the data. - $this->export_context_data_for_user($user->id, $usercontext, 'editor_atto'); - /** @var \core_privacy\tests\request\content_writer $writer */ - $writer = \core_privacy\local\request\writer::with_context($usercontext); - $this->assertTrue($writer->has_any_data()); - - $subcontext = [ - get_string('autosaves', 'editor_atto'), - $userdraftintro->id, - ]; - $data = $writer->get_data($subcontext); - $this->assertEquals(\core_privacy\local\request\transform::user($otheruser->id), $data->author); - - $contextlist = new \core_privacy\tests\request\approved_contextlist( - \core_user::get_user($user->id), - 'editor_atto', - [$usercontext->id] - ); - - - // Deleting for this context should _not_ delete as the user does not own this draft (crazy edge case, remember). - provider::delete_data_for_user($contextlist); - $records = $DB->get_records('editor_atto_autosave'); - $this->assertNotEmpty($records); - $this->assertCount(1, $records); - $firstrecord = reset($records); - $this->assertEquals($userdraftintro->id, $firstrecord->id); - } - - /** - * Test fetch and delete when you have edited another user's context. - */ - public function test_another_you_edit_different_user(): void { - global $USER, $DB; - $this->resetAfterTest(); - - $user = $this->getDataGenerator()->create_user(); - $usercontext = \context_user::instance($user->id); - $otheruser = $this->getDataGenerator()->create_user(); - $otherusercontext = \context_user::instance($otheruser->id); - $this->setUser($user); - - $userdraftintro = $this->create_editor_draft($otherusercontext, $user->id, - 'id_user_intro', 'text for other user you just edited.'); - - // Test as the context owner. - $this->setUser($user); - $contextlist = provider::get_contexts_for_userid($user->id); - $contexts = $contextlist->get_contexts(); - $this->assertCount(1, $contexts); - $firstcontext = reset($contexts); - $this->assertEquals($otherusercontext, $firstcontext); - - // Should have the data. - $this->export_context_data_for_user($user->id, $otherusercontext, 'editor_atto'); - /** @var \core_privacy\tests\request\content_writer $writer */ - $writer = \core_privacy\local\request\writer::with_context($otherusercontext); - $this->assertTrue($writer->has_any_data()); - - $subcontext = [ - get_string('autosaves', 'editor_atto'), - $userdraftintro->id, - ]; - $data = $writer->get_data($subcontext); - $this->assertFalse(isset($data->author)); - - $contextlist = new \core_privacy\tests\request\approved_contextlist( - \core_user::get_user($user->id), - 'editor_atto', - [$otherusercontext->id] - ); - provider::delete_data_for_user($contextlist); - $this->assertEmpty($DB->get_records('editor_atto_autosave')); - } - - /** - * Create an editor draft. - * - * @param \context $context The context to create the draft for. - * @param int $userid The ID to create the draft for. - * @param string $elementid The elementid for the editor. - * @param string $text The text to write. - * @param int $filecount The number of files to create. - * @return \stdClass The editor draft. - */ - protected function create_editor_draft(\context $context, $userid, $elementid, $text, $filecount = 0) { - global $DB; - - $draftid = file_get_unused_draft_itemid(); - $fs = get_file_storage(); - - for ($i = 0; $i < $filecount; $i++) { - $fs->create_file_from_string([ - 'contextid' => $context->id, - 'component' => 'user', - 'filearea' => 'draft', - 'itemid' => $draftid, - 'filepath' => '/', - 'filename' => "example_{$i}.txt", - ], - "Awesome example of a text file with id {$i} for {$context->id} and {$elementid}"); - } - - $id = $DB->insert_record('editor_atto_autosave', (object) [ - 'elementid' => $elementid, - 'contextid' => $context->id, - 'userid' => $userid, - 'drafttext' => $text, - 'draftid' => $draftid, - 'pageinstance' => 'example_page_instance_' . rand(1, 1000), - 'timemodified' => time(), - - // Page hash doesn't matter for our purposes. - 'pagehash' => sha1("{$userid}/{$context->id}/{$elementid}/{$draftid}"), - ]); - - return $DB->get_record('editor_atto_autosave', ['id' => $id]); - } -} diff --git a/lib/editor/atto/thirdpartylibs.xml b/lib/editor/atto/thirdpartylibs.xml deleted file mode 100644 index 166f0966073..00000000000 --- a/lib/editor/atto/thirdpartylibs.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - yui/src/rangy/js/*.* - Rangy - A cross-browser JavaScript range and selection library. - 1.3.1 - MIT - https://github.com/timdown/rangy - - 2014 Tim Down - - - - diff --git a/lib/editor/atto/upgrade.txt b/lib/editor/atto/upgrade.txt deleted file mode 100644 index 38a95053948..00000000000 --- a/lib/editor/atto/upgrade.txt +++ /dev/null @@ -1,35 +0,0 @@ -=== 4.5 Onwards === - -This file has been replaced by UPGRADING.md. See MDL-81125 for further information. - -=== -This files describes API changes in the editor_atto code. - -=== 4.1 === - -* Two new helper functions have been added to lib/editor/atto -to handle enable/disable the empty placeholder for empty content in the HTML source view: - - enablePlaceholderForEmptyContent() - Handle to enable the empty placeholder for empty content - - disablePlaceholderForEmptyContent() - Handle to disable the empty placeholder for empty content. - -* One property have been added to lib/editor/atto to handle the state of the empty placeholder content. - - enableAppropriateEmptyContent - Enable/disable the empty placeholder content. - -=== 3.4 === - -* The following functions, previously used (exclusively) by upgrade steps are not available - anymore because of the upgrade cleanup performed for this version. See MDL-57432 for more info: - - atto_equation_update_librarygroup4_setting() - -=== 3.0 === - -* Rangy updated to 1.3.0. - Rangy has deprecated the createCssClassApplier function in this version (it is now createClassApplier). - -=== 2.9 === - -* When adding a shortcut to the button of a plugin, atto will add a layer of validation -to ensure that only the required keys are pressed. However, if you are using a custom -keyConfig object you must validate the shortcut yourself. This is particularly important -for non-English keyboard users. For more information read the documentation of -EditorPluginButtons::_addKeyboardListener() and MDL-47133. diff --git a/lib/editor/atto/version.php b/lib/editor/atto/version.php deleted file mode 100644 index 839f5979dd6..00000000000 --- a/lib/editor/atto/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Atto text editor integration version file. - * - * @package editor_atto - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2024100100; // Requires this Moodle version. -$plugin->component = 'editor_atto'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js deleted file mode 100644 index da3c0601326..00000000000 --- a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js +++ /dev/null @@ -1,3195 +0,0 @@ -YUI.add('moodle-editor_atto-editor', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -/* eslint-disable no-unused-vars */ - -/** - * The Atto WYSIWG pluggable editor, written for Moodle. - * - * @module moodle-editor_atto-editor - * @package editor_atto - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @main moodle-editor_atto-editor - */ - -/** - * @module moodle-editor_atto-editor - * @submodule editor-base - */ - -var LOGNAME = 'moodle-editor_atto-editor'; -var CSS = { - CONTENT: 'editor_atto_content', - CONTENTWRAPPER: 'editor_atto_content_wrap', - TOOLBAR: 'editor_atto_toolbar', - WRAPPER: 'editor_atto', - HIGHLIGHT: 'highlight' - }, - rangy = window.rangy; - -/** - * The Atto editor for Moodle. - * - * @namespace M.editor_atto - * @class Editor - * @constructor - * @uses M.editor_atto.EditorClean - * @uses M.editor_atto.EditorFilepicker - * @uses M.editor_atto.EditorSelection - * @uses M.editor_atto.EditorStyling - * @uses M.editor_atto.EditorTextArea - * @uses M.editor_atto.EditorToolbar - * @uses M.editor_atto.EditorToolbarNav - */ - -function Editor() { - Editor.superclass.constructor.apply(this, arguments); -} - -Y.extend(Editor, Y.Base, { - - /** - * List of known block level tags. - * Taken from "https://developer.mozilla.org/en-US/docs/HTML/Block-level_elements". - * - * @property BLOCK_TAGS - * @type {Array} - */ - BLOCK_TAGS: [ - 'address', - 'article', - 'aside', - 'audio', - 'blockquote', - 'canvas', - 'dd', - 'div', - 'dl', - 'fieldset', - 'figcaption', - 'figure', - 'footer', - 'form', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'header', - 'hgroup', - 'hr', - 'noscript', - 'ol', - 'output', - 'p', - 'pre', - 'section', - 'table', - 'tfoot', - 'ul', - 'video' - ], - - PLACEHOLDER_CLASS: 'atto-tmp-class', - ALL_NODES_SELECTOR: '[style],font[face]', - FONT_FAMILY: 'fontFamily', - - /** - * The wrapper containing the editor. - * - * @property _wrapper - * @type Node - * @private - */ - _wrapper: null, - - /** - * A reference to the content editable Node. - * - * @property editor - * @type Node - */ - editor: null, - - /** - * A reference to the original text area. - * - * @property textarea - * @type Node - */ - textarea: null, - - /** - * A reference to the label associated with the original text area. - * - * @property textareaLabel - * @type Node - */ - textareaLabel: null, - - /** - * A reference to the list of plugins. - * - * @property plugins - * @type object - */ - plugins: null, - - /** - * An indicator of the current input direction. - * - * @property coreDirection - * @type string - */ - coreDirection: null, - - /** - * Enable/disable the empty placeholder content. - * - * @property enableAppropriateEmptyContent - * @type Boolean - */ - enableAppropriateEmptyContent: null, - - /** - * Event Handles to clear on editor destruction. - * - * @property _eventHandles - * @private - */ - _eventHandles: null, - - initializer: function() { - var template; - - // Note - it is not safe to use a CSS selector like '#' + elementid because the id - // may have colons in it - e.g. quiz. - this.textarea = Y.one(document.getElementById(this.get('elementid'))); - - if (!this.textarea) { - // No text area found. - Y.log('Text area not found - unable to setup editor for ' + this.get('elementid'), - 'error', LOGNAME); - return; - } - - var extraclasses = this.textarea.getAttribute('class'); - - this._eventHandles = []; - - var description = Y.Node.create( - '
                              ' + M.util.get_string('richtexteditor', 'editor_atto') + '
                              ' - ); - this._wrapper = Y.Node.create('
                              '); - this._wrapper.appendChild(description); - this._wrapper.setAttribute('aria-describedby', description.generateID()); - template = Y.Handlebars.compile('
                              '); - this.editor = Y.Node.create(template({ - elementid: this.get('elementid'), - CSS: CSS - })); - - // Add a labelled-by attribute to the contenteditable. - this.textareaLabel = Y.one('[for="' + this.get('elementid') + '"]'); - if (this.textareaLabel) { - this.textareaLabel.generateID(); - this.editor.setAttribute('aria-labelledby', this.textareaLabel.get("id")); - } - - // Set diretcion according to current page language. - this.coreDirection = Y.one('body').hasClass('dir-rtl') ? 'rtl' : 'ltr'; - - // Enable the placeholder for empty content. - this.enablePlaceholderForEmptyContent(); - - // Add everything to the wrapper. - this.setupToolbar(); - - // Editable content wrapper. - var content = Y.Node.create('
                              '); - content.appendChild(this.editor); - this._wrapper.appendChild(content); - - // Style the editor. According to the styles.css: 20 is the line-height, 8 is padding-top + padding-bottom. - this.editor.setStyle('minHeight', ((20 * this.textarea.getAttribute('rows')) + 8) + 'px'); - - if (Y.UA.ie === 0) { - // We set a height here to force the overflow because decent browsers allow the CSS property resize. - this.editor.setStyle('height', ((20 * this.textarea.getAttribute('rows')) + 8) + 'px'); - } - - // Disable odd inline CSS styles. - this.disableCssStyling(); - - // Use paragraphs not divs. - if (document.queryCommandSupported('DefaultParagraphSeparator')) { - document.execCommand('DefaultParagraphSeparator', false, 'p'); - } - - // Add the toolbar and editable zone to the page. - this.textarea.get('parentNode').insert(this._wrapper, this.textarea). - setAttribute('class', 'editor_atto_wrap'); - - // Hide the old textarea. - this.textarea.hide(); - - // Set up custom event for editor updated. - Y.mix(Y.Node.DOM_EVENTS, {'form:editorUpdated': true}); - this.textarea.on('form:editorUpdated', function() { - this.updateEditorState(); - }, this); - - // Copy the text to the contenteditable div. - this.updateFromTextArea(); - - // Publish the events that are defined by this editor. - this.publishEvents(); - - // Add handling for saving and restoring selections on cursor/focus changes. - this.setupSelectionWatchers(); - - // Add polling to update the textarea periodically when typing long content. - this.setupAutomaticPolling(); - - // Setup plugins. - this.setupPlugins(); - - // Initialize the auto-save timer. - this.setupAutosave(); - // Preload the icons for the notifications. - this.setupNotifications(); - }, - - /** - * Focus on the editable area for this editor. - * - * @method focus - * @chainable - */ - focus: function() { - this.editor.focus(); - - return this; - }, - - /** - * Publish events for this editor instance. - * - * @method publishEvents - * @private - * @chainable - */ - publishEvents: function() { - /** - * Fired when changes are made within the editor. - * - * @event change - */ - this.publish('change', { - broadcast: true, - preventable: true - }); - - /** - * Fired when all plugins have completed loading. - * - * @event pluginsloaded - */ - this.publish('pluginsloaded', { - fireOnce: true - }); - - this.publish('atto:selectionchanged', { - prefix: 'atto' - }); - - return this; - }, - - /** - * Set up automated polling of the text area to update the textarea. - * - * @method setupAutomaticPolling - * @chainable - */ - setupAutomaticPolling: function() { - this._registerEventHandle(this.editor.on(['keyup', 'cut'], this.updateOriginal, this)); - this._registerEventHandle(this.editor.on('paste', this.pasteCleanup, this)); - - // Call this.updateOriginal after dropped content has been processed. - this._registerEventHandle(this.editor.on('drop', this.updateOriginalDelayed, this)); - - return this; - }, - - /** - * Calls updateOriginal on a short timer to allow native event handlers to run first. - * - * @method updateOriginalDelayed - * @chainable - */ - updateOriginalDelayed: function() { - Y.soon(Y.bind(this.updateOriginal, this)); - - return this; - }, - - setupPlugins: function() { - // Clear the list of plugins. - this.plugins = {}; - - var plugins = this.get('plugins'); - - var groupIndex, - group, - pluginIndex, - plugin, - pluginConfig; - - for (groupIndex in plugins) { - group = plugins[groupIndex]; - if (!group.plugins) { - // No plugins in this group - skip it. - continue; - } - for (pluginIndex in group.plugins) { - plugin = group.plugins[pluginIndex]; - - pluginConfig = Y.mix({ - name: plugin.name, - group: group.group, - editor: this.editor, - toolbar: this.toolbar, - host: this - }, plugin); - - // Add a reference to the current editor. - if (typeof Y.M['atto_' + plugin.name] === "undefined") { - Y.log("Plugin '" + plugin.name + "' could not be found - skipping initialisation", "warn", LOGNAME); - continue; - } - this.plugins[plugin.name] = new Y.M['atto_' + plugin.name].Button(pluginConfig); - } - } - - // Some plugins need to perform actions once all plugins have loaded. - this.fire('pluginsloaded'); - - return this; - }, - - enablePlugins: function(plugin) { - this._setPluginState(true, plugin); - }, - - disablePlugins: function(plugin) { - this._setPluginState(false, plugin); - }, - - _setPluginState: function(enable, plugin) { - var target = 'disableButtons'; - if (enable) { - target = 'enableButtons'; - } - - if (plugin) { - this.plugins[plugin][target](); - } else { - Y.Object.each(this.plugins, function(currentPlugin) { - currentPlugin[target](); - }, this); - } - }, - - /** - * Update the state of the editor. - */ - updateEditorState: function() { - var disabled = this.textarea.hasAttribute('readonly'), - editorfield = Y.one('#' + this.get('elementid') + 'editable'); - // Enable/Disable all plugins. - this._setPluginState(!disabled); - // Enable/Disable content of editor. - if (editorfield) { - editorfield.setAttribute('contenteditable', !disabled); - } - }, - - /** - * Enable the empty placeholder for empty content. - */ - enablePlaceholderForEmptyContent: function() { - this.enableAppropriateEmptyContent = true; - }, - - /** - * Disable the empty placeholder for empty content. - */ - disablePlaceholderForEmptyContent: function() { - this.enableAppropriateEmptyContent = false; - }, - - /** - * Register an event handle for disposal in the destructor. - * - * @method _registerEventHandle - * @param {EventHandle} The Event Handle as returned by Y.on, and Y.delegate. - * @private - */ - _registerEventHandle: function(handle) { - this._eventHandles.push(handle); - } - -}, { - NS: 'editor_atto', - ATTRS: { - /** - * The unique identifier for the form element representing the editor. - * - * @attribute elementid - * @type String - * @writeOnce - */ - elementid: { - value: null, - writeOnce: true - }, - - /** - * The contextid of the form. - * - * @attribute contextid - * @type Integer - * @writeOnce - */ - contextid: { - value: null, - writeOnce: true - }, - - /** - * Plugins with their configuration. - * - * The plugins structure is: - * - * [ - * { - * "group": "groupName", - * "plugins": [ - * "pluginName": { - * "configKey": "configValue" - * }, - * "pluginName": { - * "configKey": "configValue" - * } - * ] - * }, - * { - * "group": "groupName", - * "plugins": [ - * "pluginName": { - * "configKey": "configValue" - * } - * ] - * } - * ] - * - * @attribute plugins - * @type Object - * @writeOnce - */ - plugins: { - value: {}, - writeOnce: true - } - } -}); - -// The Editor publishes custom events that can be subscribed to. -Y.augment(Editor, Y.EventTarget); - -Y.namespace('M.editor_atto').Editor = Editor; - -// Function for Moodle's initialisation. -Y.namespace('M.editor_atto.Editor').init = function(config) { - return new Y.M.editor_atto.Editor(config); -}; -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * A notify function for the Atto editor. - * - * @module moodle-editor_atto-notify - * @submodule notify - * @package editor_atto - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -var LOGNAME_NOTIFY = 'moodle-editor_atto-editor-notify', - NOTIFY_INFO = 'info', - NOTIFY_WARNING = 'warning'; - -function EditorNotify() {} - -EditorNotify.ATTRS = { -}; - -EditorNotify.prototype = { - - /** - * A single Y.Node for this editor. There is only ever one - it is replaced if a new message comes in. - * - * @property messageOverlay - * @type {Node} - */ - messageOverlay: null, - - /** - * A single timer object that can be used to cancel the hiding behaviour. - * - * @property hideTimer - * @type {timer} - */ - hideTimer: null, - - /** - * Initialize the notifications. - * - * @method setupNotifications - * @chainable - */ - setupNotifications: function() { - var preload1 = new Image(), - preload2 = new Image(); - - preload1.src = M.util.image_url('i/warning', 'moodle'); - preload2.src = M.util.image_url('i/info', 'moodle'); - - return this; - }, - - /** - * Show a notification in a floaty overlay somewhere in the atto editor text area. - * - * @method showMessage - * @param {String} message The translated message (use get_string) - * @param {String} type Must be either "info" or "warning" - * @param {Number} timeout Time in milliseconds to show this message for. - * @chainable - */ - showMessage: function(message, type, timeout) { - var messageTypeIcon = '', - intTimeout, - bodyContent; - - if (this.messageOverlay === null) { - this.messageOverlay = Y.Node.create('
                              '); - - this.messageOverlay.hide(true); - this.textarea.get('parentNode').append(this.messageOverlay); - - this.messageOverlay.on('click', function() { - this.messageOverlay.hide(true); - }, this); - } - - if (this.hideTimer !== null) { - this.hideTimer.cancel(); - } - - if (type === NOTIFY_WARNING) { - messageTypeIcon = '' + M.util.get_string('warning', 'moodle') + ''; - } else if (type === NOTIFY_INFO) { - messageTypeIcon = '' + M.util.get_string('info', 'moodle') + ''; - } else { - Y.log('Invalid message type specified: ' + type + '. Must be either "info" or "warning".', 'debug', LOGNAME_NOTIFY); - } - - // Parse the timeout value. - intTimeout = parseInt(timeout, 10); - if (intTimeout <= 0) { - intTimeout = 60000; - } - - // Convert class to atto_info (for example). - type = 'atto_' + type; - - bodyContent = Y.Node.create(''); - this.messageOverlay.empty(); - this.messageOverlay.append(bodyContent); - this.messageOverlay.show(true); - - this.hideTimer = Y.later(intTimeout, this, function() { - Y.log('Hide Atto notification.', 'debug', LOGNAME_NOTIFY); - this.hideTimer = null; - if (this.messageOverlay.inDoc()) { - this.messageOverlay.hide(true); - } - }); - - return this; - } - -}; - -Y.Base.mix(Y.M.editor_atto.Editor, [EditorNotify]); -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @module moodle-editor_atto-editor - * @submodule textarea - */ - -/** - * Textarea functions for the Atto editor. - * - * See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details. - * - * @namespace M.editor_atto - * @class EditorTextArea - */ - -function EditorTextArea() {} - -EditorTextArea.ATTRS = { -}; - -EditorTextArea.prototype = { - - /** - * Return the appropriate empty content value for the current browser. - * - * Different browsers use a different content when they are empty and - * we must set this reliable across the board. - * - * @method _getEmptyContent - * @return String The content to use representing no user-provided content - * @private - */ - _getEmptyContent: function() { - if (!this.enableAppropriateEmptyContent) { - // Return the empty string if we do not enable the empty placeholder. Ex: HTML mode. - return ''; - } - var alignment; - if (this.coreDirection === 'rtl') { - alignment = 'style="text-align: right;"'; - } else { - alignment = 'style="text-align: left;"'; - } - if (Y.UA.ie && Y.UA.ie < 10) { - return '

                              '; - } else { - return '


                              '; - } - }, - - /** - * Copy and clean the text from the textarea into the contenteditable div. - * - * If the text is empty, provide a default paragraph tag to hold the content. - * - * @method updateFromTextArea - * @chainable - */ - updateFromTextArea: function() { - // Clear it first. - this.editor.setHTML(''); - - // Copy cleaned HTML to editable div. - this.editor.append(this._cleanHTML(this.textarea.get('value'), true)); - - // Insert a paragraph in the empty contenteditable div. - if (this.editor.getHTML() === '') { - this.editor.setHTML(this._getEmptyContent()); - } - - return this; - }, - - /** - * Copy the text from the contenteditable to the textarea which it replaced. - * - * @method updateOriginal - * @chainable - */ - updateOriginal: function() { - // Get the previous and current value to compare them. - var oldValue = this.textarea.get('value'), - newValue = this.getCleanHTML(); - - if (newValue === "" && this.isActive()) { - // The content was entirely empty so get the empty content placeholder. - newValue = this._getEmptyContent(); - } - - // Only call this when there has been an actual change to reduce processing. - if (oldValue !== newValue) { - // Insert the cleaned content. - this.textarea.set('value', newValue); - - // Trigger the onchange callback on the textarea, essentially to notify the formchangechecker module. - this.textarea.simulate('change'); - - // Trigger handlers for this action. - this.fire('change'); - } - - return this; - } -}; - -Y.Base.mix(Y.M.editor_atto.Editor, [EditorTextArea]); -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . -/* eslint-disable no-unused-vars */ - -/** - * A autosave function for the Atto editor. - * - * @module moodle-editor_atto-autosave - * @submodule autosave-base - * @package editor_atto - * @copyright 2014 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -var SUCCESS_MESSAGE_TIMEOUT = 5000, - RECOVER_MESSAGE_TIMEOUT = 60000, - LOGNAME_AUTOSAVE = 'moodle-editor_atto-editor-autosave'; - -function EditorAutosave() {} - -EditorAutosave.ATTRS = { - /** - * Enable/Disable auto save for this instance. - * - * @attribute autosaveEnabled - * @type Boolean - * @writeOnce - */ - autosaveEnabled: { - value: true, - writeOnce: true - }, - - /** - * The time between autosaves (in seconds). - * - * @attribute autosaveFrequency - * @type Number - * @default 60 - * @writeOnce - */ - autosaveFrequency: { - value: 60, - writeOnce: true - }, - - /** - * Unique hash for this page instance. Calculated from $PAGE->url in php. - * - * @attribute pageHash - * @type String - * @writeOnce - */ - pageHash: { - value: '', - writeOnce: true - } -}; - -EditorAutosave.prototype = { - - /** - * The text that was auto saved in the last request. - * - * @property lastText - * @type string - */ - lastText: "", - - /** - * Autosave instance. - * - * @property autosaveInstance - * @type string - */ - autosaveInstance: null, - - /** - * Autosave Timer. - * - * @property autosaveTimer - * @type object - */ - autosaveTimer: null, - - /** - * Initialize the autosave process - * - * @method setupAutosave - * @chainable - */ - setupAutosave: function() { - var draftid = -1, - form, - optiontype = null, - options = this.get('filepickeroptions'), - params; - - if (!this.get('autosaveEnabled')) { - // Autosave disabled for this instance. - return; - } - - this.autosaveInstance = Y.stamp(this); - for (optiontype in options) { - if (typeof options[optiontype].itemid !== "undefined") { - draftid = options[optiontype].itemid; - } - } - - // First see if there are any saved drafts. - // Make an ajax request. - params = { - contextid: this.get('contextid'), - action: 'resume', - draftid: draftid, - elementid: this.get('elementid'), - pageinstance: this.autosaveInstance, - pagehash: this.get('pageHash') - }; - - this.autosaveIo(params, this, { - success: function(response) { - if (response === null) { - // This can happen when there is nothing to resume from. - return; - } else if (!response) { - Y.log('Invalid response received.', 'debug', LOGNAME_AUTOSAVE); - return; - } - - // Revert untouched editor contents to an empty string. - var emptyContents = [ - // For FF and Chrome. - '

                              ', - '


                              ', - '
                              ', - '

                              ', - '


                              ', - '

                              ', - '


                              ', - // For IE 9 and 10. - '

                               

                              ', - '


                               

                              ', - '

                               

                              ', - '


                               

                              ', - '

                               

                              ', - '


                               

                              ' - ]; - if (emptyContents.includes(response.result)) { - response.result = ''; - } - - if (response.error || typeof response.result === 'undefined') { - Y.log('Error occurred recovering draft text: ' + response.error, 'debug', LOGNAME_AUTOSAVE); - this.showMessage(M.util.get_string('errortextrecovery', 'editor_atto'), - NOTIFY_WARNING, RECOVER_MESSAGE_TIMEOUT); - } else if (response.result !== this.textarea.get('value') && - response.result !== '') { - Y.log('Autosave text found - recover it.', 'debug', LOGNAME_AUTOSAVE); - this.recoverText(response.result); - } - this._fireSelectionChanged(); - - }, - failure: function() { - this.showMessage(M.util.get_string('errortextrecovery', 'editor_atto'), - NOTIFY_WARNING, RECOVER_MESSAGE_TIMEOUT); - } - }); - - // Now setup the timer for periodic saves. - var delay = parseInt(this.get('autosaveFrequency'), 10) * 1000; - this.autosaveTimer = Y.later(delay, this, this.saveDraft, false, true); - - // Now setup the listener for form submission. - form = this.textarea.ancestor('form'); - if (form) { - this.autosaveIoOnSubmit(form, { - action: 'reset', - contextid: this.get('contextid'), - elementid: this.get('elementid'), - pageinstance: this.autosaveInstance, - pagehash: this.get('pageHash') - }); - } - return this; - }, - - /** - * Recover a previous version of this text and show a message. - * - * @method recoverText - * @param {String} text - * @chainable - */ - recoverText: function(text) { - this.editor.setHTML(text); - this.saveSelection(); - this.updateOriginal(); - this.lastText = text; - - this.showMessage(M.util.get_string('textrecovered', 'editor_atto'), - NOTIFY_INFO, RECOVER_MESSAGE_TIMEOUT); - - // Fire an event that the editor content has changed. - require(['core_editor/events'], function(editorEvents) { - editorEvents.notifyEditorContentRestored(this.editor.getDOMNode()); - }.bind(this)); - - return this; - }, - - /** - * Save a single draft via ajax. - * - * @method saveDraft - * @chainable - */ - saveDraft: function() { - var url, params; - - if (!this.editor.getDOMNode()) { - // Stop autosaving if the editor was removed from the page. - this.autosaveTimer.cancel(); - return; - } - // Only copy the text from the div to the textarea if the textarea is not currently visible. - if (!this.editor.get('hidden')) { - this.updateOriginal(); - } - var newText = this.textarea.get('value'); - - if (newText !== this.lastText) { - Y.log('Autosave text', 'debug', LOGNAME_AUTOSAVE); - - // Make an ajax request. - url = M.cfg.wwwroot + this.get('autosaveAjaxScript'); - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'save', - drafttext: newText, - elementid: this.get('elementid'), - pagehash: this.get('pageHash'), - pageinstance: this.autosaveInstance - }; - - // Reusable error handler - must be passed the correct context. - var ajaxErrorFunction = function(response) { - var errorDuration = parseInt(this.get('autosaveFrequency'), 10) * 1000; - Y.log('Error while autosaving text', 'warn', LOGNAME_AUTOSAVE); - Y.log(response, 'warn', LOGNAME_AUTOSAVE); - this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), NOTIFY_WARNING, errorDuration); - }; - - this.autosaveIo(params, this, { - failure: ajaxErrorFunction, - success: function(response) { - if (response && response.error) { - Y.soon(Y.bind(ajaxErrorFunction, this, [response])); - } else { - // All working. - this.lastText = newText; - this.showMessage(M.util.get_string('autosavesucceeded', 'editor_atto'), - NOTIFY_INFO, SUCCESS_MESSAGE_TIMEOUT); - } - } - }); - } - return this; - } -}; - -Y.Base.mix(Y.M.editor_atto.Editor, [EditorAutosave]); -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * A autosave function for the Atto editor. - * - * @module moodle-editor_atto-autosave-io - * @submodule autosave-io - * @package editor_atto - * @copyright 2016 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -var EditorAutosaveIoDispatcherInstance = null; - -function EditorAutosaveIoDispatcher() { - EditorAutosaveIoDispatcher.superclass.constructor.apply(this, arguments); - this._submitEvents = {}; - this._queue = []; - this._throttle = null; -} -EditorAutosaveIoDispatcher.NAME = 'EditorAutosaveIoDispatcher'; -EditorAutosaveIoDispatcher.ATTRS = { - - /** - * The relative path to the ajax script. - * - * @attribute autosaveAjaxScript - * @type String - * @default '/lib/editor/atto/autosave-ajax.php' - * @readOnly - */ - autosaveAjaxScript: { - value: '/lib/editor/atto/autosave-ajax.php', - readOnly: true - }, - - /** - * The time buffer for the throttled requested. - * - * @attribute delay - * @type Number - * @default 50 - * @readOnly - */ - delay: { - value: 50, - readOnly: true - } - -}; -Y.extend(EditorAutosaveIoDispatcher, Y.Base, { - - /** - * Dispatch an IO request. - * - * This method will put the requests in a queue in order to attempt to bulk them. - * - * @param {Object} params The parameters of the request. - * @param {Object} context The context in which the callbacks are called. - * @param {Object} callbacks Object with 'success', 'complete', 'end', 'failure' and 'start' as - * optional keys defining the callbacks to call. Success and Complete - * functions will receive the response as parameter. Success and Complete - * may receive an object containing the error key, use this to confirm - * that no errors occured. - * @return {Void} - */ - dispatch: function(params, context, callbacks) { - if (this._throttle) { - this._throttle.cancel(); - } - - this._throttle = Y.later(this.get('delay'), this, this._processDispatchQueue); - this._queue.push([params, context, callbacks]); - }, - - /** - * Dispatches the requests in the queue. - * - * @return {Void} - */ - _processDispatchQueue: function() { - var queue = this._queue, - data = {}; - - this._queue = []; - if (queue.length < 1) { - return; - } - - Y.Array.each(queue, function(item, index) { - data[index] = item[0]; - }); - - Y.io(M.cfg.wwwroot + this.get('autosaveAjaxScript'), { - method: 'POST', - data: Y.QueryString.stringify({ - actions: data, - sesskey: M.cfg.sesskey - }), - on: { - start: this._makeIoEventCallback('start', queue), - complete: this._makeIoEventCallback('complete', queue), - failure: this._makeIoEventCallback('failure', queue), - end: this._makeIoEventCallback('end', queue), - success: this._makeIoEventCallback('success', queue) - } - }); - }, - - /** - * Creates a function that dispatches an IO response to callbacks. - * - * @param {String} event The type of event. - * @param {Array} queue The queue. - * @return {Function} - */ - _makeIoEventCallback: function(event, queue) { - var noop = function() {}; - return function() { - var response = arguments[1], - parsed = {}; - - if ((event == 'complete' || event == 'success') && (typeof response !== 'undefined' - && typeof response.responseText !== 'undefined' && response.responseText !== '')) { - - // Success and complete events need to parse the response. - parsed = JSON.parse(response.responseText) || {}; - } - - Y.Array.each(queue, function(item, index) { - var context = item[1], - cb = (item[2] && item[2][event]) || noop, - arg; - - if (parsed && parsed.error) { - // The response is an error, we send it to everyone. - arg = parsed; - } else if (parsed) { - // The response was parsed, we only communicate the relevant portion of the response. - arg = parsed[index]; - } - - cb.apply(context, [arg]); - }); - }; - }, - - /** - * Form submit handler. - * - * @param {EventFacade} e The event. - * @return {Void} - */ - _onSubmit: function(e) { - var data = {}, - id = e.currentTarget.generateID(), - params = this._submitEvents[id]; - - if (!params || params.ios.length < 1) { - return; - } - - Y.Array.each(params.ios, function(param, index) { - data[index] = param; - }); - - Y.io(M.cfg.wwwroot + this.get('autosaveAjaxScript'), { - method: 'POST', - data: Y.QueryString.stringify({ - actions: data, - sesskey: M.cfg.sesskey - }), - sync: true - }); - }, - - /** - * Registers a request to be made on form submission. - * - * @param {Node} node The forum node we will listen to. - * @param {Object} params Parameters for the IO request. - * @return {Void} - */ - whenSubmit: function(node, params) { - if (typeof this._submitEvents[node.generateID()] === 'undefined') { - this._submitEvents[node.generateID()] = { - event: node.on('submit', this._onSubmit, this), - ajaxEvent: node.on(M.core.event.FORM_SUBMIT_AJAX, this._onSubmit, this), - ios: [] - }; - } - this._submitEvents[node.get('id')].ios.push([params]); - } - -}); -EditorAutosaveIoDispatcherInstance = new EditorAutosaveIoDispatcher(); - - -function EditorAutosaveIo() {} -EditorAutosaveIo.prototype = { - - /** - * Dispatch an IO request. - * - * This method will put the requests in a queue in order to attempt to bulk them. - * - * @param {Object} params The parameters of the request. - * @param {Object} context The context in which the callbacks are called. - * @param {Object} callbacks Object with 'success', 'complete', 'end', 'failure' and 'start' as - * optional keys defining the callbacks to call. Success and Complete - * functions will receive the response as parameter. Success and Complete - * may receive an object containing the error key, use this to confirm - * that no errors occured. - * @return {Void} - */ - autosaveIo: function(params, context, callbacks) { - EditorAutosaveIoDispatcherInstance.dispatch(params, context, callbacks); - }, - - /** - * Registers a request to be made on form submission. - * - * @param {Node} form The forum node we will listen to. - * @param {Object} params Parameters for the IO request. - * @return {Void} - */ - autosaveIoOnSubmit: function(form, params) { - EditorAutosaveIoDispatcherInstance.whenSubmit(form, params); - } - -}; -Y.Base.mix(Y.M.editor_atto.Editor, [EditorAutosaveIo]); -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @module moodle-editor_atto-editor - * @submodule clean - */ - -/** - * Functions for the Atto editor to clean the generated content. - * - * See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details. - * - * @namespace M.editor_atto - * @class EditorClean - */ - -function EditorClean() {} - -EditorClean.ATTRS = { -}; - -EditorClean.prototype = { - /** - * Clean the generated HTML content without modifying the editor content. - * - * This includes removes all YUI ids from the generated content. - * - * @return {string} The cleaned HTML content. - */ - getCleanHTML: function() { - // Clone the editor so that we don't actually modify the real content. - var editorClone = this.editor.cloneNode(true), - html; - - // Remove all YUI IDs. - Y.each(editorClone.all('[id^="yui"]'), function(node) { - node.removeAttribute('id'); - }); - - editorClone.all('.atto_control').remove(true); - html = editorClone.get('innerHTML'); - - // Revert untouched editor contents to an empty string. - var emptyContents = [ - // For FF and Chrome. - '

                              ', - '


                              ', - '
                              ', - '

                              ', - '


                              ', - '

                              ', - '


                              ', - // For IE 9 and 10. - '

                               

                              ', - '


                               

                              ', - '

                               

                              ', - '


                               

                              ', - '

                               

                              ', - '


                               

                              ' - ]; - if (emptyContents.includes(html)) { - return ''; - } - - // Remove any and all nasties from source. - return this._cleanHTML(html); - }, - - /** - * Clean the HTML content of the editor. - * - * @method cleanEditorHTML - * @chainable - */ - cleanEditorHTML: function() { - var startValue = this.editor.get('innerHTML'); - this.editor.set('innerHTML', this._cleanHTML(startValue)); - - return this; - }, - - /** - * Clean the specified HTML content and remove any content which could cause issues. - * - * @method _cleanHTML - * @private - * @param {String} content The content to clean - * @param {Boolean} deepClean If true, do a more in depth (and resource intensive) cleaning of the HTML. - * @return {String} The cleaned HTML - */ - _cleanHTML: function(content, deepClean) { - // Removing limited things that can break the page or a disallowed, like unclosed comments, style blocks, etc. - - var rules = [ - // Remove any style blocks. Some browsers do not work well with them in a contenteditable. - // Plus style blocks are not allowed in body html, except with "scoped", which most browsers don't support as of 2015. - // Reference: "http://stackoverflow.com/questions/1068280/javascript-regex-multiline-flag-doesnt-work" - {regex: /]*>[\s\S]*?<\/style>/gi, replace: ""}, - - // Remove any open HTML comment opens that are not followed by a close. This can completely break page layout. - {regex: /)/gi, replace: ""}, - - // Source: "http://www.codinghorror.com/blog/2006/01/cleaning-words-nasty-html.html" - // Remove forbidden tags for content, title, meta, style, st0-9, head, font, html, body, link. - {regex: /<\/?(?:title|meta|style|st\d|head\b|font|html|body|link)[^>]*?>/gi, replace: ""} - ]; - - content = this._filterContentWithRules(content, rules); - - if (deepClean) { - content = this._cleanHTMLLists(content); - } - - return content; - }, - - /** - * Take the supplied content and run on the supplied regex rules. - * - * @method _filterContentWithRules - * @private - * @param {String} content The content to clean - * @param {Array} rules An array of structures: [ {regex: /something/, replace: "something"}, {...}, ...] - * @return {String} The cleaned content - */ - _filterContentWithRules: function(content, rules) { - var i = 0; - for (i = 0; i < rules.length; i++) { - content = content.replace(rules[i].regex, rules[i].replace); - } - - return content; - }, - - /** - * Intercept and clean html paste events. - * - * @method pasteCleanup - * @param {Object} sourceEvent The YUI EventFacade object - * @return {Boolean} True if the passed event should continue, false if not. - */ - pasteCleanup: function(sourceEvent) { - // We only expect paste events, but we will check anyways. - if (sourceEvent.type === 'paste') { - // Register the delayed paste cleanup. We will cancel it if we register the fallback cleanup. - var delayedCleanup = this.postPasteCleanupDelayed(); - // The YUI event wrapper doesn't provide paste event info, so we need the underlying event. - var event = sourceEvent._event; - // Check if we have a valid clipboardData object in the event. - // IE has a clipboard object at window.clipboardData, but as of IE 11, it does not provide HTML content access. - if (event && event.clipboardData && event.clipboardData.getData && event.clipboardData.types) { - // Check if there is HTML type to be pasted, if we can get it, we want to scrub before insert. - var types = event.clipboardData.types; - var isHTML = false; - // Different browsers use different containers to hold the types, so test various functions. - if (typeof types.contains === 'function') { - isHTML = types.contains('text/html'); - } else if (typeof types.indexOf === 'function') { - isHTML = (types.indexOf('text/html') > -1); - } - - var content; - if (isHTML) { - // Get the clipboard content. - try { - content = event.clipboardData.getData('text/html'); - } catch (error) { - // Something went wrong. Fallback. - delayedCleanup.cancel(); - this.fallbackPasteCleanupDelayed(); - return true; - } - - // Stop the original paste. - sourceEvent.preventDefault(); - - // Scrub the paste content. - content = this._cleanPasteHTML(content); - - // Insert the content. - this.insertContentAtFocusPoint(content); - - // Update the text area. - this.updateOriginal(); - return false; - } else { - try { - // Plaintext clipboard content can only be retrieved this way. - content = event.clipboardData.getData('text'); - } catch (error) { - // Something went wrong. Fallback. - // Due to poor cross browser clipboard compatibility, the failure to find html doesn't mean it isn't there. - // Wait for the clipboard event to finish then fallback clean the entire editor. - delayedCleanup.cancel(); - this.fallbackPasteCleanupDelayed(); - return true; - } - } - } else { - // If we reached a here, this probably means the browser has limited (or no) clipboard support. - // Wait for the clipboard event to finish then fallback clean the entire editor. - this.fallbackPasteCleanupDelayed(); - return true; - } - } - - // We should never get here - we must have received a non-paste event for some reason. - // Um, just call updateOriginalDelayed() - it's safe. - this.updateOriginalDelayed(); - return true; - }, - - /** - * Calls postPasteCleanup on a short timer to allow the paste event handlers to complete, then deep clean the content. - * - * @method postPasteCleanupDelayed - * @return {object} - * @chainable - */ - postPasteCleanupDelayed: function() { - Y.soon(Y.bind(this.postPasteCleanup, this)); - - return this; - }, - - /** - * Do additional cleanup after the paste is complete. - * - * @method postPasteCleanup - * @return {object} - * @chainable - */ - postPasteCleanup: function() { - Y.log('Executing delayed post paste cleanup', 'debug', LOGNAME); - - // Save the current selection (cursor position). - var selection = window.rangy.saveSelection(); - - // Get, clean, and replace the content in the editable. - var content = this.editor.get('innerHTML'); - this.editor.set('innerHTML', this._cleanHTML(content, true)); - - // Update the textarea. - this.updateOriginal(); - - // Restore the selection (cursor position). - window.rangy.restoreSelection(selection); - - return this; - }, - - /** - * Cleanup code after a paste event if we couldn't intercept the paste content. - * - * @method fallbackPasteCleanup - * @return {object} - * @chainable - */ - fallbackPasteCleanup: function() { - Y.log('Using fallbackPasteCleanup for atto cleanup', 'debug', LOGNAME); - - // Save the current selection (cursor position). - var selection = window.rangy.saveSelection(); - - // Get, clean, and replace the content in the editable. - var content = this.editor.get('innerHTML'); - this.editor.set('innerHTML', this._cleanHTML(this._cleanPasteHTML(content), true)); - - // Update the textarea. - this.updateOriginal(); - - // Restore the selection (cursor position). - window.rangy.restoreSelection(selection); - - return this; - }, - - /** - * Calls fallbackPasteCleanup on a short timer to allow the paste event handlers to complete. - * - * @method fallbackPasteCleanupDelayed - * @chainable - */ - fallbackPasteCleanupDelayed: function() { - Y.soon(Y.bind(this.fallbackPasteCleanup, this)); - - return this; - }, - - /** - * Cleanup html that comes from WYSIWYG paste events. These are more likely to contain messy code that we should strip. - * - * @method _cleanPasteHTML - * @private - * @param {String} content The html content to clean - * @return {String} The cleaned HTML - */ - _cleanPasteHTML: function(content) { - // Return an empty string if passed an invalid or empty object. - if (!content || content.length === 0) { - return ""; - } - - // Rules that get rid of the real-nasties and don't care about normalize code (correct quotes, white spaces, etc). - var rules = [ - // Stuff that is specifically from MS Word and similar office packages. - // Remove all garbage after closing html tag. - {regex: /<\s*\/html\s*>([\s\S]+)$/gi, replace: ""}, - // Remove if comment blocks. - {regex: //gi, replace: ""}, - // Remove start and end fragment comment blocks. - {regex: //gi, replace: ""}, - // Remove any xml blocks. - {regex: /]*>[\s\S]*?<\/xml>/gi, replace: ""}, - // Remove any <\?xml> blocks. - {regex: /<\?xml[^>]*>[\s\S]*?<\\\?xml>/gi, replace: ""}, - // Remove , <\o:blah>. - {regex: /<\/?\w+:[^>]*>/gi, replace: ""} - ]; - - // Apply the first set of harsher rules. - content = this._filterContentWithRules(content, rules); - - // Apply the standard rules, which mainly cleans things like headers, links, and style blocks. - content = this._cleanHTML(content); - - // Check if the string is empty or only contains whitespace. - if (content.length === 0 || !content.match(/\S/)) { - return content; - } - - // Now we let the browser normalize the code by loading it into the DOM and then get the html back. - // This gives us well quoted, well formatted code to continue our work on. Word may provide very poorly formatted code. - var holder = document.createElement('div'); - holder.innerHTML = content; - content = holder.innerHTML; - // Free up the DOM memory. - holder.innerHTML = ""; - - // Run some more rules that care about quotes and whitespace. - rules = [ - // Get all class attributes so we can work on them. - {regex: /(<[^>]*?class\s*?=\s*?")([^>"]*)(")/gi, replace: function(match, group1, group2, group3) { - // Remove MSO classes. - group2 = group2.replace(/(?:^|[\s])[\s]*MSO[_a-zA-Z0-9\-]*/gi, ""); - // Remove Apple- classes. - group2 = group2.replace(/(?:^|[\s])[\s]*Apple-[_a-zA-Z0-9\-]*/gi, ""); - return group1 + group2 + group3; - }}, - // Remove OLE_LINK# anchors that may litter the code. - {regex: /]*?name\s*?=\s*?"OLE_LINK\d*?"[^>]*?>\s*?<\/a>/gi, replace: ""} - ]; - - // Clean all style attributes from the text. - content = this._cleanStyles(content); - - // Apply the rules. - content = this._filterContentWithRules(content, rules); - - // Reapply the standard cleaner to the content. - content = this._cleanHTML(content); - - // Clean unused spans out of the content. - content = this._cleanSpans(content); - - return content; - }, - - /** - * Clean all inline styles from pasted text. - * - * This code intentionally doesn't use YUI Nodes. YUI was quite a bit slower at this, so using raw DOM objects instead. - * - * @method _cleanStyles - * @private - * @param {String} content The content to clean - * @return {String} The cleaned HTML - */ - _cleanStyles: function(content) { - var holder = document.createElement('div'); - holder.innerHTML = content; - var elementsWithStyle = holder.querySelectorAll('[style]'); - var i = 0; - - for (i = 0; i < elementsWithStyle.length; i++) { - elementsWithStyle[i].removeAttribute('style'); - } - - var elementsWithClass = holder.querySelectorAll('[class]'); - for (i = 0; i < elementsWithClass.length; i++) { - elementsWithClass[i].removeAttribute('class'); - } - - return holder.innerHTML; - }, - /** - * Clean empty or un-unused spans from passed HTML. - * - * This code intentionally doesn't use YUI Nodes. YUI was quite a bit slower at this, so using raw DOM objects instead. - * - * @method _cleanSpans - * @private - * @param {String} content The content to clean - * @return {String} The cleaned HTML - */ - _cleanSpans: function(content) { - // Return an empty string if passed an invalid or empty object. - if (!content || content.length === 0) { - return ""; - } - // Check if the string is empty or only contains whitespace. - if (content.length === 0 || !content.match(/\S/)) { - return content; - } - - var rules = [ - // Remove unused class, style, or id attributes. This will make empty tag detection easier later. - {regex: /(<[^>]*?)(?:[\s]*(?:class|style|id)\s*?=\s*?"\s*?")+/gi, replace: "$1"} - ]; - // Apply the rules. - content = this._filterContentWithRules(content, rules); - - // Reference: "http://stackoverflow.com/questions/8131396/remove-nested-span-without-id" - - // This is better to run detached from the DOM, so the browser doesn't try to update on each change. - var holder = document.createElement('div'); - holder.innerHTML = content; - var spans = holder.getElementsByTagName('span'); - - // Since we will be removing elements from the list, we should copy it to an array, making it static. - var spansarr = Array.prototype.slice.call(spans, 0); - - spansarr.forEach(function(span) { - if (!span.hasAttributes()) { - // If no attributes (id, class, style, etc), this span is has no effect. - // Move each child (if they exist) to the parent in place of this span. - while (span.firstChild) { - span.parentNode.insertBefore(span.firstChild, span); - } - - // Remove the now empty span. - span.parentNode.removeChild(span); - } - }); - - return holder.innerHTML; - }, - - /** - * This is a function that searches for, and attempts to correct certain issues with ul/ol html lists. - * This is needed because these lists are used heavily in page layout, and content with bad tags can - * lead to broke course pages. - * - * The theory of operation here is to linearly process the incoming content, counting the opening and closing - * of list tags, and determining when there is a mismatch. - * - * The specific issues this should be able to correct are: - * - Orphaned li elements will be wrapped in a set of ul tags. - * - li elements inside li elements. - * - An extra closing ul, or ol tag will be discarded. - * - An extra closing li tag will have an opening tag added if appropriate, or will be discarded. - * - If there is an unmatched list open tag, a matching close tag will be inserted. - * - * It does it's best to match the case of corrected tags. Even though not required by html spec, - * it seems like the safer route. - * - * A note on parent elements of li. This code assumes that li must have a ol or ul parent. - * There are two other potential other parents of li. They are menu and dir. The dir tag was deprecated in - * HTML4, and removed in HTML5. The menu tag is experimental as of this writing, and basically doesn't work - * in any browsers, even Firefox, which theoretically has limited support for it. If other parents of li - * become viable, they will need to be added to this code. - * - * @method _cleanHTMLLists - * @private - * @param {String} content The content to clean - * @return {String} The cleaned content - */ - _cleanHTMLLists: function(content) { - var output = '', - toProcess = content, - match = null, - openTags = [], - currentTag = null, - previousTag = null; - - // Use a regular expression to find the next open or close li, ul, or ol tag. - // Keep going until there are no more matching tags left. - // This expression looks for whole words by employing the word boundary (\b) metacharacter. - while ((match = toProcess.match(/<(\/?)(li|ul|ol)\b[^>]*>/i))) { - currentTag = { - tag: match[2], - tagLowerCase: match[2].toLowerCase(), - fullTag: match[0], - isOpen: (match[1].length == 1) ? false : true - }; - - // Get the most recent open tag. - previousTag = (openTags.length) ? openTags[openTags.length - 1] : null; - - // Slice up the content based on the match and add content before the match to output. - output += toProcess.slice(0, match.index); - toProcess = toProcess.slice(match.index + match[0].length); - - // Now the full content is in output + currentTag.fullTag + toProcess. When making fixes, it is best to push the fix and - // fullTag back onto the front or toProcess, then restart the loop. This allows processing to follow the normal path - // most often. But sometimes we will need to modify output to insert or remove tags in the already complete code. - - if (currentTag.isOpen) { - // We are at the opening phase of a tag. - // We have to do special processing for list items, as they can only be children of ul and ol tags. - if (currentTag.tagLowerCase === 'li') { - if (!previousTag) { - // This means we have are opening a li, but aren't in a list. This is not allowed! - - // We are going to check for the count of open and close ol tags ahead to decide what to do. - var closeCount = (toProcess.match(/<\/(ol)[ >]/ig) || []).length; - var openCount = (toProcess.match(/<(ol)[ >]/ig) || []).length; - - if (closeCount > openCount) { - // There are more close ol's ahead than opens ahead. So open the ol and try again. - Y.log('Adding an opening ol for orphan li', 'debug', LOGNAME); - toProcess = '
                                ' + currentTag.fullTag + toProcess; - continue; - } - - // For the other cases, just open a ul and try again. Later the closing ul will get matched if it exists, - // or if it doesn't one will automatically get inserted. - Y.log('Adding an opening ul for orphan li', 'debug', LOGNAME); - toProcess = '
                                  ' + currentTag.fullTag + toProcess; - continue; - } - - if (previousTag.tagLowerCase === 'li') { - // You aren't allowed to nest li tags. Close the current one before starting the new one. - Y.log('Adding a closing ' + previousTag.tag + ' before opening a new one.', 'debug', LOGNAME); - toProcess = '' + currentTag.fullTag + toProcess; - continue; - } - - // Previous tag must be a list at this point, so we can continue. - } - - // If we made it this far, record the tag to the open tags list. - openTags.push({ - tag: currentTag.tag, - tagLowerCase: currentTag.tagLowerCase, - position: output.length, - length: currentTag.fullTag.length - }); - } else { - // We are processing a closing tag. - - if (openTags.length == 0) { - // We are closing a tag that isn't open. That's a problem. Just discarding should be safe. - Y.log('Discarding extra ' + currentTag.fullTag + ' tag.', 'debug', LOGNAME); - continue; - } - - if (previousTag.tagLowerCase === currentTag.tagLowerCase) { - // Closing a tag that matches the open tag. This is the nominal case. Pop it off, and update previousTag. - if (currentTag.tag != previousTag.tag) { - // This would mean cases don't match between the opening and closing tag. - // We are going to swap them to match, even though not required. - currentTag.fullTag = currentTag.fullTag.replace(currentTag.tag, previousTag.tag); - } - - openTags.pop(); - previousTag = (openTags.length) ? openTags[openTags.length - 1] : null; - } else { - // We are closing a tag that isn't the most recent open one open, so we have a mismatch. - if (currentTag.tagLowerCase === 'li' && previousTag.liEnd && (previousTag.liEnd < output.length)) { - // We are closing an unopened li, but the parent list has complete li tags more than 0 chars ago. - // Assume we are missing an open li at the end of the previous li, and insert there. - Y.log('Inserting opening ' + currentTag.tag + ' after previous li.', 'debug', LOGNAME); - output = this._insertString(output, '<' + currentTag.tag + '>', previousTag.liEnd); - } else if (currentTag.tagLowerCase === 'li' && !previousTag.liEnd && - ((previousTag.position + previousTag.length) < output.length)) { - // We are closing an unopened li, and the parent has no previous lis in it, but opened more than 0 - // chars ago. Assume we are missing a starting li, and insert it right after the list opened. - Y.log('Inserting opening ' + currentTag.tag + ' at start of parent.', 'debug', LOGNAME); - output = this._insertString(output, '<' + currentTag.tag + '>', previousTag.position + previousTag.length); - } else if (previousTag.tagLowerCase === 'li') { - // We must be trying to close a ul/ol while in a li. Just assume we are missing a closing li. - Y.log('Adding a closing ' + previousTag.tag + ' before closing ' + currentTag.tag + '.', 'debug', LOGNAME); - toProcess = '' + currentTag.fullTag + toProcess; - continue; - } else { - // Here we must be trying to close a tag that isn't open, or is open higher up. Just discard. - // If there ends up being a missing close tag later on, that will get fixed separately. - Y.log('Discarding incorrect ' + currentTag.fullTag + '.', 'debug', LOGNAME); - continue; - } - } - - // If we have a valid closing li tag, and a list, record where the li ended. - if (currentTag.tagLowerCase === 'li' && previousTag) { - previousTag.liEnd = output.length + currentTag.fullTag.length; - } - - } - - // Now we can add the tag to the output. - output += currentTag.fullTag; - } - - // Add anything left in toProcess to the output. - output += toProcess; - - // Anything still in the openTags list are extra and need to be dealt with. - if (openTags.length) { - // Work on the list in reverse order so positions stay correct. - while ((currentTag = openTags.pop())) { - if (currentTag.liEnd) { - // We have a position for the last list item in this element. Insert the closing it after that. - output = this._insertString(output, '', currentTag.liEnd); - Y.log('Adding closing ' + currentTag.tag + ' based on last li location.', 'debug', LOGNAME); - } else { - // If there weren't any children list items, then we should just remove the tag where it started. - // This will also remote an open li tag that runs to the end of the content, since it has no children lis. - output = output.slice(0, currentTag.position) + output.slice(currentTag.position + currentTag.length); - Y.log('Removing opening ' + currentTag.fullTag + ' because it was missing closing.', 'debug', LOGNAME); - } - } - } - - return output; - }, - - /** - * Insert a string in the middle of an existing string at the specified location. - * - * @method _insertString - * @param {String} content The subject of the insertion. - * @param {String} insert The string that will be inserted. - * @param {Number} position The location to make the insertion. - * @return {String} The string with the new content inserted. - */ - _insertString: function(content, insert, position) { - return content.slice(0, position) + insert + content.slice(position); - } -}; - -Y.Base.mix(Y.M.editor_atto.Editor, [EditorClean]); -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @module moodle-editor_atto-editor - * @submodule commands - */ - -/** - * Selection functions for the Atto editor. - * - * See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details. - * - * @namespace M.editor_atto - * @class EditorCommand - */ - -function EditorCommand() {} - -EditorCommand.ATTRS = { -}; - -EditorCommand.prototype = { - /** - * Applies a callback method to editor if selection is uncollapsed or waits for input to select first. - * @method applyFormat - * @param e EventTarget Event to be passed to callback if selection is uncollapsed - * @param method callback A callback method which changes editor when text is selected. - * @param object context Context to be used for callback method - * @param array args Array of arguments to pass to callback - */ - applyFormat: function(e, callback, context, args) { - function handleInsert(e, callback, context, args, anchorNode, anchorOffset) { - // After something is inputed, select it and apply the formating function. - Y.soon(Y.bind(function(e, callback, context, args, anchorNode, anchorOffset) { - var selection = window.rangy.getSelection(); - - // Set the start of the selection to where it was when the method was first called. - var range = selection.getRangeAt(0); - range.setStart(anchorNode, anchorOffset); - selection.setSingleRange(range); - - // Now apply callback to the new text that is selected. - callback.apply(context, [e, args]); - - // Collapse selection so cursor is at end of inserted material. - selection.collapseToEnd(); - - // Save save selection and editor contents. - this.saveSelection(); - this.updateOriginal(); - }, this, e, callback, context, args, anchorNode, anchorOffset)); - } - - // Set default context for the method. - context = context || this; - - // Check whether range is collapsed. - var selection = window.rangy.getSelection(); - - if (selection.isCollapsed) { - // Selection is collapsed so listen for input into editor. - var handle = this.editor.once('input', handleInsert, this, callback, context, args, - selection.anchorNode, selection.anchorOffset); - - // Cancel if selection changes before input. - this.editor.onceAfter(['click', 'selectstart'], handle.detach, handle); - - return; - } - - // The range is not collapsed; so apply callback method immediately. - callback.apply(context, [e, args]); - - // Save save selection and editor contents. - this.saveSelection(); - this.updateOriginal(); - }, - - /** - * Replaces all the tags in a node list with new type. - * @method replaceTags - * @param NodeList nodelist - * @param String tag - */ - replaceTags: function(nodelist, tag) { - // We mark elements in the node list for iterations. - nodelist.setAttribute('data-iterate', true); - var node = this.editor.one('[data-iterate="true"]'); - while (node) { - var clone = Y.Node.create('<' + tag + ' />') - .setAttrs(node.getAttrs()) - .removeAttribute('data-iterate'); - // Copy class and style if not blank. - if (node.getAttribute('style')) { - clone.setAttribute('style', node.getAttribute('style')); - } - if (node.getAttribute('class')) { - clone.setAttribute('class', node.getAttribute('class')); - } - // We use childNodes here because we are interested in both type 1 and 3 child nodes. - var children = node.getDOMNode().childNodes; - var child; - child = children[0]; - while (typeof child !== "undefined") { - clone.append(child); - child = children[0]; - } - node.replace(clone); - node = this.editor.one('[data-iterate="true"]'); - } - }, - - /** - * Change all tags with given type to a span with CSS class attribute. - * @method changeToCSS - * @param String tag Tag type to be changed to span - * @param String markerClass CSS class that corresponds to desired tag - */ - changeToCSS: function(tag, markerClass) { - // Save the selection. - var selection = window.rangy.saveSelection(); - - // Remove display:none from rangy markers so browser doesn't delete them. - this.editor.all('.rangySelectionBoundary').setStyle('display', null); - - // Replace tags with CSS classes. - this.editor.all(tag).addClass(markerClass); - this.replaceTags(this.editor.all('.' + markerClass), 'span'); - - // Restore selection and toggle class. - window.rangy.restoreSelection(selection); - }, - - /** - * Change spans with CSS classes in editor into elements with given tag. - * @method changeToCSS - * @param String markerClass CSS class that corresponds to desired tag - * @param String tag New tag type to be created - */ - changeToTags: function(markerClass, tag) { - // Save the selection. - var selection = window.rangy.saveSelection(); - - // Remove display:none from rangy markers so browser doesn't delete them. - this.editor.all('.rangySelectionBoundary').setStyle('display', null); - - // Replace spans with given tag. - this.replaceTags(this.editor.all('span[class="' + markerClass + '"]'), tag); - this.editor.all(tag + '[class="' + markerClass + '"]').removeAttribute('class'); - this.editor.all('.' + markerClass).each(function(n) { - n.wrap('<' + tag + '/>'); - n.removeClass(markerClass); - }); - - // Remove CSS classes. - this.editor.all('[class="' + markerClass + '"]').removeAttribute('class'); - this.editor.all(tag).removeClass(markerClass); - - // Restore selection. - window.rangy.restoreSelection(selection); - } -}; - -Y.Base.mix(Y.M.editor_atto.Editor, [EditorCommand]); -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * @module moodle-editor_atto-editor - * @submodule toolbar - */ - -/** - * Toolbar functions for the Atto editor. - * - * See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details. - * - * @namespace M.editor_atto - * @class EditorToolbar - */ - -function EditorToolbar() {} - -EditorToolbar.ATTRS = { -}; - -EditorToolbar.prototype = { - /** - * A reference to the toolbar Node. - * - * @property toolbar - * @type Node - */ - toolbar: null, - - /** - * A reference to any currently open menus in the toolbar. - * - * @property openMenus - * @type Array - */ - openMenus: null, - - /** - * Setup the toolbar on the editor. - * - * @method setupToolbar - * @chainable - */ - setupToolbar: function() { - this.toolbar = Y.Node.create('