diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js | 1006 |
1 files changed, 0 insertions, 1006 deletions
diff --git a/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js b/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js deleted file mode 100644 index fc5e3ef70..000000000 --- a/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.CSSStyleDeclarationTextEditor = function(delegate, style, element) -{ - WebInspector.Object.call(this); - - this._element = element || document.createElement("div"); - this._element.classList.add(WebInspector.CSSStyleDeclarationTextEditor.StyleClassName); - this._element.classList.add(WebInspector.SyntaxHighlightedStyleClassName); - - this._showsImplicitProperties = true; - this._alwaysShowPropertyNames = {}; - this._sortProperties = false; - - this._prefixWhitespace = ""; - this._suffixWhitespace = ""; - this._linePrefixWhitespace = ""; - - this._delegate = delegate || null; - - this._codeMirror = CodeMirror(this.element, { - readOnly: true, - lineWrapping: true, - mode: "css-rule", - electricChars: false, - indentWithTabs: true, - indentUnit: 4, - smartIndent: false, - matchBrackets: true, - autoCloseBrackets: true - }); - - this._codeMirror.on("change", this._contentChanged.bind(this)); - this._codeMirror.on("blur", this._editorBlured.bind(this)); - - this._completionController = new WebInspector.CodeMirrorCompletionController(this._codeMirror, this); - this._tokenTrackingController = new WebInspector.CodeMirrorTokenTrackingController(this._codeMirror, this); - - this._jumpToSymbolTrackingModeEnabled = false; - this._tokenTrackingController.classNameForHighlightedRange = WebInspector.CodeMirrorTokenTrackingController.JumpToSymbolHighlightStyleClassName; - this._tokenTrackingController.mouseOverDelayDuration = 0; - this._tokenTrackingController.mouseOutReleaseDelayDuration = 0; - this._tokenTrackingController.mode = WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens; - - this.style = style; -}; - -WebInspector.Object.addConstructorFunctions(WebInspector.CSSStyleDeclarationTextEditor); - -WebInspector.CSSStyleDeclarationTextEditor.StyleClassName = "css-style-text-editor"; -WebInspector.CSSStyleDeclarationTextEditor.ReadOnlyStyleClassName = "read-only"; -WebInspector.CSSStyleDeclarationTextEditor.ColorSwatchElementStyleClassName = "color-swatch"; -WebInspector.CSSStyleDeclarationTextEditor.CheckboxPlaceholderElementStyleClassName = "checkbox-placeholder"; -WebInspector.CSSStyleDeclarationTextEditor.EditingLineStyleClassName = "editing-line"; -WebInspector.CSSStyleDeclarationTextEditor.CommitCoalesceDelay = 250; -WebInspector.CSSStyleDeclarationTextEditor.RemoveEditingLineClassesDelay = 2000; - -WebInspector.CSSStyleDeclarationTextEditor.prototype = { - constructor: WebInspector.CSSStyleDeclarationTextEditor, - - // Public - - get element() - { - return this._element; - }, - - get delegate() - { - return this._delegate; - }, - - set delegate(delegate) - { - this._delegate = delegate || null; - }, - - get style() - { - return this._style; - }, - - set style(style) - { - if (this._style === style) - return; - - if (this._style) { - this._style.removeEventListener(WebInspector.CSSStyleDeclaration.Event.PropertiesChanged, this._propertiesChanged, this); - if (this._style.ownerRule && this._style.ownerRule.sourceCodeLocation) - WebInspector.notifications.removeEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateJumpToSymbolTrackingMode, this); - } - - this._style = style || null; - - if (this._style) { - this._style.addEventListener(WebInspector.CSSStyleDeclaration.Event.PropertiesChanged, this._propertiesChanged, this); - if (this._style.ownerRule && this._style.ownerRule.sourceCodeLocation) - WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateJumpToSymbolTrackingMode, this); - } - - this._updateJumpToSymbolTrackingMode(); - - this._resetContent(); - }, - - get focused() - { - return this._codeMirror.getWrapperElement().classList.contains("CodeMirror-focused"); - }, - - get alwaysShowPropertyNames() - { - return Object.keys(this._alwaysShowPropertyNames); - }, - - set alwaysShowPropertyNames(alwaysShowPropertyNames) - { - this._alwaysShowPropertyNames = (alwaysShowPropertyNames || []).keySet(); - - this._resetContent(); - }, - - get showsImplicitProperties() - { - return this._showsImplicitProperties; - }, - - set showsImplicitProperties(showsImplicitProperties) - { - if (this._showsImplicitProperties === showsImplicitProperties) - return; - - this._showsImplicitProperties = showsImplicitProperties; - - this._resetContent(); - }, - - get sortProperties() - { - return this._sortProperties; - }, - - set sortProperties(sortProperties) - { - if (this._sortProperties === sortProperties) - return; - - this._sortProperties = sortProperties; - - this._resetContent(); - }, - - focus: function() - { - this._codeMirror.focus(); - }, - - refresh: function() - { - this._resetContent(); - }, - - updateLayout: function(force) - { - this._codeMirror.refresh(); - }, - - // Protected - - didDismissPopover: function(popover) - { - if (popover === this._colorPickerPopover) - delete this._colorPickerPopover; - }, - - completionControllerCompletionsHidden: function(completionController) - { - var styleText = this._style.text; - var currentText = this._formattedContent(); - - // If the style text and the current editor text differ then we need to commit. - // Otherwise we can just update the properties that got skipped because a completion - // was pending the last time _propertiesChanged was called. - if (styleText !== currentText) - this._commitChanges(); - else - this._propertiesChanged(); - }, - - // Private - - _clearRemoveEditingLineClassesTimeout: function() - { - if (!this._removeEditingLineClassesTimeout) - return; - - clearTimeout(this._removeEditingLineClassesTimeout); - delete this._removeEditingLineClassesTimeout; - }, - - _removeEditingLineClasses: function() - { - this._clearRemoveEditingLineClassesTimeout(); - - function removeEditingLineClasses() - { - var lineCount = this._codeMirror.lineCount(); - for (var i = 0; i < lineCount; ++i) - this._codeMirror.removeLineClass(i, "wrap", WebInspector.CSSStyleDeclarationTextEditor.EditingLineStyleClassName); - } - - this._codeMirror.operation(removeEditingLineClasses.bind(this)); - }, - - _removeEditingLineClassesSoon: function() - { - if (this._removeEditingLineClassesTimeout) - return; - this._removeEditingLineClassesTimeout = setTimeout(this._removeEditingLineClasses.bind(this), WebInspector.CSSStyleDeclarationTextEditor.RemoveEditingLineClassesDelay); - }, - - _formattedContent: function() - { - // Start with the prefix whitespace we stripped. - var content = this._prefixWhitespace; - - // Get each line and add the line prefix whitespace and newlines. - var lineCount = this._codeMirror.lineCount(); - for (var i = 0; i < lineCount; ++i) { - var lineContent = this._codeMirror.getLine(i); - content += this._linePrefixWhitespace + lineContent; - if (i !== lineCount - 1) - content += "\n"; - } - - // Add the suffix whitespace we stripped. - content += this._suffixWhitespace; - - return content; - }, - - _commitChanges: function() - { - if (this._commitChangesTimeout) { - clearTimeout(this._commitChangesTimeout); - delete this._commitChangesTimeout; - } - - this._style.text = this._formattedContent(); - }, - - _editorBlured: function(codeMirror) - { - // Clicking a suggestion causes the editor to blur. We don't want to reset content in this case. - if (this._completionController.isHandlingClickEvent()) - return; - - // Reset the content on blur since we stop accepting external changes while the the editor is focused. - // This causes us to pick up any change that was suppressed while the editor was focused. - this._resetContent(); - }, - - _contentChanged: function(codeMirror, change) - { - // Return early if the style isn't editable. This still can be called when readOnly is set because - // clicking on a color swatch modifies the text. - if (!this._style || !this._style.editable || this._ignoreCodeMirrorContentDidChangeEvent) - return; - - this._markLinesWithCheckboxPlaceholder(); - - this._clearRemoveEditingLineClassesTimeout(); - this._codeMirror.addLineClass(change.from.line, "wrap", WebInspector.CSSStyleDeclarationTextEditor.EditingLineStyleClassName); - - // When the change is a completion change, create color swatches now since the changes - // will not go through _propertiesChanged until completionControllerCompletionsHidden happens. - // This way any auto completed colors get swatches right away. - if (this._completionController.isCompletionChange(change)) - this._createColorSwatches(false, change.from.line); - - // Use a short delay for user input to coalesce more changes before committing. Other actions like - // undo, redo and paste are atomic and work better with a zero delay. CodeMirror identifies changes that - // get coalesced in the undo stack with a "+" prefix on the origin. Use that to set the delay for our coalescing. - const delay = change.origin && change.origin.charAt(0) === "+" ? WebInspector.CSSStyleDeclarationTextEditor.CommitCoalesceDelay : 0; - - // Reset the timeout so rapid changes coalesce after a short delay. - if (this._commitChangesTimeout) - clearTimeout(this._commitChangesTimeout); - this._commitChangesTimeout = setTimeout(this._commitChanges.bind(this), delay); - }, - - _updateTextMarkers: function(nonatomic) - { - function update() - { - this._clearTextMarkers(true); - - var styleText = this._style.text; - - this._iterateOverProperties(true, function(property) { - var styleTextRange = property.styleDeclarationTextRange; - console.assert(styleTextRange); - if (!styleTextRange) - return; - - var from = {line: styleTextRange.startLine, ch: styleTextRange.startColumn}; - var to = {line: styleTextRange.endLine, ch: styleTextRange.endColumn}; - - // Adjust the line position for the missing prefix line. - if (this._prefixWhitespace) { - --from.line; - --to.line; - } - - // Adjust the column for the stripped line prefix whitespace. - from.ch -= this._linePrefixWhitespace.length; - to.ch -= this._linePrefixWhitespace.length; - - this._createTextMarkerForPropertyIfNeeded(from, to, property); - }); - - if (!this._codeMirror.getOption("readOnly")) { - // Matches a comment like: /* -webkit-foo: bar; */ - const commentedPropertyRegex = /\/\*\s*[-\w]+\s*:\s*[^;]+;?\s*\*\//g; - - // Look for comments that look like properties and add checkboxes in front of them. - var lineCount = this._codeMirror.lineCount(); - for (var i = 0; i < lineCount; ++i) { - var lineContent = this._codeMirror.getLine(i); - - var match = commentedPropertyRegex.exec(lineContent); - while (match) { - var checkboxElement = document.createElement("input"); - checkboxElement.type = "checkbox"; - checkboxElement.checked = false; - checkboxElement.addEventListener("change", this._propertyCommentCheckboxChanged.bind(this)); - - var from = {line: i, ch: match.index}; - var to = {line: i, ch: match.index + match[0].length}; - - var checkboxMarker = this._codeMirror.setUniqueBookmark(from, checkboxElement); - checkboxMarker.__propertyCheckbox = true; - - var commentTextMarker = this._codeMirror.markText(from, to); - - checkboxElement.__commentTextMarker = commentTextMarker; - - match = commentedPropertyRegex.exec(lineContent); - } - } - } - - // Look for colors and make swatches. - this._createColorSwatches(true); - - this._markLinesWithCheckboxPlaceholder(); - } - - if (nonatomic) - update.call(this); - else - this._codeMirror.operation(update.bind(this)); - }, - - _createColorSwatches: function(nonatomic, lineNumber) - { - function update() - { - // Look for color strings and add swatches in front of them. - this._codeMirror.createColorMarkers(lineNumber, function(marker, color, colorString) { - var swatchElement = document.createElement("span"); - swatchElement.title = WebInspector.UIString("Click to open a colorpicker. Shift-click to change color format."); - swatchElement.className = WebInspector.CSSStyleDeclarationTextEditor.ColorSwatchElementStyleClassName; - swatchElement.addEventListener("click", this._colorSwatchClicked.bind(this)); - - var swatchInnerElement = document.createElement("span"); - swatchInnerElement.style.backgroundColor = colorString; - swatchElement.appendChild(swatchInnerElement); - - var codeMirrorTextMarker = marker.codeMirrorTextMarker; - var swatchMarker = this._codeMirror.setUniqueBookmark(codeMirrorTextMarker.find().from, swatchElement); - - swatchInnerElement.__colorTextMarker = codeMirrorTextMarker; - swatchInnerElement.__color = color; - }.bind(this)); - } - - if (nonatomic) - update.call(this); - else - this._codeMirror.operation(update.bind(this)); - }, - - _updateTextMarkerForPropertyIfNeeded: function(property) - { - var textMarker = property.__propertyTextMarker; - console.assert(textMarker); - if (!textMarker) - return; - - var range = textMarker.find(); - console.assert(range); - if (!range) - return; - - this._createTextMarkerForPropertyIfNeeded(range.from, range.to, property); - }, - - _createTextMarkerForPropertyIfNeeded: function(from, to, property) - { - if (!this._codeMirror.getOption("readOnly")) { - // Create a new checkbox element and marker. - - console.assert(property.enabled); - - var checkboxElement = document.createElement("input"); - checkboxElement.type = "checkbox"; - checkboxElement.checked = true; - checkboxElement.addEventListener("change", this._propertyCheckboxChanged.bind(this)); - checkboxElement.__cssProperty = property; - - var checkboxMarker = this._codeMirror.setUniqueBookmark(from, checkboxElement); - checkboxMarker.__propertyCheckbox = true; - } - - var classNames = ["css-style-declaration-property"]; - - if (property.overridden) - classNames.push("overridden"); - - if (property.implicit) - classNames.push("implicit"); - - if (this._style.inherited && !property.inherited) - classNames.push("not-inherited"); - - if (!property.valid && property.hasOtherVendorNameOrKeyword()) - classNames.push("other-vendor"); - else if (!property.valid) - classNames.push("invalid"); - - if (!property.enabled) - classNames.push("disabled"); - - var classNamesString = classNames.join(" "); - - // If there is already a text marker and it's in the same document, then try to avoid recreating it. - // FIXME: If there are multiple CSSStyleDeclarationTextEditors for the same style then this will cause - // both editors to fight and always recreate their text markers. This isn't really common. - if (property.__propertyTextMarker && property.__propertyTextMarker.doc.cm === this._codeMirror && property.__propertyTextMarker.find()) { - // If the class name is the same then we don't need to make a new marker. - if (property.__propertyTextMarker.className === classNamesString) - return; - - property.__propertyTextMarker.clear(); - } - - var propertyTextMarker = this._codeMirror.markText(from, to, {className: classNamesString}); - - propertyTextMarker.__cssProperty = property; - property.__propertyTextMarker = propertyTextMarker; - - property.addEventListener(WebInspector.CSSProperty.Event.OverriddenStatusChanged, this._propertyOverriddenStatusChanged, this); - - this._removeCheckboxPlaceholder(from.line); - }, - - _clearTextMarkers: function(nonatomic, all) - { - function clear() - { - var markers = this._codeMirror.getAllMarks(); - for (var i = 0; i < markers.length; ++i) { - var textMarker = markers[i]; - - if (!all && textMarker.__checkboxPlaceholder) { - var position = textMarker.find(); - - // Only keep checkbox placeholders if they are in the first column. - if (position && !position.ch) - continue; - } - - if (textMarker.__cssProperty) { - textMarker.__cssProperty.removeEventListener(null, null, this); - - delete textMarker.__cssProperty.__propertyTextMarker; - delete textMarker.__cssProperty; - } - - textMarker.clear(); - } - } - - if (nonatomic) - clear.call(this); - else - this._codeMirror.operation(clear.bind(this)); - }, - - _iterateOverProperties: function(onlyVisibleProperties, callback) - { - var properties = onlyVisibleProperties ? this._style.visibleProperties : this._style.properties; - - if (!onlyVisibleProperties) { - // Filter based on options only when all properties are used. - properties = properties.filter((function(property) { - return !property.implicit || this._showsImplicitProperties || property.canonicalName in this._alwaysShowPropertyNames; - }).bind(this)); - - if (this._sortProperties) - properties.sort(function(a, b) { return a.name.localeCompare(b.name) }); - } - - for (var i = 0; i < properties.length; ++i) { - if (callback.call(this, properties[i], i === properties.length - 1)) - break; - } - }, - - _propertyCheckboxChanged: function(event) - { - var property = event.target.__cssProperty; - console.assert(property); - if (!property) - return; - - var textMarker = property.__propertyTextMarker; - console.assert(textMarker); - if (!textMarker) - return; - - // Check if the property has been removed already, like from double-clicking - // the checkbox and calling this event listener multiple times. - var range = textMarker.find(); - if (!range) - return; - - var text = this._codeMirror.getRange(range.from, range.to); - - function update() - { - // Replace the text with a commented version. - this._codeMirror.replaceRange("/* " + text + " */", range.from, range.to); - - // Update the line for any color swatches that got removed. - this._createColorSwatches(true, range.from.line); - } - - this._codeMirror.operation(update.bind(this)); - }, - - _propertyCommentCheckboxChanged: function(event) - { - var commentTextMarker = event.target.__commentTextMarker; - console.assert(commentTextMarker); - if (!commentTextMarker) - return; - - // Check if the comment has been removed already, like from double-clicking - // the checkbox and calling event listener multiple times. - var range = commentTextMarker.find(); - if (!range) - return; - - var text = this._codeMirror.getRange(range.from, range.to); - - // Remove the comment prefix and suffix. - text = text.replace(/^\/\*\s*/, "").replace(/\s*\*\/$/, ""); - - // Add a semicolon if there isn't one already. - if (text.length && text.charAt(text.length - 1) !== ";") - text += ";"; - - function update() - { - this._codeMirror.addLineClass(range.from.line, "wrap", WebInspector.CSSStyleDeclarationTextEditor.EditingLineStyleClassName); - this._codeMirror.replaceRange(text, range.from, range.to); - - // Update the line for any color swatches that got removed. - this._createColorSwatches(true, range.from.line); - } - - this._codeMirror.operation(update.bind(this)); - }, - - _colorSwatchClicked: function(event) - { - if (this._colorPickerPopover) - return; - - var swatch = event.target; - - var color = swatch.__color; - console.assert(color); - if (!color) - return; - - var colorTextMarker = swatch.__colorTextMarker; - console.assert(colorTextMarker); - if (!colorTextMarker) - return; - - var range = colorTextMarker.find(); - console.assert(range); - if (!range) - return; - - function updateCodeMirror(newColorText) - { - function update() - { - // The original text marker might have been cleared by a style update, - // in this case we need to find the new color text marker so we know - // the right range for the new style color text. - if (!colorTextMarker || !colorTextMarker.find()) { - colorTextMarker = null; - - var marks = this._codeMirror.findMarksAt(range.from); - if (!marks.length) - return; - - for (var i = 0; i < marks.length; ++i) { - var mark = marks[i]; - if (!mark.__markedColor) - continue; - colorTextMarker = mark; - break; - } - } - - if (!colorTextMarker) - return; - - // Sometimes we still might find a stale text marker with findMarksAt. - var newRange = colorTextMarker.find(); - if (!newRange) - return; - - range = newRange; - - colorTextMarker.clear(); - - this._codeMirror.replaceRange(newColorText, range.from, range.to); - - // The color's text format could have changed, so we need to update the "range" - // variable to anticipate a different "range.to" property. - range.to.ch = range.from.ch + newColorText.length; - - colorTextMarker = this._codeMirror.markText(range.from, range.to); - colorTextMarker.__markedColor = true; - - swatch.__colorTextMarker = colorTextMarker; - } - - this._codeMirror.operation(update.bind(this)); - } - - if (event.shiftKey) { - var nextFormat = color.nextFormat(); - console.assert(nextFormat); - if (!nextFormat) - return; - color.format = nextFormat; - - var newColorText = color.toString(); - - // Ignore the change so we don't commit the format change. However, any future user - // edits will commit the color format. - this._ignoreCodeMirrorContentDidChangeEvent = true; - updateCodeMirror.call(this, newColorText); - delete this._ignoreCodeMirrorContentDidChangeEvent; - } else { - this._colorPickerPopover = new WebInspector.Popover(this); - - var colorPicker = new WebInspector.ColorPicker; - - colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, function(event) { - updateCodeMirror.call(this, event.data.color.toString()); - }.bind(this)); - - var bounds = WebInspector.Rect.rectFromClientRect(swatch.getBoundingClientRect()); - - this._colorPickerPopover.content = colorPicker.element; - this._colorPickerPopover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]); - - colorPicker.color = color; - } - }, - - _propertyOverriddenStatusChanged: function(event) - { - this._updateTextMarkerForPropertyIfNeeded(event.target); - }, - - _propertiesChanged: function(event) - { - // Don't try to update the document while completions are showing. Doing so will clear - // the completion hint and prevent further interaction with the completion. - if (this._completionController.isShowingCompletions()) - return; - - // Reset the content if the text is different and we are not focused. - if (!this.focused && this._style.text !== this._formattedContent()) { - this._resetContent(); - return; - } - - this._removeEditingLineClassesSoon(); - - this._updateTextMarkers(); - }, - - _markLinesWithCheckboxPlaceholder: function() - { - if (this._codeMirror.getOption("readOnly")) - return; - - var linesWithPropertyCheckboxes = {}; - var linesWithCheckboxPlaceholders = {}; - - var markers = this._codeMirror.getAllMarks(); - for (var i = 0; i < markers.length; ++i) { - var textMarker = markers[i]; - if (textMarker.__propertyCheckbox) { - var position = textMarker.find(); - if (position) - linesWithPropertyCheckboxes[position.line] = true; - } else if (textMarker.__checkboxPlaceholder) { - var position = textMarker.find(); - if (position) - linesWithCheckboxPlaceholders[position.line] = true; - } - } - - var lineCount = this._codeMirror.lineCount(); - - for (var i = 0; i < lineCount; ++i) { - if (i in linesWithPropertyCheckboxes || i in linesWithCheckboxPlaceholders) - continue; - - var position = {line: i, ch: 0}; - - var placeholderElement = document.createElement("div"); - placeholderElement.className = WebInspector.CSSStyleDeclarationTextEditor.CheckboxPlaceholderElementStyleClassName; - - var placeholderMark = this._codeMirror.setUniqueBookmark(position, placeholderElement); - placeholderMark.__checkboxPlaceholder = true; - } - }, - - _removeCheckboxPlaceholder: function(lineNumber) - { - var marks = this._codeMirror.findMarksAt({line: lineNumber, ch: 0}); - for (var i = 0; i < marks.length; ++i) { - var mark = marks[i]; - if (!mark.__checkboxPlaceholder) - continue; - - mark.clear(); - return; - } - }, - - _resetContent: function() - { - if (this._commitChangesTimeout) { - clearTimeout(this._commitChangesTimeout); - delete this._commitChangesTimeout; - } - - this._removeEditingLineClasses(); - - // Only allow editing if we have a style, it is editable and we have text range in the stylesheet. - var readOnly = !this._style || !this._style.editable || !this._style.styleSheetTextRange; - this._codeMirror.setOption("readOnly", readOnly); - - if (readOnly) { - this.element.classList.add(WebInspector.CSSStyleDeclarationTextEditor.ReadOnlyStyleClassName); - this._codeMirror.setOption("placeholder", WebInspector.UIString("No Properties")); - } else { - this.element.classList.remove(WebInspector.CSSStyleDeclarationTextEditor.ReadOnlyStyleClassName); - this._codeMirror.setOption("placeholder", WebInspector.UIString("No Properties \u2014 Click to Edit")); - } - - if (!this._style) { - this._ignoreCodeMirrorContentDidChangeEvent = true; - - this._clearTextMarkers(false, true); - - this._codeMirror.setValue(""); - this._codeMirror.clearHistory(); - this._codeMirror.markClean(); - - delete this._ignoreCodeMirrorContentDidChangeEvent; - - return; - } - - function update() - { - // Remember the cursor position/selection. - var selectionAnchor = this._codeMirror.getCursor("anchor"); - var selectionHead = this._codeMirror.getCursor("head"); - - function countNewLineCharacters(text) - { - var matches = text.match(/\n/g); - return matches ? matches.length : 0; - } - - var styleText = this._style.text; - - // Pretty print the content if there are more properties than there are lines. - // This could be an option exposed to the user; however, it is almost always - // desired in this case. - - if (styleText && this._style.visibleProperties.length <= countNewLineCharacters(styleText.trim()) + 1) { - // This style has formatted text content, so use it for a high-fidelity experience. - - var prefixWhitespaceMatch = styleText.match(/^[ \t]*\n/); - this._prefixWhitespace = prefixWhitespaceMatch ? prefixWhitespaceMatch[0] : ""; - - var suffixWhitespaceMatch = styleText.match(/\n[ \t]*$/); - this._suffixWhitespace = suffixWhitespaceMatch ? suffixWhitespaceMatch[0] : ""; - - this._codeMirror.setValue(styleText); - - if (this._prefixWhitespace) - this._codeMirror.removeLine(0); - - if (this._suffixWhitespace) { - var lineCount = this._codeMirror.lineCount(); - this._codeMirror.replaceRange("", {line: lineCount - 2}, {line: lineCount - 1}); - } - - this._linePrefixWhitespace = ""; - - var linesToStrip = []; - - // Remember the whitespace so it can be restored on commit. - var lineCount = this._codeMirror.lineCount(); - for (var i = 0; i < lineCount; ++i) { - var lineContent = this._codeMirror.getLine(i); - - var prefixWhitespaceMatch = lineContent.match(/^\s+/); - if (!prefixWhitespaceMatch) - continue; - - linesToStrip.push(i); - - // Only remember the shortest whitespace so we don't loose any of the - // original author's whitespace if their indentation lengths differed. - // Using the shortest also makes the adjustment work in _updateTextMarkers. - - // FIXME: This messes up if there is a mix of spaces and tabs. One tab - // will be shorter than 4 or 8 spaces, but will look the same visually. - if (!this._linePrefixWhitespace || prefixWhitespaceMatch[0].length < this._linePrefixWhitespace.length) - this._linePrefixWhitespace = prefixWhitespaceMatch[0]; - } - - // Strip the whitespace from the beginning of each line. - for (var i = 0; i < linesToStrip.length; ++i) { - var lineNumber = linesToStrip[i]; - var from = {line: lineNumber, ch: 0}; - var to = {line: lineNumber, ch: this._linePrefixWhitespace.length}; - this._codeMirror.replaceRange("", from, to); - } - - // Update all the text markers. - this._updateTextMarkers(true); - } else { - // This style does not have text content or it is minified, so we want to synthesize the text content. - - this._prefixWhitespace = ""; - this._suffixWhitespace = ""; - this._linePrefixWhitespace = ""; - - this._codeMirror.setValue(""); - - var lineNumber = 0; - - // Iterate only visible properties if we have original style text. That way we known we only syntesize - // what was originaly in the style text. - this._iterateOverProperties(styleText ? true : false, function(property) { - // Some property text can have line breaks, so consider that in the ranges below. - var propertyText = property.synthesizedText; - var propertyLineCount = countNewLineCharacters(propertyText); - - var from = {line: lineNumber, ch: 0}; - var to = {line: lineNumber + propertyLineCount}; - - this._codeMirror.replaceRange((lineNumber ? "\n" : "") + propertyText, from); - this._createTextMarkerForPropertyIfNeeded(from, to, property); - - lineNumber += propertyLineCount + 1; - }); - - // Look for colors and make swatches. - this._createColorSwatches(true); - } - - this._markLinesWithCheckboxPlaceholder(); - - // Restore the cursor position/selection. - this._codeMirror.setSelection(selectionAnchor, selectionHead); - - // Reset undo history since undo past the reset is wrong when the content was empty before - // or the content was representing a previous style object. - this._codeMirror.clearHistory(); - - // Mark the editor as clean (unedited state). - this._codeMirror.markClean(); - } - - // This needs to be done first and as a separate operation to avoid an exception in CodeMirror. - this._clearTextMarkers(false, true); - - this._ignoreCodeMirrorContentDidChangeEvent = true; - this._codeMirror.operation(update.bind(this)); - delete this._ignoreCodeMirrorContentDidChangeEvent; - }, - - _updateJumpToSymbolTrackingMode: function() - { - var oldJumpToSymbolTrackingModeEnabled = this._jumpToSymbolTrackingModeEnabled; - - if (!this._style || !this._style.ownerRule || !this._style.ownerRule.sourceCodeLocation) - this._jumpToSymbolTrackingModeEnabled = false; - else - this._jumpToSymbolTrackingModeEnabled = WebInspector.modifierKeys.metaKey && !WebInspector.modifierKeys.altKey && !WebInspector.modifierKeys.shiftKey; - - if (oldJumpToSymbolTrackingModeEnabled !== this._jumpToSymbolTrackingModeEnabled) { - if (this._jumpToSymbolTrackingModeEnabled) { - this._tokenTrackingController.highlightLastHoveredRange(); - this._tokenTrackingController.enabled = !this._codeMirror.getOption("readOnly"); - } else { - this._tokenTrackingController.removeHighlightedRange(); - this._tokenTrackingController.enabled = false; - } - } - }, - - tokenTrackingControllerHighlightedRangeWasClicked: function(tokenTrackingController) - { - console.assert(this._style.ownerRule.sourceCodeLocation); - if (!this._style.ownerRule.sourceCodeLocation) - return; - - // Special case command clicking url(...) links. - var token = this._tokenTrackingController.candidate.hoveredToken; - if (/\blink\b/.test(token.type)) { - var url = token.string; - var baseURL = this._style.ownerRule.sourceCodeLocation.sourceCode.url; - WebInspector.openURL(absoluteURL(url, baseURL)); - return; - } - - // Jump to the rule if we can't find a property. - // Find a better source code location from the property that was clicked. - var sourceCodeLocation = this._style.ownerRule.sourceCodeLocation; - var marks = this._codeMirror.findMarksAt(this._tokenTrackingController.candidate.hoveredTokenRange.start); - for (var i = 0; i < marks.length; ++i) { - var mark = marks[i]; - var property = mark.__cssProperty; - if (property) { - var sourceCode = sourceCodeLocation.sourceCode; - var styleSheetTextRange = property.styleSheetTextRange; - sourceCodeLocation = sourceCode.createSourceCodeLocation(styleSheetTextRange.startLine, styleSheetTextRange.startColumn); - } - } - - WebInspector.resourceSidebarPanel.showSourceCodeLocation(sourceCodeLocation); - }, - - tokenTrackingControllerNewHighlightCandidate: function(tokenTrackingController, candidate) - { - this._tokenTrackingController.highlightRange(candidate.hoveredTokenRange); - } -}; - -WebInspector.CSSStyleDeclarationTextEditor.prototype.__proto__ = WebInspector.Object.prototype; |