Index: third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js |
index 0b4fa5624c075da79a3ae13119674acfe364982f..809f2a3735b1f6ee5b5f6a4a32791df3eed20ffa 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js |
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js |
@@ -26,2859 +26,2735 @@ |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
- |
/** |
- * @constructor |
- * @extends {WebInspector.ElementsSidebarPane} |
+ * @unrestricted |
*/ |
-WebInspector.StylesSidebarPane = function() |
-{ |
- WebInspector.ElementsSidebarPane.call(this); |
+WebInspector.StylesSidebarPane = class extends WebInspector.ElementsSidebarPane { |
+ constructor() { |
+ super(); |
this.setMinimumSize(96, 26); |
- WebInspector.moduleSetting("colorFormat").addChangeListener(this.update.bind(this)); |
- WebInspector.moduleSetting("textEditorIndent").addChangeListener(this.update.bind(this)); |
+ WebInspector.moduleSetting('colorFormat').addChangeListener(this.update.bind(this)); |
+ WebInspector.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this)); |
- this._sectionsContainer = this.element.createChild("div"); |
+ this._sectionsContainer = this.element.createChild('div'); |
this._swatchPopoverHelper = new WebInspector.SwatchPopoverHelper(); |
this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultCSSFormatter()); |
- this.element.classList.add("styles-pane"); |
+ this.element.classList.add('styles-pane'); |
- /** @type {!Array<!WebInspector.SectionBlock>} */ |
+ /** @type {!Array<!WebInspector.SectionBlock>} */ |
this._sectionBlocks = []; |
WebInspector.StylesSidebarPane._instance = this; |
- WebInspector.targetManager.addModelListener(WebInspector.CSSModel, WebInspector.CSSModel.Events.LayoutEditorChange, this._onLayoutEditorChange, this); |
+ WebInspector.targetManager.addModelListener( |
+ WebInspector.CSSModel, WebInspector.CSSModel.Events.LayoutEditorChange, this._onLayoutEditorChange, this); |
WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this.forceUpdate, this); |
-}; |
- |
-/** |
- * @param {!WebInspector.CSSProperty} property |
- * @return {!Element} |
- */ |
-WebInspector.StylesSidebarPane.createExclamationMark = function(property) |
-{ |
- var exclamationElement = createElement("label", "dt-icon-label"); |
- exclamationElement.className = "exclamation-mark"; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSProperty} property |
+ * @return {!Element} |
+ */ |
+ static createExclamationMark(property) { |
+ var exclamationElement = createElement('label', 'dt-icon-label'); |
+ exclamationElement.className = 'exclamation-mark'; |
if (!WebInspector.StylesSidebarPane.ignoreErrorsForProperty(property)) |
- exclamationElement.type = "warning-icon"; |
- exclamationElement.title = WebInspector.cssMetadata().isCSSPropertyName(property.name) ? WebInspector.UIString("Invalid property value") : WebInspector.UIString("Unknown property name"); |
+ exclamationElement.type = 'warning-icon'; |
+ exclamationElement.title = WebInspector.cssMetadata().isCSSPropertyName(property.name) ? |
+ WebInspector.UIString('Invalid property value') : |
+ WebInspector.UIString('Unknown property name'); |
return exclamationElement; |
-}; |
+ } |
-/** |
- * @param {!WebInspector.CSSProperty} property |
- * @return {boolean} |
- */ |
-WebInspector.StylesSidebarPane.ignoreErrorsForProperty = function(property) { |
+ /** |
+ * @param {!WebInspector.CSSProperty} property |
+ * @return {boolean} |
+ */ |
+ static ignoreErrorsForProperty(property) { |
/** |
* @param {string} string |
*/ |
- function hasUnknownVendorPrefix(string) |
- { |
- return !string.startsWith("-webkit-") && /^[-_][\w\d]+-\w/.test(string); |
+ function hasUnknownVendorPrefix(string) { |
+ return !string.startsWith('-webkit-') && /^[-_][\w\d]+-\w/.test(string); |
} |
var name = property.name.toLowerCase(); |
// IE hack. |
- if (name.charAt(0) === "_") |
- return true; |
+ if (name.charAt(0) === '_') |
+ return true; |
// IE has a different format for this. |
- if (name === "filter") |
- return true; |
+ if (name === 'filter') |
+ return true; |
// Common IE-specific property prefix. |
- if (name.startsWith("scrollbar-")) |
- return true; |
+ if (name.startsWith('scrollbar-')) |
+ return true; |
if (hasUnknownVendorPrefix(name)) |
- return true; |
+ return true; |
var value = property.value.toLowerCase(); |
// IE hack. |
- if (value.endsWith("\\9")) |
- return true; |
+ if (value.endsWith('\\9')) |
+ return true; |
if (hasUnknownVendorPrefix(value)) |
- return true; |
+ return true; |
return false; |
-}; |
- |
-WebInspector.StylesSidebarPane.prototype = { |
- /** |
- * @param {!WebInspector.Event} event |
- */ |
- _onLayoutEditorChange: function(event) |
- { |
- var cssModel = /** @type {!WebInspector.CSSModel} */(event.target); |
- var styleSheetId = event.data["id"]; |
- var sourceRange = /** @type {!CSSAgent.SourceRange} */(event.data["range"]); |
- var range = WebInspector.TextRange.fromObject(sourceRange); |
- this._decorator = new WebInspector.PropertyChangeHighlighter(this, cssModel, styleSheetId, range); |
- this.update(); |
- }, |
+ } |
+ |
+ /** |
+ * @param {string} placeholder |
+ * @param {!Element} container |
+ * @param {function(?RegExp)} filterCallback |
+ * @return {!Element} |
+ */ |
+ static createPropertyFilterElement(placeholder, container, filterCallback) { |
+ var input = createElement('input'); |
+ input.placeholder = placeholder; |
- /** |
- * @param {!WebInspector.CSSProperty} cssProperty |
- */ |
- revealProperty: function(cssProperty) |
- { |
- this._decorator = new WebInspector.PropertyRevealHighlighter(this, cssProperty); |
- this._decorator.perform(); |
- this.update(); |
- }, |
- |
- forceUpdate: function() |
- { |
- this._swatchPopoverHelper.hide(); |
- this._resetCache(); |
- this.update(); |
- }, |
+ function searchHandler() { |
+ var regex = input.value ? new RegExp(input.value.escapeForRegExp(), 'i') : null; |
+ filterCallback(regex); |
+ container.classList.toggle('styles-filter-engaged', !!input.value); |
+ } |
+ input.addEventListener('input', searchHandler, false); |
/** |
* @param {!Event} event |
*/ |
- _onAddButtonLongClick: function(event) |
- { |
- var cssModel = this.cssModel(); |
- if (!cssModel) |
- return; |
- var headers = cssModel.styleSheetHeaders().filter(styleSheetResourceHeader); |
- |
- /** @type {!Array.<{text: string, handler: function()}>} */ |
- var contextMenuDescriptors = []; |
- for (var i = 0; i < headers.length; ++i) { |
- var header = headers[i]; |
- var handler = this._createNewRuleInStyleSheet.bind(this, header); |
- contextMenuDescriptors.push({ |
- text: WebInspector.displayNameForURL(header.resourceURL()), |
- handler: handler |
- }); |
- } |
- |
- contextMenuDescriptors.sort(compareDescriptors); |
- |
- var contextMenu = new WebInspector.ContextMenu(event); |
- for (var i = 0; i < contextMenuDescriptors.length; ++i) { |
- var descriptor = contextMenuDescriptors[i]; |
- contextMenu.appendItem(descriptor.text, descriptor.handler); |
- } |
- if (!contextMenu.isEmpty()) |
- contextMenu.appendSeparator(); |
- contextMenu.appendItem("inspector-stylesheet", this._createNewRuleInViaInspectorStyleSheet.bind(this)); |
- contextMenu.show(); |
- |
- /** |
- * @param {!{text: string, handler: function()}} descriptor1 |
- * @param {!{text: string, handler: function()}} descriptor2 |
- * @return {number} |
- */ |
- function compareDescriptors(descriptor1, descriptor2) |
- { |
- return String.naturalOrderComparator(descriptor1.text, descriptor2.text); |
- } |
+ function keydownHandler(event) { |
+ if (event.key !== 'Escape' || !input.value) |
+ return; |
+ event.consume(true); |
+ input.value = ''; |
+ searchHandler(); |
+ } |
+ input.addEventListener('keydown', keydownHandler, false); |
- /** |
- * @param {!WebInspector.CSSStyleSheetHeader} header |
- * @return {boolean} |
- */ |
- function styleSheetResourceHeader(header) |
- { |
- return !header.isViaInspector() && !header.isInline && !!header.resourceURL(); |
- } |
- }, |
+ input.setFilterValue = setFilterValue; |
/** |
- * @param {?RegExp} regex |
+ * @param {string} value |
*/ |
- onFilterChanged: function(regex) |
- { |
- this._filterRegex = regex; |
- this._updateFilter(); |
- }, |
+ function setFilterValue(value) { |
+ input.value = value; |
+ input.focus(); |
+ searchHandler(); |
+ } |
- /** |
- * @param {!WebInspector.StylePropertiesSection=} editedSection |
- */ |
- _refreshUpdate: function(editedSection) |
- { |
- var node = this.node(); |
- if (!node) |
- return; |
+ return input; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Event} event |
+ */ |
+ _onLayoutEditorChange(event) { |
+ var cssModel = /** @type {!WebInspector.CSSModel} */ (event.target); |
+ var styleSheetId = event.data['id']; |
+ var sourceRange = /** @type {!CSSAgent.SourceRange} */ (event.data['range']); |
+ var range = WebInspector.TextRange.fromObject(sourceRange); |
+ this._decorator = new WebInspector.PropertyChangeHighlighter(this, cssModel, styleSheetId, range); |
+ this.update(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSProperty} cssProperty |
+ */ |
+ revealProperty(cssProperty) { |
+ this._decorator = new WebInspector.PropertyRevealHighlighter(this, cssProperty); |
+ this._decorator.perform(); |
+ this.update(); |
+ } |
+ |
+ forceUpdate() { |
+ this._swatchPopoverHelper.hide(); |
+ this._resetCache(); |
+ this.update(); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _onAddButtonLongClick(event) { |
+ var cssModel = this.cssModel(); |
+ if (!cssModel) |
+ return; |
+ var headers = cssModel.styleSheetHeaders().filter(styleSheetResourceHeader); |
+ |
+ /** @type {!Array.<{text: string, handler: function()}>} */ |
+ var contextMenuDescriptors = []; |
+ for (var i = 0; i < headers.length; ++i) { |
+ var header = headers[i]; |
+ var handler = this._createNewRuleInStyleSheet.bind(this, header); |
+ contextMenuDescriptors.push({text: WebInspector.displayNameForURL(header.resourceURL()), handler: handler}); |
+ } |
- var fullRefresh = Runtime.experiments.isEnabled("liveSASS"); |
- for (var section of this.allSections()) { |
- if (section.isBlank) |
- continue; |
- section.update(fullRefresh || section === editedSection); |
- } |
+ contextMenuDescriptors.sort(compareDescriptors); |
- if (this._filterRegex) |
- this._updateFilter(); |
- this._nodeStylesUpdatedForTest(node, false); |
- }, |
+ var contextMenu = new WebInspector.ContextMenu(event); |
+ for (var i = 0; i < contextMenuDescriptors.length; ++i) { |
+ var descriptor = contextMenuDescriptors[i]; |
+ contextMenu.appendItem(descriptor.text, descriptor.handler); |
+ } |
+ if (!contextMenu.isEmpty()) |
+ contextMenu.appendSeparator(); |
+ contextMenu.appendItem('inspector-stylesheet', this._createNewRuleInViaInspectorStyleSheet.bind(this)); |
+ contextMenu.show(); |
/** |
- * @override |
- * @return {!Promise.<?>} |
+ * @param {!{text: string, handler: function()}} descriptor1 |
+ * @param {!{text: string, handler: function()}} descriptor2 |
+ * @return {number} |
*/ |
- doUpdate: function() |
- { |
- return this._fetchMatchedCascade() |
- .then(this._innerRebuildUpdate.bind(this)); |
- }, |
- |
- _resetCache: function() |
- { |
- if (this.cssModel()) |
- this.cssModel().discardCachedMatchedCascade(); |
- }, |
+ function compareDescriptors(descriptor1, descriptor2) { |
+ return String.naturalOrderComparator(descriptor1.text, descriptor2.text); |
+ } |
/** |
- * @return {!Promise.<?WebInspector.CSSMatchedStyles>} |
+ * @param {!WebInspector.CSSStyleSheetHeader} header |
+ * @return {boolean} |
*/ |
- _fetchMatchedCascade: function() |
- { |
- var node = this.node(); |
- if (!node || !this.cssModel()) |
- return Promise.resolve(/** @type {?WebInspector.CSSMatchedStyles} */(null)); |
- |
- return this.cssModel().cachedMatchedCascadeForNode(node).then(validateStyles.bind(this)); |
- |
- /** |
- * @param {?WebInspector.CSSMatchedStyles} matchedStyles |
- * @return {?WebInspector.CSSMatchedStyles} |
- * @this {WebInspector.StylesSidebarPane} |
- */ |
- function validateStyles(matchedStyles) |
- { |
- return matchedStyles && matchedStyles.node() === this.node() ? matchedStyles : null; |
- } |
- }, |
+ function styleSheetResourceHeader(header) { |
+ return !header.isViaInspector() && !header.isInline && !!header.resourceURL(); |
+ } |
+ } |
+ |
+ /** |
+ * @param {?RegExp} regex |
+ */ |
+ onFilterChanged(regex) { |
+ this._filterRegex = regex; |
+ this._updateFilter(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.StylePropertiesSection=} editedSection |
+ */ |
+ _refreshUpdate(editedSection) { |
+ var node = this.node(); |
+ if (!node) |
+ return; |
+ |
+ var fullRefresh = Runtime.experiments.isEnabled('liveSASS'); |
+ for (var section of this.allSections()) { |
+ if (section.isBlank) |
+ continue; |
+ section.update(fullRefresh || section === editedSection); |
+ } |
- /** |
- * @param {boolean} editing |
- */ |
- setEditingStyle: function(editing) |
- { |
- if (this._isEditingStyle === editing) |
- return; |
- this.element.classList.toggle("is-editing-style", editing); |
- this._isEditingStyle = editing; |
- }, |
+ if (this._filterRegex) |
+ this._updateFilter(); |
+ this._nodeStylesUpdatedForTest(node, false); |
+ } |
- /** |
- * @override |
- * @param {!WebInspector.Event=} event |
- */ |
- onCSSModelChanged: function(event) |
- { |
- var edit = event && event.data ? /** @type {?WebInspector.CSSModel.Edit} */(event.data.edit) : null; |
- if (edit) { |
- for (var section of this.allSections()) |
- section._styleSheetEdited(edit); |
- return; |
- } |
+ /** |
+ * @override |
+ * @return {!Promise.<?>} |
+ */ |
+ doUpdate() { |
+ return this._fetchMatchedCascade().then(this._innerRebuildUpdate.bind(this)); |
+ } |
- if (this._userOperation || this._isEditingStyle) |
- return; |
+ _resetCache() { |
+ if (this.cssModel()) |
+ this.cssModel().discardCachedMatchedCascade(); |
+ } |
+ |
+ /** |
+ * @return {!Promise.<?WebInspector.CSSMatchedStyles>} |
+ */ |
+ _fetchMatchedCascade() { |
+ var node = this.node(); |
+ if (!node || !this.cssModel()) |
+ return Promise.resolve(/** @type {?WebInspector.CSSMatchedStyles} */ (null)); |
- this._resetCache(); |
- this.update(); |
- }, |
+ return this.cssModel().cachedMatchedCascadeForNode(node).then(validateStyles.bind(this)); |
/** |
* @param {?WebInspector.CSSMatchedStyles} matchedStyles |
+ * @return {?WebInspector.CSSMatchedStyles} |
+ * @this {WebInspector.StylesSidebarPane} |
*/ |
- _innerRebuildUpdate: function(matchedStyles) |
- { |
- this._linkifier.reset(); |
- this._sectionsContainer.removeChildren(); |
- this._sectionBlocks = []; |
- |
- var node = this.node(); |
- if (!matchedStyles || !node) |
- return; |
- |
- this._sectionBlocks = this._rebuildSectionsForMatchedStyleRules(matchedStyles); |
- var pseudoTypes = []; |
- var keys = new Set(matchedStyles.pseudoStyles().keys()); |
- if (keys.delete(DOMAgent.PseudoType.Before)) |
- pseudoTypes.push(DOMAgent.PseudoType.Before); |
- pseudoTypes = pseudoTypes.concat(keys.valuesArray().sort()); |
- for (var pseudoType of pseudoTypes) { |
- var block = WebInspector.SectionBlock.createPseudoTypeBlock(pseudoType); |
- var styles = /** @type {!Array<!WebInspector.CSSStyleDeclaration>} */(matchedStyles.pseudoStyles().get(pseudoType)); |
- for (var style of styles) { |
- var section = new WebInspector.StylePropertiesSection(this, matchedStyles, style); |
- block.sections.push(section); |
- } |
- this._sectionBlocks.push(block); |
- } |
+ function validateStyles(matchedStyles) { |
+ return matchedStyles && matchedStyles.node() === this.node() ? matchedStyles : null; |
+ } |
+ } |
+ |
+ /** |
+ * @param {boolean} editing |
+ */ |
+ setEditingStyle(editing) { |
+ if (this._isEditingStyle === editing) |
+ return; |
+ this.element.classList.toggle('is-editing-style', editing); |
+ this._isEditingStyle = editing; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!WebInspector.Event=} event |
+ */ |
+ onCSSModelChanged(event) { |
+ var edit = event && event.data ? /** @type {?WebInspector.CSSModel.Edit} */ (event.data.edit) : null; |
+ if (edit) { |
+ for (var section of this.allSections()) |
+ section._styleSheetEdited(edit); |
+ return; |
+ } |
- for (var keyframesRule of matchedStyles.keyframes()) { |
- var block = WebInspector.SectionBlock.createKeyframesBlock(keyframesRule.name().text); |
- for (var keyframe of keyframesRule.keyframes()) |
- block.sections.push(new WebInspector.KeyframePropertiesSection(this, matchedStyles, keyframe.style)); |
- this._sectionBlocks.push(block); |
- } |
+ if (this._userOperation || this._isEditingStyle) |
+ return; |
- for (var block of this._sectionBlocks) { |
- var titleElement = block.titleElement(); |
- if (titleElement) |
- this._sectionsContainer.appendChild(titleElement); |
- for (var section of block.sections) |
- this._sectionsContainer.appendChild(section.element); |
- } |
+ this._resetCache(); |
+ this.update(); |
+ } |
- if (this._filterRegex) |
- this._updateFilter(); |
+ /** |
+ * @param {?WebInspector.CSSMatchedStyles} matchedStyles |
+ */ |
+ _innerRebuildUpdate(matchedStyles) { |
+ this._linkifier.reset(); |
+ this._sectionsContainer.removeChildren(); |
+ this._sectionBlocks = []; |
- this._nodeStylesUpdatedForTest(node, true); |
- if (this._decorator) { |
- this._decorator.perform(); |
- delete this._decorator; |
- } |
- }, |
+ var node = this.node(); |
+ if (!matchedStyles || !node) |
+ return; |
+ |
+ this._sectionBlocks = this._rebuildSectionsForMatchedStyleRules(matchedStyles); |
+ var pseudoTypes = []; |
+ var keys = new Set(matchedStyles.pseudoStyles().keys()); |
+ if (keys.delete(DOMAgent.PseudoType.Before)) |
+ pseudoTypes.push(DOMAgent.PseudoType.Before); |
+ pseudoTypes = pseudoTypes.concat(keys.valuesArray().sort()); |
+ for (var pseudoType of pseudoTypes) { |
+ var block = WebInspector.SectionBlock.createPseudoTypeBlock(pseudoType); |
+ var styles = |
+ /** @type {!Array<!WebInspector.CSSStyleDeclaration>} */ (matchedStyles.pseudoStyles().get(pseudoType)); |
+ for (var style of styles) { |
+ var section = new WebInspector.StylePropertiesSection(this, matchedStyles, style); |
+ block.sections.push(section); |
+ } |
+ this._sectionBlocks.push(block); |
+ } |
- /** |
- * @param {!WebInspector.DOMNode} node |
- * @param {boolean} rebuild |
- */ |
- _nodeStylesUpdatedForTest: function(node, rebuild) |
- { |
- // For sniffing in tests. |
- }, |
+ for (var keyframesRule of matchedStyles.keyframes()) { |
+ var block = WebInspector.SectionBlock.createKeyframesBlock(keyframesRule.name().text); |
+ for (var keyframe of keyframesRule.keyframes()) |
+ block.sections.push(new WebInspector.KeyframePropertiesSection(this, matchedStyles, keyframe.style)); |
+ this._sectionBlocks.push(block); |
+ } |
- /** |
- * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
- * @return {!Array.<!WebInspector.SectionBlock>} |
- */ |
- _rebuildSectionsForMatchedStyleRules: function(matchedStyles) |
- { |
- var blocks = [new WebInspector.SectionBlock(null)]; |
- var lastParentNode = null; |
- for (var style of matchedStyles.nodeStyles()) { |
- var parentNode = matchedStyles.isInherited(style) ? matchedStyles.nodeForStyle(style) : null; |
- if (parentNode && parentNode !== lastParentNode) { |
- lastParentNode = parentNode; |
- var block = WebInspector.SectionBlock.createInheritedNodeBlock(lastParentNode); |
- blocks.push(block); |
- } |
- |
- var section = new WebInspector.StylePropertiesSection(this, matchedStyles, style); |
- blocks.peekLast().sections.push(section); |
- } |
- return blocks; |
- }, |
- |
- _createNewRuleInViaInspectorStyleSheet: function() |
- { |
- var cssModel = this.cssModel(); |
- var node = this.node(); |
- if (!cssModel || !node) |
- return; |
- this._userOperation = true; |
- cssModel.requestViaInspectorStylesheet(node, onViaInspectorStyleSheet.bind(this)); |
- |
- /** |
- * @param {?WebInspector.CSSStyleSheetHeader} styleSheetHeader |
- * @this {WebInspector.StylesSidebarPane} |
- */ |
- function onViaInspectorStyleSheet(styleSheetHeader) |
- { |
- delete this._userOperation; |
- this._createNewRuleInStyleSheet(styleSheetHeader); |
- } |
- }, |
+ for (var block of this._sectionBlocks) { |
+ var titleElement = block.titleElement(); |
+ if (titleElement) |
+ this._sectionsContainer.appendChild(titleElement); |
+ for (var section of block.sections) |
+ this._sectionsContainer.appendChild(section.element); |
+ } |
- /** |
- * @param {?WebInspector.CSSStyleSheetHeader} styleSheetHeader |
- */ |
- _createNewRuleInStyleSheet: function(styleSheetHeader) |
- { |
- if (!styleSheetHeader) |
- return; |
- styleSheetHeader.requestContent().then(onStyleSheetContent.bind(this, styleSheetHeader.id)); |
- |
- /** |
- * @param {string} styleSheetId |
- * @param {?string} text |
- * @this {WebInspector.StylesSidebarPane} |
- */ |
- function onStyleSheetContent(styleSheetId, text) |
- { |
- text = text || ""; |
- var lines = text.split("\n"); |
- var range = WebInspector.TextRange.createFromLocation(lines.length - 1, lines[lines.length - 1].length); |
- this._addBlankSection(this._sectionBlocks[0].sections[0], styleSheetId, range); |
- } |
- }, |
+ if (this._filterRegex) |
+ this._updateFilter(); |
- /** |
- * @param {!WebInspector.StylePropertiesSection} insertAfterSection |
- * @param {string} styleSheetId |
- * @param {!WebInspector.TextRange} ruleLocation |
- */ |
- _addBlankSection: function(insertAfterSection, styleSheetId, ruleLocation) |
- { |
- var node = this.node(); |
- var blankSection = new WebInspector.BlankStylePropertiesSection(this, insertAfterSection._matchedStyles, node ? WebInspector.DOMPresentationUtils.simpleSelector(node) : "", styleSheetId, ruleLocation, insertAfterSection._style); |
- |
- this._sectionsContainer.insertBefore(blankSection.element, insertAfterSection.element.nextSibling); |
- |
- for (var block of this._sectionBlocks) { |
- var index = block.sections.indexOf(insertAfterSection); |
- if (index === -1) |
- continue; |
- block.sections.splice(index + 1, 0, blankSection); |
- blankSection.startEditingSelector(); |
- } |
- }, |
+ this._nodeStylesUpdatedForTest(node, true); |
+ if (this._decorator) { |
+ this._decorator.perform(); |
+ delete this._decorator; |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.DOMNode} node |
+ * @param {boolean} rebuild |
+ */ |
+ _nodeStylesUpdatedForTest(node, rebuild) { |
+ // For sniffing in tests. |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
+ * @return {!Array.<!WebInspector.SectionBlock>} |
+ */ |
+ _rebuildSectionsForMatchedStyleRules(matchedStyles) { |
+ var blocks = [new WebInspector.SectionBlock(null)]; |
+ var lastParentNode = null; |
+ for (var style of matchedStyles.nodeStyles()) { |
+ var parentNode = matchedStyles.isInherited(style) ? matchedStyles.nodeForStyle(style) : null; |
+ if (parentNode && parentNode !== lastParentNode) { |
+ lastParentNode = parentNode; |
+ var block = WebInspector.SectionBlock.createInheritedNodeBlock(lastParentNode); |
+ blocks.push(block); |
+ } |
+ |
+ var section = new WebInspector.StylePropertiesSection(this, matchedStyles, style); |
+ blocks.peekLast().sections.push(section); |
+ } |
+ return blocks; |
+ } |
- /** |
- * @param {!WebInspector.StylePropertiesSection} section |
- */ |
- removeSection: function(section) |
- { |
- for (var block of this._sectionBlocks) { |
- var index = block.sections.indexOf(section); |
- if (index === -1) |
- continue; |
- block.sections.splice(index, 1); |
- section.element.remove(); |
- } |
- }, |
+ _createNewRuleInViaInspectorStyleSheet() { |
+ var cssModel = this.cssModel(); |
+ var node = this.node(); |
+ if (!cssModel || !node) |
+ return; |
+ this._userOperation = true; |
+ cssModel.requestViaInspectorStylesheet(node, onViaInspectorStyleSheet.bind(this)); |
/** |
- * @return {?RegExp} |
+ * @param {?WebInspector.CSSStyleSheetHeader} styleSheetHeader |
+ * @this {WebInspector.StylesSidebarPane} |
*/ |
- filterRegex: function() |
- { |
- return this._filterRegex; |
- }, |
- |
- _updateFilter: function() |
- { |
- for (var block of this._sectionBlocks) |
- block.updateFilter(); |
- }, |
+ function onViaInspectorStyleSheet(styleSheetHeader) { |
+ delete this._userOperation; |
+ this._createNewRuleInStyleSheet(styleSheetHeader); |
+ } |
+ } |
- /** |
- * @override |
- */ |
- willHide: function() |
- { |
- this._swatchPopoverHelper.hide(); |
- WebInspector.ElementsSidebarPane.prototype.willHide.call(this); |
- }, |
+ /** |
+ * @param {?WebInspector.CSSStyleSheetHeader} styleSheetHeader |
+ */ |
+ _createNewRuleInStyleSheet(styleSheetHeader) { |
+ if (!styleSheetHeader) |
+ return; |
+ styleSheetHeader.requestContent().then(onStyleSheetContent.bind(this, styleSheetHeader.id)); |
/** |
- * @return {!Array<!WebInspector.StylePropertiesSection>} |
- */ |
- allSections: function() |
- { |
- var sections = []; |
- for (var block of this._sectionBlocks) |
- sections = sections.concat(block.sections); |
- return sections; |
- }, |
- |
- __proto__: WebInspector.ElementsSidebarPane.prototype |
-}; |
- |
-/** |
- * @param {string} placeholder |
- * @param {!Element} container |
- * @param {function(?RegExp)} filterCallback |
- * @return {!Element} |
- */ |
-WebInspector.StylesSidebarPane.createPropertyFilterElement = function(placeholder, container, filterCallback) |
-{ |
- var input = createElement("input"); |
- input.placeholder = placeholder; |
- |
- function searchHandler() |
- { |
- var regex = input.value ? new RegExp(input.value.escapeForRegExp(), "i") : null; |
- filterCallback(regex); |
- container.classList.toggle("styles-filter-engaged", !!input.value); |
+ * @param {string} styleSheetId |
+ * @param {?string} text |
+ * @this {WebInspector.StylesSidebarPane} |
+ */ |
+ function onStyleSheetContent(styleSheetId, text) { |
+ text = text || ''; |
+ var lines = text.split('\n'); |
+ var range = WebInspector.TextRange.createFromLocation(lines.length - 1, lines[lines.length - 1].length); |
+ this._addBlankSection(this._sectionBlocks[0].sections[0], styleSheetId, range); |
} |
- input.addEventListener("input", searchHandler, false); |
- |
- /** |
- * @param {!Event} event |
- */ |
- function keydownHandler(event) |
- { |
- if (event.key !== "Escape" || !input.value) |
- return; |
- event.consume(true); |
- input.value = ""; |
- searchHandler(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.StylePropertiesSection} insertAfterSection |
+ * @param {string} styleSheetId |
+ * @param {!WebInspector.TextRange} ruleLocation |
+ */ |
+ _addBlankSection(insertAfterSection, styleSheetId, ruleLocation) { |
+ var node = this.node(); |
+ var blankSection = new WebInspector.BlankStylePropertiesSection( |
+ this, insertAfterSection._matchedStyles, node ? WebInspector.DOMPresentationUtils.simpleSelector(node) : '', |
+ styleSheetId, ruleLocation, insertAfterSection._style); |
+ |
+ this._sectionsContainer.insertBefore(blankSection.element, insertAfterSection.element.nextSibling); |
+ |
+ for (var block of this._sectionBlocks) { |
+ var index = block.sections.indexOf(insertAfterSection); |
+ if (index === -1) |
+ continue; |
+ block.sections.splice(index + 1, 0, blankSection); |
+ blankSection.startEditingSelector(); |
} |
- input.addEventListener("keydown", keydownHandler, false); |
- |
- input.setFilterValue = setFilterValue; |
- |
- /** |
- * @param {string} value |
- */ |
- function setFilterValue(value) |
- { |
- input.value = value; |
- input.focus(); |
- searchHandler(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.StylePropertiesSection} section |
+ */ |
+ removeSection(section) { |
+ for (var block of this._sectionBlocks) { |
+ var index = block.sections.indexOf(section); |
+ if (index === -1) |
+ continue; |
+ block.sections.splice(index, 1); |
+ section.element.remove(); |
} |
- |
- return input; |
+ } |
+ |
+ /** |
+ * @return {?RegExp} |
+ */ |
+ filterRegex() { |
+ return this._filterRegex; |
+ } |
+ |
+ _updateFilter() { |
+ for (var block of this._sectionBlocks) |
+ block.updateFilter(); |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ willHide() { |
+ this._swatchPopoverHelper.hide(); |
+ super.willHide(); |
+ } |
+ |
+ /** |
+ * @return {!Array<!WebInspector.StylePropertiesSection>} |
+ */ |
+ allSections() { |
+ var sections = []; |
+ for (var block of this._sectionBlocks) |
+ sections = sections.concat(block.sections); |
+ return sections; |
+ } |
}; |
+ |
/** |
- * @constructor |
- * @param {?Element} titleElement |
+ * @unrestricted |
*/ |
-WebInspector.SectionBlock = function(titleElement) |
-{ |
+WebInspector.SectionBlock = class { |
+ /** |
+ * @param {?Element} titleElement |
+ */ |
+ constructor(titleElement) { |
this._titleElement = titleElement; |
this.sections = []; |
-}; |
- |
-/** |
- * @param {!DOMAgent.PseudoType} pseudoType |
- * @return {!WebInspector.SectionBlock} |
- */ |
-WebInspector.SectionBlock.createPseudoTypeBlock = function(pseudoType) |
-{ |
- var separatorElement = createElement("div"); |
- separatorElement.className = "sidebar-separator"; |
- separatorElement.textContent = WebInspector.UIString("Pseudo ::%s element", pseudoType); |
+ } |
+ |
+ /** |
+ * @param {!DOMAgent.PseudoType} pseudoType |
+ * @return {!WebInspector.SectionBlock} |
+ */ |
+ static createPseudoTypeBlock(pseudoType) { |
+ var separatorElement = createElement('div'); |
+ separatorElement.className = 'sidebar-separator'; |
+ separatorElement.textContent = WebInspector.UIString('Pseudo ::%s element', pseudoType); |
return new WebInspector.SectionBlock(separatorElement); |
-}; |
- |
-/** |
- * @param {string} keyframesName |
- * @return {!WebInspector.SectionBlock} |
- */ |
-WebInspector.SectionBlock.createKeyframesBlock = function(keyframesName) |
-{ |
- var separatorElement = createElement("div"); |
- separatorElement.className = "sidebar-separator"; |
- separatorElement.textContent = WebInspector.UIString("@keyframes " + keyframesName); |
+ } |
+ |
+ /** |
+ * @param {string} keyframesName |
+ * @return {!WebInspector.SectionBlock} |
+ */ |
+ static createKeyframesBlock(keyframesName) { |
+ var separatorElement = createElement('div'); |
+ separatorElement.className = 'sidebar-separator'; |
+ separatorElement.textContent = WebInspector.UIString('@keyframes ' + keyframesName); |
return new WebInspector.SectionBlock(separatorElement); |
-}; |
- |
-/** |
- * @param {!WebInspector.DOMNode} node |
- * @return {!WebInspector.SectionBlock} |
- */ |
-WebInspector.SectionBlock.createInheritedNodeBlock = function(node) |
-{ |
- var separatorElement = createElement("div"); |
- separatorElement.className = "sidebar-separator"; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.DOMNode} node |
+ * @return {!WebInspector.SectionBlock} |
+ */ |
+ static createInheritedNodeBlock(node) { |
+ var separatorElement = createElement('div'); |
+ separatorElement.className = 'sidebar-separator'; |
var link = WebInspector.DOMPresentationUtils.linkifyNodeReference(node); |
- separatorElement.createTextChild(WebInspector.UIString("Inherited from") + " "); |
+ separatorElement.createTextChild(WebInspector.UIString('Inherited from') + ' '); |
separatorElement.appendChild(link); |
return new WebInspector.SectionBlock(separatorElement); |
+ } |
+ |
+ updateFilter() { |
+ var hasAnyVisibleSection = false; |
+ for (var section of this.sections) |
+ hasAnyVisibleSection |= section._updateFilter(); |
+ if (this._titleElement) |
+ this._titleElement.classList.toggle('hidden', !hasAnyVisibleSection); |
+ } |
+ |
+ /** |
+ * @return {?Element} |
+ */ |
+ titleElement() { |
+ return this._titleElement; |
+ } |
}; |
-WebInspector.SectionBlock.prototype = { |
- updateFilter: function() |
- { |
- var hasAnyVisibleSection = false; |
- for (var section of this.sections) |
- hasAnyVisibleSection |= section._updateFilter(); |
- if (this._titleElement) |
- this._titleElement.classList.toggle("hidden", !hasAnyVisibleSection); |
- }, |
- |
- /** |
- * @return {?Element} |
- */ |
- titleElement: function() |
- { |
- return this._titleElement; |
- } |
-}; |
/** |
- * @constructor |
- * @param {!WebInspector.StylesSidebarPane} parentPane |
- * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
- * @param {!WebInspector.CSSStyleDeclaration} style |
+ * @unrestricted |
*/ |
-WebInspector.StylePropertiesSection = function(parentPane, matchedStyles, style) |
-{ |
+WebInspector.StylePropertiesSection = class { |
+ /** |
+ * @param {!WebInspector.StylesSidebarPane} parentPane |
+ * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
+ * @param {!WebInspector.CSSStyleDeclaration} style |
+ */ |
+ constructor(parentPane, matchedStyles, style) { |
this._parentPane = parentPane; |
this._style = style; |
this._matchedStyles = matchedStyles; |
this.editable = !!(style.styleSheetId && style.range); |
var rule = style.parentRule; |
- this.element = createElementWithClass("div", "styles-section matched-styles monospace"); |
+ this.element = createElementWithClass('div', 'styles-section matched-styles monospace'); |
this.element._section = this; |
- this._titleElement = this.element.createChild("div", "styles-section-title " + (rule ? "styles-selector" : "")); |
+ this._titleElement = this.element.createChild('div', 'styles-section-title ' + (rule ? 'styles-selector' : '')); |
this.propertiesTreeOutline = new TreeOutlineInShadow(); |
- this.propertiesTreeOutline.registerRequiredCSS("elements/stylesSectionTree.css"); |
- this.propertiesTreeOutline.element.classList.add("style-properties", "matched-styles", "monospace"); |
+ this.propertiesTreeOutline.registerRequiredCSS('elements/stylesSectionTree.css'); |
+ this.propertiesTreeOutline.element.classList.add('style-properties', 'matched-styles', 'monospace'); |
this.propertiesTreeOutline.section = this; |
this.element.appendChild(this.propertiesTreeOutline.element); |
- var selectorContainer = createElement("div"); |
- this._selectorElement = createElementWithClass("span", "selector"); |
+ var selectorContainer = createElement('div'); |
+ this._selectorElement = createElementWithClass('span', 'selector'); |
this._selectorElement.textContent = this._headerText(); |
selectorContainer.appendChild(this._selectorElement); |
- this._selectorElement.addEventListener("mouseenter", this._onMouseEnterSelector.bind(this), false); |
- this._selectorElement.addEventListener("mouseleave", this._onMouseOutSelector.bind(this), false); |
+ this._selectorElement.addEventListener('mouseenter', this._onMouseEnterSelector.bind(this), false); |
+ this._selectorElement.addEventListener('mouseleave', this._onMouseOutSelector.bind(this), false); |
- var openBrace = createElement("span"); |
- openBrace.textContent = " {"; |
+ var openBrace = createElement('span'); |
+ openBrace.textContent = ' {'; |
selectorContainer.appendChild(openBrace); |
- selectorContainer.addEventListener("mousedown", this._handleEmptySpaceMouseDown.bind(this), false); |
- selectorContainer.addEventListener("click", this._handleSelectorContainerClick.bind(this), false); |
+ selectorContainer.addEventListener('mousedown', this._handleEmptySpaceMouseDown.bind(this), false); |
+ selectorContainer.addEventListener('click', this._handleSelectorContainerClick.bind(this), false); |
- var closeBrace = this.element.createChild("div", "sidebar-pane-closing-brace"); |
- closeBrace.textContent = "}"; |
+ var closeBrace = this.element.createChild('div', 'sidebar-pane-closing-brace'); |
+ closeBrace.textContent = '}'; |
this._createHoverMenuToolbar(closeBrace); |
- this._selectorElement.addEventListener("click", this._handleSelectorClick.bind(this), false); |
- this.element.addEventListener("mousedown", this._handleEmptySpaceMouseDown.bind(this), false); |
- this.element.addEventListener("click", this._handleEmptySpaceClick.bind(this), false); |
- this.element.addEventListener("mousemove", this._onMouseMove.bind(this), false); |
- this.element.addEventListener("mouseleave", this._setSectionHovered.bind(this, false), false); |
+ this._selectorElement.addEventListener('click', this._handleSelectorClick.bind(this), false); |
+ this.element.addEventListener('mousedown', this._handleEmptySpaceMouseDown.bind(this), false); |
+ this.element.addEventListener('click', this._handleEmptySpaceClick.bind(this), false); |
+ this.element.addEventListener('mousemove', this._onMouseMove.bind(this), false); |
+ this.element.addEventListener('mouseleave', this._setSectionHovered.bind(this, false), false); |
if (rule) { |
- // Prevent editing the user agent and user rules. |
- if (rule.isUserAgent() || rule.isInjected()) { |
- this.editable = false; |
- } else { |
- // Check this is a real CSSRule, not a bogus object coming from WebInspector.BlankStylePropertiesSection. |
- if (rule.styleSheetId) |
- this.navigable = !!rule.resourceURL(); |
- } |
+ // Prevent editing the user agent and user rules. |
+ if (rule.isUserAgent() || rule.isInjected()) { |
+ this.editable = false; |
+ } else { |
+ // Check this is a real CSSRule, not a bogus object coming from WebInspector.BlankStylePropertiesSection. |
+ if (rule.styleSheetId) |
+ this.navigable = !!rule.resourceURL(); |
+ } |
} |
- this._mediaListElement = this._titleElement.createChild("div", "media-list media-matches"); |
- this._selectorRefElement = this._titleElement.createChild("div", "styles-section-subtitle"); |
+ this._mediaListElement = this._titleElement.createChild('div', 'media-list media-matches'); |
+ this._selectorRefElement = this._titleElement.createChild('div', 'styles-section-subtitle'); |
this._updateMediaList(); |
this._updateRuleOrigin(); |
this._titleElement.appendChild(selectorContainer); |
this._selectorContainer = selectorContainer; |
if (this.navigable) |
- this.element.classList.add("navigable"); |
+ this.element.classList.add('navigable'); |
if (!this.editable) { |
- this.element.classList.add("read-only"); |
- this.propertiesTreeOutline.element.classList.add("read-only"); |
+ this.element.classList.add('read-only'); |
+ this.propertiesTreeOutline.element.classList.add('read-only'); |
} |
this._hoverableSelectorsMode = false; |
this._markSelectorMatches(); |
this.onpopulate(); |
-}; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
+ * @param {!WebInspector.Linkifier} linkifier |
+ * @param {?WebInspector.CSSRule} rule |
+ * @return {!Node} |
+ */ |
+ static createRuleOriginNode(matchedStyles, linkifier, rule) { |
+ if (!rule) |
+ return createTextNode(''); |
-WebInspector.StylePropertiesSection.prototype = { |
- /** |
- * @param {boolean} isHovered |
- */ |
- _setSectionHovered: function(isHovered) |
- { |
- this.element.classList.toggle("styles-panel-hovered", isHovered); |
- this.propertiesTreeOutline.element.classList.toggle("styles-panel-hovered", isHovered); |
- if (this._hoverableSelectorsMode !== isHovered) { |
- this._hoverableSelectorsMode = isHovered; |
- this._markSelectorMatches(); |
- } |
- }, |
+ var ruleLocation; |
+ if (rule instanceof WebInspector.CSSStyleRule) { |
+ var matchingSelectors = matchedStyles.matchingSelectors(rule); |
+ var firstMatchingIndex = matchingSelectors.length ? matchingSelectors[0] : 0; |
+ ruleLocation = rule.selectors[firstMatchingIndex].range; |
+ } else if (rule instanceof WebInspector.CSSKeyframeRule) { |
+ ruleLocation = rule.key().range; |
+ } |
- /** |
- * @param {!Event} event |
- */ |
- _onMouseMove: function(event) |
- { |
- var hasCtrlOrMeta = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */(event)); |
- this._setSectionHovered(hasCtrlOrMeta); |
- }, |
+ var header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null; |
+ if (ruleLocation && rule.styleSheetId && header && header.resourceURL()) |
+ return WebInspector.StylePropertiesSection._linkifyRuleLocation( |
+ matchedStyles.cssModel(), linkifier, rule.styleSheetId, ruleLocation); |
+ |
+ if (rule.isUserAgent()) |
+ return createTextNode(WebInspector.UIString('user agent stylesheet')); |
+ if (rule.isInjected()) |
+ return createTextNode(WebInspector.UIString('injected stylesheet')); |
+ if (rule.isViaInspector()) |
+ return createTextNode(WebInspector.UIString('via inspector')); |
+ |
+ if (header && header.ownerNode) { |
+ var link = WebInspector.DOMPresentationUtils.linkifyDeferredNodeReference(header.ownerNode); |
+ link.textContent = '<style>…</style>'; |
+ return link; |
+ } |
+ |
+ return createTextNode(''); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSModel} cssModel |
+ * @param {!WebInspector.Linkifier} linkifier |
+ * @param {string} styleSheetId |
+ * @param {!WebInspector.TextRange} ruleLocation |
+ * @return {!Node} |
+ */ |
+ static _linkifyRuleLocation(cssModel, linkifier, styleSheetId, ruleLocation) { |
+ var styleSheetHeader = cssModel.styleSheetHeaderForId(styleSheetId); |
+ var lineNumber = styleSheetHeader.lineNumberInSource(ruleLocation.startLine); |
+ var columnNumber = styleSheetHeader.columnNumberInSource(ruleLocation.startLine, ruleLocation.startColumn); |
+ var matchingSelectorLocation = new WebInspector.CSSLocation(styleSheetHeader, lineNumber, columnNumber); |
+ return linkifier.linkifyCSSLocation(matchingSelectorLocation); |
+ } |
+ |
+ /** |
+ * @param {boolean} isHovered |
+ */ |
+ _setSectionHovered(isHovered) { |
+ this.element.classList.toggle('styles-panel-hovered', isHovered); |
+ this.propertiesTreeOutline.element.classList.toggle('styles-panel-hovered', isHovered); |
+ if (this._hoverableSelectorsMode !== isHovered) { |
+ this._hoverableSelectorsMode = isHovered; |
+ this._markSelectorMatches(); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _onMouseMove(event) { |
+ var hasCtrlOrMeta = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */ (event)); |
+ this._setSectionHovered(hasCtrlOrMeta); |
+ } |
+ |
+ /** |
+ * @param {!Element} container |
+ */ |
+ _createHoverMenuToolbar(container) { |
+ if (!this.editable) |
+ return; |
+ var items = []; |
+ |
+ var textShadowButton = |
+ new WebInspector.ToolbarButton(WebInspector.UIString('Add text-shadow'), 'text-shadow-toolbar-item'); |
+ textShadowButton.addEventListener('click', this._onInsertShadowPropertyClick.bind(this, 'text-shadow')); |
+ items.push(textShadowButton); |
+ |
+ var boxShadowButton = |
+ new WebInspector.ToolbarButton(WebInspector.UIString('Add box-shadow'), 'box-shadow-toolbar-item'); |
+ boxShadowButton.addEventListener('click', this._onInsertShadowPropertyClick.bind(this, 'box-shadow')); |
+ items.push(boxShadowButton); |
+ |
+ var colorButton = |
+ new WebInspector.ToolbarButton(WebInspector.UIString('Add color'), 'foreground-color-toolbar-item'); |
+ colorButton.addEventListener('click', this._onInsertColorPropertyClick.bind(this)); |
+ items.push(colorButton); |
+ |
+ var backgroundButton = |
+ new WebInspector.ToolbarButton(WebInspector.UIString('Add background-color'), 'background-color-toolbar-item'); |
+ backgroundButton.addEventListener('click', this._onInsertBackgroundColorPropertyClick.bind(this)); |
+ items.push(backgroundButton); |
+ |
+ var newRuleButton = null; |
+ if (this._style.parentRule) { |
+ newRuleButton = |
+ new WebInspector.ToolbarButton(WebInspector.UIString('Insert Style Rule Below'), 'add-toolbar-item'); |
+ newRuleButton.addEventListener('click', this._onNewRuleClick.bind(this)); |
+ items.push(newRuleButton); |
+ } |
+ |
+ var sectionToolbar = new WebInspector.Toolbar('sidebar-pane-section-toolbar', container); |
+ for (var i = 0; i < items.length; ++i) |
+ sectionToolbar.appendToolbarItem(items[i]); |
+ |
+ var menuButton = new WebInspector.ToolbarButton(WebInspector.UIString('More tools\u2026'), 'menu-toolbar-item'); |
+ sectionToolbar.appendToolbarItem(menuButton); |
+ setItemsVisibility.call(this, items, false); |
+ sectionToolbar.element.addEventListener('mouseenter', setItemsVisibility.bind(this, items, true)); |
+ sectionToolbar.element.addEventListener('mouseleave', setItemsVisibility.bind(this, items, false)); |
/** |
- * @param {!Element} container |
+ * @param {!Array<!WebInspector.ToolbarButton>} items |
+ * @param {boolean} value |
+ * @this {WebInspector.StylePropertiesSection} |
*/ |
- _createHoverMenuToolbar: function(container) |
- { |
- if (!this.editable) |
- return; |
- var items = []; |
+ function setItemsVisibility(items, value) { |
+ for (var i = 0; i < items.length; ++i) |
+ items[i].setVisible(value); |
+ menuButton.setVisible(!value); |
+ if (this._isSASSStyle()) |
+ newRuleButton.setVisible(false); |
+ } |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ _isSASSStyle() { |
+ var header = |
+ this._style.styleSheetId ? this._style.cssModel().styleSheetHeaderForId(this._style.styleSheetId) : null; |
+ if (!header) |
+ return false; |
+ var sourceMap = header.cssModel().sourceMapForHeader(header); |
+ return sourceMap ? sourceMap.editable() : false; |
+ } |
+ |
+ /** |
+ * @return {!WebInspector.CSSStyleDeclaration} |
+ */ |
+ style() { |
+ return this._style; |
+ } |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ _headerText() { |
+ var node = this._matchedStyles.nodeForStyle(this._style); |
+ if (this._style.type === WebInspector.CSSStyleDeclaration.Type.Inline) |
+ return this._matchedStyles.isInherited(this._style) ? WebInspector.UIString('Style Attribute') : 'element.style'; |
+ if (this._style.type === WebInspector.CSSStyleDeclaration.Type.Attributes) |
+ return node.nodeNameInCorrectCase() + '[' + WebInspector.UIString('Attributes Style') + ']'; |
+ return this._style.parentRule.selectorText(); |
+ } |
+ |
+ _onMouseOutSelector() { |
+ if (this._hoverTimer) |
+ clearTimeout(this._hoverTimer); |
+ WebInspector.DOMModel.hideDOMNodeHighlight(); |
+ } |
+ |
+ _onMouseEnterSelector() { |
+ if (this._hoverTimer) |
+ clearTimeout(this._hoverTimer); |
+ this._hoverTimer = setTimeout(this._highlight.bind(this), 300); |
+ } |
+ |
+ _highlight() { |
+ WebInspector.DOMModel.hideDOMNodeHighlight(); |
+ var node = this._parentPane.node(); |
+ var domModel = node.domModel(); |
+ var selectors = this._style.parentRule ? this._style.parentRule.selectorText() : undefined; |
+ domModel.highlightDOMNodeWithConfig(node.id, {mode: 'all', showInfo: undefined, selectors: selectors}); |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ firstSibling() { |
+ var parent = this.element.parentElement; |
+ if (!parent) |
+ return null; |
+ |
+ var childElement = parent.firstChild; |
+ while (childElement) { |
+ if (childElement._section) |
+ return childElement._section; |
+ childElement = childElement.nextSibling; |
+ } |
- var textShadowButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add text-shadow"), "text-shadow-toolbar-item"); |
- textShadowButton.addEventListener("click", this._onInsertShadowPropertyClick.bind(this, "text-shadow")); |
- items.push(textShadowButton); |
+ return null; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ lastSibling() { |
+ var parent = this.element.parentElement; |
+ if (!parent) |
+ return null; |
+ |
+ var childElement = parent.lastChild; |
+ while (childElement) { |
+ if (childElement._section) |
+ return childElement._section; |
+ childElement = childElement.previousSibling; |
+ } |
- var boxShadowButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add box-shadow"), "box-shadow-toolbar-item"); |
- boxShadowButton.addEventListener("click", this._onInsertShadowPropertyClick.bind(this, "box-shadow")); |
- items.push(boxShadowButton); |
+ return null; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ nextSibling() { |
+ var curElement = this.element; |
+ do { |
+ curElement = curElement.nextSibling; |
+ } while (curElement && !curElement._section); |
+ |
+ return curElement ? curElement._section : null; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ previousSibling() { |
+ var curElement = this.element; |
+ do { |
+ curElement = curElement.previousSibling; |
+ } while (curElement && !curElement._section); |
+ |
+ return curElement ? curElement._section : null; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Event} event |
+ */ |
+ _onNewRuleClick(event) { |
+ event.consume(); |
+ var rule = this._style.parentRule; |
+ var range = WebInspector.TextRange.createFromLocation(rule.style.range.endLine, rule.style.range.endColumn + 1); |
+ this._parentPane._addBlankSection(this, /** @type {string} */ (rule.styleSheetId), range); |
+ } |
+ |
+ /** |
+ * @param {string} propertyName |
+ * @param {!WebInspector.Event} event |
+ */ |
+ _onInsertShadowPropertyClick(propertyName, event) { |
+ event.consume(true); |
+ var treeElement = this.addNewBlankProperty(); |
+ treeElement.property.name = propertyName; |
+ treeElement.property.value = '0 0 black'; |
+ treeElement.updateTitle(); |
+ var shadowSwatchPopoverHelper = WebInspector.ShadowSwatchPopoverHelper.forTreeElement(treeElement); |
+ if (shadowSwatchPopoverHelper) |
+ shadowSwatchPopoverHelper.showPopover(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Event} event |
+ */ |
+ _onInsertColorPropertyClick(event) { |
+ event.consume(true); |
+ var treeElement = this.addNewBlankProperty(); |
+ treeElement.property.name = 'color'; |
+ treeElement.property.value = 'black'; |
+ treeElement.updateTitle(); |
+ var colorSwatch = WebInspector.ColorSwatchPopoverIcon.forTreeElement(treeElement); |
+ if (colorSwatch) |
+ colorSwatch.showPopover(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Event} event |
+ */ |
+ _onInsertBackgroundColorPropertyClick(event) { |
+ event.consume(true); |
+ var treeElement = this.addNewBlankProperty(); |
+ treeElement.property.name = 'background-color'; |
+ treeElement.property.value = 'white'; |
+ treeElement.updateTitle(); |
+ var colorSwatch = WebInspector.ColorSwatchPopoverIcon.forTreeElement(treeElement); |
+ if (colorSwatch) |
+ colorSwatch.showPopover(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSModel.Edit} edit |
+ */ |
+ _styleSheetEdited(edit) { |
+ var rule = this._style.parentRule; |
+ if (rule) |
+ rule.rebase(edit); |
+ else |
+ this._style.rebase(edit); |
- var colorButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add color"), "foreground-color-toolbar-item"); |
- colorButton.addEventListener("click", this._onInsertColorPropertyClick.bind(this)); |
- items.push(colorButton); |
+ this._updateMediaList(); |
+ this._updateRuleOrigin(); |
+ } |
+ |
+ /** |
+ * @param {!Array.<!WebInspector.CSSMedia>} mediaRules |
+ */ |
+ _createMediaList(mediaRules) { |
+ for (var i = mediaRules.length - 1; i >= 0; --i) { |
+ var media = mediaRules[i]; |
+ // Don't display trivial non-print media types. |
+ if (!media.text.includes('(') && media.text !== 'print') |
+ continue; |
+ var mediaDataElement = this._mediaListElement.createChild('div', 'media'); |
+ var mediaContainerElement = mediaDataElement.createChild('span'); |
+ var mediaTextElement = mediaContainerElement.createChild('span', 'media-text'); |
+ switch (media.source) { |
+ case WebInspector.CSSMedia.Source.LINKED_SHEET: |
+ case WebInspector.CSSMedia.Source.INLINE_SHEET: |
+ mediaTextElement.textContent = 'media="' + media.text + '"'; |
+ break; |
+ case WebInspector.CSSMedia.Source.MEDIA_RULE: |
+ var decoration = mediaContainerElement.createChild('span'); |
+ mediaContainerElement.insertBefore(decoration, mediaTextElement); |
+ decoration.textContent = '@media '; |
+ mediaTextElement.textContent = media.text; |
+ if (media.styleSheetId) { |
+ mediaDataElement.classList.add('editable-media'); |
+ mediaTextElement.addEventListener( |
+ 'click', this._handleMediaRuleClick.bind(this, media, mediaTextElement), false); |
+ } |
+ break; |
+ case WebInspector.CSSMedia.Source.IMPORT_RULE: |
+ mediaTextElement.textContent = '@import ' + media.text; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ _updateMediaList() { |
+ this._mediaListElement.removeChildren(); |
+ if (this._style.parentRule && this._style.parentRule instanceof WebInspector.CSSStyleRule) |
+ this._createMediaList(this._style.parentRule.media); |
+ } |
+ |
+ /** |
+ * @param {string} propertyName |
+ * @return {boolean} |
+ */ |
+ isPropertyInherited(propertyName) { |
+ if (this._matchedStyles.isInherited(this._style)) { |
+ // While rendering inherited stylesheet, reverse meaning of this property. |
+ // Render truly inherited properties with black, i.e. return them as non-inherited. |
+ return !WebInspector.cssMetadata().isPropertyInherited(propertyName); |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ nextEditableSibling() { |
+ var curSection = this; |
+ do { |
+ curSection = curSection.nextSibling(); |
+ } while (curSection && !curSection.editable); |
+ |
+ if (!curSection) { |
+ curSection = this.firstSibling(); |
+ while (curSection && !curSection.editable) |
+ curSection = curSection.nextSibling(); |
+ } |
- var backgroundButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add background-color"), "background-color-toolbar-item"); |
- backgroundButton.addEventListener("click", this._onInsertBackgroundColorPropertyClick.bind(this)); |
- items.push(backgroundButton); |
+ return (curSection && curSection.editable) ? curSection : null; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ previousEditableSibling() { |
+ var curSection = this; |
+ do { |
+ curSection = curSection.previousSibling(); |
+ } while (curSection && !curSection.editable); |
+ |
+ if (!curSection) { |
+ curSection = this.lastSibling(); |
+ while (curSection && !curSection.editable) |
+ curSection = curSection.previousSibling(); |
+ } |
- var newRuleButton = null; |
- if (this._style.parentRule) { |
- newRuleButton = new WebInspector.ToolbarButton(WebInspector.UIString("Insert Style Rule Below"), "add-toolbar-item"); |
- newRuleButton.addEventListener("click", this._onNewRuleClick.bind(this)); |
- items.push(newRuleButton); |
- } |
+ return (curSection && curSection.editable) ? curSection : null; |
+ } |
- var sectionToolbar = new WebInspector.Toolbar("sidebar-pane-section-toolbar", container); |
- for (var i = 0; i < items.length; ++i) |
- sectionToolbar.appendToolbarItem(items[i]); |
- |
- var menuButton = new WebInspector.ToolbarButton(WebInspector.UIString("More tools\u2026"), "menu-toolbar-item"); |
- sectionToolbar.appendToolbarItem(menuButton); |
- setItemsVisibility.call(this, items, false); |
- sectionToolbar.element.addEventListener("mouseenter", setItemsVisibility.bind(this, items, true)); |
- sectionToolbar.element.addEventListener("mouseleave", setItemsVisibility.bind(this, items, false)); |
- |
- /** |
- * @param {!Array<!WebInspector.ToolbarButton>} items |
- * @param {boolean} value |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function setItemsVisibility(items, value) |
- { |
- for (var i = 0; i < items.length; ++i) |
- items[i].setVisible(value); |
- menuButton.setVisible(!value); |
- if (this._isSASSStyle()) |
- newRuleButton.setVisible(false); |
- } |
- }, |
+ /** |
+ * @param {boolean} full |
+ */ |
+ update(full) { |
+ this._selectorElement.textContent = this._headerText(); |
+ this._markSelectorMatches(); |
+ if (full) { |
+ this.propertiesTreeOutline.removeChildren(); |
+ this.onpopulate(); |
+ } else { |
+ var child = this.propertiesTreeOutline.firstChild(); |
+ while (child) { |
+ child.setOverloaded(this._isPropertyOverloaded(child.property)); |
+ child = child.traverseNextTreeElement(false, null, true); |
+ } |
+ } |
+ this.afterUpdate(); |
+ } |
+ |
+ afterUpdate() { |
+ if (this._afterUpdate) { |
+ this._afterUpdate(this); |
+ delete this._afterUpdate; |
+ this._afterUpdateFinishedForTest(); |
+ } |
+ } |
+ |
+ _afterUpdateFinishedForTest() { |
+ } |
+ |
+ onpopulate() { |
+ var style = this._style; |
+ for (var property of style.leadingProperties()) { |
+ var isShorthand = !!style.longhandProperties(property.name).length; |
+ var inherited = this.isPropertyInherited(property.name); |
+ var overloaded = this._isPropertyOverloaded(property); |
+ var item = new WebInspector.StylePropertyTreeElement( |
+ this._parentPane, this._matchedStyles, property, isShorthand, inherited, overloaded); |
+ this.propertiesTreeOutline.appendChild(item); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSProperty} property |
+ * @return {boolean} |
+ */ |
+ _isPropertyOverloaded(property) { |
+ return this._matchedStyles.propertyState(property) === WebInspector.CSSMatchedStyles.PropertyState.Overloaded; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ _updateFilter() { |
+ var hasMatchingChild = false; |
+ for (var child of this.propertiesTreeOutline.rootElement().children()) |
+ hasMatchingChild |= child._updateFilter(); |
+ |
+ var regex = this._parentPane.filterRegex(); |
+ var hideRule = !hasMatchingChild && !!regex && !regex.test(this.element.deepTextContent()); |
+ this.element.classList.toggle('hidden', hideRule); |
+ if (!hideRule && this._style.parentRule) |
+ this._markSelectorHighlights(); |
+ return !hideRule; |
+ } |
+ |
+ _markSelectorMatches() { |
+ var rule = this._style.parentRule; |
+ if (!rule) |
+ return; |
+ |
+ this._mediaListElement.classList.toggle('media-matches', this._matchedStyles.mediaMatches(this._style)); |
+ |
+ var selectorTexts = rule.selectors.map(selector => selector.text); |
+ var matchingSelectorIndexes = |
+ this._matchedStyles.matchingSelectors(/** @type {!WebInspector.CSSStyleRule} */ (rule)); |
+ var matchingSelectors = new Array(selectorTexts.length).fill(false); |
+ for (var matchingIndex of matchingSelectorIndexes) |
+ matchingSelectors[matchingIndex] = true; |
+ |
+ var fragment = this._hoverableSelectorsMode ? this._renderHoverableSelectors(selectorTexts, matchingSelectors) : |
+ this._renderSimplifiedSelectors(selectorTexts, matchingSelectors); |
+ this._selectorElement.removeChildren(); |
+ this._selectorElement.appendChild(fragment); |
+ this._markSelectorHighlights(); |
+ } |
+ |
+ /** |
+ * @param {!Array<string>} selectors |
+ * @param {!Array<boolean>} matchingSelectors |
+ * @return {!DocumentFragment} |
+ */ |
+ _renderHoverableSelectors(selectors, matchingSelectors) { |
+ var fragment = createDocumentFragment(); |
+ for (var i = 0; i < selectors.length; ++i) { |
+ if (i) |
+ fragment.createTextChild(', '); |
+ fragment.appendChild(this._createSelectorElement(selectors[i], matchingSelectors[i], i)); |
+ } |
+ return fragment; |
+ } |
+ |
+ /** |
+ * @param {string} text |
+ * @param {boolean} isMatching |
+ * @param {number=} navigationIndex |
+ * @return {!Element} |
+ */ |
+ _createSelectorElement(text, isMatching, navigationIndex) { |
+ var element = createElementWithClass('span', 'simple-selector'); |
+ element.classList.toggle('selector-matches', isMatching); |
+ if (typeof navigationIndex === 'number') |
+ element._selectorIndex = navigationIndex; |
+ element.textContent = text; |
+ return element; |
+ } |
+ |
+ /** |
+ * @param {!Array<string>} selectors |
+ * @param {!Array<boolean>} matchingSelectors |
+ * @return {!DocumentFragment} |
+ */ |
+ _renderSimplifiedSelectors(selectors, matchingSelectors) { |
+ var fragment = createDocumentFragment(); |
+ var currentMatching = false; |
+ var text = ''; |
+ for (var i = 0; i < selectors.length; ++i) { |
+ if (currentMatching !== matchingSelectors[i] && text) { |
+ fragment.appendChild(this._createSelectorElement(text, currentMatching)); |
+ text = ''; |
+ } |
+ currentMatching = matchingSelectors[i]; |
+ text += selectors[i] + (i === selectors.length - 1 ? '' : ', '); |
+ } |
+ if (text) |
+ fragment.appendChild(this._createSelectorElement(text, currentMatching)); |
+ return fragment; |
+ } |
+ |
+ _markSelectorHighlights() { |
+ var selectors = this._selectorElement.getElementsByClassName('simple-selector'); |
+ var regex = this._parentPane.filterRegex(); |
+ for (var i = 0; i < selectors.length; ++i) { |
+ var selectorMatchesFilter = !!regex && regex.test(selectors[i].textContent); |
+ selectors[i].classList.toggle('filter-match', selectorMatchesFilter); |
+ } |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ _checkWillCancelEditing() { |
+ var willCauseCancelEditing = this._willCauseCancelEditing; |
+ delete this._willCauseCancelEditing; |
+ return willCauseCancelEditing; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _handleSelectorContainerClick(event) { |
+ if (this._checkWillCancelEditing() || !this.editable) |
+ return; |
+ if (event.target === this._selectorContainer) { |
+ this.addNewBlankProperty(0).startEditing(); |
+ event.consume(true); |
+ } |
+ } |
+ |
+ /** |
+ * @param {number=} index |
+ * @return {!WebInspector.StylePropertyTreeElement} |
+ */ |
+ addNewBlankProperty(index) { |
+ var property = this._style.newBlankProperty(index); |
+ var item = |
+ new WebInspector.StylePropertyTreeElement(this._parentPane, this._matchedStyles, property, false, false, false); |
+ index = property.index; |
+ this.propertiesTreeOutline.insertChild(item, index); |
+ item.listItemElement.textContent = ''; |
+ item._newProperty = true; |
+ item.updateTitle(); |
+ return item; |
+ } |
+ |
+ _handleEmptySpaceMouseDown() { |
+ this._willCauseCancelEditing = this._parentPane._isEditingStyle; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _handleEmptySpaceClick(event) { |
+ if (!this.editable) |
+ return; |
+ |
+ var targetElement = event.deepElementFromPoint(); |
+ if (targetElement && !targetElement.isComponentSelectionCollapsed()) |
+ return; |
+ |
+ if (!event.target.isComponentSelectionCollapsed()) |
+ return; |
+ |
+ if (this._checkWillCancelEditing()) |
+ return; |
+ |
+ if (event.target.enclosingNodeOrSelfWithNodeName('a')) |
+ return; |
+ |
+ if (event.target.classList.contains('header') || this.element.classList.contains('read-only') || |
+ event.target.enclosingNodeOrSelfWithClass('media')) { |
+ event.consume(); |
+ return; |
+ } |
+ this.addNewBlankProperty().startEditing(); |
+ event.consume(true); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSMedia} media |
+ * @param {!Element} element |
+ * @param {!Event} event |
+ */ |
+ _handleMediaRuleClick(media, element, event) { |
+ if (WebInspector.isBeingEdited(element)) |
+ return; |
+ |
+ if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */ (event)) && this.navigable) { |
+ var location = media.rawLocation(); |
+ if (!location) { |
+ event.consume(true); |
+ return; |
+ } |
+ var uiLocation = WebInspector.cssWorkspaceBinding.rawLocationToUILocation(location); |
+ if (uiLocation) |
+ WebInspector.Revealer.reveal(uiLocation); |
+ event.consume(true); |
+ return; |
+ } |
- /** |
- * @return {boolean} |
- */ |
- _isSASSStyle: function() |
- { |
- var header = this._style.styleSheetId ? this._style.cssModel().styleSheetHeaderForId(this._style.styleSheetId) : null; |
- if (!header) |
- return false; |
- var sourceMap = header.cssModel().sourceMapForHeader(header); |
- return sourceMap ? sourceMap.editable() : false; |
- }, |
+ if (!this.editable || this._isSASSStyle()) |
+ return; |
+ |
+ var config = new WebInspector.InplaceEditor.Config( |
+ this._editingMediaCommitted.bind(this, media), this._editingMediaCancelled.bind(this, element), undefined, |
+ this._editingMediaBlurHandler.bind(this)); |
+ WebInspector.InplaceEditor.startEditing(element, config); |
+ |
+ element.getComponentSelection().setBaseAndExtent(element, 0, element, 1); |
+ this._parentPane.setEditingStyle(true); |
+ var parentMediaElement = element.enclosingNodeOrSelfWithClass('media'); |
+ parentMediaElement.classList.add('editing-media'); |
+ |
+ event.consume(true); |
+ } |
+ |
+ /** |
+ * @param {!Element} element |
+ */ |
+ _editingMediaFinished(element) { |
+ this._parentPane.setEditingStyle(false); |
+ var parentMediaElement = element.enclosingNodeOrSelfWithClass('media'); |
+ parentMediaElement.classList.remove('editing-media'); |
+ } |
+ |
+ /** |
+ * @param {!Element} element |
+ */ |
+ _editingMediaCancelled(element) { |
+ this._editingMediaFinished(element); |
+ // Mark the selectors in group if necessary. |
+ // This is overridden by BlankStylePropertiesSection. |
+ this._markSelectorMatches(); |
+ element.getComponentSelection().collapse(element, 0); |
+ } |
+ |
+ /** |
+ * @param {!Element} editor |
+ * @param {!Event} blurEvent |
+ * @return {boolean} |
+ */ |
+ _editingMediaBlurHandler(editor, blurEvent) { |
+ return true; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSMedia} media |
+ * @param {!Element} element |
+ * @param {string} newContent |
+ * @param {string} oldContent |
+ * @param {(!WebInspector.StylePropertyTreeElement.Context|undefined)} context |
+ * @param {string} moveDirection |
+ */ |
+ _editingMediaCommitted(media, element, newContent, oldContent, context, moveDirection) { |
+ this._parentPane.setEditingStyle(false); |
+ this._editingMediaFinished(element); |
+ |
+ if (newContent) |
+ newContent = newContent.trim(); |
+ |
+ /** |
+ * @param {boolean} success |
+ * @this {WebInspector.StylePropertiesSection} |
+ */ |
+ function userCallback(success) { |
+ if (success) { |
+ this._matchedStyles.resetActiveProperties(); |
+ this._parentPane._refreshUpdate(this); |
+ } |
+ delete this._parentPane._userOperation; |
+ this._editingMediaTextCommittedForTest(); |
+ } |
- /** |
- * @return {!WebInspector.CSSStyleDeclaration} |
- */ |
- style: function() |
- { |
- return this._style; |
- }, |
+ // This gets deleted in finishOperation(), which is called both on success and failure. |
+ this._parentPane._userOperation = true; |
+ this._parentPane.cssModel().setMediaText(media.styleSheetId, media.range, newContent).then(userCallback.bind(this)); |
+ } |
+ |
+ _editingMediaTextCommittedForTest() { |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _handleSelectorClick(event) { |
+ if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */ (event)) && this.navigable && |
+ event.target.classList.contains('simple-selector')) { |
+ this._navigateToSelectorSource(event.target._selectorIndex, true); |
+ event.consume(true); |
+ return; |
+ } |
+ this._startEditingOnMouseEvent(); |
+ event.consume(true); |
+ } |
+ |
+ /** |
+ * @param {number} index |
+ * @param {boolean} focus |
+ */ |
+ _navigateToSelectorSource(index, focus) { |
+ var cssModel = this._parentPane.cssModel(); |
+ var rule = this._style.parentRule; |
+ var header = cssModel.styleSheetHeaderForId(/** @type {string} */ (rule.styleSheetId)); |
+ if (!header) |
+ return; |
+ var rawLocation = |
+ new WebInspector.CSSLocation(header, rule.lineNumberInSource(index), rule.columnNumberInSource(index)); |
+ var uiLocation = WebInspector.cssWorkspaceBinding.rawLocationToUILocation(rawLocation); |
+ if (uiLocation) |
+ WebInspector.Revealer.reveal(uiLocation, !focus); |
+ } |
+ |
+ _startEditingOnMouseEvent() { |
+ if (!this.editable || this._isSASSStyle()) |
+ return; |
+ |
+ var rule = this._style.parentRule; |
+ if (!rule && !this.propertiesTreeOutline.rootElement().childCount()) { |
+ this.addNewBlankProperty().startEditing(); |
+ return; |
+ } |
- /** |
- * @return {string} |
- */ |
- _headerText: function() |
- { |
- var node = this._matchedStyles.nodeForStyle(this._style); |
- if (this._style.type === WebInspector.CSSStyleDeclaration.Type.Inline) |
- return this._matchedStyles.isInherited(this._style) ? WebInspector.UIString("Style Attribute") : "element.style"; |
- if (this._style.type === WebInspector.CSSStyleDeclaration.Type.Attributes) |
- return node.nodeNameInCorrectCase() + "[" + WebInspector.UIString("Attributes Style") + "]"; |
- return this._style.parentRule.selectorText(); |
- }, |
- |
- _onMouseOutSelector: function() |
- { |
- if (this._hoverTimer) |
- clearTimeout(this._hoverTimer); |
- WebInspector.DOMModel.hideDOMNodeHighlight(); |
- }, |
- |
- _onMouseEnterSelector: function() |
- { |
- if (this._hoverTimer) |
- clearTimeout(this._hoverTimer); |
- this._hoverTimer = setTimeout(this._highlight.bind(this), 300); |
- }, |
- |
- _highlight: function() |
- { |
- WebInspector.DOMModel.hideDOMNodeHighlight(); |
- var node = this._parentPane.node(); |
- var domModel = node.domModel(); |
- var selectors = this._style.parentRule ? this._style.parentRule.selectorText() : undefined; |
- domModel.highlightDOMNodeWithConfig(node.id, { mode: "all", showInfo: undefined, selectors: selectors }); |
- }, |
+ if (!rule) |
+ return; |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- firstSibling: function() |
- { |
- var parent = this.element.parentElement; |
- if (!parent) |
- return null; |
- |
- var childElement = parent.firstChild; |
- while (childElement) { |
- if (childElement._section) |
- return childElement._section; |
- childElement = childElement.nextSibling; |
- } |
+ this.startEditingSelector(); |
+ } |
- return null; |
- }, |
+ startEditingSelector() { |
+ var element = this._selectorElement; |
+ if (WebInspector.isBeingEdited(element)) |
+ return; |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- lastSibling: function() |
- { |
- var parent = this.element.parentElement; |
- if (!parent) |
- return null; |
- |
- var childElement = parent.lastChild; |
- while (childElement) { |
- if (childElement._section) |
- return childElement._section; |
- childElement = childElement.previousSibling; |
- } |
+ element.scrollIntoViewIfNeeded(false); |
+ element.textContent = element.textContent; // Reset selector marks in group. |
- return null; |
- }, |
+ var config = new WebInspector.InplaceEditor.Config( |
+ this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this)); |
+ WebInspector.InplaceEditor.startEditing(this._selectorElement, config); |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- nextSibling: function() |
- { |
- var curElement = this.element; |
- do { |
- curElement = curElement.nextSibling; |
- } while (curElement && !curElement._section); |
+ element.getComponentSelection().setBaseAndExtent(element, 0, element, 1); |
+ this._parentPane.setEditingStyle(true); |
+ if (element.classList.contains('simple-selector')) |
+ this._navigateToSelectorSource(0, false); |
+ } |
- return curElement ? curElement._section : null; |
- }, |
+ /** |
+ * @param {string} moveDirection |
+ */ |
+ _moveEditorFromSelector(moveDirection) { |
+ this._markSelectorMatches(); |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- previousSibling: function() |
- { |
- var curElement = this.element; |
- do { |
- curElement = curElement.previousSibling; |
- } while (curElement && !curElement._section); |
+ if (!moveDirection) |
+ return; |
- return curElement ? curElement._section : null; |
- }, |
+ if (moveDirection === 'forward') { |
+ var firstChild = this.propertiesTreeOutline.firstChild(); |
+ while (firstChild && firstChild.inherited()) |
+ firstChild = firstChild.nextSibling; |
+ if (!firstChild) |
+ this.addNewBlankProperty().startEditing(); |
+ else |
+ firstChild.startEditing(firstChild.nameElement); |
+ } else { |
+ var previousSection = this.previousEditableSibling(); |
+ if (!previousSection) |
+ return; |
+ |
+ previousSection.addNewBlankProperty().startEditing(); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!Element} element |
+ * @param {string} newContent |
+ * @param {string} oldContent |
+ * @param {(!WebInspector.StylePropertyTreeElement.Context|undefined)} context |
+ * @param {string} moveDirection |
+ */ |
+ editingSelectorCommitted(element, newContent, oldContent, context, moveDirection) { |
+ this._editingSelectorEnded(); |
+ if (newContent) |
+ newContent = newContent.trim(); |
+ if (newContent === oldContent) { |
+ // Revert to a trimmed version of the selector if need be. |
+ this._selectorElement.textContent = newContent; |
+ this._moveEditorFromSelector(moveDirection); |
+ return; |
+ } |
+ var rule = this._style.parentRule; |
+ if (!rule) |
+ return; |
/** |
- * @param {!WebInspector.Event} event |
+ * @this {WebInspector.StylePropertiesSection} |
*/ |
- _onNewRuleClick: function(event) |
- { |
- event.consume(); |
- var rule = this._style.parentRule; |
- var range = WebInspector.TextRange.createFromLocation(rule.style.range.endLine, rule.style.range.endColumn + 1); |
- this._parentPane._addBlankSection(this, /** @type {string} */(rule.styleSheetId), range); |
- }, |
+ function headerTextCommitted() { |
+ delete this._parentPane._userOperation; |
+ this._moveEditorFromSelector(moveDirection); |
+ this._editingSelectorCommittedForTest(); |
+ } |
- /** |
- * @param {string} propertyName |
- * @param {!WebInspector.Event} event |
- */ |
- _onInsertShadowPropertyClick: function(propertyName, event) |
- { |
- event.consume(true); |
- var treeElement = this.addNewBlankProperty(); |
- treeElement.property.name = propertyName; |
- treeElement.property.value = "0 0 black"; |
- treeElement.updateTitle(); |
- var shadowSwatchPopoverHelper = WebInspector.ShadowSwatchPopoverHelper.forTreeElement(treeElement); |
- if (shadowSwatchPopoverHelper) |
- shadowSwatchPopoverHelper.showPopover(); |
- }, |
+ // This gets deleted in finishOperationAndMoveEditor(), which is called both on success and failure. |
+ this._parentPane._userOperation = true; |
+ this._setHeaderText(rule, newContent).then(headerTextCommitted.bind(this)); |
+ } |
+ /** |
+ * @param {!WebInspector.CSSRule} rule |
+ * @param {string} newContent |
+ * @return {!Promise} |
+ */ |
+ _setHeaderText(rule, newContent) { |
/** |
- * @param {!WebInspector.Event} event |
+ * @param {!WebInspector.CSSStyleRule} rule |
+ * @param {boolean} success |
+ * @return {!Promise} |
+ * @this {WebInspector.StylePropertiesSection} |
*/ |
- _onInsertColorPropertyClick: function(event) |
- { |
- event.consume(true); |
- var treeElement = this.addNewBlankProperty(); |
- treeElement.property.name = "color"; |
- treeElement.property.value = "black"; |
- treeElement.updateTitle(); |
- var colorSwatch = WebInspector.ColorSwatchPopoverIcon.forTreeElement(treeElement); |
- if (colorSwatch) |
- colorSwatch.showPopover(); |
- }, |
+ function onSelectorsUpdated(rule, success) { |
+ if (!success) |
+ return Promise.resolve(); |
+ return this._matchedStyles.recomputeMatchingSelectors(rule).then(updateSourceRanges.bind(this, rule)); |
+ } |
/** |
- * @param {!WebInspector.Event} event |
+ * @param {!WebInspector.CSSStyleRule} rule |
+ * @this {WebInspector.StylePropertiesSection} |
*/ |
- _onInsertBackgroundColorPropertyClick: function(event) |
- { |
- event.consume(true); |
- var treeElement = this.addNewBlankProperty(); |
- treeElement.property.name = "background-color"; |
- treeElement.property.value = "white"; |
- treeElement.updateTitle(); |
- var colorSwatch = WebInspector.ColorSwatchPopoverIcon.forTreeElement(treeElement); |
- if (colorSwatch) |
- colorSwatch.showPopover(); |
- }, |
+ function updateSourceRanges(rule) { |
+ var doesAffectSelectedNode = this._matchedStyles.matchingSelectors(rule).length > 0; |
+ this.propertiesTreeOutline.element.classList.toggle('no-affect', !doesAffectSelectedNode); |
+ this._matchedStyles.resetActiveProperties(); |
+ this._parentPane._refreshUpdate(this); |
+ } |
- /** |
- * @param {!WebInspector.CSSModel.Edit} edit |
- */ |
- _styleSheetEdited: function(edit) |
- { |
- var rule = this._style.parentRule; |
- if (rule) |
- rule.rebase(edit); |
- else |
- this._style.rebase(edit); |
+ console.assert(rule instanceof WebInspector.CSSStyleRule); |
+ var oldSelectorRange = rule.selectorRange(); |
+ if (!oldSelectorRange) |
+ return Promise.resolve(); |
+ var selectedNode = this._parentPane.node(); |
+ return rule.setSelectorText(newContent) |
+ .then(onSelectorsUpdated.bind(this, /** @type {!WebInspector.CSSStyleRule} */ (rule), oldSelectorRange)); |
+ } |
- this._updateMediaList(); |
- this._updateRuleOrigin(); |
- }, |
+ _editingSelectorCommittedForTest() { |
+ } |
- /** |
- * @param {!Array.<!WebInspector.CSSMedia>} mediaRules |
- */ |
- _createMediaList: function(mediaRules) |
- { |
- for (var i = mediaRules.length - 1; i >= 0; --i) { |
- var media = mediaRules[i]; |
- // Don't display trivial non-print media types. |
- if (!media.text.includes("(") && media.text !== "print") |
- continue; |
- var mediaDataElement = this._mediaListElement.createChild("div", "media"); |
- var mediaContainerElement = mediaDataElement.createChild("span"); |
- var mediaTextElement = mediaContainerElement.createChild("span", "media-text"); |
- switch (media.source) { |
- case WebInspector.CSSMedia.Source.LINKED_SHEET: |
- case WebInspector.CSSMedia.Source.INLINE_SHEET: |
- mediaTextElement.textContent = "media=\"" + media.text + "\""; |
- break; |
- case WebInspector.CSSMedia.Source.MEDIA_RULE: |
- var decoration = mediaContainerElement.createChild("span"); |
- mediaContainerElement.insertBefore(decoration, mediaTextElement); |
- decoration.textContent = "@media "; |
- mediaTextElement.textContent = media.text; |
- if (media.styleSheetId) { |
- mediaDataElement.classList.add("editable-media"); |
- mediaTextElement.addEventListener("click", this._handleMediaRuleClick.bind(this, media, mediaTextElement), false); |
- } |
- break; |
- case WebInspector.CSSMedia.Source.IMPORT_RULE: |
- mediaTextElement.textContent = "@import " + media.text; |
- break; |
- } |
- } |
- }, |
+ _updateRuleOrigin() { |
+ this._selectorRefElement.removeChildren(); |
+ this._selectorRefElement.appendChild(WebInspector.StylePropertiesSection.createRuleOriginNode( |
+ this._matchedStyles, this._parentPane._linkifier, this._style.parentRule)); |
+ } |
- _updateMediaList: function() |
- { |
- this._mediaListElement.removeChildren(); |
- if (this._style.parentRule && this._style.parentRule instanceof WebInspector.CSSStyleRule) |
- this._createMediaList(this._style.parentRule.media); |
- }, |
+ _editingSelectorEnded() { |
+ this._parentPane.setEditingStyle(false); |
+ } |
- /** |
- * @param {string} propertyName |
- * @return {boolean} |
- */ |
- isPropertyInherited: function(propertyName) |
- { |
- if (this._matchedStyles.isInherited(this._style)) { |
- // While rendering inherited stylesheet, reverse meaning of this property. |
- // Render truly inherited properties with black, i.e. return them as non-inherited. |
- return !WebInspector.cssMetadata().isPropertyInherited(propertyName); |
- } |
- return false; |
- }, |
+ editingSelectorCancelled() { |
+ this._editingSelectorEnded(); |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- nextEditableSibling: function() |
- { |
- var curSection = this; |
- do { |
- curSection = curSection.nextSibling(); |
- } while (curSection && !curSection.editable); |
- |
- if (!curSection) { |
- curSection = this.firstSibling(); |
- while (curSection && !curSection.editable) |
- curSection = curSection.nextSibling(); |
- } |
+ // Mark the selectors in group if necessary. |
+ // This is overridden by BlankStylePropertiesSection. |
+ this._markSelectorMatches(); |
+ } |
+}; |
- return (curSection && curSection.editable) ? curSection : null; |
- }, |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- previousEditableSibling: function() |
- { |
- var curSection = this; |
- do { |
- curSection = curSection.previousSibling(); |
- } while (curSection && !curSection.editable); |
- |
- if (!curSection) { |
- curSection = this.lastSibling(); |
- while (curSection && !curSection.editable) |
- curSection = curSection.previousSibling(); |
- } |
+/** |
+ * @unrestricted |
+ */ |
+WebInspector.BlankStylePropertiesSection = class extends WebInspector.StylePropertiesSection { |
+ /** |
+ * @param {!WebInspector.StylesSidebarPane} stylesPane |
+ * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
+ * @param {string} defaultSelectorText |
+ * @param {string} styleSheetId |
+ * @param {!WebInspector.TextRange} ruleLocation |
+ * @param {!WebInspector.CSSStyleDeclaration} insertAfterStyle |
+ */ |
+ constructor(stylesPane, matchedStyles, defaultSelectorText, styleSheetId, ruleLocation, insertAfterStyle) { |
+ var cssModel = /** @type {!WebInspector.CSSModel} */ (stylesPane.cssModel()); |
+ var rule = WebInspector.CSSStyleRule.createDummyRule(cssModel, defaultSelectorText); |
+ super(stylesPane, matchedStyles, rule.style); |
+ this._ruleLocation = ruleLocation; |
+ this._styleSheetId = styleSheetId; |
+ this._selectorRefElement.removeChildren(); |
+ this._selectorRefElement.appendChild(WebInspector.StylePropertiesSection._linkifyRuleLocation( |
+ cssModel, this._parentPane._linkifier, styleSheetId, this._actualRuleLocation())); |
+ if (insertAfterStyle && insertAfterStyle.parentRule) |
+ this._createMediaList(insertAfterStyle.parentRule.media); |
+ this.element.classList.add('blank-section'); |
+ } |
+ |
+ /** |
+ * @return {!WebInspector.TextRange} |
+ */ |
+ _actualRuleLocation() { |
+ var prefix = this._rulePrefix(); |
+ var lines = prefix.split('\n'); |
+ var editRange = new WebInspector.TextRange(0, 0, lines.length - 1, lines.peekLast().length); |
+ return this._ruleLocation.rebaseAfterTextEdit(WebInspector.TextRange.createFromLocation(0, 0), editRange); |
+ } |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ _rulePrefix() { |
+ return this._ruleLocation.startLine === 0 && this._ruleLocation.startColumn === 0 ? '' : '\n\n'; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ get isBlank() { |
+ return !this._normal; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!Element} element |
+ * @param {string} newContent |
+ * @param {string} oldContent |
+ * @param {!WebInspector.StylePropertyTreeElement.Context|undefined} context |
+ * @param {string} moveDirection |
+ */ |
+ editingSelectorCommitted(element, newContent, oldContent, context, moveDirection) { |
+ if (!this.isBlank) { |
+ super.editingSelectorCommitted(element, newContent, oldContent, context, moveDirection); |
+ return; |
+ } |
- return (curSection && curSection.editable) ? curSection : null; |
- }, |
+ /** |
+ * @param {?WebInspector.CSSStyleRule} newRule |
+ * @return {!Promise} |
+ * @this {WebInspector.StylePropertiesSection} |
+ */ |
+ function onRuleAdded(newRule) { |
+ if (!newRule) { |
+ this.editingSelectorCancelled(); |
+ this._editingSelectorCommittedForTest(); |
+ return Promise.resolve(); |
+ } |
+ return this._matchedStyles.addNewRule(newRule, this._matchedStyles.node()) |
+ .then(onAddedToCascade.bind(this, newRule)); |
+ } |
/** |
- * @param {boolean} full |
+ * @param {!WebInspector.CSSStyleRule} newRule |
+ * @this {WebInspector.StylePropertiesSection} |
*/ |
- update: function(full) |
- { |
- this._selectorElement.textContent = this._headerText(); |
- this._markSelectorMatches(); |
- if (full) { |
- this.propertiesTreeOutline.removeChildren(); |
- this.onpopulate(); |
- } else { |
- var child = this.propertiesTreeOutline.firstChild(); |
- while (child) { |
- child.setOverloaded(this._isPropertyOverloaded(child.property)); |
- child = child.traverseNextTreeElement(false, null, true); |
- } |
- } |
- this.afterUpdate(); |
- }, |
- |
- afterUpdate: function() |
- { |
- if (this._afterUpdate) { |
- this._afterUpdate(this); |
- delete this._afterUpdate; |
- this._afterUpdateFinishedForTest(); |
- } |
- }, |
- |
- _afterUpdateFinishedForTest: function() |
- { |
- }, |
- |
- onpopulate: function() |
- { |
- var style = this._style; |
- for (var property of style.leadingProperties()) { |
- var isShorthand = !!style.longhandProperties(property.name).length; |
- var inherited = this.isPropertyInherited(property.name); |
- var overloaded = this._isPropertyOverloaded(property); |
- var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this._matchedStyles, property, isShorthand, inherited, overloaded); |
- this.propertiesTreeOutline.appendChild(item); |
- } |
- }, |
+ function onAddedToCascade(newRule) { |
+ var doesSelectorAffectSelectedNode = this._matchedStyles.matchingSelectors(newRule).length > 0; |
+ this._makeNormal(newRule); |
- /** |
- * @param {!WebInspector.CSSProperty} property |
- * @return {boolean} |
- */ |
- _isPropertyOverloaded: function(property) |
- { |
- return this._matchedStyles.propertyState(property) === WebInspector.CSSMatchedStyles.PropertyState.Overloaded; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- _updateFilter: function() |
- { |
- var hasMatchingChild = false; |
- for (var child of this.propertiesTreeOutline.rootElement().children()) |
- hasMatchingChild |= child._updateFilter(); |
- |
- var regex = this._parentPane.filterRegex(); |
- var hideRule = !hasMatchingChild && !!regex && !regex.test(this.element.deepTextContent()); |
- this.element.classList.toggle("hidden", hideRule); |
- if (!hideRule && this._style.parentRule) |
- this._markSelectorHighlights(); |
- return !hideRule; |
- }, |
- |
- _markSelectorMatches: function() |
- { |
- var rule = this._style.parentRule; |
- if (!rule) |
- return; |
- |
- this._mediaListElement.classList.toggle("media-matches", this._matchedStyles.mediaMatches(this._style)); |
- |
- var selectorTexts = rule.selectors.map(selector => selector.text); |
- var matchingSelectorIndexes = this._matchedStyles.matchingSelectors(/** @type {!WebInspector.CSSStyleRule} */(rule)); |
- var matchingSelectors = new Array(selectorTexts.length).fill(false); |
- for (var matchingIndex of matchingSelectorIndexes) |
- matchingSelectors[matchingIndex] = true; |
- |
- var fragment = this._hoverableSelectorsMode ? this._renderHoverableSelectors(selectorTexts, matchingSelectors) : this._renderSimplifiedSelectors(selectorTexts, matchingSelectors); |
- this._selectorElement.removeChildren(); |
- this._selectorElement.appendChild(fragment); |
- this._markSelectorHighlights(); |
- }, |
- |
- /** |
- * @param {!Array<string>} selectors |
- * @param {!Array<boolean>} matchingSelectors |
- * @return {!DocumentFragment} |
- */ |
- _renderHoverableSelectors: function(selectors, matchingSelectors) |
- { |
- var fragment = createDocumentFragment(); |
- for (var i = 0; i < selectors.length ; ++i) { |
- if (i) |
- fragment.createTextChild(", "); |
- fragment.appendChild(this._createSelectorElement(selectors[i], matchingSelectors[i], i)); |
- } |
- return fragment; |
- }, |
- |
- /** |
- * @param {string} text |
- * @param {boolean} isMatching |
- * @param {number=} navigationIndex |
- * @return {!Element} |
- */ |
- _createSelectorElement: function(text, isMatching, navigationIndex) |
- { |
- var element = createElementWithClass("span", "simple-selector"); |
- element.classList.toggle("selector-matches", isMatching); |
- if (typeof navigationIndex === "number") |
- element._selectorIndex = navigationIndex; |
- element.textContent = text; |
- return element; |
- }, |
- |
- /** |
- * @param {!Array<string>} selectors |
- * @param {!Array<boolean>} matchingSelectors |
- * @return {!DocumentFragment} |
- */ |
- _renderSimplifiedSelectors: function(selectors, matchingSelectors) |
- { |
- var fragment = createDocumentFragment(); |
- var currentMatching = false; |
- var text = ""; |
- for (var i = 0; i < selectors.length; ++i) { |
- if (currentMatching !== matchingSelectors[i] && text) { |
- fragment.appendChild(this._createSelectorElement(text, currentMatching)); |
- text = ""; |
- } |
- currentMatching = matchingSelectors[i]; |
- text += selectors[i] + (i === selectors.length - 1 ? "" : ", "); |
- } |
- if (text) |
- fragment.appendChild(this._createSelectorElement(text, currentMatching)); |
- return fragment; |
- }, |
- |
- _markSelectorHighlights: function() |
- { |
- var selectors = this._selectorElement.getElementsByClassName("simple-selector"); |
- var regex = this._parentPane.filterRegex(); |
- for (var i = 0; i < selectors.length; ++i) { |
- var selectorMatchesFilter = !!regex && regex.test(selectors[i].textContent); |
- selectors[i].classList.toggle("filter-match", selectorMatchesFilter); |
- } |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- _checkWillCancelEditing: function() |
- { |
- var willCauseCancelEditing = this._willCauseCancelEditing; |
- delete this._willCauseCancelEditing; |
- return willCauseCancelEditing; |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _handleSelectorContainerClick: function(event) |
- { |
- if (this._checkWillCancelEditing() || !this.editable) |
- return; |
- if (event.target === this._selectorContainer) { |
- this.addNewBlankProperty(0).startEditing(); |
- event.consume(true); |
- } |
- }, |
- |
- /** |
- * @param {number=} index |
- * @return {!WebInspector.StylePropertyTreeElement} |
- */ |
- addNewBlankProperty: function(index) |
- { |
- var property = this._style.newBlankProperty(index); |
- var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this._matchedStyles, property, false, false, false); |
- index = property.index; |
- this.propertiesTreeOutline.insertChild(item, index); |
- item.listItemElement.textContent = ""; |
- item._newProperty = true; |
- item.updateTitle(); |
- return item; |
- }, |
- |
- _handleEmptySpaceMouseDown: function() |
- { |
- this._willCauseCancelEditing = this._parentPane._isEditingStyle; |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _handleEmptySpaceClick: function(event) |
- { |
- if (!this.editable) |
- return; |
- |
- var targetElement = event.deepElementFromPoint(); |
- if (targetElement && !targetElement.isComponentSelectionCollapsed()) |
- return; |
- |
- if (!event.target.isComponentSelectionCollapsed()) |
- return; |
- |
- if (this._checkWillCancelEditing()) |
- return; |
- |
- if (event.target.enclosingNodeOrSelfWithNodeName("a")) |
- return; |
- |
- if (event.target.classList.contains("header") || this.element.classList.contains("read-only") || event.target.enclosingNodeOrSelfWithClass("media")) { |
- event.consume(); |
- return; |
- } |
- this.addNewBlankProperty().startEditing(); |
- event.consume(true); |
- }, |
- |
- /** |
- * @param {!WebInspector.CSSMedia} media |
- * @param {!Element} element |
- * @param {!Event} event |
- */ |
- _handleMediaRuleClick: function(media, element, event) |
- { |
- if (WebInspector.isBeingEdited(element)) |
- return; |
- |
- if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */(event)) && this.navigable) { |
- var location = media.rawLocation(); |
- if (!location) { |
- event.consume(true); |
- return; |
- } |
- var uiLocation = WebInspector.cssWorkspaceBinding.rawLocationToUILocation(location); |
- if (uiLocation) |
- WebInspector.Revealer.reveal(uiLocation); |
- event.consume(true); |
- return; |
- } |
- |
- if (!this.editable || this._isSASSStyle()) |
- return; |
- |
- var config = new WebInspector.InplaceEditor.Config(this._editingMediaCommitted.bind(this, media), this._editingMediaCancelled.bind(this, element), undefined, this._editingMediaBlurHandler.bind(this)); |
- WebInspector.InplaceEditor.startEditing(element, config); |
- |
- element.getComponentSelection().setBaseAndExtent(element, 0, element, 1); |
- this._parentPane.setEditingStyle(true); |
- var parentMediaElement = element.enclosingNodeOrSelfWithClass("media"); |
- parentMediaElement.classList.add("editing-media"); |
- |
- event.consume(true); |
- }, |
- |
- /** |
- * @param {!Element} element |
- */ |
- _editingMediaFinished: function(element) |
- { |
- this._parentPane.setEditingStyle(false); |
- var parentMediaElement = element.enclosingNodeOrSelfWithClass("media"); |
- parentMediaElement.classList.remove("editing-media"); |
- }, |
- |
- /** |
- * @param {!Element} element |
- */ |
- _editingMediaCancelled: function(element) |
- { |
- this._editingMediaFinished(element); |
- // Mark the selectors in group if necessary. |
- // This is overridden by BlankStylePropertiesSection. |
- this._markSelectorMatches(); |
- element.getComponentSelection().collapse(element, 0); |
- }, |
- |
- /** |
- * @param {!Element} editor |
- * @param {!Event} blurEvent |
- * @return {boolean} |
- */ |
- _editingMediaBlurHandler: function(editor, blurEvent) |
- { |
- return true; |
- }, |
- |
- /** |
- * @param {!WebInspector.CSSMedia} media |
- * @param {!Element} element |
- * @param {string} newContent |
- * @param {string} oldContent |
- * @param {(!WebInspector.StylePropertyTreeElement.Context|undefined)} context |
- * @param {string} moveDirection |
- */ |
- _editingMediaCommitted: function(media, element, newContent, oldContent, context, moveDirection) |
- { |
- this._parentPane.setEditingStyle(false); |
- this._editingMediaFinished(element); |
- |
- if (newContent) |
- newContent = newContent.trim(); |
- |
- /** |
- * @param {boolean} success |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function userCallback(success) |
- { |
- if (success) { |
- this._matchedStyles.resetActiveProperties(); |
- this._parentPane._refreshUpdate(this); |
- } |
- delete this._parentPane._userOperation; |
- this._editingMediaTextCommittedForTest(); |
- } |
- |
- // This gets deleted in finishOperation(), which is called both on success and failure. |
- this._parentPane._userOperation = true; |
- this._parentPane.cssModel().setMediaText(media.styleSheetId, media.range, newContent) |
- .then(userCallback.bind(this)); |
- }, |
- |
- _editingMediaTextCommittedForTest: function() { }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _handleSelectorClick: function(event) |
- { |
- if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */(event)) && this.navigable && event.target.classList.contains("simple-selector")) { |
- this._navigateToSelectorSource(event.target._selectorIndex, true); |
- event.consume(true); |
- return; |
- } |
- this._startEditingOnMouseEvent(); |
- event.consume(true); |
- }, |
- |
- /** |
- * @param {number} index |
- * @param {boolean} focus |
- */ |
- _navigateToSelectorSource: function(index, focus) |
- { |
- var cssModel = this._parentPane.cssModel(); |
- var rule = this._style.parentRule; |
- var header = cssModel.styleSheetHeaderForId(/** @type {string} */(rule.styleSheetId)); |
- if (!header) |
- return; |
- var rawLocation = new WebInspector.CSSLocation(header, rule.lineNumberInSource(index), rule.columnNumberInSource(index)); |
- var uiLocation = WebInspector.cssWorkspaceBinding.rawLocationToUILocation(rawLocation); |
- if (uiLocation) |
- WebInspector.Revealer.reveal(uiLocation, !focus); |
- }, |
- |
- _startEditingOnMouseEvent: function() |
- { |
- if (!this.editable || this._isSASSStyle()) |
- return; |
- |
- var rule = this._style.parentRule; |
- if (!rule && !this.propertiesTreeOutline.rootElement().childCount()) { |
- this.addNewBlankProperty().startEditing(); |
- return; |
- } |
- |
- if (!rule) |
- return; |
- |
- this.startEditingSelector(); |
- }, |
- |
- startEditingSelector: function() |
- { |
- var element = this._selectorElement; |
- if (WebInspector.isBeingEdited(element)) |
- return; |
- |
- element.scrollIntoViewIfNeeded(false); |
- element.textContent = element.textContent; // Reset selector marks in group. |
- |
- var config = new WebInspector.InplaceEditor.Config(this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this)); |
- WebInspector.InplaceEditor.startEditing(this._selectorElement, config); |
- |
- element.getComponentSelection().setBaseAndExtent(element, 0, element, 1); |
- this._parentPane.setEditingStyle(true); |
- if (element.classList.contains("simple-selector")) |
- this._navigateToSelectorSource(0, false); |
- }, |
- |
- /** |
- * @param {string} moveDirection |
- */ |
- _moveEditorFromSelector: function(moveDirection) |
- { |
- this._markSelectorMatches(); |
- |
- if (!moveDirection) |
- return; |
- |
- if (moveDirection === "forward") { |
- var firstChild = this.propertiesTreeOutline.firstChild(); |
- while (firstChild && firstChild.inherited()) |
- firstChild = firstChild.nextSibling; |
- if (!firstChild) |
- this.addNewBlankProperty().startEditing(); |
- else |
- firstChild.startEditing(firstChild.nameElement); |
- } else { |
- var previousSection = this.previousEditableSibling(); |
- if (!previousSection) |
- return; |
- |
- previousSection.addNewBlankProperty().startEditing(); |
- } |
- }, |
- |
- /** |
- * @param {!Element} element |
- * @param {string} newContent |
- * @param {string} oldContent |
- * @param {(!WebInspector.StylePropertyTreeElement.Context|undefined)} context |
- * @param {string} moveDirection |
- */ |
- editingSelectorCommitted: function(element, newContent, oldContent, context, moveDirection) |
- { |
- this._editingSelectorEnded(); |
- if (newContent) |
- newContent = newContent.trim(); |
- if (newContent === oldContent) { |
- // Revert to a trimmed version of the selector if need be. |
- this._selectorElement.textContent = newContent; |
- this._moveEditorFromSelector(moveDirection); |
- return; |
- } |
- var rule = this._style.parentRule; |
- if (!rule) |
- return; |
- |
- /** |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function headerTextCommitted() |
- { |
- delete this._parentPane._userOperation; |
- this._moveEditorFromSelector(moveDirection); |
- this._editingSelectorCommittedForTest(); |
- } |
- |
- // This gets deleted in finishOperationAndMoveEditor(), which is called both on success and failure. |
- this._parentPane._userOperation = true; |
- this._setHeaderText(rule, newContent).then(headerTextCommitted.bind(this)); |
- }, |
- |
- /** |
- * @param {!WebInspector.CSSRule} rule |
- * @param {string} newContent |
- * @return {!Promise} |
- */ |
- _setHeaderText: function(rule, newContent) |
- { |
- /** |
- * @param {!WebInspector.CSSStyleRule} rule |
- * @param {boolean} success |
- * @return {!Promise} |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function onSelectorsUpdated(rule, success) |
- { |
- if (!success) |
- return Promise.resolve(); |
- return this._matchedStyles.recomputeMatchingSelectors(rule) |
- .then(updateSourceRanges.bind(this, rule)); |
- } |
- |
- /** |
- * @param {!WebInspector.CSSStyleRule} rule |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function updateSourceRanges(rule) |
- { |
- var doesAffectSelectedNode = this._matchedStyles.matchingSelectors(rule).length > 0; |
- this.propertiesTreeOutline.element.classList.toggle("no-affect", !doesAffectSelectedNode); |
- this._matchedStyles.resetActiveProperties(); |
- this._parentPane._refreshUpdate(this); |
- } |
- |
- console.assert(rule instanceof WebInspector.CSSStyleRule); |
- var oldSelectorRange = rule.selectorRange(); |
- if (!oldSelectorRange) |
- return Promise.resolve(); |
- var selectedNode = this._parentPane.node(); |
- return rule.setSelectorText(newContent) |
- .then(onSelectorsUpdated.bind(this, /** @type {!WebInspector.CSSStyleRule} */(rule), oldSelectorRange)); |
- }, |
- |
- _editingSelectorCommittedForTest: function() { }, |
- |
- _updateRuleOrigin: function() |
- { |
- this._selectorRefElement.removeChildren(); |
- this._selectorRefElement.appendChild(WebInspector.StylePropertiesSection.createRuleOriginNode(this._matchedStyles, this._parentPane._linkifier, this._style.parentRule)); |
- }, |
- |
- _editingSelectorEnded: function() |
- { |
- this._parentPane.setEditingStyle(false); |
- }, |
- |
- editingSelectorCancelled: function() |
- { |
- this._editingSelectorEnded(); |
- |
- // Mark the selectors in group if necessary. |
- // This is overridden by BlankStylePropertiesSection. |
- this._markSelectorMatches(); |
- } |
-}; |
- |
-/** |
- * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
- * @param {!WebInspector.Linkifier} linkifier |
- * @param {?WebInspector.CSSRule} rule |
- * @return {!Node} |
- */ |
-WebInspector.StylePropertiesSection.createRuleOriginNode = function(matchedStyles, linkifier, rule) |
-{ |
- if (!rule) |
- return createTextNode(""); |
- |
- var ruleLocation; |
- if (rule instanceof WebInspector.CSSStyleRule) { |
- var matchingSelectors = matchedStyles.matchingSelectors(rule); |
- var firstMatchingIndex = matchingSelectors.length ? matchingSelectors[0] : 0; |
- ruleLocation = rule.selectors[firstMatchingIndex].range; |
- } else if (rule instanceof WebInspector.CSSKeyframeRule) { |
- ruleLocation = rule.key().range; |
- } |
- |
- var header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null; |
- if (ruleLocation && rule.styleSheetId && header && header.resourceURL()) |
- return WebInspector.StylePropertiesSection._linkifyRuleLocation(matchedStyles.cssModel(), linkifier, rule.styleSheetId, ruleLocation); |
- |
- if (rule.isUserAgent()) |
- return createTextNode(WebInspector.UIString("user agent stylesheet")); |
- if (rule.isInjected()) |
- return createTextNode(WebInspector.UIString("injected stylesheet")); |
- if (rule.isViaInspector()) |
- return createTextNode(WebInspector.UIString("via inspector")); |
- |
- if (header && header.ownerNode) { |
- var link = WebInspector.DOMPresentationUtils.linkifyDeferredNodeReference(header.ownerNode); |
- link.textContent = "<style>…</style>"; |
- return link; |
- } |
- |
- return createTextNode(""); |
-}; |
- |
-/** |
- * @param {!WebInspector.CSSModel} cssModel |
- * @param {!WebInspector.Linkifier} linkifier |
- * @param {string} styleSheetId |
- * @param {!WebInspector.TextRange} ruleLocation |
- * @return {!Node} |
- */ |
-WebInspector.StylePropertiesSection._linkifyRuleLocation = function(cssModel, linkifier, styleSheetId, ruleLocation) |
-{ |
- var styleSheetHeader = cssModel.styleSheetHeaderForId(styleSheetId); |
- var lineNumber = styleSheetHeader.lineNumberInSource(ruleLocation.startLine); |
- var columnNumber = styleSheetHeader.columnNumberInSource(ruleLocation.startLine, ruleLocation.startColumn); |
- var matchingSelectorLocation = new WebInspector.CSSLocation(styleSheetHeader, lineNumber, columnNumber); |
- return linkifier.linkifyCSSLocation(matchingSelectorLocation); |
-}; |
- |
-/** |
- * @constructor |
- * @extends {WebInspector.StylePropertiesSection} |
- * @param {!WebInspector.StylesSidebarPane} stylesPane |
- * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
- * @param {string} defaultSelectorText |
- * @param {string} styleSheetId |
- * @param {!WebInspector.TextRange} ruleLocation |
- * @param {!WebInspector.CSSStyleDeclaration} insertAfterStyle |
- */ |
-WebInspector.BlankStylePropertiesSection = function(stylesPane, matchedStyles, defaultSelectorText, styleSheetId, ruleLocation, insertAfterStyle) |
-{ |
- var cssModel = /** @type {!WebInspector.CSSModel} */(stylesPane.cssModel()); |
- var rule = WebInspector.CSSStyleRule.createDummyRule(cssModel, defaultSelectorText); |
- WebInspector.StylePropertiesSection.call(this, stylesPane, matchedStyles, rule.style); |
- this._ruleLocation = ruleLocation; |
- this._styleSheetId = styleSheetId; |
- this._selectorRefElement.removeChildren(); |
- this._selectorRefElement.appendChild(WebInspector.StylePropertiesSection._linkifyRuleLocation(cssModel, this._parentPane._linkifier, styleSheetId, this._actualRuleLocation())); |
- if (insertAfterStyle && insertAfterStyle.parentRule) |
- this._createMediaList(insertAfterStyle.parentRule.media); |
- this.element.classList.add("blank-section"); |
-}; |
- |
-WebInspector.BlankStylePropertiesSection.prototype = { |
- /** |
- * @return {!WebInspector.TextRange} |
- */ |
- _actualRuleLocation: function() |
- { |
- var prefix = this._rulePrefix(); |
- var lines = prefix.split("\n"); |
- var editRange = new WebInspector.TextRange(0, 0, lines.length - 1, lines.peekLast().length); |
- return this._ruleLocation.rebaseAfterTextEdit(WebInspector.TextRange.createFromLocation(0, 0), editRange); |
- }, |
- |
- /** |
- * @return {string} |
- */ |
- _rulePrefix: function() |
- { |
- return this._ruleLocation.startLine === 0 && this._ruleLocation.startColumn === 0 ? "" : "\n\n"; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- get isBlank() |
- { |
- return !this._normal; |
- }, |
- |
- /** |
- * @override |
- * @param {!Element} element |
- * @param {string} newContent |
- * @param {string} oldContent |
- * @param {!WebInspector.StylePropertyTreeElement.Context|undefined} context |
- * @param {string} moveDirection |
- */ |
- editingSelectorCommitted: function(element, newContent, oldContent, context, moveDirection) |
- { |
- if (!this.isBlank) { |
- WebInspector.StylePropertiesSection.prototype.editingSelectorCommitted.call(this, element, newContent, oldContent, context, moveDirection); |
- return; |
- } |
- |
- /** |
- * @param {?WebInspector.CSSStyleRule} newRule |
- * @return {!Promise} |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function onRuleAdded(newRule) |
- { |
- if (!newRule) { |
- this.editingSelectorCancelled(); |
- this._editingSelectorCommittedForTest(); |
- return Promise.resolve(); |
- } |
- return this._matchedStyles.addNewRule(newRule, this._matchedStyles.node()) |
- .then(onAddedToCascade.bind(this, newRule)); |
- } |
- |
- /** |
- * @param {!WebInspector.CSSStyleRule} newRule |
- * @this {WebInspector.StylePropertiesSection} |
- */ |
- function onAddedToCascade(newRule) |
- { |
- var doesSelectorAffectSelectedNode = this._matchedStyles.matchingSelectors(newRule).length > 0; |
- this._makeNormal(newRule); |
- |
- if (!doesSelectorAffectSelectedNode) |
- this.propertiesTreeOutline.element.classList.add("no-affect"); |
- |
- this._updateRuleOrigin(); |
- if (this.element.parentElement) // Might have been detached already. |
- this._moveEditorFromSelector(moveDirection); |
- |
- delete this._parentPane._userOperation; |
- this._editingSelectorEnded(); |
- this._markSelectorMatches(); |
- |
- this._editingSelectorCommittedForTest(); |
- } |
- |
- if (newContent) |
- newContent = newContent.trim(); |
- this._parentPane._userOperation = true; |
- |
- var cssModel = this._parentPane.cssModel(); |
- var ruleText = this._rulePrefix() + newContent + " {}"; |
- cssModel.addRule(this._styleSheetId, ruleText, this._ruleLocation) |
- .then(onRuleAdded.bind(this)); |
- }, |
- |
- editingSelectorCancelled: function() |
- { |
- delete this._parentPane._userOperation; |
- if (!this.isBlank) { |
- WebInspector.StylePropertiesSection.prototype.editingSelectorCancelled.call(this); |
- return; |
- } |
- |
- this._editingSelectorEnded(); |
- this._parentPane.removeSection(this); |
- }, |
- |
- /** |
- * @param {!WebInspector.CSSRule} newRule |
- */ |
- _makeNormal: function(newRule) |
- { |
- this.element.classList.remove("blank-section"); |
- this._style = newRule.style; |
- // FIXME: replace this instance by a normal WebInspector.StylePropertiesSection. |
- this._normal = true; |
- }, |
- |
- __proto__: WebInspector.StylePropertiesSection.prototype |
-}; |
- |
-/** |
- * @constructor |
- * @extends {WebInspector.StylePropertiesSection} |
- * @param {!WebInspector.StylesSidebarPane} stylesPane |
- * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
- * @param {!WebInspector.CSSStyleDeclaration} style |
- */ |
-WebInspector.KeyframePropertiesSection = function(stylesPane, matchedStyles, style) |
-{ |
- WebInspector.StylePropertiesSection.call(this, stylesPane, matchedStyles, style); |
- this._selectorElement.className = "keyframe-key"; |
-}; |
- |
-WebInspector.KeyframePropertiesSection.prototype = { |
- /** |
- * @override |
- * @return {string} |
- */ |
- _headerText: function() |
- { |
- return this._style.parentRule.key().text; |
- }, |
- |
- /** |
- * @override |
- * @param {!WebInspector.CSSRule} rule |
- * @param {string} newContent |
- * @return {!Promise} |
- */ |
- _setHeaderText: function(rule, newContent) |
- { |
- /** |
- * @param {boolean} success |
- * @this {WebInspector.KeyframePropertiesSection} |
- */ |
- function updateSourceRanges(success) |
- { |
- if (!success) |
- return; |
- this._parentPane._refreshUpdate(this); |
- } |
- |
- console.assert(rule instanceof WebInspector.CSSKeyframeRule); |
- var oldRange = rule.key().range; |
- if (!oldRange) |
- return Promise.resolve(); |
- var selectedNode = this._parentPane.node(); |
- return rule.setKeyText(newContent).then(updateSourceRanges.bind(this)); |
- }, |
- |
- /** |
- * @override |
- * @param {string} propertyName |
- * @return {boolean} |
- */ |
- isPropertyInherited: function(propertyName) |
- { |
- return false; |
- }, |
- |
- /** |
- * @override |
- * @param {!WebInspector.CSSProperty} property |
- * @return {boolean} |
- */ |
- _isPropertyOverloaded: function(property) |
- { |
- return false; |
- }, |
- |
- /** |
- * @override |
- */ |
- _markSelectorHighlights: function() |
- { |
- }, |
- |
- /** |
- * @override |
- */ |
- _markSelectorMatches: function() |
- { |
- this._selectorElement.textContent = this._style.parentRule.key().text; |
- }, |
- |
- /** |
- * @override |
- */ |
- _highlight: function() |
- { |
- }, |
- |
- __proto__: WebInspector.StylePropertiesSection.prototype |
-}; |
- |
-/** |
- * @constructor |
- * @extends {TreeElement} |
- * @param {!WebInspector.StylesSidebarPane} stylesPane |
- * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
- * @param {!WebInspector.CSSProperty} property |
- * @param {boolean} isShorthand |
- * @param {boolean} inherited |
- * @param {boolean} overloaded |
- */ |
-WebInspector.StylePropertyTreeElement = function(stylesPane, matchedStyles, property, isShorthand, inherited, overloaded) |
-{ |
- // Pass an empty title, the title gets made later in onattach. |
- TreeElement.call(this, "", isShorthand); |
- this._style = property.ownerStyle; |
- this._matchedStyles = matchedStyles; |
- this.property = property; |
- this._inherited = inherited; |
- this._overloaded = overloaded; |
- this.selectable = false; |
- this._parentPane = stylesPane; |
- this.isShorthand = isShorthand; |
- this._applyStyleThrottler = new WebInspector.Throttler(0); |
-}; |
- |
-/** @typedef {{expanded: boolean, hasChildren: boolean, isEditingName: boolean, previousContent: string}} */ |
-WebInspector.StylePropertyTreeElement.Context; |
- |
-WebInspector.StylePropertyTreeElement.prototype = { |
- /** |
- * @return {boolean} |
- */ |
- _editable: function() |
- { |
- return this._style.styleSheetId && this._style.range; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- inherited: function() |
- { |
- return this._inherited; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- overloaded: function() |
- { |
- return this._overloaded; |
- }, |
- |
- /** |
- * @param {boolean} x |
- */ |
- setOverloaded: function(x) |
- { |
- if (x === this._overloaded) |
- return; |
- this._overloaded = x; |
- this._updateState(); |
- }, |
- |
- get name() |
- { |
- return this.property.name; |
- }, |
- |
- get value() |
- { |
- return this.property.value; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- _updateFilter: function() |
- { |
- var regex = this._parentPane.filterRegex(); |
- var matches = !!regex && (regex.test(this.property.name) || regex.test(this.property.value)); |
- this.listItemElement.classList.toggle("filter-match", matches); |
- |
- this.onpopulate(); |
- var hasMatchingChildren = false; |
- for (var i = 0; i < this.childCount(); ++i) |
- hasMatchingChildren |= this.childAt(i)._updateFilter(); |
- |
- if (!regex) { |
- if (this._expandedDueToFilter) |
- this.collapse(); |
- this._expandedDueToFilter = false; |
- } else if (hasMatchingChildren && !this.expanded) { |
- this.expand(); |
- this._expandedDueToFilter = true; |
- } else if (!hasMatchingChildren && this.expanded && this._expandedDueToFilter) { |
- this.collapse(); |
- this._expandedDueToFilter = false; |
- } |
- return matches; |
- }, |
- |
- /** |
- * @param {string} text |
- * @return {!Node} |
- */ |
- _processColor: function(text) |
- { |
- // We can be called with valid non-color values of |text| (like 'none' from border style) |
- var color = WebInspector.Color.parse(text); |
- if (!color) |
- return createTextNode(text); |
- |
- if (!this._editable()) { |
- var swatch = WebInspector.ColorSwatch.create(); |
- swatch.setColor(color); |
- return swatch; |
- } |
- |
- var swatchPopoverHelper = this._parentPane._swatchPopoverHelper; |
- var swatch = WebInspector.ColorSwatch.create(); |
- swatch.setColor(color); |
- swatch.setFormat(WebInspector.Color.detectColorFormat(swatch.color())); |
- var swatchIcon = new WebInspector.ColorSwatchPopoverIcon(this, swatchPopoverHelper, swatch); |
- |
- /** |
- * @param {?Array<string>} backgroundColors |
- */ |
- function computedCallback(backgroundColors) |
- { |
- // TODO(aboxhall): distinguish between !backgroundColors (no text) and |
- // !backgroundColors.length (no computed bg color) |
- if (!backgroundColors || !backgroundColors.length) |
- return; |
- // TODO(samli): figure out what to do in the case of multiple background colors (i.e. gradients) |
- var bgColorText = backgroundColors[0]; |
- var bgColor = WebInspector.Color.parse(bgColorText); |
- if (!bgColor) |
- return; |
- |
- // If we have a semi-transparent background color over an unknown |
- // background, draw the line for the "worst case" scenario: where |
- // the unknown background is the same color as the text. |
- if (bgColor.hasAlpha) { |
- var blendedRGBA = []; |
- WebInspector.Color.blendColors(bgColor.rgba(), color.rgba(), blendedRGBA); |
- bgColor = new WebInspector.Color(blendedRGBA, WebInspector.Color.Format.RGBA); |
- } |
- |
- swatchIcon.setContrastColor(bgColor); |
- } |
- |
- if (Runtime.experiments.isEnabled("colorContrastRatio") && this.property.name === "color" && this._parentPane.cssModel() && this.node()) { |
- var cssModel = this._parentPane.cssModel(); |
- cssModel.backgroundColorsPromise(this.node().id).then(computedCallback); |
- } |
- |
- return swatch; |
- }, |
- |
- /** |
- * @return {string} |
- */ |
- renderedPropertyText: function() |
- { |
- return this.nameElement.textContent + ": " + this.valueElement.textContent; |
- }, |
- |
- /** |
- * @param {string} text |
- * @return {!Node} |
- */ |
- _processBezier: function(text) |
- { |
- if (!this._editable() || !WebInspector.Geometry.CubicBezier.parse(text)) |
- return createTextNode(text); |
- var swatchPopoverHelper = this._parentPane._swatchPopoverHelper; |
- var swatch = WebInspector.BezierSwatch.create(); |
- swatch.setBezierText(text); |
- new WebInspector.BezierPopoverIcon(this, swatchPopoverHelper, swatch); |
- return swatch; |
- }, |
- |
- /** |
- * @param {string} propertyValue |
- * @param {string} propertyName |
- * @return {!Node} |
- */ |
- _processShadow: function(propertyValue, propertyName) |
- { |
- if (!this._editable()) |
- return createTextNode(propertyValue); |
- var shadows; |
- if (propertyName === "text-shadow") |
- shadows = WebInspector.CSSShadowModel.parseTextShadow(propertyValue); |
- else |
- shadows = WebInspector.CSSShadowModel.parseBoxShadow(propertyValue); |
- if (!shadows.length) |
- return createTextNode(propertyValue); |
- var container = createDocumentFragment(); |
- var swatchPopoverHelper = this._parentPane._swatchPopoverHelper; |
- for (var i = 0; i < shadows.length; i++) { |
- if (i !== 0) |
- container.appendChild(createTextNode(", ")); // Add back commas and spaces between each shadow. |
- // TODO(flandy): editing the property value should use the original value with all spaces. |
- var cssShadowSwatch = WebInspector.CSSShadowSwatch.create(); |
- cssShadowSwatch.setCSSShadow(shadows[i]); |
- new WebInspector.ShadowSwatchPopoverHelper(this, swatchPopoverHelper, cssShadowSwatch); |
- var colorSwatch = cssShadowSwatch.colorSwatch(); |
- if (colorSwatch) |
- new WebInspector.ColorSwatchPopoverIcon(this, swatchPopoverHelper, colorSwatch); |
- container.appendChild(cssShadowSwatch); |
- } |
- return container; |
- }, |
+ if (!doesSelectorAffectSelectedNode) |
+ this.propertiesTreeOutline.element.classList.add('no-affect'); |
- _updateState: function() |
- { |
- if (!this.listItemElement) |
- return; |
- |
- if (this._style.isPropertyImplicit(this.name)) |
- this.listItemElement.classList.add("implicit"); |
- else |
- this.listItemElement.classList.remove("implicit"); |
- |
- var hasIgnorableError = !this.property.parsedOk && WebInspector.StylesSidebarPane.ignoreErrorsForProperty(this.property); |
- if (hasIgnorableError) |
- this.listItemElement.classList.add("has-ignorable-error"); |
- else |
- this.listItemElement.classList.remove("has-ignorable-error"); |
- |
- if (this.inherited()) |
- this.listItemElement.classList.add("inherited"); |
- else |
- this.listItemElement.classList.remove("inherited"); |
- |
- if (this.overloaded()) |
- this.listItemElement.classList.add("overloaded"); |
- else |
- this.listItemElement.classList.remove("overloaded"); |
- |
- if (this.property.disabled) |
- this.listItemElement.classList.add("disabled"); |
- else |
- this.listItemElement.classList.remove("disabled"); |
- }, |
- |
- /** |
- * @return {?WebInspector.DOMNode} |
- */ |
- node: function() |
- { |
- return this._parentPane.node(); |
- }, |
- |
- /** |
- * @return {!WebInspector.StylesSidebarPane} |
- */ |
- parentPane: function() |
- { |
- return this._parentPane; |
- }, |
- |
- /** |
- * @return {?WebInspector.StylePropertiesSection} |
- */ |
- section: function() |
- { |
- return this.treeOutline && this.treeOutline.section; |
- }, |
- |
- _updatePane: function() |
- { |
- var section = this.section(); |
- if (section && section._parentPane) |
- section._parentPane._refreshUpdate(section); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _toggleEnabled: function(event) |
- { |
- var disabled = !event.target.checked; |
- var oldStyleRange = this._style.range; |
- if (!oldStyleRange) |
- return; |
- |
- /** |
- * @param {boolean} success |
- * @this {WebInspector.StylePropertyTreeElement} |
- */ |
- function callback(success) |
- { |
- delete this._parentPane._userOperation; |
- |
- if (!success) |
- return; |
- this._matchedStyles.resetActiveProperties(); |
- this._updatePane(); |
- this.styleTextAppliedForTest(); |
- } |
- |
- event.consume(); |
- this._parentPane._userOperation = true; |
- this.property.setDisabled(disabled) |
- .then(callback.bind(this)); |
- }, |
- |
- /** |
- * @override |
- */ |
- onpopulate: function() |
- { |
- // Only populate once and if this property is a shorthand. |
- if (this.childCount() || !this.isShorthand) |
- return; |
+ this._updateRuleOrigin(); |
+ if (this.element.parentElement) // Might have been detached already. |
+ this._moveEditorFromSelector(moveDirection); |
- var longhandProperties = this._style.longhandProperties(this.name); |
- for (var i = 0; i < longhandProperties.length; ++i) { |
- var name = longhandProperties[i].name; |
- var inherited = false; |
- var overloaded = false; |
+ delete this._parentPane._userOperation; |
+ this._editingSelectorEnded(); |
+ this._markSelectorMatches(); |
- var section = this.section(); |
- if (section) { |
- inherited = section.isPropertyInherited(name); |
- overloaded = this._matchedStyles.propertyState(longhandProperties[i]) === WebInspector.CSSMatchedStyles.PropertyState.Overloaded; |
- } |
+ this._editingSelectorCommittedForTest(); |
+ } |
- var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this._matchedStyles, longhandProperties[i], false, inherited, overloaded); |
- this.appendChild(item); |
- } |
- }, |
+ if (newContent) |
+ newContent = newContent.trim(); |
+ this._parentPane._userOperation = true; |
+ |
+ var cssModel = this._parentPane.cssModel(); |
+ var ruleText = this._rulePrefix() + newContent + ' {}'; |
+ cssModel.addRule(this._styleSheetId, ruleText, this._ruleLocation).then(onRuleAdded.bind(this)); |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ editingSelectorCancelled() { |
+ delete this._parentPane._userOperation; |
+ if (!this.isBlank) { |
+ super.editingSelectorCancelled(); |
+ return; |
+ } |
- /** |
- * @override |
- */ |
- onattach: function() |
- { |
- this.updateTitle(); |
+ this._editingSelectorEnded(); |
+ this._parentPane.removeSection(this); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.CSSRule} newRule |
+ */ |
+ _makeNormal(newRule) { |
+ this.element.classList.remove('blank-section'); |
+ this._style = newRule.style; |
+ // FIXME: replace this instance by a normal WebInspector.StylePropertiesSection. |
+ this._normal = true; |
+ } |
+}; |
- this.listItemElement.addEventListener("mousedown", this._mouseDown.bind(this)); |
- this.listItemElement.addEventListener("mouseup", this._resetMouseDownElement.bind(this)); |
- this.listItemElement.addEventListener("click", this._mouseClick.bind(this)); |
- }, |
+/** |
+ * @unrestricted |
+ */ |
+WebInspector.KeyframePropertiesSection = class extends WebInspector.StylePropertiesSection { |
+ /** |
+ * @param {!WebInspector.StylesSidebarPane} stylesPane |
+ * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
+ * @param {!WebInspector.CSSStyleDeclaration} style |
+ */ |
+ constructor(stylesPane, matchedStyles, style) { |
+ super(stylesPane, matchedStyles, style); |
+ this._selectorElement.className = 'keyframe-key'; |
+ } |
+ |
+ /** |
+ * @override |
+ * @return {string} |
+ */ |
+ _headerText() { |
+ return this._style.parentRule.key().text; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!WebInspector.CSSRule} rule |
+ * @param {string} newContent |
+ * @return {!Promise} |
+ */ |
+ _setHeaderText(rule, newContent) { |
+ /** |
+ * @param {boolean} success |
+ * @this {WebInspector.KeyframePropertiesSection} |
+ */ |
+ function updateSourceRanges(success) { |
+ if (!success) |
+ return; |
+ this._parentPane._refreshUpdate(this); |
+ } |
- /** |
- * @param {!Event} event |
- */ |
- _mouseDown: function(event) |
- { |
- if (this._parentPane) { |
- this._parentPane._mouseDownTreeElement = this; |
- this._parentPane._mouseDownTreeElementIsName = this.nameElement && this.nameElement.isSelfOrAncestor(event.target); |
- this._parentPane._mouseDownTreeElementIsValue = this.valueElement && this.valueElement.isSelfOrAncestor(event.target); |
- } |
- }, |
- |
- _resetMouseDownElement: function() |
- { |
- if (this._parentPane) { |
- delete this._parentPane._mouseDownTreeElement; |
- delete this._parentPane._mouseDownTreeElementIsName; |
- delete this._parentPane._mouseDownTreeElementIsValue; |
- } |
- }, |
- |
- updateTitle: function() |
- { |
- this._updateState(); |
- this._expandElement = createElement("span"); |
- this._expandElement.className = "expand-element"; |
- |
- var propertyRenderer = new WebInspector.StylesSidebarPropertyRenderer(this._style.parentRule, this.node(), this.name, this.value); |
- if (this.property.parsedOk) { |
- propertyRenderer.setColorHandler(this._processColor.bind(this)); |
- propertyRenderer.setBezierHandler(this._processBezier.bind(this)); |
- propertyRenderer.setShadowHandler(this._processShadow.bind(this)); |
- } |
+ console.assert(rule instanceof WebInspector.CSSKeyframeRule); |
+ var oldRange = rule.key().range; |
+ if (!oldRange) |
+ return Promise.resolve(); |
+ var selectedNode = this._parentPane.node(); |
+ return rule.setKeyText(newContent).then(updateSourceRanges.bind(this)); |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {string} propertyName |
+ * @return {boolean} |
+ */ |
+ isPropertyInherited(propertyName) { |
+ return false; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!WebInspector.CSSProperty} property |
+ * @return {boolean} |
+ */ |
+ _isPropertyOverloaded(property) { |
+ return false; |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ _markSelectorHighlights() { |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ _markSelectorMatches() { |
+ this._selectorElement.textContent = this._style.parentRule.key().text; |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ _highlight() { |
+ } |
+}; |
- this.listItemElement.removeChildren(); |
- this.nameElement = propertyRenderer.renderName(); |
- this.valueElement = propertyRenderer.renderValue(); |
- if (!this.treeOutline) |
- return; |
+/** |
+ * @unrestricted |
+ */ |
+WebInspector.StylePropertyTreeElement = class extends TreeElement { |
+ /** |
+ * @param {!WebInspector.StylesSidebarPane} stylesPane |
+ * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
+ * @param {!WebInspector.CSSProperty} property |
+ * @param {boolean} isShorthand |
+ * @param {boolean} inherited |
+ * @param {boolean} overloaded |
+ */ |
+ constructor(stylesPane, matchedStyles, property, isShorthand, inherited, overloaded) { |
+ // Pass an empty title, the title gets made later in onattach. |
+ super('', isShorthand); |
+ this._style = property.ownerStyle; |
+ this._matchedStyles = matchedStyles; |
+ this.property = property; |
+ this._inherited = inherited; |
+ this._overloaded = overloaded; |
+ this.selectable = false; |
+ this._parentPane = stylesPane; |
+ this.isShorthand = isShorthand; |
+ this._applyStyleThrottler = new WebInspector.Throttler(0); |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ _editable() { |
+ return this._style.styleSheetId && this._style.range; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ inherited() { |
+ return this._inherited; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ overloaded() { |
+ return this._overloaded; |
+ } |
+ |
+ /** |
+ * @param {boolean} x |
+ */ |
+ setOverloaded(x) { |
+ if (x === this._overloaded) |
+ return; |
+ this._overloaded = x; |
+ this._updateState(); |
+ } |
+ |
+ get name() { |
+ return this.property.name; |
+ } |
+ |
+ get value() { |
+ return this.property.value; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ _updateFilter() { |
+ var regex = this._parentPane.filterRegex(); |
+ var matches = !!regex && (regex.test(this.property.name) || regex.test(this.property.value)); |
+ this.listItemElement.classList.toggle('filter-match', matches); |
- var indent = WebInspector.moduleSetting("textEditorIndent").get(); |
- this.listItemElement.createChild("span", "styles-clipboard-only").createTextChild(indent + (this.property.disabled ? "/* " : "")); |
- this.listItemElement.appendChild(this.nameElement); |
- this.listItemElement.createTextChild(": "); |
- this.listItemElement.appendChild(this._expandElement); |
- this.listItemElement.appendChild(this.valueElement); |
- this.listItemElement.createTextChild(";"); |
- if (this.property.disabled) |
- this.listItemElement.createChild("span", "styles-clipboard-only").createTextChild(" */"); |
- |
- if (!this.property.parsedOk) { |
- // Avoid having longhands under an invalid shorthand. |
- this.listItemElement.classList.add("not-parsed-ok"); |
- |
- // Add a separate exclamation mark IMG element with a tooltip. |
- this.listItemElement.insertBefore(WebInspector.StylesSidebarPane.createExclamationMark(this.property), this.listItemElement.firstChild); |
- } |
- if (!this.property.activeInStyle()) |
- this.listItemElement.classList.add("inactive"); |
- this._updateFilter(); |
- |
- if (this.property.parsedOk && this.section() && this.parent.root) { |
- var enabledCheckboxElement = createElement("input"); |
- enabledCheckboxElement.className = "enabled-button"; |
- enabledCheckboxElement.type = "checkbox"; |
- enabledCheckboxElement.checked = !this.property.disabled; |
- enabledCheckboxElement.addEventListener("click", this._toggleEnabled.bind(this), false); |
- this.listItemElement.insertBefore(enabledCheckboxElement, this.listItemElement.firstChild); |
- } |
- }, |
+ this.onpopulate(); |
+ var hasMatchingChildren = false; |
+ for (var i = 0; i < this.childCount(); ++i) |
+ hasMatchingChildren |= this.childAt(i)._updateFilter(); |
+ |
+ if (!regex) { |
+ if (this._expandedDueToFilter) |
+ this.collapse(); |
+ this._expandedDueToFilter = false; |
+ } else if (hasMatchingChildren && !this.expanded) { |
+ this.expand(); |
+ this._expandedDueToFilter = true; |
+ } else if (!hasMatchingChildren && this.expanded && this._expandedDueToFilter) { |
+ this.collapse(); |
+ this._expandedDueToFilter = false; |
+ } |
+ return matches; |
+ } |
+ |
+ /** |
+ * @param {string} text |
+ * @return {!Node} |
+ */ |
+ _processColor(text) { |
+ // We can be called with valid non-color values of |text| (like 'none' from border style) |
+ var color = WebInspector.Color.parse(text); |
+ if (!color) |
+ return createTextNode(text); |
+ |
+ if (!this._editable()) { |
+ var swatch = WebInspector.ColorSwatch.create(); |
+ swatch.setColor(color); |
+ return swatch; |
+ } |
- /** |
- * @param {!Event} event |
- */ |
- _mouseClick: function(event) |
- { |
- if (!event.target.isComponentSelectionCollapsed()) |
- return; |
+ var swatchPopoverHelper = this._parentPane._swatchPopoverHelper; |
+ var swatch = WebInspector.ColorSwatch.create(); |
+ swatch.setColor(color); |
+ swatch.setFormat(WebInspector.Color.detectColorFormat(swatch.color())); |
+ var swatchIcon = new WebInspector.ColorSwatchPopoverIcon(this, swatchPopoverHelper, swatch); |
+ |
+ /** |
+ * @param {?Array<string>} backgroundColors |
+ */ |
+ function computedCallback(backgroundColors) { |
+ // TODO(aboxhall): distinguish between !backgroundColors (no text) and |
+ // !backgroundColors.length (no computed bg color) |
+ if (!backgroundColors || !backgroundColors.length) |
+ return; |
+ // TODO(samli): figure out what to do in the case of multiple background colors (i.e. gradients) |
+ var bgColorText = backgroundColors[0]; |
+ var bgColor = WebInspector.Color.parse(bgColorText); |
+ if (!bgColor) |
+ return; |
+ |
+ // If we have a semi-transparent background color over an unknown |
+ // background, draw the line for the "worst case" scenario: where |
+ // the unknown background is the same color as the text. |
+ if (bgColor.hasAlpha) { |
+ var blendedRGBA = []; |
+ WebInspector.Color.blendColors(bgColor.rgba(), color.rgba(), blendedRGBA); |
+ bgColor = new WebInspector.Color(blendedRGBA, WebInspector.Color.Format.RGBA); |
+ } |
+ |
+ swatchIcon.setContrastColor(bgColor); |
+ } |
- event.consume(true); |
+ if (Runtime.experiments.isEnabled('colorContrastRatio') && this.property.name === 'color' && |
+ this._parentPane.cssModel() && this.node()) { |
+ var cssModel = this._parentPane.cssModel(); |
+ cssModel.backgroundColorsPromise(this.node().id).then(computedCallback); |
+ } |
- if (event.target === this.listItemElement) { |
- var section = this.section(); |
- if (!section || !section.editable) |
- return; |
+ return swatch; |
+ } |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ renderedPropertyText() { |
+ return this.nameElement.textContent + ': ' + this.valueElement.textContent; |
+ } |
+ |
+ /** |
+ * @param {string} text |
+ * @return {!Node} |
+ */ |
+ _processBezier(text) { |
+ if (!this._editable() || !WebInspector.Geometry.CubicBezier.parse(text)) |
+ return createTextNode(text); |
+ var swatchPopoverHelper = this._parentPane._swatchPopoverHelper; |
+ var swatch = WebInspector.BezierSwatch.create(); |
+ swatch.setBezierText(text); |
+ new WebInspector.BezierPopoverIcon(this, swatchPopoverHelper, swatch); |
+ return swatch; |
+ } |
+ |
+ /** |
+ * @param {string} propertyValue |
+ * @param {string} propertyName |
+ * @return {!Node} |
+ */ |
+ _processShadow(propertyValue, propertyName) { |
+ if (!this._editable()) |
+ return createTextNode(propertyValue); |
+ var shadows; |
+ if (propertyName === 'text-shadow') |
+ shadows = WebInspector.CSSShadowModel.parseTextShadow(propertyValue); |
+ else |
+ shadows = WebInspector.CSSShadowModel.parseBoxShadow(propertyValue); |
+ if (!shadows.length) |
+ return createTextNode(propertyValue); |
+ var container = createDocumentFragment(); |
+ var swatchPopoverHelper = this._parentPane._swatchPopoverHelper; |
+ for (var i = 0; i < shadows.length; i++) { |
+ if (i !== 0) |
+ container.appendChild(createTextNode(', ')); // Add back commas and spaces between each shadow. |
+ // TODO(flandy): editing the property value should use the original value with all spaces. |
+ var cssShadowSwatch = WebInspector.CSSShadowSwatch.create(); |
+ cssShadowSwatch.setCSSShadow(shadows[i]); |
+ new WebInspector.ShadowSwatchPopoverHelper(this, swatchPopoverHelper, cssShadowSwatch); |
+ var colorSwatch = cssShadowSwatch.colorSwatch(); |
+ if (colorSwatch) |
+ new WebInspector.ColorSwatchPopoverIcon(this, swatchPopoverHelper, colorSwatch); |
+ container.appendChild(cssShadowSwatch); |
+ } |
+ return container; |
+ } |
+ |
+ _updateState() { |
+ if (!this.listItemElement) |
+ return; |
+ |
+ if (this._style.isPropertyImplicit(this.name)) |
+ this.listItemElement.classList.add('implicit'); |
+ else |
+ this.listItemElement.classList.remove('implicit'); |
+ |
+ var hasIgnorableError = |
+ !this.property.parsedOk && WebInspector.StylesSidebarPane.ignoreErrorsForProperty(this.property); |
+ if (hasIgnorableError) |
+ this.listItemElement.classList.add('has-ignorable-error'); |
+ else |
+ this.listItemElement.classList.remove('has-ignorable-error'); |
+ |
+ if (this.inherited()) |
+ this.listItemElement.classList.add('inherited'); |
+ else |
+ this.listItemElement.classList.remove('inherited'); |
+ |
+ if (this.overloaded()) |
+ this.listItemElement.classList.add('overloaded'); |
+ else |
+ this.listItemElement.classList.remove('overloaded'); |
+ |
+ if (this.property.disabled) |
+ this.listItemElement.classList.add('disabled'); |
+ else |
+ this.listItemElement.classList.remove('disabled'); |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.DOMNode} |
+ */ |
+ node() { |
+ return this._parentPane.node(); |
+ } |
+ |
+ /** |
+ * @return {!WebInspector.StylesSidebarPane} |
+ */ |
+ parentPane() { |
+ return this._parentPane; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.StylePropertiesSection} |
+ */ |
+ section() { |
+ return this.treeOutline && this.treeOutline.section; |
+ } |
+ |
+ _updatePane() { |
+ var section = this.section(); |
+ if (section && section._parentPane) |
+ section._parentPane._refreshUpdate(section); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _toggleEnabled(event) { |
+ var disabled = !event.target.checked; |
+ var oldStyleRange = this._style.range; |
+ if (!oldStyleRange) |
+ return; |
+ |
+ /** |
+ * @param {boolean} success |
+ * @this {WebInspector.StylePropertyTreeElement} |
+ */ |
+ function callback(success) { |
+ delete this._parentPane._userOperation; |
+ |
+ if (!success) |
+ return; |
+ this._matchedStyles.resetActiveProperties(); |
+ this._updatePane(); |
+ this.styleTextAppliedForTest(); |
+ } |
- if (section._checkWillCancelEditing()) |
- return; |
- section.addNewBlankProperty(this.property.index + 1).startEditing(); |
- return; |
- } |
+ event.consume(); |
+ this._parentPane._userOperation = true; |
+ this.property.setDisabled(disabled).then(callback.bind(this)); |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ onpopulate() { |
+ // Only populate once and if this property is a shorthand. |
+ if (this.childCount() || !this.isShorthand) |
+ return; |
+ |
+ var longhandProperties = this._style.longhandProperties(this.name); |
+ for (var i = 0; i < longhandProperties.length; ++i) { |
+ var name = longhandProperties[i].name; |
+ var inherited = false; |
+ var overloaded = false; |
+ |
+ var section = this.section(); |
+ if (section) { |
+ inherited = section.isPropertyInherited(name); |
+ overloaded = this._matchedStyles.propertyState(longhandProperties[i]) === |
+ WebInspector.CSSMatchedStyles.PropertyState.Overloaded; |
+ } |
+ |
+ var item = new WebInspector.StylePropertyTreeElement( |
+ this._parentPane, this._matchedStyles, longhandProperties[i], false, inherited, overloaded); |
+ this.appendChild(item); |
+ } |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ onattach() { |
+ this.updateTitle(); |
+ |
+ this.listItemElement.addEventListener('mousedown', this._mouseDown.bind(this)); |
+ this.listItemElement.addEventListener('mouseup', this._resetMouseDownElement.bind(this)); |
+ this.listItemElement.addEventListener('click', this._mouseClick.bind(this)); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _mouseDown(event) { |
+ if (this._parentPane) { |
+ this._parentPane._mouseDownTreeElement = this; |
+ this._parentPane._mouseDownTreeElementIsName = |
+ this.nameElement && this.nameElement.isSelfOrAncestor(event.target); |
+ this._parentPane._mouseDownTreeElementIsValue = |
+ this.valueElement && this.valueElement.isSelfOrAncestor(event.target); |
+ } |
+ } |
- if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */(event)) && this.section().navigable) { |
- this._navigateToSource(/** @type {!Element} */(event.target)); |
- return; |
- } |
+ _resetMouseDownElement() { |
+ if (this._parentPane) { |
+ delete this._parentPane._mouseDownTreeElement; |
+ delete this._parentPane._mouseDownTreeElementIsName; |
+ delete this._parentPane._mouseDownTreeElementIsValue; |
+ } |
+ } |
+ |
+ updateTitle() { |
+ this._updateState(); |
+ this._expandElement = createElement('span'); |
+ this._expandElement.className = 'expand-element'; |
+ |
+ var propertyRenderer = |
+ new WebInspector.StylesSidebarPropertyRenderer(this._style.parentRule, this.node(), this.name, this.value); |
+ if (this.property.parsedOk) { |
+ propertyRenderer.setColorHandler(this._processColor.bind(this)); |
+ propertyRenderer.setBezierHandler(this._processBezier.bind(this)); |
+ propertyRenderer.setShadowHandler(this._processShadow.bind(this)); |
+ } |
- this.startEditing(/** @type {!Element} */(event.target)); |
- }, |
+ this.listItemElement.removeChildren(); |
+ this.nameElement = propertyRenderer.renderName(); |
+ this.valueElement = propertyRenderer.renderValue(); |
+ if (!this.treeOutline) |
+ return; |
+ |
+ var indent = WebInspector.moduleSetting('textEditorIndent').get(); |
+ this.listItemElement.createChild('span', 'styles-clipboard-only') |
+ .createTextChild(indent + (this.property.disabled ? '/* ' : '')); |
+ this.listItemElement.appendChild(this.nameElement); |
+ this.listItemElement.createTextChild(': '); |
+ this.listItemElement.appendChild(this._expandElement); |
+ this.listItemElement.appendChild(this.valueElement); |
+ this.listItemElement.createTextChild(';'); |
+ if (this.property.disabled) |
+ this.listItemElement.createChild('span', 'styles-clipboard-only').createTextChild(' */'); |
+ |
+ if (!this.property.parsedOk) { |
+ // Avoid having longhands under an invalid shorthand. |
+ this.listItemElement.classList.add('not-parsed-ok'); |
+ |
+ // Add a separate exclamation mark IMG element with a tooltip. |
+ this.listItemElement.insertBefore( |
+ WebInspector.StylesSidebarPane.createExclamationMark(this.property), this.listItemElement.firstChild); |
+ } |
+ if (!this.property.activeInStyle()) |
+ this.listItemElement.classList.add('inactive'); |
+ this._updateFilter(); |
+ |
+ if (this.property.parsedOk && this.section() && this.parent.root) { |
+ var enabledCheckboxElement = createElement('input'); |
+ enabledCheckboxElement.className = 'enabled-button'; |
+ enabledCheckboxElement.type = 'checkbox'; |
+ enabledCheckboxElement.checked = !this.property.disabled; |
+ enabledCheckboxElement.addEventListener('click', this._toggleEnabled.bind(this), false); |
+ this.listItemElement.insertBefore(enabledCheckboxElement, this.listItemElement.firstChild); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _mouseClick(event) { |
+ if (!event.target.isComponentSelectionCollapsed()) |
+ return; |
+ |
+ event.consume(true); |
+ |
+ if (event.target === this.listItemElement) { |
+ var section = this.section(); |
+ if (!section || !section.editable) |
+ return; |
+ |
+ if (section._checkWillCancelEditing()) |
+ return; |
+ section.addNewBlankProperty(this.property.index + 1).startEditing(); |
+ return; |
+ } |
- /** |
- * @param {!Element} element |
- * @param {boolean=} omitFocus |
- */ |
- _navigateToSource: function(element, omitFocus) |
- { |
- if (!this.section().navigable) |
- return; |
- var propertyNameClicked = element === this.nameElement; |
- var uiLocation = WebInspector.cssWorkspaceBinding.propertyUILocation(this.property, propertyNameClicked); |
- if (uiLocation) |
- WebInspector.Revealer.reveal(uiLocation, omitFocus); |
- }, |
+ if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */ (event)) && |
+ this.section().navigable) { |
+ this._navigateToSource(/** @type {!Element} */ (event.target)); |
+ return; |
+ } |
- /** |
- * @param {?Element=} selectElement |
+ this.startEditing(/** @type {!Element} */ (event.target)); |
+ } |
+ |
+ /** |
+ * @param {!Element} element |
+ * @param {boolean=} omitFocus |
+ */ |
+ _navigateToSource(element, omitFocus) { |
+ if (!this.section().navigable) |
+ return; |
+ var propertyNameClicked = element === this.nameElement; |
+ var uiLocation = WebInspector.cssWorkspaceBinding.propertyUILocation(this.property, propertyNameClicked); |
+ if (uiLocation) |
+ WebInspector.Revealer.reveal(uiLocation, omitFocus); |
+ } |
+ |
+ /** |
+ * @param {?Element=} selectElement |
+ */ |
+ startEditing(selectElement) { |
+ // FIXME: we don't allow editing of longhand properties under a shorthand right now. |
+ if (this.parent.isShorthand) |
+ return; |
+ |
+ if (selectElement === this._expandElement) |
+ return; |
+ |
+ var section = this.section(); |
+ if (section && !section.editable) |
+ return; |
+ |
+ if (selectElement) |
+ selectElement = selectElement.enclosingNodeOrSelfWithClass('webkit-css-property') || |
+ selectElement.enclosingNodeOrSelfWithClass('value'); |
+ if (!selectElement) |
+ selectElement = this.nameElement; |
+ |
+ if (WebInspector.isBeingEdited(selectElement)) |
+ return; |
+ |
+ var isEditingName = selectElement === this.nameElement; |
+ if (!isEditingName) |
+ this.valueElement.textContent = restoreURLs(this.valueElement.textContent, this.value); |
+ |
+ /** |
+ * @param {string} fieldValue |
+ * @param {string} modelValue |
+ * @return {string} |
*/ |
- startEditing: function(selectElement) |
- { |
- // FIXME: we don't allow editing of longhand properties under a shorthand right now. |
- if (this.parent.isShorthand) |
- return; |
- |
- if (selectElement === this._expandElement) |
- return; |
- |
- var section = this.section(); |
- if (section && !section.editable) |
- return; |
- |
- if (selectElement) |
- selectElement = selectElement.enclosingNodeOrSelfWithClass("webkit-css-property") || selectElement.enclosingNodeOrSelfWithClass("value"); |
- if (!selectElement) |
- selectElement = this.nameElement; |
- |
- if (WebInspector.isBeingEdited(selectElement)) |
- return; |
- |
- var isEditingName = selectElement === this.nameElement; |
- if (!isEditingName) |
- this.valueElement.textContent = restoreURLs(this.valueElement.textContent, this.value); |
- |
- /** |
- * @param {string} fieldValue |
- * @param {string} modelValue |
- * @return {string} |
- */ |
- function restoreURLs(fieldValue, modelValue) |
- { |
- const urlRegex = /\b(url\([^)]*\))/g; |
- var splitFieldValue = fieldValue.split(urlRegex); |
- if (splitFieldValue.length === 1) |
- return fieldValue; |
- var modelUrlRegex = new RegExp(urlRegex); |
- for (var i = 1; i < splitFieldValue.length; i += 2) { |
- var match = modelUrlRegex.exec(modelValue); |
- if (match) |
- splitFieldValue[i] = match[0]; |
- } |
- return splitFieldValue.join(""); |
- } |
- |
- /** @type {!WebInspector.StylePropertyTreeElement.Context} */ |
- var context = { |
- expanded: this.expanded, |
- hasChildren: this.isExpandable(), |
- isEditingName: isEditingName, |
- previousContent: selectElement.textContent |
- }; |
- |
- // Lie about our children to prevent expanding on double click and to collapse shorthands. |
- this.setExpandable(false); |
- |
- if (selectElement.parentElement) |
- selectElement.parentElement.classList.add("child-editing"); |
- selectElement.textContent = selectElement.textContent; // remove color swatch and the like |
- |
- /** |
- * @param {!WebInspector.StylePropertyTreeElement.Context} context |
- * @param {!Event} event |
- * @this {WebInspector.StylePropertyTreeElement} |
- */ |
- function pasteHandler(context, event) |
- { |
- var data = event.clipboardData.getData("Text"); |
- if (!data) |
- return; |
- var colonIdx = data.indexOf(":"); |
- if (colonIdx < 0) |
- return; |
- var name = data.substring(0, colonIdx).trim(); |
- var value = data.substring(colonIdx + 1).trim(); |
- |
- event.preventDefault(); |
- |
- if (!("originalName" in context)) { |
- context.originalName = this.nameElement.textContent; |
- context.originalValue = this.valueElement.textContent; |
- } |
- this.property.name = name; |
- this.property.value = value; |
- this.nameElement.textContent = name; |
- this.valueElement.textContent = value; |
- this.nameElement.normalize(); |
- this.valueElement.normalize(); |
- |
- this._editingCommitted(event.target.textContent, context, "forward"); |
- } |
- |
- /** |
- * @param {!WebInspector.StylePropertyTreeElement.Context} context |
- * @param {!Event} event |
- * @this {WebInspector.StylePropertyTreeElement} |
- */ |
- function blurListener(context, event) |
- { |
- var treeElement = this._parentPane._mouseDownTreeElement; |
- var moveDirection = ""; |
- if (treeElement === this) { |
- if (isEditingName && this._parentPane._mouseDownTreeElementIsValue) |
- moveDirection = "forward"; |
- if (!isEditingName && this._parentPane._mouseDownTreeElementIsName) |
- moveDirection = "backward"; |
- } |
- var text = event.target.textContent; |
- if (!context.isEditingName) |
- text = this.value || text; |
- this._editingCommitted(text, context, moveDirection); |
- } |
- |
- this._originalPropertyText = this.property.propertyText; |
- |
- this._parentPane.setEditingStyle(true); |
- if (selectElement.parentElement) |
- selectElement.parentElement.scrollIntoViewIfNeeded(false); |
+ function restoreURLs(fieldValue, modelValue) { |
+ const urlRegex = /\b(url\([^)]*\))/g; |
+ var splitFieldValue = fieldValue.split(urlRegex); |
+ if (splitFieldValue.length === 1) |
+ return fieldValue; |
+ var modelUrlRegex = new RegExp(urlRegex); |
+ for (var i = 1; i < splitFieldValue.length; i += 2) { |
+ var match = modelUrlRegex.exec(modelValue); |
+ if (match) |
+ splitFieldValue[i] = match[0]; |
+ } |
+ return splitFieldValue.join(''); |
+ } |
- var applyItemCallback = !isEditingName ? this._applyFreeFlowStyleTextEdit.bind(this) : undefined; |
- var cssCompletions = isEditingName ? WebInspector.cssMetadata().allProperties() : WebInspector.cssMetadata().propertyValues(this.nameElement.textContent); |
- this._prompt = new WebInspector.StylesSidebarPane.CSSPropertyPrompt(cssCompletions, this, isEditingName); |
- this._prompt.setAutocompletionTimeout(0); |
- if (applyItemCallback) { |
- this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemApplied, applyItemCallback, this); |
- this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemAccepted, applyItemCallback, this); |
- } |
- var proxyElement = this._prompt.attachAndStartEditing(selectElement, blurListener.bind(this, context)); |
- this._navigateToSource(selectElement, true); |
+ /** @type {!WebInspector.StylePropertyTreeElement.Context} */ |
+ var context = { |
+ expanded: this.expanded, |
+ hasChildren: this.isExpandable(), |
+ isEditingName: isEditingName, |
+ previousContent: selectElement.textContent |
+ }; |
- proxyElement.addEventListener("keydown", this._editingNameValueKeyDown.bind(this, context), false); |
- proxyElement.addEventListener("keypress", this._editingNameValueKeyPress.bind(this, context), false); |
- proxyElement.addEventListener("input", this._editingNameValueInput.bind(this, context), false); |
- if (isEditingName) |
- proxyElement.addEventListener("paste", pasteHandler.bind(this, context), false); |
+ // Lie about our children to prevent expanding on double click and to collapse shorthands. |
+ this.setExpandable(false); |
- selectElement.getComponentSelection().setBaseAndExtent(selectElement, 0, selectElement, 1); |
- }, |
+ if (selectElement.parentElement) |
+ selectElement.parentElement.classList.add('child-editing'); |
+ selectElement.textContent = selectElement.textContent; // remove color swatch and the like |
/** |
* @param {!WebInspector.StylePropertyTreeElement.Context} context |
* @param {!Event} event |
- */ |
- _editingNameValueKeyDown: function(context, event) |
- { |
- if (event.handled) |
- return; |
- |
- var result; |
- |
- if (isEnterKey(event)) { |
- event.preventDefault(); |
- result = "forward"; |
- } else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.key === "Escape") |
- result = "cancel"; |
- else if (!context.isEditingName && this._newProperty && event.keyCode === WebInspector.KeyboardShortcut.Keys.Backspace.code) { |
- // For a new property, when Backspace is pressed at the beginning of new property value, move back to the property name. |
- var selection = event.target.getComponentSelection(); |
- if (selection.isCollapsed && !selection.focusOffset) { |
- event.preventDefault(); |
- result = "backward"; |
- } |
- } else if (event.key === "Tab") { |
- result = event.shiftKey ? "backward" : "forward"; |
- event.preventDefault(); |
- } |
- |
- if (result) { |
- switch (result) { |
- case "cancel": |
- this.editingCancelled(null, context); |
- break; |
- case "forward": |
- case "backward": |
- this._editingCommitted(event.target.textContent, context, result); |
- break; |
- } |
- |
- event.consume(); |
- return; |
- } |
- }, |
+ * @this {WebInspector.StylePropertyTreeElement} |
+ */ |
+ function pasteHandler(context, event) { |
+ var data = event.clipboardData.getData('Text'); |
+ if (!data) |
+ return; |
+ var colonIdx = data.indexOf(':'); |
+ if (colonIdx < 0) |
+ return; |
+ var name = data.substring(0, colonIdx).trim(); |
+ var value = data.substring(colonIdx + 1).trim(); |
+ |
+ event.preventDefault(); |
+ |
+ if (!('originalName' in context)) { |
+ context.originalName = this.nameElement.textContent; |
+ context.originalValue = this.valueElement.textContent; |
+ } |
+ this.property.name = name; |
+ this.property.value = value; |
+ this.nameElement.textContent = name; |
+ this.valueElement.textContent = value; |
+ this.nameElement.normalize(); |
+ this.valueElement.normalize(); |
+ |
+ this._editingCommitted(event.target.textContent, context, 'forward'); |
+ } |
/** |
* @param {!WebInspector.StylePropertyTreeElement.Context} context |
* @param {!Event} event |
- */ |
- _editingNameValueKeyPress: function(context, event) |
- { |
- /** |
- * @param {string} text |
- * @param {number} cursorPosition |
- * @return {boolean} |
- */ |
- function shouldCommitValueSemicolon(text, cursorPosition) |
- { |
- // FIXME: should this account for semicolons inside comments? |
- var openQuote = ""; |
- for (var i = 0; i < cursorPosition; ++i) { |
- var ch = text[i]; |
- if (ch === "\\" && openQuote !== "") |
- ++i; // skip next character inside string |
- else if (!openQuote && (ch === "\"" || ch === "'")) |
- openQuote = ch; |
- else if (openQuote === ch) |
- openQuote = ""; |
- } |
- return !openQuote; |
- } |
- |
- var keyChar = String.fromCharCode(event.charCode); |
- var isFieldInputTerminated = (context.isEditingName ? keyChar === ":" : keyChar === ";" && shouldCommitValueSemicolon(event.target.textContent, event.target.selectionLeftOffset())); |
- if (isFieldInputTerminated) { |
- // Enter or colon (for name)/semicolon outside of string (for value). |
- event.consume(true); |
- this._editingCommitted(event.target.textContent, context, "forward"); |
- return; |
- } |
- }, |
+ * @this {WebInspector.StylePropertyTreeElement} |
+ */ |
+ function blurListener(context, event) { |
+ var treeElement = this._parentPane._mouseDownTreeElement; |
+ var moveDirection = ''; |
+ if (treeElement === this) { |
+ if (isEditingName && this._parentPane._mouseDownTreeElementIsValue) |
+ moveDirection = 'forward'; |
+ if (!isEditingName && this._parentPane._mouseDownTreeElementIsName) |
+ moveDirection = 'backward'; |
+ } |
+ var text = event.target.textContent; |
+ if (!context.isEditingName) |
+ text = this.value || text; |
+ this._editingCommitted(text, context, moveDirection); |
+ } |
- /** |
- * @param {!WebInspector.StylePropertyTreeElement.Context} context |
- * @param {!Event} event |
- */ |
- _editingNameValueInput: function(context, event) |
- { |
- // Do not live-edit "content" property of pseudo elements. crbug.com/433889 |
- if (!context.isEditingName && (!this._parentPane.node().pseudoType() || this.name !== "content")) |
- this._applyFreeFlowStyleTextEdit(); |
- }, |
- |
- _applyFreeFlowStyleTextEdit: function() |
- { |
- var valueText = this.valueElement.textContent; |
- if (valueText.indexOf(";") === -1) |
- this.applyStyleText(this.nameElement.textContent + ": " + valueText, false); |
- }, |
- |
- kickFreeFlowStyleEditForTest: function() |
- { |
- this._applyFreeFlowStyleTextEdit(); |
- }, |
+ this._originalPropertyText = this.property.propertyText; |
- /** |
- * @param {!WebInspector.StylePropertyTreeElement.Context} context |
- */ |
- editingEnded: function(context) |
- { |
- this._resetMouseDownElement(); |
+ this._parentPane.setEditingStyle(true); |
+ if (selectElement.parentElement) |
+ selectElement.parentElement.scrollIntoViewIfNeeded(false); |
- this.setExpandable(context.hasChildren); |
- if (context.expanded) |
- this.expand(); |
- var editedElement = context.isEditingName ? this.nameElement : this.valueElement; |
- // The proxyElement has been deleted, no need to remove listener. |
- if (editedElement.parentElement) |
- editedElement.parentElement.classList.remove("child-editing"); |
+ var applyItemCallback = !isEditingName ? this._applyFreeFlowStyleTextEdit.bind(this) : undefined; |
+ var cssCompletions = isEditingName ? WebInspector.cssMetadata().allProperties() : |
+ WebInspector.cssMetadata().propertyValues(this.nameElement.textContent); |
+ this._prompt = new WebInspector.StylesSidebarPane.CSSPropertyPrompt(cssCompletions, this, isEditingName); |
+ this._prompt.setAutocompletionTimeout(0); |
+ if (applyItemCallback) { |
+ this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemApplied, applyItemCallback, this); |
+ this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemAccepted, applyItemCallback, this); |
+ } |
+ var proxyElement = this._prompt.attachAndStartEditing(selectElement, blurListener.bind(this, context)); |
+ this._navigateToSource(selectElement, true); |
+ |
+ proxyElement.addEventListener('keydown', this._editingNameValueKeyDown.bind(this, context), false); |
+ proxyElement.addEventListener('keypress', this._editingNameValueKeyPress.bind(this, context), false); |
+ proxyElement.addEventListener('input', this._editingNameValueInput.bind(this, context), false); |
+ if (isEditingName) |
+ proxyElement.addEventListener('paste', pasteHandler.bind(this, context), false); |
+ |
+ selectElement.getComponentSelection().setBaseAndExtent(selectElement, 0, selectElement, 1); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ * @param {!Event} event |
+ */ |
+ _editingNameValueKeyDown(context, event) { |
+ if (event.handled) |
+ return; |
+ |
+ var result; |
+ |
+ if (isEnterKey(event)) { |
+ event.preventDefault(); |
+ result = 'forward'; |
+ } else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.key === 'Escape') |
+ result = 'cancel'; |
+ else if ( |
+ !context.isEditingName && this._newProperty && |
+ event.keyCode === WebInspector.KeyboardShortcut.Keys.Backspace.code) { |
+ // For a new property, when Backspace is pressed at the beginning of new property value, move back to the property name. |
+ var selection = event.target.getComponentSelection(); |
+ if (selection.isCollapsed && !selection.focusOffset) { |
+ event.preventDefault(); |
+ result = 'backward'; |
+ } |
+ } else if (event.key === 'Tab') { |
+ result = event.shiftKey ? 'backward' : 'forward'; |
+ event.preventDefault(); |
+ } |
- this._parentPane.setEditingStyle(false); |
- }, |
+ if (result) { |
+ switch (result) { |
+ case 'cancel': |
+ this.editingCancelled(null, context); |
+ break; |
+ case 'forward': |
+ case 'backward': |
+ this._editingCommitted(event.target.textContent, context, result); |
+ break; |
+ } |
+ |
+ event.consume(); |
+ return; |
+ } |
+ } |
+ /** |
+ * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ * @param {!Event} event |
+ */ |
+ _editingNameValueKeyPress(context, event) { |
/** |
- * @param {?Element} element |
- * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ * @param {string} text |
+ * @param {number} cursorPosition |
+ * @return {boolean} |
*/ |
- editingCancelled: function(element, context) |
- { |
- this._removePrompt(); |
- this._revertStyleUponEditingCanceled(); |
- // This should happen last, as it clears the info necessary to restore the property value after [Page]Up/Down changes. |
- this.editingEnded(context); |
- }, |
- |
- _revertStyleUponEditingCanceled: function() |
- { |
- if (this._propertyHasBeenEditedIncrementally) { |
- this.applyStyleText(this._originalPropertyText, false); |
- delete this._originalPropertyText; |
- } else if (this._newProperty) { |
- this.treeOutline.removeChild(this); |
- } else { |
- this.updateTitle(); |
- } |
- }, |
+ function shouldCommitValueSemicolon(text, cursorPosition) { |
+ // FIXME: should this account for semicolons inside comments? |
+ var openQuote = ''; |
+ for (var i = 0; i < cursorPosition; ++i) { |
+ var ch = text[i]; |
+ if (ch === '\\' && openQuote !== '') |
+ ++i; // skip next character inside string |
+ else if (!openQuote && (ch === '"' || ch === '\'')) |
+ openQuote = ch; |
+ else if (openQuote === ch) |
+ openQuote = ''; |
+ } |
+ return !openQuote; |
+ } |
- /** |
- * @param {string} moveDirection |
- * @return {?WebInspector.StylePropertyTreeElement} |
- */ |
- _findSibling: function(moveDirection) |
- { |
- var target = this; |
- do { |
- target = (moveDirection === "forward" ? target.nextSibling : target.previousSibling); |
- } while (target && target.inherited()); |
+ var keyChar = String.fromCharCode(event.charCode); |
+ var isFieldInputTerminated = |
+ (context.isEditingName ? keyChar === ':' : |
+ keyChar === ';' && |
+ shouldCommitValueSemicolon(event.target.textContent, event.target.selectionLeftOffset())); |
+ if (isFieldInputTerminated) { |
+ // Enter or colon (for name)/semicolon outside of string (for value). |
+ event.consume(true); |
+ this._editingCommitted(event.target.textContent, context, 'forward'); |
+ return; |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ * @param {!Event} event |
+ */ |
+ _editingNameValueInput(context, event) { |
+ // Do not live-edit "content" property of pseudo elements. crbug.com/433889 |
+ if (!context.isEditingName && (!this._parentPane.node().pseudoType() || this.name !== 'content')) |
+ this._applyFreeFlowStyleTextEdit(); |
+ } |
+ |
+ _applyFreeFlowStyleTextEdit() { |
+ var valueText = this.valueElement.textContent; |
+ if (valueText.indexOf(';') === -1) |
+ this.applyStyleText(this.nameElement.textContent + ': ' + valueText, false); |
+ } |
+ |
+ kickFreeFlowStyleEditForTest() { |
+ this._applyFreeFlowStyleTextEdit(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ */ |
+ editingEnded(context) { |
+ this._resetMouseDownElement(); |
+ |
+ this.setExpandable(context.hasChildren); |
+ if (context.expanded) |
+ this.expand(); |
+ var editedElement = context.isEditingName ? this.nameElement : this.valueElement; |
+ // The proxyElement has been deleted, no need to remove listener. |
+ if (editedElement.parentElement) |
+ editedElement.parentElement.classList.remove('child-editing'); |
+ |
+ this._parentPane.setEditingStyle(false); |
+ } |
+ |
+ /** |
+ * @param {?Element} element |
+ * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ */ |
+ editingCancelled(element, context) { |
+ this._removePrompt(); |
+ this._revertStyleUponEditingCanceled(); |
+ // This should happen last, as it clears the info necessary to restore the property value after [Page]Up/Down changes. |
+ this.editingEnded(context); |
+ } |
+ |
+ _revertStyleUponEditingCanceled() { |
+ if (this._propertyHasBeenEditedIncrementally) { |
+ this.applyStyleText(this._originalPropertyText, false); |
+ delete this._originalPropertyText; |
+ } else if (this._newProperty) { |
+ this.treeOutline.removeChild(this); |
+ } else { |
+ this.updateTitle(); |
+ } |
+ } |
+ |
+ /** |
+ * @param {string} moveDirection |
+ * @return {?WebInspector.StylePropertyTreeElement} |
+ */ |
+ _findSibling(moveDirection) { |
+ var target = this; |
+ do { |
+ target = (moveDirection === 'forward' ? target.nextSibling : target.previousSibling); |
+ } while (target && target.inherited()); |
+ |
+ return target; |
+ } |
+ |
+ /** |
+ * @param {string} userInput |
+ * @param {!WebInspector.StylePropertyTreeElement.Context} context |
+ * @param {string} moveDirection |
+ */ |
+ _editingCommitted(userInput, context, moveDirection) { |
+ this._removePrompt(); |
+ this.editingEnded(context); |
+ var isEditingName = context.isEditingName; |
+ |
+ // Determine where to move to before making changes |
+ var createNewProperty, moveToPropertyName, moveToSelector; |
+ var isDataPasted = 'originalName' in context; |
+ var isDirtyViaPaste = isDataPasted && (this.nameElement.textContent !== context.originalName || |
+ this.valueElement.textContent !== context.originalValue); |
+ var isPropertySplitPaste = isDataPasted && isEditingName && this.valueElement.textContent !== context.originalValue; |
+ var moveTo = this; |
+ var moveToOther = (isEditingName ^ (moveDirection === 'forward')); |
+ var abandonNewProperty = this._newProperty && !userInput && (moveToOther || isEditingName); |
+ if (moveDirection === 'forward' && (!isEditingName || isPropertySplitPaste) || |
+ moveDirection === 'backward' && isEditingName) { |
+ moveTo = moveTo._findSibling(moveDirection); |
+ if (moveTo) |
+ moveToPropertyName = moveTo.name; |
+ else if (moveDirection === 'forward' && (!this._newProperty || userInput)) |
+ createNewProperty = true; |
+ else if (moveDirection === 'backward') |
+ moveToSelector = true; |
+ } |
- return target; |
- }, |
+ // Make the Changes and trigger the moveToNextCallback after updating. |
+ var moveToIndex = moveTo && this.treeOutline ? this.treeOutline.rootElement().indexOfChild(moveTo) : -1; |
+ var blankInput = userInput.isWhitespace(); |
+ var shouldCommitNewProperty = this._newProperty && |
+ (isPropertySplitPaste || moveToOther || (!moveDirection && !isEditingName) || (isEditingName && blankInput)); |
+ var section = /** @type {!WebInspector.StylePropertiesSection} */ (this.section()); |
+ if (((userInput !== context.previousContent || isDirtyViaPaste) && !this._newProperty) || shouldCommitNewProperty) { |
+ section._afterUpdate = moveToNextCallback.bind(this, this._newProperty, !blankInput, section); |
+ var propertyText; |
+ if (blankInput || (this._newProperty && this.valueElement.textContent.isWhitespace())) |
+ propertyText = ''; |
+ else { |
+ if (isEditingName) |
+ propertyText = userInput + ': ' + this.property.value; |
+ else |
+ propertyText = this.property.name + ': ' + userInput; |
+ } |
+ this.applyStyleText(propertyText, true); |
+ } else { |
+ if (isEditingName) |
+ this.property.name = userInput; |
+ else |
+ this.property.value = userInput; |
+ if (!isDataPasted && !this._newProperty) |
+ this.updateTitle(); |
+ moveToNextCallback.call(this, this._newProperty, false, section); |
+ } |
/** |
- * @param {string} userInput |
- * @param {!WebInspector.StylePropertyTreeElement.Context} context |
- * @param {string} moveDirection |
- */ |
- _editingCommitted: function(userInput, context, moveDirection) |
- { |
- this._removePrompt(); |
- this.editingEnded(context); |
- var isEditingName = context.isEditingName; |
- |
- // Determine where to move to before making changes |
- var createNewProperty, moveToPropertyName, moveToSelector; |
- var isDataPasted = "originalName" in context; |
- var isDirtyViaPaste = isDataPasted && (this.nameElement.textContent !== context.originalName || this.valueElement.textContent !== context.originalValue); |
- var isPropertySplitPaste = isDataPasted && isEditingName && this.valueElement.textContent !== context.originalValue; |
- var moveTo = this; |
- var moveToOther = (isEditingName ^ (moveDirection === "forward")); |
- var abandonNewProperty = this._newProperty && !userInput && (moveToOther || isEditingName); |
- if (moveDirection === "forward" && (!isEditingName || isPropertySplitPaste) || moveDirection === "backward" && isEditingName) { |
- moveTo = moveTo._findSibling(moveDirection); |
- if (moveTo) |
- moveToPropertyName = moveTo.name; |
- else if (moveDirection === "forward" && (!this._newProperty || userInput)) |
- createNewProperty = true; |
- else if (moveDirection === "backward") |
- moveToSelector = true; |
- } |
- |
- // Make the Changes and trigger the moveToNextCallback after updating. |
- var moveToIndex = moveTo && this.treeOutline ? this.treeOutline.rootElement().indexOfChild(moveTo) : -1; |
- var blankInput = userInput.isWhitespace(); |
- var shouldCommitNewProperty = this._newProperty && (isPropertySplitPaste || moveToOther || (!moveDirection && !isEditingName) || (isEditingName && blankInput)); |
- var section = /** @type {!WebInspector.StylePropertiesSection} */(this.section()); |
- if (((userInput !== context.previousContent || isDirtyViaPaste) && !this._newProperty) || shouldCommitNewProperty) { |
- section._afterUpdate = moveToNextCallback.bind(this, this._newProperty, !blankInput, section); |
- var propertyText; |
- if (blankInput || (this._newProperty && this.valueElement.textContent.isWhitespace())) |
- propertyText = ""; |
- else { |
- if (isEditingName) |
- propertyText = userInput + ": " + this.property.value; |
- else |
- propertyText = this.property.name + ": " + userInput; |
- } |
- this.applyStyleText(propertyText, true); |
- } else { |
- if (isEditingName) |
- this.property.name = userInput; |
- else |
- this.property.value = userInput; |
- if (!isDataPasted && !this._newProperty) |
- this.updateTitle(); |
- moveToNextCallback.call(this, this._newProperty, false, section); |
- } |
- |
- /** |
- * The Callback to start editing the next/previous property/selector. |
- * @param {boolean} alreadyNew |
- * @param {boolean} valueChanged |
- * @param {!WebInspector.StylePropertiesSection} section |
- * @this {WebInspector.StylePropertyTreeElement} |
- */ |
- function moveToNextCallback(alreadyNew, valueChanged, section) |
- { |
- if (!moveDirection) |
- return; |
- |
- // User just tabbed through without changes. |
- if (moveTo && moveTo.parent) { |
- moveTo.startEditing(!isEditingName ? moveTo.nameElement : moveTo.valueElement); |
- return; |
- } |
- |
- // User has made a change then tabbed, wiping all the original treeElements. |
- // Recalculate the new treeElement for the same property we were going to edit next. |
- if (moveTo && !moveTo.parent) { |
- var rootElement = section.propertiesTreeOutline.rootElement(); |
- if (moveDirection === "forward" && blankInput && !isEditingName) |
- --moveToIndex; |
- if (moveToIndex >= rootElement.childCount() && !this._newProperty) |
- createNewProperty = true; |
- else { |
- var treeElement = moveToIndex >= 0 ? rootElement.childAt(moveToIndex) : null; |
- if (treeElement) { |
- var elementToEdit = !isEditingName || isPropertySplitPaste ? treeElement.nameElement : treeElement.valueElement; |
- if (alreadyNew && blankInput) |
- elementToEdit = moveDirection === "forward" ? treeElement.nameElement : treeElement.valueElement; |
- treeElement.startEditing(elementToEdit); |
- return; |
- } else if (!alreadyNew) |
- moveToSelector = true; |
- } |
- } |
- |
- // Create a new attribute in this section (or move to next editable selector if possible). |
- if (createNewProperty) { |
- if (alreadyNew && !valueChanged && (isEditingName ^ (moveDirection === "backward"))) |
- return; |
- |
- section.addNewBlankProperty().startEditing(); |
- return; |
- } |
- |
- if (abandonNewProperty) { |
- moveTo = this._findSibling(moveDirection); |
- var sectionToEdit = (moveTo || moveDirection === "backward") ? section : section.nextEditableSibling(); |
- if (sectionToEdit) { |
- if (sectionToEdit.style().parentRule) |
- sectionToEdit.startEditingSelector(); |
- else |
- sectionToEdit._moveEditorFromSelector(moveDirection); |
- } |
- return; |
- } |
- |
- if (moveToSelector) { |
- if (section.style().parentRule) |
- section.startEditingSelector(); |
- else |
- section._moveEditorFromSelector(moveDirection); |
- } |
- } |
- }, |
- |
- _removePrompt: function() |
- { |
- // BUG 53242. This cannot go into editingEnded(), as it should always happen first for any editing outcome. |
- if (this._prompt) { |
- this._prompt.detach(); |
- delete this._prompt; |
- } |
- }, |
+ * The Callback to start editing the next/previous property/selector. |
+ * @param {boolean} alreadyNew |
+ * @param {boolean} valueChanged |
+ * @param {!WebInspector.StylePropertiesSection} section |
+ * @this {WebInspector.StylePropertyTreeElement} |
+ */ |
+ function moveToNextCallback(alreadyNew, valueChanged, section) { |
+ if (!moveDirection) |
+ return; |
+ |
+ // User just tabbed through without changes. |
+ if (moveTo && moveTo.parent) { |
+ moveTo.startEditing(!isEditingName ? moveTo.nameElement : moveTo.valueElement); |
+ return; |
+ } |
+ |
+ // User has made a change then tabbed, wiping all the original treeElements. |
+ // Recalculate the new treeElement for the same property we were going to edit next. |
+ if (moveTo && !moveTo.parent) { |
+ var rootElement = section.propertiesTreeOutline.rootElement(); |
+ if (moveDirection === 'forward' && blankInput && !isEditingName) |
+ --moveToIndex; |
+ if (moveToIndex >= rootElement.childCount() && !this._newProperty) |
+ createNewProperty = true; |
+ else { |
+ var treeElement = moveToIndex >= 0 ? rootElement.childAt(moveToIndex) : null; |
+ if (treeElement) { |
+ var elementToEdit = |
+ !isEditingName || isPropertySplitPaste ? treeElement.nameElement : treeElement.valueElement; |
+ if (alreadyNew && blankInput) |
+ elementToEdit = moveDirection === 'forward' ? treeElement.nameElement : treeElement.valueElement; |
+ treeElement.startEditing(elementToEdit); |
+ return; |
+ } else if (!alreadyNew) |
+ moveToSelector = true; |
+ } |
+ } |
+ |
+ // Create a new attribute in this section (or move to next editable selector if possible). |
+ if (createNewProperty) { |
+ if (alreadyNew && !valueChanged && (isEditingName ^ (moveDirection === 'backward'))) |
+ return; |
+ |
+ section.addNewBlankProperty().startEditing(); |
+ return; |
+ } |
+ |
+ if (abandonNewProperty) { |
+ moveTo = this._findSibling(moveDirection); |
+ var sectionToEdit = (moveTo || moveDirection === 'backward') ? section : section.nextEditableSibling(); |
+ if (sectionToEdit) { |
+ if (sectionToEdit.style().parentRule) |
+ sectionToEdit.startEditingSelector(); |
+ else |
+ sectionToEdit._moveEditorFromSelector(moveDirection); |
+ } |
+ return; |
+ } |
+ |
+ if (moveToSelector) { |
+ if (section.style().parentRule) |
+ section.startEditingSelector(); |
+ else |
+ section._moveEditorFromSelector(moveDirection); |
+ } |
+ } |
+ } |
- styleTextAppliedForTest: function() { }, |
+ _removePrompt() { |
+ // BUG 53242. This cannot go into editingEnded(), as it should always happen first for any editing outcome. |
+ if (this._prompt) { |
+ this._prompt.detach(); |
+ delete this._prompt; |
+ } |
+ } |
+ |
+ styleTextAppliedForTest() { |
+ } |
+ |
+ /** |
+ * @param {string} styleText |
+ * @param {boolean} majorChange |
+ */ |
+ applyStyleText(styleText, majorChange) { |
+ this._applyStyleThrottler.schedule(this._innerApplyStyleText.bind(this, styleText, majorChange)); |
+ } |
+ |
+ /** |
+ * @param {string} styleText |
+ * @param {boolean} majorChange |
+ * @return {!Promise.<undefined>} |
+ */ |
+ _innerApplyStyleText(styleText, majorChange) { |
+ if (!this.treeOutline) |
+ return Promise.resolve(); |
+ |
+ var oldStyleRange = this._style.range; |
+ if (!oldStyleRange) |
+ return Promise.resolve(); |
+ |
+ styleText = styleText.replace(/\s/g, ' ').trim(); // Replace with whitespace. |
+ if (!styleText.length && majorChange && this._newProperty && !this._propertyHasBeenEditedIncrementally) { |
+ // The user deleted everything and never applied a new property value via Up/Down scrolling/live editing, so remove the tree element and update. |
+ var section = this.section(); |
+ this.parent.removeChild(this); |
+ section.afterUpdate(); |
+ return Promise.resolve(); |
+ } |
- /** |
- * @param {string} styleText |
- * @param {boolean} majorChange |
- */ |
- applyStyleText: function(styleText, majorChange) |
- { |
- this._applyStyleThrottler.schedule(this._innerApplyStyleText.bind(this, styleText, majorChange)); |
- }, |
+ var currentNode = this._parentPane.node(); |
+ this._parentPane._userOperation = true; |
/** |
- * @param {string} styleText |
- * @param {boolean} majorChange |
- * @return {!Promise.<undefined>} |
+ * @param {boolean} success |
+ * @this {WebInspector.StylePropertyTreeElement} |
*/ |
- _innerApplyStyleText: function(styleText, majorChange) |
- { |
- if (!this.treeOutline) |
- return Promise.resolve(); |
- |
- var oldStyleRange = this._style.range; |
- if (!oldStyleRange) |
- return Promise.resolve(); |
- |
- styleText = styleText.replace(/\s/g, " ").trim(); // Replace with whitespace. |
- if (!styleText.length && majorChange && this._newProperty && !this._propertyHasBeenEditedIncrementally) { |
- // The user deleted everything and never applied a new property value via Up/Down scrolling/live editing, so remove the tree element and update. |
- var section = this.section(); |
- this.parent.removeChild(this); |
- section.afterUpdate(); |
- return Promise.resolve(); |
- } |
+ function callback(success) { |
+ delete this._parentPane._userOperation; |
- var currentNode = this._parentPane.node(); |
- this._parentPane._userOperation = true; |
- |
- /** |
- * @param {boolean} success |
- * @this {WebInspector.StylePropertyTreeElement} |
- */ |
- function callback(success) |
- { |
- delete this._parentPane._userOperation; |
- |
- if (!success) { |
- if (majorChange) { |
- // It did not apply, cancel editing. |
- this._revertStyleUponEditingCanceled(); |
- } |
- this.styleTextAppliedForTest(); |
- return; |
- } |
- |
- this._matchedStyles.resetActiveProperties(); |
- this._propertyHasBeenEditedIncrementally = true; |
- this.property = this._style.propertyAt(this.property.index); |
- |
- // We are happy to update UI if user is not editing. |
- if (!this._parentPane._isEditingStyle && currentNode === this.node()) |
- this._updatePane(); |
- |
- this.styleTextAppliedForTest(); |
+ if (!success) { |
+ if (majorChange) { |
+ // It did not apply, cancel editing. |
+ this._revertStyleUponEditingCanceled(); |
} |
+ this.styleTextAppliedForTest(); |
+ return; |
+ } |
- // Append a ";" if the new text does not end in ";". |
- // FIXME: this does not handle trailing comments. |
- if (styleText.length && !/;\s*$/.test(styleText)) |
- styleText += ";"; |
- var overwriteProperty = !this._newProperty || this._propertyHasBeenEditedIncrementally; |
- return this.property.setText(styleText, majorChange, overwriteProperty) |
- .then(callback.bind(this)); |
- }, |
+ this._matchedStyles.resetActiveProperties(); |
+ this._propertyHasBeenEditedIncrementally = true; |
+ this.property = this._style.propertyAt(this.property.index); |
- /** |
- * @override |
- * @return {boolean} |
- */ |
- ondblclick: function() |
- { |
- return true; // handled |
- }, |
+ // We are happy to update UI if user is not editing. |
+ if (!this._parentPane._isEditingStyle && currentNode === this.node()) |
+ this._updatePane(); |
- /** |
- * @override |
- * @param {!Event} event |
- * @return {boolean} |
- */ |
- isEventWithinDisclosureTriangle: function(event) |
- { |
- return event.target === this._expandElement; |
- }, |
+ this.styleTextAppliedForTest(); |
+ } |
- __proto__: TreeElement.prototype |
+ // Append a ";" if the new text does not end in ";". |
+ // FIXME: this does not handle trailing comments. |
+ if (styleText.length && !/;\s*$/.test(styleText)) |
+ styleText += ';'; |
+ var overwriteProperty = !this._newProperty || this._propertyHasBeenEditedIncrementally; |
+ return this.property.setText(styleText, majorChange, overwriteProperty).then(callback.bind(this)); |
+ } |
+ |
+ /** |
+ * @override |
+ * @return {boolean} |
+ */ |
+ ondblclick() { |
+ return true; // handled |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!Event} event |
+ * @return {boolean} |
+ */ |
+ isEventWithinDisclosureTriangle(event) { |
+ return event.target === this._expandElement; |
+ } |
}; |
+/** @typedef {{expanded: boolean, hasChildren: boolean, isEditingName: boolean, previousContent: string}} */ |
+WebInspector.StylePropertyTreeElement.Context; |
+ |
/** |
- * @constructor |
- * @extends {WebInspector.TextPrompt} |
- * @param {!Array<string>} cssCompletions |
- * @param {!WebInspector.StylePropertyTreeElement} treeElement |
- * @param {boolean} isEditingName |
+ * @unrestricted |
*/ |
-WebInspector.StylesSidebarPane.CSSPropertyPrompt = function(cssCompletions, treeElement, isEditingName) |
-{ |
+WebInspector.StylesSidebarPane.CSSPropertyPrompt = class extends WebInspector.TextPrompt { |
+ /** |
+ * @param {!Array<string>} cssCompletions |
+ * @param {!WebInspector.StylePropertyTreeElement} treeElement |
+ * @param {boolean} isEditingName |
+ */ |
+ constructor(cssCompletions, treeElement, isEditingName) { |
// Use the same callback both for applyItemCallback and acceptItemCallback. |
- WebInspector.TextPrompt.call(this); |
+ super(); |
this.initialize(this._buildPropertyCompletions.bind(this), WebInspector.StyleValueDelimiters); |
this.setSuggestBoxEnabled(true); |
this._cssCompletions = cssCompletions; |
@@ -2886,277 +2762,270 @@ WebInspector.StylesSidebarPane.CSSPropertyPrompt = function(cssCompletions, tree |
this._isEditingName = isEditingName; |
if (!isEditingName) { |
- this.disableDefaultSuggestionForEmptyInput(); |
- |
- // If a CSS value is being edited that has a numeric or hex substring, hint that precision modifier shortcuts are available. |
- if (treeElement && treeElement.valueElement) { |
- var cssValueText = treeElement.valueElement.textContent; |
- if (cssValueText.match(/#[\da-f]{3,6}$/i)) |
- this.setTitle(WebInspector.UIString("Increment/decrement with mousewheel or up/down keys. %s: R ±1, Shift: G ±1, Alt: B ±1", WebInspector.isMac() ? "Cmd" : "Ctrl")); |
- else if (cssValueText.match(/\d+/)) |
- this.setTitle(WebInspector.UIString("Increment/decrement with mousewheel or up/down keys. %s: ±100, Shift: ±10, Alt: ±0.1", WebInspector.isMac() ? "Cmd" : "Ctrl")); |
- } |
- |
+ this.disableDefaultSuggestionForEmptyInput(); |
+ |
+ // If a CSS value is being edited that has a numeric or hex substring, hint that precision modifier shortcuts are available. |
+ if (treeElement && treeElement.valueElement) { |
+ var cssValueText = treeElement.valueElement.textContent; |
+ if (cssValueText.match(/#[\da-f]{3,6}$/i)) |
+ this.setTitle(WebInspector.UIString( |
+ 'Increment/decrement with mousewheel or up/down keys. %s: R ±1, Shift: G ±1, Alt: B ±1', |
+ WebInspector.isMac() ? 'Cmd' : 'Ctrl')); |
+ else if (cssValueText.match(/\d+/)) |
+ this.setTitle(WebInspector.UIString( |
+ 'Increment/decrement with mousewheel or up/down keys. %s: ±100, Shift: ±10, Alt: ±0.1', |
+ WebInspector.isMac() ? 'Cmd' : 'Ctrl')); |
+ } |
} |
-}; |
- |
-WebInspector.StylesSidebarPane.CSSPropertyPrompt.prototype = { |
- /** |
- * @override |
- * @param {!Event} event |
- */ |
- onKeyDown: function(event) |
- { |
- switch (event.key) { |
- case "ArrowUp": |
- case "ArrowDown": |
- case "PageUp": |
- case "PageDown": |
- if (this._handleNameOrValueUpDown(event)) { |
- event.preventDefault(); |
- return; |
- } |
- break; |
- case "Enter": |
- // Accept any available autocompletions and advance to the next field. |
- if (this.textWithCurrentSuggestion() !== this.text()) { |
- this.tabKeyPressed(); |
- return; |
- } |
- break; |
- } |
- |
- WebInspector.TextPrompt.prototype.onKeyDown.call(this, event); |
- }, |
- |
- /** |
- * @override |
- * @param {!Event} event |
- */ |
- onMouseWheel: function(event) |
- { |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!Event} event |
+ */ |
+ onKeyDown(event) { |
+ switch (event.key) { |
+ case 'ArrowUp': |
+ case 'ArrowDown': |
+ case 'PageUp': |
+ case 'PageDown': |
if (this._handleNameOrValueUpDown(event)) { |
- event.consume(true); |
- return; |
+ event.preventDefault(); |
+ return; |
} |
- WebInspector.TextPrompt.prototype.onMouseWheel.call(this, event); |
- }, |
- |
- /** |
- * @override |
- * @return {boolean} |
- */ |
- tabKeyPressed: function() |
- { |
- this.acceptAutoComplete(); |
- |
- // Always tab to the next field. |
- return false; |
- }, |
- |
- /** |
- * @param {!Event} event |
- * @return {boolean} |
- */ |
- _handleNameOrValueUpDown: function(event) |
- { |
- /** |
- * @param {string} originalValue |
- * @param {string} replacementString |
- * @this {WebInspector.StylesSidebarPane.CSSPropertyPrompt} |
- */ |
- function finishHandler(originalValue, replacementString) |
- { |
- // Synthesize property text disregarding any comments, custom whitespace etc. |
- this._treeElement.applyStyleText(this._treeElement.nameElement.textContent + ": " + this._treeElement.valueElement.textContent, false); |
+ break; |
+ case 'Enter': |
+ // Accept any available autocompletions and advance to the next field. |
+ if (this.textWithCurrentSuggestion() !== this.text()) { |
+ this.tabKeyPressed(); |
+ return; |
} |
+ break; |
+ } |
- /** |
- * @param {string} prefix |
- * @param {number} number |
- * @param {string} suffix |
- * @return {string} |
- * @this {WebInspector.StylesSidebarPane.CSSPropertyPrompt} |
- */ |
- function customNumberHandler(prefix, number, suffix) |
- { |
- if (number !== 0 && !suffix.length && WebInspector.cssMetadata().isLengthProperty(this._treeElement.property.name)) |
- suffix = "px"; |
- return prefix + number + suffix; |
- } |
+ super.onKeyDown(event); |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!Event} event |
+ */ |
+ onMouseWheel(event) { |
+ if (this._handleNameOrValueUpDown(event)) { |
+ event.consume(true); |
+ return; |
+ } |
+ super.onMouseWheel(event); |
+ } |
- // Handle numeric value increment/decrement only at this point. |
- if (!this._isEditingName && WebInspector.handleElementValueModifications(event, this._treeElement.valueElement, finishHandler.bind(this), this._isValueSuggestion.bind(this), customNumberHandler.bind(this))) |
- return true; |
+ /** |
+ * @override |
+ * @return {boolean} |
+ */ |
+ tabKeyPressed() { |
+ this.acceptAutoComplete(); |
- return false; |
- }, |
+ // Always tab to the next field. |
+ return false; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ * @return {boolean} |
+ */ |
+ _handleNameOrValueUpDown(event) { |
+ /** |
+ * @param {string} originalValue |
+ * @param {string} replacementString |
+ * @this {WebInspector.StylesSidebarPane.CSSPropertyPrompt} |
+ */ |
+ function finishHandler(originalValue, replacementString) { |
+ // Synthesize property text disregarding any comments, custom whitespace etc. |
+ this._treeElement.applyStyleText( |
+ this._treeElement.nameElement.textContent + ': ' + this._treeElement.valueElement.textContent, false); |
+ } |
/** |
- * @param {string} word |
- * @return {boolean} |
+ * @param {string} prefix |
+ * @param {number} number |
+ * @param {string} suffix |
+ * @return {string} |
+ * @this {WebInspector.StylesSidebarPane.CSSPropertyPrompt} |
*/ |
- _isValueSuggestion: function(word) |
- { |
- if (!word) |
- return false; |
- word = word.toLowerCase(); |
- return this._cssCompletions.indexOf(word) !== -1; |
- }, |
+ function customNumberHandler(prefix, number, suffix) { |
+ if (number !== 0 && !suffix.length && |
+ WebInspector.cssMetadata().isLengthProperty(this._treeElement.property.name)) |
+ suffix = 'px'; |
+ return prefix + number + suffix; |
+ } |
- /** |
- * @param {!Element} proxyElement |
- * @param {!Range} wordRange |
- * @param {boolean} force |
- * @param {function(!Array.<string>, number=)} completionsReadyCallback |
- */ |
- _buildPropertyCompletions: function(proxyElement, wordRange, force, completionsReadyCallback) |
- { |
- var prefix = wordRange.toString().toLowerCase(); |
- if (!prefix && !force && (this._isEditingName || proxyElement.textContent.length)) { |
- completionsReadyCallback([]); |
- return; |
- } |
+ // Handle numeric value increment/decrement only at this point. |
+ if (!this._isEditingName && |
+ WebInspector.handleElementValueModifications( |
+ event, this._treeElement.valueElement, finishHandler.bind(this), this._isValueSuggestion.bind(this), |
+ customNumberHandler.bind(this))) |
+ return true; |
- var results = this._cssCompletions.filter(completion => completion.startsWith(prefix)); |
- if (!this._isEditingName && !results.length && prefix.length > 1 && "!important".startsWith(prefix)) |
- results.push("!important"); |
- var userEnteredText = wordRange.toString().replace("-", ""); |
- if (userEnteredText && (userEnteredText === userEnteredText.toUpperCase())) { |
- for (var i = 0; i < results.length; ++i) |
- results[i] = results[i].toUpperCase(); |
- } |
- var selectedIndex = this._isEditingName ? WebInspector.cssMetadata().mostUsedProperty(results) : 0; |
- completionsReadyCallback(results, selectedIndex); |
- }, |
+ return false; |
+ } |
+ |
+ /** |
+ * @param {string} word |
+ * @return {boolean} |
+ */ |
+ _isValueSuggestion(word) { |
+ if (!word) |
+ return false; |
+ word = word.toLowerCase(); |
+ return this._cssCompletions.indexOf(word) !== -1; |
+ } |
+ |
+ /** |
+ * @param {!Element} proxyElement |
+ * @param {!Range} wordRange |
+ * @param {boolean} force |
+ * @param {function(!Array.<string>, number=)} completionsReadyCallback |
+ */ |
+ _buildPropertyCompletions(proxyElement, wordRange, force, completionsReadyCallback) { |
+ var prefix = wordRange.toString().toLowerCase(); |
+ if (!prefix && !force && (this._isEditingName || proxyElement.textContent.length)) { |
+ completionsReadyCallback([]); |
+ return; |
+ } |
- __proto__: WebInspector.TextPrompt.prototype |
+ var results = this._cssCompletions.filter(completion => completion.startsWith(prefix)); |
+ if (!this._isEditingName && !results.length && prefix.length > 1 && '!important'.startsWith(prefix)) |
+ results.push('!important'); |
+ var userEnteredText = wordRange.toString().replace('-', ''); |
+ if (userEnteredText && (userEnteredText === userEnteredText.toUpperCase())) { |
+ for (var i = 0; i < results.length; ++i) |
+ results[i] = results[i].toUpperCase(); |
+ } |
+ var selectedIndex = this._isEditingName ? WebInspector.cssMetadata().mostUsedProperty(results) : 0; |
+ completionsReadyCallback(results, selectedIndex); |
+ } |
}; |
/** |
- * @constructor |
- * @param {?WebInspector.CSSRule} rule |
- * @param {?WebInspector.DOMNode} node |
- * @param {string} name |
- * @param {string} value |
+ * @unrestricted |
*/ |
-WebInspector.StylesSidebarPropertyRenderer = function(rule, node, name, value) |
-{ |
+WebInspector.StylesSidebarPropertyRenderer = class { |
+ /** |
+ * @param {?WebInspector.CSSRule} rule |
+ * @param {?WebInspector.DOMNode} node |
+ * @param {string} name |
+ * @param {string} value |
+ */ |
+ constructor(rule, node, name, value) { |
this._rule = rule; |
this._node = node; |
this._propertyName = name; |
this._propertyValue = value; |
-}; |
- |
-WebInspector.StylesSidebarPropertyRenderer.prototype = { |
- /** |
- * @param {function(string):!Node} handler |
- */ |
- setColorHandler: function(handler) |
- { |
- this._colorHandler = handler; |
- }, |
- |
- /** |
- * @param {function(string):!Node} handler |
- */ |
- setBezierHandler: function(handler) |
- { |
- this._bezierHandler = handler; |
- }, |
- |
- /** |
- * @param {function(string, string):!Node} handler |
- */ |
- setShadowHandler: function(handler) |
- { |
- this._shadowHandler = handler; |
- }, |
- |
- /** |
- * @return {!Element} |
- */ |
- renderName: function() |
- { |
- var nameElement = createElement("span"); |
- nameElement.className = "webkit-css-property"; |
- nameElement.textContent = this._propertyName; |
- nameElement.normalize(); |
- return nameElement; |
- }, |
- |
- /** |
- * @return {!Element} |
- */ |
- renderValue: function() |
- { |
- var valueElement = createElement("span"); |
- valueElement.className = "value"; |
- if (!this._propertyValue) |
- return valueElement; |
- |
- if (this._shadowHandler && (this._propertyName === "box-shadow" || this._propertyName === "text-shadow" || this._propertyName === "-webkit-box-shadow") |
- && !WebInspector.CSSMetadata.VariableRegex.test(this._propertyValue)) { |
- valueElement.appendChild(this._shadowHandler(this._propertyValue, this._propertyName)); |
- valueElement.normalize(); |
- return valueElement; |
- } |
- |
- var regexes = [WebInspector.CSSMetadata.VariableRegex, WebInspector.CSSMetadata.URLRegex]; |
- var processors = [createTextNode, this._processURL.bind(this)]; |
- if (this._bezierHandler && WebInspector.cssMetadata().isBezierAwareProperty(this._propertyName)) { |
- regexes.push(WebInspector.Geometry.CubicBezier.Regex); |
- processors.push(this._bezierHandler); |
- } |
- if (this._colorHandler && WebInspector.cssMetadata().isColorAwareProperty(this._propertyName)) { |
- regexes.push(WebInspector.Color.Regex); |
- processors.push(this._colorHandler); |
- } |
- var results = WebInspector.TextUtils.splitStringByRegexes(this._propertyValue, regexes); |
- for (var i = 0; i < results.length; i++) { |
- var result = results[i]; |
- var processor = result.regexIndex === -1 ? createTextNode : processors[result.regexIndex]; |
- valueElement.appendChild(processor(result.value)); |
- } |
- valueElement.normalize(); |
- return valueElement; |
- }, |
+ } |
+ |
+ /** |
+ * @param {function(string):!Node} handler |
+ */ |
+ setColorHandler(handler) { |
+ this._colorHandler = handler; |
+ } |
+ |
+ /** |
+ * @param {function(string):!Node} handler |
+ */ |
+ setBezierHandler(handler) { |
+ this._bezierHandler = handler; |
+ } |
+ |
+ /** |
+ * @param {function(string, string):!Node} handler |
+ */ |
+ setShadowHandler(handler) { |
+ this._shadowHandler = handler; |
+ } |
+ |
+ /** |
+ * @return {!Element} |
+ */ |
+ renderName() { |
+ var nameElement = createElement('span'); |
+ nameElement.className = 'webkit-css-property'; |
+ nameElement.textContent = this._propertyName; |
+ nameElement.normalize(); |
+ return nameElement; |
+ } |
+ |
+ /** |
+ * @return {!Element} |
+ */ |
+ renderValue() { |
+ var valueElement = createElement('span'); |
+ valueElement.className = 'value'; |
+ if (!this._propertyValue) |
+ return valueElement; |
+ |
+ if (this._shadowHandler && (this._propertyName === 'box-shadow' || this._propertyName === 'text-shadow' || |
+ this._propertyName === '-webkit-box-shadow') && |
+ !WebInspector.CSSMetadata.VariableRegex.test(this._propertyValue)) { |
+ valueElement.appendChild(this._shadowHandler(this._propertyValue, this._propertyName)); |
+ valueElement.normalize(); |
+ return valueElement; |
+ } |
- /** |
- * @param {string} text |
- * @return {!Node} |
- */ |
- _processURL: function(text) |
- { |
- // Strip "url(" and ")" along with whitespace. |
- var url = text.substring(4, text.length - 1).trim(); |
- var isQuoted = /^'.*'$/.test(url) || /^".*"$/.test(url); |
- if (isQuoted) |
- url = url.substring(1, url.length - 1); |
- var container = createDocumentFragment(); |
- container.createTextChild("url("); |
- var hrefUrl = null; |
- if (this._rule && this._rule.resourceURL()) |
- hrefUrl = WebInspector.ParsedURL.completeURL(this._rule.resourceURL(), url); |
- else if (this._node) |
- hrefUrl = this._node.resolveURL(url); |
- var hasResource = hrefUrl && !!WebInspector.resourceForURL(hrefUrl); |
- // FIXME: WebInspector.linkifyURLAsNode() should really use baseURI. |
- container.appendChild(WebInspector.linkifyURLAsNode(hrefUrl || url, url, undefined, !hasResource)); |
- container.createTextChild(")"); |
- return container; |
+ var regexes = [WebInspector.CSSMetadata.VariableRegex, WebInspector.CSSMetadata.URLRegex]; |
+ var processors = [createTextNode, this._processURL.bind(this)]; |
+ if (this._bezierHandler && WebInspector.cssMetadata().isBezierAwareProperty(this._propertyName)) { |
+ regexes.push(WebInspector.Geometry.CubicBezier.Regex); |
+ processors.push(this._bezierHandler); |
+ } |
+ if (this._colorHandler && WebInspector.cssMetadata().isColorAwareProperty(this._propertyName)) { |
+ regexes.push(WebInspector.Color.Regex); |
+ processors.push(this._colorHandler); |
} |
+ var results = WebInspector.TextUtils.splitStringByRegexes(this._propertyValue, regexes); |
+ for (var i = 0; i < results.length; i++) { |
+ var result = results[i]; |
+ var processor = result.regexIndex === -1 ? createTextNode : processors[result.regexIndex]; |
+ valueElement.appendChild(processor(result.value)); |
+ } |
+ valueElement.normalize(); |
+ return valueElement; |
+ } |
+ |
+ /** |
+ * @param {string} text |
+ * @return {!Node} |
+ */ |
+ _processURL(text) { |
+ // Strip "url(" and ")" along with whitespace. |
+ var url = text.substring(4, text.length - 1).trim(); |
+ var isQuoted = /^'.*'$/.test(url) || /^".*"$/.test(url); |
+ if (isQuoted) |
+ url = url.substring(1, url.length - 1); |
+ var container = createDocumentFragment(); |
+ container.createTextChild('url('); |
+ var hrefUrl = null; |
+ if (this._rule && this._rule.resourceURL()) |
+ hrefUrl = WebInspector.ParsedURL.completeURL(this._rule.resourceURL(), url); |
+ else if (this._node) |
+ hrefUrl = this._node.resolveURL(url); |
+ var hasResource = hrefUrl && !!WebInspector.resourceForURL(hrefUrl); |
+ // FIXME: WebInspector.linkifyURLAsNode() should really use baseURI. |
+ container.appendChild(WebInspector.linkifyURLAsNode(hrefUrl || url, url, undefined, !hasResource)); |
+ container.createTextChild(')'); |
+ return container; |
+ } |
}; |
/** |
- * @constructor |
* @implements {WebInspector.ToolbarItem.Provider} |
+ * @unrestricted |
*/ |
-WebInspector.StylesSidebarPane.ButtonProvider = function() |
-{ |
- this._button = new WebInspector.ToolbarButton(WebInspector.UIString("New Style Rule"), "add-toolbar-item"); |
- this._button.addEventListener("click", this._clicked, this); |
- this._button.element.createChild("div", "long-click-glyph toolbar-button-theme"); |
+WebInspector.StylesSidebarPane.ButtonProvider = class { |
+ constructor() { |
+ this._button = new WebInspector.ToolbarButton(WebInspector.UIString('New Style Rule'), 'add-toolbar-item'); |
+ this._button.addEventListener('click', this._clicked, this); |
+ this._button.element.createChild('div', 'long-click-glyph toolbar-button-theme'); |
new WebInspector.LongClickController(this._button.element, this._longClicked.bind(this)); |
WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, onNodeChanged.bind(this)); |
onNodeChanged.call(this); |
@@ -3164,34 +3033,29 @@ WebInspector.StylesSidebarPane.ButtonProvider = function() |
/** |
* @this {WebInspector.StylesSidebarPane.ButtonProvider} |
*/ |
- function onNodeChanged() |
- { |
- var node = WebInspector.context.flavor(WebInspector.DOMNode); |
- node = node ? node.enclosingElementOrSelf() : null; |
- this._button.setEnabled(!!node); |
- } |
-}; |
- |
-WebInspector.StylesSidebarPane.ButtonProvider.prototype = { |
- _clicked: function() |
- { |
- WebInspector.StylesSidebarPane._instance._createNewRuleInViaInspectorStyleSheet(); |
- }, |
- |
- /** |
- * @param {!Event} e |
- */ |
- _longClicked: function(e) |
- { |
- WebInspector.StylesSidebarPane._instance._onAddButtonLongClick(e); |
- }, |
- |
- /** |
- * @override |
- * @return {!WebInspector.ToolbarItem} |
- */ |
- item: function() |
- { |
- return this._button; |
+ function onNodeChanged() { |
+ var node = WebInspector.context.flavor(WebInspector.DOMNode); |
+ node = node ? node.enclosingElementOrSelf() : null; |
+ this._button.setEnabled(!!node); |
} |
+ } |
+ |
+ _clicked() { |
+ WebInspector.StylesSidebarPane._instance._createNewRuleInViaInspectorStyleSheet(); |
+ } |
+ |
+ /** |
+ * @param {!Event} e |
+ */ |
+ _longClicked(e) { |
+ WebInspector.StylesSidebarPane._instance._onAddButtonLongClick(e); |
+ } |
+ |
+ /** |
+ * @override |
+ * @return {!WebInspector.ToolbarItem} |
+ */ |
+ item() { |
+ return this._button; |
+ } |
}; |