/script-kiddie/002_script_kiddie/script-kiddie/node_modules/ace-builds/src-noconflict/ext-chromevox.js |
@@ -0,0 +1,540 @@ |
ace.define("ace/ext/chromevox",["require","exports","module","ace/editor","ace/config"], function(require, exports, module) { |
var cvoxAce = {}; |
cvoxAce.SpeechProperty; |
cvoxAce.Cursor; |
cvoxAce.Token; |
cvoxAce.Annotation; |
var CONSTANT_PROP = { |
'rate': 0.8, |
'pitch': 0.4, |
'volume': 0.9 |
}; |
var DEFAULT_PROP = { |
'rate': 1, |
'pitch': 0.5, |
'volume': 0.9 |
}; |
var ENTITY_PROP = { |
'rate': 0.8, |
'pitch': 0.8, |
'volume': 0.9 |
}; |
var KEYWORD_PROP = { |
'rate': 0.8, |
'pitch': 0.3, |
'volume': 0.9 |
}; |
var STORAGE_PROP = { |
'rate': 0.8, |
'pitch': 0.7, |
'volume': 0.9 |
}; |
var VARIABLE_PROP = { |
'rate': 0.8, |
'pitch': 0.8, |
'volume': 0.9 |
}; |
var DELETED_PROP = { |
'punctuationEcho': 'none', |
'relativePitch': -0.6 |
}; |
var ERROR_EARCON = 'ALERT_NONMODAL'; |
var MODE_SWITCH_EARCON = 'ALERT_MODAL'; |
var NO_MATCH_EARCON = 'INVALID_KEYPRESS'; |
var INSERT_MODE_STATE = 'insertMode'; |
var COMMAND_MODE_STATE = 'start'; |
|
var REPLACE_LIST = [ |
{ |
substr: ';', |
newSubstr: ' semicolon ' |
}, |
{ |
substr: ':', |
newSubstr: ' colon ' |
} |
]; |
var Command = { |
SPEAK_ANNOT: 'annots', |
SPEAK_ALL_ANNOTS: 'all_annots', |
TOGGLE_LOCATION: 'toggle_location', |
SPEAK_MODE: 'mode', |
SPEAK_ROW_COL: 'row_col', |
TOGGLE_DISPLACEMENT: 'toggle_displacement', |
FOCUS_TEXT: 'focus_text' |
}; |
var KEY_PREFIX = 'CONTROL + SHIFT '; |
cvoxAce.editor = null; |
var lastCursor = null; |
var annotTable = {}; |
var shouldSpeakRowLocation = false; |
var shouldSpeakDisplacement = false; |
var changed = false; |
var vimState = null; |
var keyCodeToShortcutMap = {}; |
var cmdToShortcutMap = {}; |
var getKeyShortcutString = function(keyCode) { |
return KEY_PREFIX + String.fromCharCode(keyCode); |
}; |
var isVimMode = function() { |
var keyboardHandler = cvoxAce.editor.keyBinding.getKeyboardHandler(); |
return keyboardHandler.$id === 'ace/keyboard/vim'; |
}; |
var getCurrentToken = function(cursor) { |
return cvoxAce.editor.getSession().getTokenAt(cursor.row, cursor.column + 1); |
}; |
var getCurrentLine = function(cursor) { |
return cvoxAce.editor.getSession().getLine(cursor.row); |
}; |
var onRowChange = function(currCursor) { |
if (annotTable[currCursor.row]) { |
cvox.Api.playEarcon(ERROR_EARCON); |
} |
if (shouldSpeakRowLocation) { |
cvox.Api.stop(); |
speakChar(currCursor); |
speakTokenQueue(getCurrentToken(currCursor)); |
speakLine(currCursor.row, 1); |
} else { |
speakLine(currCursor.row, 0); |
} |
}; |
var isWord = function(cursor) { |
var line = getCurrentLine(cursor); |
var lineSuffix = line.substr(cursor.column - 1); |
if (cursor.column === 0) { |
lineSuffix = ' ' + line; |
} |
var firstWordRegExp = /^\W(\w+)/; |
var words = firstWordRegExp.exec(lineSuffix); |
return words !== null; |
}; |
var rules = { |
'constant': { |
prop: CONSTANT_PROP |
}, |
'entity': { |
prop: ENTITY_PROP |
}, |
'keyword': { |
prop: KEYWORD_PROP |
}, |
'storage': { |
prop: STORAGE_PROP |
}, |
'variable': { |
prop: VARIABLE_PROP |
}, |
'meta': { |
prop: DEFAULT_PROP, |
replace: [ |
{ |
substr: '</', |
newSubstr: ' closing tag ' |
}, |
{ |
substr: '/>', |
newSubstr: ' close tag ' |
}, |
{ |
substr: '<', |
newSubstr: ' tag start ' |
}, |
{ |
substr: '>', |
newSubstr: ' tag end ' |
} |
] |
} |
}; |
var DEFAULT_RULE = { |
prop: DEFAULT_RULE |
}; |
var expand = function(value, replaceRules) { |
var newValue = value; |
for (var i = 0; i < replaceRules.length; i++) { |
var replaceRule = replaceRules[i]; |
var regexp = new RegExp(replaceRule.substr, 'g'); |
newValue = newValue.replace(regexp, replaceRule.newSubstr); |
} |
return newValue; |
}; |
var mergeTokens = function(tokens, start, end) { |
var newToken = {}; |
newToken.value = ''; |
newToken.type = tokens[start].type; |
for (var j = start; j < end; j++) { |
newToken.value += tokens[j].value; |
} |
return newToken; |
}; |
var mergeLikeTokens = function(tokens) { |
if (tokens.length <= 1) { |
return tokens; |
} |
var newTokens = []; |
var lastLikeIndex = 0; |
for (var i = 1; i < tokens.length; i++) { |
var lastLikeToken = tokens[lastLikeIndex]; |
var currToken = tokens[i]; |
if (getTokenRule(lastLikeToken) !== getTokenRule(currToken)) { |
newTokens.push(mergeTokens(tokens, lastLikeIndex, i)); |
lastLikeIndex = i; |
} |
} |
newTokens.push(mergeTokens(tokens, lastLikeIndex, tokens.length)); |
return newTokens; |
}; |
var isRowWhiteSpace = function(row) { |
var line = cvoxAce.editor.getSession().getLine(row); |
var whiteSpaceRegexp = /^\s*$/; |
return whiteSpaceRegexp.exec(line) !== null; |
}; |
var speakLine = function(row, queue) { |
var tokens = cvoxAce.editor.getSession().getTokens(row); |
if (tokens.length === 0 || isRowWhiteSpace(row)) { |
cvox.Api.playEarcon('EDITABLE_TEXT'); |
return; |
} |
tokens = mergeLikeTokens(tokens); |
var firstToken = tokens[0]; |
tokens = tokens.filter(function(token) { |
return token !== firstToken; |
}); |
speakToken_(firstToken, queue); |
tokens.forEach(speakTokenQueue); |
}; |
var speakTokenFlush = function(token) { |
speakToken_(token, 0); |
}; |
var speakTokenQueue = function(token) { |
speakToken_(token, 1); |
}; |
var getTokenRule = function(token) { |
if (!token || !token.type) { |
return; |
} |
var split = token.type.split('.'); |
if (split.length === 0) { |
return; |
} |
var type = split[0]; |
var rule = rules[type]; |
if (!rule) { |
return DEFAULT_RULE; |
} |
return rule; |
}; |
var speakToken_ = function(token, queue) { |
var rule = getTokenRule(token); |
var value = expand(token.value, REPLACE_LIST); |
if (rule.replace) { |
value = expand(value, rule.replace); |
} |
cvox.Api.speak(value, queue, rule.prop); |
}; |
var speakChar = function(cursor) { |
var line = getCurrentLine(cursor); |
cvox.Api.speak(line[cursor.column], 1); |
}; |
var speakDisplacement = function(lastCursor, currCursor) { |
var line = getCurrentLine(currCursor); |
var displace = line.substring(lastCursor.column, currCursor.column); |
displace = displace.replace(/ /g, ' space '); |
cvox.Api.speak(displace); |
}; |
var speakCharOrWordOrLine = function(lastCursor, currCursor) { |
if (Math.abs(lastCursor.column - currCursor.column) !== 1) { |
var currLineLength = getCurrentLine(currCursor).length; |
if (currCursor.column === 0 || currCursor.column === currLineLength) { |
speakLine(currCursor.row, 0); |
return; |
} |
if (isWord(currCursor)) { |
cvox.Api.stop(); |
speakTokenQueue(getCurrentToken(currCursor)); |
return; |
} |
} |
speakChar(currCursor); |
}; |
var onColumnChange = function(lastCursor, currCursor) { |
if (!cvoxAce.editor.selection.isEmpty()) { |
speakDisplacement(lastCursor, currCursor); |
cvox.Api.speak('selected', 1); |
} |
else if (shouldSpeakDisplacement) { |
speakDisplacement(lastCursor, currCursor); |
} else { |
speakCharOrWordOrLine(lastCursor, currCursor); |
} |
}; |
var onCursorChange = function(evt) { |
if (changed) { |
changed = false; |
return; |
} |
var currCursor = cvoxAce.editor.selection.getCursor(); |
if (currCursor.row !== lastCursor.row) { |
onRowChange(currCursor); |
} else { |
onColumnChange(lastCursor, currCursor); |
} |
lastCursor = currCursor; |
}; |
var onSelectionChange = function(evt) { |
if (cvoxAce.editor.selection.isEmpty()) { |
cvox.Api.speak('unselected'); |
} |
}; |
var onChange = function(delta) { |
switch (delta.action) { |
case 'remove': |
cvox.Api.speak(delta.text, 0, DELETED_PROP); |
changed = true; |
break; |
case 'insert': |
cvox.Api.speak(delta.text, 0); |
changed = true; |
break; |
} |
}; |
var isNewAnnotation = function(annot) { |
var row = annot.row; |
var col = annot.column; |
return !annotTable[row] || !annotTable[row][col]; |
}; |
var populateAnnotations = function(annotations) { |
annotTable = {}; |
for (var i = 0; i < annotations.length; i++) { |
var annotation = annotations[i]; |
var row = annotation.row; |
var col = annotation.column; |
if (!annotTable[row]) { |
annotTable[row] = {}; |
} |
annotTable[row][col] = annotation; |
} |
}; |
var onAnnotationChange = function(evt) { |
var annotations = cvoxAce.editor.getSession().getAnnotations(); |
var newAnnotations = annotations.filter(isNewAnnotation); |
if (newAnnotations.length > 0) { |
cvox.Api.playEarcon(ERROR_EARCON); |
} |
populateAnnotations(annotations); |
}; |
var speakAnnot = function(annot) { |
var annotText = annot.type + ' ' + annot.text + ' on ' + |
rowColToString(annot.row, annot.column); |
annotText = annotText.replace(';', 'semicolon'); |
cvox.Api.speak(annotText, 1); |
}; |
var speakAnnotsByRow = function(row) { |
var annots = annotTable[row]; |
for (var col in annots) { |
speakAnnot(annots[col]); |
} |
}; |
var rowColToString = function(row, col) { |
return 'row ' + (row + 1) + ' column ' + (col + 1); |
}; |
var speakCurrRowAndCol = function() { |
cvox.Api.speak(rowColToString(lastCursor.row, lastCursor.column)); |
}; |
var speakAllAnnots = function() { |
for (var row in annotTable) { |
speakAnnotsByRow(row); |
} |
}; |
var speakMode = function() { |
if (!isVimMode()) { |
return; |
} |
switch (cvoxAce.editor.keyBinding.$data.state) { |
case INSERT_MODE_STATE: |
cvox.Api.speak('Insert mode'); |
break; |
case COMMAND_MODE_STATE: |
cvox.Api.speak('Command mode'); |
break; |
} |
}; |
var toggleSpeakRowLocation = function() { |
shouldSpeakRowLocation = !shouldSpeakRowLocation; |
if (shouldSpeakRowLocation) { |
cvox.Api.speak('Speak location on row change enabled.'); |
} else { |
cvox.Api.speak('Speak location on row change disabled.'); |
} |
}; |
var toggleSpeakDisplacement = function() { |
shouldSpeakDisplacement = !shouldSpeakDisplacement; |
if (shouldSpeakDisplacement) { |
cvox.Api.speak('Speak displacement on column changes.'); |
} else { |
cvox.Api.speak('Speak current character or word on column changes.'); |
} |
}; |
var onKeyDown = function(evt) { |
if (evt.ctrlKey && evt.shiftKey) { |
var shortcut = keyCodeToShortcutMap[evt.keyCode]; |
if (shortcut) { |
shortcut.func(); |
} |
} |
}; |
var onChangeStatus = function(evt, editor) { |
if (!isVimMode()) { |
return; |
} |
var state = editor.keyBinding.$data.state; |
if (state === vimState) { |
return; |
} |
switch (state) { |
case INSERT_MODE_STATE: |
cvox.Api.playEarcon(MODE_SWITCH_EARCON); |
cvox.Api.setKeyEcho(true); |
break; |
case COMMAND_MODE_STATE: |
cvox.Api.playEarcon(MODE_SWITCH_EARCON); |
cvox.Api.setKeyEcho(false); |
break; |
} |
vimState = state; |
}; |
var contextMenuHandler = function(evt) { |
var cmd = evt.detail['customCommand']; |
var shortcut = cmdToShortcutMap[cmd]; |
if (shortcut) { |
shortcut.func(); |
cvoxAce.editor.focus(); |
} |
}; |
var initContextMenu = function() { |
var ACTIONS = SHORTCUTS.map(function(shortcut) { |
return { |
desc: shortcut.desc + getKeyShortcutString(shortcut.keyCode), |
cmd: shortcut.cmd |
}; |
}); |
var body = document.querySelector('body'); |
body.setAttribute('contextMenuActions', JSON.stringify(ACTIONS)); |
body.addEventListener('ATCustomEvent', contextMenuHandler, true); |
}; |
var onFindSearchbox = function(evt) { |
if (evt.match) { |
speakLine(lastCursor.row, 0); |
} else { |
cvox.Api.playEarcon(NO_MATCH_EARCON); |
} |
}; |
var focus = function() { |
cvoxAce.editor.focus(); |
}; |
var SHORTCUTS = [ |
{ |
keyCode: 49, |
func: function() { |
speakAnnotsByRow(lastCursor.row); |
}, |
cmd: Command.SPEAK_ANNOT, |
desc: 'Speak annotations on line' |
}, |
{ |
keyCode: 50, |
func: speakAllAnnots, |
cmd: Command.SPEAK_ALL_ANNOTS, |
desc: 'Speak all annotations' |
}, |
{ |
keyCode: 51, |
func: speakMode, |
cmd: Command.SPEAK_MODE, |
desc: 'Speak Vim mode' |
}, |
{ |
keyCode: 52, |
func: toggleSpeakRowLocation, |
cmd: Command.TOGGLE_LOCATION, |
desc: 'Toggle speak row location' |
}, |
{ |
keyCode: 53, |
func: speakCurrRowAndCol, |
cmd: Command.SPEAK_ROW_COL, |
desc: 'Speak row and column' |
}, |
{ |
keyCode: 54, |
func: toggleSpeakDisplacement, |
cmd: Command.TOGGLE_DISPLACEMENT, |
desc: 'Toggle speak displacement' |
}, |
{ |
keyCode: 55, |
func: focus, |
cmd: Command.FOCUS_TEXT, |
desc: 'Focus text' |
} |
]; |
var onFocus = function(_, editor) { |
cvoxAce.editor = editor; |
editor.getSession().selection.on('changeCursor', onCursorChange); |
editor.getSession().selection.on('changeSelection', onSelectionChange); |
editor.getSession().on('change', onChange); |
editor.getSession().on('changeAnnotation', onAnnotationChange); |
editor.on('changeStatus', onChangeStatus); |
editor.on('findSearchBox', onFindSearchbox); |
editor.container.addEventListener('keydown', onKeyDown); |
|
lastCursor = editor.selection.getCursor(); |
}; |
var init = function(editor) { |
onFocus(null, editor); |
SHORTCUTS.forEach(function(shortcut) { |
keyCodeToShortcutMap[shortcut.keyCode] = shortcut; |
cmdToShortcutMap[shortcut.cmd] = shortcut; |
}); |
|
editor.on('focus', onFocus); |
if (isVimMode()) { |
cvox.Api.setKeyEcho(false); |
} |
initContextMenu(); |
}; |
function cvoxApiExists() { |
return (typeof(cvox) !== 'undefined') && cvox && cvox.Api; |
} |
var tries = 0; |
var MAX_TRIES = 15; |
function watchForCvoxLoad(editor) { |
if (cvoxApiExists()) { |
init(editor); |
} else { |
tries++; |
if (tries >= MAX_TRIES) { |
return; |
} |
window.setTimeout(watchForCvoxLoad, 500, editor); |
} |
} |
|
var Editor = require('../editor').Editor; |
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 |
} |
}); |
|
}); |
(function() { |
ace.require(["ace/ext/chromevox"], function() {}); |
})(); |
|