summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js1006
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;