Commit a1f0679f by Sofiya Semenova

Educator 1552 - Implement roving tabindex for WYSIWYG editor for discussions

parent f9623fc9
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
DiscussionUtil.wmdEditors = {}; DiscussionUtil.wmdEditors = {};
DiscussionUtil.leftKey = 37;
DiscussionUtil.rightKey = 39;
DiscussionUtil.getTemplate = function(id) { DiscussionUtil.getTemplate = function(id) {
return $('script#' + id).html(); return $('script#' + id).html();
}; };
...@@ -539,6 +542,38 @@ ...@@ -539,6 +542,38 @@
}; };
}; };
DiscussionUtil.handleKeypressInToolbar = function(event) {
var $currentButton, $nextButton, $toolbar, $allButtons,
keyPressed, nextIndex, currentButtonIndex,
validKeyPress, toolbarHasButtons;
$currentButton = $(event.target);
keyPressed = event.which || event.keyCode;
$toolbar = $currentButton.parent();
$allButtons = $toolbar.children('.wmd-button');
validKeyPress = keyPressed === this.leftKey || keyPressed === this.rightKey;
toolbarHasButtons = $allButtons.length > 0;
if (validKeyPress && toolbarHasButtons) {
currentButtonIndex = $allButtons.index($currentButton);
nextIndex = keyPressed === this.leftKey ? currentButtonIndex - 1 : currentButtonIndex + 1;
nextIndex = Math.max(Math.min(nextIndex, $allButtons.length - 1), 0);
$nextButton = $($allButtons[nextIndex]);
this.moveSelectionToNextItem($currentButton, $nextButton);
}
};
DiscussionUtil.moveSelectionToNextItem = function(prevItem, nextItem) {
prevItem.attr('aria-selected', 'false');
prevItem.attr('tabindex', '-1');
nextItem.attr('aria-selected', 'true');
nextItem.attr('tabindex', '0');
nextItem.focus();
};
return DiscussionUtil; return DiscussionUtil;
}).call(this); }).call(this);
}).call(window); }).call(window);
...@@ -62,7 +62,10 @@ ...@@ -62,7 +62,10 @@
DiscussionThreadView.prototype.events = { DiscussionThreadView.prototype.events = {
'click .discussion-submit-post': 'submitComment', 'click .discussion-submit-post': 'submitComment',
'click .add-response-btn': 'scrollToAddResponse' 'click .add-response-btn': 'scrollToAddResponse',
'keydown .wmd-button': function(event) {
return DiscussionUtil.handleKeypressInToolbar(event);
}
}; };
DiscussionThreadView.prototype.$ = function(selector) { DiscussionThreadView.prototype.$ = function(selector) {
......
...@@ -137,7 +137,10 @@ ...@@ -137,7 +137,10 @@
'change .post-option-input': 'postOptionChange', 'change .post-option-input': 'postOptionChange',
'click .cancel': 'cancel', 'click .cancel': 'cancel',
'click .add-post-cancel': 'cancel', 'click .add-post-cancel': 'cancel',
'reset .forum-new-post-form': 'updateStyles' 'reset .forum-new-post-form': 'updateStyles',
'keydown .wmd-button': function(event) {
return DiscussionUtil.handleKeypressInToolbar(event);
}
}; };
NewPostView.prototype.toggleGroupDropdown = function($target) { NewPostView.prototype.toggleGroupDropdown = function($target) {
......
// needs Markdown.Converter.js at the moment // needs Markdown.Converter.js at the moment
(function() { (function() {
var util = {}, var util = {},
position = {}, position = {},
ui = {}, ui = {},
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
// - getConverter() returns the markdown converter object that was passed to the constructor // - getConverter() returns the markdown converter object that was passed to the constructor
// - run() actually starts the editor; should be called after all necessary plugins are registered. Calling this more than once is a no-op. // - run() actually starts the editor; should be called after all necessary plugins are registered. Calling this more than once is a no-op.
// - refreshPreview() forces the preview to be updated. This method is only available after run() was called. // - refreshPreview() forces the preview to be updated. This method is only available after run() was called.
Markdown.Editor = function(markdownConverter, idPostfix, help, imageUploadHandler) { Markdown.Editor = function(markdownConverter, idPostfix, help, imageUploadHandler) {
idPostfix = idPostfix || ''; idPostfix = idPostfix || '';
var hooks = this.hooks = new Markdown.HookCollection(); var hooks = this.hooks = new Markdown.HookCollection();
...@@ -107,7 +107,7 @@ ...@@ -107,7 +107,7 @@
var forceRefresh = that.refreshPreview = function() { previewManager.refresh(true); }; var forceRefresh = that.refreshPreview = function() { previewManager.refresh(true); };
forceRefresh(); forceRefresh();
}; };
}; };
// before: contains all the text in the input box BEFORE the selection. // before: contains all the text in the input box BEFORE the selection.
...@@ -116,11 +116,11 @@ ...@@ -116,11 +116,11 @@
// startRegex: a regular expression to find the start tag // startRegex: a regular expression to find the start tag
// endRegex: a regular expresssion to find the end tag // endRegex: a regular expresssion to find the end tag
Chunks.prototype.findTags = function(startRegex, endRegex) { Chunks.prototype.findTags = function(startRegex, endRegex) {
var chunkObj = this; var chunkObj = this;
var regex; var regex;
if (startRegex) { if (startRegex) {
regex = util.extendRegExp(startRegex, '', '$'); regex = util.extendRegExp(startRegex, '', '$');
this.before = this.before.replace(regex, this.before = this.before.replace(regex,
...@@ -138,7 +138,7 @@ ...@@ -138,7 +138,7 @@
}); });
} }
if (endRegex) { if (endRegex) {
regex = util.extendRegExp(endRegex, '', '$'); regex = util.extendRegExp(endRegex, '', '$');
this.selection = this.selection.replace(regex, this.selection = this.selection.replace(regex,
...@@ -174,7 +174,7 @@ ...@@ -174,7 +174,7 @@
}; };
Chunks.prototype.skipLines = function(nLinesBefore, nLinesAfter, findExtraNewlines) { Chunks.prototype.skipLines = function(nLinesBefore, nLinesAfter, findExtraNewlines) {
if (nLinesBefore === undefined) { if (nLinesBefore === undefined) {
nLinesBefore = 1; nLinesBefore = 1;
} }
...@@ -205,7 +205,7 @@ ...@@ -205,7 +205,7 @@
this.endTag = this.endTag.replace(/(\n*$)/, ''); this.endTag = this.endTag.replace(/(\n*$)/, '');
this.after = this.after + re.$1; this.after = this.after + re.$1;
if (this.before) { if (this.before) {
regexText = replacementText = ''; regexText = replacementText = '';
while (nLinesBefore--) { while (nLinesBefore--) {
...@@ -219,7 +219,7 @@ ...@@ -219,7 +219,7 @@
this.before = this.before.replace(new re(regexText + '$', ''), replacementText); this.before = this.before.replace(new re(regexText + '$', ''), replacementText);
} }
if (this.after) { if (this.after) {
regexText = replacementText = ''; regexText = replacementText = '';
while (nLinesAfter--) { while (nLinesAfter--) {
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
// Returns true if the DOM element is visible, false if it's hidden. // Returns true if the DOM element is visible, false if it's hidden.
// Checks if display is anything other than none. // Checks if display is anything other than none.
util.isVisible = function(elem) { util.isVisible = function(elem) {
if (window.getComputedStyle) { if (window.getComputedStyle) {
// Most browsers // Most browsers
return window.getComputedStyle(elem, null).getPropertyValue('display') !== 'none'; return window.getComputedStyle(elem, null).getPropertyValue('display') !== 'none';
...@@ -318,7 +318,7 @@ ...@@ -318,7 +318,7 @@
// The flags are unchanged. // The flags are unchanged.
// //
// regex is a RegExp, pre and post are strings. // regex is a RegExp, pre and post are strings.
util.extendRegExp = function(regex, pre, post) { util.extendRegExp = function(regex, pre, post) {
if (pre === null || pre === undefined) { if (pre === null || pre === undefined) {
pre = ''; pre = '';
} }
...@@ -363,7 +363,7 @@ ...@@ -363,7 +363,7 @@
return elem.offsetWidth || elem.scrollWidth; return elem.offsetWidth || elem.scrollWidth;
}; };
position.getPageSize = function() { position.getPageSize = function() {
var scrollWidth, scrollHeight; var scrollWidth, scrollHeight;
var innerWidth, innerHeight; var innerWidth, innerHeight;
...@@ -404,7 +404,7 @@ ...@@ -404,7 +404,7 @@
// Handles pushing and popping TextareaStates for undo/redo commands. // Handles pushing and popping TextareaStates for undo/redo commands.
// I should rename the stack variables to list. // I should rename the stack variables to list.
function UndoManager(callback, panels) { function UndoManager(callback, panels) {
var undoObj = this; var undoObj = this;
var undoStack = []; // A stack of undo states var undoStack = []; // A stack of undo states
var stackPtr = 0; // The index of the current state var stackPtr = 0; // The index of the current state
...@@ -453,7 +453,7 @@ ...@@ -453,7 +453,7 @@
}; };
// Removes the last state and restores it. // Removes the last state and restores it.
this.undo = function() { this.undo = function() {
if (undoObj.canUndo()) { if (undoObj.canUndo()) {
if (lastState) { if (lastState) {
// What about setting state -1 to null or checking for undefined? // What about setting state -1 to null or checking for undefined?
...@@ -476,8 +476,8 @@ ...@@ -476,8 +476,8 @@
}; };
// Redo an action. // Redo an action.
this.redo = function() { this.redo = function() {
if (undoObj.canRedo()) { if (undoObj.canRedo()) {
undoStack[++stackPtr].restore(); undoStack[++stackPtr].restore();
if (callback) { if (callback) {
...@@ -516,10 +516,10 @@ ...@@ -516,10 +516,10 @@
} }
}; };
var handleCtrlYZ = function(event) { var handleCtrlYZ = function(event) {
var handled = false; var handled = false;
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
// IE and Opera do not support charCode. // IE and Opera do not support charCode.
var keyCode = event.charCode || event.keyCode; var keyCode = event.charCode || event.keyCode;
var keyCodeChar = String.fromCharCode(keyCode); var keyCodeChar = String.fromCharCode(keyCode);
...@@ -555,8 +555,8 @@ ...@@ -555,8 +555,8 @@
}; };
// Set the mode depending on what is going on in the input area. // Set the mode depending on what is going on in the input area.
var handleModeChange = function(event) { var handleModeChange = function(event) {
if (!event.ctrlKey && !event.metaKey) { if (!event.ctrlKey && !event.metaKey) {
var keyCode = event.keyCode; var keyCode = event.keyCode;
if ((keyCode >= 33 && keyCode <= 40) || (keyCode >= 63232 && keyCode <= 63235)) { if ((keyCode >= 33 && keyCode <= 40) || (keyCode >= 63232 && keyCode <= 63235)) {
...@@ -630,7 +630,7 @@ ...@@ -630,7 +630,7 @@
// The input textarea state/contents. // The input textarea state/contents.
// This is used to implement undo/redo by the undo manager. // This is used to implement undo/redo by the undo manager.
function TextareaState(panels, isInitialState) { function TextareaState(panels, isInitialState) {
// Aliases // Aliases
var stateObj = this; var stateObj = this;
var inputArea = panels.input; var inputArea = panels.input;
...@@ -646,23 +646,23 @@ ...@@ -646,23 +646,23 @@
this.scrollTop = inputArea.scrollTop; this.scrollTop = inputArea.scrollTop;
if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) { if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) {
this.text = inputArea.value; this.text = inputArea.value;
} }
}; };
// Sets the selected text in the input box after we've performed an // Sets the selected text in the input box after we've performed an
// operation. // operation.
this.setInputAreaSelection = function() { this.setInputAreaSelection = function() {
if (!util.isVisible(inputArea)) { if (!util.isVisible(inputArea)) {
return; return;
} }
if (inputArea.selectionStart !== undefined && !uaSniffed.isOpera) { if (inputArea.selectionStart !== undefined && !uaSniffed.isOpera) {
inputArea.focus(); inputArea.focus();
inputArea.selectionStart = stateObj.start; inputArea.selectionStart = stateObj.start;
inputArea.selectionEnd = stateObj.end; inputArea.selectionEnd = stateObj.end;
inputArea.scrollTop = stateObj.scrollTop; inputArea.scrollTop = stateObj.scrollTop;
} }
else if (doc.selection) { else if (doc.selection) {
if (doc.activeElement && doc.activeElement !== inputArea) { if (doc.activeElement && doc.activeElement !== inputArea) {
return; return;
} }
...@@ -677,12 +677,12 @@ ...@@ -677,12 +677,12 @@
} }
}; };
this.setInputAreaSelectionStartEnd = function() { this.setInputAreaSelectionStartEnd = function() {
if (!panels.ieCachedRange && (inputArea.selectionStart || inputArea.selectionStart === 0)) { if (!panels.ieCachedRange && (inputArea.selectionStart || inputArea.selectionStart === 0)) {
stateObj.start = inputArea.selectionStart; stateObj.start = inputArea.selectionStart;
stateObj.end = inputArea.selectionEnd; stateObj.end = inputArea.selectionEnd;
} }
else if (doc.selection) { else if (doc.selection) {
stateObj.text = util.fixEolChars(inputArea.value); stateObj.text = util.fixEolChars(inputArea.value);
// IE loses the selection in the textarea when buttons are // IE loses the selection in the textarea when buttons are
...@@ -723,7 +723,7 @@ ...@@ -723,7 +723,7 @@
}; };
// Restore this state into the input area. // Restore this state into the input area.
this.restore = function() { this.restore = function() {
if (stateObj.text != undefined && stateObj.text != inputArea.value) { if (stateObj.text != undefined && stateObj.text != inputArea.value) {
inputArea.value = stateObj.text; inputArea.value = stateObj.text;
} }
...@@ -732,7 +732,7 @@ ...@@ -732,7 +732,7 @@
}; };
// Gets a collection of HTML chunks from the inptut textarea. // Gets a collection of HTML chunks from the inptut textarea.
this.getChunks = function() { this.getChunks = function() {
var chunk = new Chunks(); var chunk = new Chunks();
chunk.before = util.fixEolChars(stateObj.text.substring(0, stateObj.start)); chunk.before = util.fixEolChars(stateObj.text.substring(0, stateObj.start));
chunk.startTag = ''; chunk.startTag = '';
...@@ -745,7 +745,7 @@ ...@@ -745,7 +745,7 @@
}; };
// Sets the TextareaState properties given a chunk of markdown. // Sets the TextareaState properties given a chunk of markdown.
this.setChunks = function(chunk) { this.setChunks = function(chunk) {
chunk.before = chunk.before + chunk.startTag; chunk.before = chunk.before + chunk.startTag;
chunk.after = chunk.endTag + chunk.after; chunk.after = chunk.endTag + chunk.after;
...@@ -757,7 +757,7 @@ ...@@ -757,7 +757,7 @@
this.init(); this.init();
} }
function PreviewManager(converter, panels, previewPushCallback) { function PreviewManager(converter, panels, previewPushCallback) {
var managerObj = this; var managerObj = this;
var timeout; var timeout;
var elapsedTime; var elapsedTime;
...@@ -766,7 +766,7 @@ ...@@ -766,7 +766,7 @@
var startType = 'delayed'; // The other legal value is "manual" var startType = 'delayed'; // The other legal value is "manual"
// Adds event listeners to elements // Adds event listeners to elements
var setupEvents = function(inputElem, listener) { var setupEvents = function(inputElem, listener) {
util.addEvent(inputElem, 'input', listener); util.addEvent(inputElem, 'input', listener);
inputElem.onpaste = listener; inputElem.onpaste = listener;
inputElem.ondrop = listener; inputElem.ondrop = listener;
...@@ -775,7 +775,7 @@ ...@@ -775,7 +775,7 @@
util.addEvent(inputElem, 'keydown', listener); util.addEvent(inputElem, 'keydown', listener);
}; };
var getDocScrollTop = function() { var getDocScrollTop = function() {
var result = 0; var result = 0;
if (window.innerHeight) { if (window.innerHeight) {
...@@ -793,7 +793,7 @@ ...@@ -793,7 +793,7 @@
return result; return result;
}; };
var makePreviewHtml = function() { var makePreviewHtml = function() {
// If there is no registered preview panel // If there is no registered preview panel
// there is nothing to do. // there is nothing to do.
if (!panels.preview) if (!panels.preview)
...@@ -821,13 +821,13 @@ ...@@ -821,13 +821,13 @@
}; };
// setTimeout is already used. Used as an event listener. // setTimeout is already used. Used as an event listener.
var applyTimeout = function() { var applyTimeout = function() {
if (timeout) { if (timeout) {
clearTimeout(timeout); clearTimeout(timeout);
timeout = undefined; timeout = undefined;
} }
if (startType !== 'manual') { if (startType !== 'manual') {
var delay = 0; var delay = 0;
if (startType === 'delayed') { if (startType === 'delayed') {
...@@ -854,7 +854,7 @@ ...@@ -854,7 +854,7 @@
} }
}; };
this.refresh = function(requiresRefresh) { this.refresh = function(requiresRefresh) {
if (requiresRefresh) { if (requiresRefresh) {
oldInputText = ''; oldInputText = '';
makePreviewHtml(); makePreviewHtml();
...@@ -904,7 +904,7 @@ ...@@ -904,7 +904,7 @@
} }
}; };
var pushPreviewHtml = function(text) { var pushPreviewHtml = function(text) {
var emptyTop = position.getTop(panels.input) - getDocScrollTop(); var emptyTop = position.getTop(panels.input) - getDocScrollTop();
if (panels.preview) { if (panels.preview) {
...@@ -930,7 +930,7 @@ ...@@ -930,7 +930,7 @@
} }
}; };
var init = function() { var init = function() {
setupEvents(panels.input, applyTimeout); setupEvents(panels.input, applyTimeout);
makePreviewHtml(); makePreviewHtml();
...@@ -946,7 +946,7 @@ ...@@ -946,7 +946,7 @@
// And download dialog // And download dialog
// Most of this has been moved to CSS but the div creation and // Most of this has been moved to CSS but the div creation and
// browser-specific hacks remain here. // browser-specific hacks remain here.
ui.createBackground = function() { ui.createBackground = function() {
var background = doc.createElement('div'), var background = doc.createElement('div'),
style = background.style; style = background.style;
...@@ -999,7 +999,7 @@ ...@@ -999,7 +999,7 @@
defaultInputText, defaultInputText,
callback, callback,
imageIsDecorativeLabel, imageIsDecorativeLabel,
imageUploadHandler) { imageUploadHandler) {
// These variables need to be declared at this level since they are used // These variables need to be declared at this level since they are used
// in multiple functions. // in multiple functions.
var dialog, // The dialog box. var dialog, // The dialog box.
...@@ -1108,7 +1108,7 @@ ...@@ -1108,7 +1108,7 @@
imageIsDecorativeLabel: imageIsDecorativeLabel, imageIsDecorativeLabel: imageIsDecorativeLabel,
imageUploadHandler: imageUploadHandler imageUploadHandler: imageUploadHandler
}); });
dialog.setAttribute('dir', doc.head.getAttribute('dir')); dialog.setAttribute('dir', doc.head.getAttribute('dir'));
dialog.setAttribute('role', 'dialog'); dialog.setAttribute('role', 'dialog');
dialog.setAttribute('tabindex', '-1'); dialog.setAttribute('tabindex', '-1');
dialog.setAttribute('aria-labelledby', 'editorDialogTitle'); dialog.setAttribute('aria-labelledby', 'editorDialogTitle');
...@@ -1184,7 +1184,7 @@ ...@@ -1184,7 +1184,7 @@
// Why is this in a zero-length timeout? // Why is this in a zero-length timeout?
// Is it working around a browser bug? // Is it working around a browser bug?
setTimeout(function() { setTimeout(function() {
createDialog(); createDialog();
var defTextLen = defaultInputText.length; var defTextLen = defaultInputText.length;
...@@ -1204,7 +1204,7 @@ ...@@ -1204,7 +1204,7 @@
}, 0); }, 0);
}; };
function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, imageUploadHandler) { function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, imageUploadHandler) {
var inputBox = panels.input, var inputBox = panels.input,
buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements. buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements.
...@@ -1215,9 +1215,9 @@ ...@@ -1215,9 +1215,9 @@
keyEvent = 'keypress'; keyEvent = 'keypress';
} }
util.addEvent(inputBox, keyEvent, function(key) { util.addEvent(inputBox, keyEvent, function(key) {
// Check to see if we have a button key and, if so execute the callback. // Check to see if we have a button key and, if so execute the callback.
if ((key.ctrlKey || key.metaKey) && !key.altKey && !key.shiftKey) { if ((key.ctrlKey || key.metaKey) && !key.altKey && !key.shiftKey) {
var keyCode = key.charCode || key.keyCode; var keyCode = key.charCode || key.keyCode;
var keyCodeStr = String.fromCharCode(keyCode).toLowerCase(); var keyCodeStr = String.fromCharCode(keyCode).toLowerCase();
...@@ -1303,10 +1303,10 @@ ...@@ -1303,10 +1303,10 @@
// Perform the button's action. // Perform the button's action.
function doClick(button) { function doClick(button) {
inputBox.focus(); inputBox.focus();
if (button.textOp) { if (button.textOp) {
if (undoManager) { if (undoManager) {
undoManager.setCommandMode(); undoManager.setCommandMode();
} }
...@@ -1336,7 +1336,7 @@ ...@@ -1336,7 +1336,7 @@
// Yes this is awkward and I think it sucks, but there's // Yes this is awkward and I think it sucks, but there's
// no real workaround. Only the image and link code // no real workaround. Only the image and link code
// create dialogs and require the function pointers. // create dialogs and require the function pointers.
var fixupInputArea = function() { var fixupInputArea = function() {
inputBox.focus(); inputBox.focus();
if (chunks) { if (chunks) {
...@@ -1351,7 +1351,7 @@ ...@@ -1351,7 +1351,7 @@
if (!noCleanup) { if (!noCleanup) {
fixupInputArea(); fixupInputArea();
} }
} }
if (button.execute) { if (button.execute) {
...@@ -1359,7 +1359,7 @@ ...@@ -1359,7 +1359,7 @@
} }
} }
function setupButton(button, isEnabled) { function setupButton(button, isEnabled) {
var normalYShift = '0px'; var normalYShift = '0px';
var disabledYShift = '-20px'; var disabledYShift = '-20px';
var highlightYShift = '-40px'; var highlightYShift = '-40px';
...@@ -1429,7 +1429,7 @@ ...@@ -1429,7 +1429,7 @@
return function() { method.apply(commandManager, arguments); }; return function() { method.apply(commandManager, arguments); };
} }
function makeSpritedButtonRow() { function makeSpritedButtonRow() {
var buttonBar = panels.buttonBar; var buttonBar = panels.buttonBar;
var normalYShift = '0px'; var normalYShift = '0px';
...@@ -1442,9 +1442,9 @@ ...@@ -1442,9 +1442,9 @@
buttonRow.className = 'wmd-button-row'; buttonRow.className = 'wmd-button-row';
buttonRow = buttonBar.appendChild(buttonRow); buttonRow = buttonBar.appendChild(buttonRow);
var xPosition = 0; var xPosition = 0;
var makeButton = function(id, title, XShift, textOp) { var makeButton = function(id, title, XShift, textOp, tabIndex) {
var button = document.createElement('button'); var button = document.createElement('button');
button.tabIndex = 0; button.tabIndex = tabIndex;
button.className = 'wmd-button'; button.className = 'wmd-button';
button.style.left = xPosition + 'px'; button.style.left = xPosition + 'px';
xPosition += 25; xPosition += 25;
...@@ -1468,35 +1468,35 @@ ...@@ -1468,35 +1468,35 @@
xPosition += 25; xPosition += 25;
}; };
buttons.bold = makeButton('wmd-bold-button', gettext('Bold (Ctrl+B)'), '0px', bindCommand('doBold')); buttons.bold = makeButton('wmd-bold-button', gettext('Bold (Ctrl+B)'), '0px', bindCommand('doBold'), 0);
buttons.italic = makeButton('wmd-italic-button', gettext('Italic (Ctrl+I)'), '-20px', bindCommand('doItalic')); buttons.italic = makeButton('wmd-italic-button', gettext('Italic (Ctrl+I)'), '-20px', bindCommand('doItalic'), -1);
makeSpacer(1); makeSpacer(1);
buttons.link = makeButton('wmd-link-button', gettext('Hyperlink (Ctrl+L)'), '-40px', bindCommand(function(chunk, postProcessing) { buttons.link = makeButton('wmd-link-button', gettext('Hyperlink (Ctrl+L)'), '-40px', bindCommand(function(chunk, postProcessing) {
return this.doLinkOrImage(chunk, postProcessing, false); return this.doLinkOrImage(chunk, postProcessing, false);
})); }), -1);
buttons.quote = makeButton('wmd-quote-button', gettext('Blockquote (Ctrl+Q)'), '-60px', bindCommand('doBlockquote')); buttons.quote = makeButton('wmd-quote-button', gettext('Blockquote (Ctrl+Q)'), '-60px', bindCommand('doBlockquote'), -1);
buttons.code = makeButton('wmd-code-button', gettext('Code Sample (Ctrl+K)'), '-80px', bindCommand('doCode')); buttons.code = makeButton('wmd-code-button', gettext('Code Sample (Ctrl+K)'), '-80px', bindCommand('doCode'), -1);
buttons.image = makeButton('wmd-image-button', gettext('Image (Ctrl+G)'), '-100px', bindCommand(function(chunk, postProcessing) { buttons.image = makeButton('wmd-image-button', gettext('Image (Ctrl+G)'), '-100px', bindCommand(function(chunk, postProcessing) {
return this.doLinkOrImage(chunk, postProcessing, true, imageUploadHandler); return this.doLinkOrImage(chunk, postProcessing, true, imageUploadHandler);
})); }), -1);
makeSpacer(2); makeSpacer(2);
buttons.olist = makeButton('wmd-olist-button', gettext('Numbered List (Ctrl+O)'), '-120px', bindCommand(function(chunk, postProcessing) { buttons.olist = makeButton('wmd-olist-button', gettext('Numbered List (Ctrl+O)'), '-120px', bindCommand(function(chunk, postProcessing) {
this.doList(chunk, postProcessing, true); this.doList(chunk, postProcessing, true);
})); }), -1);
buttons.ulist = makeButton('wmd-ulist-button', gettext('Bulleted List (Ctrl+U)'), '-140px', bindCommand(function(chunk, postProcessing) { buttons.ulist = makeButton('wmd-ulist-button', gettext('Bulleted List (Ctrl+U)'), '-140px', bindCommand(function(chunk, postProcessing) {
this.doList(chunk, postProcessing, false); this.doList(chunk, postProcessing, false);
})); }), -1);
buttons.heading = makeButton('wmd-heading-button', gettext('Heading (Ctrl+H)'), '-160px', bindCommand('doHeading')); buttons.heading = makeButton('wmd-heading-button', gettext('Heading (Ctrl+H)'), '-160px', bindCommand('doHeading'), -1);
buttons.hr = makeButton('wmd-hr-button', gettext('Horizontal Rule (Ctrl+R)'), '-180px', bindCommand('doHorizontalRule')); buttons.hr = makeButton('wmd-hr-button', gettext('Horizontal Rule (Ctrl+R)'), '-180px', bindCommand('doHorizontalRule'), -1);
makeSpacer(3); makeSpacer(3);
buttons.undo = makeButton('wmd-undo-button', gettext('Undo (Ctrl+Z)'), '-200px', null); buttons.undo = makeButton('wmd-undo-button', gettext('Undo (Ctrl+Z)'), '-200px', null, -1);
buttons.undo.execute = function(manager) { if (manager) manager.undo(); }; buttons.undo.execute = function(manager) { if (manager) manager.undo(); };
var redoTitle = /win/.test(nav.platform.toLowerCase()) ? var redoTitle = /win/.test(nav.platform.toLowerCase()) ?
gettext('Redo (Ctrl+Y)') : gettext('Redo (Ctrl+Y)') :
gettext('Redo (Ctrl+Shift+Z)'); // mac and other non-Windows platforms gettext('Redo (Ctrl+Shift+Z)'); // mac and other non-Windows platforms
buttons.redo = makeButton('wmd-redo-button', redoTitle, '-220px', null); buttons.redo = makeButton('wmd-redo-button', redoTitle, '-220px', null, -1);
buttons.redo.execute = function(manager) { if (manager) manager.redo(); }; buttons.redo.execute = function(manager) { if (manager) manager.redo(); };
if (helpOptions) { if (helpOptions) {
...@@ -1526,7 +1526,7 @@ ...@@ -1526,7 +1526,7 @@
} }
} }
this.setUndoRedoButtonStates = setUndoRedoButtonStates; this.setUndoRedoButtonStates = setUndoRedoButtonStates;
} }
function CommandManager(pluginHooks) { function CommandManager(pluginHooks) {
...@@ -1570,7 +1570,7 @@ ...@@ -1570,7 +1570,7 @@
// chunk: The selected region that will be enclosed with */** // chunk: The selected region that will be enclosed with */**
// nStars: 1 for italics, 2 for bold // nStars: 1 for italics, 2 for bold
// insertText: If you just click the button without highlighting text, this gets inserted // insertText: If you just click the button without highlighting text, this gets inserted
commandProto.doBorI = function(chunk, postProcessing, nStars, insertText) { commandProto.doBorI = function(chunk, postProcessing, nStars, insertText) {
// Get rid of whitespace and fixup newlines. // Get rid of whitespace and fixup newlines.
chunk.trimWhitespace(); chunk.trimWhitespace();
chunk.selection = chunk.selection.replace(/\n{2,}/g, '\n'); chunk.selection = chunk.selection.replace(/\n{2,}/g, '\n');
...@@ -1595,7 +1595,7 @@ ...@@ -1595,7 +1595,7 @@
var whitespace = re.$1; var whitespace = re.$1;
chunk.before = chunk.before + starsAfter + whitespace; chunk.before = chunk.before + starsAfter + whitespace;
} }
else { else {
// In most cases, if you don't have any selected text and click the button // In most cases, if you don't have any selected text and click the button
// you'll get a selected, marked up region with the default text inserted. // you'll get a selected, marked up region with the default text inserted.
if (!chunk.selection && !starsAfter) { if (!chunk.selection && !starsAfter) {
...@@ -1611,7 +1611,7 @@ ...@@ -1611,7 +1611,7 @@
return; return;
}; };
commandProto.stripLinkDefs = function(text, defsToAdd) { commandProto.stripLinkDefs = function(text, defsToAdd) {
text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm, text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,
function(totalMatch, id, link, newlines, title) { function(totalMatch, id, link, newlines, title) {
defsToAdd[id] = totalMatch.replace(/\s*$/, ''); defsToAdd[id] = totalMatch.replace(/\s*$/, '');
...@@ -1626,7 +1626,7 @@ ...@@ -1626,7 +1626,7 @@
return text; return text;
}; };
commandProto.addLinkDef = function(chunk, linkDef) { commandProto.addLinkDef = function(chunk, linkDef) {
var refNumber = 0; // The current reference number var refNumber = 0; // The current reference number
var defsToAdd = {}; // var defsToAdd = {}; //
// Start with a clean slate by removing all previous link definitions. // Start with a clean slate by removing all previous link definitions.
...@@ -1707,12 +1707,12 @@ ...@@ -1707,12 +1707,12 @@
chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/); chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/);
var background; var background;
if (chunk.endTag.length > 1 && chunk.startTag.length > 0) { if (chunk.endTag.length > 1 && chunk.startTag.length > 0) {
chunk.startTag = chunk.startTag.replace(/!?\[/, ''); chunk.startTag = chunk.startTag.replace(/!?\[/, '');
chunk.endTag = ''; chunk.endTag = '';
this.addLinkDef(chunk, null); this.addLinkDef(chunk, null);
} }
else { else {
// We're moving start and end tag back into the selection, since (as we're in the else block) we're not // We're moving start and end tag back into the selection, since (as we're in the else block) we're not
// *removing* a link, but *adding* one, so whatever findTags() found is now back to being part of the // *removing* a link, but *adding* one, so whatever findTags() found is now back to being part of the
// link text. linkEnteredCallback takes care of escaping any brackets. // link text. linkEnteredCallback takes care of escaping any brackets.
...@@ -1808,7 +1808,7 @@ ...@@ -1808,7 +1808,7 @@
// When making a list, hitting shift-enter will put your cursor on the next line // When making a list, hitting shift-enter will put your cursor on the next line
// at the current indent level. // at the current indent level.
commandProto.doAutoindent = function(chunk, postProcessing) { commandProto.doAutoindent = function(chunk, postProcessing) {
var commandMgr = this, var commandMgr = this,
fakeSelection = false; fakeSelection = false;
...@@ -1850,7 +1850,7 @@ ...@@ -1850,7 +1850,7 @@
} }
}; };
commandProto.doBlockquote = function(chunk, postProcessing) { commandProto.doBlockquote = function(chunk, postProcessing) {
chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/, chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/,
function(totalMatch, newlinesBefore, text, newlinesAfter) { function(totalMatch, newlinesBefore, text, newlinesAfter) {
chunk.before += newlinesBefore; chunk.before += newlinesBefore;
...@@ -1945,7 +1945,7 @@ ...@@ -1945,7 +1945,7 @@
} }
); );
var replaceBlanksInTags = function(useBracket) { var replaceBlanksInTags = function(useBracket) {
var replacement = useBracket ? '> ' : ''; var replacement = useBracket ? '> ' : '';
if (chunk.startTag) { if (chunk.startTag) {
...@@ -1992,13 +1992,13 @@ ...@@ -1992,13 +1992,13 @@
} }
}; };
commandProto.doCode = function(chunk, postProcessing) { commandProto.doCode = function(chunk, postProcessing) {
var hasTextBefore = /\S[ ]*$/.test(chunk.before); var hasTextBefore = /\S[ ]*$/.test(chunk.before);
var hasTextAfter = /^[ ]*\S/.test(chunk.after); var hasTextAfter = /^[ ]*\S/.test(chunk.after);
// Use 'four space' markdown if the selection is on its own // Use 'four space' markdown if the selection is on its own
// line or is multiline. // line or is multiline.
if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) { if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) {
chunk.before = chunk.before.replace(/[ ]{4}$/, chunk.before = chunk.before.replace(/[ ]{4}$/,
function(totalMatch) { function(totalMatch) {
chunk.selection = totalMatch + chunk.selection; chunk.selection = totalMatch + chunk.selection;
...@@ -2055,7 +2055,7 @@ ...@@ -2055,7 +2055,7 @@
} }
}; };
commandProto.doList = function(chunk, postProcessing, isNumberedList) { commandProto.doList = function(chunk, postProcessing, isNumberedList) {
// These are identical except at the very beginning and end. // These are identical except at the very beginning and end.
// Should probably use the regex extension function to make this clearer. // Should probably use the regex extension function to make this clearer.
var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/; var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/;
...@@ -2083,7 +2083,7 @@ ...@@ -2083,7 +2083,7 @@
}; };
// Fixes the prefixes of the other list items. // Fixes the prefixes of the other list items.
var getPrefixedItem = function(itemText) { var getPrefixedItem = function(itemText) {
// The numbering flag is unset when called by autoindent. // The numbering flag is unset when called by autoindent.
if (isNumberedList === undefined) { if (isNumberedList === undefined) {
isNumberedList = /^\s*\d/.test(itemText); isNumberedList = /^\s*\d/.test(itemText);
...@@ -2105,7 +2105,7 @@ ...@@ -2105,7 +2105,7 @@
chunk.startTag = ''; chunk.startTag = '';
} }
if (chunk.startTag) { if (chunk.startTag) {
var hasDigits = /\d+[.]/.test(chunk.startTag); var hasDigits = /\d+[.]/.test(chunk.startTag);
chunk.startTag = ''; chunk.startTag = '';
chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, '\n'); chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, '\n');
...@@ -2151,10 +2151,10 @@ ...@@ -2151,10 +2151,10 @@
chunk.startTag = prefix; chunk.startTag = prefix;
var spaces = prefix.replace(/./g, ' '); var spaces = prefix.replace(/./g, ' ');
this.wrap(chunk, SETTINGS.lineLength - spaces.length); this.wrap(chunk, SETTINGS.lineLength - spaces.length);
chunk.selection = chunk.selection.replace(/\n/g, '\n' + spaces); chunk.selection = chunk.selection.replace(/\n/g, '\n' + spaces);
}; };
commandProto.doHeading = function(chunk, postProcessing) { commandProto.doHeading = function(chunk, postProcessing) {
// Remove leading/trailing whitespace and reduce internal spaces to single spaces. // Remove leading/trailing whitespace and reduce internal spaces to single spaces.
chunk.selection = chunk.selection.replace(/\s+/g, ' '); chunk.selection = chunk.selection.replace(/\s+/g, ' ');
chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, ''); chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, '');
...@@ -2196,7 +2196,7 @@ ...@@ -2196,7 +2196,7 @@
// If it's already a level 1 header, it's removed. // If it's already a level 1 header, it's removed.
var headerLevelToCreate = headerLevel == 0 ? 2 : headerLevel - 1; var headerLevelToCreate = headerLevel == 0 ? 2 : headerLevel - 1;
if (headerLevelToCreate > 0) { if (headerLevelToCreate > 0) {
// The button only creates level 1 and 2 underline headers. // The button only creates level 1 and 2 underline headers.
// Why not have it iterate over hash header levels? Wouldn't that be easier and cleaner? // Why not have it iterate over hash header levels? Wouldn't that be easier and cleaner?
var headerChar = headerLevelToCreate >= 2 ? '-' : '='; var headerChar = headerLevelToCreate >= 2 ? '-' : '=';
...@@ -2215,5 +2215,5 @@ ...@@ -2215,5 +2215,5 @@
chunk.startTag = '----------\n'; chunk.startTag = '----------\n';
chunk.selection = ''; chunk.selection = '';
chunk.skipLines(2, 1, true); chunk.skipLines(2, 1, true);
}; };
})(); })();
...@@ -13,7 +13,7 @@ set -e ...@@ -13,7 +13,7 @@ set -e
# Violations thresholds for failing the build # Violations thresholds for failing the build
export LOWER_PYLINT_THRESHOLD=1000 export LOWER_PYLINT_THRESHOLD=1000
export UPPER_PYLINT_THRESHOLD=5900 export UPPER_PYLINT_THRESHOLD=5900
export ESLINT_THRESHOLD=9134 export ESLINT_THRESHOLD=9543
export STYLELINT_THRESHOLD=973 export STYLELINT_THRESHOLD=973
XSSLINT_THRESHOLDS=`cat scripts/xsslint_thresholds.json` XSSLINT_THRESHOLDS=`cat scripts/xsslint_thresholds.json`
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment