Fix elem not selected if id contains special chars
If the id of a `.formulaequationinput input` element contains a special character, then the selector for $preview was silently failing to match the element, because no escaping was happening. This fixes the issue by escaping the id before passing to the jQuery selector function. CSS.escape is the ideal method, but this isn't present in IE or Edge, so we use a fallback borrowed from the new jQuery.escapeSelector method.
This commit is contained in:
@@ -1,3 +1,29 @@
|
||||
describe('escapeSelector', function() {
|
||||
'use strict';
|
||||
var escapeSelector = window.escapeSelector;
|
||||
|
||||
it('correctly escapes css', function() {
|
||||
// tests borrowed from https://github.com/jquery/jquery/blob/3edfa1bcdc50bca41ac58b2642b12f3feee03a3b/test/unit/selector.js#L2030
|
||||
expect(escapeSelector('-')).toEqual('\\-');
|
||||
expect(escapeSelector('-a')).toEqual('-a');
|
||||
expect(escapeSelector('--')).toEqual('--');
|
||||
expect(escapeSelector('--a')).toEqual('--a');
|
||||
expect(escapeSelector('\uFFFD')).toEqual('\uFFFD');
|
||||
expect(escapeSelector('\uFFFDb')).toEqual('\uFFFDb');
|
||||
expect(escapeSelector('a\uFFFDb')).toEqual('a\uFFFDb');
|
||||
expect(escapeSelector('1a')).toEqual('\\31 a');
|
||||
expect(escapeSelector('a\0b')).toEqual('a\uFFFDb');
|
||||
expect(escapeSelector('a3b')).toEqual('a3b');
|
||||
expect(escapeSelector('-4a')).toEqual('-\\34 a');
|
||||
expect(escapeSelector('\x01\x02\x1E\x1F')).toEqual('\\1 \\2 \\1e \\1f ');
|
||||
|
||||
// This is the important one; xblocks and course ids often contain invalid characters, so if these aren't
|
||||
// escaped when embedding/searching xblock IDs using css selectors, bad things happen.
|
||||
expect(escapeSelector('course-v1:edX+DemoX+Demo_Course')).toEqual('course-v1\\:edX\\+DemoX\\+Demo_Course');
|
||||
expect(escapeSelector('block-v1:edX+DemoX+Demo_Course+type@sequential+block')).toEqual('block-v1\\:edX\\+DemoX\\+Demo_Course\\+type\\@sequential\\+block');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Formula Equation Preview', function() {
|
||||
'use strict';
|
||||
var formulaEquationPreview = window.formulaEquationPreview;
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
function escapeSelector(id) {
|
||||
// Wrapper around window.CSS.escape that uses a fallback method if CSS.escape is not available.
|
||||
// This is designed to serialize a string to be used as a valid css selector. See https://drafts.csswg.org/cssom/#the-css.escape()-method
|
||||
// For example, can be used with xblock and course ids, which often contain invalid characters that must be escaped
|
||||
// to function properly in css selectors.
|
||||
|
||||
// TODO: if this escaping is also required elsewhere, it may be useful to add a global CSS.escape polyfill and
|
||||
// use that directly.
|
||||
if (window.CSS && window.CSS.escape) {
|
||||
return CSS.escape(id);
|
||||
} else {
|
||||
// CSS escape alternative borrowed from https://api.jquery.com/jQuery.escapeSelector/ source. When we upgrade to jQuery 3.0, we can use $.escapeSelector() instead of this shim escapeSelector function.
|
||||
// source: https://github.com/jquery/jquery/blob/3edfa1bc/src/selector/escapeSelector.js
|
||||
|
||||
// CSS string/identifier serialization
|
||||
// https://drafts.csswg.org/cssom/#common-serializing-idioms
|
||||
var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
|
||||
function fcssescape( ch, asCodePoint ) {
|
||||
if ( asCodePoint ) {
|
||||
// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
|
||||
if ( ch === "\0" ) {
|
||||
return "\uFFFD";
|
||||
}
|
||||
// Control characters and (dependent upon position) numbers get escaped as code points
|
||||
return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
|
||||
}
|
||||
// Other potentially-special ASCII characters get backslash-escaped
|
||||
return "\\" + ch;
|
||||
}
|
||||
// ensure string and then run the replacements
|
||||
return (id + "").replace(rcssescape, fcssescape);
|
||||
}
|
||||
}
|
||||
|
||||
var formulaEquationPreview = {
|
||||
minDelay: 300, // Minimum time between requests sent out.
|
||||
errorDelay: 1500 // Wait time before showing error (prevent frustration).
|
||||
@@ -13,7 +47,7 @@ formulaEquationPreview.enable = function() {
|
||||
function setupInput() {
|
||||
var $this = $(this); // cache the jQuery object
|
||||
|
||||
var $preview = $('#' + this.id + '_preview');
|
||||
var $preview = $('#' + escapeSelector(this.id) + '_preview');
|
||||
var inputData = {
|
||||
// These are the mutable values
|
||||
|
||||
|
||||
Reference in New Issue
Block a user