| 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;
|
| + }
|
| };
|
|
|