/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk

« back to all changes in this revision

Viewing changes to js/ace/keybinding-emacs.js

  • Committer: Gustav Hatvigsson
  • Date: 2013-05-31 06:15:46 UTC
  • mfrom: (90.1.20 lenasys2)
  • Revision ID: gustav.hartvigsson@gmail.com-20130531061546-vj8z28sq375kvghq
Merged Jonsson:s changes:
Fixed the layout on cms index so the arrows and dots marks expanded objects.
Fixed so the course content is sorted by course occasion and not by name

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Distributed under the BSD license:
 
3
 *
 
4
 * Copyright (c) 2010, Ajax.org B.V.
 
5
 * All rights reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted provided that the following conditions are met:
 
9
 *     * Redistributions of source code must retain the above copyright
 
10
 *       notice, this list of conditions and the following disclaimer.
 
11
 *     * Redistributions in binary form must reproduce the above copyright
 
12
 *       notice, this list of conditions and the following disclaimer in the
 
13
 *       documentation and/or other materials provided with the distribution.
 
14
 *     * Neither the name of Ajax.org B.V. nor the
 
15
 *       names of its contributors may be used to endorse or promote products
 
16
 *       derived from this software without specific prior written permission.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
21
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
27
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
28
 *
 
29
 * ***** END LICENSE BLOCK ***** */
 
