apply MVC to the virtual renderer. Split off all

state into the new WindowModel class and sync using
the new WindowController.
This commit is contained in:
Fabian Jakobs 2011-07-27 15:10:19 +02:00
commit 1657ffb93e
14 changed files with 444 additions and 223 deletions

View file

@ -48,6 +48,7 @@ var UA = require("pilot/useragent")
var Editor = require("ace/editor").Editor;
var Buffer = require("ace/model/buffer").Buffer;
var Window = require("ace/model/window").Window;
var UndoManager = require("ace/undomanager").UndoManager;
var Renderer = require("ace/view/window_view").WindowView;
@ -61,7 +62,7 @@ window.__ace_shadowed__.edit = function(el) {
doc.setUndoManager(new UndoManager());
el.innerHTML = '';
var editor = new Editor(new Renderer(el, "ace/theme/textmate"));
var editor = new Editor(new Renderer(new Window(), el, "ace/theme/textmate"));
editor.setSession(doc);
var env = {};
@ -297,7 +298,7 @@ function setupApi(editor, editorDiv, settingDiv, ace, options) {
switch (key) {
case "gutter":
renderer.setShowGutter(toBool(value));
editor.setShowGutter(toBool(value));
break;
case "mode":
@ -331,12 +332,12 @@ function setupApi(editor, editorDiv, settingDiv, ace, options) {
switch (value) {
case "off":
session.setUseWrapMode(false);
renderer.setPrintMarginColumn(80);
editor.setPrintMarginColumn(80);
break;
case "40":
session.setUseWrapMode(true);
session.setWrapLimitRange(40, 40);
renderer.setPrintMarginColumn(40);
editor.setPrintMarginColumn(40);
break;
case "80":
session.setUseWrapMode(true);
@ -346,7 +347,7 @@ function setupApi(editor, editorDiv, settingDiv, ace, options) {
case "free":
session.setUseWrapMode(true);
session.setWrapLimitRange(null, null);
renderer.setPrintMarginColumn(80);
editor.setPrintMarginColumn(80);
break;
}
break;

View file

@ -336,8 +336,8 @@ define(function(require, exports, module) {
themeEl.value = editor.getTheme();
highlightActiveEl.checked = editor.getHighlightActiveLine();
showHiddenEl.checked = editor.getShowInvisibles();
showGutterEl.checked = editor.renderer.getShowGutter();
showPrintMarginEl.checked = editor.renderer.getShowPrintMargin();
showGutterEl.checked = editor.getShowGutter();
showPrintMarginEl.checked = editor.getShowPrintMargin();
highlightSelectedWordE.checked = editor.getHighlightSelectedWord();
showHScrollEl.checked = editor.renderer.getHScrollBarAlwaysVisible();
softTabEl.checked = session.getUseSoftTabs();
@ -369,26 +369,26 @@ define(function(require, exports, module) {
bindDropdown("soft_wrap", function(value) {
var session = env.editor.getSession();
var renderer = env.editor.renderer;
var editor = env.editor;
switch (value) {
case "off":
session.setUseWrapMode(false);
renderer.setPrintMarginColumn(80);
editor.setPrintMarginColumn(80);
break;
case "40":
session.setUseWrapMode(true);
session.setWrapLimitRange(40, 40);
renderer.setPrintMarginColumn(40);
editor.setPrintMarginColumn(40);
break;
case "80":
session.setUseWrapMode(true);
session.setWrapLimitRange(80, 80);
renderer.setPrintMarginColumn(80);
editor.setPrintMarginColumn(80);
break;
case "free":
session.setUseWrapMode(true);
session.setWrapLimitRange(null, null);
renderer.setPrintMarginColumn(80);
editor.setPrintMarginColumn(80);
break;
}
});
@ -406,11 +406,11 @@ define(function(require, exports, module) {
});
bindCheckbox("show_gutter", function(checked) {
env.editor.renderer.setShowGutter(checked);
env.editor.setShowGutter(checked);
});
bindCheckbox("show_print_margin", function(checked) {
env.editor.renderer.setShowPrintMargin(checked);
env.editor.setShowPrintMargin(checked);
});
bindCheckbox("highlight_selected_word", function(checked) {

View file

@ -45,6 +45,7 @@ define(function(require, exports, module) {
var Editor = require("ace/editor").Editor;
var Buffer = require("ace/model/buffer").Buffer;
var Window = require("ace/model/window").Window;
var UndoManager = require("ace/undomanager").UndoManager;
var Renderer = require("ace/view/window_view").WindowView;
@ -57,7 +58,7 @@ define(function(require, exports, module) {
doc.setUndoManager(new UndoManager());
el.innerHTML = '';
var editor = new Editor(new Renderer(el, require("ace/theme/textmate")));
var editor = new Editor(new Renderer(new Window(), el, require("ace/theme/textmate")));
editor.setSession(doc);
var env = {};

View file

@ -51,18 +51,20 @@ var MouseHandler = require("ace/mouse_handler").MouseHandler;
//var TouchHandler = require("ace/touch_handler").TouchHandler;
var KeyBinding = require("ace/keyboard/keybinding").KeyBinding;
var Buffer = require("ace/model/buffer").Buffer;
var Window = require("ace/model/window").Window;
var WindowController = require("ace/window_controller").WindowController;
var Search = require("ace/search").Search;
var Range = require("ace/range").Range;
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var CommandManager = require("ace/commands/command_manager").CommandManager;
var defaultCommands = require("ace/commands/default_commands").commands;
var Editor = function(renderer, buffer) {
var container = renderer.getContainerElement();
var Editor = function(windowView, buffer) {
var container = windowView.getContainerElement();
this.container = container;
this.renderer = renderer;
this.renderer = windowView;
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
this.textInput = new TextInput(windowView.getTextAreaContainer(), this);
this.keyBinding = new KeyBinding(this);
// TODO detect touch event support
@ -77,6 +79,9 @@ var Editor = function(renderer, buffer) {
wrap: true
});
this.windowModel = this.renderer.model;
this.windowController = new WindowController(this.windowModel, this.renderer);
this.commands = new CommandManager(defaultCommands);
this.setSession(buffer || new Buffer(""));
};
@ -615,30 +620,35 @@ var Editor = function(renderer, buffer) {
};
this.setShowInvisibles = function(showInvisibles) {
if (this.getShowInvisibles() == showInvisibles)
return;
this.renderer.setShowInvisibles(showInvisibles);
this.windowModel.setShowInvisibles(showInvisibles);
};
this.getShowInvisibles = function() {
return this.renderer.getShowInvisibles();
return this.windowModel.getShowInvisibles();
};
this.setShowPrintMargin = function(showPrintMargin) {
this.renderer.setShowPrintMargin(showPrintMargin);
this.windowModel.setShowPrintMargin(showPrintMargin);
};
this.getShowPrintMargin = function() {
return this.renderer.getShowPrintMargin();
return this.windowModel.getShowPrintMargin();
};
this.setPrintMarginColumn = function(showPrintMargin) {
this.renderer.setPrintMarginColumn(showPrintMargin);
this.windowModel.setPrintMarginColumn(showPrintMargin);
};
this.getPrintMarginColumn = function() {
return this.renderer.getPrintMarginColumn();
return this.windowModel.getPrintMarginColumn();
};
this.setShowGutter = function(showGutter) {
this.windowModel.setShowGutter(showGutter);
};
this.getShowGutter = function() {
return this.windowModel.getShowGutter();
};
this.$readOnly = false;

157
lib/ace/model/window.js Normal file
View file

@ -0,0 +1,157 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var lang = require("pilot/lang");
var EventEmitter = require("pilot/event_emitter").EventEmitter;
/**
* A window represents the viewport of a buffer
*
*
*/
var Window = exports.Window = function() {
this._buffer = null;
this.layerConfig = {
width : 1,
padding : 0,
firstRow : 0,
firstRowScreen: 0,
lastRow : 0,
lineHeight : 1,
characterWidth : 1,
minHeight : 1,
maxHeight : 1,
offset : 0,
height : 1
};
this.size = {
width: 0,
height: 0,
scrollerHeight: 0,
scrollerWidth: 0
};
this.showInvisibles = false;
this.showPrintMargin = true;
this.printMarginColumn = 80;
this.showGutter = true;
this.padding = 4;
};
(function() {
oop.implement(this, EventEmitter);
this.setBuffer = function(buffer) {
if (this._buffer === buffer)
return;
var oldValue = this._buffer;
this._buffer = buffer;
this._emit("changeBuffer", {oldValue: oldValue, value: buffer});
};
this.setShowInvisibles = function(showInvisibles) {
if (this.showInvisibles == showInvisibles)
return;
this.showInvisibles = showInvisibles;
this._emit("changeShowInvisibles");
};
this.getShowInvisibles = function() {
return this.showInvisibles;
};
this.setShowPrintMargin = function(showPrintMargin) {
if (this.showPrintMargin == showPrintMargin)
return;
this.showPrintMargin = showPrintMargin;
this._emit("changePrintMargin");
};
this.getShowPrintMargin = function() {
return this.showPrintMargin;
};
this.setPrintMarginColumn = function(printMarginColumn) {
if (this.printMarginColumn == printMarginColumn)
return;
this.printMarginColumn = printMarginColumn;
this._emit("changePrintMargin");
};
this.getPrintMarginColumn = function() {
return this.printMarginColumn;
};
this.setShowGutter = function(showGutter){
if(this.showGutter === showGutter)
return;
this.showGutter = showGutter;
this._emit("changeShowGutter");
};
this.getShowGutter = function(){
return this.showGutter;
};
this.setPadding = function(padding) {
if (this.padding == padding)
return;
this.padding = padding;
this._emit("changePadding");
};
this.getPadding = function() {
return this.padding;
}
}).call(Window.prototype);
});

View file

@ -0,0 +1,66 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../../support/paths");
require("ace/test/mockdom");
}
define(function(require, exports, module) {
var assert = require("ace/test/assertions");
var Window = require("ace/model/window").Window;
var Buffer = require("ace/model/buffer").Buffer;
module.exports = {
setUp: function() {
this.win = new Window();
},
"test setting a buffer chould emit a change event": function() {
assert.eventFired(this.win, "changeBuffer", function() {
this.win.setBuffer(new Buffer(""));
}, this);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs/test").testcase(module.exports).exec()
}

View file

@ -45,6 +45,7 @@ var EventEmitter = require("pilot/event_emitter").EventEmitter;
var Editor = require("ace/editor").Editor;
var Renderer = require("ace/view/window_view").WindowView;
var Window = require("ace/model/window").Window;
var Buffer = require("ace/model/buffer").Buffer;
var Split = function(container, theme, splits) {
@ -77,7 +78,7 @@ var Split = function(container, theme, splits) {
el.style.cssText = "position: absolute; top:0px; bottom:0px";
this.$container.appendChild(el);
var session = new Buffer("");
var editor = new Editor(new Renderer(el, this.$theme));
var editor = new Editor(new Renderer(new Window(), el, this.$theme));
editor.on("focus", function() {
this._emit("focus", editor);

View file

@ -41,7 +41,9 @@ define(function(require, exports, module) {
var dom = require("pilot/dom");
var Cursor = function(parentEl) {
var Cursor = function(model, parentEl) {
this.model = model;
this.element = dom.createElement("div");
this.element.className = "ace_layer ace_cursor-layer";
parentEl.appendChild(this.element);
@ -55,11 +57,6 @@ var Cursor = function(parentEl) {
(function() {
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
};
this.setSession = function(session) {
this.session = session;
};
@ -102,10 +99,12 @@ var Cursor = function(parentEl) {
var position = this.session.selection.getCursor();
var pos = this.session.documentToScreenPosition(position);
var cursorLeft = Math.round(this.$padding +
pos.column * this.config.characterWidth);
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
this.config.lineHeight;
var cursorLeft = Math.round(
this.model.padding
+ pos.column * this.config.characterWidth
);
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0))
* this.config.lineHeight;
return {
left : cursorLeft,

View file

@ -41,7 +41,9 @@ define(function(require, exports, module) {
var dom = require("pilot/dom");
var Gutter = function(parentEl) {
var Gutter = function(model, parentEl) {
this.model = model;
this.element = dom.createElement("div");
this.element.className = "ace_layer ace_gutter-layer";
parentEl.appendChild(this.element);

View file

@ -42,7 +42,9 @@ define(function(require, exports, module) {
var Range = require("ace/range").Range;
var dom = require("pilot/dom");
var Marker = function(parentEl) {
var Marker = function(model, parentEl) {
this.model = model;
this.element = dom.createElement("div");
this.element.className = "ace_layer ace_marker-layer";
parentEl.appendChild(this.element);
@ -50,11 +52,6 @@ var Marker = function(parentEl) {
(function() {
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
};
this.setSession = function(session) {
this.session = session;
};
@ -82,7 +79,7 @@ var Marker = function(parentEl) {
if (marker.renderer) {
var top = this.$getTop(range.start.row, config);
var left = Math.round(
this.$padding + range.start.column * config.characterWidth
this.model.padding + range.start.column * config.characterWidth
);
marker.renderer(html, range, left, top, config);
}
@ -141,7 +138,7 @@ var Marker = function(parentEl) {
*/
this.drawMultiLineMarker = function(stringBuilder, range, clazz, layerConfig, type) {
// from selection start to the end of the line
var padding = type === "background" ? 0 : this.$padding;
var padding = type === "background" ? 0 : this.model.padding;
var height = layerConfig.lineHeight;
var width = Math.round(layerConfig.width - (range.start.column * layerConfig.characterWidth));
var top = this.$getTop(range.start.row, layerConfig);
@ -189,7 +186,7 @@ var Marker = function(parentEl) {
* Draws a marker which covers one single full line
*/
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength, type) {
var padding = type === "background" ? 0 : this.$padding;
var padding = type === "background" ? 0 : this.model.padding;
var height = layerConfig.lineHeight;
if (type === "background")

View file

@ -46,7 +46,9 @@ var lang = require("pilot/lang");
var useragent = require("pilot/useragent");
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var Text = function(parentEl) {
var Text = function(model, parentEl) {
this.model = model;
this.element = dom.createElement("div");
this.element.className = "ace_layer ace_text-layer";
this.element.style.width = "auto";
@ -64,12 +66,6 @@ var Text = function(parentEl) {
this.EOL_CHAR = "&not;";
this.TAB_CHAR = "&rarr;";
this.SPACE_CHAR = "&middot;";
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
this.element.style.padding = "0 " + padding + "px";
};
this.getLineHeight = function() {
return this.$characterSize.height || 1;
@ -154,21 +150,12 @@ var Text = function(parentEl) {
this.session = session;
};
this.showInvisibles = false;
this.setShowInvisibles = function(showInvisibles) {
if (this.showInvisibles == showInvisibles)
return false;
this.showInvisibles = showInvisibles;
return true;
};
this.$tabStrings = [];
this.$computeTabString = function() {
var tabSize = this.session.getTabSize();
var tabStr = this.$tabStrings = [0];
for (var i = 1; i < tabSize + 1; i++) {
if (this.showInvisibles) {
if (this.model.showInvisibles) {
tabStr.push("<span class='ace_invisible'>"
+ this.TAB_CHAR
+ new Array(i).join("&#160;")
@ -369,7 +356,7 @@ var Text = function(parentEl) {
(self.config.characterWidth * 2) +
"px'>" + space + "</span>";
} else if (c.match(/[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]/)) {
if (self.showInvisibles) {
if (self.model.showInvisibles) {
var space = new Array(c.length+1).join(self.SPACE_CHAR);
return "<span class='ace_invisible'>" + space + "</span>";
} else {
@ -455,8 +442,8 @@ var Text = function(parentEl) {
}
}
if (this.showInvisibles) {
if (lastRow !== this.session.getLength() - 1)
if (this.model.showInvisibles) {
if (lastRow !== this.session.getLength() - 1) {
stringBuilder.push("<span class='ace_invisible'>" + this.EOL_CHAR + "</span>");
else
stringBuilder.push("<span class='ace_invisible'>" + this.EOF_CHAR + "</span>");

View file

@ -56,7 +56,8 @@ var editorCss = require("text!ace/view/css/editor.css");
// import CSS once
dom.importCssString(editorCss);
var WindowView = function(container, theme) {
var WindowView = function(windowModel, container, theme) {
this.model = windowModel;
this.container = container;
dom.addCssClass(this.container, "ace_editor");
@ -74,18 +75,18 @@ var WindowView = function(container, theme) {
this.content.className = "ace_content";
this.scroller.appendChild(this.content);
this.$gutterLayer = new GutterLayer(this.$gutter);
this.$markerBack = new MarkerLayer(this.content);
this.$gutterLayer = new GutterLayer(windowModel, this.$gutter);
this.$markerBack = new MarkerLayer(windowModel, this.content);
var textLayer = this.$textLayer = new TextLayer(this.content);
var textLayer = this.$textLayer = new TextLayer(windowModel, this.content);
this.canvas = textLayer.element;
this.$markerFront = new MarkerLayer(this.content);
this.$markerFront = new MarkerLayer(windowModel, this.content);
this.characterWidth = textLayer.getCharacterWidth();
this.lineHeight = textLayer.getLineHeight();
this.$cursorLayer = new CursorLayer(this.content);
this.$cursorLayer = new CursorLayer(windowModel, this.content);
this.$cursorPadding = 8;
// Indicates whether the horizontal scrollbar is visible
@ -106,45 +107,22 @@ var WindowView = function(container, theme) {
this.$textLayer.addEventListener("changeCharaterSize", function() {
_self.characterWidth = textLayer.getCharacterWidth();
_self.lineHeight = textLayer.getLineHeight();
_self.$updatePrintMargin();
_self.updatePrintMargin();
_self.onResize(true);
_self.$loop.schedule(_self.CHANGE_FULL);
});
event.addListener(this.$gutter, "click", this.$onGutterClick.bind(this));
event.addListener(this.$gutter, "dblclick", this.$onGutterClick.bind(this));
this.$size = {
width: 0,
height: 0,
scrollerHeight: 0,
scrollerWidth: 0
};
this.layerConfig = {
width : 1,
padding : 0,
firstRow : 0,
firstRowScreen: 0,
lastRow : 0,
lineHeight : 1,
characterWidth : 1,
minHeight : 1,
maxHeight : 1,
offset : 0,
height : 1
};
this.$loop = new RenderLoop(this.$renderChanges.bind(this));
this.$loop.schedule(this.CHANGE_FULL);
this.setPadding(4);
this.$updatePrintMargin();
this.updatePadding();
this.updatePrintMargin();
};
(function() {
this.showGutter = true;
this.CHANGE_CURSOR = 1;
this.CHANGE_MARKER = 2;
this.CHANGE_GUTTER = 4;
@ -214,8 +192,11 @@ var WindowView = function(container, theme) {
* Triggers resize of the editor
*/
this.onResize = function(force) {
if (! this.scroller || !this.container)
return;
var changes = this.CHANGE_SIZE;
var size = this.$size;
var size = this.model.size;
var height = dom.getInnerHeight(this.container);
if (force || size.height != height) {
@ -235,7 +216,7 @@ var WindowView = function(container, theme) {
if (force || size.width != width) {
size.width = width;
var gutterWidth = this.showGutter ? this.$gutter.offsetWidth : 0;
var gutterWidth = this.model.showGutter ? this.$gutter.offsetWidth : 0;
this.scroller.style.left = gutterWidth + "px";
size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBar.getWidth())
this.scroller.style.width = size.scrollerWidth + "px";
@ -248,7 +229,7 @@ var WindowView = function(container, theme) {
};
this.adjustWrapLimit = function(){
var availableWidth = this.$size.scrollerWidth - this.$padding * 2;
var availableWidth = this.model.size.scrollerWidth - this.model.padding * 2;
var limit = Math.floor(availableWidth / this.characterWidth) - 1;
return this.session.adjustWrapLimit(limit);
};
@ -263,51 +244,19 @@ var WindowView = function(container, theme) {
});
};
this.setShowInvisibles = function(showInvisibles) {
if (this.$textLayer.setShowInvisibles(showInvisibles))
this.$loop.schedule(this.CHANGE_TEXT);
this.updateShowInvisibles = function() {
this.$loop.schedule(this.CHANGE_TEXT);
};
this.getShowInvisibles = function() {
return this.$textLayer.showInvisibles;
};
this.$showPrintMargin = true;
this.setShowPrintMargin = function(showPrintMargin) {
this.$showPrintMargin = showPrintMargin;
this.$updatePrintMargin();
};
this.getShowPrintMargin = function() {
return this.$showPrintMargin;
};
this.$printMarginColumn = 80;
this.setPrintMarginColumn = function(showPrintMargin) {
this.$printMarginColumn = showPrintMargin;
this.$updatePrintMargin();
};
this.getPrintMarginColumn = function() {
return this.$printMarginColumn;
};
this.getShowGutter = function(){
return this.showGutter;
};
this.setShowGutter = function(show){
if(this.showGutter === show)
return;
this.$gutter.style.display = show ? "block" : "none";
this.showGutter = show;
this.updateShowGutter = function(){
this.$gutter.style.display = this.model.showGutter ? "block" : "none";
this.onResize(true);
};
this.$updatePrintMargin = function() {
this.updatePrintMargin = function() {
var containerEl;
if (!this.$showPrintMargin && !this.$printMarginEl)
if (!this.model.showPrintMargin && !this.$printMarginEl)
return;
if (!this.$printMarginEl) {
@ -320,8 +269,8 @@ var WindowView = function(container, theme) {
}
var style = this.$printMarginEl.style;
style.left = ((this.characterWidth * this.$printMarginColumn) + this.$padding * 2) + "px";
style.visibility = this.$showPrintMargin ? "visible" : "hidden";
style.left = ((this.characterWidth * this.model.printMarginColumn) + this.model.padding * 2) + "px";
style.visibility = this.model.showPrintMargin ? "visible" : "hidden";
};
this.getContainerElement = function() {
@ -346,38 +295,33 @@ var WindowView = function(container, theme) {
return;
var bounds = this.content.getBoundingClientRect();
var offset = this.layerConfig.offset;
var offset = this.model.layerConfig.offset;
textarea.style.left = (bounds.left + pos.left + this.$padding) + "px";
textarea.style.left = (bounds.left + pos.left + this.model.padding) + "px";
textarea.style.top = (bounds.top + pos.top - this.scrollTop + offset) + "px";
};
this.getFirstVisibleRow = function() {
return this.layerConfig.firstRow;
return this.model.layerConfig.firstRow;
};
this.getFirstFullyVisibleRow = function() {
return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1);
return this.model.layerConfig.firstRow + (this.model.layerConfig.offset === 0 ? 0 : 1);
};
this.getLastFullyVisibleRow = function() {
var flint = Math.floor((this.layerConfig.height + this.layerConfig.offset) / this.layerConfig.lineHeight);
return this.layerConfig.firstRow - 1 + flint;
var flint = Math.floor((this.model.layerConfig.height + this.model.layerConfig.offset) / this.model.layerConfig.lineHeight);
return this.model.layerConfig.firstRow - 1 + flint;
};
this.getLastVisibleRow = function() {
return this.layerConfig.lastRow;
return this.model.layerConfig.lastRow;
};
this.$padding = null;
this.setPadding = function(padding) {
this.$padding = padding;
this.$textLayer.setPadding(padding);
this.$cursorLayer.setPadding(padding);
this.$markerFront.setPadding(padding);
this.$markerBack.setPadding(padding);
this.updatePadding = function() {
this.$textLayer.element.style.padding = "0 " + this.model.padding + "px";
this.$loop.schedule(this.CHANGE_FULL);
this.$updatePrintMargin();
this.updatePrintMargin();
};
this.getHScrollBarAlwaysVisible = function() {
@ -397,7 +341,7 @@ var WindowView = function(container, theme) {
};
this.$updateScrollBar = function() {
this.scrollBar.setInnerHeight(this.layerConfig.maxHeight);
this.scrollBar.setInnerHeight(this.model.layerConfig.maxHeight);
this.scrollBar.setScrollTop(this.scrollTop);
};
@ -416,12 +360,12 @@ var WindowView = function(container, theme) {
// full
if (changes & this.CHANGE_FULL) {
this.$textLayer.update(this.layerConfig);
if (this.showGutter)
this.$gutterLayer.update(this.layerConfig);
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$textLayer.update(this.model.layerConfig);
if (this.model.showGutter)
this.$gutterLayer.update(this.model.layerConfig);
this.$markerBack.update(this.model.layerConfig);
this.$markerFront.update(this.model.layerConfig);
this.$cursorLayer.update(this.model.layerConfig);
this.$updateScrollBar();
return;
}
@ -429,43 +373,43 @@ var WindowView = function(container, theme) {
// scrolling
if (changes & this.CHANGE_SCROLL) {
if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES)
this.$textLayer.update(this.layerConfig);
this.$textLayer.update(this.model.layerConfig);
else
this.$textLayer.scrollLines(this.layerConfig);
this.$textLayer.scrollLines(this.model.layerConfig);
if (this.showGutter)
this.$gutterLayer.update(this.layerConfig);
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
if (this.model.showGutter)
this.$gutterLayer.update(this.model.layerConfig);
this.$markerBack.update(this.model.layerConfig);
this.$markerFront.update(this.model.layerConfig);
this.$cursorLayer.update(this.model.layerConfig);
this.$updateScrollBar();
return;
}
if (changes & this.CHANGE_TEXT) {
this.$textLayer.update(this.layerConfig);
if (this.showGutter)
this.$gutterLayer.update(this.layerConfig);
this.$textLayer.update(this.model.layerConfig);
if (this.model.showGutter)
this.$gutterLayer.update(this.model.layerConfig);
}
else if (changes & this.CHANGE_LINES) {
this.$updateLines();
this.$updateScrollBar();
if (this.showGutter)
this.$gutterLayer.update(this.layerConfig);
if (this.model.showGutter)
this.$gutterLayer.update(this.model.layerConfig);
} else if (changes & this.CHANGE_GUTTER) {
if (this.showGutter)
this.$gutterLayer.update(this.layerConfig);
if (this.model.showGutter)
this.$gutterLayer.update(this.model.layerConfig);
}
if (changes & this.CHANGE_CURSOR)
this.$cursorLayer.update(this.layerConfig);
this.$cursorLayer.update(this.model.layerConfig);
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
this.$markerFront.update(this.layerConfig);
this.$markerFront.update(this.model.layerConfig);
}
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) {
this.$markerBack.update(this.layerConfig);
this.$markerBack.update(this.model.layerConfig);
}
if (changes & this.CHANGE_SIZE)
@ -476,19 +420,19 @@ var WindowView = function(container, theme) {
var session = this.session;
var offset = this.scrollTop % this.lineHeight;
var minHeight = this.$size.scrollerHeight + this.lineHeight;
var minHeight = this.model.size.scrollerHeight + this.lineHeight;
var longestLine = this.$getLongestLine();
var widthChanged = this.layerConfig.width != longestLine;
var widthChanged = this.model.layerConfig.width != longestLine;
var horizScroll = this.$horizScrollAlwaysVisible || this.$size.scrollerWidth - longestLine < 0;
var horizScroll = this.$horizScrollAlwaysVisible || this.model.size.scrollerWidth - longestLine < 0;
var horizScrollChanged = this.$horizScroll !== horizScroll;
this.$horizScroll = horizScroll;
if (horizScrollChanged)
this.scroller.style.overflowX = horizScroll ? "scroll" : "hidden";
var maxHeight = this.session.getScreenLength() * this.lineHeight;
this.scrollTop = Math.max(0, Math.min(this.scrollTop, maxHeight - this.$size.scrollerHeight));
this.scrollTop = Math.max(0, Math.min(this.scrollTop, maxHeight - this.model.size.scrollerHeight));
var lineCount = Math.ceil(minHeight / this.lineHeight) - 1;
var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight));
@ -510,14 +454,14 @@ var WindowView = function(container, theme) {
firstRowHeight = session.getRowHeight(lineHeight, firstRow);
lastRow = Math.min(session.screenToDocumentRow(lastRow, 0), session.getLength() - 1);
minHeight = this.$size.scrollerHeight + session.getRowHeight(lineHeight, lastRow)+
minHeight = this.model.size.scrollerHeight + session.getRowHeight(lineHeight, lastRow)+
firstRowHeight;
offset = this.scrollTop - firstRowScreen * this.lineHeight;
this.layerConfig = {
this.model.layerConfig = {
width : longestLine,
padding : this.$padding,
padding : this.model.padding,
firstRow : firstRow,
firstRowScreen: firstRowScreen,
lastRow : lastRow,
@ -526,7 +470,7 @@ var WindowView = function(container, theme) {
minHeight : minHeight,
maxHeight : maxHeight,
offset : offset,
height : this.$size.scrollerHeight
height : this.model.size.scrollerHeight
};
// For debugging.
@ -554,7 +498,7 @@ var WindowView = function(container, theme) {
var lastRow = this.$changedLines.lastRow;
this.$changedLines = null;
var layerConfig = this.layerConfig;
var layerConfig = this.model.layerConfig;
// if the update changes the width of the document do a full redraw
if (layerConfig.width != this.$getLongestLine())
@ -565,7 +509,7 @@ var WindowView = function(container, theme) {
// if the last row is unknown -> redraw everything
if (lastRow === Infinity) {
if (this.showGutter)
if (this.model.showGutter)
this.$gutterLayer.update(layerConfig);
this.$textLayer.update(layerConfig);
return;
@ -577,10 +521,10 @@ var WindowView = function(container, theme) {
this.$getLongestLine = function() {
var charCount = this.session.getScreenWidth() + 1;
if (this.$textLayer.showInvisibles)
if (this.model.showInvisibles)
charCount += 1;
return Math.max(this.$size.scrollerWidth, Math.round(charCount * this.characterWidth));
return Math.max(this.model.size.scrollerWidth, Math.round(charCount * this.characterWidth));
};
this.updateFrontMarkers = function() {
@ -627,20 +571,20 @@ var WindowView = function(container, theme) {
this.scrollCursorIntoView = function() {
// the editor is not visible
if (this.$size.scrollerHeight === 0)
if (this.model.size.scrollerHeight === 0)
return;
var pos = this.$cursorLayer.getPixelPosition();
var left = pos.left + this.$padding;
var left = pos.left + this.model.padding;
var top = pos.top;
if (this.scrollTop > top) {
this.scrollToY(top);
}
if (this.scrollTop + this.$size.scrollerHeight < top + this.lineHeight) {
this.scrollToY(top + this.lineHeight - this.$size.scrollerHeight);
if (this.scrollTop + this.model.size.scrollerHeight < top + this.lineHeight) {
this.scrollToY(top + this.lineHeight - this.model.size.scrollerHeight);
}
var scrollLeft = this.scroller.scrollLeft;
@ -649,11 +593,11 @@ var WindowView = function(container, theme) {
this.scrollToX(left);
}
if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) {
if (left > this.layerConfig.width)
if (scrollLeft + this.model.size.scrollerWidth < left + this.characterWidth) {
if (left > this.model.layerConfig.width)
this.$desiredScrollLeft = left + 2 * this.characterWidth;
else
this.scrollToX(Math.round(left + this.characterWidth - this.$size.scrollerWidth));
this.scrollToX(Math.round(left + this.characterWidth - this.model.size.scrollerWidth));
}
};
@ -670,7 +614,7 @@ var WindowView = function(container, theme) {
};
this.getScrollBottomRow = function() {
return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1);
return Math.max(0, Math.floor((this.scrollTop + this.model.size.scrollerHeight) / this.lineHeight) - 1);
};
this.scrollToRow = function(row) {
@ -685,7 +629,7 @@ var WindowView = function(container, theme) {
}
if (center) {
offset -= this.$size.scrollerHeight / 2;
offset -= this.model.size.scrollerHeight / 2;
}
this.scrollToY(offset);
};
@ -701,7 +645,7 @@ var WindowView = function(container, theme) {
};
this.scrollToX = function(scrollLeft) {
if (scrollLeft <= this.$padding)
if (scrollLeft <= this.model.padding)
scrollLeft = 0;
this.scroller.scrollLeft = scrollLeft;
@ -715,7 +659,7 @@ var WindowView = function(container, theme) {
this.screenToTextCoordinates = function(pageX, pageY) {
var canvasPos = this.scroller.getBoundingClientRect();
var col = Math.round((pageX + this.scroller.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft())
var col = Math.round((pageX + this.scroller.scrollLeft - canvasPos.left - this.model.padding - dom.getPageScrollLeft())
/ this.characterWidth);
var row = Math.floor((pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop())
/ this.lineHeight);
@ -727,7 +671,7 @@ var WindowView = function(container, theme) {
var canvasPos = this.scroller.getBoundingClientRect();
var pos = this.session.documentToScreenPosition(row, column);
var x = this.$padding + Math.round(pos.column * this.characterWidth);
var x = this.model.padding + Math.round(pos.column * this.characterWidth);
var y = pos.row * this.lineHeight;
return {
@ -756,7 +700,7 @@ var WindowView = function(container, theme) {
var pos = this.$cursorLayer.getPixelPosition();
var style = this.$composition.style;
style.top = pos.top + "px";
style.left = (pos.left + this.$padding) + "px";
style.left = (pos.left + this.model.padding) + "px";
style.height = this.lineHeight + "px";
this.hideCursor();
@ -781,16 +725,16 @@ var WindowView = function(container, theme) {
var _self = this;
this.$themeValue = theme;
if (!theme || typeof theme == "string") {
theme = theme || "ace/theme/textmate";
require([theme], function(theme) {
afterLoad(theme);
});
} else {
afterLoad(theme);
}
function afterLoad(theme) {
(function(next) {
if (!theme || typeof theme == "string") {
theme = theme || "ace/theme/textmate";
require([theme], function(theme) {
next(theme);
});
} else {
next(theme);
}
})(function next(theme) {
if (_self.$theme)
dom.removeCssClass(_self.container, _self.$theme);
@ -800,11 +744,11 @@ var WindowView = function(container, theme) {
dom.addCssClass(_self.container, _self.$theme);
// force re-measure of the gutter width
if (_self.$size) {
_self.$size.width = 0;
if (_self.model.size) {
_self.model.size.width = 0;
_self.onResize();
}
}
});
};
this.getTheme = function() {

View file

@ -44,6 +44,8 @@ define(function(require, exports, module) {
var Buffer = require("ace/model/buffer").Buffer;
var WindowView = require("ace/view/window_view").WindowView;
var Window = require("ace/model/window").Window;
var assert = require("ace/test/assertions");
module.exports = {
@ -63,7 +65,7 @@ module.exports = {
document.body.style.padding = "0px";
document.body.appendChild(el);
var renderer = new WindowView(el);
var renderer = new WindowView(new Window(), el);
renderer.setPadding(0);
renderer.setSession(new Buffer("1234"));

View file

@ -0,0 +1,54 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var WindowController = exports.WindowController = function(model, view) {
this.model = model;
this.view = view;
model.on("changeShowInvisibles", view.updateShowInvisibles.bind(view));
model.on("changePrintMargin", view.updatePrintMargin.bind(view));
model.on("changeShowGutter", view.updateShowGutter.bind(view));
model.on("changePadding", view.updatePadding.bind(view));
};
(function() {
}).call(WindowController.prototype);
});