panel.js (4278B)
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/LICENSE 3 4 (function(mod) { 5 if (typeof exports == "object" && typeof module == "object") // CommonJS 6 mod(require("../../lib/codemirror")); 7 else if (typeof define == "function" && define.amd) // AMD 8 define(["../../lib/codemirror"], mod); 9 else // Plain browser env 10 mod(CodeMirror); 11 })(function(CodeMirror) { 12 CodeMirror.defineExtension("addPanel", function(node, options) { 13 options = options || {}; 14 15 if (!this.state.panels) initPanels(this); 16 17 var info = this.state.panels; 18 var wrapper = info.wrapper; 19 var cmWrapper = this.getWrapperElement(); 20 21 if (options.after instanceof Panel && !options.after.cleared) { 22 wrapper.insertBefore(node, options.before.node.nextSibling); 23 } else if (options.before instanceof Panel && !options.before.cleared) { 24 wrapper.insertBefore(node, options.before.node); 25 } else if (options.replace instanceof Panel && !options.replace.cleared) { 26 wrapper.insertBefore(node, options.replace.node); 27 options.replace.clear(); 28 } else if (options.position == "bottom") { 29 wrapper.appendChild(node); 30 } else if (options.position == "before-bottom") { 31 wrapper.insertBefore(node, cmWrapper.nextSibling); 32 } else if (options.position == "after-top") { 33 wrapper.insertBefore(node, cmWrapper); 34 } else { 35 wrapper.insertBefore(node, wrapper.firstChild); 36 } 37 38 var height = (options && options.height) || node.offsetHeight; 39 this._setSize(null, info.heightLeft -= height); 40 info.panels++; 41 if (options.stable && isAtTop(this, node)) 42 this.scrollTo(null, this.getScrollInfo().top + height) 43 44 return new Panel(this, node, options, height); 45 }); 46 47 function Panel(cm, node, options, height) { 48 this.cm = cm; 49 this.node = node; 50 this.options = options; 51 this.height = height; 52 this.cleared = false; 53 } 54 55 Panel.prototype.clear = function() { 56 if (this.cleared) return; 57 this.cleared = true; 58 var info = this.cm.state.panels; 59 this.cm._setSize(null, info.heightLeft += this.height); 60 if (this.options.stable && isAtTop(this.cm, this.node)) 61 this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) 62 info.wrapper.removeChild(this.node); 63 if (--info.panels == 0) removePanels(this.cm); 64 }; 65 66 Panel.prototype.changed = function(height) { 67 var newHeight = height == null ? this.node.offsetHeight : height; 68 var info = this.cm.state.panels; 69 this.cm._setSize(null, info.heightLeft -= (newHeight - this.height)); 70 this.height = newHeight; 71 }; 72 73 function initPanels(cm) { 74 var wrap = cm.getWrapperElement(); 75 var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; 76 var height = parseInt(style.height); 77 var info = cm.state.panels = { 78 setHeight: wrap.style.height, 79 heightLeft: height, 80 panels: 0, 81 wrapper: document.createElement("div") 82 }; 83 wrap.parentNode.insertBefore(info.wrapper, wrap); 84 var hasFocus = cm.hasFocus(); 85 info.wrapper.appendChild(wrap); 86 if (hasFocus) cm.focus(); 87 88 cm._setSize = cm.setSize; 89 if (height != null) cm.setSize = function(width, newHeight) { 90 if (newHeight == null) return this._setSize(width, newHeight); 91 info.setHeight = newHeight; 92 if (typeof newHeight != "number") { 93 var px = /^(\d+\.?\d*)px$/.exec(newHeight); 94 if (px) { 95 newHeight = Number(px[1]); 96 } else { 97 info.wrapper.style.height = newHeight; 98 newHeight = info.wrapper.offsetHeight; 99 info.wrapper.style.height = ""; 100 } 101 } 102 cm._setSize(width, info.heightLeft += (newHeight - height)); 103 height = newHeight; 104 }; 105 } 106 107 function removePanels(cm) { 108 var info = cm.state.panels; 109 cm.state.panels = null; 110 111 var wrap = cm.getWrapperElement(); 112 info.wrapper.parentNode.replaceChild(wrap, info.wrapper); 113 wrap.style.height = info.setHeight; 114 cm.setSize = cm._setSize; 115 cm.setSize(); 116 } 117 118 function isAtTop(cm, dom) { 119 for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) 120 if (sibling == cm.getWrapperElement()) return true 121 return false 122 } 123 });