30
 
 
31
define('ace/keyboard/emacs', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/keyboard/hash_handler', 'ace/lib/keys'], function(require, exports, module) {
 
32
 
 
33
 
 
34
var dom = require("../lib/dom");
 
35
 
 
36
var screenToTextBlockCoordinates = function(x, y) {
 
37
    var canvasPos = this.scroller.getBoundingClientRect();
 
38
 
 
39
    var col = Math.floor(
 
40
        (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth
 
41
    );
 
42
    var row = Math.floor(
 
43
        (y + this.scrollTop - canvasPos.top) / this.lineHeight
 
44
    );
 
45
 
 
46
    return this.session.screenToDocumentPosition(row, col);
 
47
};
 
48
 
 
49
var HashHandler = require("./hash_handler").HashHandler;
 
50
exports.handler = new HashHandler();
 
51
 
 
52
var initialized = false;
 
53
var $formerLongWords;
 
54
var $formerLineStart;
 
55
 
 
56
exports.handler.attach = function(editor) {
 
57
    if (!initialized) {
 
58
        initialized = true;
 
59
        dom.importCssString('\
 
60
            .emacs-mode .ace_cursor{\
 
61
                border: 2px rgba(50,250,50,0.8) solid!important;\
 
62
                -moz-box-sizing: border-box!important;\
 
63
                -webkit-box-sizing: border-box!important;\
 
64
                box-sizing: border-box!important;\
 
65
                background-color: rgba(0,250,0,0.9);\
 
66
                opacity: 0.5;\
 
67
            }\
 
68
            .emacs-mode .ace_cursor.ace_hidden{\
 
69
                opacity: 1;\
 
70
                background-color: transparent;\
 
71
            }\
 
72
            .emacs-mode .ace_overwrite-cursors .ace_cursor {\
 
73
                opacity: 1;\
 
74
                background-color: transparent;\
 
75
                border-width: 0 0 2px 2px !important;\
 
76
            }\
 
77
            .emacs-mode .ace_text-layer {\
 
78
                z-index: 4\
 
79
            }\
 
80
            .emacs-mode .ace_cursor-layer {\
 
81
                z-index: 2\
 
82
            }', 'emacsMode'
 
83
        );
 
84
    }
 
85
    $formerLongWords = editor.session.$selectLongWords;
 
86
    editor.session.$selectLongWords = true;
 
87
    $formerLineStart = editor.session.$useEmacsStyleLineStart;
 
88
    editor.session.$useEmacsStyleLineStart = true;
 
89
 
 
90
    editor.session.$emacsMark = null;
 
91
 
 
92
    exports.markMode = function() {
 
93
        return editor.session.$emacsMark;
 
94
    }
 
95
 
 
96
    exports.setMarkMode = function(p) {
 
97
        editor.session.$emacsMark = p;
 
98
    }
 
99
 
 
100
    editor.on("click",$resetMarkMode);
 
101
    editor.on("changeSession",$kbSessionChange);
 
102
    editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
 
103
    editor.setStyle("emacs-mode");
 
104
    editor.commands.addCommands(commands);
 
105
    exports.handler.platform = editor.commands.platform;
 
106
};
 
107
 
 
108
exports.handler.detach = function(editor) {
 
109
    delete editor.renderer.screenToTextCoordinates;
 
110
    editor.session.$selectLongWords = $formerLongWords;
 
111
    editor.session.$useEmacsStyleLineStart = $formerLineStart;
 
112
    editor.removeEventListener("click",$resetMarkMode);
 
113
    editor.removeEventListener("changeSession",$kbSessionChange);
 
114
    editor.unsetStyle("emacs-mode");
 
115
    editor.commands.removeCommands(commands);
 
116
};
 
117
 
 
118
var $kbSessionChange = function(e) {
 
119
    if (e.oldSession) {
 
120
        e.oldSession.$selectLongWords = $formerLongWords;
 
121
        e.oldSession.$useEmacsStyleLineStart = $formerLineStart;
 
122
    }
 
123
 
 
124
    $formerLongWords = e.session.$selectLongWords;
 
125
    e.session.$selectLongWords = true;
 
126
    $formerLineStart = e.session.$useEmacsStyleLineStart;
 
127
    e.session.$useEmacsStyleLineStart = true;
 
128
 
 
129
    if (!e.session.hasOwnProperty('$emacsMark'))
 
130
        e.session.$emacsMark = null;
 
131
}
 
132
 
 
133
var $resetMarkMode = function(e) {
 
134
    e.editor.session.$emacsMark = null;
 
135
}
 
136
 
 
137
var keys = require("../lib/keys").KEY_MODS,
 
138
    eMods = {C: "ctrl", S: "shift", M: "alt", CMD: "command"},
 
139
    combinations = ["C-S-M-CMD",
 
140
                    "S-M-CMD", "C-M-CMD", "C-S-CMD", "C-S-M",
 
141
                    "M-CMD", "S-CMD", "S-M", "C-CMD", "C-M", "C-S",
 
142
                    "CMD", "M", "S", "C"];
 
143
combinations.forEach(function(c) {
 
144
    var hashId = 0;
 
145
    c.split("-").forEach(function(c) {
 
146
        hashId = hashId | keys[eMods[c]];
 
147
    });
 
148
    eMods[hashId] = c.toLowerCase() + "-";
 
149
});
 
150
 
 
151
exports.handler.bindKey = function(key, command) {
 
152
    if (!key)
 
153
        return;
 
154
 
 
155
    var ckb = this.commmandKeyBinding;
 
156
    key.split("|").forEach(function(keyPart) {
 
157
        keyPart = keyPart.toLowerCase();
 
158
        ckb[keyPart] = command;
 
159
        keyPart = keyPart.split(" ")[0];
 
160
        if (!ckb[keyPart])
 
161
            ckb[keyPart] = "null";
 
162
    }, this);
 
163
};
 
164
 
 
165
 
 
166
exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
 
167
    if (hashId == -1) {
 
168
        exports.setMarkMode(null);
 
169
        if (data.count) {
 
170
            var str = Array(data.count + 1).join(key);
 
171
            data.count = null;
 
172
            return {command: "insertstring", args: str};
 
173
        }
 
174
    }
 
175
 
 
176
    if (key == "\x00")
 
177
        return;
 
178
 
 
179
    var modifier = eMods[hashId];
 
180
    if (modifier == "c-" || data.universalArgument) {
 
181
        var count = parseInt(key[key.length - 1]);
 
182
        if (count) {
 
183
            data.count = count;
 
184
            return {command: "null"};
 
185
        }
 
186
    }
 
187
    data.universalArgument = false;
 
188
    if (modifier) key = modifier + key;
 
189
    if (data.keyChain) key = data.keyChain += " " + key;
 
190
    var command = this.commmandKeyBinding[key];
 
191
    data.keyChain = command == "null" ? key : "";
 
192
    if (!command) return;
 
193
    if (command === "null") return {command: "null"};
 
194
 
 
195
    if (command === "universalArgument") {
 
196
        data.universalArgument = true;
 
197
        return {command: "null"};
 
198
    }
 
199
    var args;
 
200
    if (typeof command !== "string") {
 
201
        args = command.args;
 
202
        if (command.command) command = command.command;
 
203
        if (command === "goorselect") {
 
204
            command = exports.markMode() ? args[1] : args[0];
 
205
            args = null;
 
206
        }
 
207
    }
 
208
 
 
209
    if (typeof command === "string") {
 
210
        if (command === "insertstring" ||
 
211
            command === "splitline" ||
 
212
            command === "togglecomment") {
 
213
            exports.setMarkMode(null);
 
214
        }
 
215
        command = this.commands[command] || data.editor.commands.commands[command];
 
216
    }
 
217
 
 
218
    if (!command.readonly && !command.isYank)
 
219
        data.lastCommand = null;
 
220
 
 
221
    if (data.count) {
 
222
        var count = data.count;
 
223
        data.count = 0;
 
224
        return {
 
225
            args: args,
 
226
            command: {
 
227
                exec: function(editor, args) {
 
228
                    for (var i = 0; i < count; i++)
 
229
                        command.exec(editor, args);
 
230
                }
 
231
            }
 
232
        };
 
233
    }
 
234
 
 
235
    return {command: command, args: args};
 
236
};
 
237
 
 
238
exports.emacsKeys = {
 
239
    "Up|C-p"      : {command: "goorselect", args: ["golineup","selectup"]},
 
240
    "Down|C-n"    : {command: "goorselect", args: ["golinedown","selectdown"]},
 
241
    "Left|C-b"    : {command: "goorselect", args: ["gotoleft","selectleft"]},
 
242
    "Right|C-f"   : {command: "goorselect", args: ["gotoright","selectright"]},
 
243
    "C-Left|M-b"  : {command: "goorselect", args: ["gotowordleft","selectwordleft"]},
 
244
    "C-Right|M-f" : {command: "goorselect", args: ["gotowordright","selectwordright"]},
 
245
    "Home|C-a"    : {command: "goorselect", args: ["gotolinestart","selecttolinestart"]},
 
246
    "End|C-e"     : {command: "goorselect", args: ["gotolineend","selecttolineend"]},
 
247
    "C-Home|S-M-,": {command: "goorselect", args: ["gotostart","selecttostart"]},
 
248
    "C-End|S-M-." : {command: "goorselect", args: ["gotoend","selecttoend"]},
 
249
    "S-Up|S-C-p"      : "selectup",
 
250
    "S-Down|S-C-n"    : "selectdown",
 
251
    "S-Left|S-C-b"    : "selectleft",
 
252
    "S-Right|S-C-f"   : "selectright",
 
253
    "S-C-Left|S-M-b"  : "selectwordleft",
 
254
    "S-C-Right|S-M-f" : "selectwordright",
 
255
    "S-Home|S-C-a"    : "selecttolinestart",
 
256
    "S-End|S-C-e"     : "selecttolineend",
 
257
    "S-C-Home"        : "selecttostart",
 
258
    "S-C-End"         : "selecttoend",
 
259
 
 
260
    "C-l" : "recenterTopBottom",
 
261
    "M-s" : "centerselection",
 
262
    "M-g": "gotoline",
 
263
    "C-x C-p": "selectall",
 
264
    "C-Down": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},
 
265
    "C-Up": {command: "goorselect", args: ["gotopageup","selectpageup"]},
 
266
    "PageDown|C-v": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},
 
