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.
This commit is contained in:
Michael Terry
2018-03-23 15:30:20 -04:00
committed by Michael Terry
parent 2abbd1eb83
commit a34c8c8233
107 changed files with 3346 additions and 2502 deletions

View File

@@ -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

View File

@@ -810,10 +810,7 @@ PIPELINE_JS = {
},
}
PIPELINE_COMPILERS = (
'pipeline.compilers.coffee.CoffeeScriptCompiler',
)
PIPELINE_COMPILERS = ()
PIPELINE_CSS_COMPRESSOR = None
PIPELINE_JS_COMPRESSOR = None
@@ -829,10 +826,6 @@ STATICFILES_IGNORE_PATTERNS = (
"sass/*/*.scss",
"sass/*/*/*.scss",
"sass/*/*/*/*.scss",
"coffee/*.coffee",
"coffee/*/*.coffee",
"coffee/*/*/*.coffee",
"coffee/*/*/*/*.coffee",
# Ignore tests
"spec",

View File

@@ -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

View File

@@ -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',

View File

@@ -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'

View File

@@ -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: {

View File

@@ -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'}
],

View File

@@ -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/**/*.*'}
],

View File

@@ -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();

View File

@@ -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'),
]

View File

@@ -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'),
]

View File

@@ -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"

View File

@@ -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')]}

View File

@@ -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'),
]

View File

@@ -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},

View File

@@ -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.

View File

@@ -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 Ø<<

View File

@@ -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

View File

