editor.js

来自「在线编辑器」· JavaScript 代码 · 共 1,381 行 · 第 1/4 页

JS
1,381
字号
        this.toggleCursorFullRepaintCounter = 0;    // tracks how many cursor toggles since the last full repaint        // these two canvases are used as buffers for the scrollbar images, which are then composited onto the        // main code view. we could have saved ourselves some misery by just prerendering slices of the scrollbars and        // combining them like sane people, but... meh        this.horizontalScrollCanvas = dojo.create("canvas");        this.verticalScrollCanvas = dojo.create("canvas");        this.GUTTER_WIDTH = 54;        this.LINE_HEIGHT = 23;        this.GUTTER_INSETS = { top: 0, left: 6, right: 0, bottom: 6 }        this.LINE_INSETS = { top: 0, left: 5, right: 0, bottom: 6 }        this.FALLBACK_CHARACTER_WIDTH = 10;        this.NIB_WIDTH = 15;        this.NIB_INSETS = { top: Math.floor(this.NIB_WIDTH / 2),                            left: Math.floor(this.NIB_WIDTH / 2),                            right: Math.floor(this.NIB_WIDTH / 2),                            bottom: Math.floor(this.NIB_WIDTH / 2) }        this.NIB_ARROW_INSETS = { top: 3, left: 3, right: 3, bottom: 5 }        this.lineHeight;        // reserved for when line height is calculated dynamically instead of with a constant; set first time a paint occurs        this.charWidth;         // set first time a paint occurs        this.visibleRows;       // the number of rows visible in the editor; set each time a paint occurs        this.firstVisibleRow;   // first row that is visible in the editor; set each time a paint occurs        this.nibup;             // rect        this.nibdown;           // rect        this.nibleft;           // rect        this.nibright;          // rect        this.selectMouseDownPos;        // position when the user moused down        this.xoffset = 0;       // number of pixels to translate the canvas for scrolling        this.yoffset = 0;        this.showCursor = true;        this.overXScrollBar = false;        this.overYScrollBar = false;        this.hasFocus = false;        var source = this.editor.container;        dojo.connect(source, "mousemove", this, "handleScrollBars");        dojo.connect(source, "mouseout", this, "handleScrollBars");        dojo.connect(source, "click", this, "handleScrollBars");        dojo.connect(source, "mousedown", this, "handleScrollBars");        dojo.connect(source, "mousedown", this, "mouseDownSelect");        dojo.connect(source, "mousemove", this, "mouseMoveSelect");        dojo.connect(source, "mouseup", this, "mouseUpSelect");        // painting optimization state        this.lastLineCount = 0;        this.lastCursorPos = null;        this.lastxoffset = 0;        this.lastyoffset = 0;        this.xscrollbar = new bespin.editor.Scrollbar(this, "horizontal");        this.xscrollbar.valueChanged = dojo.hitch(this, function() {            this.xoffset = -this.xscrollbar.value;            this.editor.paint();        });            dojo.connect(window, "mousemove", this.xscrollbar, "onmousemove");        dojo.connect(window, "mouseup", this.xscrollbar, "onmouseup");        dojo.connect(window, (!dojo.isMozilla ? "onmousewheel" : "DOMMouseScroll"), this.xscrollbar, "onmousewheel");        this.yscrollbar = new bespin.editor.Scrollbar(this, "vertical");        this.yscrollbar.valueChanged = dojo.hitch(this, function() {            this.yoffset = -this.yscrollbar.value;            this.editor.paint();        });         dojo.connect(window, "mousemove", this.yscrollbar, "onmousemove");         dojo.connect(window, "mouseup", this.yscrollbar, "onmouseup");                 dojo.connect(window, (!dojo.isMozilla ? "onmousewheel" : "DOMMouseScroll"), this.yscrollbar, "onmousewheel");                       setTimeout(dojo.hitch(this, function() { this.toggleCursor(this); }), 250);    },    // col is -1 if user clicked in gutter; clicking below last line maps to last line    convertClientPointToCursorPoint: function(pos) {        var x, y;        if (y > (this.lineHeight * this.editor.model.getRowCount())) {            y = this.editor.model.getRowCount() - 1;        } else {            var ty = pos.y;            y = Math.floor(ty / this.lineHeight);        }        if (pos.x <= (this.GUTTER_WIDTH + this.LINE_INSETS.left)) {            x = -1;        } else {            var tx = pos.x - this.GUTTER_WIDTH - this.LINE_INSETS.left;            x = Math.floor(tx / this.charWidth);                        // With striclines turned on, don't select past the end of the line            if (_settings.isOn(_settings.get('strictlines'))) {                var maxcol = this.editor.model.getRowLength(y);                            if (x >= maxcol) {                    x = this.editor.model.getRowLength(y);                }            }        }                return { col: x, row: y };    },    mouseDownSelect: function(e) {        var clientY = e.clientY - this.getTopOffset();        var clientX = e.clientX - this.getLeftOffset();        if (this.overXScrollBar || this.overYScrollBar) return;        if (e.shiftKey) {            this.selectMouseDownPos = (this.editor.selection) ? this.editor.selection.startPos : this.editor.cursorPosition;            this.setSelection(e);        } else {            var point = { x: clientX, y: clientY };            point.x += Math.abs(this.xoffset);            point.y += Math.abs(this.yoffset);            if ((this.xscrollbar.rect.contains(point)) || (this.yscrollbar.rect.contains(point))) return;            this.selectMouseDownPos = this.convertClientPointToCursorPoint(point);        }    },    mouseMoveSelect: function(e) {        this.setSelection(e);    },    mouseUpSelect: function(e) {        this.setSelection(e);        this.selectMouseDownPos = undefined;    },    setSelection: function(e) {        var clientY = e.clientY - this.getTopOffset();        var clientX = e.clientX - this.getLeftOffset();        if (!this.selectMouseDownPos) return;        var down = bespin.editor.utils.copyPos(this.selectMouseDownPos);        var point = { x: clientX, y: clientY };        point.x += Math.abs(this.xoffset);        point.y += Math.abs(this.yoffset);        var up = this.convertClientPointToCursorPoint(point);        if (down.col == -1) down.col = 0;        if (up.col == -1) up.col = 0;        if (!bespin.editor.utils.posEquals(down, up)) {            this.editor.setSelection({ startPos: down, endPos: up });        } else {            if (e.detail == 1) {                this.editor.setSelection(undefined);            } else if (e.detail == 2) {                var row = this.editor.model.rows[down.row];                var cursorAt = row[down.col];                if (!cursorAt || cursorAt.charAt(0) == ' ') { // empty space                    // For now, don't select anything, but think about copying Textmate and grabbing around it                } else {                    var startPos = up = this.editor.model.findBefore(down.row, down.col);                                        var endPos = this.editor.model.findAfter(down.row, down.col);                                        this.editor.setSelection({ startPos: startPos, endPos: endPos });                }            } else if (e.detail > 2) {                // select the line                this.editor.setSelection({ startPos: { row: down.row, col: 0 }, endPos: { row: down.row + 1, col: 0 } });            }        }        this.editor.moveCursor(up);        this.editor.paint();    },    toggleCursor: function(ui) {        ui.showCursor = !ui.showCursor;        if (++this.toggleCursorFullRepaintCounter > 0) {            this.toggleCursorFullRepaintCounter = 0;            ui.editor.paint(true);        } else {            ui.editor.paint();        }        setTimeout(function() { ui.toggleCursor(ui) }, 250);    },    ensureCursorVisible: function() {        if ((!this.lineHeight) || (!this.charWidth)) return;    // can't do much without these        var y = this.lineHeight * this.editor.cursorPosition.row;        var x = this.charWidth * this.editor.cursorPosition.col;        var cheight = this.getHeight();        var cwidth = this.getWidth() - this.GUTTER_WIDTH;        if (Math.abs(this.yoffset) > y) {               // current row before top-most visible row            this.yoffset = -y;        } else if ((Math.abs(this.yoffset) + cheight) < (y + this.lineHeight)) {       // current row after bottom-most visible row            this.yoffset = -((y + this.lineHeight) - cheight);        }        if (Math.abs(this.xoffset) > x) {               // current col before left-most visible col            this.xoffset = -x;        } else if ((Math.abs(this.xoffset) + cwidth) < (x + (this.charWidth * 2))) { // current col after right-most visible col            this.xoffset = -((x + (this.charWidth * 2)) - cwidth);        }    },    handleFocus: function(e) {        this.editor.model.clear();        this.editor.model.insertCharacters({ row: 0, col: 0}, e.type);    },        handleScrollBars: function(e) {        var clientY = e.clientY - this.getTopOffset();        var clientX = e.clientX - this.getLeftOffset();        var oldX = this.overXScrollBar;        var oldY = this.overYScrollBar;        var scrolled = false;        var w = this.editor.container.clientWidth;        var h = this.editor.container.clientHeight;        var sx = w - this.NIB_WIDTH - this.NIB_INSETS.right;    // x start of the vert. scroll bar        var sy = h - this.NIB_WIDTH - this.NIB_INSETS.bottom;   // y start of the hor. scroll bar        var p = { x: clientX, y:clientY };        if (e.type == "mousedown") {            // dispatch to the scrollbars            if ((this.xscrollbar) && (this.xscrollbar.rect.contains(p))) {                this.xscrollbar.onmousedown(e);            } else if ((this.yscrollbar) && (this.yscrollbar.rect.contains(p))) {                this.yscrollbar.onmousedown(e);            }        }        if (e.type == "mouseout") {            this.overXScrollBar = false;            this.overYScrollBar = false;        }        if ((e.type == "mousemove") || (e.type == "click")) {            this.overYScrollBar = p.x > sx;            this.overXScrollBar = p.y > sy;        }        if (e.type == "click") {             if ((typeof e.button != "undefined") && (e.button == 0)) {                var button;                if (this.nibup.contains(p)) {                    button = "up";                } else if (this.nibdown.contains(p)) {                    button = "down";                } else if (this.nibleft.contains(p)) {                    button = "left";                } else if (this.nibright.contains(p)) {                    button = "right";                }                if (button == "up") {                    this.yoffset += this.lineHeight;                    scrolled = true;                } else if (button == "down") {                    this.yoffset -= this.lineHeight;                    scrolled = true;                } else if (button == "left") {                    this.xoffset += this.charWidth * 2;                    scrolled = true;                } else if (button == "right") {                    this.xoffset -= this.charWidth * 2;                    scrolled = true;                }            }        }        if ((oldX != this.overXScrollBar) || (oldY != this.overYScrollBar) || scrolled) this.editor.paint();    },    installKeyListener: function(listener) {        var Key = bespin.util.keys.Key; // alias        if (this.oldkeydown) dojo.disconnect(this.oldkeydown);        if (this.oldkeypress) dojo.disconnect(this.oldkeypress);        this.oldkeydown = dojo.hitch(listener, "onkeydown");        this.oldkeypress = dojo.hitch(listener, "onkeypress");        dojo.connect(document, "keydown", this, "oldkeydown");        dojo.connect(document, "keypress", this, "oldkeypress");        // Modifiers, Key, Action                listener.bindKeyStringSelectable("", Key.ARROW_LEFT, this.actions.moveCursorLeft);        listener.bindKeyStringSelectable("", Key.ARROW_RIGHT, this.actions.moveCursorRight);        listener.bindKeyStringSelectable("", Key.ARROW_UP, this.actions.moveCursorUp);        listener.bindKeyStringSelectable("", Key.ARROW_DOWN, this.actions.moveCursorDown);        listener.bindKeyStringSelectable("ALT", Key.ARROW_LEFT, this.actions.moveWordLeft);        listener.bindKeyStringSelectable("ALT", Key.ARROW_RIGHT, this.actions.moveWordRight);        listener.bindKeyStringSelectable("", Key.HOME, this.actions.moveToLineStart);        listener.bindKeyStringSelectable("APPLE", Key.ARROW_LEFT, this.actions.moveToLineStart);        listener.bindKeyStringSelectable("", Key.END, this.actions.moveToLineEnd);        listener.bindKeyStringSelectable("APPLE", Key.ARROW_RIGHT, this.actions.moveToLineEnd);        listener.bindKeyString("CTRL", Key.K, this.actions.killLine);        listener.bindKeyString("CTRL", Key.L, this.actions.moveCursorRowToCenter);        listener.bindKeyString("", Key.BACKSPACE, this.actions.backspace);        listener.bindKeyString("", Key.DELETE, this.actions.deleteKey);        listener.bindKeyString("", Key.ENTER, this.actions.newline);        listener.bindKeyString("", Key.TAB, this.actions.insertTab);        listener.bindKeyString("SHIFT", Key.TAB, this.actions.unindent);        listener.bindKeyString("APPLE", Key.A, this.actions.selectAll);        listener.bindKeyString("CTRL", Key.A, this.actions.selectAll);        listener.bindKeyString("APPLE", Key.Z, this.actions.undoRedo);        listener.bindKeyString("CTRL", Key.Z, this.actions.undoRedo);        listener.bindKeyStringSelectable("APPLE", Key.ARROW_UP, this.actions.moveToFileTop);        listener.bindKeyStringSelectable("APPLE", Key.ARROW_DOWN, this.actions.moveToFileBottom);                listener.bindKeyStringSelectable("", Key.PAGE_UP, this.actions.movePageUp);        listener.bindKeyStringSelectable("", Key.PAGE_DOWN, this.actions.movePageDown);        // Other key bindings can be found in commands themselves.        // For example, this:        // listener.bindKeyString("CTRL SHIFT", Key.N, "bespin:editor:newfile");        // has been moved to the 'newfile' command withKey        // Also, the clipboard.js handles C, V, and X    },    getWidth: function() {        return parseInt(dojo.attr(this.editor.canvas.parentNode, "width"));    },    getHeight: function() {           return parseInt(dojo.attr(this.editor.canvas.parentNode, "height"));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?