267
    "PageUp|M-v": {command: "goorselect", args: ["gotopageup","selectpageup"]},
 
268
    "S-C-Down": "selectpagedown",
 
269
    "S-C-Up": "selectpageup",
 
270
    "C-s": "findnext",
 
271
    "C-r": "findprevious",
 
272
    "M-C-s": "findnext",
 
273
    "M-C-r": "findprevious",
 
274
    "S-M-5": "replace",
 
275
    "Backspace": "backspace",
 
276
    "Delete|C-d": "del",
 
277
    "Return|C-m": {command: "insertstring", args: "\n"}, // "newline"
 
278
    "C-o": "splitline",
 
279
 
 
280
    "M-d|C-Delete": {command: "killWord", args: "right"},
 
281
    "C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"},
 
282
    "C-k": "killLine",
 
283
 
 
284
    "C-y|S-Delete": "yank",
 
285
    "M-y": "yankRotate",
 
286
    "C-g": "keyboardQuit",
 
287
 
 
288
    "C-w": "killRegion",
 
289
    "M-w": "killRingSave",
 
290
    "C-Space": "setMark",
 
291
    "C-x C-x": "exchangePointAndMark",
 
292
 
 
293
    "C-t": "transposeletters",
 
294
    "M-u": "touppercase",    // Doesn't work
 
295
    "M-l": "tolowercase",
 
296
    "M-/": "autocomplete",   // Doesn't work
 
297
    "C-u": "universalArgument",
 
298
 
 
299
    "M-;": "togglecomment",
 
300
 
 
301
    "C-/|C-x u|S-C--|C-z": "undo",
 
302
    "S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo?
 
303
    "C-x r":  "selectRectangularRegion"
 
304
};
 
305
 
 
306
 
 
307
exports.handler.bindKeys(exports.emacsKeys);
 
