Chromevox theme now an extension, added demo file, added findSearchBox event.

This commit is contained in:
Peter Xiao 2013-08-12 15:58:09 -07:00
commit 38b42d20d3
4 changed files with 809 additions and 786 deletions

44
demo/chromevox.html Normal file
View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ACE Autocompletion demo</title>
<style type="text/css" media="screen">
body {
overflow: hidden;
}
#editor {
margin: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
</head>
<body>
<pre id="editor"></pre>
<!-- load ace -->
<script src="../build/src/ace.js"></script>
<!-- load ace language tools -->
<script src="../build/src/ext-chromevox.js"></script>
<script>
// trigger extension
ace.require("ace/ext/chromevox");
var editor = ace.edit("editor");
editor.session.setMode("ace/mode/html");
editor.setTheme("ace/theme/tomorrow");
// enable autocompletion and snippets
editor.setOptions({
enableBasicAutocompletion: true,
enableSnippets: true
});
</script>
<script src="./show_own_source.js"></script>
</body>
</html>

View file

@ -1,4 +1,5 @@
define(function(require, exports, module) { define(function(require, exports, module) {
/* ChromeVox Ace namespace. */ /* ChromeVox Ace namespace. */
var cvoxAce = {}; var cvoxAce = {};
@ -141,11 +142,12 @@ define(function(require, exports, module) {
var KEY_PREFIX = 'CONTROL + SHIFT '; var KEY_PREFIX = 'CONTROL + SHIFT ';
/* Globals. */ /* Globals. */
cvoxAce.editor = null;
/** /**
* Last cursor position. * Last cursor position.
* @type {!cvoxAce.Cursor} * @type {cvoxAce.Cursor}
*/ */
var lastCursor = ace.selection.getCursor(); var lastCursor = null;
/** /**
* Table of annotations. * Table of annotations.
@ -201,7 +203,8 @@ define(function(require, exports, module) {
* @return {boolean} True if in Vim mode. * @return {boolean} True if in Vim mode.
*/ */
var isVimMode = function() { var isVimMode = function() {
return ace.keyBinding.getKeyboardHandler().$id === 'ace/keyboard/vim'; var keyboardHandler = cvoxAce.editor.keyBinding.getKeyboardHandler();
return keyboardHandler.$id === 'ace/keyboard/vim';
}; };
/** /**
@ -210,7 +213,7 @@ define(function(require, exports, module) {
* @return {!cvoxAce.Token} Token at the current position. * @return {!cvoxAce.Token} Token at the current position.
*/ */
var getCurrentToken = function(cursor) { var getCurrentToken = function(cursor) {
return ace.getSession().getTokenAt(cursor.row, cursor.column + 1); return cvoxAce.editor.getSession().getTokenAt(cursor.row, cursor.column + 1);
}; };
/** /**
@ -218,7 +221,7 @@ define(function(require, exports, module) {
* @param {!cvoxAce.Cursor} cursor Current cursor position. * @param {!cvoxAce.Cursor} cursor Current cursor position.
*/ */
var getCurrentLine = function(cursor) { var getCurrentLine = function(cursor) {
return ace.getSession().getLine(cursor.row); return cvoxAce.editor.getSession().getLine(cursor.row);
}; };
/** /**
@ -278,7 +281,7 @@ define(function(require, exports, module) {
* @param {number} queue Queue mode to speak. * @param {number} queue Queue mode to speak.
*/ */
var speakLine = function(row, queue) { var speakLine = function(row, queue) {
var tokens = ace.getSession().getTokens(row); var tokens = cvoxAce.editor.getSession().getTokens(row);
if (tokens.length === 0) { if (tokens.length === 0) {
return; return;
} }
@ -418,7 +421,7 @@ define(function(require, exports, module) {
changed = false; changed = false;
return; return;
} }
var currCursor = ace.selection.getCursor(); var currCursor = cvoxAce.editor.selection.getCursor();
if (currCursor.row !== lastCursor.row) { if (currCursor.row !== lastCursor.row) {
onRowChange(currCursor); onRowChange(currCursor);
} else { } else {
@ -482,7 +485,7 @@ define(function(require, exports, module) {
* @param {!Event} evt Event. * @param {!Event} evt Event.
*/ */
var onAnnotationChange = function(evt) { var onAnnotationChange = function(evt) {
var annotations = ace.getSession().getAnnotations(); var annotations = cvoxAce.editor.getSession().getAnnotations();
var newAnnotations = annotations.filter(isNewAnnotation); var newAnnotations = annotations.filter(isNewAnnotation);
if (newAnnotations.length > 0) { if (newAnnotations.length > 0) {
cvox.Api.playEarcon(ERROR_EARCON); cvox.Api.playEarcon(ERROR_EARCON);
@ -545,7 +548,7 @@ define(function(require, exports, module) {
if (!isVimMode()) { if (!isVimMode()) {
return; return;
} }
switch (ace.keyBinding.$data.state) { switch (cvoxAce.editor.keyBinding.$data.state) {
case INSERT_MODE_STATE: case INSERT_MODE_STATE:
cvox.Api.speak('Insert mode'); cvox.Api.speak('Insert mode');
break; break;
@ -640,7 +643,7 @@ define(function(require, exports, module) {
shortcut.func(); shortcut.func();
/* ChromeVox will bring focus to an element near the cursor instead of the /* ChromeVox will bring focus to an element near the cursor instead of the
* text input. */ * text input. */
ace.focus(); cvoxAce.editor.focus();
} }
}; };
@ -663,47 +666,13 @@ define(function(require, exports, module) {
body.addEventListener('ATCustomEvent', contextMenuHandler, true); body.addEventListener('ATCustomEvent', contextMenuHandler, true);
}; };
/** var onFindSearchbox = function(evt) {
* Returns a mutations handler where f is applied to each mutation. if (evt.match) {
* @param {function} f Function to be applied to mutations.
*/
var getMutationHandler = function(f) {
return function(mutations) {
mutations.forEach(f);
};
};
/**
* Watches and handles the mutation that is a result of a search.
* @param {Mutation} m Mutation.
*/
var watchForSearch = function(m) {
if (m.attributeName === 'class' &&
m.target.className === 'ace_search_form ace_nomatch') {
/* No match, give auditory feedback! */
cvox.Api.playEarcon(NO_MATCH_EARCON);
} else {
/* There is still a match! Speak the line. */ /* There is still a match! Speak the line. */
speakLine(lastCursor.row, 0); speakLine(lastCursor.row, 0);
} } else {
}; /* No match, give auditory feedback! */
cvox.Api.playEarcon(NO_MATCH_EARCON);
/**
* Configuration for mutation observer.
*/
var MO_CONFIG = { attributes: true, childList: true, characterData: true};
/**
* Watches and handles the mutation that adds the search bar to the DOM.
*/
var watchForStartSearch = function(m) {
for (var i = 0; i < m.addedNodes.length; i++) {
if (m.addedNodes.item(i).className === 'ace_search right') {
var mutationHandler = getMutationHandler(watchForSearch);
var searchObs = new MutationObserver(mutationHandler);
var target = m.addedNodes.item(i).querySelector('.ace_search_form');
searchObs.observe(target, MO_CONFIG);
}
} }
}; };
@ -711,7 +680,7 @@ define(function(require, exports, module) {
* Focus to text input. * Focus to text input.
*/ */
var focus = function() { var focus = function() {
ace.focus(); cvoxAce.editor.focus();
}; };
/** /**
@ -774,7 +743,9 @@ define(function(require, exports, module) {
/** /**
* Initialize the theme. * Initialize the theme.
*/ */
var init = function() { var init = function(editor) {
cvoxAce.editor = editor;
lastCursor = editor.selection.getCursor();
/* Construct maps. */ /* Construct maps. */
SHORTCUTS.forEach(function(shortcut) { SHORTCUTS.forEach(function(shortcut) {
keyCodeToShortcutMap[shortcut.keyCode] = shortcut; keyCodeToShortcutMap[shortcut.keyCode] = shortcut;
@ -782,10 +753,11 @@ define(function(require, exports, module) {
}); });
/* Set up listeners. */ /* Set up listeners. */
ace.getSession().selection.on('changeCursor', onCursorChange); cvoxAce.editor.getSession().selection.on('changeCursor', onCursorChange);
ace.getSession().on('change', onChange); cvoxAce.editor.getSession().on('change', onChange);
ace.getSession().on('changeAnnotation', onAnnotationChange); cvoxAce.editor.getSession().on('changeAnnotation', onAnnotationChange);
ace.on('changeStatus', onChangeStatus); cvoxAce.editor.on('changeStatus', onChangeStatus);
cvoxAce.editor.on('findSearchBox', onFindSearchbox);
window.addEventListener('keydown', onKeyDown); window.addEventListener('keydown', onKeyDown);
/* Assume we start in command mode if vim. */ /* Assume we start in command mode if vim. */
@ -794,13 +766,7 @@ define(function(require, exports, module) {
} }
initContextMenu(); initContextMenu();
var target = document.querySelector('.ace_editor'); cvoxAce.editor.focus();
var mutationHandler = getMutationHandler(watchForStartSearch);
var observer = new MutationObserver(mutationHandler);
observer.observe(target, MO_CONFIG);
ace.focus();
}; };
/** /**
@ -825,19 +791,30 @@ define(function(require, exports, module) {
/** /**
* Check for ChromeVox load. * Check for ChromeVox load.
* @param {Object} editor Editor to use.
*/ */
function watchForCvoxLoad() { function watchForCvoxLoad(editor) {
if (cvoxApiExists()) { if (cvoxApiExists()) {
init(); init(editor);
} else { } else {
tries++; tries++;
if (tries >= MAX_TRIES) { if (tries >= MAX_TRIES) {
return; return;
} }
window.setTimeout(watchForCvoxLoad, 500); window.setTimeout(watchForCvoxLoad, 500, editor);
} }
} }
/* Initialize everything when ChromeVox has loaded. */ var Editor = require('../editor').Editor;
watchForCvoxLoad(); require('../config').defineOptions(Editor.prototype, 'editor', {
enableChromevoxEnhancements: {
set: function(val) {
if (val) {
watchForCvoxLoad(this);
}
},
value: true // turn it on by default or check for window.cvox
}
});
}); });

View file

@ -214,7 +214,9 @@ var SearchBox = function(editor, range, showReplaceForm) {
caseSensitive: this.caseSensitiveOption.checked, caseSensitive: this.caseSensitiveOption.checked,
wholeWord: this.wholeWordOption.checked wholeWord: this.wholeWordOption.checked
}); });
dom.setCssClass(this.searchBox, "ace_nomatch", !range && this.searchInput.value); var noMatch = !range && this.searchInput.value;
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
this.editor._emit("findSearchBox", { match: !noMatch });
this.highlight(); this.highlight();
}; };
this.findNext = function() { this.findNext = function() {

View file

@ -16,8 +16,8 @@ module.exports.themes = [
"kr_theme", "kr_theme",
"merbivore", "merbivore",
"merbivore_soft", "merbivore_soft",
"monokai",
"mono_industrial", "mono_industrial",
"monokai",
"pastel_on_dark", "pastel_on_dark",
"solarized_dark", "solarized_dark",
"solarized_light", "solarized_light",