@@ -1,261 +1,443 @@
class @Annotatable
_debug: false
// 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); }; };
# 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'
this.Annotatable = (function() {
Annotatable.prototype._debug = false;
# 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()
/*
selectors for the annotatable xmodule
*/
$: (selector) ->
$(selector, @el)
Annotatable.prototype.wrapperSelector = '.annotatable-wrapper';
init: () ->
@initEvents()
@initTips()
Annotatable.prototype.toggleAnnotationsSelector = '.annotatable-toggle-annotations';
initEvents: () ->
# Initialize toggle handlers for the instructions and annotations sections
[@annotationsHidden, @instructionsHidden] = [false, false]
@$(@toggleAnnotationsSelector).bind 'click', @onClickToggleAnnotations
@$(@toggleInstructionsSelector).bind 'click', @onClickToggleInstructions
Annotatable.prototype.toggleInstructionsSelector = '.annotatable-toggle-instructions';
# 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
Annotatable.prototype.instructionsSelector = '.annotatable-instructions';
# 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
Annotatable.prototype.sectionSelector = '.annotatable-section';
initTips: () ->
# tooltips are used to display annotations for highlighted text spans
@$(@spanSelector).each (index, el) =>
$(el).qtip(@getSpanTipOptions el)
Annotatable.prototype.spanSelector = '.annotatable-span';
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
Annotatable.prototype.replySelector = '.annotatable-reply';
onClickToggleAnnotations: (e) => @toggleAnnotations()
onClickToggleInstructions: (e) => @toggleInstructions()
/*
these selectors are for responding to events from the annotation capa problem type
*/
onClickReply: (e) => @replyTo(e.currentTarget)
Annotatable.prototype.problemXModuleSelector = '.xmodule_CapaModule';
onClickReturn: (e) => @returnFrom(e.currentTarget)
Annotatable.prototype.problemSelector = 'div.problem';
onShowTip: (event, api) =>
event.preventDefault() if @annotationsHidden
Annotatable.prototype.problemInputSelector = 'div.problem .annotation-input';
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:
Annotatable.prototype.problemReturnSelector = 'div.problem .annotation-return';
(( TOOLTIP ))
\/
text text text ... text text text ...... <span span span>
<span span span>
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();
}
The problem is that the tooltip looks disconnected from both spans, so
we should re-position the tooltip to appear above the span.
###
Annotatable.prototype.$ = function(selector) {
return $(selector, this.el);
};
tip = api.elements.tooltip
adjust_y = api.options.position?.adjust?.y || 0
container = api.options.position?.container || $('body')
target = api.elements.target
Annotatable.prototype.init = function() {
this.initEvents();
return this.initTips();
};
rects = $(target).get(0).getClientRects()
is_non_overlapping = (rects?.length == 2 and rects[0].left > rects[1].right)
Annotatable.prototype.initEvents = function() {
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]
/*
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);
rect_center = focus_rect.left + (focus_rect.width / 2)
rect_top = focus_rect.top
tip_width = $(tip).width()
tip_height = $(tip).height()
/*
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);
# 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
/*
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);
};
tip_left = offset_left + rect_center - (tip_width / 2)
tip_top = offset_top + rect_top - tip_height + adjust_y
Annotatable.prototype.initTips = function() {
# 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
/*
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));
};
# 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
Annotatable.prototype.getSpanTipOptions = function(el) {
return {
content: {
title: {
text: this.makeTipTitle(el)
},
text: this.makeTipContent(el)
},
position: {
getSpanForProblemReturn: (el) ->
problem_id = $(@problemReturnSelector).index(el)
@$(@spanSelector).filter("[data-problem-id='#{problem_id}']")
/*
of tooltip
*/
my: 'bottom center',
getProblem: (el) ->
problem_id = @getProblemId(el)
$(@problemInputSelector).eq(problem_id)
/*
of target
*/
at: 'top center',
getProblemId: (el) ->
$(el).data('problem-id')
/*
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,
toggleAnnotations: () ->
hide = (@annotationsHidden = not @annotationsHidden)
@toggleAnnotationButtonText hide
@toggleSpans hide
@toggleTips hide
/*
don't hide the tooltip if it is moused over
*/
fixed: true
},
style: {
classes: 'ui-tooltip-annotatable'
},
events: {
show: this.onShowTip,
move: this.onMoveTip
}
};
};
toggleTips: (hide) ->
visible = @findVisibleTips()
@hideTips visible
Annotatable.prototype.onClickToggleAnnotations = function(e) {
return this.toggleAnnotations();
};
toggleAnnotationButtonText: (hide) ->
if hide
buttonText = gettext('Show Annotations')
else
buttonText = gettext('Hide Annotations')
@$(@toggleAnnotationsSelector).text(buttonText)
Annotatable.prototype.onClickToggleInstructions = function(e) {
return this.toggleInstructions();
};
toggleInstructions: () ->
hide = (@instructionsHidden = not @instructionsHidden)
@toggleInstructionsButton hide
@toggleInstructionsText hide
Annotatable.prototype.onClickReply = function(e) {
return this.replyTo(e.currentTarget);
};
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])
Annotatable.prototype.onClickReturn = function(e) {
return this.returnFrom(e.currentTarget);
};
toggleInstructionsText: (hide) ->
slideMethod = (if hide then 'slideUp' else 'slideDown')
@$(@instructionsSelector)[slideMethod]()
Annotatable.prototype.onShowTip = function(event, api) {
if (this.annotationsHidden) {
return event.preventDefault();
}
};
toggleSpans: (hide) ->
@$(@spanSelector).toggleClass 'hide', hide, 250
Annotatable.prototype.onMoveTip = function(event, api, position) {
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
/*
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 ...... <span span span>
<span span span>
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) {
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
/*
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 {
scrollTo: (el, after, offset = -20) ->
$('html,body').scrollTo(el, {
duration: 500
onAfter: @_once => after?.call this, el
offset: offset
}) if $(el).length > 0
/*
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();
afterScrollToProblem: (problem_el) ->
problem_el.effect 'highlight', {}, 500
/*
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;
afterScrollToSpan: (span_el) ->
span_el.addClass 'selected', 400, 'swing', ->
span_el.removeClass 'selected', 400, 'swing'
/*
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;
}
makeTipContent: (el) ->
(api) =>
text = $(el).data('comment-body')
comment = @createComment(text)
problem_id = @getProblemId(el)
reply = @createReplyLink(problem_id)
$(comment).add(reply)
/*
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
});
};
makeTipTitle: (el) ->
(api) =>
title = $(el).data('comment-title')
(if title then title else gettext('Commentary'))
Annotatable.prototype.getSpanForProblemReturn = function(el) {
var problem_id;
problem_id = $(this.problemReturnSelector).index(el);
return this.$(this.spanSelector).filter("[data-problem-id='" + problem_id + "']");
};
createComment: (text) ->
$("<div class=\"annotatable-comment\">#{text}</div>")
Annotatable.prototype.getProblem = function(el) {
var problem_id;
problem_id = this.getProblemId(el);
return $(this.problemInputSelector).eq(problem_id);
};
createReplyLink: (problem_id) ->
linktxt = gettext('Reply to Annotation')
$("<a class=\"annotatable-reply\" href=\"javascript:void(0);\" data-problem-id=\"#{problem_id}\">#{linktxt}</a>")
Annotatable.prototype.getProblemId = function(el) {
return $(el).data('problem-id');
};
findVisibleTips: () ->
visible = []
@$(@spanSelector).each (index, el) ->
api = $(el).qtip('api')
tip = $(api?.elements.tooltip)
if tip.is(':visible')
visible.push el
visible
Annotatable.prototype.toggleAnnotations = function() {
var hide;
hide = (this.annotationsHidden = !this.annotationsHidden);
this.toggleAnnotationButtonText(hide);
this.toggleSpans(hide);
return this.toggleTips(hide);
};
hideTips: (elements) ->
$(elements).qtip('hide')
Annotatable.prototype.toggleTips = function(hide) {
var visible;
visible = this.findVisibleTips();
return this.hideTips(visible);
};
_once: (fn) ->
done = false
return =>
fn.call this unless done
done = true
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 $("<div class=\"annotatable-comment\">" + text + "</div>"); // xss-lint: disable=javascript-concat-html
};
Annotatable.prototype.createReplyLink = function(problem_id) {
var linktxt;
linktxt = gettext('Reply to Annotation');
return $("<a class=\"annotatable-reply\" href=\"javascript:void(0);\" data-problem-id=\"" + problem_id + "\">" + linktxt + "</a>"); // 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);

View File

@@ -1,3 +1,5 @@
/* eslint-disable */
//////////////////////////////////////////////////////////////////////////////
//
// Circuit simulator

View File

@@ -1,38 +1,60 @@
class @Conditional
// 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);
}
}
constructor: (element, callerElId) ->
@el = $(element).find('.conditional-wrapper')
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();
}
}
@callerElId = callerElId
/*
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));
};
if callerElId isnt undefined
dependencies = @el.data('depends')
if (typeof dependencies is 'string') and (dependencies.length > 0) and (dependencies.indexOf(callerElId) is -1)
return
return Conditional;
@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)
}).call(this);

View File

@@ -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);

View File

@@ -1,13 +1,26 @@
class @HTMLModule
// 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();
}
}
constructor: (@element) ->
@el = $(@element)
JavascriptLoader.executeModuleScripts(@el)
Collapsible.setCollapsibles(@el)
if MathJax?
MathJax.Hub.Queue ["Typeset", MathJax.Hub, @el[0]]
if setupFullScreenModal?
setupFullScreenModal()
HTMLModule.prototype.$ = function(selector) {
return $(selector, this.el);
};
$: (selector) ->
$(selector, @el)
return HTMLModule;
})();
}).call(this);

View File

@@ -1,92 +1,141 @@
class @HTMLEditingDescriptor
// 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); }; };
# custom fonts are prepended to font selection dropdown
CUSTOM_FONTS = "Default='Open Sans', Verdana, Arial, Helvetica, sans-serif;"
this.HTMLEditingDescriptor = (function() {
# 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"
/*
custom fonts are prepended to font selection dropdown
*/
var CUSTOM_FONTS, STANDARD_FONTS, _getFonts;
_getFonts = () ->
CUSTOM_FONTS + STANDARD_FONTS
CUSTOM_FONTS = "Default='Open Sans', Verdana, Arial, Helvetica, sans-serif;";
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
/*
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";
# 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
_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 (this.editor_choice === 'visual') {
this.$advancedEditorWrapper = $(this.advanced_editor.getWrapperElement());
this.$advancedEditorWrapper.addClass('is-inactive');
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
/*
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"
@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", {
/*
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,
width: '100%',
height: '400px',
menubar: false,
statusbar: false,
# Necessary to avoid stripping of style tags.
valid_children : "+body[style]",
/*
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: "",
/*
Allow any elements to be used, e.g. link, script, math
*/
valid_elements: "*[*]",
extended_valid_elements: "*[*]",
invalid_elements: "",
setup: this.setupTinyMCE,
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,
/*
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', {
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."),
})
/*
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"),
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')
})
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Advanced": gettext("Advanced"),
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
})
/*
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"),
@visualEditor = ed
@imageModal = $('#edit-image-modal .modal')
/*
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"),
# 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)
/*
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"),
@imageModal.on('submitForm', @editImageSubmit)
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Alignment": gettext("Alignment"),
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/')
/*
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"),
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)
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Anchor": gettext("Anchor"),
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}))
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Anchors": gettext("Anchors"),
closeImageModal: () =>
@imageModal[0].dispatchEvent(new CustomEvent('closeModal', {bubbles: true}))
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Author": gettext("Author"),
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)
/*
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"),
@visualEditor.insertContent(@visualEditor.dom.createHTML('img', data))
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Blockquote": gettext("Blockquote"),
editImageSubmit: (event) =>
if event.detail
@saveImageFromModal(event.detail)
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Blocks": gettext("Blocks"),
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/')
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Body": gettext("Body"),
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)
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Bold": gettext("Bold"),
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
/*
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"),
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
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Border": gettext("Border"),
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()
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Bottom": gettext("Bottom"),
getVisualEditor: () ->
###
Returns the instance of TinyMCE.
/*
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"),
Pulled out as a helper method for unit test.
###
return @visualEditor
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Cancel": gettext("Cancel"),
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/')
/*
Translators: this is a message from the raw HTML editor displayed in the browser when a user needs to edit HTML
*/
"Caption": gettext("Caption"),
if text == undefined
text = @advanced_editor.getValue()
/*
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"),
data: text
/*
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);

View File

@@ -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
})
// 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: JSON.parse @edit_box.getValue()
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);

View File

@@ -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);

View File

@@ -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
})
// 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: @edit_box.getValue()
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);

View File

@@ -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);

View File

@@ -1,142 +1,190 @@
class @TabsEditingDescriptor
@isInactiveClass : "is-inactive"
// 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); }; };
constructor: (element) ->
@element = element;
###
Not tested on syncing of multiple editors of same type in tabs
(Like many CodeMirrors).
###
this.TabsEditingDescriptor = (function() {
TabsEditingDescriptor.isInactiveClass = "is-inactive";
@$tabs = $(".tab", @element)
@$content = $(".component-tab", @element)
function TabsEditingDescriptor(element) {
this.onSwitchEditor = bind(this.onSwitchEditor, this);
var currentTab;
this.element = element;
@element.find('.editor-tabs .tab').each (index, value) =>
$(value).on('click', @onSwitchEditor)
/*
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 = @$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])
/*
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]);
}
onSwitchEditor: (e, firstTime, html_id) =>
e.preventDefault()
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');
}
});
isInactiveClass = TabsEditingDescriptor.isInactiveClass
$currentTarget = $(e.currentTarget)
/*
init and save data from previous tab
*/
TabsEditingDescriptor.Model.updateValue(this.html_id, previousTab);
if not $currentTarget.hasClass('current') or firstTime is true
previousTab = null
/*
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)
*/
@$tabs.each( (index, value) ->
if $(value).hasClass('current')
previousTab = $(value).data('tab_name')
)
// 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');
# init and save data from previous tab
TabsEditingDescriptor.Model.updateValue(@html_id, previousTab)
/*
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);
}
};
# 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)
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)
};
};
# call onswitch
onSwitchFunction = TabsEditingDescriptor.Model.modules[@html_id].tabSwitch[$currentTarget.data('tab_name')]
onSwitchFunction() if $.isFunction(onSwitchFunction)
TabsEditingDescriptor.prototype.setMetadataEditor = function(metadataEditor) {
return TabsEditingDescriptor.setMetadataEditor.apply(TabsEditingDescriptor, arguments);
};
@$tabs.removeClass('current')
$currentTarget.addClass('current')
TabsEditingDescriptor.prototype.getStorage = function() {
return TabsEditingDescriptor.getStorage();
};
# Tabs are implemeted like anchors. Therefore we can use hash to find
# corresponding content
content_id = $currentTarget.attr('href')
TabsEditingDescriptor.prototype.addToStorage = function(id, data) {
return TabsEditingDescriptor.addToStorage.apply(TabsEditingDescriptor, arguments);
};
@$content
.addClass(isInactiveClass)
.filter(content_id)
.removeClass(isInactiveClass)
TabsEditingDescriptor.Model = {
addModelUpdate: function(id, tabName, modelUpdateFunction) {
save: ->
@element.off('click', '.editor-tabs .tab', @onSwitchEditor)
current_tab = @$tabs.filter('.current').data('tab_name')
data: TabsEditingDescriptor.Model.getValue(@html_id, current_tab)
/*
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) {
setMetadataEditor : (metadataEditor) ->
TabsEditingDescriptor.setMetadataEditor.apply(TabsEditingDescriptor, arguments)
/*
Function that registers functions invoked when switching
to particular tab.
*/
this.initialize(id);
return this.modules[id].tabSwitch[tabName] = onSwitchFunction;
},
updateValue: function(id, tabName) {
getStorage : () ->
TabsEditingDescriptor.getStorage()
/*
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) {
addToStorage : (id, data) ->
TabsEditingDescriptor.addToStorage.apply(TabsEditingDescriptor, arguments)
/*
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'];
}
}
},
@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
/*
html_id's of descriptors will be stored in modules variable as
containers for callbacks.
*/
modules: {},
Storage: {},
initialize: function(id) {
addOnSwitch : (id, tabName, onSwitchFunction) ->
###
Function that registers functions invoked when switching
to particular tab.
###
@initialize(id)
@modules[id].tabSwitch[tabName] = onSwitchFunction
/*
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'] || {};
}
};
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)
TabsEditingDescriptor.setMetadataEditor = function(metadataEditor) {
return TabsEditingDescriptor.Model.Storage['MetadataEditor'] = metadataEditor;
};
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']
TabsEditingDescriptor.addToStorage = function(id, data) {
return TabsEditingDescriptor.Model.Storage[id] = data;
};
# html_id's of descriptors will be stored in modules variable as
# containers for callbacks.
modules: {}
Storage: {}
TabsEditingDescriptor.getStorage = function() {
return TabsEditingDescriptor.Model.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 {}
return TabsEditingDescriptor;
@setMetadataEditor : (metadataEditor) ->
TabsEditingDescriptor.Model.Storage['MetadataEditor'] = metadataEditor
@addToStorage : (id, data) ->
TabsEditingDescriptor.Model.Storage[id] = data
@getStorage : () ->
TabsEditingDescriptor.Model.Storage
})();
}).call(this);

View File

@@ -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);

View File

@@ -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

View File

@@ -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"

View File

@@ -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'

View File

@@ -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'),
]

View File

@@ -1 +0,0 @@
*.js

View File

@@ -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'}

View File

@@ -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',

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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}

View File

@@ -16,7 +16,6 @@ var options = {
},
libraryFiles: [
{pattern: 'coffee/src/**/*.js'},
{pattern: 'js/libs/**/*.js'},
{pattern: 'js/test/**/*.js'},
{pattern: 'js/vendor/**/*.js'}

View File

@@ -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.

View File

@@ -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

View File

@@ -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'),

View File

@@ -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:

View File

@@ -448,7 +448,6 @@ system_node_path = os.environ.get("NODE_PATH", NODE_MODULES_ROOT)
node_paths = [
COMMON_ROOT / "static/js/vendor",
COMMON_ROOT / "static/coffee/src",
system_node_path,
]
NODE_PATH = ':'.join(node_paths)
@@ -1163,10 +1162,6 @@ EDXNOTES_READ_TIMEOUT = 1.5 # time in seconds
# 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 @@ PIPELINE_UGLIFYJS_BINARY = 'node_modules/.bin/uglifyjs'
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 @@ dashboard_js = (
)
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 @@ discussion_vendor_js = [
'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 @@ PIPELINE_CSS = {
},
}
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 @@ STATICFILES_IGNORE_PATTERNS = (
"sass/*/*.scss",
"sass/*/*/*.scss",
"sass/*/*/*/*.scss",
"coffee/*.coffee",
"coffee/*/*.coffee",
"coffee/*/*/*.coffee",
"coffee/*/*/*/*.coffee",
# Ignore tests
"spec",

View File

@@ -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.

View File

@@ -1 +0,0 @@
*.js

View File

@@ -1,224 +1,274 @@
# Keyboard Support
// Once generated by CoffeeScript 1.9.3, but now lives as pure JS
/* eslint-disable */
# 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
/*
Keyboard Support
# 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
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')));
(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));
}
$('.calc').click @toggle
$('form#calculator').submit(@calculate).submit (e) ->
e.preventDefault()
Calculator.prototype.KEY = {
TAB: 9,
ENTER: 13,
ESC: 27,
SPACE: 32,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
};
@hintButton
.click(($.proxy(@handleClickOnHintButton, @)))
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');
@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
/*
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)
}).find('.utility-control-label').text(text);
$calc.find('.icon').removeClass('fa-calculator').removeClass('fa-close').addClass(icon);
return $calc.toggleClass('closed');
};
$calc.toggleClass 'closed'
inputClickHandler: ->
$('#calculator_output').removeClass('has-result')
Calculator.prototype.inputClickHandler = function() {
return $('#calculator_output').removeClass('has-result');
};
showHint: ->
@hintPopup
.addClass('shown')
.attr('aria-hidden', false)
Calculator.prototype.showHint = function() {
this.hintPopup.addClass('shown').attr('aria-hidden', false);
$('#calculator_output').removeClass('has-result');
return $(document).on('click', this.handleClickOnDocument);
};
$('#calculator_output').removeClass('has-result')
Calculator.prototype.hideHint = function() {
this.hintPopup.removeClass('shown').attr('aria-hidden', true);
$('#calculator_output').removeClass('has-result');
return $(document).off('click', this.handleClickOnDocument);
};
$(document).on('click', @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'));
};
hideHint: ->
@hintPopup
.removeClass('shown')
.attr('aria-hidden', true)
$('#calculator_output').removeClass('has-result')
Calculator.prototype.prevHint = function() {
$(document).off('click', @handleClickOnDocument)
/*
the previous hint
*/
var prev;
prev = this.activeHint.prev();
selectHint: (element) ->
if not element or (element and element.length == 0)
element = @hintsList.first()
/*
if this was the first item
select the last one in the group.
*/
if (this.activeHint.index() === 0) {
prev = this.hintsList.last();
}
@activeHint = element;
@activeHint.focus();
@hintPopup.attr('data-calculator-hint', element.attr('id'));
/*
select the previous hint
*/
return this.selectHint(prev);
};
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)
Calculator.prototype.nextHint = function() {
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)
/*
the next hint
*/
var next;
next = this.activeHint.next();
handleKeyDown: (e) ->
if e.altKey
# do nothing
return true
/*
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();
}
if e.keyCode == @KEY.ENTER or e.keyCode == @KEY.SPACE
if @hintPopup.hasClass 'shown'
@hideHint()
else
@showHint()
@activeHint.focus()
/*
give the next hint focus
*/
return this.selectHint(next);
};
e.preventDefault()
return false
Calculator.prototype.handleKeyDown = function(e) {
if (e.altKey) {
# allow the event to propagate
return true
/*
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;
}
handleKeyDownOnHint: (e) ->
if e.altKey
# do nothing
return true
/*
allow the event to propagate
*/
return true;
};
switch e.keyCode
Calculator.prototype.handleKeyDownOnHint = function(e) {
if (e.altKey) {
when @KEY.ESC
# hide popup with hints
@hideHint()
@hintButton.focus()
/*
do nothing
*/
return true;
}
switch (e.keyCode) {
case this.KEY.ESC:
e.stopPropagation()
return false
/*
hide popup with hints
*/
this.hideHint();
this.hintButton.focus();
e.stopPropagation();
return false;
case this.KEY.LEFT:
case this.KEY.UP:
if (e.shiftKey) {
when @KEY.LEFT, @KEY.UP
if e.shiftKey
# do nothing
return true
/*
do nothing
*/
}
return true;
this.prevHint();
e.stopPropagation();
return false;
case this.KEY.RIGHT:
case this.KEY.DOWN:
if (e.shiftKey) {
@prevHint()
/*
do nothing
*/
return true;
}
this.nextHint();
e.stopPropagation();
return false;
}
e.stopPropagation()
return false
/*
allow the event to propagate
*/
return true;
};
when @KEY.RIGHT, @KEY.DOWN
if e.shiftKey
# do nothing
return true
Calculator.prototype.handleKeyUpOnHint = function(e) {
switch (e.keyCode) {
case this.KEY.TAB:
@nextHint()
/*
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();
}
}
};
e.stopPropagation()
return false
Calculator.prototype.handleClickOnDocument = function(e) {
return this.hideHint();
};
# allow the event to propagate
return true
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();
}
};
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()
Calculator.prototype.handleClickOnHintPopup = function(e) {
return e.stopPropagation();
};
handleClickOnDocument: (e) ->
@hideHint()
Calculator.prototype.calculate = function() {
return $.getWithPrefix('/calculate', {
equation: $('#calculator_input').val()
}, function(data) {
return $('#calculator_output').val(data.result).addClass('has-result').focus();
});
};
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()
return Calculator;
handleClickOnHintPopup: (e) ->
e.stopPropagation()
})();
calculate: ->
$.getWithPrefix '/calculate', { equation: $('#calculator_input').val() }, (data) ->
$('#calculator_output')
.val(data.result)
.addClass('has-result')
.focus()
}).call(this);

View File

@@ -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);

View File

@@ -1,181 +1,247 @@
# Mostly adapted from math.stackexchange.com: http://cdn.sstatic.net/js/mathjax-editing-new.js
// 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)
class MathJaxProcessor
/*
Mostly adapted from math.stackexchange.com: http://cdn.sstatic.net/js/mathjax-editing-new.js
*/
(function() {
var 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
MathJaxProcessor = (function() {
CODESPAN = ///
(^|[^\\]) # match beginning or any previous character other than escape delimiter ('/')
(`+) # code span starts
([^\n]*?[^`\n]) # code content
\2 # code span ends
(?!`)
///gm
var CODESPAN, MATHSPLIT;
constructor: (inlineMark, displayMark) ->
@inlineMark = inlineMark || "$"
@displayMark = displayMark || "$$"
@math = null
@blocks = null
/*
\$\$? # 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
*/
MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i;
processMath: (start, last, preProcess) ->
block = @blocks.slice(start, last + 1).join("").replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
if MathJax.Hub.Browser.isMSIE
block = block.replace /(%[^\n]*)\n/g, "$1<br/>\n"
@blocks[i] = "" for i in [start+1..last]
@blocks[start] = "@@#{@math.length}@@"
block = preProcess(block) if preProcess
@math.push block
removeMath: (text) ->
/*
(^|[^\\]) # match beginning or any previous character other than escape delimiter ('/')
(`+) # code span starts
([^\n]*?[^`\n]) # code content
\2 # code span ends
(?!`)
*/
CODESPAN = /(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm;
text = text || ""
@math = []
start = end = last = null
braces = 0
function MathJaxProcessor(inlineMark, displayMark) {
this.inlineMark = inlineMark || "$";
this.displayMark = displayMark || "$$";
this.math = null;
this.blocks = null;
}
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
MathJaxProcessor.prototype.processMath = function(start, last, preProcess) {
var block, i, j, ref, ref1;
block = this.blocks.slice(start, last + 1).join("").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
if (MathJax.Hub.Browser.isMSIE) {
block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n");
}
for (i = j = ref = start + 1, ref1 = last; ref <= ref1 ? j <= ref1 : j >= ref1; i = ref <= ref1 ? ++j : --j) {
this.blocks[i] = "";
}
this.blocks[start] = "@@" + this.math.length + "@@";
if (preProcess) {
block = preProcess(block);
}
return this.math.push(block);
};
@blocks = _split(text.replace(/\r\n?/g, "\n"), MATHSPLIT)
MathJaxProcessor.prototype.removeMath = function(text) {
var block, braces, current, deTilde, end, hasCodeSpans, j, last, ref, start;
text = text || "";
this.math = [];
start = end = last = null;
braces = 0;
hasCodeSpans = /`/.test(text);
if (hasCodeSpans) {
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
/*
replace dollar sign in code span temporarily
*/
text = text.replace(/~/g, "~T").replace(CODESPAN, function($0) {
return $0.replace(/\$/g, "~D");
});
deTilde = function(text) {
return text.replace(/~([TD])/g, function($0, $1) {
return {
T: "~",
D: "$"
}[$1];
});
};
} else {
deTilde = function(text) {
return text;
};
}
this.blocks = _split(text.replace(/\r\n?/g, "\n"), MATHSPLIT);
for (current = j = 1, ref = this.blocks.length; j < ref; current = j += 2) {
block = this.blocks[current];
if (block.charAt(0) === "@") {
this.blocks[current] = "@@" + this.math.length + "@@";
this.math.push(block);
} else if (start) {
if (block === end) {
if (braces) {
last = current;
} else {
this.processMath(start, current, deTilde);
start = end = last = null;
}
} else if (block.match(/\n.*\n/)) {
if (last) {
current = last;
this.processMath(start, current, deTilde);
}
start = end = last = null;
braces = 0;
} else if (block === "{") {
++braces;
} else if (block === "}" && braces) {
--braces;
}
} else {
if (block === this.inlineMark || block === this.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) {
this.processMath(start, last, deTilde);
start = end = last = null;
}
return deTilde(this.blocks.join(""));
};
if last
@processMath(start, last, deTilde)
start = end = last = null
MathJaxProcessor.removeMathWrapper = function(_this) {
return function(text) {
return _this.removeMath(text);
};
};
deTilde(@blocks.join(""))
MathJaxProcessor.prototype.replaceMath = function(text) {
text = text.replace(/@@(\d+)@@/g, (function(_this) {
return function($0, $1) {
return _this.math[$1];
};
})(this));
this.math = null;
return text;
};
@removeMathWrapper: (_this) ->
(text) -> _this.removeMath(text)
MathJaxProcessor.replaceMathWrapper = function(_this) {
return function(text) {
return _this.replaceMath(text);
};
};
replaceMath: (text) ->
text = text.replace /@@(\d+)@@/g, ($0, $1) => @math[$1]
@math = null
text
return MathJaxProcessor;
@replaceMathWrapper: (_this) ->
(text) -> _this.replaceMath(text)
})();
if Markdown?
if (typeof Markdown !== "undefined" && Markdown !== null) {
Markdown.getMathCompatibleConverter = function(postProcessor) {
var converter, processor;
postProcessor || (postProcessor = (function(text) {
return text;
}));
converter = Markdown.getSanitizingConverter();
if (typeof MathJax !== "undefined" && MathJax !== null) {
processor = new MathJaxProcessor();
converter.hooks.chain("preConversion", MathJaxProcessor.removeMathWrapper(processor));
converter.hooks.chain("postConversion", function(text) {
return postProcessor(MathJaxProcessor.replaceMathWrapper(processor)(text));
});
}
return converter;
};
Markdown.makeWmdEditor = function(elem, appended_id, imageUploadUrl, postProcessor) {
var $elem, $wmdPanel, $wmdPreviewContainer, _append, ajaxFileUpload, converter, delayRenderer, editor, imageUploadHandler, initialText, wmdInputId;
$elem = $(elem);
if (!$elem.length) {
console.log("warning: elem for makeWmdEditor doesn't exist");
return;
}
if (!$elem.find(".wmd-panel").length) {
initialText = $elem.html();
$elem.empty();
_append = appended_id || "";
wmdInputId = "wmd-input" + _append;
$wmdPreviewContainer = $("<div>").addClass("wmd-preview-container").attr("role", "region").attr("aria-label", gettext("HTML preview of post")).append($("<div>").addClass("wmd-preview-label").text(gettext("Preview"))).append($("<div>").attr("id", "wmd-preview" + _append).addClass("wmd-panel wmd-preview"));
$wmdPanel = $("<div>").addClass("wmd-panel").append($("<div>").attr("id", "wmd-button-bar" + _append)).append($("<label>").addClass("sr").attr("for", wmdInputId).text(gettext("Your question or idea (required)"))).append($("<textarea>").addClass("wmd-input").attr("id", wmdInputId).html(initialText)).append($wmdPreviewContainer); // xss-lint: disable=javascript-jquery-html
$elem.append($wmdPanel);
}
converter = Markdown.getMathCompatibleConverter(postProcessor);
ajaxFileUpload = function(imageUploadUrl, input, startUploadHandler) {
$("#loading").ajaxStart(function() {
return $(this).show();
}).ajaxComplete(function() {
return $(this).hide();
});
$("#upload").ajaxStart(function() {
return $(this).hide();
}).ajaxComplete(function() {
return $(this).show();
});
return $.ajaxFileUpload({
url: imageUploadUrl,
secureuri: false,
fileElementId: 'file-upload',
dataType: 'json',
success: function(data, status) {
var error, fileURL;
fileURL = data['result']['file_url'];
error = data['result']['error'];
if (error !== '') {
alert(error);
if (startUploadHandler) {
$('#file-upload').unbind('change').change(startUploadHandler);
}
return console.log(error);
} else {
return $(input).attr('value', fileURL);
}
},
error: function(data, status, e) {
alert(e);
if (startUploadHandler) {
return $('#file-upload').unbind('change').change(startUploadHandler);
}
}
});
};
imageUploadHandler = function(elem, input) {
return ajaxFileUpload(imageUploadUrl, input, imageUploadHandler);
};
editor = new Markdown.Editor(converter,
appended_id, // idPostfix
null, // help handler
imageUploadHandler);
delayRenderer = new MathJaxDelayRenderer();
editor.hooks.chain("onPreviewPush", function(text, previewSet) {
return delayRenderer.render({
text: text,
previewSetter: previewSet
});
});
editor.run();
return editor;
};
}
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 = $("<div>").addClass("wmd-preview-container")
.attr("role", "region")
.attr("aria-label", gettext("HTML preview of post"))
.append($("<div>").addClass("wmd-preview-label").text(gettext("Preview")))
.append($("<div>").attr("id", "wmd-preview#{_append}").addClass("wmd-panel wmd-preview"))
$wmdPanel = $("<div>").addClass("wmd-panel")
.append($("<div>").attr("id", "wmd-button-bar#{_append}"))
.append($("<label>").addClass("sr").attr("for", wmdInputId).text(gettext("Your question or idea (required)")))
.append($("<textarea>").addClass("wmd-input").attr("id", wmdInputId).html(initialText))
.append($wmdPreviewContainer)
$elem.append($wmdPanel)
converter = Markdown.getMathCompatibleConverter(postProcessor)
ajaxFileUpload = (imageUploadUrl, input, startUploadHandler) ->
$("#loading").ajaxStart(-> $(this).show()).ajaxComplete(-> $(this).hide())
$("#upload").ajaxStart(-> $(this).hide()).ajaxComplete(-> $(this).show())
$.ajaxFileUpload
url: imageUploadUrl
secureuri: false
fileElementId: 'file-upload'
dataType: 'json'
success: (data, status) ->
fileURL = data['result']['file_url']
error = data['result']['error']
if error != ''
alert error
if startUploadHandler
$('#file-upload').unbind('change').change(startUploadHandler)
console.log error
else
$(input).attr('value', fileURL)
error: (data, status, e) ->
alert(e)
if startUploadHandler
$('#file-upload').unbind('change').change(startUploadHandler)
imageUploadHandler = (elem, input) ->
ajaxFileUpload(imageUploadUrl, input, imageUploadHandler)
editor = new Markdown.Editor(
converter,
appended_id, # idPostfix
null, # help handler
imageUploadHandler
)
delayRenderer = new MathJaxDelayRenderer()
editor.hooks.chain "onPreviewPush", (text, previewSet) ->
delayRenderer.render
text: text
previewSetter: previewSet
editor.run()
editor
}).call(this);

View File

@@ -1,10 +1,23 @@
class @FeedbackForm
constructor: ->
$('#feedback_button').click ->
data =
subject: $('#feedback_subject').val()
message: $('#feedback_message').val()
url: window.location.href
$.postWithPrefix '/send_feedback', data, ->
$('#feedback_div').html 'Feedback submitted. Thank you'
,'json'
// Once generated by CoffeeScript 1.9.3, but now lives as pure JS
/* eslint-disable */
(function() {
this.FeedbackForm = (function() {
function FeedbackForm() {
$('#feedback_button').click(function() {
var data;
data = {
subject: $('#feedback_subject').val(),
message: $('#feedback_message').val(),
url: window.location.href
};
return $.postWithPrefix('/send_feedback', data, function() {
return $('#feedback_div').html('Feedback submitted. Thank you'); // xss-lint: disable=javascript-jquery-html
}, 'json');
});
}
return FeedbackForm;
})();
}).call(this);

View File

@@ -1,36 +1,68 @@
class @Histogram
constructor: (@id, @rawData) ->
@xTicks = []
@yTicks = []
@data = []
@calculate()
@render()
// Once generated by CoffeeScript 1.9.3, but now lives as pure JS
/* eslint-disable */
(function() {
this.Histogram = (function() {
function Histogram(id, rawData) {
this.id = id;
this.rawData = rawData;
this.xTicks = [];
this.yTicks = [];
this.data = [];
this.calculate();
this.render();
}
calculate: ->
for [score, count] in @rawData
continue if score == null
log_count = Math.log(count + 1)
@data.push [score, log_count]
@xTicks.push [score, score.toString()]
@yTicks.push [log_count, count.toString()]
Histogram.prototype.calculate = function() {
var count, i, len, log_count, ref, ref1, results, score;
ref = this.rawData;
results = [];
for (i = 0, len = ref.length; i < len; i++) {
ref1 = ref[i], score = ref1[0], count = ref1[1];
if (score === null) {
continue;
}
log_count = Math.log(count + 1);
this.data.push([score, log_count]);
this.xTicks.push([score, score.toString()]);
results.push(this.yTicks.push([log_count, count.toString()]));
}
return results;
};
render: ->
$.plot $("#histogram_#{@id}"), [
data: @data
bars:
show: true
align: 'center'
lineWidth: 0
fill: 1.0
color: "#b72121"
],
xaxis:
min: -1
max: Math.max.apply Math, $.map(@xTicks, (data) -> data[0] + 1)
ticks: @xTicks
tickLength: 0
yaxis:
min: 0.0
max: Math.max.apply Math, $.map(@yTicks, (data) -> data[0] * 1.1)
ticks: @yTicks
labelWidth: 50
Histogram.prototype.render = function() {
return $.plot($("#histogram_" + this.id), [
{
data: this.data,
bars: {
show: true,
align: 'center',
lineWidth: 0,
fill: 1.0
},
color: "#b72121"
}
], {
xaxis: {
min: -1,
max: Math.max.apply(Math, $.map(this.xTicks, function(data) {
return data[0] + 1;
})),
ticks: this.xTicks,
tickLength: 0
},
yaxis: {
min: 0.0,
max: Math.max.apply(Math, $.map(this.yTicks, function(data) {
return data[0] * 1.1;
})),
ticks: this.yTicks,
labelWidth: 50
}
});
};
return Histogram;
})();
}).call(this);

View File

@@ -6,7 +6,7 @@ The instructor dashboard is broken into sections.
Only one section is visible at a time,
and is responsible for its own functionality.
NOTE: plantTimeout (which is just setTimeout from util.coffee)
NOTE: plantTimeout (which is just setTimeout from util.js)
is used frequently in the instructor dashboard to isolate
failures. If one piece of code under a plantTimeout fails
then it will not crash the rest of the dashboard.
@@ -19,7 +19,7 @@ NOTE: Server endpoints in the dashboard are stored in
The urls are rendered there by a template.
NOTE: For an example of what a section object should look like
see course_info.coffee
see course_info.js
imports from other modules
wrap in (-> ... apply) to defer evaluation

View File

@@ -1,38 +1,64 @@
AjaxPrefix.addAjaxPrefix(jQuery, -> $("meta[name='path_prefix']").attr('content'))
// Once generated by CoffeeScript 1.9.3, but now lives as pure JS
/* eslint-disable */
(function() {
AjaxPrefix.addAjaxPrefix(jQuery, function() {
return $("meta[name='path_prefix']").attr('content');
});
$ ->
$.ajaxSetup
headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
dataType: 'json'
$(function() {
$.ajaxSetup({
headers: {
'X-CSRFToken': $.cookie('csrftoken')
},
dataType: 'json'
});
window.onTouchBasedDevice = function() {
return navigator.userAgent.match(/iPhone|iPod|iPad|Android/i);
};
if (onTouchBasedDevice()) {
$('body').addClass('touch-based-device');
}
window.onTouchBasedDevice = ->
navigator.userAgent.match /iPhone|iPod|iPad|Android/i
/*
$("a[rel*=leanModal]").leanModal()
*/
$('#csrfmiddlewaretoken').attr('value', $.cookie('csrftoken'));
new Calculator;
new FeedbackForm;
if ($('body').hasClass('courseware')) {
Courseware.start();
}
window.postJSON = function(url, data, callback) {
return $.postWithPrefix(url, data, callback);
};
$('#login').click(function() {
$('#login_form input[name="email"]').focus();
return false;
});
$('#signup').click(function() {
$('#signup-modal input[name="email"]').focus();
return false;
});
$('body').addClass 'touch-based-device' if onTouchBasedDevice()
/*
fix for ie
*/
if (!Array.prototype.indexOf) {
return Array.prototype.indexOf = function(obj, start) {
var ele, i, j, len, ref;
if (start == null) {
start = 0;
}
ref = this.slice(start);
for (i = j = 0, len = ref.length; j < len; i = ++j) {
ele = ref[i];
if (ele === obj) {
return i + start;
}
return -1;
}
};
}
});
# $("a[rel*=leanModal]").leanModal()
$('#csrfmiddlewaretoken').attr 'value', $.cookie('csrftoken')
new Calculator
new FeedbackForm
if $('body').hasClass('courseware')
Courseware.start()
window.postJSON = (url, data, callback) ->
$.postWithPrefix url, data, callback
$('#login').click ->
$('#login_form input[name="email"]').focus()
false
$('#signup').click ->
$('#signup-modal input[name="email"]').focus()
false
# fix for ie
if !Array::indexOf
Array::indexOf = (obj, start = 0) ->
for ele, i in this[start..]
if ele is obj
return i + start
return -1
}).call(this);

View File

@@ -1,21 +1,37 @@
$ ->
if window.navigator.appName is "Microsoft Internet Explorer"
isMPInstalled = (boolean) ->
# check if MathPlayer is installed
# (from http://www.dessci.com/en/products/mathplayer/check.htm)
try
oMP = new ActiveXObject("MathPlayer.Factory.1")
true
catch e
false
// Once generated by CoffeeScript 1.9.3, but now lives as pure JS
/* eslint-disable */
(function() {
$(function() {
var isMPInstalled;
if (window.navigator.appName === "Microsoft Internet Explorer") {
isMPInstalled = function(boolean) {
var e, oMP;
/*
check if MathPlayer is installed
(from http://www.dessci.com/en/products/mathplayer/check.htm)
*/
try {
oMP = new ActiveXObject("MathPlayer.Factory.1");
return true;
} catch (_error) {
e = _error;
return false;
}
};
# detect if there is mathjax on the page
# if not, set 'aria-hidden' to 'true'
if MathJax? and not isMPInstalled()
$("#mathjax-accessibility-message").attr("aria-hidden", "false")
/*
detect if there is mathjax on the page
if not, set 'aria-hidden' to 'true'
*/
if ((typeof MathJax !== "undefined" && MathJax !== null) && !isMPInstalled()) {
$("#mathjax-accessibility-message").attr("aria-hidden", "false");
}
if ((typeof MathJax !== "undefined" && MathJax !== null) && $("#mathplayer-browser-message").length > 0) {
return $("#mathplayer-browser-message").attr("aria-hidden", "false");
} else {
return $("#mathjax-accessibility-message").attr("aria-hidden", "true");
}
}
});
if MathJax? and $("#mathplayer-browser-message").length > 0
$("#mathplayer-browser-message").attr("aria-hidden", "false")
else
$("#mathjax-accessibility-message").attr("aria-hidden", "true")
}).call(this);

View File

@@ -1,73 +1,109 @@
getTime = ->
new Date().getTime()
// 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 getTime;
class @MathJaxDelayRenderer
getTime = function() {
return new Date().getTime();
};
maxDelay: 3000
mathjaxRunning: false
elapsedTime: 0
mathjaxDelay: 0
mathjaxTimeout: undefined
bufferId = "mathjax_delay_buffer"
numBuffers = 0
this.MathJaxDelayRenderer = (function() {
var bufferId, numBuffers;
constructor: (params) ->
params = params || {}
@maxDelay = params["maxDelay"] || @maxDelay
@bufferId = params["bufferId"] || (bufferId + numBuffers)
numBuffers += 1
@$buffer = $("<div>").attr("id", @bufferId).css("display", "none").appendTo($("body"))
MathJaxDelayRenderer.prototype.maxDelay = 3000;
# render: (params) ->
# params:
# elem: jquery element to be rendered
# text: text to be rendered & put into the element;
# if blank, then just render the current text in the element
# preprocessor: pre-process the text before rendering using MathJax
# if text is blank, it will pre-process the html in the element
# previewSetter: if provided, will pass text back to it instead of
# directly setting the element
MathJaxDelayRenderer.prototype.mathjaxRunning = false;
render: (params) ->
MathJaxDelayRenderer.prototype.elapsedTime = 0;
elem = params["element"]
previewSetter = params["previewSetter"]
text = params["text"]
if not text?
text = $(elem).html()
preprocessor = params["preprocessor"]
MathJaxDelayRenderer.prototype.mathjaxDelay = 0;
if params["delay"] == false
if preprocessor?
text = preprocessor(text)
$(elem).html(text)
MathJax.Hub.Queue ["Typeset", MathJax.Hub, $(elem).attr("id")]
else
if @mathjaxTimeout
window.clearTimeout(@mathjaxTimeout)
@mathjaxTimeout = undefined
delay = Math.min @elapsedTime + @mathjaxDelay, @maxDelay
renderer = =>
if @mathjaxRunning
return
prevTime = getTime()
if preprocessor?
text = preprocessor(text)
@$buffer.html(text)
curTime = getTime()
@elapsedTime = curTime - prevTime
if MathJax?
prevTime = getTime()
@mathjaxRunning = true
MathJax.Hub.Queue ["Typeset", MathJax.Hub, @$buffer.attr("id")], =>
@mathjaxRunning = false
curTime = getTime()
@mathjaxDelay = curTime - prevTime
if previewSetter
previewSetter($(@$buffer).html())
else
$(elem).html($(@$buffer).html())
else
@mathjaxDelay = 0
@mathjaxTimeout = window.setTimeout(renderer, delay)
MathJaxDelayRenderer.prototype.mathjaxTimeout = void 0;
bufferId = "mathjax_delay_buffer";
numBuffers = 0;
function MathJaxDelayRenderer(params) {
params = params || {};
this.maxDelay = params["maxDelay"] || this.maxDelay;
this.bufferId = params["bufferId"] || (bufferId + numBuffers);
numBuffers += 1;
this.$buffer = $("<div>").attr("id", this.bufferId).css("display", "none").appendTo($("body")); // xss-lint: disable=javascript-jquery-insert-into-target
}
/*
render: (params) ->
params:
elem: jquery element to be rendered
text: text to be rendered & put into the element;
if blank, then just render the current text in the element
preprocessor: pre-process the text before rendering using MathJax
if text is blank, it will pre-process the html in the element
previewSetter: if provided, will pass text back to it instead of
directly setting the element
*/
MathJaxDelayRenderer.prototype.render = function(params) {
var delay, elem, preprocessor, previewSetter, renderer, text;
elem = params["element"];
previewSetter = params["previewSetter"];
text = params["text"];
if (text == null) {
text = $(elem).html();
}
preprocessor = params["preprocessor"];
if (params["delay"] === false) {
if (preprocessor != null) {
text = preprocessor(text);
}
$(elem).html(text); // xss-lint: disable=javascript-jquery-html
return MathJax.Hub.Queue(["Typeset", MathJax.Hub, $(elem).attr("id")]);
} else {
if (this.mathjaxTimeout) {
window.clearTimeout(this.mathjaxTimeout);
this.mathjaxTimeout = void 0;
}
delay = Math.min(this.elapsedTime + this.mathjaxDelay, this.maxDelay);
renderer = (function(_this) {
return function() {
var curTime, prevTime;
if (_this.mathjaxRunning) {
return;
}
prevTime = getTime();
if (preprocessor != null) {
text = preprocessor(text);
}
_this.$buffer.html(text); // xss-lint: disable=javascript-jquery-html
curTime = getTime();
_this.elapsedTime = curTime - prevTime;
if (typeof MathJax !== "undefined" && MathJax !== null) {
prevTime = getTime();
_this.mathjaxRunning = true;
return MathJax.Hub.Queue(["Typeset", MathJax.Hub, _this.$buffer.attr("id")], function() {
_this.mathjaxRunning = false;
curTime = getTime();
_this.mathjaxDelay = curTime - prevTime;
if (previewSetter) {
return previewSetter($(_this.$buffer).html());
} else {
return $(elem).html($(_this.$buffer).html()); // xss-lint: disable=javascript-jquery-html
}
});
} else {
return _this.mathjaxDelay = 0;
}
};
})(this);
return this.mathjaxTimeout = window.setTimeout(renderer, delay);
}
};
return MathJaxDelayRenderer;
})();
}).call(this);

View File

@@ -1,23 +1,52 @@
class @Tab
constructor: (@id, @items) ->
@el = $("#tab_#{id}")
@render()
// 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); }; };
$: (selector) ->
$(selector, @el)
this.Tab = (function() {
function Tab(id1, items) {
this.id = id1;
this.items = items;
this.onShow = bind(this.onShow, this);
this.el = $("#tab_" + id);
this.render();
}
render: ->
$.each @items, (index, item) =>
tab = $('<a>').attr(href: "##{@tabId(index)}").html(item.title)
@$('.navigation').append($('<li>').append(tab))
@el.append($('<section>').attr(id: @tabId(index)))
@el.tabs
show: @onShow
Tab.prototype.$ = function(selector) {
return $(selector, this.el);
};
onShow: (element, ui) =>
@$('section.ui-tabs-hide').html('')
@$("##{@tabId(ui.index)}").html(@items[ui.index]['content'])
@el.trigger 'contentChanged'
Tab.prototype.render = function() {
$.each(this.items, (function(_this) {
return function(index, item) {
var tab;
tab = $('<a>').attr({
href: "#" + (_this.tabId(index))
}).html(item.title); // xss-lint: disable=javascript-jquery-html
_this.$('.navigation').append($('<li>').append(tab)); // xss-lint: disable=javascript-jquery-append
return _this.el.append($('<section>').attr({
id: _this.tabId(index)
}));
};
})(this));
return this.el.tabs({
show: this.onShow
});
};
tabId: (index) ->
"tab-#{@id}-#{index}"
Tab.prototype.onShow = function(element, ui) {
this.$('section.ui-tabs-hide').html('');
this.$("#" + (this.tabId(ui.index))).html(this.items[ui.index]['content']); // xss-lint: disable=javascript-jquery-html
return this.el.trigger('contentChanged');
};
Tab.prototype.tabId = function(index) {
return "tab-" + this.id + "-" + index;
};
return Tab;
})();
}).call(this);

View File

@@ -1,5 +1,5 @@
// This file is intentionally blank as it was removed because it was not
// This file is intentionally blank as it was removed because it was no
// longer necessary, but the pipeline requires it for whatever reason.
// Until the pipeline issue is resolved this file is here. It shouldn't
// conflict with anything.
var nothingtoseehere;
var nothingtoseehere;

View File

@@ -1,97 +1,168 @@
class StudentNotes
_debug: false
// Once generated by CoffeeScript 1.9.3, but now lives as pure JS
/* eslint-disable */
(function() {
var StudentNotes,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
targets: [] # holds elements with annotator() instances
StudentNotes = (function() {
StudentNotes.prototype._debug = false;
# Adds a listener for "notes" events that may bubble up from descendants.
constructor: ($, el) ->
console.log 'student notes init', arguments, this if @_debug
if not $(el).data('notes-instance')
events = 'notes:init': @onInitNotes
$(el).delegate('*', events)
$(el).data('notes-instance', @)
/*
holds elements with annotator() instances
*/
# Initializes annotations on a container element in response to an init event.
onInitNotes: (event, uri=null, storage_url=null, token=null) =>
event.stopPropagation()
StudentNotes.prototype.targets = [];
found = @targets.some (target) -> target is event.target
# Get uri
unless uri.substring(0, 4) is "http"
uri_root = (window.location.href.split(/#|\?/).shift() or "")
uri = uri_root + uri.substring(1)
parts = window.location.href.split("/")
courseid = parts[4] + "/" + parts[5] + "/" + parts[6]
/*
Adds a listener for "notes" events that may bubble up from descendants.
*/
# Get id and name user
idUdiv = $(event.target).parent().find(".idU")[0]
idDUdiv = $(event.target).parent().find(".idDU")[0]
idUdiv = (if typeof idUdiv isnt "undefined" then idUdiv.innerHTML else "")
idDUdiv = (if typeof idDUdiv isnt "undefined" then idDUdiv.innerHTML else "")
options =
optionsAnnotator:
permissions:
user:
id: idUdiv
name: idDUdiv
function StudentNotes($, el) {
this.onInitNotes = bind(this.onInitNotes, this);
var events;
if (this._debug) {
console.log('student notes init', arguments, this);
}
if (!$(el).data('notes-instance')) {
events = {
'notes:init': this.onInitNotes
};
$(el).delegate('*', events);
$(el).data('notes-instance', this);
}
}
userString: (user) ->
return user.name if user and user.name
user
userId: (user) ->
return user.id if user and user.id
user
auth:
token: token
/*
Initializes annotations on a container element in response to an init event.
*/
store:
prefix: storage_url
StudentNotes.prototype.onInitNotes = function(event, uri, storage_url, token) {
var courseid, found, idDUdiv, idUdiv, options, ova, parts, uri_root;
if (uri == null) {
uri = null;
}
if (storage_url == null) {
storage_url = null;
}
if (token == null) {
token = null;
}
event.stopPropagation();
found = this.targets.some(function(target) {
return target === event.target;
});
annotationData: uri:uri
/*
Get uri
*/
if (uri.substring(0, 4) !== "http") {
uri_root = window.location.href.split(/#|\?/).shift() || "";
uri = uri_root + uri.substring(1);
}
parts = window.location.href.split("/");
courseid = parts[4] + "/" + parts[5] + "/" + parts[6];
urls:
create: '/create',
read: '/read/:id',
update: '/update/:id',
destroy: '/delete/:id',
search: '/search'
/*
Get id and name user
*/
idUdiv = $(event.target).parent().find(".idU")[0];
idDUdiv = $(event.target).parent().find(".idDU")[0];
idUdiv = (typeof idUdiv !== "undefined" ? idUdiv.innerHTML : "");
idDUdiv = (typeof idDUdiv !== "undefined" ? idDUdiv.innerHTML : "");
options = {
optionsAnnotator: {
permissions: {
user: {
id: idUdiv,
name: idDUdiv
},
userString: function(user) {
if (user && user.name) {
return user.name;
}
return user;
},
userId: function(user) {
if (user && user.id) {
return user.id;
}
return user;
}
},
auth: {
token: token
},
store: {
prefix: storage_url,
annotationData: {
uri: uri
},
urls: {
create: '/create',
read: '/read/:id',
update: '/update/:id',
destroy: '/delete/:id',
search: '/search'
},
loadFromSearch: {
limit: 10000,
uri: uri,
user: idUdiv
}
}
},
optionsVideoJS: {
techOrder: ["html5", "flash", "youtube"],
customControlsOnMobile: true
},
optionsOVA: {
posBigNew: 'none',
NumAnnotations: 20
},
optionsRichText: {
tinymce: {
selector: "li.annotator-item textarea",
plugins: "media image insertdatetime link code",
menubar: false,
toolbar_items_size: 'small',
extended_valid_elements: "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]",
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media rubric | code "
}
}
};
if (found) {
if (Annotator._instances.length !== 0) {
$(event.target).annotator("destroy");
}
return ova = new OpenVideoAnnotation.Annotator($(event.target), options);
} else {
if (event.target.id === "annotator-viewer") {
return ova = new OpenVideoAnnotation.Annotator($(event.target), options);
} else {
return this.targets.push(event.target);
}
}
};
loadFromSearch:
limit:10000
uri: uri
user:idUdiv
optionsVideoJS: techOrder: ["html5","flash","youtube"],customControlsOnMobile: true
optionsOVA:
posBigNew:'none'
NumAnnotations:20
optionsRichText:
tinymce:
selector: "li.annotator-item textarea"
plugins: "media image insertdatetime link code"
menubar: false
toolbar_items_size: 'small'
extended_valid_elements : "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]"
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media rubric | code "
if found
$(event.target).annotator "destroy" unless Annotator._instances.length is 0
ova = new OpenVideoAnnotation.Annotator($(event.target), options)
else
if event.target.id is "annotator-viewer"
ova = new OpenVideoAnnotation.Annotator($(event.target), options)
else
@targets.push(event.target)
return StudentNotes;
# Enable notes by default on the document root.
# To initialize annotations on a container element in the document:
#
# $('#myElement').trigger('notes:init');
#
# Comment this line to disable notes.
})();
$(document).ready ($) -> new StudentNotes $, @
/*
Enable notes by default on the document root.
To initialize annotations on a container element in the document:
$('#myElement').trigger('notes:init');
Comment this line to disable notes.
*/
$(document).ready(function($) {
return new StudentNotes($, this);
});
}).call(this);

View File

@@ -26,7 +26,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/**/!(*spec).js'},
{pattern: 'course_bookmarks/**/!(*spec).js'},
{pattern: 'course_search/**/!(*spec).js'},
{pattern: 'discussion/js/**/!(*spec).js'},

View File

@@ -1,71 +0,0 @@
// Karma config for lms-coffee suite.
// Docs and troubleshooting tips in common/static/common/js/karma.common.conf.js
/* eslint-env node */
'use strict';
var path = require('path');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var options = {
useRequireJs: false,
includeCommonFiles: true,
// Avoid adding files to this list. Use RequireJS.
libraryFilesToInclude: [
{pattern: 'common/js/vendor/require.js', included: true},
{pattern: 'js/RequireJS-namespace-undefine.js', included: true},
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/slick.core.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/slick.grid.js', included: true},
{pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: true},
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
{pattern: 'common/js/vendor/underscore.js', included: true},
{pattern: 'common/js/xblock/*.js', included: true},
{pattern: 'xmodule_js/common_static/js/src/logger.js', included: true},
{pattern: 'xmodule_js/common_static/js/test/i18n.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/flot/jquery.flot.js', included: true},
{pattern: 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/URI.min.js', included: true},
{pattern: 'common/js/vendor/hls.js', included: true},
{pattern: 'xmodule_js/src/capa/*.js', included: true},
{pattern: 'xmodule_js/src/video/*.js', included: true},
{pattern: 'xmodule_js/src/xmodule.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: true},
{pattern: 'common/js/spec_helpers/jasmine-extensions.js', included: true},
{pattern: 'lms/js/spec/main_requirejs_coffee.js', included: true}
],
libraryFiles: [
{pattern: 'xmodule_js/common_static/js/vendor/**/*.js'}
],
// 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}
],
specFiles: [
{pattern: 'coffee/spec/**/*.js', included: true}
],
fixtureFiles: [
{pattern: 'coffee/fixtures/**/*.*', included: true}
]
};
module.exports = function(config) {
configModule.configure(config, options);
};

View File

@@ -69,7 +69,7 @@
*/
paths: {
gettext: 'empty:',
'coffee/src/ajax_prefix': 'empty:',
'js/src/ajax_prefix': 'empty:',
jquery: 'empty:',
'jquery-migrate': 'empty:',
'jquery.cookie': 'empty:',

View File

@@ -31,7 +31,7 @@
'jquery.fileupload': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload',
'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',
'jquery.timeago': 'xmodule_js/common_static/js/vendor/jquery.timeago',
'jquery.url': 'xmodule_js/common_static/js/vendor/url.min',
@@ -58,7 +58,7 @@
'domReady': 'xmodule_js/common_static/js/vendor/domReady',
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/instructor_dashboard/student_admin': 'js/instructor_dashboard/student_admin',
'xmodule_js/common_static/js/test/add_ajax_prefix': 'xmodule_js/common_static/js/test/add_ajax_prefix',
'xblock/lms.runtime.v1': 'lms/js/xblock/lms.runtime.v1',
@@ -71,8 +71,8 @@
'Markdown.Editor': 'js/Markdown.Editor',
'Markdown.Sanitizer': 'js/Markdown.Sanitizer',
'_split': 'js/split',
'mathjax_delay_renderer': 'coffee/src/mathjax_delay_renderer',
'MathJaxProcessor': 'coffee/src/customwmd',
'mathjax_delay_renderer': 'js/mathjax_delay_renderer',
'MathJaxProcessor': 'js/customwmd',
'picturefill': 'common/js/vendor/picturefill',
'bootstrap': 'common/js/vendor/bootstrap.bundle',
'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly',
@@ -282,7 +282,7 @@
},
'xmodule_js/common_static/js/test/add_ajax_prefix': {
exports: 'AjaxPrefix',
deps: ['coffee/src/ajax_prefix']
deps: ['js/src/ajax_prefix']
},
'js/instructor_dashboard/util': {
exports: 'js/instructor_dashboard/util',

View File

@@ -16,9 +16,9 @@ from openedx.core.djangolib.markup import HTML
## add in a definition of 'xxx_url' in the right section_data for whatever page your
## feature is on.
## 3. Add a url() entry in api_urls.py
## 4. Over in lms/static/coffee/src/instructor_dashboard/ there there are .coffee files
## for each page which define the .js. Edit this to make your input do something
## when clicked. The .coffee files use the name=xx to pick out inputs, not id=
## 4. Over in lms/static/js/instructor_dashboard/ there are .js files for each page.
## Edit this to make your input do something when clicked. The .js files use the
## name=xx to pick out inputs, not id=
## 5. Implement your standard django/python in lms/djangoapps/instructor/views/api.py
## 6. And tests go in lms/djangoapps/instructor/tests/
@@ -110,7 +110,7 @@ from openedx.core.djangolib.markup import HTML
</div>
## links which are tied to idash-sections below.
## the links are activated and handled in instructor_dashboard.coffee
## the links are activated and handled in instructor_dashboard.js
## when the javascript loads, it clicks on the first section
<ul class="instructor-nav">
% for section_data in sections:

25
package-lock.json generated
View File

@@ -2091,31 +2091,6 @@
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"coffee-loader": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/coffee-loader/-/coffee-loader-0.7.3.tgz",
"integrity": "sha1-+tvG79b8fsyIxbMEaiwpIGa8tUo=",
"requires": {
"loader-utils": "1.1.0"
},
"dependencies": {
"loader-utils": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
"integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
"requires": {
"big.js": "3.2.0",
"emojis-list": "2.1.0",
"json5": "0.5.1"
}
}
}
},
"coffee-script": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.1.tgz",
"integrity": "sha1-NLVd7bCc7zbRseKQgwLgV/HiYGg="
},
"collapse-white-space": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.3.tgz",

View File

@@ -19,8 +19,6 @@
"bootstrap": "4.0.0-beta.2",
"camelize": "1.0.0",
"classnames": "2.2.5",
"coffee-loader": "0.7.3",
"coffee-script": "1.6.1",
"css-loader": "0.28.8",
"edx-pattern-library": "0.18.1",
"edx-ui-toolkit": "1.5.2",

View File

@@ -28,7 +28,6 @@ from .utils.timer import timed
# setup baseline paths
ALL_SYSTEMS = ['lms', 'studio']
COFFEE_DIRS = ['lms', 'cms', 'common']
LMS = 'lms'
CMS = 'cms'
@@ -301,32 +300,6 @@ def debounce(seconds=1):
return decorator
class CoffeeScriptWatcher(PatternMatchingEventHandler):
"""
Watches for coffeescript changes
"""
ignore_directories = True
patterns = ['*.coffee']
def register(self, observer):
"""
register files with observer
"""
dirnames = set()
for filename in sh(coffeescript_files(), capture=True).splitlines():
dirnames.add(path(filename).dirname())
for dirname in dirnames:
observer.schedule(self, dirname)
@debounce()
def on_any_event(self, event):
print('\tCHANGED:', event.src_path)
try:
compile_coffeescript(event.src_path)
except Exception: # pylint: disable=broad-except
traceback.print_exc()
class SassWatcher(PatternMatchingEventHandler):
"""
Watches for sass file changes
@@ -403,28 +376,6 @@ class XModuleAssetsWatcher(PatternMatchingEventHandler):
restart_django_servers()
def coffeescript_files():
"""
return find command for paths containing coffee files
"""
dirs = " ".join(Env.REPO_ROOT / coffee_dir for coffee_dir in COFFEE_DIRS)
return cmd('find', dirs, '-type f', '-name \"*.coffee\"')
@task
@no_help
@timed
def compile_coffeescript(*files):
"""
Compile CoffeeScript to JavaScript.
"""
if not files:
files = ["`{}`".format(coffeescript_files())]
sh(cmd(
"node_modules/.bin/coffee", "--compile", *files
))
@task
@no_help
@cmdopts([
@@ -736,7 +687,6 @@ def collect_assets(systems, settings, **kwargs):
# We compile these out, don't need the source files in staticfiles
"sass",
"*.coffee",
]
ignore_args = " ".join(
@@ -906,7 +856,6 @@ def watch_assets(options):
sass_directories = get_watcher_dirs(theme_dirs, themes)
observer = Observer(timeout=wait)
CoffeeScriptWatcher().register(observer)
SassWatcher().register(observer, sass_directories)
XModuleSassWatcher().register(observer, ['common/lib/xmodule/'])
XModuleAssetsWatcher().register(observer)
@@ -936,7 +885,7 @@ def watch_assets(options):
@timed
def update_assets(args):
"""
Compile CoffeeScript and Sass, then collect static assets.
Compile Sass, then collect static assets.
"""
parser = argparse.ArgumentParser(prog='paver update_assets')
parser.add_argument(
@@ -980,7 +929,6 @@ def update_assets(args):
process_xmodule_assets()
process_npm_assets()
compile_coffeescript()
# Build Webpack
call_task('pavelib.assets.webpack', options={'settings': args.settings})

View File

@@ -25,7 +25,6 @@ DEFAULT_SETTINGS = Env.DEVSTACK_SETTINGS
@needs(
"pavelib.prereqs.install_prereqs",
"pavelib.i18n.i18n_validate_gettext",
"pavelib.assets.compile_coffeescript",
)
@cmdopts([
("verbose", "v", "Sets 'verbose' to True"),

View File

@@ -18,10 +18,6 @@ class TestPaverJavaScriptTestTasks(PaverTestCase):
EXPECTED_DELETE_JAVASCRIPT_REPORT_COMMAND = u'find {platform_root}/reports/javascript -type f -delete'
EXPECTED_INSTALL_NPM_ASSETS_COMMAND = u'install npm_assets'
EXPECTED_COFFEE_COMMAND = (
u'node_modules/.bin/coffee --compile `find {platform_root}/lms {platform_root}/cms '
u'{platform_root}/common -type f -name "*.coffee"`'
)
EXPECTED_KARMA_OPTIONS = (
u"{config_file} "
u"--single-run={single_run} "
@@ -120,7 +116,6 @@ class TestPaverJavaScriptTestTasks(PaverTestCase):
platform_root=self.platform_root
))
expected_messages.append(self.EXPECTED_INSTALL_NPM_ASSETS_COMMAND)
expected_messages.append(self.EXPECTED_COFFEE_COMMAND.format(platform_root=self.platform_root))
for suite in suites:
# Karma test command

View File

@@ -6,10 +6,6 @@ from paver.easy import call_task
from ..utils.envs import Env
from .utils import PaverTestCase
EXPECTED_COFFEE_COMMAND = (
u"node_modules/.bin/coffee --compile `find {platform_root}/lms "
u"{platform_root}/cms {platform_root}/common -type f -name \"*.coffee\"`"
)
EXPECTED_SASS_COMMAND = (
u"libsass {sass_directory}"
)
@@ -33,7 +29,7 @@ EXPECTED_COLLECT_STATIC_COMMAND = (
u'python manage.py {system} --settings={asset_settings} collectstatic '
u'--ignore "fixtures" --ignore "karma_*.js" --ignore "spec" '
u'--ignore "spec_helpers" --ignore "spec-helpers" --ignore "xmodule_js" '
u'--ignore "geoip" --ignore "sass" --ignore "*.coffee" '
u'--ignore "geoip" --ignore "sass" '
u'--noinput {log_string}'
)
EXPECTED_CELERY_COMMAND = (
@@ -247,7 +243,6 @@ class TestPaverServerTasks(PaverTestCase):
if not is_fast:
expected_messages.append(u"xmodule_assets common/static/xmodule")
expected_messages.append(u"install npm_assets")
expected_messages.append(EXPECTED_COFFEE_COMMAND.format(platform_root=self.platform_root))
expected_messages.extend(
[c.format(settings=expected_asset_settings) for c in EXPECTED_PRINT_SETTINGS_COMMAND]
)
@@ -293,7 +288,6 @@ class TestPaverServerTasks(PaverTestCase):
if not is_fast:
expected_messages.append(u"xmodule_assets common/static/xmodule")
expected_messages.append(u"install npm_assets")
expected_messages.append(EXPECTED_COFFEE_COMMAND.format(platform_root=self.platform_root))
expected_messages.extend(
[c.format(settings=expected_asset_settings) for c in EXPECTED_PRINT_SETTINGS_COMMAND]
)

View File

@@ -182,7 +182,6 @@ class Env(object):
REPO_ROOT / 'cms/static/karma_cms.conf.js',
REPO_ROOT / 'cms/static/karma_cms_squire.conf.js',
REPO_ROOT / 'lms/static/karma_lms.conf.js',
REPO_ROOT / 'lms/static/karma_lms_coffee.conf.js',
REPO_ROOT / 'common/lib/xmodule/xmodule/js/karma_xmodule.conf.js',
REPO_ROOT / 'common/static/karma_common.conf.js',
REPO_ROOT / 'common/static/karma_common_requirejs.conf.js',
@@ -192,7 +191,6 @@ class Env(object):
'cms',
'cms-squire',
'lms',
'lms-coffee',
'xmodule',
'common',
'common-requirejs'

View File

@@ -39,7 +39,6 @@ class JsTestSuite(TestSuite):
test_utils.clean_dir(self.report_dir)
assets.process_npm_assets()
assets.compile_coffeescript("`find lms cms common -type f -name \"*.coffee\"`")
@property
def _default_subsuites(self):
@@ -51,7 +50,7 @@ class JsTestSuite(TestSuite):
class JsTestSubSuite(TestSuite):
"""
Class for JS suites like cms, cms-squire, lms, lms-coffee, common,
Class for JS suites like cms, cms-squire, lms, common,
common-requirejs and xmodule
"""
def __init__(self, *args, **kwargs):

Some files were not shown because too many files have changed in this diff Show More