: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
}, NullScrollbars.prototype);
CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
function initScrollbars(cm) {
if (cm.display.scrollbars) {
cm.display.scrollbars.clear();
if (cm.display.scrollbars.addClass)
rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
// Prevent clicks in the scrollbars from killing focus
on(node, "mousedown", function() {
if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
node.setAttribute("cm-not-content", "true");
if (axis == "horizontal") setScrollLeft(cm, pos);
else setScrollTop(cm, pos);
if (cm.display.scrollbars.addClass)
addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
function updateScrollbars(cm, measure) {
if (!measure) measure = measureForScrollbars(cm);
var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
updateScrollbarsInner(cm, measure);
for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
updateHeightsInViewport(cm);
updateScrollbarsInner(cm, measureForScrollbars(cm));
startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
// Re-synchronize the fake scrollbars with the actual size of the
function updateScrollbarsInner(cm, measure) {
var sizes = d.scrollbars.update(measure);
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
if (sizes.right && sizes.bottom) {
d.scrollbarFiller.style.display = "block";
d.scrollbarFiller.style.height = sizes.bottom + "px";
d.scrollbarFiller.style.width = sizes.right + "px";
} else d.scrollbarFiller.style.display = "";
if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
d.gutterFiller.style.display = "block";
d.gutterFiller.style.height = sizes.bottom + "px";
d.gutterFiller.style.width = measure.gutterWidth + "px";
} else d.gutterFiller.style.display = "";
// Compute the lines that are visible in a given viewport (defaults
// the the current scroll position). viewport may contain top,
// height, and ensure (see op.scrollToPos) properties.
function visibleLines(display, doc, viewport) {
var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
top = Math.floor(top - paddingTop(display));
var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
// Ensure is a {from: {line, ch}, to: {line, ch}} object, and
// forces those lines into the viewport (if possible).
if (viewport && viewport.ensure) {
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
} else if (Math.min(ensureTo, doc.lastLine()) >= to) {
from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
return {from: from, to: Math.max(to, from + 1)};
// Re-align line numbers and gutter marks to compensate for
function alignHorizontally(cm) {
var display = cm.display, view = display.view;
if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
var gutterW = display.gutters.offsetWidth, left = comp + "px";
for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
if (cm.options.fixedGutter) {
view[i].gutter.style.left = left;
if (view[i].gutterBackground)
view[i].gutterBackground.style.left = left;
var align = view[i].alignable;
if (align) for (var j = 0; j < align.length; j++)
align[j].style.left = left;
if (cm.options.fixedGutter)
display.gutters.style.left = (comp + gutterW) + "px";
// Used to ensure that the line number gutter is still the right
// size for the current document size. Returns true when an update
function maybeUpdateLineNumberWidth(cm) {
if (!cm.options.lineNumbers) return false;
var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
if (last.length != display.lineNumChars) {
var test = display.measure.appendChild(elt("div", [elt("div", last)],
"CodeMirror-linenumber CodeMirror-gutter-elt"));
var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
display.lineGutter.style.width = "";
display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
display.lineNumWidth = display.lineNumInnerWidth + padding;
display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
display.lineGutter.style.width = display.lineNumWidth + "px";
function lineNumberFor(options, i) {
return String(options.lineNumberFormatter(i + options.firstLineNumber));
// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
// but using getBoundingClientRect to get a sub-pixel-accurate
function compensateForHScroll(display) {
return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
function DisplayUpdate(cm, viewport, force) {
var display = cm.display;
this.viewport = viewport;
// Store some values that we'll need later (but don't want to force a relayout for)
this.visible = visibleLines(display, cm.doc, viewport);
this.editorIsHidden = !display.wrapper.offsetWidth;
this.wrapperHeight = display.wrapper.clientHeight;
this.wrapperWidth = display.wrapper.clientWidth;
this.oldDisplayWidth = displayWidth(cm);
this.dims = getDimensions(cm);
DisplayUpdate.prototype.signal = function(emitter, type) {
if (hasHandler(emitter, type))
this.events.push(arguments);
DisplayUpdate.prototype.finish = function() {
for (var i = 0; i < this.events.length; i++)
signal.apply(null, this.events[i]);
function maybeClipScrollbars(cm) {
var display = cm.display;
if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
display.heightForcer.style.height = scrollGap(cm) + "px";
display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
display.scrollbarsClipped = true;
// Does the actual updating of the line display. Bails out
// (returning false) when there is nothing to be done and forced is
function updateDisplayIfNeeded(cm, update) {
var display = cm.display, doc = cm.doc;
if (update.editorIsHidden) {
// Bail out if the visible area is already rendered and nothing changed.
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
display.renderedView == display.view && countDirtyView(cm) == 0)
if (maybeUpdateLineNumberWidth(cm)) {
update.dims = getDimensions(cm);
// Compute a suitable new viewport (from & to)
var end = doc.first + doc.size;
var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
from = visualLineNo(cm.doc, from);
to = visualLineEndNo(cm.doc, to);
var different = from != display.viewFrom || to != display.viewTo ||
display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
adjustView(cm, from, to);
display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
// Position the mover div to align with the current scroll position
cm.display.mover.style.top = display.viewOffset + "px";
var toUpdate = countDirtyView(cm);
if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
// For big changes, we hide the enclosing element during the
// update, since that speeds up the operations on most browsers.
var focused = activeElt();
if (toUpdate > 4) display.lineDiv.style.display = "none";
patchDisplay(cm, display.updateLineNumbers, update.dims);
if (toUpdate > 4) display.lineDiv.style.display = "";
display.renderedView = display.view;
// There might have been a widget with a focused element that got
// hidden or updated, if so re-focus it.
if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
// Prevent selection and cursors from interfering with the scroll
removeChildren(display.cursorDiv);
removeChildren(display.selectionDiv);
display.gutters.style.height = display.sizer.style.minHeight = 0;
display.lastWrapHeight = update.wrapperHeight;
display.lastWrapWidth = update.wrapperWidth;
display.updateLineNumbers = null;
function postUpdateDisplay(cm, update) {
var viewport = update.viewport;
for (var first = true;; first = false) {
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
// Clip forced viewport to actual scrollable area.
if (viewport && viewport.top != null)
viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
// Updated line heights might result in the drawn area not
// actually covering the viewport. Keep looping until it does.
update.visible = visibleLines(cm.display, cm.doc, viewport);
if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
if (!updateDisplayIfNeeded(cm, update)) break;
updateHeightsInViewport(cm);
var barMeasure = measureForScrollbars(cm);
updateScrollbars(cm, barMeasure);
setDocumentHeight(cm, barMeasure);
update.signal(cm, "update", cm);
if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
function updateDisplaySimple(cm, viewport) {
var update = new DisplayUpdate(cm, viewport);
if (updateDisplayIfNeeded(cm, update)) {
updateHeightsInViewport(cm);
postUpdateDisplay(cm, update);
var barMeasure = measureForScrollbars(cm);
updateScrollbars(cm, barMeasure);
setDocumentHeight(cm, barMeasure);
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = measure.docHeight + "px";
cm.display.heightForcer.style.top = measure.docHeight + "px";
cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
// Read the actual heights of the rendered lines, and update their
// stored heights to match.
function updateHeightsInViewport(cm) {
var display = cm.display;
var prevBottom = display.lineDiv.offsetTop;
for (var i = 0; i < display.view.length; i++) {
var cur = display.view[i], height;
if (cur.hidden) continue;
if (ie && ie_version < 8) {
var bot = cur.node.offsetTop + cur.node.offsetHeight;
height = bot - prevBottom;
var box = cur.node.getBoundingClientRect();
height = box.bottom - box.top;
var diff = cur.line.height - height;
if (height < 2) height = textHeight(display);
if (diff > .001 || diff < -.001) {
updateLineHeight(cur.line, height);
updateWidgetHeight(cur.line);
if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
updateWidgetHeight(cur.rest[j]);
// Read and store the height of line widgets associated with the
function updateWidgetHeight(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
// Do a bulk-read of the DOM positions and sizes needed to draw the
// view, so that we don't interleave reading and writing to the DOM.
function getDimensions(cm) {
var d = cm.display, left = {}, width = {};
var gutterLeft = d.gutters.clientLeft;
for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
width[cm.options.gutters[i]] = n.clientWidth;
return {fixedPos: compensateForHScroll(d),
gutterTotalWidth: d.gutters.offsetWidth,
wrapperWidth: d.wrapper.clientWidth};
// Sync the actual display DOM structure with display.view, removing
// nodes for lines that are no longer in view, and creating the ones
// that are not there yet, and updating the ones that are out of
function patchDisplay(cm, updateNumbersFrom, dims) {
var display = cm.display, lineNumbers = cm.options.lineNumbers;
var container = display.lineDiv, cur = container.firstChild;
var next = node.nextSibling;
// Works around a throw-scroll bug in OS X Webkit
if (webkit && mac && cm.display.currentWheelTarget == node)
node.style.display = "none";
node.parentNode.removeChild(node);
var view = display.view, lineN = display.viewFrom;
// Loop over the elements in the view, syncing cur (the DOM nodes
// in display.lineDiv) with the view as we go.
for (var i = 0; i < view.length; i++) {
} else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
var node = buildLineElement(cm, lineView, lineN, dims);
container.insertBefore(node, cur);
} else { // Already drawn
while (cur != lineView.node) cur = rm(cur);
var updateNumber = lineNumbers && updateNumbersFrom != null &&
updateNumbersFrom <= lineN && lineView.lineNumber;
if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
updateLineForChanges(cm, lineView, lineN, dims);
removeChildren(lineView.lineNumber);
lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
cur = lineView.node.nextSibling;
while (cur) cur = rm(cur);
// When an aspect of a line changes, a string is added to
// lineView.changes. This updates the relevant part of the line's
function updateLineForChanges(cm, lineView, lineN, dims) {
for (var j = 0; j < lineView.changes.length; j++) {
var type = lineView.changes[j];
if (type == "text") updateLineText(cm, lineView);
else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
else if (type == "class") updateLineClasses(lineView);
else if (type == "widget") updateLineWidgets(cm, lineView, dims);
// Lines with gutter elements, widgets or a background class need to
// be wrapped, and have the extra elements added to the wrapper div
function ensureLineWrapped(lineView) {
if (lineView.node == lineView.text) {
lineView.node = elt("div", null, null, "position: relative");
if (lineView.text.parentNode)
lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
lineView.node.appendChild(lineView.text);
if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
function updateLineBackground(lineView) {
var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
if (cls) cls += " CodeMirror-linebackground";
if (lineView.background) {
if (cls) lineView.background.className = cls;
else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
var wrap = ensureLineWrapped(lineView);
lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
// Wrapper around buildLineContent which will reuse the structure
// in display.externalMeasured when possible.
function getLineContent(cm, lineView) {
var ext = cm.display.externalMeasured;
if (ext && ext.line == lineView.line) {
cm.display.externalMeasured = null;
lineView.measure = ext.measure;
return buildLineContent(cm, lineView);
// Redraw the line's text. Interacts with the background and text
// classes because the mode may output tokens that influence these
function updateLineText(cm, lineView) {
var cls = lineView.text.className;
var built = getLineContent(cm, lineView);
if (lineView.text == lineView.node) lineView.node = built.pre;
lineView.text.parentNode.replaceChild(built.pre, lineView.text);
lineView.text = built.pre;
if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
lineView.bgClass = built.bgClass;
lineView.textClass = built.textClass;
updateLineClasses(lineView);
lineView.text.className = cls;
function updateLineClasses(lineView) {
updateLineBackground(lineView);
if (lineView.line.wrapClass)
ensureLineWrapped(lineView).className = lineView.line.wrapClass;
else if (lineView.node != lineView.text)
lineView.node.className = "";
var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
lineView.text.className = textClass || "";
function updateLineGutter(cm, lineView, lineN, dims) {
lineView.node.removeChild(lineView.gutter);
if (lineView.gutterBackground) {
lineView.node.removeChild(lineView.gutterBackground);
lineView.gutterBackground = null;
if (lineView.line.gutterClass) {
var wrap = ensureLineWrapped(lineView);
lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
"left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
"px; width: " + dims.gutterTotalWidth + "px");
wrap.insertBefore(lineView.gutterBackground, lineView.text);
var markers = lineView.line.gutterMarkers;
if (cm.options.lineNumbers || markers) {
var wrap = ensureLineWrapped(lineView);
var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
(cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px");
cm.display.input.setUneditable(gutterWrap);
wrap.insertBefore(gutterWrap, lineView.text);
if (lineView.line.gutterClass)
gutterWrap.className += " " + lineView.line.gutterClass;