From a34c8c8233859711f1971bed9af658a63b9bb96d Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Fri, 23 Mar 2018 15:30:20 -0400 Subject: [PATCH] Drop remaining coffee use This basically commits the transpiled CoffeeScript JS (with minor cleanup) and removes coffee build support. A tiny amount of support for xblocks exists, because external users may have xblocks with coffee. But no coffee in our tree anyway. --- .eslintignore | 52 +- cms/envs/common.py | 9 +- cms/static/cms/js/require-config.js | 6 +- cms/static/cms/js/spec/main.js | 30 +- cms/static/cms/js/spec/main_squire.js | 10 +- cms/static/js/models/metadata.js | 2 +- .../{coffee => js}/spec/models/course_spec.js | 0 .../spec/models/metadata_spec.js | 0 .../spec/models/section_spec.js | 0 .../models/settings_course_grader_spec.js | 0 .../spec/models/settings_grading_spec.js | 0 .../spec/models/textbook_spec.js | 0 .../{coffee => js}/spec/models/upload_spec.js | 0 .../spec/views/assets_squire_spec.js} | 0 .../spec/views/course_info_spec.js | 0 .../spec/views/metadata_edit_spec.js | 0 .../spec/views/textbook_spec.js | 0 .../{coffee => js}/spec/views/upload_spec.js | 0 cms/static/karma_cms.conf.js | 2 - cms/static/karma_cms_squire.conf.js | 3 - .../test_files/js/mersenne-twister-min.js | 1 + .../lib/xmodule/xmodule/annotatable_module.py | 6 +- .../lib/xmodule/xmodule/conditional_module.py | 4 +- common/lib/xmodule/xmodule/editing_module.py | 10 +- common/lib/xmodule/xmodule/html_module.py | 6 +- .../xmodule/xmodule/imageannotation_module.py | 6 +- .../xmodule/xmodule/js/karma_xmodule.conf.js | 2 +- .../xmodule/js/spec/capa/display_spec.js | 2 +- .../xmodule/js/spec/problem/edit_spec_hint.js | 2 - common/lib/xmodule/xmodule/js/src/.gitignore | 16 - .../xmodule/js/src/annotatable/display.js | 704 +++-- .../xmodule/xmodule/js/src/capa/schematic.js | 2 + .../xmodule/js/src/conditional/display.js | 98 +- .../xmodule/js/src/discussion/display.js | 25 +- .../xmodule/xmodule/js/src/html/display.js | 39 +- .../lib/xmodule/xmodule/js/src/html/edit.js | 2426 ++++++++++------- .../xmodule/xmodule/js/src/raw/edit/json.js | 42 +- .../xmodule/js/src/raw/edit/metadata-only.js | 27 +- .../xmodule/xmodule/js/src/raw/edit/xml.js | 39 +- .../xmodule/xmodule/js/src/sequence/edit.js | 18 +- .../xmodule/js/src/tabs/tabs-aggregator.js | 332 ++- .../xmodule/xmodule/js/src/vertical/edit.js | 18 +- .../xmodule/xmodule/library_content_module.py | 2 +- common/lib/xmodule/xmodule/seq_module.py | 2 +- .../xmodule/xmodule/textannotation_module.py | 3 +- .../xmodule/xmodule/videoannotation_module.py | 6 +- common/static/coffee/src/.gitignore | 1 - common/static/common/js/karma.common.conf.js | 1 - .../static/common/js/spec/main_requirejs.js | 2 +- common/static/css/tinymce-studio-content.css | 2 +- .../spec/jquery.immediateDescendents_spec.js | 0 common/static/js/src/ajax_prefix.js | 38 +- .../js/src/jquery.immediateDescendents.js | 34 +- common/static/js/src/xproblem.js | 83 +- common/static/karma_common.conf.js | 6 +- common/static/karma_common_requirejs.conf.js | 1 - docs/static_assets.rst | 8 +- docs/testing.rst | 12 +- lms/djangoapps/instructor/views/api.py | 2 +- lms/djangoapps/notes/README.md | 2 +- lms/envs/common.py | 46 +- lms/static/coffee/README.md | 44 - lms/static/coffee/src/.gitignore | 1 - lms/static/js/calculator.js | 496 ++-- lms/static/js/courseware.js | 53 +- lms/static/js/customwmd.js | 428 +-- lms/static/js/feedback_form.js | 33 +- .../{coffee => js}/fixtures/calculator.html | 0 .../fixtures/feedback_form.html | 0 lms/static/{coffee => js}/fixtures/items.json | 0 .../fixtures/staff_grading.html | 0 lms/static/{coffee => js}/fixtures/tab.html | 0 lms/static/js/histogram.js | 100 +- .../instructor_dashboard.js | 4 +- lms/static/js/main.js | 94 +- lms/static/js/mathjax_accessible.js | 54 +- lms/static/js/mathjax_delay_renderer.js | 182 +- lms/static/js/modules/tab.js | 75 +- lms/static/{coffee/src => js}/navigation.js | 4 +- lms/static/js/notes.js | 265 +- .../{coffee => js}/spec/calculator_spec.js | 0 .../{coffee => js}/spec/courseware_spec.js | 0 .../{coffee => js}/spec/feedback_form_spec.js | 0 lms/static/{coffee => js}/spec/helper.js | 0 .../{coffee => js}/spec/histogram_spec.js | 0 .../{coffee => js}/spec/modules/tab_spec.js | 0 .../{coffee => js}/spec/requirejs_spec.js | 0 lms/static/karma_lms.conf.js | 1 - lms/static/karma_lms_coffee.conf.js | 71 - lms/static/lms/js/build.js | 2 +- lms/static/lms/js/spec/main.js | 10 +- .../instructor_dashboard_2.html | 8 +- package-lock.json | 25 - package.json | 2 - pavelib/assets.py | 54 +- pavelib/i18n.py | 1 - pavelib/paver_tests/test_js_test.py | 5 - pavelib/paver_tests/test_servers.py | 8 +- pavelib/utils/envs.py | 2 - pavelib/utils/test/suites/js_suite.py | 3 +- requirements/system/ubuntu/apt-packages.txt | 1 - scripts/xsslint/tests/templates/test.coffee | 2 - scripts/xsslint/tests/test_main.py | 2 - scripts/xsslint/xsslint/default_config.py | 4 +- scripts/xsslint/xsslint/linters.py | 7 +- scripts/xsslint_config.py | 4 +- webpack.common.config.js | 5 +- 107 files changed, 3542 insertions(+), 2698 deletions(-) rename cms/static/{coffee => js}/spec/models/course_spec.js (100%) rename cms/static/{coffee => js}/spec/models/metadata_spec.js (100%) rename cms/static/{coffee => js}/spec/models/section_spec.js (100%) rename cms/static/{coffee => js}/spec/models/settings_course_grader_spec.js (100%) rename cms/static/{coffee => js}/spec/models/settings_grading_spec.js (100%) rename cms/static/{coffee => js}/spec/models/textbook_spec.js (100%) rename cms/static/{coffee => js}/spec/models/upload_spec.js (100%) rename cms/static/{coffee/spec/views/assets_spec.js => js/spec/views/assets_squire_spec.js} (100%) rename cms/static/{coffee => js}/spec/views/course_info_spec.js (100%) rename cms/static/{coffee => js}/spec/views/metadata_edit_spec.js (100%) rename cms/static/{coffee => js}/spec/views/textbook_spec.js (100%) rename cms/static/{coffee => js}/spec/views/upload_spec.js (100%) delete mode 100644 common/lib/xmodule/xmodule/js/src/.gitignore delete mode 100644 common/static/coffee/src/.gitignore rename common/static/{coffee => js}/spec/jquery.immediateDescendents_spec.js (100%) delete mode 100644 lms/static/coffee/README.md delete mode 100644 lms/static/coffee/src/.gitignore rename lms/static/{coffee => js}/fixtures/calculator.html (100%) rename lms/static/{coffee => js}/fixtures/feedback_form.html (100%) rename lms/static/{coffee => js}/fixtures/items.json (100%) rename lms/static/{coffee => js}/fixtures/staff_grading.html (100%) rename lms/static/{coffee => js}/fixtures/tab.html (100%) rename lms/static/{coffee/src => js}/navigation.js (88%) rename lms/static/{coffee => js}/spec/calculator_spec.js (100%) rename lms/static/{coffee => js}/spec/courseware_spec.js (100%) rename lms/static/{coffee => js}/spec/feedback_form_spec.js (100%) rename lms/static/{coffee => js}/spec/helper.js (100%) rename lms/static/{coffee => js}/spec/histogram_spec.js (100%) rename lms/static/{coffee => js}/spec/modules/tab_spec.js (100%) rename lms/static/{coffee => js}/spec/requirejs_spec.js (100%) delete mode 100644 lms/static/karma_lms_coffee.conf.js delete mode 100644 scripts/xsslint/tests/templates/test.coffee diff --git a/.eslintignore b/.eslintignore index 8277bea27284..60f59bde2a8e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -20,13 +20,6 @@ test_root/staticfiles common/static/xmodule -# Coffeescript directories (don't lint autogenerated files) -cms/static/coffee -lms/static/coffee -common/static/coffee -common/lib/capa/capa/tests/test_files/js - - # Symlinks into common/lib/xmodule/xmodule/js cms/static/xmodule_js lms/static/xmodule_js @@ -36,27 +29,40 @@ lms/static/xmodule_js cms/djangoapps/pipeline_js/templates -# This directory is about half Coffee and half JS, things get messy here so just ignore all existing coffee paths +# These are es2015 spec files that used to be in an ignored path. +# Now they live with the rest of the code, but we want to ignore them +# until the surrounding code is es2015 and we have a chance to clean them. +# We need to ignore them here, because es2015 will cause a parse error +# even if we add an eslint-disable line to the file. +cms/static/js/spec/models/course_spec.js +cms/static/js/spec/models/metadata_spec.js +cms/static/js/spec/models/section_spec.js +cms/static/js/spec/models/settings_course_grader_spec.js +cms/static/js/spec/models/settings_grading_spec.js +cms/static/js/spec/models/textbook_spec.js +cms/static/js/spec/models/upload_spec.js +cms/static/js/spec/views/assets_squire_spec.js +cms/static/js/spec/views/course_info_spec.js +cms/static/js/spec/views/metadata_edit_spec.js +cms/static/js/spec/views/textbook_spec.js +cms/static/js/spec/views/upload_spec.js +common/lib/capa/capa/tests/test_files/js/test_problem_display.js +common/lib/capa/capa/tests/test_files/js/test_problem_generator.js +common/lib/capa/capa/tests/test_files/js/test_problem_grader.js +common/lib/capa/capa/tests/test_files/js/xproblem.js common/lib/xmodule/xmodule/js/spec/annotatable/display_spec.js common/lib/xmodule/xmodule/js/spec/capa/display_spec.js common/lib/xmodule/xmodule/js/spec/html/edit_spec.js -common/lib/xmodule/xmodule/js/spec/problem/edit_spec.js common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.js +common/lib/xmodule/xmodule/js/spec/problem/edit_spec.js common/lib/xmodule/xmodule/js/spec/tabs/edit.js +lms/static/js/spec/calculator_spec.js +lms/static/js/spec/courseware_spec.js +lms/static/js/spec/feedback_form_spec.js +lms/static/js/spec/helper.js +lms/static/js/spec/histogram_spec.js +lms/static/js/spec/modules/tab_spec.js +lms/static/js/spec/requirejs_spec.js -common/lib/xmodule/xmodule/js/src/annotatable/display.js -common/lib/xmodule/xmodule/js/src/conditional/display.js -common/lib/xmodule/xmodule/js/src/discussion/display.js -common/lib/xmodule/xmodule/js/src/html/display.js -common/lib/xmodule/xmodule/js/src/html/edit.js -common/lib/xmodule/xmodule/js/src/raw/edit/json.js -common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js -common/lib/xmodule/xmodule/js/src/raw/edit/xml.js -common/lib/xmodule/xmodule/js/src/sequence/edit.js -common/lib/xmodule/xmodule/js/src/tabs/tabs-aggregator.js -common/lib/xmodule/xmodule/js/src/vertical/edit.js - -# This file is responsible for almost half of the repo's total issues. -common/lib/xmodule/xmodule/js/src/capa/schematic.js !**/.eslintrc.js diff --git a/cms/envs/common.py b/cms/envs/common.py index 93f26be69795..3f2fceef815d 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -810,10 +810,7 @@ }, } -PIPELINE_COMPILERS = ( - 'pipeline.compilers.coffee.CoffeeScriptCompiler', -) - +PIPELINE_COMPILERS = () PIPELINE_CSS_COMPRESSOR = None PIPELINE_JS_COMPRESSOR = None @@ -829,10 +826,6 @@ "sass/*/*.scss", "sass/*/*/*.scss", "sass/*/*/*/*.scss", - "coffee/*.coffee", - "coffee/*/*.coffee", - "coffee/*/*/*.coffee", - "coffee/*/*/*/*.coffee", # Ignore tests "spec", diff --git a/cms/static/cms/js/require-config.js b/cms/static/cms/js/require-config.js index 14afba77f34f..b030c8a330cb 100644 --- a/cms/static/cms/js/require-config.js +++ b/cms/static/cms/js/require-config.js @@ -104,7 +104,7 @@ 'jquery.fileupload-validate': 'js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', 'jquery.iframe-transport': 'js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', 'jquery.inputnumber': 'js/vendor/html5-input-polyfills/number-polyfill', - 'jquery.immediateDescendents': 'coffee/src/jquery.immediateDescendents', + 'jquery.immediateDescendents': 'js/src/jquery.immediateDescendents', 'datepair': 'js/vendor/timepicker/datepair', 'date': 'js/vendor/date', moment: 'common/js/vendor/moment-with-locales', @@ -304,11 +304,11 @@ deps: ['xblock/core'] }, 'cms/js/main': { - deps: ['coffee/src/ajax_prefix'] + deps: ['js/src/ajax_prefix'] }, 'js/src/logger': { exports: 'Logger', - deps: ['coffee/src/ajax_prefix'] + deps: ['js/src/ajax_prefix'] }, // the following are all needed for annotation tools diff --git a/cms/static/cms/js/spec/main.js b/cms/static/cms/js/spec/main.js index af109088aafa..1b3344f8d7f6 100644 --- a/cms/static/cms/js/spec/main.js +++ b/cms/static/cms/js/spec/main.js @@ -44,7 +44,7 @@ 'jquery.fileupload-validate': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', // eslint-disable-line max-len 'jquery.iframe-transport': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', // eslint-disable-line max-len 'jquery.inputnumber': 'xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill', - 'jquery.immediateDescendents': 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents', + 'jquery.immediateDescendents': 'xmodule_js/common_static/js/src/jquery.immediateDescendents', 'jquery.simulate': 'xmodule_js/common_static/js/vendor/jquery.simulate', 'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair', 'date': 'xmodule_js/common_static/js/vendor/date', @@ -72,7 +72,7 @@ 'mock-ajax': 'xmodule_js/common_static/js/vendor/mock-ajax', mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len 'youtube': '//www.youtube.com/player_api?noext', - 'coffee/src/ajax_prefix': 'xmodule_js/common_static/coffee/src/ajax_prefix', + 'js/src/ajax_prefix': 'xmodule_js/common_static/js/src/ajax_prefix', 'js/spec/test_utils': 'js/spec/test_utils' }, shim: { @@ -218,9 +218,9 @@ deps: ['jquery'] }, 'cms/js/main': { - deps: ['coffee/src/ajax_prefix'] + deps: ['js/src/ajax_prefix'] }, - 'coffee/src/ajax_prefix': { + 'js/src/ajax_prefix': { deps: ['jquery'] } } @@ -231,17 +231,17 @@ testFiles = [ 'cms/js/spec/main_spec', 'cms/js/spec/xblock/cms.runtime.v1_spec', - 'coffee/spec/models/course_spec', - 'coffee/spec/models/metadata_spec', - 'coffee/spec/models/section_spec', - 'coffee/spec/models/settings_course_grader_spec', - 'coffee/spec/models/settings_grading_spec', - 'coffee/spec/models/textbook_spec', - 'coffee/spec/models/upload_spec', - 'coffee/spec/views/course_info_spec', - 'coffee/spec/views/metadata_edit_spec', - 'coffee/spec/views/textbook_spec', - 'coffee/spec/views/upload_spec', + 'js/spec/models/course_spec', + 'js/spec/models/metadata_spec', + 'js/spec/models/section_spec', + 'js/spec/models/settings_course_grader_spec', + 'js/spec/models/settings_grading_spec', + 'js/spec/models/textbook_spec', + 'js/spec/models/upload_spec', + 'js/spec/views/course_info_spec', + 'js/spec/views/metadata_edit_spec', + 'js/spec/views/textbook_spec', + 'js/spec/views/upload_spec', 'js/spec/video/transcripts/utils_spec', 'js/spec/video/transcripts/editor_spec', 'js/spec/video/transcripts/videolist_spec', diff --git a/cms/static/cms/js/spec/main_squire.js b/cms/static/cms/js/spec/main_squire.js index 90d1d6b8d62d..3ae2b2bf3245 100644 --- a/cms/static/cms/js/spec/main_squire.js +++ b/cms/static/cms/js/spec/main_squire.js @@ -27,7 +27,7 @@ 'jquery.fileupload-validate': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', // eslint-disable-line max-len 'jquery.iframe-transport': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', // eslint-disable-line max-len 'jquery.inputnumber': 'xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill', - 'jquery.immediateDescendents': 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents', + 'jquery.immediateDescendents': 'xmodule_js/common_static/js/src/jquery.immediateDescendents', 'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair', 'date': 'xmodule_js/common_static/js/vendor/date', 'text': 'xmodule_js/common_static/js/vendor/requirejs/text', @@ -49,7 +49,7 @@ 'URI': 'xmodule_js/common_static/js/vendor/URI.min', mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len 'youtube': '//www.youtube.com/player_api?noext', - 'coffee/src/ajax_prefix': 'xmodule_js/common_static/coffee/src/ajax_prefix' + 'js/src/ajax_prefix': 'xmodule_js/common_static/js/src/ajax_prefix' }, shim: { 'gettext': { @@ -174,9 +174,9 @@ deps: ['xblock/core'] }, 'cms/js/main': { - deps: ['coffee/src/ajax_prefix'] + deps: ['js/src/ajax_prefix'] }, - 'coffee/src/ajax_prefix': { + 'js/src/ajax_prefix': { deps: ['jquery'] } } @@ -185,7 +185,7 @@ jasmine.getFixtures().fixturesPath = '/base/templates'; testFiles = [ - 'coffee/spec/views/assets_spec', + 'js/spec/views/assets_squire_spec', 'js/spec/video/translations_editor_spec', 'js/spec/video/file_uploader_editor_spec', 'js/spec/models/group_configuration_spec' diff --git a/cms/static/js/models/metadata.js b/cms/static/js/models/metadata.js index 137286100519..68aef82b270e 100644 --- a/cms/static/js/models/metadata.js +++ b/cms/static/js/models/metadata.js @@ -1,7 +1,7 @@ define(['backbone'], function(Backbone) { /** * Model used for metadata setting editors. This model does not do its own saving, - * as that is done by module_edit.coffee. + * as that is done by module_edit.js. */ var Metadata = Backbone.Model.extend({ defaults: { diff --git a/cms/static/coffee/spec/models/course_spec.js b/cms/static/js/spec/models/course_spec.js similarity index 100% rename from cms/static/coffee/spec/models/course_spec.js rename to cms/static/js/spec/models/course_spec.js diff --git a/cms/static/coffee/spec/models/metadata_spec.js b/cms/static/js/spec/models/metadata_spec.js similarity index 100% rename from cms/static/coffee/spec/models/metadata_spec.js rename to cms/static/js/spec/models/metadata_spec.js diff --git a/cms/static/coffee/spec/models/section_spec.js b/cms/static/js/spec/models/section_spec.js similarity index 100% rename from cms/static/coffee/spec/models/section_spec.js rename to cms/static/js/spec/models/section_spec.js diff --git a/cms/static/coffee/spec/models/settings_course_grader_spec.js b/cms/static/js/spec/models/settings_course_grader_spec.js similarity index 100% rename from cms/static/coffee/spec/models/settings_course_grader_spec.js rename to cms/static/js/spec/models/settings_course_grader_spec.js diff --git a/cms/static/coffee/spec/models/settings_grading_spec.js b/cms/static/js/spec/models/settings_grading_spec.js similarity index 100% rename from cms/static/coffee/spec/models/settings_grading_spec.js rename to cms/static/js/spec/models/settings_grading_spec.js diff --git a/cms/static/coffee/spec/models/textbook_spec.js b/cms/static/js/spec/models/textbook_spec.js similarity index 100% rename from cms/static/coffee/spec/models/textbook_spec.js rename to cms/static/js/spec/models/textbook_spec.js diff --git a/cms/static/coffee/spec/models/upload_spec.js b/cms/static/js/spec/models/upload_spec.js similarity index 100% rename from cms/static/coffee/spec/models/upload_spec.js rename to cms/static/js/spec/models/upload_spec.js diff --git a/cms/static/coffee/spec/views/assets_spec.js b/cms/static/js/spec/views/assets_squire_spec.js similarity index 100% rename from cms/static/coffee/spec/views/assets_spec.js rename to cms/static/js/spec/views/assets_squire_spec.js diff --git a/cms/static/coffee/spec/views/course_info_spec.js b/cms/static/js/spec/views/course_info_spec.js similarity index 100% rename from cms/static/coffee/spec/views/course_info_spec.js rename to cms/static/js/spec/views/course_info_spec.js diff --git a/cms/static/coffee/spec/views/metadata_edit_spec.js b/cms/static/js/spec/views/metadata_edit_spec.js similarity index 100% rename from cms/static/coffee/spec/views/metadata_edit_spec.js rename to cms/static/js/spec/views/metadata_edit_spec.js diff --git a/cms/static/coffee/spec/views/textbook_spec.js b/cms/static/js/spec/views/textbook_spec.js similarity index 100% rename from cms/static/coffee/spec/views/textbook_spec.js rename to cms/static/js/spec/views/textbook_spec.js diff --git a/cms/static/coffee/spec/views/upload_spec.js b/cms/static/js/spec/views/upload_spec.js similarity index 100% rename from cms/static/coffee/spec/views/upload_spec.js rename to cms/static/js/spec/views/upload_spec.js diff --git a/cms/static/karma_cms.conf.js b/cms/static/karma_cms.conf.js index effd233d227d..23acdaa9b48b 100644 --- a/cms/static/karma_cms.conf.js +++ b/cms/static/karma_cms.conf.js @@ -22,13 +22,11 @@ var options = { // Otherwise Istanbul which is used for coverage tracking will cause tests to not run. sourceFiles: [ {pattern: 'cms/**/!(*spec|djangojs).js'}, - {pattern: 'coffee/src/**/!(*spec).js'}, {pattern: 'js/**/!(*spec|djangojs).js'} ], specFiles: [ {pattern: 'cms/**/*spec.js'}, - {pattern: 'coffee/spec/**/*spec.js'}, {pattern: 'js/certificates/spec/**/*spec.js'}, {pattern: 'js/spec/**/*spec.js'} ], diff --git a/cms/static/karma_cms_squire.conf.js b/cms/static/karma_cms_squire.conf.js index d861dc99cae3..b45abc627561 100644 --- a/cms/static/karma_cms_squire.conf.js +++ b/cms/static/karma_cms_squire.conf.js @@ -21,18 +21,15 @@ var options = { // Make sure the patterns in sourceFiles and specFiles do not match the same file. // Otherwise Istanbul which is used for coverage tracking will cause tests to not run. sourceFiles: [ - {pattern: 'coffee/src/**/!(*spec).js'}, {pattern: 'cms/js/**/!(*spec|djangojs).js'}, {pattern: 'js/**/!(*spec|djangojs).js'} ], specFiles: [ - {pattern: 'coffee/spec/**/*spec.js'}, {pattern: 'js/spec/**/*spec.js'} ], fixtureFiles: [ - {pattern: 'coffee/fixtures/**/*.*'}, {pattern: 'templates/**/*.*'} ], diff --git a/common/lib/capa/capa/tests/test_files/js/mersenne-twister-min.js b/common/lib/capa/capa/tests/test_files/js/mersenne-twister-min.js index 6721e9e06d44..f96671a634de 100644 --- a/common/lib/capa/capa/tests/test_files/js/mersenne-twister-min.js +++ b/common/lib/capa/capa/tests/test_files/js/mersenne-twister-min.js @@ -64,6 +64,7 @@ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ +/* eslint-disable */ var MersenneTwister = function(seed) { if (seed == undefined) { seed = new Date().getTime(); diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py index 1046f8853de1..c974da2157b6 100644 --- a/common/lib/xmodule/xmodule/annotatable_module.py +++ b/common/lib/xmodule/xmodule/annotatable_module.py @@ -47,11 +47,9 @@ class AnnotatableFields(object): class AnnotatableModule(AnnotatableFields, XModule): js = { - 'coffee': [ - resource_string(__name__, 'js/src/html/display.coffee'), - resource_string(__name__, 'js/src/annotatable/display.coffee'), - ], 'js': [ + resource_string(__name__, 'js/src/html/display.js'), + resource_string(__name__, 'js/src/annotatable/display.js'), resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py index 3ab75c82303e..1449b52bb9a2 100644 --- a/common/lib/xmodule/xmodule/conditional_module.py +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -116,10 +116,8 @@ class ConditionalModule(ConditionalFields, XModule, StudioEditableModule): """ js = { - 'coffee': [ - resource_string(__name__, 'js/src/conditional/display.coffee'), - ], 'js': [ + resource_string(__name__, 'js/src/conditional/display.js'), resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] diff --git a/common/lib/xmodule/xmodule/editing_module.py b/common/lib/xmodule/xmodule/editing_module.py index 92e2bdf906d1..7ef506ab44b0 100644 --- a/common/lib/xmodule/xmodule/editing_module.py +++ b/common/lib/xmodule/xmodule/editing_module.py @@ -58,8 +58,8 @@ class TabsEditingDescriptor(EditingFields, MakoModuleDescriptor): """ mako_template = "widgets/tabs-aggregator.html" css = {'scss': [resource_string(__name__, 'css/tabs/tabs.scss')]} - js = {'coffee': [resource_string( - __name__, 'js/src/tabs/tabs-aggregator.coffee')]} + js = {'js': [resource_string( + __name__, 'js/src/tabs/tabs-aggregator.js')]} js_module_name = "TabsEditingDescriptor" tabs = [] @@ -93,7 +93,7 @@ class XMLEditingDescriptor(EditingDescriptor): css = {'scss': [resource_string(__name__, 'css/codemirror/codemirror.scss')]} - js = {'coffee': [resource_string(__name__, 'js/src/raw/edit/xml.coffee')]} + js = {'js': [resource_string(__name__, 'js/src/raw/edit/xml.js')]} js_module_name = "XMLEditingDescriptor" @@ -103,7 +103,7 @@ class MetadataOnlyEditingDescriptor(EditingDescriptor): not expose a UI for editing the module data """ - js = {'coffee': [resource_string(__name__, 'js/src/raw/edit/metadata-only.coffee')]} + js = {'js': [resource_string(__name__, 'js/src/raw/edit/metadata-only.js')]} js_module_name = "MetadataOnlyEditingDescriptor" mako_template = "widgets/metadata-only-edit.html" @@ -117,5 +117,5 @@ class JSONEditingDescriptor(EditingDescriptor): css = {'scss': [resource_string(__name__, 'css/codemirror/codemirror.scss')]} - js = {'coffee': [resource_string(__name__, 'js/src/raw/edit/json.coffee')]} + js = {'js': [resource_string(__name__, 'js/src/raw/edit/json.js')]} js_module_name = "JSONEditingDescriptor" diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index 9837f97c8a7a..6eaafbe38c37 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -107,10 +107,8 @@ class HtmlModuleMixin(HtmlBlock, XModule): Attributes and methods used by HtmlModules internally. """ js = { - 'coffee': [ - resource_string(__name__, 'js/src/html/display.coffee'), - ], 'js': [ + resource_string(__name__, 'js/src/html/display.js'), resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), resource_string(__name__, 'js/src/html/imageModal.js'), @@ -139,7 +137,7 @@ class HtmlDescriptor(HtmlBlock, XmlDescriptor, EditingDescriptor): # pylint: di template_dir_name = "html" show_in_read_only_mode = True - js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]} + js = {'js': [resource_string(__name__, 'js/src/html/edit.js')]} js_module_name = "HTMLEditingDescriptor" css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/html/edit.scss')]} diff --git a/common/lib/xmodule/xmodule/imageannotation_module.py b/common/lib/xmodule/xmodule/imageannotation_module.py index e58b8362aeee..05e109b3176e 100644 --- a/common/lib/xmodule/xmodule/imageannotation_module.py +++ b/common/lib/xmodule/xmodule/imageannotation_module.py @@ -91,11 +91,9 @@ class AnnotatableFields(object): class ImageAnnotationModule(AnnotatableFields, XModule): '''Image Annotation Module''' js = { - 'coffee': [ - resource_string(__name__, 'js/src/html/display.coffee'), - resource_string(__name__, 'js/src/annotatable/display.coffee'), - ], 'js': [ + resource_string(__name__, 'js/src/html/display.js'), + resource_string(__name__, 'js/src/annotatable/display.js'), resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] diff --git a/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js b/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js index ca335c5d5971..46ce08ef9b43 100644 --- a/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js +++ b/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js @@ -18,7 +18,7 @@ var options = { // Avoid adding files to this list. Use RequireJS. libraryFilesToInclude: [ // Load the core JavaScript dependencies - {pattern: 'common_static/coffee/src/ajax_prefix.js', included: true}, + {pattern: 'common_static/js/src/ajax_prefix.js', included: true}, {pattern: 'common_static/common/js/vendor/underscore.js', included: true}, {pattern: 'common_static/common/js/vendor/backbone.js', included: true}, {pattern: 'common_static/js/vendor/CodeMirror/codemirror.js', included: true}, diff --git a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.js b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.js index e3bdbca321f8..385bd2d24333 100644 --- a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.js @@ -19,7 +19,7 @@ describe('Problem', function() { spyOn(SR, 'readText'); spyOn(SR, 'readTexts'); - // Load this function from spec/helper.coffee + // Load this function from spec/helper.js // Note that if your test fails with a message like: // 'External request attempted for blah, which is not defined.' // this msg is coming from the stubRequests function else clause. diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.js b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.js index 13adad407eba..419421e26aff 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.js +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.js @@ -885,8 +885,6 @@ hint ); describe('Markdown to xml extended hint with tricky syntax cases', function() { - // I'm entering this as utf-8 in this file. - // I cannot find a way to set the encoding for .coffee files but it seems to work. it('produces xml with unicode', function() { const data = MarkdownEditingDescriptor.markdownToXml(`\ >>á and Ø<< diff --git a/common/lib/xmodule/xmodule/js/src/.gitignore b/common/lib/xmodule/xmodule/js/src/.gitignore deleted file mode 100644 index 4baebb5a2765..000000000000 --- a/common/lib/xmodule/xmodule/js/src/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# Ignore .js files in this folder as they are compiled from coffeescript -# For each of the xmodules subdirectories, add a .gitignore file that -# will version any *.js file that is specifically written, not compiled. -*.js - - -# Video are written in pure JavaScript. -!video/*.js -!video/transcripts/*.js - - -# Converted to JS from CoffeeScript. -!time.js -!collapsible.js -!xmodule.js -!javascript_loader.js diff --git a/common/lib/xmodule/xmodule/js/src/annotatable/display.js b/common/lib/xmodule/xmodule/js/src/annotatable/display.js index 8f1d0dbaaef3..5777b95313de 100644 --- a/common/lib/xmodule/xmodule/js/src/annotatable/display.js +++ b/common/lib/xmodule/xmodule/js/src/annotatable/display.js @@ -1,261 +1,443 @@ -class @Annotatable - _debug: false - - # selectors for the annotatable xmodule - wrapperSelector: '.annotatable-wrapper' - toggleAnnotationsSelector: '.annotatable-toggle-annotations' - toggleInstructionsSelector: '.annotatable-toggle-instructions' - instructionsSelector: '.annotatable-instructions' - sectionSelector: '.annotatable-section' - spanSelector: '.annotatable-span' - replySelector: '.annotatable-reply' - - # these selectors are for responding to events from the annotation capa problem type - problemXModuleSelector: '.xmodule_CapaModule' - problemSelector: 'div.problem' - problemInputSelector: 'div.problem .annotation-input' - problemReturnSelector: 'div.problem .annotation-return' - - constructor: (el) -> - console.log 'loaded Annotatable' if @_debug - @el = el - @$el = $(el) - @init() - - $: (selector) -> - $(selector, @el) - - init: () -> - @initEvents() - @initTips() - - initEvents: () -> - # Initialize toggle handlers for the instructions and annotations sections - [@annotationsHidden, @instructionsHidden] = [false, false] - @$(@toggleAnnotationsSelector).bind 'click', @onClickToggleAnnotations - @$(@toggleInstructionsSelector).bind 'click', @onClickToggleInstructions - - # Initialize handler for 'reply to annotation' events that scroll to - # the associated problem. The reply buttons are part of the tooltip - # content. It's important that the tooltips be configured to render - # as descendants of the annotation module and *not* the document.body. - @$el.on 'click', @replySelector, @onClickReply - - # Initialize handler for 'return to annotation' events triggered from problems. - # 1) There are annotationinput capa problems rendered on the page - # 2) Each one has an embedded return link (see annotation capa problem template). - # Since the capa problem injects HTML content via AJAX, the best we can do is - # is let the click events bubble up to the body and handle them there. - $(document).on 'click', @problemReturnSelector, @onClickReturn - - initTips: () -> - # tooltips are used to display annotations for highlighted text spans - @$(@spanSelector).each (index, el) => - $(el).qtip(@getSpanTipOptions el) - - getSpanTipOptions: (el) -> - content: - title: - text: @makeTipTitle(el) - text: @makeTipContent(el) - position: - my: 'bottom center' # of tooltip - at: 'top center' # of target - target: $(el) # where the tooltip was triggered (i.e. the annotation span) - container: @$(@wrapperSelector) - adjust: - y: -5 - show: - event: 'click mouseenter' - solo: true - hide: - event: 'click mouseleave' - delay: 500, - fixed: true # don't hide the tooltip if it is moused over - style: - classes: 'ui-tooltip-annotatable' - events: - show: @onShowTip - move: @onMoveTip - - onClickToggleAnnotations: (e) => @toggleAnnotations() - - onClickToggleInstructions: (e) => @toggleInstructions() - - onClickReply: (e) => @replyTo(e.currentTarget) - - onClickReturn: (e) => @returnFrom(e.currentTarget) - - onShowTip: (event, api) => - event.preventDefault() if @annotationsHidden - - onMoveTip: (event, api, position) => - ### - This method handles a vertical positioning bug in Firefox as - well as an edge case in which a tooltip is displayed above a - non-overlapping span like this: - - (( TOOLTIP )) - \/ - text text text ... text text text ...... - - - The problem is that the tooltip looks disconnected from both spans, so - we should re-position the tooltip to appear above the span. - ### - - tip = api.elements.tooltip - adjust_y = api.options.position?.adjust?.y || 0 - container = api.options.position?.container || $('body') - target = api.elements.target - - rects = $(target).get(0).getClientRects() - is_non_overlapping = (rects?.length == 2 and rects[0].left > rects[1].right) - - if is_non_overlapping - # we want to choose the largest of the two non-overlapping spans and display - # the tooltip above the center of it (see api.options.position settings) - focus_rect = (if rects[0].width > rects[1].width then rects[0] else rects[1]) - else - # always compute the new position because Firefox doesn't - # properly vertically position the tooltip - focus_rect = rects[0] - - rect_center = focus_rect.left + (focus_rect.width / 2) - rect_top = focus_rect.top - tip_width = $(tip).width() - tip_height = $(tip).height() - - # tooltip is positioned relative to its container, so we need to factor in offsets - container_offset = $(container).offset() - offset_left = -container_offset.left - offset_top = $(document).scrollTop() - container_offset.top - - tip_left = offset_left + rect_center - (tip_width / 2) - tip_top = offset_top + rect_top - tip_height + adjust_y - - # make sure the new tip position doesn't clip the edges of the screen - win_width = $(window).width() - if tip_left < offset_left - tip_left = offset_left - else if tip_left + tip_width > win_width + offset_left - tip_left = win_width + offset_left - tip_width - - # final step: update the position object (used by qtip2 to show the tip after the move event) - $.extend position, 'left': tip_left, 'top': tip_top - - getSpanForProblemReturn: (el) -> - problem_id = $(@problemReturnSelector).index(el) - @$(@spanSelector).filter("[data-problem-id='#{problem_id}']") - - getProblem: (el) -> - problem_id = @getProblemId(el) - $(@problemInputSelector).eq(problem_id) - - getProblemId: (el) -> - $(el).data('problem-id') - - toggleAnnotations: () -> - hide = (@annotationsHidden = not @annotationsHidden) - @toggleAnnotationButtonText hide - @toggleSpans hide - @toggleTips hide - - toggleTips: (hide) -> - visible = @findVisibleTips() - @hideTips visible - - toggleAnnotationButtonText: (hide) -> - if hide - buttonText = gettext('Show Annotations') - else - buttonText = gettext('Hide Annotations') - @$(@toggleAnnotationsSelector).text(buttonText) - - toggleInstructions: () -> - hide = (@instructionsHidden = not @instructionsHidden) - @toggleInstructionsButton hide - @toggleInstructionsText hide - - toggleInstructionsButton: (hide) -> - if hide - txt = gettext('Expand Instructions') - else - txt = gettext('Collapse Instructions') - cls = (if hide then ['expanded', 'collapsed'] else ['collapsed','expanded']) - @$(@toggleInstructionsSelector).text(txt).removeClass(cls[0]).addClass(cls[1]) - - toggleInstructionsText: (hide) -> - slideMethod = (if hide then 'slideUp' else 'slideDown') - @$(@instructionsSelector)[slideMethod]() - - toggleSpans: (hide) -> - @$(@spanSelector).toggleClass 'hide', hide, 250 - - replyTo: (buttonEl) -> - offset = -20 - el = @getProblem buttonEl - if el.length > 0 - @scrollTo(el, @afterScrollToProblem, offset) - else - console.log('problem not found. event: ', e) if @_debug - - returnFrom: (buttonEl) -> - offset = -200 - el = @getSpanForProblemReturn buttonEl - if el.length > 0 - @scrollTo(el, @afterScrollToSpan, offset) - else - console.log('span not found. event:', e) if @_debug - - scrollTo: (el, after, offset = -20) -> - $('html,body').scrollTo(el, { - duration: 500 - onAfter: @_once => after?.call this, el - offset: offset - }) if $(el).length > 0 - - afterScrollToProblem: (problem_el) -> - problem_el.effect 'highlight', {}, 500 - - afterScrollToSpan: (span_el) -> - span_el.addClass 'selected', 400, 'swing', -> - span_el.removeClass 'selected', 400, 'swing' - - makeTipContent: (el) -> - (api) => - text = $(el).data('comment-body') - comment = @createComment(text) - problem_id = @getProblemId(el) - reply = @createReplyLink(problem_id) - $(comment).add(reply) - - makeTipTitle: (el) -> - (api) => - title = $(el).data('comment-title') - (if title then title else gettext('Commentary')) - - createComment: (text) -> - $("
#{text}
") - - createReplyLink: (problem_id) -> - linktxt = gettext('Reply to Annotation') - $("#{linktxt}") - - findVisibleTips: () -> - visible = [] - @$(@spanSelector).each (index, el) -> - api = $(el).qtip('api') - tip = $(api?.elements.tooltip) - if tip.is(':visible') - visible.push el - visible - - hideTips: (elements) -> - $(elements).qtip('hide') - - _once: (fn) -> - done = false - return => - fn.call this unless done - done = true +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +// TODO: Examine all of the xss-lint exceptions (https://openedx.atlassian.net/browse/PLAT-2084) +(function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + this.Annotatable = (function() { + Annotatable.prototype._debug = false; + + + /* + selectors for the annotatable xmodule + */ + + Annotatable.prototype.wrapperSelector = '.annotatable-wrapper'; + + Annotatable.prototype.toggleAnnotationsSelector = '.annotatable-toggle-annotations'; + + Annotatable.prototype.toggleInstructionsSelector = '.annotatable-toggle-instructions'; + + Annotatable.prototype.instructionsSelector = '.annotatable-instructions'; + + Annotatable.prototype.sectionSelector = '.annotatable-section'; + + Annotatable.prototype.spanSelector = '.annotatable-span'; + + Annotatable.prototype.replySelector = '.annotatable-reply'; + + + /* + these selectors are for responding to events from the annotation capa problem type + */ + + Annotatable.prototype.problemXModuleSelector = '.xmodule_CapaModule'; + + Annotatable.prototype.problemSelector = 'div.problem'; + + Annotatable.prototype.problemInputSelector = 'div.problem .annotation-input'; + + Annotatable.prototype.problemReturnSelector = 'div.problem .annotation-return'; + + function Annotatable(el) { + this.onMoveTip = bind(this.onMoveTip, this); + this.onShowTip = bind(this.onShowTip, this); + this.onClickReturn = bind(this.onClickReturn, this); + this.onClickReply = bind(this.onClickReply, this); + this.onClickToggleInstructions = bind(this.onClickToggleInstructions, this); + this.onClickToggleAnnotations = bind(this.onClickToggleAnnotations, this); + if (this._debug) { + console.log('loaded Annotatable'); + } + this.el = el; + this.$el = $(el); + this.init(); + } + + Annotatable.prototype.$ = function(selector) { + return $(selector, this.el); + }; + + Annotatable.prototype.init = function() { + this.initEvents(); + return this.initTips(); + }; + + Annotatable.prototype.initEvents = function() { + + /* + Initialize toggle handlers for the instructions and annotations sections + */ + var ref; + ref = [false, false], this.annotationsHidden = ref[0], this.instructionsHidden = ref[1]; + this.$(this.toggleAnnotationsSelector).bind('click', this.onClickToggleAnnotations); + this.$(this.toggleInstructionsSelector).bind('click', this.onClickToggleInstructions); + + /* + Initialize handler for 'reply to annotation' events that scroll to + the associated problem. The reply buttons are part of the tooltip + content. It's important that the tooltips be configured to render + as descendants of the annotation module and *not* the document.body. + */ + this.$el.on('click', this.replySelector, this.onClickReply); + + /* + Initialize handler for 'return to annotation' events triggered from problems. + 1) There are annotationinput capa problems rendered on the page + 2) Each one has an embedded return link (see annotation capa problem template). + Since the capa problem injects HTML content via AJAX, the best we can do is + is let the click events bubble up to the body and handle them there. + */ + return $(document).on('click', this.problemReturnSelector, this.onClickReturn); + }; + + Annotatable.prototype.initTips = function() { + + /* + tooltips are used to display annotations for highlighted text spans + */ + return this.$(this.spanSelector).each((function(_this) { + return function(index, el) { + return $(el).qtip(_this.getSpanTipOptions(el)); + }; + })(this)); + }; + + Annotatable.prototype.getSpanTipOptions = function(el) { + return { + content: { + title: { + text: this.makeTipTitle(el) + }, + text: this.makeTipContent(el) + }, + position: { + + /* + of tooltip + */ + my: 'bottom center', + + /* + of target + */ + at: 'top center', + + /* + where the tooltip was triggered (i.e. the annotation span) + */ + target: $(el), + container: this.$(this.wrapperSelector), + adjust: { + y: -5 + } + }, + show: { + event: 'click mouseenter', + solo: true + }, + hide: { + event: 'click mouseleave', + delay: 500, + + /* + don't hide the tooltip if it is moused over + */ + fixed: true + }, + style: { + classes: 'ui-tooltip-annotatable' + }, + events: { + show: this.onShowTip, + move: this.onMoveTip + } + }; + }; + + Annotatable.prototype.onClickToggleAnnotations = function(e) { + return this.toggleAnnotations(); + }; + + Annotatable.prototype.onClickToggleInstructions = function(e) { + return this.toggleInstructions(); + }; + + Annotatable.prototype.onClickReply = function(e) { + return this.replyTo(e.currentTarget); + }; + + Annotatable.prototype.onClickReturn = function(e) { + return this.returnFrom(e.currentTarget); + }; + + Annotatable.prototype.onShowTip = function(event, api) { + if (this.annotationsHidden) { + return event.preventDefault(); + } + }; + + Annotatable.prototype.onMoveTip = function(event, api, position) { + + /* + This method handles a vertical positioning bug in Firefox as + well as an edge case in which a tooltip is displayed above a + non-overlapping span like this: + + (( TOOLTIP )) + \/ + text text text ... text text text ...... + + + The problem is that the tooltip looks disconnected from both spans, so + we should re-position the tooltip to appear above the span. + */ + var adjust_y, container, container_offset, focus_rect, is_non_overlapping, offset_left, offset_top, rect_center, rect_top, rects, ref, ref1, ref2, target, tip, tip_height, tip_left, tip_top, tip_width, win_width; + tip = api.elements.tooltip; + adjust_y = ((ref = api.options.position) != null ? (ref1 = ref.adjust) != null ? ref1.y : void 0 : void 0) || 0; + container = ((ref2 = api.options.position) != null ? ref2.container : void 0) || $('body'); + target = api.elements.target; + rects = $(target).get(0).getClientRects(); + is_non_overlapping = (rects != null ? rects.length : void 0) === 2 && rects[0].left > rects[1].right; + if (is_non_overlapping) { + + /* + we want to choose the largest of the two non-overlapping spans and display + the tooltip above the center of it (see api.options.position settings) + */ + focus_rect = (rects[0].width > rects[1].width ? rects[0] : rects[1]); + } else { + + /* + always compute the new position because Firefox doesn't + properly vertically position the tooltip + */ + focus_rect = rects[0]; + } + rect_center = focus_rect.left + (focus_rect.width / 2); + rect_top = focus_rect.top; + tip_width = $(tip).width(); + tip_height = $(tip).height(); + + /* + tooltip is positioned relative to its container, so we need to factor in offsets + */ + container_offset = $(container).offset(); + offset_left = -container_offset.left; + offset_top = $(document).scrollTop() - container_offset.top; + tip_left = offset_left + rect_center - (tip_width / 2); + tip_top = offset_top + rect_top - tip_height + adjust_y; + + /* + make sure the new tip position doesn't clip the edges of the screen + */ + win_width = $(window).width(); + if (tip_left < offset_left) { + tip_left = offset_left; + } else if (tip_left + tip_width > win_width + offset_left) { + tip_left = win_width + offset_left - tip_width; + } + + /* + final step: update the position object (used by qtip2 to show the tip after the move event) + */ + return $.extend(position, { + 'left': tip_left, + 'top': tip_top + }); + }; + + Annotatable.prototype.getSpanForProblemReturn = function(el) { + var problem_id; + problem_id = $(this.problemReturnSelector).index(el); + return this.$(this.spanSelector).filter("[data-problem-id='" + problem_id + "']"); + }; + + Annotatable.prototype.getProblem = function(el) { + var problem_id; + problem_id = this.getProblemId(el); + return $(this.problemInputSelector).eq(problem_id); + }; + + Annotatable.prototype.getProblemId = function(el) { + return $(el).data('problem-id'); + }; + + Annotatable.prototype.toggleAnnotations = function() { + var hide; + hide = (this.annotationsHidden = !this.annotationsHidden); + this.toggleAnnotationButtonText(hide); + this.toggleSpans(hide); + return this.toggleTips(hide); + }; + + Annotatable.prototype.toggleTips = function(hide) { + var visible; + visible = this.findVisibleTips(); + return this.hideTips(visible); + }; + + Annotatable.prototype.toggleAnnotationButtonText = function(hide) { + var buttonText; + if (hide) { + buttonText = gettext('Show Annotations'); + } else { + buttonText = gettext('Hide Annotations'); + } + return this.$(this.toggleAnnotationsSelector).text(buttonText); + }; + + Annotatable.prototype.toggleInstructions = function() { + var hide; + hide = (this.instructionsHidden = !this.instructionsHidden); + this.toggleInstructionsButton(hide); + return this.toggleInstructionsText(hide); + }; + + Annotatable.prototype.toggleInstructionsButton = function(hide) { + var cls, txt; + if (hide) { + txt = gettext('Expand Instructions'); + } else { + txt = gettext('Collapse Instructions'); + } + cls = (hide ? ['expanded', 'collapsed'] : ['collapsed', 'expanded']); + return this.$(this.toggleInstructionsSelector).text(txt).removeClass(cls[0]).addClass(cls[1]); + }; + + Annotatable.prototype.toggleInstructionsText = function(hide) { + var slideMethod; + slideMethod = (hide ? 'slideUp' : 'slideDown'); + return this.$(this.instructionsSelector)[slideMethod](); + }; + + Annotatable.prototype.toggleSpans = function(hide) { + return this.$(this.spanSelector).toggleClass('hide', hide, 250); + }; + + Annotatable.prototype.replyTo = function(buttonEl) { + var el, offset; + offset = -20; + el = this.getProblem(buttonEl); + if (el.length > 0) { + return this.scrollTo(el, this.afterScrollToProblem, offset); + } else { + if (this._debug) { + return console.log('problem not found. event: ', e); + } + } + }; + + Annotatable.prototype.returnFrom = function(buttonEl) { + var el, offset; + offset = -200; + el = this.getSpanForProblemReturn(buttonEl); + if (el.length > 0) { + return this.scrollTo(el, this.afterScrollToSpan, offset); + } else { + if (this._debug) { + return console.log('span not found. event:', e); + } + } + }; + + Annotatable.prototype.scrollTo = function(el, after, offset) { + if (offset == null) { + offset = -20; + } + if ($(el).length > 0) { + return $('html,body').scrollTo(el, { + duration: 500, + onAfter: this._once((function(_this) { + return function() { + return after != null ? after.call(_this, el) : void 0; + }; + })(this)), + offset: offset + }); + } + }; + + Annotatable.prototype.afterScrollToProblem = function(problem_el) { + return problem_el.effect('highlight', {}, 500); + }; + + Annotatable.prototype.afterScrollToSpan = function(span_el) { + return span_el.addClass('selected', 400, 'swing', function() { + return span_el.removeClass('selected', 400, 'swing'); + }); + }; + + Annotatable.prototype.makeTipContent = function(el) { + return (function(_this) { + return function(api) { + var comment, problem_id, reply, text; + text = $(el).data('comment-body'); + comment = _this.createComment(text); + problem_id = _this.getProblemId(el); + reply = _this.createReplyLink(problem_id); + return $(comment).add(reply); + }; + })(this); + }; + + Annotatable.prototype.makeTipTitle = function(el) { + return (function(_this) { + return function(api) { + var title; + title = $(el).data('comment-title'); + if (title) { + return title; + } else { + return gettext('Commentary'); + } + }; + })(this); + }; + + Annotatable.prototype.createComment = function(text) { + return $("
" + text + "
"); // xss-lint: disable=javascript-concat-html + }; + + Annotatable.prototype.createReplyLink = function(problem_id) { + var linktxt; + linktxt = gettext('Reply to Annotation'); + return $("" + linktxt + ""); // xss-lint: disable=javascript-concat-html + }; + + Annotatable.prototype.findVisibleTips = function() { + var visible; + visible = []; + this.$(this.spanSelector).each(function(index, el) { + var api, tip; + api = $(el).qtip('api'); + tip = $(api != null ? api.elements.tooltip : void 0); + if (tip.is(':visible')) { + return visible.push(el); + } + }); + return visible; + }; + + Annotatable.prototype.hideTips = function(elements) { + return $(elements).qtip('hide'); + }; + + Annotatable.prototype._once = function(fn) { + var done; + done = false; + return (function(_this) { + return function() { + if (!done) { + fn.call(_this); + } + return done = true; + }; + })(this); + }; + + return Annotatable; + + })(); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/capa/schematic.js b/common/lib/xmodule/xmodule/js/src/capa/schematic.js index d0cb25c5e568..e1059a9fa7bd 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/schematic.js +++ b/common/lib/xmodule/xmodule/js/src/capa/schematic.js @@ -1,3 +1,5 @@ +/* eslint-disable */ + ////////////////////////////////////////////////////////////////////////////// // // Circuit simulator diff --git a/common/lib/xmodule/xmodule/js/src/conditional/display.js b/common/lib/xmodule/xmodule/js/src/conditional/display.js index f726fc872967..4efbd37981c4 100644 --- a/common/lib/xmodule/xmodule/js/src/conditional/display.js +++ b/common/lib/xmodule/xmodule/js/src/conditional/display.js @@ -1,38 +1,60 @@ -class @Conditional - - constructor: (element, callerElId) -> - @el = $(element).find('.conditional-wrapper') - - @callerElId = callerElId - - if callerElId isnt undefined - dependencies = @el.data('depends') - if (typeof dependencies is 'string') and (dependencies.length > 0) and (dependencies.indexOf(callerElId) is -1) - return - - @url = @el.data('url') - if @url - @render(element) - - render: (element) -> - $.postWithPrefix "#{@url}/conditional_get", (response) => - @el.html '' - @el.append(i) for i in response.html - - parentEl = $(element).parent() - parentId = parentEl.attr 'id' - - if response.message is false - if parentEl.hasClass('vert') - parentEl.hide() - else - $(element).hide() - else - if parentEl.hasClass('vert') - parentEl.show() - else - $(element).show() - - # The children are rendered with a new request, so they have a different request-token. - # Use that token instead of @requestToken by simply not passing a token into initializeBlocks. - XBlock.initializeBlocks(@el) +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + this.Conditional = (function() { + function Conditional(element, callerElId) { + var dependencies; + this.el = $(element).find('.conditional-wrapper'); + this.callerElId = callerElId; + if (callerElId !== void 0) { + dependencies = this.el.data('depends'); + if ((typeof dependencies === 'string') && (dependencies.length > 0) && (dependencies.indexOf(callerElId) === -1)) { + return; + } + } + this.url = this.el.data('url'); + if (this.url) { + this.render(element); + } + } + + Conditional.prototype.render = function(element) { + return $.postWithPrefix(this.url + "/conditional_get", (function(_this) { + return function(response) { + var i, j, len, parentEl, parentId, ref; + _this.el.html(''); + ref = response.html; + for (j = 0, len = ref.length; j < len; j++) { + i = ref[j]; + _this.el.append(i); + } + parentEl = $(element).parent(); + parentId = parentEl.attr('id'); + if (response.message === false) { + if (parentEl.hasClass('vert')) { + parentEl.hide(); + } else { + $(element).hide(); + } + } else { + if (parentEl.hasClass('vert')) { + parentEl.show(); + } else { + $(element).show(); + } + } + + /* + The children are rendered with a new request, so they have a different request-token. + Use that token instead of @requestToken by simply not passing a token into initializeBlocks. + */ + return XBlock.initializeBlocks(_this.el); + }; + })(this)); + }; + + return Conditional; + + })(); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/discussion/display.js b/common/lib/xmodule/xmodule/js/src/discussion/display.js index 2369b0f92d22..64dfc685fef8 100644 --- a/common/lib/xmodule/xmodule/js/src/discussion/display.js +++ b/common/lib/xmodule/xmodule/js/src/discussion/display.js @@ -1,4 +1,21 @@ -class @InlineDiscussion extends XModule.Descriptor - constructor: (element) -> - @el = $(element).find('.discussion-module') - @view = new DiscussionInlineView(el: @el) +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + this.InlineDiscussion = (function(superClass) { + extend(InlineDiscussion, superClass); + + function InlineDiscussion(element) { + this.el = $(element).find('.discussion-module'); + this.view = new DiscussionInlineView({ + el: this.el + }); + } + + return InlineDiscussion; + + })(XModule.Descriptor); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/html/display.js b/common/lib/xmodule/xmodule/js/src/html/display.js index 194ef4b70c13..ec3e0f3097fb 100644 --- a/common/lib/xmodule/xmodule/js/src/html/display.js +++ b/common/lib/xmodule/xmodule/js/src/html/display.js @@ -1,13 +1,26 @@ -class @HTMLModule - - constructor: (@element) -> - @el = $(@element) - JavascriptLoader.executeModuleScripts(@el) - Collapsible.setCollapsibles(@el) - if MathJax? - MathJax.Hub.Queue ["Typeset", MathJax.Hub, @el[0]] - if setupFullScreenModal? - setupFullScreenModal() - - $: (selector) -> - $(selector, @el) +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + this.HTMLModule = (function() { + function HTMLModule(element) { + this.element = element; + this.el = $(this.element); + JavascriptLoader.executeModuleScripts(this.el); + Collapsible.setCollapsibles(this.el); + if (typeof MathJax !== "undefined" && MathJax !== null) { + MathJax.Hub.Queue(["Typeset", MathJax.Hub, this.el[0]]); + } + if (typeof setupFullScreenModal !== "undefined" && setupFullScreenModal !== null) { + setupFullScreenModal(); + } + } + + HTMLModule.prototype.$ = function(selector) { + return $(selector, this.el); + }; + + return HTMLModule; + + })(); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/html/edit.js b/common/lib/xmodule/xmodule/js/src/html/edit.js index e4ab125c3c2b..d8428dafce97 100644 --- a/common/lib/xmodule/xmodule/js/src/html/edit.js +++ b/common/lib/xmodule/xmodule/js/src/html/edit.js @@ -1,92 +1,141 @@ -class @HTMLEditingDescriptor - - # custom fonts are prepended to font selection dropdown - CUSTOM_FONTS = "Default='Open Sans', Verdana, Arial, Helvetica, sans-serif;" - - # list of standard tinyMCE fonts: http://www.tinymce.com/wiki.php/Configuration:font_formats - STANDARD_FONTS = "Andale Mono=andale mono,times;"+ - "Arial=arial,helvetica,sans-serif;"+ - "Arial Black=arial black,avant garde;"+ - "Book Antiqua=book antiqua,palatino;"+ - "Comic Sans MS=comic sans ms,sans-serif;"+ - "Courier New=courier new,courier;"+ - "Georgia=georgia,palatino;"+ - "Helvetica=helvetica;"+ - "Impact=impact,chicago;"+ - "Symbol=symbol;"+ - "Tahoma=tahoma,arial,helvetica,sans-serif;"+ - "Terminal=terminal,monaco;"+ - "Times New Roman=times new roman,times;"+ - "Trebuchet MS=trebuchet ms,geneva;"+ - "Verdana=verdana,geneva;"+ - "Webdings=webdings;"+ - "Wingdings=wingdings,zapf dingbats" - - _getFonts = () -> - CUSTOM_FONTS + STANDARD_FONTS - - constructor: (element) -> - @element = element - @base_asset_url = @element.find("#editor-tab").data('base-asset-url') - @editor_choice = @element.find("#editor-tab").data('editor') - @new_image_modal = window.STUDIO_FRONTEND_IN_CONTEXT_IMAGE_SELECTION - if @base_asset_url == undefined - @base_asset_url = null - - # We always create the "raw editor" so we can get the text out of it if necessary on save. - @advanced_editor = CodeMirror.fromTextArea($(".edit-box", @element)[0], { - mode: "text/html" - lineNumbers: true +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + this.HTMLEditingDescriptor = (function() { + + /* + custom fonts are prepended to font selection dropdown + */ + var CUSTOM_FONTS, STANDARD_FONTS, _getFonts; + + CUSTOM_FONTS = "Default='Open Sans', Verdana, Arial, Helvetica, sans-serif;"; + + /* + list of standard tinyMCE fonts: http://www.tinymce.com/wiki.php/Configuration:font_formats + */ + STANDARD_FONTS = "Andale Mono=andale mono,times;" + + "Arial=arial,helvetica,sans-serif;" + + "Arial Black=arial black,avant garde;" + + "Book Antiqua=book antiqua,palatino;" + + "Comic Sans MS=comic sans ms,sans-serif;" + + "Courier New=courier new,courier;" + + "Georgia=georgia,palatino;" + + "Helvetica=helvetica;" + + "Impact=impact,chicago;" + + "Symbol=symbol;" + + "Tahoma=tahoma,arial,helvetica,sans-serif;" + + "Terminal=terminal,monaco;" + + "Times New Roman=times new roman,times;" + + "Trebuchet MS=trebuchet ms,geneva;" + + "Verdana=verdana,geneva;" + + "Webdings=webdings;" + + "Wingdings=wingdings,zapf dingbats"; + + _getFonts = function() { + return CUSTOM_FONTS + STANDARD_FONTS; + }; + + function HTMLEditingDescriptor(element) { + this.initInstanceCallback = bind(this.initInstanceCallback, this); + this.saveCodeEditor = bind(this.saveCodeEditor, this); + this.showCodeEditor = bind(this.showCodeEditor, this); + this.saveLink = bind(this.saveLink, this); + this.editLink = bind(this.editLink, this); + this.editImageSubmit = bind(this.editImageSubmit, this); + this.saveImageFromModal = bind(this.saveImageFromModal, this); + this.closeImageModal = bind(this.closeImageModal, this); + this.openImageModal = bind(this.openImageModal, this); + this.saveImage = bind(this.saveImage, this); + this.editImage = bind(this.editImage, this); + this.setupTinyMCE = bind(this.setupTinyMCE, this); + var tiny_mce_css_links; + this.element = element; + this.base_asset_url = this.element.find("#editor-tab").data('base-asset-url'); + this.editor_choice = this.element.find("#editor-tab").data('editor'); + this.new_image_modal = window.STUDIO_FRONTEND_IN_CONTEXT_IMAGE_SELECTION; + if (this.base_asset_url === void 0) { + this.base_asset_url = null; + } + + /* + We always create the "raw editor" so we can get the text out of it if necessary on save. + */ + this.advanced_editor = CodeMirror.fromTextArea($(".edit-box", this.element)[0], { + mode: "text/html", + lineNumbers: true, lineWrapping: true - }) - - if @editor_choice == 'visual' - @$advancedEditorWrapper = $(@advanced_editor.getWrapperElement()) - @$advancedEditorWrapper.addClass('is-inactive') - # Create an array of all content CSS links to use in and pass to Tiny MCE. - # We create this dynamically in order to support hashed files from our Django pipeline. - # CSS files that are to be used by Tiny MCE should contain the string "tinymce" so - # they can be found by the search below. - # We filter for only those files that are "content" files (as opposed to "skin" files). - tiny_mce_css_links = [] - $("link[rel=stylesheet][href*='tinymce']").filter("[href*='content']").each -> - tiny_mce_css_links.push $(this).attr("href") - return - - # This is a workaround for the fact that tinyMCE's baseURL property is not getting correctly set on AWS - # instances (like sandbox). It is not necessary to explicitly set baseURL when running locally. - tinyMCE.baseURL = "#{baseUrl}/js/vendor/tinymce/js/tinymce" - # This is necessary for the LMS bulk e-mail acceptance test. In that particular scenario, - # tinyMCE incorrectly decides that the suffix should be "", which means it fails to load files. - tinyMCE.suffix = ".min" - @tiny_mce_textarea = $(".tiny-mce", @element).tinymce({ - script_url : "#{baseUrl}/js/vendor/tinymce/js/tinymce/tinymce.full.min.js", - font_formats : _getFonts(), - theme : "modern", - skin: 'studio-tmce4', - schema: "html5", - # Necessary to preserve relative URLs to our images. - convert_urls : false, - # Sniff UI direction from `.wrapper-view` in studio or `.window-wrap` in LMS - directionality: $(".wrapper-view, .window-wrap").prop('dir'), - content_css : tiny_mce_css_links.join(", "), - formats : { - # tinyMCE does block level for code by default - code: {inline: 'code'} - }, - # Disable visual aid on borderless table. - visual: false, - plugins: "textcolor, link, image, codemirror", - codemirror: { - path: "#{baseUrl}/js/vendor" - }, - image_advtab: true, - # We may want to add "styleselect" when we collect all styles used throughout the LMS - toolbar: "formatselect | fontselect | bold italic underline forecolor wrapAsCode | " + - "alignleft aligncenter alignright alignjustify | " + - "bullist numlist outdent indent blockquote | link unlink " + - "#{if @new_image_modal then 'insertImage' else 'image'} | code", - block_formats: interpolate("%(paragraph)s=p;%(preformatted)s=pre;%(heading3)s=h3;%(heading4)s=h4;%(heading5)s=h5;%(heading6)s=h6", { + }); + if (this.editor_choice === 'visual') { + this.$advancedEditorWrapper = $(this.advanced_editor.getWrapperElement()); + this.$advancedEditorWrapper.addClass('is-inactive'); + + /* + Create an array of all content CSS links to use in and pass to Tiny MCE. + We create this dynamically in order to support hashed files from our Django pipeline. + CSS files that are to be used by Tiny MCE should contain the string "tinymce" so + they can be found by the search below. + We filter for only those files that are "content" files (as opposed to "skin" files). + */ + tiny_mce_css_links = []; + $("link[rel=stylesheet][href*='tinymce']").filter("[href*='content']").each(function() { + tiny_mce_css_links.push($(this).attr("href")); + }); + + /* + This is a workaround for the fact that tinyMCE's baseURL property is not getting correctly set on AWS + instances (like sandbox). It is not necessary to explicitly set baseURL when running locally. + */ + tinyMCE.baseURL = baseUrl + "/js/vendor/tinymce/js/tinymce"; + + /* + This is necessary for the LMS bulk e-mail acceptance test. In that particular scenario, + tinyMCE incorrectly decides that the suffix should be "", which means it fails to load files. + */ + tinyMCE.suffix = ".min"; + this.tiny_mce_textarea = $(".tiny-mce", this.element).tinymce({ + script_url: baseUrl + "/js/vendor/tinymce/js/tinymce/tinymce.full.min.js", + font_formats: _getFonts(), + theme: "modern", + skin: 'studio-tmce4', + schema: "html5", + + /* + Necessary to preserve relative URLs to our images. + */ + convert_urls: false, + + /* + Sniff UI direction from `.wrapper-view` in studio or `.window-wrap` in LMS + */ + directionality: $(".wrapper-view, .window-wrap").prop('dir'), + content_css: tiny_mce_css_links.join(", "), + formats: { + // tinyMCE does block level for code by default + code: { + inline: 'code' + } + }, + + /* + Disable visual aid on borderless table. + */ + visual: false, + plugins: "textcolor, link, image, codemirror", + codemirror: { + path: baseUrl + "/js/vendor" + }, + image_advtab: true, + + /* + We may want to add "styleselect" when we collect all styles used throughout the LMS + */ + toolbar: "formatselect | fontselect | bold italic underline forecolor wrapAsCode | " + + "alignleft aligncenter alignright alignjustify | " + + "bullist numlist outdent indent blockquote | link unlink " + + ((this.new_image_modal ? 'insertImage' : 'image') + " | code"), + block_formats: interpolate("%(paragraph)s=p;%(preformatted)s=pre;%(heading3)s=h3;%(heading4)s=h4;%(heading5)s=h5;%(heading6)s=h6", { paragraph: gettext("Paragraph"), preformatted: gettext("Preformatted"), heading3: gettext("Heading 3"), @@ -94,961 +143,1246 @@ class @HTMLEditingDescriptor heading5: gettext("Heading 5"), heading6: gettext("Heading 6") }, true), - width: '100%', - height: '400px', - menubar: false, - statusbar: false, - - # Necessary to avoid stripping of style tags. - valid_children : "+body[style]", - - # Allow any elements to be used, e.g. link, script, math - valid_elements: "*[*]", - extended_valid_elements: "*[*]", - invalid_elements: "", - - setup: @setupTinyMCE, - # Cannot get access to tinyMCE Editor instance (for focusing) until after it is rendered. - # The tinyMCE callback passes in the editor as a parameter. - init_instance_callback: @initInstanceCallback, - - browser_spellcheck: true - }) - tinymce.addI18n('en', { - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Add to Dictionary": gettext("Add to Dictionary"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Advanced": gettext("Advanced"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Align center": gettext("Align center"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Align left": gettext("Align left"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Align right": gettext("Align right"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Alignment": gettext("Alignment"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Alternative source": gettext("Alternative source"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Anchor": gettext("Anchor"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Anchors": gettext("Anchors"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Author": gettext("Author"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Background color": gettext("Background color"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Blockquote": gettext("Blockquote"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Blocks": gettext("Blocks"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Body": gettext("Body"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Bold": gettext("Bold"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Border color": gettext("Border color"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Border": gettext("Border"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Bottom": gettext("Bottom"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Bullet list": gettext("Bullet list"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cancel": gettext("Cancel"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Caption": gettext("Caption"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cell padding": gettext("Cell padding"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cell properties": gettext("Cell properties"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cell spacing": gettext("Cell spacing"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cell type": gettext("Cell type"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cell": gettext("Cell"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Center": gettext("Center"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Circle": gettext("Circle"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Clear formatting": gettext("Clear formatting"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Close": gettext("Close"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Code block": gettext("Code block"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Code": gettext("Code"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Color": gettext("Color"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cols": gettext("Cols"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Column group": gettext("Column group"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Column": gettext("Column"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Constrain proportions": gettext("Constrain proportions"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Copy row": gettext("Copy row"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Copy": gettext("Copy"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Could not find the specified string.": gettext("Could not find the specified string."), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Custom color": gettext("Custom color"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Custom...": gettext("Custom..."), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cut row": gettext("Cut row"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Cut": gettext("Cut"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Decrease indent": gettext("Decrease indent"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Default": gettext("Default"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Delete column": gettext("Delete column"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Delete row": gettext("Delete row"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Delete table": gettext("Delete table"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Description": gettext("Description"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Dimensions": gettext("Dimensions"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Disc": gettext("Disc"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Div": gettext("Div"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Document properties": gettext("Document properties"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Edit HTML": gettext("Edit HTML"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Edit": gettext("Edit"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Embed": gettext("Embed"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Emoticons": gettext("Emoticons"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Encoding": gettext("Encoding"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "File": gettext("File"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Find and replace": gettext("Find and replace"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Find next": gettext("Find next"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Find previous": gettext("Find previous"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Find": gettext("Find"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Finish": gettext("Finish"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Font Family": gettext("Font Family"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Font Sizes": gettext("Font Sizes"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Footer": gettext("Footer"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Format": gettext("Format"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Formats": gettext("Formats"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Fullscreen": gettext("Fullscreen"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "General": gettext("General"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "H Align": gettext("H Align"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header 1": gettext("Header 1"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header 2": gettext("Header 2"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header 3": gettext("Header 3"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header 4": gettext("Header 4"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header 5": gettext("Header 5"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header 6": gettext("Header 6"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header cell": gettext("Header cell"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Header": gettext("Header"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Headers": gettext("Headers"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Heading 1": gettext("Heading 1"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Heading 2": gettext("Heading 2"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Heading 3": gettext("Heading 3"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Heading 4": gettext("Heading 4"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Heading 5": gettext("Heading 5"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Heading 6": gettext("Heading 6"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Headings": gettext("Headings"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Height": gettext("Height"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Horizontal line": gettext("Horizontal line"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Horizontal space": gettext("Horizontal space"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "HTML source code": gettext("HTML source code"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Ignore all": gettext("Ignore all"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Ignore": gettext("Ignore"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Image description": gettext("Image description"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Increase indent": gettext("Increase indent"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Inline": gettext("Inline"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert column after": gettext("Insert column after"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert column before": gettext("Insert column before"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert date/time": gettext("Insert date/time"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert image": gettext("Insert image"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert link": gettext("Insert link"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert row after": gettext("Insert row after"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert row before": gettext("Insert row before"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert table": gettext("Insert table"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert template": gettext("Insert template"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert video": gettext("Insert video"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert": gettext("Insert"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert/edit image": gettext("Insert/edit image"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert/edit link": gettext("Insert/edit link"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Insert/edit video": gettext("Insert/edit video"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Italic": gettext("Italic"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Justify": gettext("Justify"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Keywords": gettext("Keywords"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Left to right": gettext("Left to right"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Left": gettext("Left"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Lower Alpha": gettext("Lower Alpha"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Lower Greek": gettext("Lower Greek"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Lower Roman": gettext("Lower Roman"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Match case": gettext("Match case"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Merge cells": gettext("Merge cells"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Middle": gettext("Middle"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Name": gettext("Name"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "New document": gettext("New document"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "New window": gettext("New window"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Next": gettext("Next"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "No color": gettext("No color"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Nonbreaking space": gettext("Nonbreaking space"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "None": gettext("None"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Numbered list": gettext("Numbered list"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Ok": gettext("Ok"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "OK": gettext("OK"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Page break": gettext("Page break"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paragraph": gettext("Paragraph"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paste as text": gettext("Paste as text"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": gettext("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off."), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paste row after": gettext("Paste row after"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paste row before": gettext("Paste row before"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paste your embed code below:": gettext("Paste your embed code below:"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Paste": gettext("Paste"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Poster": gettext("Poster"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Pre": gettext("Pre"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Prev": gettext("Prev"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Preview": gettext("Preview"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Print": gettext("Print"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Redo": gettext("Redo"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Remove link": gettext("Remove link"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Replace all": gettext("Replace all"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Replace all": gettext("Replace all"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Replace with": gettext("Replace with"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Replace": gettext("Replace"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Replace": gettext("Replace"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Restore last draft": gettext("Restore last draft"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": gettext("Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Right to left": gettext("Right to left"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Right": gettext("Right"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Robots": gettext("Robots"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Row group": gettext("Row group"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Row properties": gettext("Row properties"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Row type": gettext("Row type"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Row": gettext("Row"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Rows": gettext("Rows"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Save": gettext("Save"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Scope": gettext("Scope"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Select all": gettext("Select all"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Show blocks": gettext("Show blocks"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Show invisible characters": gettext("Show invisible characters"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Source code": gettext("Source code"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Source": gettext("Source"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Special character": gettext("Special character"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Spellcheck": gettext("Spellcheck"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Split cell": gettext("Split cell"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Square": gettext("Square"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Start search": gettext("Start search"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Strikethrough": gettext("Strikethrough"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Style": gettext("Style"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Subscript": gettext("Subscript"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Superscript": gettext("Superscript"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Table properties": gettext("Table properties"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Table": gettext("Table"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Target": gettext("Target"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Templates": gettext("Templates"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Text color": gettext("Text color"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Text to display": gettext("Text to display"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": gettext("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": gettext("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Title": gettext("Title"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Tools": gettext("Tools"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Top": gettext("Top"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Underline": gettext("Underline"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Undo": gettext("Undo"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Upper Alpha": gettext("Upper Alpha"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Upper Roman": gettext("Upper Roman"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Url": gettext("Url"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "V Align": gettext("V Align"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Vertical space": gettext("Vertical space"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "View": gettext("View"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Visual aids": gettext("Visual aids"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Whole words": gettext("Whole words"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Width": gettext("Width"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Words: {0}": gettext("Words: {0}"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "You have unsaved changes are you sure you want to navigate away?": gettext("You have unsaved changes are you sure you want to navigate away?"), - ### - Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.": gettext("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead."), - }) - - setupTinyMCE: (ed) => - ed.addButton('wrapAsCode', { - ### - Translators: this is a toolbar button tooltip from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - title : gettext('Code block'), - image : "#{baseUrl}/images/ico-tinymce-code.png", - onclick : () -> - ed.formatter.toggle('code') - }) - - ed.addButton('insertImage', { - ### - Translators: this is a toolbar button tooltip from the raw HTML editor displayed in the browser when a user needs to edit HTML - ### - title : gettext('Insert/Edit Image'), - icon: 'image', - onclick : @openImageModal - }) - - @visualEditor = ed - @imageModal = $('#edit-image-modal .modal') - - # These events were added to the plugin code as the TinyMCE PluginManager - # does not fire any events when plugins are opened or closed. - ed.on('SaveImage', @saveImage) - ed.on('EditImage', @editImage) - ed.on('SaveLink', @saveLink) - ed.on('EditLink', @editLink) - ed.on('ShowCodeEditor', @showCodeEditor) - ed.on('SaveCodeEditor', @saveCodeEditor) - - @imageModal.on('submitForm', @editImageSubmit) - - editImage: (data) => - # Called when the image plugin will be shown. Input arg is the JSON version of the image data. - if data['src'] - data['src'] = rewriteStaticLinks(data['src'], @base_asset_url, '/static/') - - saveImage: (data) => - # Called when the image plugin is saved. Input arg is the JSON version of the image data. - if data['src'] - data['src'] = rewriteStaticLinks(data['src'], '/static/', @base_asset_url) - - openImageModal: () => - img = $(@visualEditor.selection.getNode()) - imgAttrs = - baseAssetUrl: @base_asset_url - if img && img.is('img') - imgAttrs['src'] = rewriteStaticLinks(img.attr('src'), @base_asset_url, '/static/') - imgAttrs['alt'] = img.attr('alt') - imgAttrs['width'] = parseInt(img.attr('width'), 10) || img[0].naturalWidth - imgAttrs['height'] = parseInt(img.attr('height'), 10) || img[0].naturalHeight - imgAttrs['style'] = img.attr('style') - @imageModal[0].dispatchEvent(new CustomEvent('openModal', {bubbles: true, detail: imgAttrs})) - - closeImageModal: () => - @imageModal[0].dispatchEvent(new CustomEvent('closeModal', {bubbles: true})) - - saveImageFromModal: (data) => - # Insert img node from studio-frontend modal form data passed as a javascript object - if data['src'] - data['src'] = rewriteStaticLinks(data['src'], '/static/', @base_asset_url) - - @visualEditor.insertContent(@visualEditor.dom.createHTML('img', data)) - - editImageSubmit: (event) => - if event.detail - @saveImageFromModal(event.detail) - - editLink: (data) => - # Called when the link plugin will be shown. Input arg is the JSON version of the link data. - if data['href'] - data['href'] = rewriteStaticLinks(data['href'], @base_asset_url, '/static/') - - saveLink: (data) => - # Called when the link plugin is saved. Input arg is the JSON version of the link data. - if data['href'] - data['href'] = rewriteStaticLinks(data['href'], '/static/', @base_asset_url) - - showCodeEditor: (source) => - # Called when the CodeMirror Editor is displayed to convert links to show static prefix. - # The input argument is a dict with the text content. - content = rewriteStaticLinks(source.content, @base_asset_url, '/static/') - source.content = content - - saveCodeEditor: (source) => - # Called when the CodeMirror Editor is saved to convert links back to the full form. - # The input argument is a dict with the text content. - content = rewriteStaticLinks(source.content, '/static/', @base_asset_url) - source.content = content - - initInstanceCallback: (visualEditor) => - visualEditor.setContent(rewriteStaticLinks(visualEditor.getContent({no_events: 1}), '/static/', @base_asset_url)) - # Unfortunately, just setting visualEditor.isNortDirty = true is not enough to convince TinyMCE we - # haven't dirtied the Editor. Store the raw content so we can compare it later. - @starting_content = visualEditor.getContent({format:"raw", no_events: 1}) - visualEditor.focus() - - getVisualEditor: () -> - ### - Returns the instance of TinyMCE. - - Pulled out as a helper method for unit test. - ### - return @visualEditor - - save: -> - text = undefined - if @editor_choice == 'visual' - visualEditor = @getVisualEditor() - raw_content = visualEditor.getContent({format:"raw", no_events: 1}) - if @starting_content != raw_content - text = rewriteStaticLinks(visualEditor.getContent({no_events: 1}), @base_asset_url, '/static/') - - if text == undefined - text = @advanced_editor.getValue() - - data: text + width: '100%', + height: '400px', + menubar: false, + statusbar: false, + + /* + Necessary to avoid stripping of style tags. + */ + valid_children: "+body[style]", + + /* + Allow any elements to be used, e.g. link, script, math + */ + valid_elements: "*[*]", + extended_valid_elements: "*[*]", + invalid_elements: "", + setup: this.setupTinyMCE, + + /* + Cannot get access to tinyMCE Editor instance (for focusing) until after it is rendered. + The tinyMCE callback passes in the editor as a parameter. + */ + init_instance_callback: this.initInstanceCallback, + browser_spellcheck: true + }); + tinymce.addI18n('en', { + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Add to Dictionary": gettext("Add to Dictionary"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Advanced": gettext("Advanced"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Align center": gettext("Align center"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Align left": gettext("Align left"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Align right": gettext("Align right"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Alignment": gettext("Alignment"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Alternative source": gettext("Alternative source"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Anchor": gettext("Anchor"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Anchors": gettext("Anchors"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Author": gettext("Author"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Background color": gettext("Background color"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Blockquote": gettext("Blockquote"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Blocks": gettext("Blocks"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Body": gettext("Body"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Bold": gettext("Bold"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Border color": gettext("Border color"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Border": gettext("Border"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Bottom": gettext("Bottom"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Bullet list": gettext("Bullet list"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cancel": gettext("Cancel"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Caption": gettext("Caption"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cell padding": gettext("Cell padding"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cell properties": gettext("Cell properties"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cell spacing": gettext("Cell spacing"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cell type": gettext("Cell type"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cell": gettext("Cell"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Center": gettext("Center"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Circle": gettext("Circle"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Clear formatting": gettext("Clear formatting"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Close": gettext("Close"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Code block": gettext("Code block"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Code": gettext("Code"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Color": gettext("Color"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cols": gettext("Cols"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Column group": gettext("Column group"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Column": gettext("Column"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Constrain proportions": gettext("Constrain proportions"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Copy row": gettext("Copy row"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Copy": gettext("Copy"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Could not find the specified string.": gettext("Could not find the specified string."), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Custom color": gettext("Custom color"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Custom...": gettext("Custom..."), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cut row": gettext("Cut row"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Cut": gettext("Cut"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Decrease indent": gettext("Decrease indent"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Default": gettext("Default"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Delete column": gettext("Delete column"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Delete row": gettext("Delete row"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Delete table": gettext("Delete table"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Description": gettext("Description"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Dimensions": gettext("Dimensions"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Disc": gettext("Disc"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Div": gettext("Div"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Document properties": gettext("Document properties"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Edit HTML": gettext("Edit HTML"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Edit": gettext("Edit"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Embed": gettext("Embed"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Emoticons": gettext("Emoticons"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Encoding": gettext("Encoding"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "File": gettext("File"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Find and replace": gettext("Find and replace"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Find next": gettext("Find next"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Find previous": gettext("Find previous"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Find": gettext("Find"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Finish": gettext("Finish"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Font Family": gettext("Font Family"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Font Sizes": gettext("Font Sizes"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Footer": gettext("Footer"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Format": gettext("Format"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Formats": gettext("Formats"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Fullscreen": gettext("Fullscreen"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "General": gettext("General"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "H Align": gettext("H Align"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header 1": gettext("Header 1"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header 2": gettext("Header 2"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header 3": gettext("Header 3"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header 4": gettext("Header 4"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header 5": gettext("Header 5"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header 6": gettext("Header 6"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header cell": gettext("Header cell"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Header": gettext("Header"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Headers": gettext("Headers"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Heading 1": gettext("Heading 1"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Heading 2": gettext("Heading 2"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Heading 3": gettext("Heading 3"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Heading 4": gettext("Heading 4"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Heading 5": gettext("Heading 5"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Heading 6": gettext("Heading 6"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Headings": gettext("Headings"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Height": gettext("Height"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Horizontal line": gettext("Horizontal line"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Horizontal space": gettext("Horizontal space"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "HTML source code": gettext("HTML source code"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Ignore all": gettext("Ignore all"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Ignore": gettext("Ignore"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Image description": gettext("Image description"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Increase indent": gettext("Increase indent"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Inline": gettext("Inline"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert column after": gettext("Insert column after"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert column before": gettext("Insert column before"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert date/time": gettext("Insert date/time"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert image": gettext("Insert image"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert link": gettext("Insert link"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert row after": gettext("Insert row after"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert row before": gettext("Insert row before"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert table": gettext("Insert table"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert template": gettext("Insert template"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert video": gettext("Insert video"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert": gettext("Insert"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert/edit image": gettext("Insert/edit image"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert/edit link": gettext("Insert/edit link"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Insert/edit video": gettext("Insert/edit video"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Italic": gettext("Italic"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Justify": gettext("Justify"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Keywords": gettext("Keywords"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Left to right": gettext("Left to right"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Left": gettext("Left"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Lower Alpha": gettext("Lower Alpha"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Lower Greek": gettext("Lower Greek"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Lower Roman": gettext("Lower Roman"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Match case": gettext("Match case"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Merge cells": gettext("Merge cells"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Middle": gettext("Middle"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Name": gettext("Name"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "New document": gettext("New document"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "New window": gettext("New window"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Next": gettext("Next"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "No color": gettext("No color"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Nonbreaking space": gettext("Nonbreaking space"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "None": gettext("None"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Numbered list": gettext("Numbered list"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Ok": gettext("Ok"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "OK": gettext("OK"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Page break": gettext("Page break"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paragraph": gettext("Paragraph"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paste as text": gettext("Paste as text"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": gettext("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off."), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paste row after": gettext("Paste row after"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paste row before": gettext("Paste row before"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paste your embed code below:": gettext("Paste your embed code below:"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Paste": gettext("Paste"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Poster": gettext("Poster"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Pre": gettext("Pre"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Prev": gettext("Prev"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Preview": gettext("Preview"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Print": gettext("Print"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Redo": gettext("Redo"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Remove link": gettext("Remove link"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Replace all": gettext("Replace all"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Replace all": gettext("Replace all"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Replace with": gettext("Replace with"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Replace": gettext("Replace"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Replace": gettext("Replace"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Restore last draft": gettext("Restore last draft"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": gettext("Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Right to left": gettext("Right to left"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Right": gettext("Right"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Robots": gettext("Robots"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Row group": gettext("Row group"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Row properties": gettext("Row properties"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Row type": gettext("Row type"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Row": gettext("Row"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Rows": gettext("Rows"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Save": gettext("Save"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Scope": gettext("Scope"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Select all": gettext("Select all"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Show blocks": gettext("Show blocks"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Show invisible characters": gettext("Show invisible characters"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Source code": gettext("Source code"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Source": gettext("Source"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Special character": gettext("Special character"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Spellcheck": gettext("Spellcheck"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Split cell": gettext("Split cell"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Square": gettext("Square"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Start search": gettext("Start search"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Strikethrough": gettext("Strikethrough"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Style": gettext("Style"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Subscript": gettext("Subscript"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Superscript": gettext("Superscript"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Table properties": gettext("Table properties"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Table": gettext("Table"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Target": gettext("Target"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Templates": gettext("Templates"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Text color": gettext("Text color"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Text to display": gettext("Text to display"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": gettext("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": gettext("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Title": gettext("Title"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Tools": gettext("Tools"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Top": gettext("Top"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Underline": gettext("Underline"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Undo": gettext("Undo"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Upper Alpha": gettext("Upper Alpha"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Upper Roman": gettext("Upper Roman"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Url": gettext("Url"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "V Align": gettext("V Align"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Vertical space": gettext("Vertical space"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "View": gettext("View"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Visual aids": gettext("Visual aids"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Whole words": gettext("Whole words"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Width": gettext("Width"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Words: {0}": gettext("Words: {0}"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "You have unsaved changes are you sure you want to navigate away?": gettext("You have unsaved changes are you sure you want to navigate away?"), + + /* + Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.": gettext("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.") + }); + } + } + + HTMLEditingDescriptor.prototype.setupTinyMCE = function(ed) { + ed.addButton('wrapAsCode', { + + /* + Translators: this is a toolbar button tooltip from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + title: gettext('Code block'), + image: baseUrl + "/images/ico-tinymce-code.png", + onclick: function() { + return ed.formatter.toggle('code'); + } + }); + ed.addButton('insertImage', { + + /* + Translators: this is a toolbar button tooltip from the raw HTML editor displayed in the browser when a user needs to edit HTML + */ + title: gettext('Insert/Edit Image'), + icon: 'image', + onclick: this.openImageModal + }); + this.visualEditor = ed; + this.imageModal = $('#edit-image-modal .modal'); + + /* + These events were added to the plugin code as the TinyMCE PluginManager + does not fire any events when plugins are opened or closed. + */ + ed.on('SaveImage', this.saveImage); + ed.on('EditImage', this.editImage); + ed.on('SaveLink', this.saveLink); + ed.on('EditLink', this.editLink); + ed.on('ShowCodeEditor', this.showCodeEditor); + ed.on('SaveCodeEditor', this.saveCodeEditor); + return this.imageModal.on('submitForm', this.editImageSubmit); + }; + + HTMLEditingDescriptor.prototype.editImage = function(data) { + + /* + Called when the image plugin will be shown. Input arg is the JSON version of the image data. + */ + if (data['src']) { + return data['src'] = rewriteStaticLinks(data['src'], this.base_asset_url, '/static/'); + } + }; + + HTMLEditingDescriptor.prototype.saveImage = function(data) { + + /* + Called when the image plugin is saved. Input arg is the JSON version of the image data. + */ + if (data['src']) { + return data['src'] = rewriteStaticLinks(data['src'], '/static/', this.base_asset_url); + } + }; + + HTMLEditingDescriptor.prototype.openImageModal = function() { + var img, imgAttrs; + img = $(this.visualEditor.selection.getNode()); + imgAttrs = { + baseAssetUrl: this.base_asset_url + }; + if (img && img.is('img')) { + imgAttrs['src'] = rewriteStaticLinks(img.attr('src'), this.base_asset_url, '/static/'); + imgAttrs['alt'] = img.attr('alt'); + imgAttrs['width'] = parseInt(img.attr('width'), 10) || img[0].naturalWidth; + imgAttrs['height'] = parseInt(img.attr('height'), 10) || img[0].naturalHeight; + imgAttrs['style'] = img.attr('style'); + } + return this.imageModal[0].dispatchEvent(new CustomEvent('openModal', { + bubbles: true, + detail: imgAttrs + })); + }; + + HTMLEditingDescriptor.prototype.closeImageModal = function() { + return this.imageModal[0].dispatchEvent(new CustomEvent('closeModal', { + bubbles: true + })); + }; + + HTMLEditingDescriptor.prototype.saveImageFromModal = function(data) { + + /* + Insert img node from studio-frontend modal form data passed as a javascript object + */ + if (data['src']) { + data['src'] = rewriteStaticLinks(data['src'], '/static/', this.base_asset_url); + } + return this.visualEditor.insertContent(this.visualEditor.dom.createHTML('img', data)); + }; + + HTMLEditingDescriptor.prototype.editImageSubmit = function(event) { + if (event.detail) { + return this.saveImageFromModal(event.detail); + } + }; + + HTMLEditingDescriptor.prototype.editLink = function(data) { + + /* + Called when the link plugin will be shown. Input arg is the JSON version of the link data. + */ + if (data['href']) { + return data['href'] = rewriteStaticLinks(data['href'], this.base_asset_url, '/static/'); + } + }; + + HTMLEditingDescriptor.prototype.saveLink = function(data) { + + /* + Called when the link plugin is saved. Input arg is the JSON version of the link data. + */ + if (data['href']) { + return data['href'] = rewriteStaticLinks(data['href'], '/static/', this.base_asset_url); + } + }; + + HTMLEditingDescriptor.prototype.showCodeEditor = function(source) { + + /* + Called when the CodeMirror Editor is displayed to convert links to show static prefix. + The input argument is a dict with the text content. + */ + var content; + content = rewriteStaticLinks(source.content, this.base_asset_url, '/static/'); + return source.content = content; + }; + + HTMLEditingDescriptor.prototype.saveCodeEditor = function(source) { + + /* + Called when the CodeMirror Editor is saved to convert links back to the full form. + The input argument is a dict with the text content. + */ + var content; + content = rewriteStaticLinks(source.content, '/static/', this.base_asset_url); + return source.content = content; + }; + + HTMLEditingDescriptor.prototype.initInstanceCallback = function(visualEditor) { + visualEditor.setContent(rewriteStaticLinks(visualEditor.getContent({ + no_events: 1 + }), '/static/', this.base_asset_url)); + + /* + Unfortunately, just setting visualEditor.isNortDirty = true is not enough to convince TinyMCE we + haven't dirtied the Editor. Store the raw content so we can compare it later. + */ + this.starting_content = visualEditor.getContent({ + format: "raw", + no_events: 1 + }); + return visualEditor.focus(); + }; + + HTMLEditingDescriptor.prototype.getVisualEditor = function() { + /* + Returns the instance of TinyMCE. + Pulled out as a helper method for unit test. + */ + return this.visualEditor; + }; + + HTMLEditingDescriptor.prototype.save = function() { + var raw_content, text, visualEditor; + text = void 0; + if (this.editor_choice === 'visual') { + visualEditor = this.getVisualEditor(); + raw_content = visualEditor.getContent({ + format: "raw", + no_events: 1 + }); + if (this.starting_content !== raw_content) { + text = rewriteStaticLinks(visualEditor.getContent({ + no_events: 1 + }), this.base_asset_url, '/static/'); + } + } + if (text === void 0) { + text = this.advanced_editor.getValue(); + } + return { + data: text + }; + }; + + return HTMLEditingDescriptor; + + })(); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/raw/edit/json.js b/common/lib/xmodule/xmodule/js/src/raw/edit/json.js index 7c3c09cefc86..2de28c03f728 100644 --- a/common/lib/xmodule/xmodule/js/src/raw/edit/json.js +++ b/common/lib/xmodule/xmodule/js/src/raw/edit/json.js @@ -1,10 +1,32 @@ -class @JSONEditingDescriptor extends XModule.Descriptor - constructor: (@element) -> - @edit_box = CodeMirror.fromTextArea($(".edit-box", @element)[0], { - mode: { name: "javascript", json: true } - lineNumbers: true - lineWrapping: true - }) - - save: -> - data: JSON.parse @edit_box.getValue() +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + this.JSONEditingDescriptor = (function(superClass) { + extend(JSONEditingDescriptor, superClass); + + function JSONEditingDescriptor(element) { + this.element = element; + this.edit_box = CodeMirror.fromTextArea($(".edit-box", this.element)[0], { + mode: { + name: "javascript", + json: true + }, + lineNumbers: true, + lineWrapping: true + }); + } + + JSONEditingDescriptor.prototype.save = function() { + return { + data: JSON.parse(this.edit_box.getValue()) + }; + }; + + return JSONEditingDescriptor; + + })(XModule.Descriptor); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js b/common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js index 8c9afe86aa35..5c55c4b0f489 100644 --- a/common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js +++ b/common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js @@ -1,5 +1,24 @@ -class @MetadataOnlyEditingDescriptor extends XModule.Descriptor - constructor: (@element) -> +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - save: -> - data: null + this.MetadataOnlyEditingDescriptor = (function(superClass) { + extend(MetadataOnlyEditingDescriptor, superClass); + + function MetadataOnlyEditingDescriptor(element) { + this.element = element; + } + + MetadataOnlyEditingDescriptor.prototype.save = function() { + return { + data: null + }; + }; + + return MetadataOnlyEditingDescriptor; + + })(XModule.Descriptor); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/raw/edit/xml.js b/common/lib/xmodule/xmodule/js/src/raw/edit/xml.js index 68981e465bd1..b4215994d2c3 100644 --- a/common/lib/xmodule/xmodule/js/src/raw/edit/xml.js +++ b/common/lib/xmodule/xmodule/js/src/raw/edit/xml.js @@ -1,10 +1,29 @@ -class @XMLEditingDescriptor extends XModule.Descriptor - constructor: (@element) -> - @edit_box = CodeMirror.fromTextArea($(".edit-box", @element)[0], { - mode: "xml" - lineNumbers: true - lineWrapping: true - }) - - save: -> - data: @edit_box.getValue() +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + this.XMLEditingDescriptor = (function(superClass) { + extend(XMLEditingDescriptor, superClass); + + function XMLEditingDescriptor(element) { + this.element = element; + this.edit_box = CodeMirror.fromTextArea($(".edit-box", this.element)[0], { + mode: "xml", + lineNumbers: true, + lineWrapping: true + }); + } + + XMLEditingDescriptor.prototype.save = function() { + return { + data: this.edit_box.getValue() + }; + }; + + return XMLEditingDescriptor; + + })(XModule.Descriptor); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/sequence/edit.js b/common/lib/xmodule/xmodule/js/src/sequence/edit.js index 1856266697e9..3dacf1906403 100644 --- a/common/lib/xmodule/xmodule/js/src/sequence/edit.js +++ b/common/lib/xmodule/xmodule/js/src/sequence/edit.js @@ -1,2 +1,18 @@ -class @SequenceDescriptor extends XModule.Descriptor +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + this.SequenceDescriptor = (function(superClass) { + extend(SequenceDescriptor, superClass); + + function SequenceDescriptor() { + return SequenceDescriptor.__super__.constructor.apply(this, arguments); + } + + return SequenceDescriptor; + + })(XModule.Descriptor); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/tabs/tabs-aggregator.js b/common/lib/xmodule/xmodule/js/src/tabs/tabs-aggregator.js index e64d0ca84000..83baca4cf6e9 100644 --- a/common/lib/xmodule/xmodule/js/src/tabs/tabs-aggregator.js +++ b/common/lib/xmodule/xmodule/js/src/tabs/tabs-aggregator.js @@ -1,142 +1,190 @@ -class @TabsEditingDescriptor - @isInactiveClass : "is-inactive" - - constructor: (element) -> - @element = element; - ### - Not tested on syncing of multiple editors of same type in tabs - (Like many CodeMirrors). - ### - - @$tabs = $(".tab", @element) - @$content = $(".component-tab", @element) - - @element.find('.editor-tabs .tab').each (index, value) => - $(value).on('click', @onSwitchEditor) - - # If default visible tab is not setted or if were marked as current - # more than 1 tab just first tab will be shown - currentTab = @$tabs.filter('.current') - currentTab = @$tabs.first() if currentTab.length isnt 1 - @html_id = @$tabs.closest('.wrapper-comp-editor').data('html_id') - currentTab.trigger("click", [true, @html_id]) - - onSwitchEditor: (e, firstTime, html_id) => - e.preventDefault() - - isInactiveClass = TabsEditingDescriptor.isInactiveClass - $currentTarget = $(e.currentTarget) - - if not $currentTarget.hasClass('current') or firstTime is true - previousTab = null - - @$tabs.each( (index, value) -> - if $(value).hasClass('current') - previousTab = $(value).data('tab_name') - ) - - # init and save data from previous tab - TabsEditingDescriptor.Model.updateValue(@html_id, previousTab) - - # Save data from editor in previous tab to editor in current tab here. - # (to be implemented when there is a use case for this functionality) - - # call onswitch - onSwitchFunction = TabsEditingDescriptor.Model.modules[@html_id].tabSwitch[$currentTarget.data('tab_name')] - onSwitchFunction() if $.isFunction(onSwitchFunction) - - @$tabs.removeClass('current') - $currentTarget.addClass('current') - - # Tabs are implemeted like anchors. Therefore we can use hash to find - # corresponding content - content_id = $currentTarget.attr('href') - - @$content - .addClass(isInactiveClass) - .filter(content_id) - .removeClass(isInactiveClass) - - save: -> - @element.off('click', '.editor-tabs .tab', @onSwitchEditor) - current_tab = @$tabs.filter('.current').data('tab_name') - data: TabsEditingDescriptor.Model.getValue(@html_id, current_tab) - - setMetadataEditor : (metadataEditor) -> - TabsEditingDescriptor.setMetadataEditor.apply(TabsEditingDescriptor, arguments) - - getStorage : () -> - TabsEditingDescriptor.getStorage() - - addToStorage : (id, data) -> - TabsEditingDescriptor.addToStorage.apply(TabsEditingDescriptor, arguments) - - @Model : - addModelUpdate : (id, tabName, modelUpdateFunction) -> - ### - Function that registers 'modelUpdate' functions of every tab. - These functions are used to update value, which will be returned - by calling save on component. - ### - @initialize(id) - @modules[id].modelUpdate[tabName] = modelUpdateFunction - - addOnSwitch : (id, tabName, onSwitchFunction) -> - ### - Function that registers functions invoked when switching - to particular tab. - ### - @initialize(id) - @modules[id].tabSwitch[tabName] = onSwitchFunction - - updateValue : (id, tabName) -> - ### - Function that invokes when switching tabs. - It ensures that data from previous tab is stored. - If new tab need this data, it should retrieve it from - stored value. - ### - @initialize(id) - modelUpdateFunction = @modules[id]['modelUpdate'][tabName] - @modules[id]['value'] = modelUpdateFunction() if $.isFunction(modelUpdateFunction) - - getValue : (id, tabName) -> - ### - Retrieves stored data on component save. - 1. When we switching tabs - previous tab data is always saved to @[id].value - 2. If current tab have registered 'modelUpdate' method, it should be invoked 1st. - (If we have edited in 1st tab, then switched to 2nd, 2nd tab should - care about getting data from @[id].value in onSwitch.) - ### - if not @modules[id] - return null - if $.isFunction(@modules[id]['modelUpdate'][tabName]) - return @modules[id]['modelUpdate'][tabName]() - else - if typeof @modules[id]['value'] is 'undefined' - return null - else - return @modules[id]['value'] - - # html_id's of descriptors will be stored in modules variable as - # containers for callbacks. - modules: {} - Storage: {} - - initialize : (id) -> - ### - Initialize objects per id. Id is html_id of descriptor. - ### - @modules[id] = @modules[id] or {} - @modules[id].tabSwitch = @modules[id]['tabSwitch'] or {} - @modules[id].modelUpdate = @modules[id]['modelUpdate'] or {} - - @setMetadataEditor : (metadataEditor) -> - TabsEditingDescriptor.Model.Storage['MetadataEditor'] = metadataEditor - - @addToStorage : (id, data) -> - TabsEditingDescriptor.Model.Storage[id] = data - - @getStorage : () -> - TabsEditingDescriptor.Model.Storage - +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + this.TabsEditingDescriptor = (function() { + TabsEditingDescriptor.isInactiveClass = "is-inactive"; + + function TabsEditingDescriptor(element) { + this.onSwitchEditor = bind(this.onSwitchEditor, this); + var currentTab; + this.element = element; + + /* + Not tested on syncing of multiple editors of same type in tabs + (Like many CodeMirrors). + */ + this.$tabs = $(".tab", this.element); + this.$content = $(".component-tab", this.element); + this.element.find('.editor-tabs .tab').each((function(_this) { + return function(index, value) { + return $(value).on('click', _this.onSwitchEditor); + }; + })(this)); + + /* + If default visible tab is not setted or if were marked as current + more than 1 tab just first tab will be shown + */ + currentTab = this.$tabs.filter('.current'); + if (currentTab.length !== 1) { + currentTab = this.$tabs.first(); + } + this.html_id = this.$tabs.closest('.wrapper-comp-editor').data('html_id'); + currentTab.trigger("click", [true, this.html_id]); + } + + TabsEditingDescriptor.prototype.onSwitchEditor = function(e, firstTime, html_id) { + var $currentTarget, content_id, isInactiveClass, onSwitchFunction, previousTab; + e.preventDefault(); + isInactiveClass = TabsEditingDescriptor.isInactiveClass; + $currentTarget = $(e.currentTarget); + if (!$currentTarget.hasClass('current') || firstTime === true) { + previousTab = null; + this.$tabs.each(function(index, value) { + if ($(value).hasClass('current')) { + return previousTab = $(value).data('tab_name'); + } + }); + + /* + init and save data from previous tab + */ + TabsEditingDescriptor.Model.updateValue(this.html_id, previousTab); + + /* + Save data from editor in previous tab to editor in current tab here. + (to be implemented when there is a use case for this functionality) + */ + + // call onswitch + onSwitchFunction = TabsEditingDescriptor.Model.modules[this.html_id].tabSwitch[$currentTarget.data('tab_name')]; + if ($.isFunction(onSwitchFunction)) { + onSwitchFunction(); + } + this.$tabs.removeClass('current'); + $currentTarget.addClass('current'); + + /* + Tabs are implemeted like anchors. Therefore we can use hash to find + corresponding content + */ + content_id = $currentTarget.attr('href'); + return this.$content.addClass(isInactiveClass).filter(content_id).removeClass(isInactiveClass); + } + }; + + TabsEditingDescriptor.prototype.save = function() { + var current_tab; + this.element.off('click', '.editor-tabs .tab', this.onSwitchEditor); + current_tab = this.$tabs.filter('.current').data('tab_name'); + return { + data: TabsEditingDescriptor.Model.getValue(this.html_id, current_tab) + }; + }; + + TabsEditingDescriptor.prototype.setMetadataEditor = function(metadataEditor) { + return TabsEditingDescriptor.setMetadataEditor.apply(TabsEditingDescriptor, arguments); + }; + + TabsEditingDescriptor.prototype.getStorage = function() { + return TabsEditingDescriptor.getStorage(); + }; + + TabsEditingDescriptor.prototype.addToStorage = function(id, data) { + return TabsEditingDescriptor.addToStorage.apply(TabsEditingDescriptor, arguments); + }; + + TabsEditingDescriptor.Model = { + addModelUpdate: function(id, tabName, modelUpdateFunction) { + + /* + Function that registers 'modelUpdate' functions of every tab. + These functions are used to update value, which will be returned + by calling save on component. + */ + this.initialize(id); + return this.modules[id].modelUpdate[tabName] = modelUpdateFunction; + }, + addOnSwitch: function(id, tabName, onSwitchFunction) { + + /* + Function that registers functions invoked when switching + to particular tab. + */ + this.initialize(id); + return this.modules[id].tabSwitch[tabName] = onSwitchFunction; + }, + updateValue: function(id, tabName) { + + /* + Function that invokes when switching tabs. + It ensures that data from previous tab is stored. + If new tab need this data, it should retrieve it from + stored value. + */ + var modelUpdateFunction; + this.initialize(id); + modelUpdateFunction = this.modules[id]['modelUpdate'][tabName]; + if ($.isFunction(modelUpdateFunction)) { + return this.modules[id]['value'] = modelUpdateFunction(); + } + }, + getValue: function(id, tabName) { + + /* + Retrieves stored data on component save. + 1. When we switching tabs - previous tab data is always saved to @[id].value + 2. If current tab have registered 'modelUpdate' method, it should be invoked 1st. + (If we have edited in 1st tab, then switched to 2nd, 2nd tab should + care about getting data from @[id].value in onSwitch.) + */ + if (!this.modules[id]) { + return null; + } + if ($.isFunction(this.modules[id]['modelUpdate'][tabName])) { + return this.modules[id]['modelUpdate'][tabName](); + } else { + if (typeof this.modules[id]['value'] === 'undefined') { + return null; + } else { + return this.modules[id]['value']; + } + } + }, + + /* + html_id's of descriptors will be stored in modules variable as + containers for callbacks. + */ + modules: {}, + Storage: {}, + initialize: function(id) { + + /* + Initialize objects per id. Id is html_id of descriptor. + */ + this.modules[id] = this.modules[id] || {}; + this.modules[id].tabSwitch = this.modules[id]['tabSwitch'] || {}; + return this.modules[id].modelUpdate = this.modules[id]['modelUpdate'] || {}; + } + }; + + TabsEditingDescriptor.setMetadataEditor = function(metadataEditor) { + return TabsEditingDescriptor.Model.Storage['MetadataEditor'] = metadataEditor; + }; + + TabsEditingDescriptor.addToStorage = function(id, data) { + return TabsEditingDescriptor.Model.Storage[id] = data; + }; + + TabsEditingDescriptor.getStorage = function() { + return TabsEditingDescriptor.Model.Storage; + }; + + return TabsEditingDescriptor; + + })(); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/vertical/edit.js b/common/lib/xmodule/xmodule/js/src/vertical/edit.js index 09bec3bef5f0..bfaf849a6667 100644 --- a/common/lib/xmodule/xmodule/js/src/vertical/edit.js +++ b/common/lib/xmodule/xmodule/js/src/vertical/edit.js @@ -1,2 +1,18 @@ -class @VerticalDescriptor extends XModule.Descriptor +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + this.VerticalDescriptor = (function(superClass) { + extend(VerticalDescriptor, superClass); + + function VerticalDescriptor() { + return VerticalDescriptor.__super__.constructor.apply(this, arguments); + } + + return VerticalDescriptor; + + })(XModule.Descriptor); + +}).call(this); diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py index 535b4ede5767..ed7bc20a4faf 100644 --- a/common/lib/xmodule/xmodule/library_content_module.py +++ b/common/lib/xmodule/xmodule/library_content_module.py @@ -409,7 +409,7 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe module_class = LibraryContentModule mako_template = 'widgets/metadata-edit.html' - js = {'coffee': [resource_string(__name__, 'js/src/vertical/edit.coffee')]} + js = {'js': [resource_string(__name__, 'js/src/vertical/edit.js')]} js_module_name = "VerticalDescriptor" show_in_read_only_mode = True diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index 8f7320381c68..b657f4816004 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -642,7 +642,7 @@ class SequenceDescriptor(SequenceFields, ProctoringFields, MakoModuleDescriptor, show_in_read_only_mode = True js = { - 'coffee': [resource_string(__name__, 'js/src/sequence/edit.coffee')], + 'js': [resource_string(__name__, 'js/src/sequence/edit.js')], } js_module_name = "SequenceDescriptor" diff --git a/common/lib/xmodule/xmodule/textannotation_module.py b/common/lib/xmodule/xmodule/textannotation_module.py index b2ee3504bb4c..6fb52708fdb9 100644 --- a/common/lib/xmodule/xmodule/textannotation_module.py +++ b/common/lib/xmodule/xmodule/textannotation_module.py @@ -92,8 +92,7 @@ class AnnotatableFields(object): class TextAnnotationModule(AnnotatableFields, XModule): ''' Text Annotation Module ''' - js = {'coffee': [], - 'js': []} + js = {'js': []} css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]} icon_class = 'textannotation' diff --git a/common/lib/xmodule/xmodule/videoannotation_module.py b/common/lib/xmodule/xmodule/videoannotation_module.py index feee166c264c..e46ca53779ae 100644 --- a/common/lib/xmodule/xmodule/videoannotation_module.py +++ b/common/lib/xmodule/xmodule/videoannotation_module.py @@ -85,11 +85,9 @@ class AnnotatableFields(object): class VideoAnnotationModule(AnnotatableFields, XModule): '''Video Annotation Module''' js = { - 'coffee': [ - resource_string(__name__, 'js/src/html/display.coffee'), - resource_string(__name__, 'js/src/annotatable/display.coffee'), - ], 'js': [ + resource_string(__name__, 'js/src/html/display.js'), + resource_string(__name__, 'js/src/annotatable/display.js'), resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] diff --git a/common/static/coffee/src/.gitignore b/common/static/coffee/src/.gitignore deleted file mode 100644 index a6c7c2852d06..000000000000 --- a/common/static/coffee/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.js diff --git a/common/static/common/js/karma.common.conf.js b/common/static/common/js/karma.common.conf.js index 938dbe61c4a0..de12b1544392 100644 --- a/common/static/common/js/karma.common.conf.js +++ b/common/static/common/js/karma.common.conf.js @@ -65,7 +65,6 @@ var commonFiles = { {pattern: 'common/js/vendor/**/*.js'}, {pattern: 'edx-pattern-library/js/**/*.js'}, {pattern: 'edx-ui-toolkit/js/**/*.js'}, - {pattern: 'xmodule_js/common_static/coffee/src/**/!(*spec).js'}, {pattern: 'xmodule_js/common_static/common/js/**/!(*spec).js'}, {pattern: 'xmodule_js/common_static/js/**/!(*spec).js'}, {pattern: 'xmodule_js/src/**/*.js'} diff --git a/common/static/common/js/spec/main_requirejs.js b/common/static/common/js/spec/main_requirejs.js index a155145984f1..65e2161845d4 100644 --- a/common/static/common/js/spec/main_requirejs.js +++ b/common/static/common/js/spec/main_requirejs.js @@ -26,7 +26,7 @@ 'jquery.fileupload': 'js/vendor/jQuery-File-Upload/js/jquery.fileupload', 'jquery.iframe-transport': 'js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', 'jquery.inputnumber': 'js/vendor/html5-input-polyfills/number-polyfill', - 'jquery.immediateDescendents': 'coffee/src/jquery.immediateDescendents', + 'jquery.immediateDescendents': 'js/src/jquery.immediateDescendents', 'jquery.simulate': 'js/vendor/jquery.simulate', 'jquery.url': 'js/vendor/url.min', 'sinon': 'common/js/vendor/sinon', diff --git a/common/static/css/tinymce-studio-content.css b/common/static/css/tinymce-studio-content.css index 8ae477421128..724c2737b6f3 100644 --- a/common/static/css/tinymce-studio-content.css +++ b/common/static/css/tinymce-studio-content.css @@ -3,7 +3,7 @@ padding: 10px; background-color: #fff; /* keep font-family in sync with CUSTOM_FONTS constant in Html editor XModule - * (edx-platform/common/lib/xmodule/xmodule/js/src/html/edit.coffee) + * (edx-platform/common/lib/xmodule/xmodule/js/src/html/edit.js) * and with acceptance tests in cms/djangoapps/contentstore/features/html-editor.feature */ font-family: 'Open Sans', Verdana, Arial, Helvetica, sans-serif; diff --git a/common/static/coffee/spec/jquery.immediateDescendents_spec.js b/common/static/js/spec/jquery.immediateDescendents_spec.js similarity index 100% rename from common/static/coffee/spec/jquery.immediateDescendents_spec.js rename to common/static/js/spec/jquery.immediateDescendents_spec.js diff --git a/common/static/js/src/ajax_prefix.js b/common/static/js/src/ajax_prefix.js index 59db5becca11..d5b1324d88f4 100644 --- a/common/static/js/src/ajax_prefix.js +++ b/common/static/js/src/ajax_prefix.js @@ -1,16 +1,24 @@ -@AjaxPrefix = - addAjaxPrefix: (jQuery, prefix) -> - jQuery.postWithPrefix = (url, data, callback, type) -> - $.post("#{prefix()}#{url}", data, callback, type) - - jQuery.getWithPrefix = (url, data, callback, type) -> - $.get("#{prefix()}#{url}", data, callback, type) - - jQuery.ajaxWithPrefix = (url, settings) -> - if settings? - $.ajax("#{prefix()}#{url}", settings) - else - settings = url - settings.url = "#{prefix()}#{settings.url}" - $.ajax settings +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + this.AjaxPrefix = { + addAjaxPrefix: function(jQuery, prefix) { + jQuery.postWithPrefix = function(url, data, callback, type) { + return $.post("" + (prefix()) + url, data, callback, type); + }; + jQuery.getWithPrefix = function(url, data, callback, type) { + return $.get("" + (prefix()) + url, data, callback, type); + }; + return jQuery.ajaxWithPrefix = function(url, settings) { + if (settings != null) { + return $.ajax("" + (prefix()) + url, settings); + } else { + settings = url; + settings.url = "" + (prefix()) + settings.url; + return $.ajax(settings); + } + }; + } + }; +}).call(this); diff --git a/common/static/js/src/jquery.immediateDescendents.js b/common/static/js/src/jquery.immediateDescendents.js index e2ee15c6d7f6..295a2746a841 100644 --- a/common/static/js/src/jquery.immediateDescendents.js +++ b/common/static/js/src/jquery.immediateDescendents.js @@ -1,11 +1,23 @@ -# Find all the children of an element that match the selector, but only -# the first instance found down any path. For example, we'll find all -# the ".xblock" elements below us, but not the ones that are themselves -# contained somewhere inside ".xblock" elements. -jQuery.fn.immediateDescendents = (selector) -> - @children().map -> - elem = jQuery(this) - if elem.is(selector) - this - else - elem.immediateDescendents(selector).get() +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ + +/* +Find all the children of an element that match the selector, but only +the first instance found down any path. For example, we'll find all +the ".xblock" elements below us, but not the ones that are themselves +contained somewhere inside ".xblock" elements. + */ +(function() { + jQuery.fn.immediateDescendents = function(selector) { + return this.children().map(function() { + var elem; + elem = jQuery(this); + if (elem.is(selector)) { + return this; + } else { + return elem.immediateDescendents(selector).get(); + } + }); + }; + +}).call(this); diff --git a/common/static/js/src/xproblem.js b/common/static/js/src/xproblem.js index 7f93ac1de027..8f950e7321dd 100644 --- a/common/static/js/src/xproblem.js +++ b/common/static/js/src/xproblem.js @@ -1,47 +1,76 @@ -class XProblemGenerator - - constructor: (seed, @parameters={}) -> +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + var XProblemDisplay, XProblemGenerator, XProblemGrader, root; - @random = new MersenneTwister(seed) + XProblemGenerator = (function() { + function XProblemGenerator(seed, parameters) { + this.parameters = parameters != null ? parameters : {}; + this.random = new MersenneTwister(seed); + this.problemState = {}; + } - @problemState = {} + XProblemGenerator.prototype.generate = function() { + return console.error("Abstract method called: XProblemGenerator.generate"); + }; - generate: () -> + return XProblemGenerator; - console.error("Abstract method called: XProblemGenerator.generate") + })(); -class XProblemDisplay + XProblemDisplay = (function() { + function XProblemDisplay(state, submission, evaluation, container, submissionField, parameters) { + this.state = state; + this.submission = submission; + this.evaluation = evaluation; + this.container = container; + this.submissionField = submissionField; + this.parameters = parameters != null ? parameters : {}; + } - constructor: (@state, @submission, @evaluation, @container, @submissionField, @parameters={}) -> + XProblemDisplay.prototype.render = function() { + return console.error("Abstract method called: XProblemDisplay.render"); + }; - render: () -> + XProblemDisplay.prototype.updateSubmission = function() { + return this.submissionField.val(JSON.stringify(this.getCurrentSubmission())); + }; - console.error("Abstract method called: XProblemDisplay.render") + XProblemDisplay.prototype.getCurrentSubmission = function() { + return console.error("Abstract method called: XProblemDisplay.getCurrentSubmission"); + }; - updateSubmission: () -> + return XProblemDisplay; - @submissionField.val(JSON.stringify(@getCurrentSubmission())) + })(); - getCurrentSubmission: () -> - console.error("Abstract method called: XProblemDisplay.getCurrentSubmission") + XProblemGrader = (function() { + function XProblemGrader(submission, problemState, parameters) { + this.submission = submission; + this.problemState = problemState; + this.parameters = parameters != null ? parameters : {}; + this.solution = null; + this.evaluation = {}; + } -class XProblemGrader + XProblemGrader.prototype.solve = function() { + return console.error("Abstract method called: XProblemGrader.solve"); + }; - constructor: (@submission, @problemState, @parameters={}) -> + XProblemGrader.prototype.grade = function() { + return console.error("Abstract method called: XProblemGrader.grade"); + }; - @solution = null - @evaluation = {} + return XProblemGrader; - solve: () -> + })(); - console.error("Abstract method called: XProblemGrader.solve") + root = typeof exports !== "undefined" && exports !== null ? exports : this; - grade: () -> + root.XProblemGenerator = XProblemGenerator; - console.error("Abstract method called: XProblemGrader.grade") + root.XProblemDisplay = XProblemDisplay; -root = exports ? this + root.XProblemGrader = XProblemGrader; -root.XProblemGenerator = XProblemGenerator -root.XProblemDisplay = XProblemDisplay -root.XProblemGrader = XProblemGrader +}).call(this); diff --git a/common/static/karma_common.conf.js b/common/static/karma_common.conf.js index 427dbc1a6eb3..28039cccc6c6 100644 --- a/common/static/karma_common.conf.js +++ b/common/static/karma_common.conf.js @@ -16,11 +16,11 @@ var options = { // Avoid adding files to this list. Use RequireJS. libraryFilesToInclude: [ - {pattern: 'coffee/src/ajax_prefix.js', included: true}, + {pattern: 'js/src/ajax_prefix.js', included: true}, {pattern: 'js/vendor/draggabilly.js', included: true}, {pattern: 'common/js/vendor/jquery.js', included: true}, {pattern: 'common/js/vendor/jquery-migrate.js', included: true}, - {pattern: 'coffee/src/jquery.immediateDescendents.js', included: true}, + {pattern: 'js/src/jquery.immediateDescendents.js', included: true}, {pattern: 'js/vendor/jquery.leanModal.js', included: true}, {pattern: 'js/vendor/jquery.timeago.js', included: true}, {pattern: 'js/vendor/jquery.truncate.js', included: true}, @@ -49,7 +49,6 @@ var options = { // Make sure the patterns in sourceFiles and specFiles do not match the same file. // Otherwise Istanbul which is used for coverage tracking will cause tests to not run. sourceFiles: [ - {pattern: 'coffee/src/**/*.js', included: true}, {pattern: 'common/js/xblock/core.js', included: true}, {pattern: 'common/js/xblock/runtime.v1.js', included: true}, {pattern: 'common/js/discussion/**/*.js', included: true}, @@ -58,7 +57,6 @@ var options = { ], specFiles: [ - {pattern: 'coffee/spec/**/*.js', included: true}, {pattern: 'common/js/spec/xblock/*.js', included: true}, {pattern: 'common/js/spec/discussion/**/*spec.js', included: true}, {pattern: 'js/**/*spec.js', included: true} diff --git a/common/static/karma_common_requirejs.conf.js b/common/static/karma_common_requirejs.conf.js index e8152fe69c8f..f0151b5a6d9b 100644 --- a/common/static/karma_common_requirejs.conf.js +++ b/common/static/karma_common_requirejs.conf.js @@ -16,7 +16,6 @@ var options = { }, libraryFiles: [ - {pattern: 'coffee/src/**/*.js'}, {pattern: 'js/libs/**/*.js'}, {pattern: 'js/test/**/*.js'}, {pattern: 'js/vendor/**/*.js'} diff --git a/docs/static_assets.rst b/docs/static_assets.rst index 4224a0d015e7..621d6311cec3 100644 --- a/docs/static_assets.rst +++ b/docs/static_assets.rst @@ -66,9 +66,8 @@ out when files are missing (added when we started dynamically scanning XBlocks for assets). The ``django-pipeline`` config is aware of CSS files for the purposes of -concatenation, but it does *not* know about the source Sass files (or handful of -remaining CoffeeScript files). Those are processed with paver tasks before -``django-pipeline`` ever sees them. +concatenation, but it does *not* know about the source Sass files. +Those are processed with paver tasks before ``django-pipeline`` ever sees them. We also have the following custom extensions to Django's builtin ``STATICFILES`` mechanism: @@ -168,8 +167,7 @@ also be responsible for the optimization/minification of JavaScript assets, but those optimized assets would only appear under the ``/webpack`` directory. Third party assets that Webpack is not aware of may have hash suffixes applied to them by the Django collectstatic layer, but will not otherwise be processed or -optimized in any way -- so no coffeescript/sass compilation, no uglifyjs -minification, etc. +optimized in any way -- so no sass compilation, no uglifyjs minification, etc. The django-pipeline dependency should be removed altogether. diff --git a/docs/testing.rst b/docs/testing.rst index 122b25fe6690..918dac1e1a5e 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -92,10 +92,10 @@ Test Locations - Javascript unit tests: Located in ``spec`` folders. For example, ``common/lib/xmodule/xmodule/js/spec`` and - ``{cms,lms}/static/coffee/spec`` For consistency, you should use the + ``{cms,lms}/static/js/spec`` For consistency, you should use the same directory structure for implementation and test. For example, - the test for ``src/views/module.coffee`` should be written in - ``spec/views/module_spec.coffee``. + the test for ``src/views/module.js`` should be written in + ``spec/views/module_spec.js``. - UI acceptance tests: @@ -151,8 +151,8 @@ For example, this command runs all the python test scripts:: paver test_python It also runs ``collectstatic``, which prepares the -static files used by the site (for example, compiling CoffeeScript to -JavaScript). +static files used by the site (for example, compiling Sass to +CSS). You can re-run all failed python tests by running this command (see note at end of section):: @@ -332,7 +332,6 @@ To run a specific set of JavaScript tests and print the results to the console, run these commands:: paver test_js_run -s lms - paver test_js_run -s lms-coffee paver test_js_run -s cms paver test_js_run -s cms-squire paver test_js_run -s xmodule @@ -342,7 +341,6 @@ console, run these commands:: To run JavaScript tests in a browser, run these commands:: paver test_js_dev -s lms - paver test_js_dev -s lms-coffee paver test_js_dev -s cms paver test_js_dev -s cms-squire paver test_js_dev -s xmodule diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 95adfcba7902..9e9337e7a64e 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -1241,7 +1241,7 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=red ] # Provide human-friendly and translatable names for these features. These names - # will be displayed in the table generated in data_download.coffee. It is not (yet) + # will be displayed in the table generated in data_download.js. It is not (yet) # used as the header row in the CSV, but could be in the future. query_features_names = { 'id': _('User ID'), diff --git a/lms/djangoapps/notes/README.md b/lms/djangoapps/notes/README.md index 233575ddacf9..07bcfa3d221a 100644 --- a/lms/djangoapps/notes/README.md +++ b/lms/djangoapps/notes/README.md @@ -48,7 +48,7 @@ lms/djangoapps/notes: Also requires: -* lms/static/coffee/src/notes.coffee -- wrapper around annotator.js +* lms/static/js/notes.js -- wrapper around annotator.js * lms/templates/notes.html -- used by views.py to display the notes Interacts with: diff --git a/lms/envs/common.py b/lms/envs/common.py index 4cf56e234162..292257af79d5 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -448,7 +448,6 @@ node_paths = [ COMMON_ROOT / "static/js/vendor", - COMMON_ROOT / "static/coffee/src", system_node_path, ] NODE_PATH = ':'.join(node_paths) @@ -1163,10 +1162,6 @@ def _make_locale_paths(settings): # if parental consent is never required. PARENTAL_CONSENT_AGE_LIMIT = 13 -################################# Jasmine ################################## -JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee' - - ######################### Branded Footer ################################### # Constants for the footer used on the site and shared with other sites # (such as marketing and the blog) via the branding API. @@ -1340,14 +1335,13 @@ def _make_locale_paths(settings): from openedx.core.lib.rooted_paths import rooted_glob -courseware_js = ( - [ - 'coffee/src/' + pth + '.js' - for pth in ['courseware', 'histogram', 'navigation'] - ] + - ['js/' + pth + '.js' for pth in ['ajax-error']] + - sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/modules/**/*.js')) -) +courseware_js = [ + 'js/ajax-error.js', + 'js/courseware.js', + 'js/histogram.js', + 'js/navigation.js', + 'js/modules/tab.js', +] proctoring_js = ( [ @@ -1428,9 +1422,9 @@ def _make_locale_paths(settings): ) discussion_js = ( rooted_glob(COMMON_ROOT / 'static', 'common/js/discussion/mathjax_include.js') + - rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/customwmd.js') + - rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/mathjax_accessible.js') + - rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/mathjax_delay_renderer.js') + + rooted_glob(PROJECT_ROOT / 'static', 'js/customwmd.js') + + rooted_glob(PROJECT_ROOT / 'static', 'js/mathjax_accessible.js') + + rooted_glob(PROJECT_ROOT / 'static', 'js/mathjax_delay_renderer.js') + sorted(rooted_glob(COMMON_ROOT / 'static', 'common/js/discussion/**/*.js')) ) @@ -1445,7 +1439,7 @@ def _make_locale_paths(settings): 'js/split.js' ] -notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js')) +notes_js = ['js/notes.js'] instructor_dash_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/instructor_dashboard/**/*.js')) verify_student_js = [ @@ -1682,15 +1676,21 @@ def _make_locale_paths(settings): }, } - -separately_bundled_js = set(courseware_js + discussion_js + notes_js + instructor_dash_js) -common_js = sorted(set(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/**/*.js')) - separately_bundled_js) +common_js = [ + 'js/src/ajax_prefix.js', + 'js/src/jquery.immediateDescendents.js', + 'js/src/xproblem.js', +] xblock_runtime_js = [ 'common/js/xblock/core.js', 'common/js/xblock/runtime.v1.js', 'lms/js/xblock/lms.runtime.v1.js', ] -lms_application_js = sorted(set(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/**/*.js')) - separately_bundled_js) +lms_application_js = [ + 'js/calculator.js', + 'js/feedback_form.js', + 'js/main.js', +] PIPELINE_JS = { 'base_application': { @@ -1796,10 +1796,6 @@ def _make_locale_paths(settings): "sass/*/*.scss", "sass/*/*/*.scss", "sass/*/*/*/*.scss", - "coffee/*.coffee", - "coffee/*/*.coffee", - "coffee/*/*/*.coffee", - "coffee/*/*/*/*.coffee", # Ignore tests "spec", diff --git a/lms/static/coffee/README.md b/lms/static/coffee/README.md deleted file mode 100644 index 5e54f56a169e..000000000000 --- a/lms/static/coffee/README.md +++ /dev/null @@ -1,44 +0,0 @@ -CoffeeScript -============ - -This folder contains the CoffeeScript file that will be compiled to the static -directory. By default, we're compile and merge all the files ending `.coffee` -into `static/js/application.js`. - -Install the Compiler --------------------- - -CoffeeScript compiler are written in JavaScript. You'll need to install Node and -npm (Node Package Manager) to be able to install the CoffeeScript compiler. - -### Mac OS X - -Install Node via Homebrew, then use npm: - - $ brew install node - $ curl http://npmjs.org/install.sh | sh - $ npm install -g git://github.com/jashkenas/coffee-script.git - -(Note that we're using the edge version of CoffeeScript for now, as there was -some issue with directory watching in 1.3.1.) - -Try to run `coffee` and make sure you get a coffee prompt. - -### Debian/Ubuntu - -Conveniently, you can install Node via `apt-get`, then use npm: - - $ sudo apt-get install nodejs npm && - $ sudo npm install -g git://github.com/jashkenas/coffee-script.git - -Compiling ---------- - -CoffeeScript is compiled when you update assets using the command: - - $ paver update_assets - -Testing -------- - -We use Jasmine to unit-test the JavaScript files. See `docs/en_us/internal/testing.rst` for details. diff --git a/lms/static/coffee/src/.gitignore b/lms/static/coffee/src/.gitignore deleted file mode 100644 index a6c7c2852d06..000000000000 --- a/lms/static/coffee/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.js diff --git a/lms/static/js/calculator.js b/lms/static/js/calculator.js index 0c5f4795a6ab..5edb83fd1017 100644 --- a/lms/static/js/calculator.js +++ b/lms/static/js/calculator.js @@ -1,224 +1,274 @@ -# Keyboard Support - -# If focus is on the hint button: -# * Enter: Open or close hint popup. Select last focused hint item if opening -# * Space: Open or close hint popup. Select last focused hint item if opening - -# If focus is on a hint item: -# * Left arrow: Select previous hint item -# * Up arrow: Select previous hint item -# * Right arrow: Select next hint item -# * Down arrow: Select next hint item - - -class @Calculator - constructor: -> - @hintButton = $('#calculator_hint') - @calcInput = $('#calculator_input') - @hintPopup = $('.help') - @hintsList = @hintPopup.find('.hint-item') - @selectHint($('#' + @hintPopup.attr('data-calculator-hint'))); - - $('.calc').click @toggle - $('form#calculator').submit(@calculate).submit (e) -> - e.preventDefault() - - @hintButton - .click(($.proxy(@handleClickOnHintButton, @))) - - @hintPopup - .click(($.proxy(@handleClickOnHintPopup, @))) - - @hintPopup - .keydown($.proxy(@handleKeyDownOnHint, @)) - - $('#calculator_wrapper') - .keyup($.proxy(@handleKeyUpOnHint, @)) - - @handleClickOnDocument = $.proxy(@handleClickOnDocument, @) - - @calcInput - .focus(($.proxy(@inputClickHandler, @))) - - KEY: - TAB : 9 - ENTER : 13 - ESC : 27 - SPACE : 32 - LEFT : 37 - UP : 38 - RIGHT : 39 - DOWN : 40 - - toggle: (event) -> - event.preventDefault() - $calc = $('.calc') - $calcWrapper = $('#calculator_wrapper') - text = gettext('Open Calculator') - isExpanded = false - icon = 'fa-calculator' - - $('.calc-main').toggleClass 'open' - if $calc.hasClass('closed') - $calcWrapper - .attr('aria-hidden', 'true') - else - text = gettext('Close Calculator') - icon = 'fa-close' - isExpanded = true - - $calcWrapper - .attr('aria-hidden', 'false') - # TODO: Investigate why doing this without the timeout causes it to jump - # down to the bottom of the page. I suspect it's because it's putting the - # focus on the text field before it transitions onto the page. - setTimeout (-> $calcWrapper.find('#calculator_input').focus()), 100 - - $calc - .attr - 'title': text +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ + +/* +Keyboard Support + +If focus is on the hint button: + * Enter: Open or close hint popup. Select last focused hint item if opening + * Space: Open or close hint popup. Select last focused hint item if opening + +If focus is on a hint item: + * Left arrow: Select previous hint item + * Up arrow: Select previous hint item + * Right arrow: Select next hint item + * Down arrow: Select next hint item + */ + +(function() { + this.Calculator = (function() { + function Calculator() { + this.hintButton = $('#calculator_hint'); + this.calcInput = $('#calculator_input'); + this.hintPopup = $('.help'); + this.hintsList = this.hintPopup.find('.hint-item'); + this.selectHint($('#' + this.hintPopup.attr('data-calculator-hint'))); + $('.calc').click(this.toggle); + $('form#calculator').submit(this.calculate).submit(function(e) { + return e.preventDefault(); + }); + this.hintButton.click($.proxy(this.handleClickOnHintButton, this)); + this.hintPopup.click($.proxy(this.handleClickOnHintPopup, this)); + this.hintPopup.keydown($.proxy(this.handleKeyDownOnHint, this)); + $('#calculator_wrapper').keyup($.proxy(this.handleKeyUpOnHint, this)); + this.handleClickOnDocument = $.proxy(this.handleClickOnDocument, this); + this.calcInput.focus($.proxy(this.inputClickHandler, this)); + } + + Calculator.prototype.KEY = { + TAB: 9, + ENTER: 13, + ESC: 27, + SPACE: 32, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40 + }; + + Calculator.prototype.toggle = function(event) { + var $calc, $calcWrapper, icon, isExpanded, text; + event.preventDefault(); + $calc = $('.calc'); + $calcWrapper = $('#calculator_wrapper'); + text = gettext('Open Calculator'); + isExpanded = false; + icon = 'fa-calculator'; + $('.calc-main').toggleClass('open'); + if ($calc.hasClass('closed')) { + $calcWrapper.attr('aria-hidden', 'true'); + } else { + text = gettext('Close Calculator'); + icon = 'fa-close'; + isExpanded = true; + $calcWrapper.attr('aria-hidden', 'false'); + + /* + TODO: Investigate why doing this without the timeout causes it to jump + down to the bottom of the page. I suspect it's because it's putting the + focus on the text field before it transitions onto the page. + */ + setTimeout((function() { + return $calcWrapper.find('#calculator_input').focus(); + }), 100); + } + $calc.attr({ + 'title': text, 'aria-expanded': isExpanded - .find('.utility-control-label').text text - - $calc - .find('.icon') - .removeClass('fa-calculator') - .removeClass('fa-close') - .addClass(icon) - - $calc.toggleClass 'closed' - - inputClickHandler: -> - $('#calculator_output').removeClass('has-result') - - showHint: -> - @hintPopup - .addClass('shown') - .attr('aria-hidden', false) - - $('#calculator_output').removeClass('has-result') - - $(document).on('click', @handleClickOnDocument) - - hideHint: -> - @hintPopup - .removeClass('shown') - .attr('aria-hidden', true) - - $('#calculator_output').removeClass('has-result') - - $(document).off('click', @handleClickOnDocument) - - selectHint: (element) -> - if not element or (element and element.length == 0) - element = @hintsList.first() - - @activeHint = element; - @activeHint.focus(); - @hintPopup.attr('data-calculator-hint', element.attr('id')); - - prevHint: () -> - prev = @activeHint.prev(); # the previous hint - # if this was the first item - # select the last one in the group. - if @activeHint.index() == 0 - prev = @hintsList.last() - # select the previous hint - @selectHint(prev) - - nextHint: () -> - next = @activeHint.next(); # the next hint - # if this was the last item, - # select the first one in the group. - if @activeHint.index() == @hintsList.length - 1 - next = @hintsList.first() - # give the next hint focus - @selectHint(next) - - handleKeyDown: (e) -> - if e.altKey - # do nothing - return true - - if e.keyCode == @KEY.ENTER or e.keyCode == @KEY.SPACE - if @hintPopup.hasClass 'shown' - @hideHint() - else - @showHint() - @activeHint.focus() - - e.preventDefault() - return false - - # allow the event to propagate - return true - - handleKeyDownOnHint: (e) -> - if e.altKey - # do nothing - return true - - switch e.keyCode - - when @KEY.ESC - # hide popup with hints - @hideHint() - @hintButton.focus() - - e.stopPropagation() - return false - - when @KEY.LEFT, @KEY.UP - if e.shiftKey - # do nothing - return true - - @prevHint() - - e.stopPropagation() - return false - - when @KEY.RIGHT, @KEY.DOWN - if e.shiftKey - # do nothing - return true - - @nextHint() - - e.stopPropagation() - return false - - # allow the event to propagate - return true - - handleKeyUpOnHint: (e) -> - switch e.keyCode - when @KEY.TAB - # move focus to hint links and hide hint once focus is out of hint pop up - @active_element = document.activeElement - if not $(@active_element).parents().is(@hintPopup) - @hideHint() - - handleClickOnDocument: (e) -> - @hideHint() - - handleClickOnHintButton: (e) -> - e.preventDefault() - e.stopPropagation() - if @hintPopup.hasClass 'shown' - @hideHint() - @hintButton.attr('aria-expanded', false) - else - @showHint() - @hintButton.attr('aria-expanded', true) - @activeHint.focus() - - handleClickOnHintPopup: (e) -> - e.stopPropagation() - - calculate: -> - $.getWithPrefix '/calculate', { equation: $('#calculator_input').val() }, (data) -> - $('#calculator_output') - .val(data.result) - .addClass('has-result') - .focus() + }).find('.utility-control-label').text(text); + $calc.find('.icon').removeClass('fa-calculator').removeClass('fa-close').addClass(icon); + return $calc.toggleClass('closed'); + }; + + Calculator.prototype.inputClickHandler = function() { + return $('#calculator_output').removeClass('has-result'); + }; + + Calculator.prototype.showHint = function() { + this.hintPopup.addClass('shown').attr('aria-hidden', false); + $('#calculator_output').removeClass('has-result'); + return $(document).on('click', this.handleClickOnDocument); + }; + + Calculator.prototype.hideHint = function() { + this.hintPopup.removeClass('shown').attr('aria-hidden', true); + $('#calculator_output').removeClass('has-result'); + return $(document).off('click', this.handleClickOnDocument); + }; + + Calculator.prototype.selectHint = function(element) { + if (!element || (element && element.length === 0)) { + element = this.hintsList.first(); + } + this.activeHint = element; + this.activeHint.focus(); + return this.hintPopup.attr('data-calculator-hint', element.attr('id')); + }; + + Calculator.prototype.prevHint = function() { + + /* + the previous hint + */ + var prev; + prev = this.activeHint.prev(); + + /* + if this was the first item + select the last one in the group. + */ + if (this.activeHint.index() === 0) { + prev = this.hintsList.last(); + } + + /* + select the previous hint + */ + return this.selectHint(prev); + }; + + Calculator.prototype.nextHint = function() { + + /* + the next hint + */ + var next; + next = this.activeHint.next(); + + /* + if this was the last item, + select the first one in the group. + */ + if (this.activeHint.index() === this.hintsList.length - 1) { + next = this.hintsList.first(); + } + + /* + give the next hint focus + */ + return this.selectHint(next); + }; + + Calculator.prototype.handleKeyDown = function(e) { + if (e.altKey) { + + /* + do nothing + */ + return true; + } + if (e.keyCode === this.KEY.ENTER || e.keyCode === this.KEY.SPACE) { + if (this.hintPopup.hasClass('shown')) { + this.hideHint(); + } else { + this.showHint(); + this.activeHint.focus(); + } + e.preventDefault(); + return false; + } + + /* + allow the event to propagate + */ + return true; + }; + + Calculator.prototype.handleKeyDownOnHint = function(e) { + if (e.altKey) { + + /* + do nothing + */ + return true; + } + switch (e.keyCode) { + case this.KEY.ESC: + + /* + hide popup with hints + */ + this.hideHint(); + this.hintButton.focus(); + e.stopPropagation(); + return false; + case this.KEY.LEFT: + case this.KEY.UP: + if (e.shiftKey) { + + /* + do nothing + */ + } + return true; + this.prevHint(); + e.stopPropagation(); + return false; + case this.KEY.RIGHT: + case this.KEY.DOWN: + if (e.shiftKey) { + + /* + do nothing + */ + return true; + } + this.nextHint(); + e.stopPropagation(); + return false; + } + + /* + allow the event to propagate + */ + return true; + }; + + Calculator.prototype.handleKeyUpOnHint = function(e) { + switch (e.keyCode) { + case this.KEY.TAB: + + /* + move focus to hint links and hide hint once focus is out of hint pop up + */ + this.active_element = document.activeElement; + if (!$(this.active_element).parents().is(this.hintPopup)) { + return this.hideHint(); + } + } + }; + + Calculator.prototype.handleClickOnDocument = function(e) { + return this.hideHint(); + }; + + Calculator.prototype.handleClickOnHintButton = function(e) { + e.preventDefault(); + e.stopPropagation(); + if (this.hintPopup.hasClass('shown')) { + this.hideHint(); + return this.hintButton.attr('aria-expanded', false); + } else { + this.showHint(); + this.hintButton.attr('aria-expanded', true); + return this.activeHint.focus(); + } + }; + + Calculator.prototype.handleClickOnHintPopup = function(e) { + return e.stopPropagation(); + }; + + Calculator.prototype.calculate = function() { + return $.getWithPrefix('/calculate', { + equation: $('#calculator_input').val() + }, function(data) { + return $('#calculator_output').val(data.result).addClass('has-result').focus(); + }); + }; + + return Calculator; + + })(); + +}).call(this); diff --git a/lms/static/js/courseware.js b/lms/static/js/courseware.js index 49e27c484b8c..1a593cf202d7 100644 --- a/lms/static/js/courseware.js +++ b/lms/static/js/courseware.js @@ -1,21 +1,38 @@ -class @Courseware - @prefix: '' +// Once generated by CoffeeScript 1.9.3, but now lives as pure JS +/* eslint-disable */ +(function() { + this.Courseware = (function() { + Courseware.prefix = ''; - constructor: -> - Logger.bind() - @render() + function Courseware() { + Logger.bind(); + this.render(); + } - @start: -> - new Courseware + Courseware.start = function() { + return new Courseware; + }; - render: -> - XBlock.initializeBlocks($('.course-content')) - $('.course-content .histogram').each -> - id = $(this).attr('id').replace(/histogram_/, '') - try - histg = new Histogram id, $(this).data('histogram') - catch error - histg = error - if console? - console.log(error) - return histg + Courseware.prototype.render = function() { + XBlock.initializeBlocks($('.course-content')); + return $('.course-content .histogram').each(function() { + var error, histg, id; + id = $(this).attr('id').replace(/histogram_/, ''); + try { + histg = new Histogram(id, $(this).data('histogram')); + } catch (_error) { + error = _error; + histg = error; + if (typeof console !== "undefined" && console !== null) { + console.log(error); + } + } + return histg; + }); + }; + + return Courseware; + + })(); + +}).call(this); diff --git a/lms/static/js/customwmd.js b/lms/static/js/customwmd.js index f6339eabf477..6a2bb93eccf1 100644 --- a/lms/static/js/customwmd.js +++ b/lms/static/js/customwmd.js @@ -1,181 +1,247 @@ -# Mostly adapted from math.stackexchange.com: http://cdn.sstatic.net/js/mathjax-editing-new.js - -class MathJaxProcessor - - MATHSPLIT = /// ( - \$\$? # normal inline or display delimiter - | \\(?:begin|end)\{[a-z]*\*?\} # \begin{} \end{} style - | \\[\\{}$] - | [{}] - | (?:\n\s*)+ # only treat as math when there's single new line - | @@\d+@@ # delimiter similar to the one used internally - ) ///i - - CODESPAN = /// - (^|[^\\]) # match beginning or any previous character other than escape delimiter ('/') - (`+) # code span starts - ([^\n]*?[^`\n]) # code content - \2 # code span ends - (?!`) - ///gm - - constructor: (inlineMark, displayMark) -> - @inlineMark = inlineMark || "$" - @displayMark = displayMark || "$$" - @math = null - @blocks = null - - processMath: (start, last, preProcess) -> - block = @blocks.slice(start, last + 1).join("").replace(/&/g, "&") - .replace(//g, ">") - if MathJax.Hub.Browser.isMSIE - block = block.replace /(%[^\n]*)\n/g, "$1
\n" - @blocks[i] = "" for i in [start+1..last] - @blocks[start] = "@@#{@math.length}@@" - block = preProcess(block) if preProcess - @math.push block - - removeMath: (text) -> - - text = text || "" - @math = [] - start = end = last = null - braces = 0 - - hasCodeSpans = /`/.test text - if hasCodeSpans - text = text.replace(/~/g, "~T").replace CODESPAN, ($0) -> # replace dollar sign in code span temporarily - $0.replace /\$/g, "~D" - deTilde = (text) -> - text.replace /~([TD])/g, ($0, $1) -> - {T: "~", D: "$"}[$1] - else - deTilde = (text) -> text - - @blocks = _split(text.replace(/\r\n?/g, "\n"), MATHSPLIT) - - for current in [1...@blocks.length] by 2 - block = @blocks[current] - if block.charAt(0) == "@" - @blocks[current] = "@@#{@math.length}@@" - @math.push block - else if start - if block == end - if braces - last = current - else - @processMath(start, current, deTilde) - start = end = last = null - else if block.match /\n.*\n/ - if last - current = last - @processMath(start, current, deTilde) - start = end = last = null - braces = 0 - else if block == "{" - ++braces - else if block == "}" and braces - --braces - else - if block == @inlineMark or block == @displayMark - start = current - end = block - braces = 0 - else if block.substr(1, 5) == "begin" - start = current - end = "\\end" + block.substr(6) - braces = 0 - - if last - @processMath(start, last, deTilde) - start = end = last = null - - deTilde(@blocks.join("")) - - @removeMathWrapper: (_this) -> - (text) -> _this.removeMath(text) - - replaceMath: (text) -> - text = text.replace /@@(\d+)@@/g, ($0, $1) => @math[$1] - @math = null - text - - @replaceMathWrapper: (_this) -> - (text) -> _this.replaceMath(text) - -if Markdown? - - Markdown.getMathCompatibleConverter = (postProcessor) -> - postProcessor ||= ((text) -> text) - converter = Markdown.getSanitizingConverter() - if MathJax? - processor = new MathJaxProcessor() - converter.hooks.chain "preConversion", MathJaxProcessor.removeMathWrapper(processor) - converter.hooks.chain "postConversion", (text) -> - postProcessor(MathJaxProcessor.replaceMathWrapper(processor)(text)) - converter - - Markdown.makeWmdEditor = (elem, appended_id, imageUploadUrl, postProcessor) -> - $elem = $(elem) - if not $elem.length - console.log "warning: elem for makeWmdEditor doesn't exist" - return - if not $elem.find(".wmd-panel").length - initialText = $elem.html() - $elem.empty() - _append = appended_id || "" - wmdInputId = "wmd-input#{_append}" - $wmdPreviewContainer = $("
").addClass("wmd-preview-container") - .attr("role", "region") - .attr("aria-label", gettext("HTML preview of post")) - .append($("
").addClass("wmd-preview-label").text(gettext("Preview"))) - .append($("
").attr("id", "wmd-preview#{_append}").addClass("wmd-panel wmd-preview")) - $wmdPanel = $("
").addClass("wmd-panel") - .append($("
").attr("id", "wmd-button-bar#{_append}")) - .append($("