diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 6efa58d7d6..049a09d320 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -46,8 +46,7 @@ class VirtualRenderer { if (dom.HI_DPI) dom.addCssClass(this.container, "ace_hidpi"); this.setTheme(theme); - if (config.get("useStrictCSP") == null) - config.set("useStrictCSP", false); + if (config.get("useStrictCSP") == null) config.set("useStrictCSP", false); this.$gutter = dom.createElement("div"); this.$gutter.className = "ace_gutter"; @@ -67,7 +66,7 @@ class VirtualRenderer { this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this)); this.$markerBack = new MarkerLayer(this.content); - var textLayer = this.$textLayer = new TextLayer(this.content); + var textLayer = (this.$textLayer = new TextLayer(this.content)); this.canvas = textLayer.element; this.$markerFront = new MarkerLayer(this.content); @@ -78,29 +77,26 @@ class VirtualRenderer { this.$horizScroll = false; this.$vScroll = false; - this.scrollBar = - this.scrollBarV = new VScrollBar(this.container, this); + this.scrollBar = this.scrollBarV = new VScrollBar(this.container, this); this.scrollBarH = new HScrollBar(this.container, this); - this.scrollBarV.on("scroll", function(e) { - if (!_self.$scrollAnimation) - _self.session.setScrollTop(e.data - _self.scrollMargin.top); + this.scrollBarV.on("scroll", function (e) { + if (!_self.$scrollAnimation) _self.session.setScrollTop(e.data - _self.scrollMargin.top); }); - this.scrollBarH.on("scroll", function(e) { - if (!_self.$scrollAnimation) - _self.session.setScrollLeft(e.data - _self.scrollMargin.left); + this.scrollBarH.on("scroll", function (e) { + if (!_self.$scrollAnimation) _self.session.setScrollLeft(e.data - _self.scrollMargin.left); }); this.scrollTop = 0; this.scrollLeft = 0; this.cursorPos = { - row : 0, - column : 0 + row: 0, + column: 0 }; this.$fontMetrics = new FontMetrics(this.container); this.$textLayer.$setFontMetrics(this.$fontMetrics); - this.$textLayer.on("changeCharacterSize", function(e) { + this.$textLayer.on("changeCharacterSize", function (e) { _self.updateCharacterSize(); _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); _self._signal("changeCharacterSize", e); @@ -115,17 +111,17 @@ class VirtualRenderer { }; this.layerConfig = { - width : 1, - padding : 0, - firstRow : 0, + width: 1, + padding: 0, + firstRow: 0, firstRowScreen: 0, - lastRow : 0, - lineHeight : 0, - characterWidth : 0, - minHeight : 1, - maxHeight : 1, - offset : 0, - height : 1, + lastRow: 0, + lineHeight: 0, + characterWidth: 0, + minHeight: 1, + maxHeight: 1, + offset: 0, + height: 1, gutterOffset: 1 }; @@ -149,10 +145,7 @@ class VirtualRenderer { this.$keepTextAreaAtCursor = !useragent.isIOS; - this.$loop = new RenderLoop( - this.$renderChanges.bind(this), - this.container.ownerDocument.defaultView - ); + this.$loop = new RenderLoop(this.$renderChanges.bind(this), this.container.ownerDocument.defaultView); this.$loop.schedule(this.CHANGE_FULL); this.updateCharacterSize(); @@ -162,7 +155,6 @@ class VirtualRenderer { config._signal("renderer", this); } - // this.$logChanges = function(changes) { // var a = "" // if (changes & this.CHANGE_CURSOR) a += " cursor"; @@ -187,10 +179,8 @@ class VirtualRenderer { this.setStyle("ace_nobold", !this.$allowBoldFonts); } - this.layerConfig.characterWidth = - this.characterWidth = this.$textLayer.getCharacterWidth(); - this.layerConfig.lineHeight = - this.lineHeight = this.$textLayer.getLineHeight(); + this.layerConfig.characterWidth = this.characterWidth = this.$textLayer.getCharacterWidth(); + this.layerConfig.lineHeight = this.lineHeight = this.$textLayer.getLineHeight(); this.$updatePrintMargin(); // set explicit line height to avoid normal resolving to different values based on text dom.setStyle(this.scroller.style, "line-height", this.lineHeight + "px"); @@ -202,8 +192,7 @@ class VirtualRenderer { * @param {EditSession} session The session to associate with **/ setSession(session) { - if (this.session) - this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); + if (this.session) this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); this.session = session; if (session && this.scrollMargin.top && session.getScrollTop() <= 0) @@ -214,8 +203,7 @@ class VirtualRenderer { this.$markerFront.setSession(session); this.$gutterLayer.setSession(session); this.$textLayer.setSession(session); - if (!session) - return; + if (!session) return; this.$loop.schedule(this.CHANGE_FULL); this.session.$setFontMetrics(this.$fontMetrics); @@ -233,21 +221,17 @@ class VirtualRenderer { * @param {boolean} [force] **/ updateLines(firstRow, lastRow, force) { - if (lastRow === undefined) - lastRow = Infinity; + if (lastRow === undefined) lastRow = Infinity; if (!this.$changedLines) { this.$changedLines = { firstRow: firstRow, lastRow: lastRow }; - } - else { - if (this.$changedLines.firstRow > firstRow) - this.$changedLines.firstRow = firstRow; + } else { + if (this.$changedLines.firstRow > firstRow) this.$changedLines.firstRow = firstRow; - if (this.$changedLines.lastRow < lastRow) - this.$changedLines.lastRow = lastRow; + if (this.$changedLines.lastRow < lastRow) this.$changedLines.lastRow = lastRow; } // If the change happened offscreen above us then it's possible @@ -255,13 +239,10 @@ class VirtualRenderer { // screen so they need redrawn. // TODO: better solution is to not change scroll position when text is changed outside of visible area if (this.$changedLines.lastRow < this.layerConfig.firstRow) { - if (force) - this.$changedLines.lastRow = this.layerConfig.lastRow; - else - return; + if (force) this.$changedLines.lastRow = this.layerConfig.lastRow; + else return; } - if (this.$changedLines.firstRow > this.layerConfig.lastRow) - return; + if (this.$changedLines.firstRow > this.layerConfig.lastRow) return; this.$loop.schedule(this.CHANGE_LINES); } @@ -295,10 +276,8 @@ class VirtualRenderer { **/ updateFull(force) { - if (force) - this.$renderChanges(this.CHANGE_FULL, true); - else - this.$loop.schedule(this.CHANGE_FULL); + if (force) this.$renderChanges(this.CHANGE_FULL, true); + else this.$loop.schedule(this.CHANGE_FULL); } /** @@ -309,10 +288,8 @@ class VirtualRenderer { } $updateSizeAsync() { - if (this.$loop.pending) - this.$size.$dirty = true; - else - this.onResize(); + if (this.$loop.pending) this.$size.$dirty = true; + else this.onResize(); } /** * [Triggers a resize of the editor.]{: #VirtualRenderer.onResize} @@ -323,17 +300,13 @@ class VirtualRenderer { * @internal **/ onResize(force, gutterWidth, width, height) { - if (this.resizing > 2) - return; - else if (this.resizing > 0) - this.resizing++; - else - this.resizing = force ? 1 : 0; + if (this.resizing > 2) return; + else if (this.resizing > 0) this.resizing++; + else this.resizing = force ? 1 : 0; // `|| el.scrollHeight` is required for autosizing editors on ie // where elements with clientHeight = 0 also have clientWidth = 0 var el = this.container; - if (!height) - height = el.clientHeight || el.scrollHeight; + if (!height) height = el.clientHeight || el.scrollHeight; if (!height && this.$maxLines && this.lineHeight > 1) { // if we are supposed to fit to content set height at least to 1 // so that render does not exit early before calling $autosize @@ -342,25 +315,19 @@ class VirtualRenderer { height = el.clientHeight || el.scrollHeight; } } - if (!width) - width = el.clientWidth || el.scrollWidth; + if (!width) width = el.clientWidth || el.scrollWidth; var changes = this.$updateCachedSize(force, gutterWidth, width, height); if (this.$resizeTimer) this.$resizeTimer.cancel(); - if (!this.$size.scrollerHeight || (!width && !height)) - return this.resizing = 0; + if (!this.$size.scrollerHeight || (!width && !height)) return (this.resizing = 0); - if (force) - this.$gutterLayer.$padding = null; + if (force) this.$gutterLayer.$padding = null; - if (force) - this.$renderChanges(changes | this.$changes, true); - else - this.$loop.schedule(changes | this.$changes); + if (force) this.$renderChanges(changes | this.$changes, true); + else this.$loop.schedule(changes | this.$changes); - if (this.resizing) - this.resizing = 0; + if (this.resizing) this.resizing = 0; // reset cached values on scrollbars, needs to be removed when switching to non-native scrollbars // see https://github.com/ajaxorg/ace/issues/2195 this.scrollBarH.scrollLeft = this.scrollBarV.scrollTop = null; @@ -378,7 +345,7 @@ class VirtualRenderer { */ $updateCachedSize(force, gutterWidth, width, height) { - height -= (this.$extraHeight || 0); + height -= this.$extraHeight || 0; var changes = 0; var size = this.$size; var oldSize = { @@ -392,8 +359,7 @@ class VirtualRenderer { changes |= this.CHANGE_SIZE; size.scrollerHeight = size.height; - if (this.$horizScroll) - size.scrollerHeight -= this.scrollBarH.getHeight(); + if (this.$horizScroll) size.scrollerHeight -= this.scrollBarH.getHeight(); this.scrollBarV.setHeight(size.scrollerHeight); this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; @@ -405,8 +371,7 @@ class VirtualRenderer { changes |= this.CHANGE_SIZE; size.width = width; - if (gutterWidth == null) - gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; + if (gutterWidth == null) gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; this.gutterWidth = gutterWidth; @@ -422,15 +387,14 @@ class VirtualRenderer { this.scrollBarH.setWidth(size.scrollerWidth); - if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) { + if ((this.session && this.session.getUseWrapMode() && this.adjustWrapLimit()) || force) { changes |= this.CHANGE_FULL; } } size.$dirty = !width || !height; - if (changes) - this._signal("resize", oldSize); + if (changes) this._signal("resize", oldSize); return changes; } @@ -469,7 +433,7 @@ class VirtualRenderer { * @param {Boolean} shouldAnimate Set to `true` to show animated scrolls **/ - setAnimatedScroll(shouldAnimate){ + setAnimatedScroll(shouldAnimate) { this.setOption("animatedScroll", shouldAnimate); } @@ -573,7 +537,7 @@ class VirtualRenderer { * @returns {Boolean} **/ - getShowGutter(){ + getShowGutter() { return this.getOption("showGutter"); } @@ -582,7 +546,7 @@ class VirtualRenderer { * @param {Boolean} show Set to `true` to show the gutter **/ - setShowGutter(show){ + setShowGutter(show) { return this.setOption("showGutter", show); } @@ -590,7 +554,7 @@ class VirtualRenderer { * @returns {boolean} */ - getFadeFoldWidgets(){ + getFadeFoldWidgets() { return this.getOption("fadeFoldWidgets"); } @@ -603,7 +567,7 @@ class VirtualRenderer { } /** - * + * * @param {boolean} shouldHighlight */ setHighlightGutterLine(shouldHighlight) { @@ -622,8 +586,7 @@ class VirtualRenderer { */ $updatePrintMargin() { - if (!this.$showPrintMargin && !this.$printMarginEl) - return; + if (!this.$showPrintMargin && !this.$printMarginEl) return; if (!this.$printMarginEl) { var containerEl = dom.createElement("div"); @@ -638,8 +601,7 @@ class VirtualRenderer { style.left = Math.round(this.characterWidth * this.$printMarginColumn + this.$padding) + "px"; style.visibility = this.$showPrintMargin ? "visible" : "hidden"; - if (this.session && this.session.$wrap == -1) - this.adjustWrapLimit(); + if (this.session && this.session.$wrap == -1) this.adjustWrapLimit(); } /** @@ -683,8 +645,7 @@ class VirtualRenderer { return; } var pixelPos = this.$cursorLayer.$pixelPos; - if (!pixelPos) - return; + if (!pixelPos) return; if (composition && composition.markerRange) pixelPos = this.$cursorLayer.getPixelPosition(composition.markerRange.start, true); @@ -693,7 +654,7 @@ class VirtualRenderer { var posLeft = pixelPos.left; posTop -= config.offset; - var h = composition && composition.useTextareaForIME || useragent.isMobile ? this.lineHeight : 1; + var h = (composition && composition.useTextareaForIME) || useragent.isMobile ? this.lineHeight : 1; if (posTop < 0 || posTop > config.height - h) { dom.translate(this.textarea, 0, 0); return; @@ -703,20 +664,17 @@ class VirtualRenderer { var maxTop = this.$size.height - h; if (!composition) { posTop += this.lineHeight; - } - else { + } else { if (composition.useTextareaForIME) { var val = this.textarea.value; - w = this.characterWidth * (this.session.$getStringScreenWidth(val)[0]); - } - else { + w = this.characterWidth * this.session.$getStringScreenWidth(val)[0]; + } else { posTop += this.lineHeight + 2; } } posLeft -= this.scrollLeft; - if (posLeft > this.$size.scrollerWidth - w) - posLeft = this.$size.scrollerWidth - w; + if (posLeft > this.$size.scrollerWidth - w) posLeft = this.$size.scrollerWidth - w; posLeft += this.gutterWidth + this.margin.left; @@ -751,8 +709,7 @@ class VirtualRenderer { var config = this.layerConfig; var lastRow = config.lastRow; var top = this.session.documentToScreenRow(lastRow, 0) * config.lineHeight; - if (top - this.session.getScrollTop() > config.height - config.lineHeight) - return lastRow - 1; + if (top - this.session.getScrollTop() > config.height - config.lineHeight) return lastRow - 1; return lastRow; } @@ -790,14 +747,13 @@ class VirtualRenderer { */ setScrollMargin(top, bottom, left, right) { var sm = this.scrollMargin; - sm.top = top|0; - sm.bottom = bottom|0; - sm.right = right|0; - sm.left = left|0; + sm.top = top | 0; + sm.bottom = bottom | 0; + sm.right = right | 0; + sm.left = left | 0; sm.v = sm.top + sm.bottom; sm.h = sm.left + sm.right; - if (sm.top && this.scrollTop <= 0 && this.session) - this.session.setScrollTop(-sm.top); + if (sm.top && this.scrollTop <= 0 && this.session) this.session.setScrollTop(-sm.top); this.updateFull(); } @@ -811,10 +767,10 @@ class VirtualRenderer { */ setMargin(top, bottom, left, right) { var sm = this.margin; - sm.top = top|0; - sm.bottom = bottom|0; - sm.right = right|0; - sm.left = left|0; + sm.top = top | 0; + sm.bottom = bottom | 0; + sm.right = right | 0; + sm.left = left | 0; sm.v = sm.top + sm.bottom; sm.h = sm.left + sm.right; this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); @@ -896,7 +852,7 @@ class VirtualRenderer { changes |= this.$changes; this.$changes = 0; } - if ((!this.session || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) { + if (!this.session || !this.container.offsetWidth || this.$frozen || (!changes && !force)) { this.$changes |= changes; return; } @@ -916,7 +872,8 @@ class VirtualRenderer { var config = this.layerConfig; // text, scrolling and resize changes can cause the view port size to change - if (changes & this.CHANGE_FULL || + if ( + changes & this.CHANGE_FULL || changes & this.CHANGE_SIZE || changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES || @@ -929,7 +886,10 @@ class VirtualRenderer { // have changed, but the first actual row will. In that case, adjust // scrollTop so that the cursor and onscreen content stays in the same place. // TODO: find a better way to handle this, that works non wrapped case and doesn't compute layerConfig twice - if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) { + if ( + config.firstRow != this.layerConfig.firstRow && + config.firstRowScreen == this.layerConfig.firstRowScreen + ) { var st = this.scrollTop + (config.firstRow - Math.max(this.layerConfig.firstRow, 0)) * this.lineHeight; if (st > 0) { // this check is needed as a workaround for the documentToScreenRow returning -1 if document.length == 0 @@ -941,8 +901,7 @@ class VirtualRenderer { config = this.layerConfig; // update scrollbar first to not lose scroll position when gutter calls resize this.$updateScrollBarV(); - if (changes & this.CHANGE_H_SCROLL) - this.$updateScrollBarH(); + if (changes & this.CHANGE_H_SCROLL) this.$updateScrollBarH(); dom.translate(this.content, -this.scrollLeft, -config.offset); @@ -957,16 +916,14 @@ class VirtualRenderer { if (changes & this.CHANGE_H_SCROLL) { dom.translate(this.content, -this.scrollLeft, -config.offset); this.scroller.className = this.scrollLeft <= 0 ? "ace_scroller " : "ace_scroller ace_scroll-left "; - if (this.enableKeyboardAccessibility) - this.scroller.className += this.keyboardFocusClassName; + if (this.enableKeyboardAccessibility) this.scroller.className += this.keyboardFocusClassName; } // full if (changes & this.CHANGE_FULL) { this.$changedLines = null; this.$textLayer.update(config); - if (this.$showGutter) - this.$gutterLayer.update(config); + if (this.$showGutter) this.$gutterLayer.update(config); if (this.$customScrollbar) { this.$scrollDecorator.$updateDecorators(config); } @@ -981,16 +938,12 @@ class VirtualRenderer { // scrolling if (changes & this.CHANGE_SCROLL) { this.$changedLines = null; - if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) - this.$textLayer.update(config); - else - this.$textLayer.scrollLines(config); + if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) this.$textLayer.update(config); + else this.$textLayer.scrollLines(config); if (this.$showGutter) { - if (changes & this.CHANGE_GUTTER || changes & this.CHANGE_LINES) - this.$gutterLayer.update(config); - else - this.$gutterLayer.scrollLines(config); + if (changes & this.CHANGE_GUTTER || changes & this.CHANGE_LINES) this.$gutterLayer.update(config); + else this.$gutterLayer.scrollLines(config); } if (this.$customScrollbar) { this.$scrollDecorator.$updateDecorators(config); @@ -1006,27 +959,22 @@ class VirtualRenderer { if (changes & this.CHANGE_TEXT) { this.$changedLines = null; this.$textLayer.update(config); - if (this.$showGutter) - this.$gutterLayer.update(config); + if (this.$showGutter) this.$gutterLayer.update(config); if (this.$customScrollbar) { this.$scrollDecorator.$updateDecorators(config); } - } - else if (changes & this.CHANGE_LINES) { - if (this.$updateLines() || (changes & this.CHANGE_GUTTER) && this.$showGutter) + } else if (changes & this.CHANGE_LINES) { + if (this.$updateLines() || (changes & this.CHANGE_GUTTER && this.$showGutter)) this.$gutterLayer.update(config); if (this.$customScrollbar) { this.$scrollDecorator.$updateDecorators(config); } - } - else if (changes & this.CHANGE_TEXT || changes & this.CHANGE_GUTTER) { - if (this.$showGutter) - this.$gutterLayer.update(config); + } else if (changes & this.CHANGE_TEXT || changes & this.CHANGE_GUTTER) { + if (this.$showGutter) this.$gutterLayer.update(config); if (this.$customScrollbar) { this.$scrollDecorator.$updateDecorators(config); } - } - else if (changes & this.CHANGE_CURSOR) { + } else if (changes & this.CHANGE_CURSOR) { if (this.$highlightGutterLine) // @ts-expect-error TODO: potential wrong param this.$gutterLayer.updateLineHighlight(config); @@ -1057,19 +1005,21 @@ class VirtualRenderer { $autosize() { var height = this.session.getScreenLength() * this.lineHeight; var maxHeight = this.$maxLines * this.lineHeight; - var desiredHeight = Math.min(maxHeight, - Math.max((this.$minLines || 1) * this.lineHeight, height) - ) + this.scrollMargin.v + (this.$extraHeight || 0); - if (this.$horizScroll) - desiredHeight += this.scrollBarH.getHeight(); - if (this.$maxPixelHeight && desiredHeight > this.$maxPixelHeight) - desiredHeight = this.$maxPixelHeight; + var desiredHeight = + Math.min(maxHeight, Math.max((this.$minLines || 1) * this.lineHeight, height)) + + this.scrollMargin.v + + (this.$extraHeight || 0); + if (this.$horizScroll) desiredHeight += this.scrollBarH.getHeight(); + if (this.$maxPixelHeight && desiredHeight > this.$maxPixelHeight) desiredHeight = this.$maxPixelHeight; var hideScrollbars = desiredHeight <= 2 * this.lineHeight; var vScroll = !hideScrollbars && height > maxHeight; - if (desiredHeight != this.desiredHeight || - this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { + if ( + desiredHeight != this.desiredHeight || + this.$size.height != this.desiredHeight || + vScroll != this.$vScroll + ) { if (vScroll != this.$vScroll) { this.$vScroll = vScroll; this.scrollBarV.setVisible(vScroll); @@ -1099,8 +1049,9 @@ class VirtualRenderer { var longestLine = this.$getLongestLine(); - var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || - size.scrollerWidth - longestLine - 2 * this.$padding < 0); + var horizScroll = + !hideScrollbars && + (this.$hScrollBarAlwaysVisible || size.scrollerWidth - longestLine - 2 * this.$padding < 0); var hScrollChanged = this.$horizScroll !== horizScroll; if (hScrollChanged) { @@ -1109,25 +1060,35 @@ class VirtualRenderer { } var vScrollBefore = this.$vScroll; // autosize can change vscroll value in which case we need to update longestLine // autoresize only after updating hscroll to include scrollbar height in desired height - if (this.$maxLines && this.lineHeight > 1) + if (this.$maxLines && this.lineHeight > 1) { this.$autosize(); + // recalculate this after $autosize so we take vertical scroll into account when calculating width + hideScrollbars = size.height <= 2 * this.lineHeight; + } var minHeight = size.scrollerHeight + this.lineHeight; - var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd - ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd - : 0; + var scrollPastEnd = + !this.$maxLines && this.$scrollPastEnd ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd : 0; maxHeight += scrollPastEnd; var sm = this.scrollMargin; - this.session.setScrollTop(Math.max(-sm.top, - Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom))); + this.session.setScrollTop( + Math.max(-sm.top, Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom)) + ); - this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft, - longestLine + 2 * this.$padding - size.scrollerWidth + sm.right))); + this.session.setScrollLeft( + Math.max( + -sm.left, + Math.min(this.scrollLeft, longestLine + 2 * this.$padding - size.scrollerWidth + sm.right) + ) + ); - var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || - size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop > sm.top); + var vScroll = + !hideScrollbars && + (this.$vScrollBarAlwaysVisible || + size.scrollerHeight - maxHeight + scrollPastEnd < 0 || + this.scrollTop > sm.top); var vScrollChanged = vScrollBefore !== vScroll; if (vScrollChanged) { this.$vScroll = vScroll; @@ -1155,40 +1116,38 @@ class VirtualRenderer { firstRowHeight = session.getRowLength(firstRow) * lineHeight; lastRow = Math.min(session.screenToDocumentRow(lastRow, 0), session.getLength() - 1); - minHeight = size.scrollerHeight + session.getRowLength(lastRow) * lineHeight + - firstRowHeight; + minHeight = size.scrollerHeight + session.getRowLength(lastRow) * lineHeight + firstRowHeight; offset = this.scrollTop - firstRowScreen * lineHeight; var changes = 0; - if (this.layerConfig.width != longestLine || hScrollChanged) - changes = this.CHANGE_H_SCROLL; + if (this.layerConfig.width != longestLine || hScrollChanged) changes = this.CHANGE_H_SCROLL; // Horizontal scrollbar visibility may have changed, which changes // the client height of the scroller if (hScrollChanged || vScrollChanged) { changes |= this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); this._signal("scrollbarVisibilityChanged"); - if (vScrollChanged) - longestLine = this.$getLongestLine(); + if (vScrollChanged) longestLine = this.$getLongestLine(); } this.layerConfig = { - width : longestLine, - padding : this.$padding, - firstRow : firstRow, + width: longestLine, + padding: this.$padding, + firstRow: firstRow, firstRowScreen: firstRowScreen, - lastRow : lastRow, - lineHeight : lineHeight, - characterWidth : this.characterWidth, - minHeight : minHeight, - maxHeight : maxHeight, - offset : offset, - gutterOffset : lineHeight ? Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)) : 0, - height : this.$size.scrollerHeight + lastRow: lastRow, + lineHeight: lineHeight, + characterWidth: this.characterWidth, + minHeight: minHeight, + maxHeight: maxHeight, + offset: offset, + gutterOffset: lineHeight + ? Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)) + : 0, + height: this.$size.scrollerHeight }; - if (this.session.$bidiHandler) - this.session.$bidiHandler.setContentWidth(longestLine - this.$padding); + if (this.session.$bidiHandler) this.session.$bidiHandler.setContentWidth(longestLine - this.$padding); // For debugging. // console.log(JSON.stringify(this.layerConfig)); @@ -1207,13 +1166,16 @@ class VirtualRenderer { var layerConfig = this.layerConfig; - if (firstRow > layerConfig.lastRow + 1) { return; } - if (lastRow < layerConfig.firstRow) { return; } + if (firstRow > layerConfig.lastRow + 1) { + return; + } + if (lastRow < layerConfig.firstRow) { + return; + } // if the last row is unknown -> redraw everything if (lastRow === Infinity) { - if (this.$showGutter) - this.$gutterLayer.update(layerConfig); + if (this.$showGutter) this.$gutterLayer.update(layerConfig); this.$textLayer.update(layerConfig); return; } @@ -1230,8 +1192,7 @@ class VirtualRenderer { */ $getLongestLine() { var charCount = this.session.getScreenWidth(); - if (this.showInvisibles && !this.session.$useWrapMode) - charCount += 1; + if (this.showInvisibles && !this.session.$useWrapMode) charCount += 1; if (this.$textLayer && charCount > this.$textLayer.MAX_LINE_LENGTH) charCount = this.$textLayer.MAX_LINE_LENGTH + 30; @@ -1261,7 +1222,7 @@ class VirtualRenderer { * Deprecated; (moved to [[EditSession]]) * @deprecated **/ - addGutterDecoration(row, className){ + addGutterDecoration(row, className) { this.$gutterLayer.addGutterDecoration(row, className); } @@ -1269,7 +1230,7 @@ class VirtualRenderer { * Deprecated; (moved to [[EditSession]]) * @deprecated **/ - removeGutterDecoration(row, className){ + removeGutterDecoration(row, className) { this.$gutterLayer.removeGutterDecoration(row, className); } @@ -1338,16 +1299,15 @@ class VirtualRenderer { */ scrollCursorIntoView(cursor, offset, $viewMargin) { // the editor is not visible - if (this.$size.scrollerHeight === 0) - return; + if (this.$size.scrollerHeight === 0) return; var pos = this.$cursorLayer.getPixelPosition(cursor); var newLeft = pos.left; var newTop = pos.top; - var topMargin = $viewMargin && $viewMargin.top || 0; - var bottomMargin = $viewMargin && $viewMargin.bottom || 0; + var topMargin = ($viewMargin && $viewMargin.top) || 0; + var bottomMargin = ($viewMargin && $viewMargin.bottom) || 0; if (this.$scrollAnimation) { this.$stopAnimation = true; @@ -1358,11 +1318,10 @@ class VirtualRenderer { if (currentTop + topMargin > newTop) { if (offset && currentTop + topMargin > newTop + this.lineHeight) newTop -= offset * this.$size.scrollerHeight; - if (newTop === 0) - newTop = -this.scrollMargin.top; + if (newTop === 0) newTop = -this.scrollMargin.top; this.session.setScrollTop(newTop); } else if (currentTop + this.$size.scrollerHeight - bottomMargin < newTop + this.lineHeight) { - if (offset && currentTop + this.$size.scrollerHeight - bottomMargin < newTop - this.lineHeight) + if (offset && currentTop + this.$size.scrollerHeight - bottomMargin < newTop - this.lineHeight) newTop += offset * this.$size.scrollerHeight; this.session.setScrollTop(newTop + this.lineHeight + bottomMargin - this.$size.scrollerHeight); } @@ -1438,8 +1397,7 @@ class VirtualRenderer { * @returns {number} */ alignCursor(cursor, alignment) { - if (typeof cursor == "number") - cursor = {row: cursor, column: 0}; + if (typeof cursor == "number") cursor = {row: cursor, column: 0}; var pos = this.$cursorLayer.getPixelPosition(cursor); var h = this.$size.scrollerHeight - this.lineHeight; @@ -1455,17 +1413,16 @@ class VirtualRenderer { * @param {number} toValue * @returns {*[]} */ - $calcSteps(fromValue, toValue){ + $calcSteps(fromValue, toValue) { var i = 0; var l = this.STEPS; var steps = []; - var func = function(t, x_min, dx) { + var func = function (t, x_min, dx) { return dx * (Math.pow(t - 1, 3) + 1) + x_min; }; - for (i = 0; i < l; ++i) - steps.push(func(i / this.STEPS, fromValue, toValue - fromValue)); + for (i = 0; i < l; ++i) steps.push(func(i / this.STEPS, fromValue, toValue - fromValue)); return steps; } @@ -1481,13 +1438,11 @@ class VirtualRenderer { scrollToLine(line, center, animate, callback) { var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0}); var offset = pos.top; - if (center) - offset -= this.$size.scrollerHeight / 2; + if (center) offset -= this.$size.scrollerHeight / 2; var initialScroll = this.scrollTop; this.session.setScrollTop(offset); - if (animate !== false) - this.animateScrolling(initialScroll, callback); + if (animate !== false) this.animateScrolling(initialScroll, callback); } /** @@ -1498,19 +1453,16 @@ class VirtualRenderer { */ animateScrolling(fromValue, callback) { var toValue = this.scrollTop; - if (!this.$animatedScroll) - return; + if (!this.$animatedScroll) return; var _self = this; - if (fromValue == toValue) - return; + if (fromValue == toValue) return; if (this.$scrollAnimation) { var oldSteps = this.$scrollAnimation.steps; if (oldSteps.length) { fromValue = oldSteps[0]; - if (fromValue == toValue) - return; + if (fromValue == toValue) return; } } @@ -1531,14 +1483,13 @@ class VirtualRenderer { callback && callback(); } - this.$timer = setInterval(function() { + this.$timer = setInterval(function () { if (_self.$stopAnimation) { endAnimation(); return; } - if (!_self.session) - return clearInterval(_self.$timer); + if (!_self.session) return clearInterval(_self.$timer); if (steps.length) { _self.session.setScrollTop(steps.shift()); _self.session.$scrollTop = toValue; @@ -1571,8 +1522,7 @@ class VirtualRenderer { * @param {Number} scrollLeft The position to scroll to **/ scrollToX(scrollLeft) { - if (this.scrollLeft !== scrollLeft) - this.scrollLeft = scrollLeft; + if (this.scrollLeft !== scrollLeft) this.scrollLeft = scrollLeft; this.$loop.schedule(this.CHANGE_H_SCROLL); } @@ -1604,16 +1554,20 @@ class VirtualRenderer { * @returns {Boolean} **/ isScrollableBy(deltaX, deltaY) { - if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top) - return true; - if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight - - this.layerConfig.maxHeight < -1 + this.scrollMargin.bottom) - return true; - if (deltaX < 0 && this.session.getScrollLeft() >= 1 - this.scrollMargin.left) + if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top) return true; + if ( + deltaY > 0 && + this.session.getScrollTop() + this.$size.scrollerHeight - this.layerConfig.maxHeight < + -1 + this.scrollMargin.bottom + ) + return true; + if (deltaX < 0 && this.session.getScrollLeft() >= 1 - this.scrollMargin.left) return true; + if ( + deltaX > 0 && + this.session.getScrollLeft() + this.$size.scrollerWidth - this.layerConfig.width < + -1 + this.scrollMargin.right + ) return true; - if (deltaX > 0 && this.session.getScrollLeft() + this.$size.scrollerWidth - - this.layerConfig.width < -1 + this.scrollMargin.right) - return true; } /** @@ -1626,7 +1580,7 @@ class VirtualRenderer { pixelToScreenCoordinates(x, y) { var canvasPos; if (this.$hasCssTransforms) { - canvasPos = {top:0, left: 0}; + canvasPos = {top: 0, left: 0}; var p = this.$fontMetrics.transformCoordinates([x, y]); x = p[1] - this.gutterWidth - this.margin.left; y = p[0]; @@ -1639,7 +1593,7 @@ class VirtualRenderer { var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight); var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset); - return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX}; + return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX}; } /** @@ -1652,7 +1606,7 @@ class VirtualRenderer { screenToTextCoordinates(x, y) { var canvasPos; if (this.$hasCssTransforms) { - canvasPos = {top:0, left: 0}; + canvasPos = {top: 0, left: 0}; var p = this.$fontMetrics.transformCoordinates([x, y]); x = p[1] - this.gutterWidth - this.margin.left; y = p[0]; @@ -1680,9 +1634,11 @@ class VirtualRenderer { var canvasPos = this.scroller.getBoundingClientRect(); var pos = this.session.documentToScreenPosition(row, column); - var x = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, row) - ? this.session.$bidiHandler.getPosLeft(pos.column) - : Math.round(pos.column * this.characterWidth)); + var x = + this.$padding + + (this.session.$bidiHandler.isBidiRow(pos.row, row) + ? this.session.$bidiHandler.getPosLeft(pos.column) + : Math.round(pos.column * this.characterWidth)); var y = pos.row * this.lineHeight; @@ -1717,16 +1673,14 @@ class VirtualRenderer { if (!composition.cssText) { composition.cssText = this.textarea.style.cssText; } - if (composition.useTextareaForIME == undefined) - composition.useTextareaForIME = this.$useTextareaForIME; + if (composition.useTextareaForIME == undefined) composition.useTextareaForIME = this.$useTextareaForIME; if (this.$useTextareaForIME) { dom.addCssClass(this.textarea, "ace_composition"); this.textarea.style.cssText = ""; this.$moveTextAreaToCursor(); this.$cursorLayer.element.style.display = "none"; - } - else { + } else { composition.markerId = this.session.addMarker(composition.markerRange, "ace_composition_marker", "text"); } } @@ -1749,11 +1703,9 @@ class VirtualRenderer { **/ hideComposition() { - if (!this.$composition) - return; + if (!this.$composition) return; - if (this.$composition.markerId) - this.session.removeMarker(this.$composition.markerId); + if (this.$composition.markerId) this.session.removeMarker(this.$composition.markerId); dom.removeCssClass(this.textarea, "ace_composition"); this.textarea.style.cssText = this.$composition.cssText; @@ -1769,7 +1721,7 @@ class VirtualRenderer { */ setGhostText(text, position) { var cursor = this.session.selection.cursor; - var insertPosition = position || { row: cursor.row, column: cursor.column }; + var insertPosition = position || {row: cursor.row, column: cursor.column}; this.removeGhostText(); @@ -1780,7 +1732,7 @@ class VirtualRenderer { text: text, position: { row: insertPosition.row, - column: insertPosition. column + column: insertPosition.column } }; @@ -1790,7 +1742,7 @@ class VirtualRenderer { var hiddenTokens = this.hideTokensAfterPosition(insertPosition.row, insertPosition.column); var lastLineDiv; - textChunks.slice(1).forEach(el => { + textChunks.slice(1).forEach((el) => { var chunkDiv = dom.createElement("div"); var chunkSpan = dom.createElement("span"); chunkSpan.className = "ace_ghost_text"; @@ -1812,7 +1764,7 @@ class VirtualRenderer { }); // Add the hidden tokens to the last line of the ghost text. - hiddenTokens.forEach(token => { + hiddenTokens.forEach((token) => { var element = dom.createElement("span"); if (!isTextToken(token.type)) element.className = "ace_" + token.type.replace(/\./g, " ace_"); element.appendChild(dom.createTextNode(token.value)); @@ -1832,7 +1784,7 @@ class VirtualRenderer { var el = this.container; var height = el.getBoundingClientRect().height; var ghostTextHeight = textChunks.length * this.lineHeight; - var fitsY = ghostTextHeight < (height - pixelPosition.top); + var fitsY = ghostTextHeight < height - pixelPosition.top; // If it fits, no action needed if (fitsY) return; @@ -1846,7 +1798,6 @@ class VirtualRenderer { this.scrollToRow(insertPosition.row); } } - } /** @@ -1877,8 +1828,7 @@ class VirtualRenderer { textChunks.push({text: textSlice, wrapped: true}); start = wrapSplits[j]; } - } - else { + } else { textChunks.push({text: textLines[i], wrapped: false}); } } @@ -1912,7 +1862,7 @@ class VirtualRenderer { tokens.push(newToken); } else { var l = 0; - for (var i =0; i < tokens.length; i++) { + for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; l += token.value.length; if (column <= l) { @@ -1920,7 +1870,7 @@ class VirtualRenderer { var before = token.value.slice(0, diff); var after = token.value.slice(diff); - tokens.splice(i, 1, {type: token.type, value: before}, newToken, {type: token.type, value: after}); + tokens.splice(i, 1, {type: token.type, value: before}, newToken, {type: token.type, value: after}); break; } } @@ -1972,7 +1922,7 @@ class VirtualRenderer { var _self = this; /**@type {any}*/ this.$themeId = theme; - _self._dispatchEvent('themeChange',{theme:theme}); + _self._dispatchEvent("themeChange", {theme: theme}); if (!theme || typeof theme == "string") { // @ts-ignore @@ -1986,24 +1936,15 @@ class VirtualRenderer { * @param {Theme} module */ function afterLoad(module) { - if (_self.$themeId != theme) - return cb && cb(); + if (_self.$themeId != theme) return cb && cb(); if (!module || !module.cssClass) throw new Error("couldn't load module " + theme + " or it didn't call define"); - if (module.$id) - _self.$themeId = module.$id; - dom.importCssString( - module.cssText, - module.cssClass, - _self.container - ); - if (_self.theme) - dom.removeCssClass(_self.container, _self.theme.cssClass); + if (module.$id) _self.$themeId = module.$id; + dom.importCssString(module.cssText, module.cssClass, _self.container); + if (_self.theme) dom.removeCssClass(_self.container, _self.theme.cssClass); /**@type {any}*/ - var padding = "padding" in module ? module.padding - : "padding" in (_self.theme || {}) ? 4 : _self.$padding; - if (_self.$padding && padding != _self.$padding) - _self.setPadding(padding); + var padding = "padding" in module ? module.padding : "padding" in (_self.theme || {}) ? 4 : _self.$padding; + if (_self.$padding && padding != _self.$padding) _self.setPadding(padding); // this is kept only for backwards compatibility _self.$theme = module.cssClass; @@ -2018,7 +1959,7 @@ class VirtualRenderer { _self.$updateSizeAsync(); } - _self._dispatchEvent('themeLoaded', {theme:module}); + _self._dispatchEvent("themeLoaded", {theme: module}); cb && cb(); // workaround for safari not redrawing the editor @@ -2119,8 +2060,7 @@ class VirtualRenderer { }); this.$scrollDecorator = new Decorator(this.scrollBarV, this); this.$scrollDecorator.$updateDecorators(); - } - else { + } else { this.scrollBarV = new VScrollBar(this.container, this); this.scrollBarH = new HScrollBar(this.container, this); this.scrollBarV.addEventListener("scroll", function (e) { @@ -2138,16 +2078,13 @@ class VirtualRenderer { $addResizeObserver() { if (!window.ResizeObserver || this.$resizeObserver) return; var self = this; - this.$resizeTimer = lang.delayedCall(function() { - if (!self.destroyed) self.onResize(); + this.$resizeTimer = lang.delayedCall(function () { + if (!self.destroyed) self.onResize(); }, 50); - this.$resizeObserver = new window.ResizeObserver(function(e) { + this.$resizeObserver = new window.ResizeObserver(function (e) { var w = e[0].contentRect.width; var h = e[0].contentRect.height; - if ( - Math.abs(self.$size.width - w) > 1 - || Math.abs(self.$size.height - h) > 1 - ) { + if (Math.abs(self.$size.width - w) > 1 || Math.abs(self.$size.height - h) > 1) { self.$resizeTimer.delay(); } else { self.$resizeTimer.cancel(); @@ -2155,7 +2092,6 @@ class VirtualRenderer { }); this.$resizeObserver.observe(this.container); } - } VirtualRenderer.prototype.CHANGE_CURSOR = 1; @@ -2182,7 +2118,7 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { * @param value * @this{VirtualRenderer} */ - set: function(value) { + set: function (value) { if (!value && this.$resizeObserver) { this.$resizeObserver.disconnect(); this.$resizeTimer.cancel(); @@ -2194,18 +2130,21 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { }, animatedScroll: {initialValue: false}, showInvisibles: { - set: function(value) { - if (this.$textLayer.setShowInvisibles(value)) - this.$loop.schedule(this.CHANGE_TEXT); + set: function (value) { + if (this.$textLayer.setShowInvisibles(value)) this.$loop.schedule(this.CHANGE_TEXT); }, initialValue: false }, showPrintMargin: { - set: function() { this.$updatePrintMargin(); }, + set: function () { + this.$updatePrintMargin(); + }, initialValue: true }, printMarginColumn: { - set: function() { this.$updatePrintMargin(); }, + set: function () { + this.$updatePrintMargin(); + }, initialValue: 80 }, printMargin: { @@ -2213,18 +2152,17 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { * @param val * @this{VirtualRenderer} */ - set: function(val) { - if (typeof val == "number") - this.$printMarginColumn = val; + set: function (val) { + if (typeof val == "number") this.$printMarginColumn = val; this.$showPrintMargin = !!val; this.$updatePrintMargin(); }, - get: function() { + get: function () { return this.$showPrintMargin && this.$printMarginColumn; } }, showGutter: { - set: function(show){ + set: function (show) { this.$gutter.style.display = show ? "block" : "none"; this.$loop.schedule(this.CHANGE_FULL); this.onGutterResize(); @@ -2232,34 +2170,33 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { initialValue: true }, useSvgGutterIcons: { - set: function(value){ + set: function (value) { this.$gutterLayer.$useSvgGutterIcons = value; }, initialValue: false }, showFoldedAnnotations: { - set: function(value){ + set: function (value) { this.$gutterLayer.$showFoldedAnnotations = value; }, initialValue: false }, fadeFoldWidgets: { - set: function(show) { + set: function (show) { dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show); }, initialValue: false }, showFoldWidgets: { - set: function(show) { + set: function (show) { this.$gutterLayer.setShowFoldWidgets(show); this.$loop.schedule(this.CHANGE_GUTTER); }, initialValue: true }, displayIndentGuides: { - set: function(show) { - if (this.$textLayer.setDisplayIndentGuides(show)) - this.$loop.schedule(this.CHANGE_TEXT); + set: function (show) { + if (this.$textLayer.setDisplayIndentGuides(show)) this.$loop.schedule(this.CHANGE_TEXT); }, initialValue: true }, @@ -2267,51 +2204,47 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { set: function (show) { if (this.$textLayer.setHighlightIndentGuides(show) == true) { this.$textLayer.$highlightIndentGuide(); - } - else { + } else { this.$textLayer.$clearActiveIndentGuide(this.$textLayer.$lines.cells); } }, initialValue: true }, highlightGutterLine: { - set: function(shouldHighlight) { + set: function (shouldHighlight) { this.$gutterLayer.setHighlightGutterLine(shouldHighlight); this.$loop.schedule(this.CHANGE_GUTTER); }, initialValue: true }, hScrollBarAlwaysVisible: { - set: function(val) { - if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll) - this.$loop.schedule(this.CHANGE_SCROLL); + set: function (val) { + if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll) this.$loop.schedule(this.CHANGE_SCROLL); }, initialValue: false }, vScrollBarAlwaysVisible: { - set: function(val) { - if (!this.$vScrollBarAlwaysVisible || !this.$vScroll) - this.$loop.schedule(this.CHANGE_SCROLL); + set: function (val) { + if (!this.$vScrollBarAlwaysVisible || !this.$vScroll) this.$loop.schedule(this.CHANGE_SCROLL); }, initialValue: false }, fontSize: { - set: function(size) { - if (typeof size == "number") - size = size + "px"; + set: function (size) { + if (typeof size == "number") size = size + "px"; this.container.style.fontSize = size; this.updateFontSize(); }, initialValue: 12 }, fontFamily: { - set: function(name) { + set: function (name) { this.container.style.fontFamily = name; this.updateFontSize(); } }, maxLines: { - set: function(val) { + set: function (val) { this.updateFull(); } }, @@ -2320,14 +2253,13 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { * @param val * @this{VirtualRenderer} */ - set: function(val) { - if (!(this.$minLines < 0x1ffffffffffff)) - this.$minLines = 0; + set: function (val) { + if (!(this.$minLines < 0x1ffffffffffff)) this.$minLines = 0; this.updateFull(); } }, maxPixelHeight: { - set: function(val) { + set: function (val) { this.updateFull(); }, initialValue: 0 @@ -2337,10 +2269,9 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { * @param val * @this{VirtualRenderer} */ - set: function(val) { + set: function (val) { val = +val || 0; - if (this.$scrollPastEnd == val) - return; + if (this.$scrollPastEnd == val) return; this.$scrollPastEnd = val; this.$loop.schedule(this.CHANGE_SCROLL); }, @@ -2348,25 +2279,28 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { handlesSet: true }, fixedWidthGutter: { - set: function(val) { + set: function (val) { this.$gutterLayer.$fixedWidth = !!val; this.$loop.schedule(this.CHANGE_GUTTER); } }, customScrollbar: { - set: function(val) { + set: function (val) { this.$updateCustomScrollbar(val); }, initialValue: false }, theme: { - set: function(val) { this.setTheme(val); }, - get: function() { return this.$themeId || this.theme; }, + set: function (val) { + this.setTheme(val); + }, + get: function () { + return this.$themeId || this.theme; + }, initialValue: "./theme/textmate", handlesSet: true }, - hasCssTransforms: { - }, + hasCssTransforms: {}, useTextareaForIME: { initialValue: !useragent.isMobile && !useragent.isIE }