308
 
 
309
exports.handler.addCommands({
 
310
    recenterTopBottom: function(editor) {
 
311
        var renderer = editor.renderer;
 
312
        var pos = renderer.$cursorLayer.getPixelPosition();
 
313
        var h = renderer.$size.scrollerHeight - renderer.lineHeight;
 
314
        var scrollTop = renderer.scrollTop;
 
315
        if (Math.abs(pos.top - scrollTop) < 2) {
 
316
            scrollTop = pos.top - h;
 
317
        } else if (Math.abs(pos.top - scrollTop - h * 0.5) < 2) {
 
318
            scrollTop = pos.top;
 
319
        } else {
 
320
            scrollTop = pos.top - h * 0.5;
 
321
        }
 
322
        editor.session.setScrollTop(scrollTop);
 
323
    },
 
324
    selectRectangularRegion:  function(editor) {
 
325
        editor.multiSelect.toggleBlockSelection();
 
326
    },
 
327
    setMark:  function(editor) {
 
328
        var markMode = exports.markMode();
 
329
        if (markMode) {
 
330
            var cp = editor.getCursorPosition();
 
331
            if (editor.selection.isEmpty() &&
 
332
               markMode.row == cp.row && markMode.column == cp.column) {
 
333
                exports.setMarkMode(null);
 
334
                return;
 
335
            }
 
336
        }
 
337
        markMode = editor.getCursorPosition();
 
338
        exports.setMarkMode(markMode);
 
339
        editor.selection.setSelectionAnchor(markMode.row, markMode.column);
 
340
 
 
341
    },
 
342
    exchangePointAndMark: {
 
343
        exec: function(editor) {
 
344
            var range = editor.selection.getRange();
 
345
            editor.selection.setSelectionRange(range, !editor.selection.isBackwards());
 
346
        },
 
347
        readonly: true,
 
348
        multiselectAction: "forEach"
 
349
    },
 
350
    killWord: {
 
351
        exec: function(editor, dir) {
 
352
            editor.clearSelection();
 
353
            if (dir == "left")
 
354
                editor.selection.selectWordLeft();
 
355
            else
 
356
                editor.selection.selectWordRight();
 
357
 
 
358
            var range = editor.getSelectionRange();
 
359
            var text = editor.session.getTextRange(range);
 
360
            exports.killRing.add(text);
 
361
 
 
362
            editor.session.remove(range);
 
363
            editor.clearSelection();
 
364
        },
 
365
        multiselectAction: "forEach"
 
366
    },
 
367
    killLine: function(editor) {
 
368
        exports.setMarkMode(null);
 
369
        var pos = editor.getCursorPosition();
 
370
        if (pos.column == 0 &&
 
371
            editor.session.doc.getLine(pos.row).length == 0) {
 
372
            editor.selection.selectLine();
 
373
        } else {
 
374
            editor.clearSelection();
 
375
            editor.selection.selectLineEnd();
 
376
        }
 
377
        var range = editor.getSelectionRange();
 
378
        var text = editor.session.getTextRange(range);
 
379
        exports.killRing.add(text);
 
380
 
 
381
        editor.session.remove(range);
 
382
        editor.clearSelection();
 
383
    },
 
384
    yank: function(editor) {
 
385
        editor.onPaste(exports.killRing.get());
 
386
        editor.keyBinding.$data.lastCommand = "yank";
 
387
    },
 
388
    yankRotate: function(editor) {
 
389
        if (editor.keyBinding.$data.lastCommand != "yank")
 
390
            return;
 
391
        editor.undo();
 
392
        editor.onPaste(exports.killRing.rotate());
 
393
        editor.keyBinding.$data.lastCommand = "yank";
 
394
    },
 
395
    killRegion: function(editor) {
 
396
        exports.killRing.add(editor.getCopyText());
 
397
        editor.commands.byName.cut.exec(editor);
 
398
    },
 
399
    killRingSave: function(editor) {
 
400
        exports.killRing.add(editor.getCopyText());
 
401
    },
 
402
    keyboardQuit: function(editor) {
 
403
        editor.selection.clearSelection();
 
404
        exports.setMarkMode(null);
 
405
    }
 
406
});
 
407
 
 
408
var commands = exports.handler.commands;
 
409
commands.yank.isYank = true;
 
410
commands.yankRotate.isYank = true;
 
411
 
 
412
exports.killRing = {
 
413
    $data: [],
 
414
    add: function(str) {
 
415
        str && this.$data.push(str);
 
416
        if (this.$data.length > 30)
 
417
            this.$data.shift();
 
418
    },
 
419
    get: function() {
 
420
        return this.$data[this.$data.length - 1] || "";
 
421
    },
 
422
    pop: function() {
 
423
        if (this.$data.length > 1)
 
424
            this.$data.pop();
 
425
        return this.get();
 
426
    },
 
427
    rotate: function() {
 
428
        this.$data.unshift(this.$data.pop());
 
429
        return this.get();
 
430
    }
 
431
};
 
432
 
 
433
 
 
434
});