stackprofiler 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/README.md +1 -1
  4. data/config.ru +3 -2
  5. data/lib/stackprofiler.rb +0 -1
  6. data/lib/stackprofiler/filters/build_tree.rb +3 -4
  7. data/lib/stackprofiler/filters/gem_removal.rb +3 -0
  8. data/lib/stackprofiler/web_ui.rb +34 -11
  9. data/lib/stackprofiler/web_ui/public/css/stackprofiler.css +77 -0
  10. data/lib/stackprofiler/web_ui/public/js/stackprofiler.js +129 -58
  11. data/lib/stackprofiler/web_ui/public/vendor/ace/ace.js +18298 -0
  12. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-beautify.js +334 -0
  13. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-chromevox.js +541 -0
  14. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-elastic_tabstops_lite.js +275 -0
  15. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-emmet.js +1190 -0
  16. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-error_marker.js +6 -0
  17. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-keybinding_menu.js +170 -0
  18. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-language_tools.js +1934 -0
  19. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-linking.js +52 -0
  20. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-modelist.js +187 -0
  21. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-old_ie.js +494 -0
  22. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-searchbox.js +409 -0
  23. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-settings_menu.js +637 -0
  24. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-spellcheck.js +71 -0
  25. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-split.js +246 -0
  26. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-static_highlight.js +154 -0
  27. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-statusbar.js +51 -0
  28. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-textarea.js +632 -0
  29. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-themelist.js +58 -0
  30. data/lib/stackprofiler/web_ui/public/vendor/ace/ext-whitespace.js +181 -0
  31. data/lib/stackprofiler/web_ui/public/vendor/ace/keybinding-emacs.js +1182 -0
  32. data/lib/stackprofiler/web_ui/public/vendor/ace/keybinding-vim.js +5320 -0
  33. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-haml.js +525 -0
  34. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-html.js +2427 -0
  35. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-html_ruby.js +2955 -0
  36. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-javascript.js +1025 -0
  37. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-json.js +668 -0
  38. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-ruby.js +839 -0
  39. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-xml.js +637 -0
  40. data/lib/stackprofiler/web_ui/public/vendor/ace/mode-yaml.js +256 -0
  41. data/lib/stackprofiler/web_ui/public/vendor/ace/theme-xcode.js +89 -0
  42. data/lib/stackprofiler/web_ui/public/vendor/ace/worker-coffee.js +7599 -0
  43. data/lib/stackprofiler/web_ui/public/vendor/ace/worker-css.js +8682 -0
  44. data/lib/stackprofiler/web_ui/public/vendor/ace/worker-html.js +11527 -0
  45. data/lib/stackprofiler/web_ui/public/vendor/ace/worker-javascript.js +10429 -0
  46. data/lib/stackprofiler/web_ui/public/vendor/ace/worker-json.js +2319 -0
  47. data/lib/stackprofiler/web_ui/views/index.erb +1 -1
  48. data/lib/stackprofiler/web_ui/views/layout.erb +2 -55
  49. data/stackprofiler.gemspec +2 -4
  50. metadata +42 -19
  51. data/lib/stackprofiler/web_ui/views/code.erb +0 -17
