1/* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31/** 32 * @constructor 33 * @extends {WebInspector.InplaceEditor} 34 */ 35WebInspector.CodeMirrorUtils = function() 36{ 37 WebInspector.InplaceEditor.call(this); 38} 39 40/** 41 * @param {!WebInspector.TextRange} range 42 * @return {!{start: !CodeMirror.Pos, end: !CodeMirror.Pos}} 43 */ 44WebInspector.CodeMirrorUtils.toPos = function(range) 45{ 46 return { 47 start: new CodeMirror.Pos(range.startLine, range.startColumn), 48 end: new CodeMirror.Pos(range.endLine, range.endColumn) 49 } 50} 51 52/** 53 * @param {!CodeMirror.Pos} start 54 * @param {!CodeMirror.Pos} end 55 * @return {!WebInspector.TextRange} 56 */ 57WebInspector.CodeMirrorUtils.toRange = function(start, end) 58{ 59 return new WebInspector.TextRange(start.line, start.ch, end.line, end.ch); 60} 61 62WebInspector.CodeMirrorUtils.prototype = { 63 /** 64 * @return {string} 65 */ 66 editorContent: function(editingContext) { 67 return editingContext.codeMirror.getValue(); 68 }, 69 70 /** 71 * @param {?Event} e 72 */ 73 _consumeCopy: function(e) 74 { 75 e.consume(); 76 }, 77 78 setUpEditor: function(editingContext) 79 { 80 var element = editingContext.element; 81 var config = editingContext.config; 82 editingContext.cssLoadView = new WebInspector.CodeMirrorCSSLoadView(); 83 editingContext.cssLoadView.show(element); 84 WebInspector.setCurrentFocusElement(element); 85 element.addEventListener("copy", this._consumeCopy, false); 86 var codeMirror = new window.CodeMirror(element, { 87 mode: config.mode, 88 lineWrapping: config.lineWrapping, 89 smartIndent: config.smartIndent, 90 autofocus: true, 91 theme: config.theme, 92 value: config.initialValue 93 }); 94 codeMirror.getWrapperElement().classList.add("source-code"); 95 codeMirror.on("cursorActivity", function(cm) { 96 cm.display.cursorDiv.scrollIntoViewIfNeeded(false); 97 }); 98 editingContext.codeMirror = codeMirror; 99 }, 100 101 closeEditor: function(editingContext) 102 { 103 editingContext.element.removeEventListener("copy", this._consumeCopy, false); 104 editingContext.cssLoadView.detach(); 105 }, 106 107 cancelEditing: function(editingContext) 108 { 109 editingContext.codeMirror.setValue(editingContext.oldText); 110 }, 111 112 augmentEditingHandle: function(editingContext, handle) 113 { 114 function setWidth(editingContext, width) 115 { 116 var padding = 30; 117 var codeMirror = editingContext.codeMirror; 118 codeMirror.getWrapperElement().style.width = (width - codeMirror.getWrapperElement().offsetLeft - padding) + "px"; 119 codeMirror.refresh(); 120 } 121 122 handle.codeMirror = editingContext.codeMirror; 123 handle.setWidth = setWidth.bind(null, editingContext); 124 }, 125 126 __proto__: WebInspector.InplaceEditor.prototype 127} 128 129/** 130 * @constructor 131 * @implements {WebInspector.TokenizerFactory} 132 */ 133WebInspector.CodeMirrorUtils.TokenizerFactory = function() { } 134 135WebInspector.CodeMirrorUtils.TokenizerFactory.prototype = { 136 /** 137 * @param {string} mimeType 138 * @return {function(string, function(string, ?string, number, number))} 139 */ 140 createTokenizer: function(mimeType) 141 { 142 var mode = CodeMirror.getMode({indentUnit: 2}, mimeType); 143 var state = CodeMirror.startState(mode); 144 function tokenize(line, callback) 145 { 146 var stream = new CodeMirror.StringStream(line); 147 while (!stream.eol()) { 148 var style = mode.token(stream, state); 149 var value = stream.current(); 150 callback(value, style, stream.start, stream.start + value.length); 151 stream.start = stream.pos; 152 } 153 } 154 return tokenize; 155 } 156} 157 158/** 159 * This bogus view is needed to load/unload CodeMirror-related CSS on demand. 160 * 161 * @constructor 162 * @extends {WebInspector.VBox} 163 */ 164WebInspector.CodeMirrorCSSLoadView = function() 165{ 166 WebInspector.VBox.call(this); 167 this.element.classList.add("hidden"); 168 this.registerRequiredCSS("cm/codemirror.css"); 169 this.registerRequiredCSS("cm/cmdevtools.css"); 170} 171 172WebInspector.CodeMirrorCSSLoadView.prototype = { 173 __proto__: WebInspector.VBox.prototype 174} 175