stackprofiler 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/README.md +1 -1
- data/config.ru +3 -2
- data/lib/stackprofiler.rb +0 -1
- data/lib/stackprofiler/filters/build_tree.rb +3 -4
- data/lib/stackprofiler/filters/gem_removal.rb +3 -0
- data/lib/stackprofiler/web_ui.rb +34 -11
- data/lib/stackprofiler/web_ui/public/css/stackprofiler.css +77 -0
- data/lib/stackprofiler/web_ui/public/js/stackprofiler.js +129 -58
- data/lib/stackprofiler/web_ui/public/vendor/ace/ace.js +18298 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-beautify.js +334 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-chromevox.js +541 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-elastic_tabstops_lite.js +275 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-emmet.js +1190 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-error_marker.js +6 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-keybinding_menu.js +170 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-language_tools.js +1934 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-linking.js +52 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-modelist.js +187 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-old_ie.js +494 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-searchbox.js +409 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-settings_menu.js +637 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-spellcheck.js +71 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-split.js +246 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-static_highlight.js +154 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-statusbar.js +51 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-textarea.js +632 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-themelist.js +58 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/ext-whitespace.js +181 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/keybinding-emacs.js +1182 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/keybinding-vim.js +5320 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-haml.js +525 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-html.js +2427 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-html_ruby.js +2955 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-javascript.js +1025 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-json.js +668 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-ruby.js +839 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-xml.js +637 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/mode-yaml.js +256 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/theme-xcode.js +89 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/worker-coffee.js +7599 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/worker-css.js +8682 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/worker-html.js +11527 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/worker-javascript.js +10429 -0
- data/lib/stackprofiler/web_ui/public/vendor/ace/worker-json.js +2319 -0
- data/lib/stackprofiler/web_ui/views/index.erb +1 -1
- data/lib/stackprofiler/web_ui/views/layout.erb +2 -55
- data/stackprofiler.gemspec +2 -4
- metadata +42 -19
- 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
|
+
|