@@ -0,0 +1,334 @@
1
+ ace.define("ace/ext/beautify/php_rules",["require","exports","module","ace/token_iterator"], function(require, exports, module) {
2
+ "use strict";
3
+ var TokenIterator = require("ace/token_iterator").TokenIterator;
4
+ exports.newLines = [{
5
+ type: 'support.php_tag',
6
+ value: '<?php'
7
+ }, {
8
+ type: 'support.php_tag',
9
+ value: '<?'
10
+ }, {
11
+ type: 'support.php_tag',
12
+ value: '?>'
13
+ }, {
14
+ type: 'paren.lparen',
15
+ value: '{',
16
+ indent: true
17
+ }, {
18
+ type: 'paren.rparen',
19
+ breakBefore: true,
20
+ value: '}',
21
+ indent: false
22
+ }, {
23
+ type: 'paren.rparen',
24
+ breakBefore: true,
25
+ value: '})',
26
+ indent: false,
27
+ dontBreak: true
28
+ }, {
29
+ type: 'comment'
30
+ }, {
31
+ type: 'text',
32
+ value: ';'
33
+ }, {
34
+ type: 'text',
35
+ value: ':',
36
+ context: 'php'
37
+ }, {
38
+ type: 'keyword',
39
+ value: 'case',
40
+ indent: true,
41
+ dontBreak: true
42
+ }, {
43
+ type: 'keyword',
44
+ value: 'default',
45
+ indent: true,
46
+ dontBreak: true
47
+ }, {
48
+ type: 'keyword',
49
+ value: 'break',
50
+ indent: false,
51
+ dontBreak: true
52
+ }, {
53
+ type: 'punctuation.doctype.end',
54
+ value: '>'
55
+ }, {
56
+ type: 'meta.tag.punctuation.end',
57
+ value: '>'
58
+ }, {
59
+ type: 'meta.tag.punctuation.begin',
60
+ value: '<',
61
+ blockTag: true,
62
+ indent: true,
63
+ dontBreak: true
64
+ }, {
65
+ type: 'meta.tag.punctuation.begin',
66
+ value: '</',
67
+ indent: false,
68
+ breakBefore: true,
69
+ dontBreak: true
70
+ }, {
71
+ type: 'punctuation.operator',
72
+ value: ';'
73
+ }];
74
+
75
+ exports.spaces = [{
76
+ type: 'xml-pe',
77
+ prepend: true
78
+ },{
79
+ type: 'entity.other.attribute-name',
80
+ prepend: true
81
+ }, {
82
+ type: 'storage.type',
83
+ value: 'var',
84
+ append: true
85
+ }, {
86
+ type: 'storage.type',
87
+ value: 'function',
88
+ append: true
89
+ }, {
90
+ type: 'keyword.operator',
91
+ value: '='
92
+ }, {
93
+ type: 'keyword',
94
+ value: 'as',
95
+ prepend: true,
96
+ append: true
97
+ }, {
98
+ type: 'keyword',
99
+ value: 'function',
100
+ append: true
101
+ }, {
102
+ type: 'support.function',
103
+ next: /[^\(]/,
104
+ append: true
105
+ }, {
106
+ type: 'keyword',
107
+ value: 'or',
108
+ append: true,
109
+ prepend: true
110
+ }, {
111
+ type: 'keyword',
112
+ value: 'and',
113
+ append: true,
114
+ prepend: true
115
+ }, {
116
+ type: 'keyword',
117
+ value: 'case',
118
+ append: true
119
+ }, {
120
+ type: 'keyword.operator',
121
+ value: '||',
122
+ append: true,
123
+ prepend: true
124
+ }, {
125
+ type: 'keyword.operator',
126
+ value: '&&',
127
+ append: true,
128
+ prepend: true
129
+ }];
130
+ exports.singleTags = ['!doctype','area','base','br','hr','input','img','link','meta'];
131
+
132
+ exports.transform = function(iterator, maxPos, context) {
133
+ var token = iterator.getCurrentToken();
134
+
135
+ var newLines = exports.newLines;
136
+ var spaces = exports.spaces;
137
+ var singleTags = exports.singleTags;
138
+
139
+ var code = '';
140
+
141
+ var indentation = 0;
142
+ var dontBreak = false;
143
+ var tag;
144
+ var lastTag;
145
+ var lastToken = {};
146
+ var nextTag;
147
+ var nextToken = {};
148
+ var breakAdded = false;
149
+ var value = '';
150
+
151
+ while (token!==null) {
152
+ console.log(token);
153
+
154
+ if( !token ){
155
+ token = iterator.stepForward();
156
+ continue;
157
+ }
158
+ if( token.type == 'support.php_tag' && token.value != '?>' ){
159
+ context = 'php';
160
+ }
161
+ else if( token.type == 'support.php_tag' && token.value == '?>' ){
162
+ context = 'html';
163
+ }
164
+ else if( token.type == 'meta.tag.name.style' && context != 'css' ){
165
+ context = 'css';
166
+ }
167
+ else if( token.type == 'meta.tag.name.style' && context == 'css' ){
168
+ context = 'html';
169
+ }
170
+ else if( token.type == 'meta.tag.name.script' && context != 'js' ){
171
+ context = 'js';
172
+ }
173
+ else if( token.type == 'meta.tag.name.script' && context == 'js' ){
174
+ context = 'html';
175
+ }
176
+
177
+ nextToken = iterator.stepForward();
178
+ if (nextToken && nextToken.type.indexOf('meta.tag.name') == 0) {
179
+ nextTag = nextToken.value;
180
+ }
181
+ if ( lastToken.type == 'support.php_tag' && lastToken.value == '<?=') {
182
+ dontBreak = true;
183
+ }
184
+ if (token.type == 'meta.tag.name') {
185
+ token.value = token.value.toLowerCase();
186
+ }
187
+ if (token.type == 'text') {
188
+ token.value = token.value.trim();
189
+ }
190
+ if (!token.value) {
191
+ token = nextToken;
192
+ continue;
193
+ }
194
+ value = token.value;
195
+ for (var i in spaces) {
196
+ if (
197
+ token.type == spaces[i].type &&
198
+ (!spaces[i].value || token.value == spaces[i].value) &&
199
+ (
200
+ nextToken &&
201
+ (!spaces[i].next || spaces[i].next.test(nextToken.value))
202
+ )
203
+ ) {
204
+ if (spaces[i].prepend) {
205
+ value = ' ' + token.value;
206
+ }
207
+
208
+ if (spaces[i].append) {
209
+ value += ' ';
210
+ }
211
+ }
212
+ }
213
+ if (token.type.indexOf('meta.tag.name') == 0) {
214
+ tag = token.value;
215
+ }
216
+ breakAdded = false;
217
+ for (i in newLines) {
218
+ if (
219
+ token.type == newLines[i].type &&
220
+ (
221
+ !newLines[i].value ||
222
+ token.value == newLines[i].value
223
+ ) &&
224
+ (
225
+ !newLines[i].blockTag ||
226
+ singleTags.indexOf(nextTag) === -1
227
+ ) &&
228
+ (
229
+ !newLines[i].context ||
230
+ newLines[i].context === context
231
+ )
232
+ ) {
233
+ if (newLines[i].indent === false) {
234
+ indentation--;
235
+ }
236
+
237
+ if (
238
+ newLines[i].breakBefore &&
239
+ ( !newLines[i].prev || newLines[i].prev.test(lastToken.value) )
240
+ ) {
241
+ code += "\n";
242
+ breakAdded = true;
243
+ for (i = 0; i < indentation; i++) {
244
+ code += "\t";
245
+ }
246
+ }
247
+
248
+ break;
249
+ }
250
+ }
251
+
252
+ if (dontBreak===false) {
253
+ for (i in newLines) {
254
+ if (
255
+ lastToken.type == newLines[i].type &&
256
+ (
257
+ !newLines[i].value || lastToken.value == newLines[i].value
258
+ ) &&
259
+ (
260
+ !newLines[i].blockTag ||
261
+ singleTags.indexOf(tag) === -1
262
+ ) &&
263
+ (
264
+ !newLines[i].context ||
265
+ newLines[i].context === context
266
+ )
267
+ ) {
268
+ if (newLines[i].indent === true) {
269
+ indentation++;
270
+ }
271
+
272
+ if (!newLines[i].dontBreak && !breakAdded) {
273
+ code += "\n";
274
+ for (i = 0; i < indentation; i++) {
275
+ code += "\t";
276
+ }
277
+ }
278
+
279
+ break;
280
+ }
281
+ }
282
+ }
283
+
284
+ code += value;
285
+ if ( lastToken.type == 'support.php_tag' && lastToken.value == '?>' ) {
286
+ dontBreak = false;
287
+ }
288
+ lastTag = tag;
289
+
290
+ lastToken = token;
291
+
292
+ token = nextToken;
293
+
294
+ if (token===null) {
295
+ break;
296
+ }
297
+ }
298
+
299
+ return code;
300
+ };
301
+
302
+
303
+
304
+ });
305
+
306
+ ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator","ace/ext/beautify/php_rules"], function(require, exports, module) {
307
+ "use strict";
308
+ var TokenIterator = require("ace/token_iterator").TokenIterator;
309
+
310
+ var phpTransform = require("./beautify/php_rules").transform;
311
+
312
+ exports.beautify = function(session) {
313
+ var iterator = new TokenIterator(session, 0, 0);
314
+ var token = iterator.getCurrentToken();
315
+
316
+ var context = session.$modeId.split("/").pop();
317
+
318
+ var code = phpTransform(iterator, context);
319
+ session.doc.setValue(code);
320
+ };
321
+
322
+ exports.commands = [{
323
+ name: "beautify",
324
+ exec: function(editor) {
325
+ exports.beautify(editor.session);
326
+ },
327
+ bindKey: "Ctrl-Shift-B"
328
+ }]
329
+
330
+ });
331
+ (function() {
332
+ ace.require(["ace/ext/beautify"], function() {});
333
+ })();
334
+
@@ -0,0 +1,541 @@
1
+ ace.define("ace/ext/chromevox",["require","exports","module","ace/editor","ace/config"], function(require, exports, module) {
2
+ var cvoxAce = {};
3
+ cvoxAce.SpeechProperty;
4
+ cvoxAce.Cursor;
5
+ cvoxAce.Token;
6
+ cvoxAce.Annotation;
7
+ var CONSTANT_PROP = {
8
+ 'rate': 0.8,
9
+ 'pitch': 0.4,
10
+ 'volume': 0.9
11
+ };
12
+ var DEFAULT_PROP = {
13
+ 'rate': 1,
14
+ 'pitch': 0.5,
15
+ 'volume': 0.9
16
+ };
17
+ var ENTITY_PROP = {
18
+ 'rate': 0.8,
19
+ 'pitch': 0.8,
20
+ 'volume': 0.9
21
+ };
22
+ var KEYWORD_PROP = {
23
+ 'rate': 0.8,
24
+ 'pitch': 0.3,
25
+ 'volume': 0.9
26
+ };
27
+ var STORAGE_PROP = {
28
+ 'rate': 0.8,
29
+ 'pitch': 0.7,
30
+ 'volume': 0.9
31
+ };
32
+ var VARIABLE_PROP = {
33
+ 'rate': 0.8,
34
+ 'pitch': 0.8,
35
+ 'volume': 0.9
36
+ };
37
+ var DELETED_PROP = {
38
+ 'punctuationEcho': 'none',
39
+ 'relativePitch': -0.6
40
+ };
41
+ var ERROR_EARCON = 'ALERT_NONMODAL';
42
+ var MODE_SWITCH_EARCON = 'ALERT_MODAL';
43
+ var NO_MATCH_EARCON = 'INVALID_KEYPRESS';
44
+ var INSERT_MODE_STATE = 'insertMode';
45
+ var COMMAND_MODE_STATE = 'start';
46
+
47
+ var REPLACE_LIST = [
48
+ {
49
+ substr: ';',
50
+ newSubstr: ' semicolon '
51
+ },
52
+ {
53
+ substr: ':',
54
+ newSubstr: ' colon '
55
+ }
56
+ ];
57
+ var Command = {
58
+ SPEAK_ANNOT: 'annots',
59
+ SPEAK_ALL_ANNOTS: 'all_annots',
60
+ TOGGLE_LOCATION: 'toggle_location',
61
+ SPEAK_MODE: 'mode',
62
+ SPEAK_ROW_COL: 'row_col',
63
+ TOGGLE_DISPLACEMENT: 'toggle_displacement',
64
+ FOCUS_TEXT: 'focus_text'
65
+ };
66
+ var KEY_PREFIX = 'CONTROL + SHIFT ';
67
+ cvoxAce.editor = null;
68
+ var lastCursor = null;
69
+ var annotTable = {};
70
+ var shouldSpeakRowLocation = false;
71
+ var shouldSpeakDisplacement = false;
72
+ var changed = false;
73
+ var vimState = null;
74
+ var keyCodeToShortcutMap = {};
75
+ var cmdToShortcutMap = {};
76
+ var getKeyShortcutString = function(keyCode) {
77
+ return KEY_PREFIX + String.fromCharCode(keyCode);
78
+ };
79
+ var isVimMode = function() {
80
+ var keyboardHandler = cvoxAce.editor.keyBinding.getKeyboardHandler();
81
+ return keyboardHandler.$id === 'ace/keyboard/vim';
82
+ };
83
+ var getCurrentToken = function(cursor) {
84
+ return cvoxAce.editor.getSession().getTokenAt(cursor.row, cursor.column + 1);
85
+ };
86
+ var getCurrentLine = function(cursor) {
87
+ return cvoxAce.editor.getSession().getLine(cursor.row);
88
+ };
89
+ var onRowChange = function(currCursor) {
90
+ if (annotTable[currCursor.row]) {
91
+ cvox.Api.playEarcon(ERROR_EARCON);
92
+ }
93
+ if (shouldSpeakRowLocation) {
94
+ cvox.Api.stop();
95
+ speakChar(currCursor);
96
+ speakTokenQueue(getCurrentToken(currCursor));
97
+ speakLine(currCursor.row, 1);
98
+ } else {
99
+ speakLine(currCursor.row, 0);
100
+ }
101
+ };
102
+ var isWord = function(cursor) {
103
+ var line = getCurrentLine(cursor);
104
+ var lineSuffix = line.substr(cursor.column - 1);
105
+ if (cursor.column === 0) {
106
+ lineSuffix = ' ' + line;
107
+ }
108
+ var firstWordRegExp = /^\W(\w+)/;
109
+ var words = firstWordRegExp.exec(lineSuffix);
110
+ return words !== null;
111
+ };
112
+ var rules = {
113
+ 'constant': {
114
+ prop: CONSTANT_PROP
115
+ },
116
+ 'entity': {
117
+ prop: ENTITY_PROP
118
+ },
119
+ 'keyword': {
120
+ prop: KEYWORD_PROP
121
+ },
122
+ 'storage': {
123
+ prop: STORAGE_PROP
124
+ },
125
+ 'variable': {
126
+ prop: VARIABLE_PROP
127
+ },
128
+ 'meta': {
129
+ prop: DEFAULT_PROP,
130
+ replace: [
131
+ {
132
+ substr: '</',
133
+ newSubstr: ' closing tag '
134
+ },
135
+ {
136
+ substr: '/>',
137
+ newSubstr: ' close tag '
138
+ },
139
+ {
140
+ substr: '<',
141
+ newSubstr: ' tag start '
142
+ },
143
+ {
144
+ substr: '>',
145
+ newSubstr: ' tag end '
146
+ }
147
+ ]
148
+ }
149
+ };
150
+ var DEFAULT_RULE = {
151
+ prop: DEFAULT_RULE
152
+ };
153
+ var expand = function(value, replaceRules) {
154
+ var newValue = value;
155
+ for (var i = 0; i < replaceRules.length; i++) {
156
+ var replaceRule = replaceRules[i];
157
+ var regexp = new RegExp(replaceRule.substr, 'g');
158
+ newValue = newValue.replace(regexp, replaceRule.newSubstr);
159
+ }
160
+ return newValue;
161
+ };
162
+ var mergeTokens = function(tokens, start, end) {
163
+ var newToken = {};
164
+ newToken.value = '';
165
+ newToken.type = tokens[start].type;
166
+ for (var j = start; j < end; j++) {
167
+ newToken.value += tokens[j].value;
168
+ }
169
+ return newToken;
170
+ };
171
+ var mergeLikeTokens = function(tokens) {
172
+ if (tokens.length <= 1) {
173
+ return tokens;
174
+ }
175
+ var newTokens = [];
176
+ var lastLikeIndex = 0;
177
+ for (var i = 1; i < tokens.length; i++) {
178
+ var lastLikeToken = tokens[lastLikeIndex];
179
+ var currToken = tokens[i];
180
+ if (getTokenRule(lastLikeToken) !== getTokenRule(currToken)) {
181
+ newTokens.push(mergeTokens(tokens, lastLikeIndex, i));
182
+ lastLikeIndex = i;
183
+ }
184
+ }
185
+ newTokens.push(mergeTokens(tokens, lastLikeIndex, tokens.length));
186
+ return newTokens;
187
+ };
188
+ var isRowWhiteSpace = function(row) {
189
+ var line = cvoxAce.editor.getSession().getLine(row);
190
+ var whiteSpaceRegexp = /^\s*$/;
191
+ return whiteSpaceRegexp.exec(line) !== null;
192
+ };
193
+ var speakLine = function(row, queue) {
194
+ var tokens = cvoxAce.editor.getSession().getTokens(row);
195
+ if (tokens.length === 0 || isRowWhiteSpace(row)) {
196
+ cvox.Api.playEarcon('EDITABLE_TEXT');
197
+ return;
198
+ }
199
+ tokens = mergeLikeTokens(tokens);
200
+ var firstToken = tokens[0];
201
+ tokens = tokens.filter(function(token) {
202
+ return token !== firstToken;
203
+ });
204
+ speakToken_(firstToken, queue);
205
+ tokens.forEach(speakTokenQueue);
206
+ };
207
+ var speakTokenFlush = function(token) {
208
+ speakToken_(token, 0);
209
+ };
210
+ var speakTokenQueue = function(token) {
211
+ speakToken_(token, 1);
212
+ };
213
+ var getTokenRule = function(token) {
214
+ if (!token || !token.type) {
215
+ return;
216
+ }
217
+ var split = token.type.split('.');
218
+ if (split.length === 0) {
219
+ return;
220
+ }
221
+ var type = split[0];
222
+ var rule = rules[type];
223
+ if (!rule) {
224
+ return DEFAULT_RULE;
225
+ }
226
+ return rule;
227
+ };
228
+ var speakToken_ = function(token, queue) {
229
+ var rule = getTokenRule(token);
230
+ var value = expand(token.value, REPLACE_LIST);
231
+ if (rule.replace) {
232
+ value = expand(value, rule.replace);
233
+ }
234
+ cvox.Api.speak(value, queue, rule.prop);
235
+ };
236
+ var speakChar = function(cursor) {
237
+ var line = getCurrentLine(cursor);
238
+ cvox.Api.speak(line[cursor.column], 1);
239
+ };
240
+ var speakDisplacement = function(lastCursor, currCursor) {
241
+ var line = getCurrentLine(currCursor);
242
+ var displace = line.substring(lastCursor.column, currCursor.column);
243
+ displace = displace.replace(/ /g, ' space ');
244
+ cvox.Api.speak(displace);
245
+ };
246
+ var speakCharOrWordOrLine = function(lastCursor, currCursor) {
247
+ if (Math.abs(lastCursor.column - currCursor.column) !== 1) {
248
+ var currLineLength = getCurrentLine(currCursor).length;
249
+ if (currCursor.column === 0 || currCursor.column === currLineLength) {
250
+ speakLine(currCursor.row, 0);
251
+ return;
252
+ }
253
+ if (isWord(currCursor)) {
254
+ cvox.Api.stop();
255
+ speakTokenQueue(getCurrentToken(currCursor));
256
+ return;
257
+ }
258
+ }
259
+ speakChar(currCursor);
260
+ };
261
+ var onColumnChange = function(lastCursor, currCursor) {
262
+ if (!cvoxAce.editor.selection.isEmpty()) {
263
+ speakDisplacement(lastCursor, currCursor);
264
+ cvox.Api.speak('selected', 1);
265
+ }
266
+ else if (shouldSpeakDisplacement) {
267
+ speakDisplacement(lastCursor, currCursor);
268
+ } else {
269
+ speakCharOrWordOrLine(lastCursor, currCursor);
270
+ }
271
+ };
272
+ var onCursorChange = function(evt) {
273
+ if (changed) {
274
+ changed = false;
275
+ return;
276
+ }
277
+ var currCursor = cvoxAce.editor.selection.getCursor();
278
+ if (currCursor.row !== lastCursor.row) {
279
+ onRowChange(currCursor);
280
+ } else {
281
+ onColumnChange(lastCursor, currCursor);
282
+ }
283
+ lastCursor = currCursor;
284
+ };
285
+ var onSelectionChange = function(evt) {
286
+ if (cvoxAce.editor.selection.isEmpty()) {
287
+ cvox.Api.speak('unselected');
288
+ }
289
+ };
290
+ var onChange = function(evt) {
291
+ var data = evt.data;
292
+ switch (data.action) {
293
+ case 'removeText':
294
+ cvox.Api.speak(data.text, 0, DELETED_PROP);
295
+ changed = true;
296
+ break;
297
+ case 'insertText':
298
+ cvox.Api.speak(data.text, 0);
299
+ changed = true;
300
+ break;
301
+ }
302
+ };
303
+ var isNewAnnotation = function(annot) {
304
+ var row = annot.row;
305
+ var col = annot.column;
306
+ return !annotTable[row] || !annotTable[row][col];
307
+ };
308
+ var populateAnnotations = function(annotations) {
309
+ annotTable = {};
310
+ for (var i = 0; i < annotations.length; i++) {
311
+ var annotation = annotations[i];
312
+ var row = annotation.row;
313
+ var col = annotation.column;
314
+ if (!annotTable[row]) {
315
+ annotTable[row] = {};
316
+ }
317
+ annotTable[row][col] = annotation;
318
+ }
319
+ };
320
+ var onAnnotationChange = function(evt) {
321
+ var annotations = cvoxAce.editor.getSession().getAnnotations();
322
+ var newAnnotations = annotations.filter(isNewAnnotation);
323
+ if (newAnnotations.length > 0) {
324
+ cvox.Api.playEarcon(ERROR_EARCON);
325
+ }
326
+ populateAnnotations(annotations);
327
+ };
328
+ var speakAnnot = function(annot) {
329
+ var annotText = annot.type + ' ' + annot.text + ' on ' +
330
+ rowColToString(annot.row, annot.column);
331
+ annotText = annotText.replace(';', 'semicolon');
332
+ cvox.Api.speak(annotText, 1);
333
+ };
334
+ var speakAnnotsByRow = function(row) {
335
+ var annots = annotTable[row];
336
+ for (var col in annots) {
337
+ speakAnnot(annots[col]);
338
+ }
339
+ };
340
+ var rowColToString = function(row, col) {
341
+ return 'row ' + (row + 1) + ' column ' + (col + 1);
342
+ };
343
+ var speakCurrRowAndCol = function() {
344
+ cvox.Api.speak(rowColToString(lastCursor.row, lastCursor.column));
345
+ };
346
+ var speakAllAnnots = function() {
347
+ for (var row in annotTable) {
348
+ speakAnnotsByRow(row);
349
+ }
350
+ };
351
+ var speakMode = function() {
352
+ if (!isVimMode()) {
353
+ return;
354
+ }
355
+ switch (cvoxAce.editor.keyBinding.$data.state) {
356
+ case INSERT_MODE_STATE:
357
+ cvox.Api.speak('Insert mode');
358
+ break;
359
+ case COMMAND_MODE_STATE:
360
+ cvox.Api.speak('Command mode');
361
+ break;
362
+ }
363
+ };
364
+ var toggleSpeakRowLocation = function() {
365
+ shouldSpeakRowLocation = !shouldSpeakRowLocation;
366
+ if (shouldSpeakRowLocation) {
367
+ cvox.Api.speak('Speak location on row change enabled.');
368
+ } else {
369
+ cvox.Api.speak('Speak location on row change disabled.');
370
+ }
371
+ };
372
+ var toggleSpeakDisplacement = function() {
373
+ shouldSpeakDisplacement = !shouldSpeakDisplacement;
374
+ if (shouldSpeakDisplacement) {
375
+ cvox.Api.speak('Speak displacement on column changes.');
376
+ } else {
377
+ cvox.Api.speak('Speak current character or word on column changes.');
378
+ }
379
+ };
380
+ var onKeyDown = function(evt) {
381
+ if (evt.ctrlKey && evt.shiftKey) {
382
+ var shortcut = keyCodeToShortcutMap[evt.keyCode];
383
+ if (shortcut) {
384
+ shortcut.func();
385
+ }
386
+ }
387
+ };
388
+ var onChangeStatus = function(evt, editor) {
389
+ if (!isVimMode()) {
390
+ return;
391
+ }
392
+ var state = editor.keyBinding.$data.state;
393
+ if (state === vimState) {
394
+ return;
395
+ }
396
+ switch (state) {
397
+ case INSERT_MODE_STATE:
398
+ cvox.Api.playEarcon(MODE_SWITCH_EARCON);
399
+ cvox.Api.setKeyEcho(true);
400
+ break;
401
+ case COMMAND_MODE_STATE:
402
+ cvox.Api.playEarcon(MODE_SWITCH_EARCON);
403
+ cvox.Api.setKeyEcho(false);
404
+ break;
405
+ }
406
+ vimState = state;
407
+ };
408
+ var contextMenuHandler = function(evt) {
409
+ var cmd = evt.detail['customCommand'];
410
+ var shortcut = cmdToShortcutMap[cmd];
411
+ if (shortcut) {
412
+ shortcut.func();
413
+ cvoxAce.editor.focus();
414
+ }
415
+ };
416
+ var initContextMenu = function() {
417
+ var ACTIONS = SHORTCUTS.map(function(shortcut) {
418
+ return {
419
+ desc: shortcut.desc + getKeyShortcutString(shortcut.keyCode),
420
+ cmd: shortcut.cmd
421
+ };
422
+ });
423
+ var body = document.querySelector('body');
424
+ body.setAttribute('contextMenuActions', JSON.stringify(ACTIONS));
425
+ body.addEventListener('ATCustomEvent', contextMenuHandler, true);
426
+ };
427
+ var onFindSearchbox = function(evt) {
428
+ if (evt.match) {
429
+ speakLine(lastCursor.row, 0);
430
+ } else {
431
+ cvox.Api.playEarcon(NO_MATCH_EARCON);
432
+ }
433
+ };
434
+ var focus = function() {
435
+ cvoxAce.editor.focus();
436
+ };
437
+ var SHORTCUTS = [
438
+ {
439
+ keyCode: 49,
440
+ func: function() {
441
+ speakAnnotsByRow(lastCursor.row);
442
+ },
443
+ cmd: Command.SPEAK_ANNOT,
444
+ desc: 'Speak annotations on line'
445
+ },
446
+ {
447
+ keyCode: 50,
448
+ func: speakAllAnnots,
449
+ cmd: Command.SPEAK_ALL_ANNOTS,
450
+ desc: 'Speak all annotations'
451
+ },
452
+ {
453
+ keyCode: 51,
454
+ func: speakMode,
455
+ cmd: Command.SPEAK_MODE,
456
+ desc: 'Speak Vim mode'
457
+ },
458
+ {
459
+ keyCode: 52,
460
+ func: toggleSpeakRowLocation,
461
+ cmd: Command.TOGGLE_LOCATION,
462
+ desc: 'Toggle speak row location'
463
+ },
464
+ {
465
+ keyCode: 53,
466
+ func: speakCurrRowAndCol,
467
+ cmd: Command.SPEAK_ROW_COL,
468
+ desc: 'Speak row and column'
469
+ },
470
+ {
471
+ keyCode: 54,
472
+ func: toggleSpeakDisplacement,
473
+ cmd: Command.TOGGLE_DISPLACEMENT,
474
+ desc: 'Toggle speak displacement'
475
+ },
476
+ {
477
+ keyCode: 55,
478
+ func: focus,
479
+ cmd: Command.FOCUS_TEXT,
480
+ desc: 'Focus text'
481
+ }
482
+ ];
483
+ var onFocus = function() {
484
+ cvoxAce.editor = editor;
485
+ editor.getSession().selection.on('changeCursor', onCursorChange);
486
+ editor.getSession().selection.on('changeSelection', onSelectionChange);
487
+ editor.getSession().on('change', onChange);
488
+ editor.getSession().on('changeAnnotation', onAnnotationChange);
489
+ editor.on('changeStatus', onChangeStatus);
490
+ editor.on('findSearchBox', onFindSearchbox);
491
+ editor.container.addEventListener('keydown', onKeyDown);
492
+
493
+ lastCursor = editor.selection.getCursor();
494
+ };
495
+ var init = function(editor) {
496
+ onFocus();
497
+ SHORTCUTS.forEach(function(shortcut) {
498
+ keyCodeToShortcutMap[shortcut.keyCode] = shortcut;
499
+ cmdToShortcutMap[shortcut.cmd] = shortcut;
500
+ });
501
+
502
+ editor.on('focus', onFocus);
503
+ if (isVimMode()) {
504
+ cvox.Api.setKeyEcho(false);
505
+ }
506
+ initContextMenu();
507
+ };
508
+ function cvoxApiExists() {
509
+ return (typeof(cvox) !== 'undefined') && cvox && cvox.Api;
510
+ }
511
+ var tries = 0;
512
+ var MAX_TRIES = 15;
513
+ function watchForCvoxLoad(editor) {
514
+ if (cvoxApiExists()) {
515
+ init(editor);
516
+ } else {
517
+ tries++;
518
+ if (tries >= MAX_TRIES) {
519
+ return;
520
+ }
521
+ window.setTimeout(watchForCvoxLoad, 500, editor);
522
+ }
523
+ }
524
+
525
+ var Editor = require('../editor').Editor;
526
+ require('../config').defineOptions(Editor.prototype, 'editor', {
527
+ enableChromevoxEnhancements: {
528
+ set: function(val) {
529
+ if (val) {
530
+ watchForCvoxLoad(this);
531
+ }
532
+ },
533
+ value: true // turn it on by default or check for window.cvox
534
+ }
535
+ });
536
+
537
+ });
538
+ (function() {
539
+ ace.require(["ace/ext/chromevox"], function() {});
540
+ })();
541
+