diff --git a/build_support/boot_textarea.js b/build_support/boot_textarea.js index c3e8b03a..9fdeb8c9 100644 --- a/build_support/boot_textarea.js +++ b/build_support/boot_textarea.js @@ -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; diff --git a/demo/demo.js b/demo/demo.js index 25daf764..84208d56 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -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) { diff --git a/lib/ace/ace.js b/lib/ace/ace.js index 3be0b533..b0f4accf 100644 --- a/lib/ace/ace.js +++ b/lib/ace/ace.js @@ -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 = {}; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 51131d0b..45f9cd56 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -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; diff --git a/lib/ace/model/window.js b/lib/ace/model/window.js new file mode 100644 index 00000000..ff5b775d --- /dev/null +++ b/lib/ace/model/window.js @@ -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 + * + * 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); + +}); \ No newline at end of file diff --git a/lib/ace/model/window_test.js b/lib/ace/model/window_test.js new file mode 100644 index 00000000..7077a5ba --- /dev/null +++ b/lib/ace/model/window_test.js @@ -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 + * + * 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() +} \ No newline at end of file diff --git a/lib/ace/split.js b/lib/ace/split.js index 9a6bb380..9c29513c 100644 --- a/lib/ace/split.js +++ b/lib/ace/split.js @@ -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); diff --git a/lib/ace/view/layer/cursor.js b/lib/ace/view/layer/cursor.js index c6908039..14816cf6 100644 --- a/lib/ace/view/layer/cursor.js +++ b/lib/ace/view/layer/cursor.js @@ -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, diff --git a/lib/ace/view/layer/gutter.js b/lib/ace/view/layer/gutter.js index 190fa6f1..08a5f653 100644 --- a/lib/ace/view/layer/gutter.js +++ b/lib/ace/view/layer/gutter.js @@ -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); diff --git a/lib/ace/view/layer/marker.js b/lib/ace/view/layer/marker.js index cd57d94b..a7a287f0 100644 --- a/lib/ace/view/layer/marker.js +++ b/lib/ace/view/layer/marker.js @@ -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") diff --git a/lib/ace/view/layer/text.js b/lib/ace/view/layer/text.js index b251d9bb..d5572a50 100644 --- a/lib/ace/view/layer/text.js +++ b/lib/ace/view/layer/text.js @@ -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 = "¬"; this.TAB_CHAR = "→"; this.SPACE_CHAR = "·"; - 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("" + this.TAB_CHAR + new Array(i).join(" ") @@ -369,7 +356,7 @@ var Text = function(parentEl) { (self.config.characterWidth * 2) + "px'>" + space + ""; } 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 "" + space + ""; } 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("" + this.EOL_CHAR + ""); else stringBuilder.push("" + this.EOF_CHAR + ""); diff --git a/lib/ace/view/window_view.js b/lib/ace/view/window_view.js index 15d9c9e1..bfcff423 100644 --- a/lib/ace/view/window_view.js +++ b/lib/ace/view/window_view.js @@ -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() { diff --git a/lib/ace/view/window_view_test.js b/lib/ace/view/window_view_test.js index 2e9739f0..8a59e820 100644 --- a/lib/ace/view/window_view_test.js +++ b/lib/ace/view/window_view_test.js @@ -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")); diff --git a/lib/ace/window_controller.js b/lib/ace/window_controller.js new file mode 100644 index 00000000..823f18ac --- /dev/null +++ b/lib/ace/window_controller.js @@ -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 + * + * 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); + +}); \ No newline at end of file