StylesSidebarPane.js 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. export default class StylesSidebarPane extends Elements.ElementsSidebarPane{constructor(){super(true);this.setMinimumSize(96,26);this.registerRequiredCSS('elements/stylesSidebarPane.css');Common.moduleSetting('colorFormat').addChangeListener(this.update.bind(this));Common.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this));this._currentToolbarPane=null;this._animatedToolbarPane=null;this._pendingWidget=null;this._pendingWidgetToggle=null;this._toolbarPaneElement=this._createStylesSidebarToolbar();this._noMatchesElement=this.contentElement.createChild('div','gray-info-message hidden');this._noMatchesElement.textContent=ls`No matching selector or style`;this._sectionsContainer=this.contentElement.createChild('div');UI.ARIAUtils.markAsTree(this._sectionsContainer);this._sectionsContainer.addEventListener('keydown',this._sectionsContainerKeyDown.bind(this),false);this._sectionsContainer.addEventListener('focusin',this._sectionsContainerFocusChanged.bind(this),false);this._sectionsContainer.addEventListener('focusout',this._sectionsContainerFocusChanged.bind(this),false);this._swatchPopoverHelper=new InlineEditor.SwatchPopoverHelper();this._linkifier=new Components.Linkifier(_maxLinkLength,true);this._decorator=null;this._userOperation=false;this._isEditingStyle=false;this._filterRegex=null;this._isActivePropertyHighlighted=false;this.contentElement.classList.add('styles-pane');this._sectionBlocks=[];this._needsForceUpdate=false;StylesSidebarPane._instance=this;UI.context.addFlavorChangeListener(SDK.DOMNode,this.forceUpdate,this);this.contentElement.addEventListener('copy',this._clipboardCopy.bind(this));this._resizeThrottler=new Common.Throttler(100);}
  2. swatchPopoverHelper(){return this._swatchPopoverHelper;}
  3. setUserOperation(userOperation){this._userOperation=userOperation;}
  4. static createExclamationMark(property){const exclamationElement=createElement('span','dt-icon-label');exclamationElement.className='exclamation-mark';if(!StylesSidebarPane.ignoreErrorsForProperty(property)){exclamationElement.type='smallicon-warning';}
  5. exclamationElement.title=SDK.cssMetadata().isCSSPropertyName(property.name)?Common.UIString('Invalid property value'):Common.UIString('Unknown property name');return exclamationElement;}
  6. static ignoreErrorsForProperty(property){function hasUnknownVendorPrefix(string){return!string.startsWith('-webkit-')&&/^[-_][\w\d]+-\w/.test(string);}
  7. const name=property.name.toLowerCase();if(name.charAt(0)==='_'){return true;}
  8. if(name==='filter'){return true;}
  9. if(name.startsWith('scrollbar-')){return true;}
  10. if(hasUnknownVendorPrefix(name)){return true;}
  11. const value=property.value.toLowerCase();if(value.endsWith('\\9')){return true;}
  12. if(hasUnknownVendorPrefix(value)){return true;}
  13. return false;}
  14. static createPropertyFilterElement(placeholder,container,filterCallback){const input=createElementWithClass('input');input.placeholder=placeholder;function searchHandler(){const regex=input.value?new RegExp(input.value.escapeForRegExp(),'i'):null;filterCallback(regex);}
  15. input.addEventListener('input',searchHandler,false);function keydownHandler(event){if(event.key!=='Escape'||!input.value){return;}
  16. event.consume(true);input.value='';searchHandler();}
  17. input.addEventListener('keydown',keydownHandler,false);input.setFilterValue=setFilterValue;function setFilterValue(value){input.value=value;input.focus();searchHandler();}
  18. return input;}
  19. revealProperty(cssProperty){this._decorator=new Elements.StylePropertyHighlighter(this,cssProperty);this._decorator.perform();this.update();}
  20. forceUpdate(){this._needsForceUpdate=true;this._swatchPopoverHelper.hide();this._resetCache();this.update();}
  21. _sectionsContainerKeyDown(event){const activeElement=this._sectionsContainer.ownerDocument.deepActiveElement();if(!activeElement){return;}
  22. const section=activeElement._section;if(!section){return;}
  23. switch(event.key){case'ArrowUp':case'ArrowLeft':const sectionToFocus=section.previousSibling()||section.lastSibling();sectionToFocus.element.focus();event.consume(true);break;case'ArrowDown':case'ArrowRight':{const sectionToFocus=section.nextSibling()||section.firstSibling();sectionToFocus.element.focus();event.consume(true);break;}
  24. case'Home':section.firstSibling().element.focus();event.consume(true);break;case'End':section.lastSibling().element.focus();event.consume(true);break;}}
  25. _sectionsContainerFocusChanged(){this.resetFocus();}
  26. resetFocus(){if(this._sectionBlocks[0]&&this._sectionBlocks[0].sections[0]){this._sectionBlocks[0].sections[0].element.tabIndex=this._sectionsContainer.hasFocus()?-1:0;}}
  27. _onAddButtonLongClick(event){const cssModel=this.cssModel();if(!cssModel){return;}
  28. const headers=cssModel.styleSheetHeaders().filter(styleSheetResourceHeader);const contextMenuDescriptors=[];for(let i=0;i<headers.length;++i){const header=headers[i];const handler=this._createNewRuleInStyleSheet.bind(this,header);contextMenuDescriptors.push({text:Bindings.displayNameForURL(header.resourceURL()),handler:handler});}
  29. contextMenuDescriptors.sort(compareDescriptors);const contextMenu=new UI.ContextMenu(event);for(let i=0;i<contextMenuDescriptors.length;++i){const descriptor=contextMenuDescriptors[i];contextMenu.defaultSection().appendItem(descriptor.text,descriptor.handler);}
  30. contextMenu.footerSection().appendItem('inspector-stylesheet',this._createNewRuleInViaInspectorStyleSheet.bind(this));contextMenu.show();function compareDescriptors(descriptor1,descriptor2){return String.naturalOrderComparator(descriptor1.text,descriptor2.text);}
  31. function styleSheetResourceHeader(header){return!header.isViaInspector()&&!header.isInline&&!!header.resourceURL();}}
  32. _onFilterChanged(regex){this._filterRegex=regex;this._updateFilter();}
  33. _refreshUpdate(editedSection,editedTreeElement){if(editedTreeElement){for(const section of this.allSections()){if(section.isBlank){continue;}
  34. section._updateVarFunctions(editedTreeElement);}}
  35. if(this._isEditingStyle){return;}
  36. const node=this.node();if(!node){return;}
  37. for(const section of this.allSections()){if(section.isBlank){continue;}
  38. section.update(section===editedSection);}
  39. if(this._filterRegex){this._updateFilter();}
  40. this._nodeStylesUpdatedForTest(node,false);}
  41. doUpdate(){return this._fetchMatchedCascade().then(this._innerRebuildUpdate.bind(this));}
  42. onResize(){this._resizeThrottler.schedule(this._innerResize.bind(this));}
  43. _innerResize(){const width=this.contentElement.getBoundingClientRect().width+'px';this.allSections().forEach(section=>section.propertiesTreeOutline.element.style.width=width);return Promise.resolve();}
  44. _resetCache(){if(this.cssModel()){this.cssModel().discardCachedMatchedCascade();}}
  45. _fetchMatchedCascade(){const node=this.node();if(!node||!this.cssModel()){return Promise.resolve((null));}
  46. return this.cssModel().cachedMatchedCascadeForNode(node).then(validateStyles.bind(this));function validateStyles(matchedStyles){return matchedStyles&&matchedStyles.node()===this.node()?matchedStyles:null;}}
  47. setEditingStyle(editing,treeElement){if(this._isEditingStyle===editing){return;}
  48. this.contentElement.classList.toggle('is-editing-style',editing);this._isEditingStyle=editing;this._setActiveProperty(null);}
  49. _setActiveProperty(treeElement){if(this._isActivePropertyHighlighted){SDK.OverlayModel.hideDOMNodeHighlight();}
  50. this._isActivePropertyHighlighted=false;if(!this.node()){return;}
  51. if(!treeElement||treeElement.overloaded()||treeElement.inherited()){return;}
  52. const rule=treeElement.property.ownerStyle.parentRule;const selectorList=(rule instanceof SDK.CSSStyleRule)?rule.selectorText():undefined;for(const mode of['padding','border','margin']){if(!treeElement.name.startsWith(mode)){continue;}
  53. this.node().domModel().overlayModel().highlightInOverlay({node:(this.node()),selectorList},mode);this._isActivePropertyHighlighted=true;break;}}
  54. onCSSModelChanged(event){const edit=event&&event.data?(event.data.edit):null;if(edit){for(const section of this.allSections()){section._styleSheetEdited(edit);}
  55. return;}
  56. if(this._userOperation||this._isEditingStyle){return;}
  57. this._resetCache();this.update();}
  58. focusedSectionIndex(){let index=0;for(const block of this._sectionBlocks){for(const section of block.sections){if(section.element.hasFocus()){return index;}
  59. index++;}}
  60. return-1;}
  61. continueEditingElement(sectionIndex,propertyIndex){const section=this.allSections()[sectionIndex];if(section){section.propertiesTreeOutline.rootElement().childAt(propertyIndex).startEditing();}}
  62. async _innerRebuildUpdate(matchedStyles){if(this._needsForceUpdate){this._needsForceUpdate=false;}else if(this._isEditingStyle||this._userOperation){return;}
  63. const focusedIndex=this.focusedSectionIndex();this._linkifier.reset();this._sectionsContainer.removeChildren();this._sectionBlocks=[];const node=this.node();if(!matchedStyles||!node){this._noMatchesElement.classList.remove('hidden');return;}
  64. this._sectionBlocks=await this._rebuildSectionsForMatchedStyleRules((matchedStyles));let pseudoTypes=[];const keys=matchedStyles.pseudoTypes();if(keys.delete(Protocol.DOM.PseudoType.Before)){pseudoTypes.push(Protocol.DOM.PseudoType.Before);}
  65. pseudoTypes=pseudoTypes.concat(keys.valuesArray().sort());for(const pseudoType of pseudoTypes){const block=SectionBlock.createPseudoTypeBlock(pseudoType);for(const style of matchedStyles.pseudoStyles(pseudoType)){const section=new StylePropertiesSection(this,matchedStyles,style);block.sections.push(section);}
  66. this._sectionBlocks.push(block);}
  67. for(const keyframesRule of matchedStyles.keyframes()){const block=SectionBlock.createKeyframesBlock(keyframesRule.name().text);for(const keyframe of keyframesRule.keyframes()){block.sections.push(new KeyframePropertiesSection(this,matchedStyles,keyframe.style));}
  68. this._sectionBlocks.push(block);}
  69. let index=0;for(const block of this._sectionBlocks){const titleElement=block.titleElement();if(titleElement){this._sectionsContainer.appendChild(titleElement);}
  70. for(const section of block.sections){this._sectionsContainer.appendChild(section.element);if(index===focusedIndex){section.element.focus();}
  71. index++;}}
  72. if(focusedIndex>=index){this._sectionBlocks[0].sections[0].element.focus();}
  73. this._sectionsContainerFocusChanged();if(this._filterRegex){this._updateFilter();}else{this._noMatchesElement.classList.toggle('hidden',this._sectionBlocks.length>0);}
  74. this._nodeStylesUpdatedForTest((node),true);if(this._decorator){this._decorator.perform();this._decorator=null;}}
  75. _nodeStylesUpdatedForTest(node,rebuild){}
  76. async _rebuildSectionsForMatchedStyleRules(matchedStyles){const blocks=[new SectionBlock(null)];let lastParentNode=null;for(const style of matchedStyles.nodeStyles()){const parentNode=matchedStyles.isInherited(style)?matchedStyles.nodeForStyle(style):null;if(parentNode&&parentNode!==lastParentNode){lastParentNode=parentNode;const block=await SectionBlock._createInheritedNodeBlock(lastParentNode);blocks.push(block);}
  77. const section=new StylePropertiesSection(this,matchedStyles,style);blocks.peekLast().sections.push(section);}
  78. return blocks;}
  79. async _createNewRuleInViaInspectorStyleSheet(){const cssModel=this.cssModel();const node=this.node();if(!cssModel||!node){return;}
  80. this.setUserOperation(true);const styleSheetHeader=await cssModel.requestViaInspectorStylesheet((node));this.setUserOperation(false);await this._createNewRuleInStyleSheet(styleSheetHeader);}
  81. async _createNewRuleInStyleSheet(styleSheetHeader){if(!styleSheetHeader){return;}
  82. const text=(await styleSheetHeader.requestContent()).content||'';const lines=text.split('\n');const range=TextUtils.TextRange.createFromLocation(lines.length-1,lines[lines.length-1].length);this._addBlankSection(this._sectionBlocks[0].sections[0],styleSheetHeader.id,range);}
  83. _addBlankSection(insertAfterSection,styleSheetId,ruleLocation){const node=this.node();const blankSection=new BlankStylePropertiesSection(this,insertAfterSection._matchedStyles,node?node.simpleSelector():'',styleSheetId,ruleLocation,insertAfterSection._style);this._sectionsContainer.insertBefore(blankSection.element,insertAfterSection.element.nextSibling);for(const block of this._sectionBlocks){const index=block.sections.indexOf(insertAfterSection);if(index===-1){continue;}
  84. block.sections.splice(index+1,0,blankSection);blankSection.startEditingSelector();}}
  85. removeSection(section){for(const block of this._sectionBlocks){const index=block.sections.indexOf(section);if(index===-1){continue;}
  86. block.sections.splice(index,1);section.element.remove();}}
  87. filterRegex(){return this._filterRegex;}
  88. _updateFilter(){let hasAnyVisibleBlock=false;for(const block of this._sectionBlocks){hasAnyVisibleBlock|=block.updateFilter();}
  89. this._noMatchesElement.classList.toggle('hidden',!!hasAnyVisibleBlock);}
  90. willHide(){this._swatchPopoverHelper.hide();super.willHide();}
  91. allSections(){let sections=[];for(const block of this._sectionBlocks){sections=sections.concat(block.sections);}
  92. return sections;}
  93. _clipboardCopy(event){Host.userMetrics.actionTaken(Host.UserMetrics.Action.StyleRuleCopied);}
  94. _createStylesSidebarToolbar(){const container=this.contentElement.createChild('div','styles-sidebar-pane-toolbar-container');const hbox=container.createChild('div','hbox styles-sidebar-pane-toolbar');const filterContainerElement=hbox.createChild('div','styles-sidebar-pane-filter-box');const filterInput=StylesSidebarPane.createPropertyFilterElement(ls`Filter`,hbox,this._onFilterChanged.bind(this));UI.ARIAUtils.setAccessibleName(filterInput,Common.UIString('Filter Styles'));filterContainerElement.appendChild(filterInput);const toolbar=new UI.Toolbar('styles-pane-toolbar',hbox);toolbar.makeToggledGray();toolbar.appendItemsAtLocation('styles-sidebarpane-toolbar');const toolbarPaneContainer=container.createChild('div','styles-sidebar-toolbar-pane-container');const toolbarPaneContent=toolbarPaneContainer.createChild('div','styles-sidebar-toolbar-pane');return toolbarPaneContent;}
  95. showToolbarPane(widget,toggle){if(this._pendingWidgetToggle){this._pendingWidgetToggle.setToggled(false);}
  96. this._pendingWidgetToggle=toggle;if(this._animatedToolbarPane){this._pendingWidget=widget;}else{this._startToolbarPaneAnimation(widget);}
  97. if(widget&&toggle){toggle.setToggled(true);}}
  98. _startToolbarPaneAnimation(widget){if(widget===this._currentToolbarPane){return;}
  99. if(widget&&this._currentToolbarPane){this._currentToolbarPane.detach();widget.show(this._toolbarPaneElement);this._currentToolbarPane=widget;this._currentToolbarPane.focus();return;}
  100. this._animatedToolbarPane=widget;if(this._currentToolbarPane){this._toolbarPaneElement.style.animationName='styles-element-state-pane-slideout';}else if(widget){this._toolbarPaneElement.style.animationName='styles-element-state-pane-slidein';}
  101. if(widget){widget.show(this._toolbarPaneElement);}
  102. const listener=onAnimationEnd.bind(this);this._toolbarPaneElement.addEventListener('animationend',listener,false);function onAnimationEnd(){this._toolbarPaneElement.style.removeProperty('animation-name');this._toolbarPaneElement.removeEventListener('animationend',listener,false);if(this._currentToolbarPane){this._currentToolbarPane.detach();}
  103. this._currentToolbarPane=this._animatedToolbarPane;if(this._currentToolbarPane){this._currentToolbarPane.focus();}
  104. this._animatedToolbarPane=null;if(this._pendingWidget){this._startToolbarPaneAnimation(this._pendingWidget);this._pendingWidget=null;}}}}
  105. export const _maxLinkLength=23;export class SectionBlock{constructor(titleElement){this._titleElement=titleElement;this.sections=[];}
  106. static createPseudoTypeBlock(pseudoType){const separatorElement=createElement('div');separatorElement.className='sidebar-separator';separatorElement.textContent=Common.UIString('Pseudo ::%s element',pseudoType);return new SectionBlock(separatorElement);}
  107. static createKeyframesBlock(keyframesName){const separatorElement=createElement('div');separatorElement.className='sidebar-separator';separatorElement.textContent=`@keyframes ${keyframesName}`;return new SectionBlock(separatorElement);}
  108. static async _createInheritedNodeBlock(node){const separatorElement=createElement('div');separatorElement.className='sidebar-separator';separatorElement.createTextChild(ls`Inherited from${' '}`);const link=await Common.Linkifier.linkify(node,{preventKeyboardFocus:true});separatorElement.appendChild(link);return new SectionBlock(separatorElement);}
  109. updateFilter(){let hasAnyVisibleSection=false;for(const section of this.sections){hasAnyVisibleSection|=section._updateFilter();}
  110. if(this._titleElement){this._titleElement.classList.toggle('hidden',!hasAnyVisibleSection);}
  111. return!!hasAnyVisibleSection;}
  112. titleElement(){return this._titleElement;}}
  113. export class StylePropertiesSection{constructor(parentPane,matchedStyles,style){this._parentPane=parentPane;this._style=style;this._matchedStyles=matchedStyles;this.editable=!!(style.styleSheetId&&style.range);this._hoverTimer=null;this._willCauseCancelEditing=false;this._forceShowAll=false;this._originalPropertiesCount=style.leadingProperties().length;const rule=style.parentRule;this.element=createElementWithClass('div','styles-section matched-styles monospace');this.element.tabIndex=-1;UI.ARIAUtils.markAsTreeitem(this.element);this.element.addEventListener('keydown',this._onKeyDown.bind(this),false);this.element._section=this;this._innerElement=this.element.createChild('div');this._titleElement=this._innerElement.createChild('div','styles-section-title '+(rule?'styles-selector':''));this.propertiesTreeOutline=new UI.TreeOutlineInShadow();this.propertiesTreeOutline.setFocusable(false);this.propertiesTreeOutline.registerRequiredCSS('elements/stylesSectionTree.css');this.propertiesTreeOutline.element.classList.add('style-properties','matched-styles','monospace');this.propertiesTreeOutline.section=this;this._innerElement.appendChild(this.propertiesTreeOutline.element);this._showAllButton=UI.createTextButton('',this._showAllItems.bind(this),'styles-show-all');this._innerElement.appendChild(this._showAllButton);const 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('mousemove',event=>event.consume(),false);this._selectorElement.addEventListener('mouseleave',this._onMouseOutSelector.bind(this),false);const openBrace=selectorContainer.createChild('span','sidebar-pane-open-brace');openBrace.textContent=' {';selectorContainer.addEventListener('mousedown',this._handleEmptySpaceMouseDown.bind(this),false);selectorContainer.addEventListener('click',this._handleSelectorContainerClick.bind(this),false);const closeBrace=this._innerElement.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._onMouseLeave.bind(this),false);this._selectedSinceMouseDown=false;if(rule){if(rule.isUserAgent()||rule.isInjected()){this.editable=false;}else{if(rule.styleSheetId){const header=rule.cssModel().styleSheetHeaderForId(rule.styleSheetId);this.navigable=!header.isAnonymousInlineStyleSheet();}}}
  114. 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');}
  115. if(!this.editable){this.element.classList.add('read-only');this.propertiesTreeOutline.element.classList.add('read-only');}
  116. this._hoverableSelectorsMode=false;this._markSelectorMatches();this.onpopulate();}
  117. static createRuleOriginNode(matchedStyles,linkifier,rule){if(!rule){return createTextNode('');}
  118. const ruleLocation=this._getRuleLocationFromCSSRule(rule);const header=rule.styleSheetId?matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId):null;if(ruleLocation&&rule.styleSheetId&&header&&!header.isAnonymousInlineStyleSheet()){return StylePropertiesSection._linkifyRuleLocation(matchedStyles.cssModel(),linkifier,rule.styleSheetId,ruleLocation);}
  119. if(rule.isUserAgent()){return createTextNode(Common.UIString('user agent stylesheet'));}
  120. if(rule.isInjected()){return createTextNode(Common.UIString('injected stylesheet'));}
  121. if(rule.isViaInspector()){return createTextNode(Common.UIString('via inspector'));}
  122. if(header&&header.ownerNode){const link=Elements.DOMLinkifier.linkifyDeferredNodeReference(header.ownerNode,{preventKeyboardFocus:true});link.textContent='<style>';return link;}
  123. return createTextNode('');}
  124. static _getRuleLocationFromCSSRule(rule){let ruleLocation=null;if(rule instanceof SDK.CSSStyleRule){ruleLocation=rule.style.range;}else if(rule instanceof SDK.CSSKeyframeRule){ruleLocation=rule.key().range;}
  125. return ruleLocation;}
  126. static tryNavigateToRuleLocation(matchedStyles,rule){if(!rule){return;}
  127. const ruleLocation=this._getRuleLocationFromCSSRule(rule);const header=rule.styleSheetId?matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId):null;if(ruleLocation&&rule.styleSheetId&&header&&!header.isAnonymousInlineStyleSheet()){const matchingSelectorLocation=this._getCSSSelectorLocation(matchedStyles.cssModel(),rule.styleSheetId,ruleLocation);this._revealSelectorSource(matchingSelectorLocation,true);}}
  128. static _linkifyRuleLocation(cssModel,linkifier,styleSheetId,ruleLocation){const matchingSelectorLocation=this._getCSSSelectorLocation(cssModel,styleSheetId,ruleLocation);return linkifier.linkifyCSSLocation(matchingSelectorLocation);}
  129. static _getCSSSelectorLocation(cssModel,styleSheetId,ruleLocation){const styleSheetHeader=cssModel.styleSheetHeaderForId(styleSheetId);const lineNumber=styleSheetHeader.lineNumberInSource(ruleLocation.startLine);const columnNumber=styleSheetHeader.columnNumberInSource(ruleLocation.startLine,ruleLocation.startColumn);return new SDK.CSSLocation(styleSheetHeader,lineNumber,columnNumber);}
  130. _onKeyDown(event){if(UI.isEditing()||!this.editable||event.altKey||event.ctrlKey||event.metaKey){return;}
  131. switch(event.key){case'Enter':case' ':this._startEditingAtFirstPosition();event.consume(true);break;default:if(event.key.length===1){this.addNewBlankProperty(0).startEditing();}
  132. break;}}
  133. _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();}}
  134. _onMouseLeave(event){this._setSectionHovered(false);this._parentPane._setActiveProperty(null);}
  135. _onMouseMove(event){const hasCtrlOrMeta=UI.KeyboardShortcut.eventHasCtrlOrMeta((event));this._setSectionHovered(hasCtrlOrMeta);const treeElement=this.propertiesTreeOutline.treeElementFromEvent(event);if(treeElement instanceof Elements.StylePropertyTreeElement){this._parentPane._setActiveProperty((treeElement));}else{this._parentPane._setActiveProperty(null);}
  136. if(!this._selectedSinceMouseDown&&this.element.getComponentSelection().toString()){this._selectedSinceMouseDown=true;}}
  137. _createHoverMenuToolbar(container){if(!this.editable){return;}
  138. const items=[];const textShadowButton=new UI.ToolbarButton(Common.UIString('Add text-shadow'),'largeicon-text-shadow');textShadowButton.addEventListener(UI.ToolbarButton.Events.Click,this._onInsertShadowPropertyClick.bind(this,'text-shadow'));textShadowButton.element.tabIndex=-1;items.push(textShadowButton);const boxShadowButton=new UI.ToolbarButton(Common.UIString('Add box-shadow'),'largeicon-box-shadow');boxShadowButton.addEventListener(UI.ToolbarButton.Events.Click,this._onInsertShadowPropertyClick.bind(this,'box-shadow'));boxShadowButton.element.tabIndex=-1;items.push(boxShadowButton);const colorButton=new UI.ToolbarButton(Common.UIString('Add color'),'largeicon-foreground-color');colorButton.addEventListener(UI.ToolbarButton.Events.Click,this._onInsertColorPropertyClick,this);colorButton.element.tabIndex=-1;items.push(colorButton);const backgroundButton=new UI.ToolbarButton(Common.UIString('Add background-color'),'largeicon-background-color');backgroundButton.addEventListener(UI.ToolbarButton.Events.Click,this._onInsertBackgroundColorPropertyClick,this);backgroundButton.element.tabIndex=-1;items.push(backgroundButton);let newRuleButton=null;if(this._style.parentRule){newRuleButton=new UI.ToolbarButton(Common.UIString('Insert Style Rule Below'),'largeicon-add');newRuleButton.addEventListener(UI.ToolbarButton.Events.Click,this._onNewRuleClick,this);newRuleButton.element.tabIndex=-1;items.push(newRuleButton);}
  139. const sectionToolbar=new UI.Toolbar('sidebar-pane-section-toolbar',container);for(let i=0;i<items.length;++i){sectionToolbar.appendToolbarItem(items[i]);}
  140. const menuButton=new UI.ToolbarButton('','largeicon-menu');menuButton.element.tabIndex=-1;sectionToolbar.appendToolbarItem(menuButton);setItemsVisibility(items,false);sectionToolbar.element.addEventListener('mouseenter',setItemsVisibility.bind(null,items,true));sectionToolbar.element.addEventListener('mouseleave',setItemsVisibility.bind(null,items,false));UI.ARIAUtils.markAsHidden(sectionToolbar.element);function setItemsVisibility(items,value){for(let i=0;i<items.length;++i){items[i].setVisible(value);}
  141. menuButton.setVisible(!value);}}
  142. style(){return this._style;}
  143. _headerText(){const node=this._matchedStyles.nodeForStyle(this._style);if(this._style.type===SDK.CSSStyleDeclaration.Type.Inline){return this._matchedStyles.isInherited(this._style)?Common.UIString('Style Attribute'):'element.style';}
  144. if(this._style.type===SDK.CSSStyleDeclaration.Type.Attributes){return ls`${node.nodeNameInCorrectCase()}[Attributes Style]`;}
  145. return this._style.parentRule.selectorText();}
  146. _onMouseOutSelector(){if(this._hoverTimer){clearTimeout(this._hoverTimer);}
  147. SDK.OverlayModel.hideDOMNodeHighlight();}
  148. _onMouseEnterSelector(){if(this._hoverTimer){clearTimeout(this._hoverTimer);}
  149. this._hoverTimer=setTimeout(this._highlight.bind(this),300);}
  150. _highlight(mode='all'){SDK.OverlayModel.hideDOMNodeHighlight();const node=this._parentPane.node();if(!node){return;}
  151. const selectorList=this._style.parentRule?this._style.parentRule.selectorText():undefined;node.domModel().overlayModel().highlightInOverlay({node,selectorList},mode);}
  152. firstSibling(){const parent=this.element.parentElement;if(!parent){return null;}
  153. let childElement=parent.firstChild;while(childElement){if(childElement._section){return childElement._section;}
  154. childElement=childElement.nextSibling;}
  155. return null;}
  156. lastSibling(){const parent=this.element.parentElement;if(!parent){return null;}
  157. let childElement=parent.lastChild;while(childElement){if(childElement._section){return childElement._section;}
  158. childElement=childElement.previousSibling;}
  159. return null;}
  160. nextSibling(){let curElement=this.element;do{curElement=curElement.nextSibling;}while(curElement&&!curElement._section);return curElement?curElement._section:null;}
  161. previousSibling(){let curElement=this.element;do{curElement=curElement.previousSibling;}while(curElement&&!curElement._section);return curElement?curElement._section:null;}
  162. _onNewRuleClick(event){event.data.consume();const rule=this._style.parentRule;const range=TextUtils.TextRange.createFromLocation(rule.style.range.endLine,rule.style.range.endColumn+1);this._parentPane._addBlankSection(this,(rule.styleSheetId),range);}
  163. _onInsertShadowPropertyClick(propertyName,event){event.data.consume(true);const treeElement=this.addNewBlankProperty();treeElement.property.name=propertyName;treeElement.property.value='0 0 black';treeElement.updateTitle();const shadowSwatchPopoverHelper=Elements.ShadowSwatchPopoverHelper.forTreeElement(treeElement);if(shadowSwatchPopoverHelper){shadowSwatchPopoverHelper.showPopover();}}
  164. _onInsertColorPropertyClick(event){event.data.consume(true);const treeElement=this.addNewBlankProperty();treeElement.property.name='color';treeElement.property.value='black';treeElement.updateTitle();const colorSwatch=Elements.ColorSwatchPopoverIcon.forTreeElement(treeElement);if(colorSwatch){colorSwatch.showPopover();}}
  165. _onInsertBackgroundColorPropertyClick(event){event.data.consume(true);const treeElement=this.addNewBlankProperty();treeElement.property.name='background-color';treeElement.property.value='white';treeElement.updateTitle();const colorSwatch=Elements.ColorSwatchPopoverIcon.forTreeElement(treeElement);if(colorSwatch){colorSwatch.showPopover();}}
  166. _styleSheetEdited(edit){const rule=this._style.parentRule;if(rule){rule.rebase(edit);}else{this._style.rebase(edit);}
  167. this._updateMediaList();this._updateRuleOrigin();}
  168. _createMediaList(mediaRules){for(let i=mediaRules.length-1;i>=0;--i){const media=mediaRules[i];if(!media.text.includes('(')&&media.text!=='print'){continue;}
  169. const mediaDataElement=this._mediaListElement.createChild('div','media');const mediaContainerElement=mediaDataElement.createChild('span');const mediaTextElement=mediaContainerElement.createChild('span','media-text');switch(media.source){case SDK.CSSMedia.Source.LINKED_SHEET:case SDK.CSSMedia.Source.INLINE_SHEET:mediaTextElement.textContent='media="'+media.text+'"';break;case SDK.CSSMedia.Source.MEDIA_RULE:const 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);}
  170. break;case SDK.CSSMedia.Source.IMPORT_RULE:mediaTextElement.textContent='@import '+media.text;break;}}}
  171. _updateMediaList(){this._mediaListElement.removeChildren();if(this._style.parentRule&&this._style.parentRule instanceof SDK.CSSStyleRule){this._createMediaList(this._style.parentRule.media);}}
  172. isPropertyInherited(propertyName){if(this._matchedStyles.isInherited(this._style)){return!SDK.cssMetadata().isPropertyInherited(propertyName);}
  173. return false;}
  174. nextEditableSibling(){let curSection=this;do{curSection=curSection.nextSibling();}while(curSection&&!curSection.editable);if(!curSection){curSection=this.firstSibling();while(curSection&&!curSection.editable){curSection=curSection.nextSibling();}}
  175. return(curSection&&curSection.editable)?curSection:null;}
  176. previousEditableSibling(){let curSection=this;do{curSection=curSection.previousSibling();}while(curSection&&!curSection.editable);if(!curSection){curSection=this.lastSibling();while(curSection&&!curSection.editable){curSection=curSection.previousSibling();}}
  177. return(curSection&&curSection.editable)?curSection:null;}
  178. refreshUpdate(editedTreeElement){this._parentPane._refreshUpdate(this,editedTreeElement);}
  179. _updateVarFunctions(editedTreeElement){let child=this.propertiesTreeOutline.firstChild();while(child){if(child!==editedTreeElement){child.updateTitleIfComputedValueChanged();}
  180. child=child.traverseNextTreeElement(false,null,true);}}
  181. update(full){this._selectorElement.textContent=this._headerText();this._markSelectorMatches();if(full){this.onpopulate();}else{let child=this.propertiesTreeOutline.firstChild();while(child){child.setOverloaded(this._isPropertyOverloaded(child.property));child=child.traverseNextTreeElement(false,null,true);}}}
  182. _showAllItems(event){if(event){event.consume();}
  183. if(this._forceShowAll){return;}
  184. this._forceShowAll=true;this.onpopulate();}
  185. onpopulate(){this._parentPane._setActiveProperty(null);this.propertiesTreeOutline.removeChildren();const style=this._style;let count=0;const properties=style.leadingProperties();const maxProperties=StylePropertiesSection.MaxProperties+properties.length-this._originalPropertiesCount;for(const property of properties){if(!this._forceShowAll&&count>=maxProperties){break;}
  186. count++;const isShorthand=!!style.longhandProperties(property.name).length;const inherited=this.isPropertyInherited(property.name);const overloaded=this._isPropertyOverloaded(property);if(style.parentRule&&style.parentRule.isUserAgent()&&inherited){continue;}
  187. const item=new Elements.StylePropertyTreeElement(this._parentPane,this._matchedStyles,property,isShorthand,inherited,overloaded,false);this.propertiesTreeOutline.appendChild(item);}
  188. if(count<properties.length){this._showAllButton.classList.remove('hidden');this._showAllButton.textContent=ls`Show All Properties (${properties.length - count} more)`;}else{this._showAllButton.classList.add('hidden');}}
  189. _isPropertyOverloaded(property){return this._matchedStyles.propertyState(property)===SDK.CSSMatchedStyles.PropertyState.Overloaded;}
  190. _updateFilter(){let hasMatchingChild=false;this._showAllItems();for(const child of this.propertiesTreeOutline.rootElement().children()){hasMatchingChild|=child._updateFilter();}
  191. const regex=this._parentPane.filterRegex();const hideRule=!hasMatchingChild&&!!regex&&!regex.test(this.element.deepTextContent());this.element.classList.toggle('hidden',hideRule);if(!hideRule&&this._style.parentRule){this._markSelectorHighlights();}
  192. return!hideRule;}
  193. _markSelectorMatches(){const rule=this._style.parentRule;if(!rule){return;}
  194. this._mediaListElement.classList.toggle('media-matches',this._matchedStyles.mediaMatches(this._style));const selectorTexts=rule.selectors.map(selector=>selector.text);const matchingSelectorIndexes=this._matchedStyles.matchingSelectors((rule));const matchingSelectors=(new Array(selectorTexts.length).fill(false));for(const matchingIndex of matchingSelectorIndexes){matchingSelectors[matchingIndex]=true;}
  195. if(this._parentPane._isEditingStyle){return;}
  196. const fragment=this._hoverableSelectorsMode?this._renderHoverableSelectors(selectorTexts,matchingSelectors):this._renderSimplifiedSelectors(selectorTexts,matchingSelectors);this._selectorElement.removeChildren();this._selectorElement.appendChild(fragment);this._markSelectorHighlights();}
  197. _renderHoverableSelectors(selectors,matchingSelectors){const fragment=createDocumentFragment();for(let i=0;i<selectors.length;++i){if(i){fragment.createTextChild(', ');}
  198. fragment.appendChild(this._createSelectorElement(selectors[i],matchingSelectors[i],i));}
  199. return fragment;}
  200. _createSelectorElement(text,isMatching,navigationIndex){const element=createElementWithClass('span','simple-selector');element.classList.toggle('selector-matches',isMatching);if(typeof navigationIndex==='number'){element._selectorIndex=navigationIndex;}
  201. element.textContent=text;return element;}
  202. _renderSimplifiedSelectors(selectors,matchingSelectors){const fragment=createDocumentFragment();let currentMatching=false;let text='';for(let i=0;i<selectors.length;++i){if(currentMatching!==matchingSelectors[i]&&text){fragment.appendChild(this._createSelectorElement(text,currentMatching));text='';}
  203. currentMatching=matchingSelectors[i];text+=selectors[i]+(i===selectors.length-1?'':', ');}
  204. if(text){fragment.appendChild(this._createSelectorElement(text,currentMatching));}
  205. return fragment;}
  206. _markSelectorHighlights(){const selectors=this._selectorElement.getElementsByClassName('simple-selector');const regex=this._parentPane.filterRegex();for(let i=0;i<selectors.length;++i){const selectorMatchesFilter=!!regex&&regex.test(selectors[i].textContent);selectors[i].classList.toggle('filter-match',selectorMatchesFilter);}}
  207. _checkWillCancelEditing(){const willCauseCancelEditing=this._willCauseCancelEditing;this._willCauseCancelEditing=false;return willCauseCancelEditing;}
  208. _handleSelectorContainerClick(event){if(this._checkWillCancelEditing()||!this.editable){return;}
  209. if(event.target===this._selectorContainer){this.addNewBlankProperty(0).startEditing();event.consume(true);}}
  210. addNewBlankProperty(index=this.propertiesTreeOutline.rootElement().childCount()){const property=this._style.newBlankProperty(index);const item=new Elements.StylePropertyTreeElement(this._parentPane,this._matchedStyles,property,false,false,false,true);this.propertiesTreeOutline.insertChild(item,property.index);return item;}
  211. _handleEmptySpaceMouseDown(){this._willCauseCancelEditing=this._parentPane._isEditingStyle;this._selectedSinceMouseDown=false;}
  212. _handleEmptySpaceClick(event){if(!this.editable||this.element.hasSelection()||this._checkWillCancelEditing()||this._selectedSinceMouseDown){return;}
  213. if(event.target.classList.contains('header')||this.element.classList.contains('read-only')||event.target.enclosingNodeOrSelfWithClass('media')){event.consume();return;}
  214. const deepTarget=event.deepElementFromPoint();if(deepTarget.treeElement){this.addNewBlankProperty(deepTarget.treeElement.property.index+1).startEditing();}else{this.addNewBlankProperty().startEditing();}
  215. event.consume(true);}
  216. _handleMediaRuleClick(media,element,event){if(UI.isBeingEdited(element)){return;}
  217. if(UI.KeyboardShortcut.eventHasCtrlOrMeta((event))&&this.navigable){const location=media.rawLocation();if(!location){event.consume(true);return;}
  218. const uiLocation=Bindings.cssWorkspaceBinding.rawLocationToUILocation(location);if(uiLocation){Common.Revealer.reveal(uiLocation);}
  219. event.consume(true);return;}
  220. if(!this.editable){return;}
  221. const config=new UI.InplaceEditor.Config(this._editingMediaCommitted.bind(this,media),this._editingMediaCancelled.bind(this,element),undefined,this._editingMediaBlurHandler.bind(this));UI.InplaceEditor.startEditing(element,config);element.getComponentSelection().selectAllChildren(element);this._parentPane.setEditingStyle(true);const parentMediaElement=element.enclosingNodeOrSelfWithClass('media');parentMediaElement.classList.add('editing-media');event.consume(true);}
  222. _editingMediaFinished(element){this._parentPane.setEditingStyle(false);const parentMediaElement=element.enclosingNodeOrSelfWithClass('media');parentMediaElement.classList.remove('editing-media');}
  223. _editingMediaCancelled(element){this._editingMediaFinished(element);this._markSelectorMatches();element.getComponentSelection().collapse(element,0);}
  224. _editingMediaBlurHandler(editor,blurEvent){return true;}
  225. _editingMediaCommitted(media,element,newContent,oldContent,context,moveDirection){this._parentPane.setEditingStyle(false);this._editingMediaFinished(element);if(newContent){newContent=newContent.trim();}
  226. function userCallback(success){if(success){this._matchedStyles.resetActiveProperties();this._parentPane._refreshUpdate(this);}
  227. this._parentPane.setUserOperation(false);this._editingMediaTextCommittedForTest();}
  228. this._parentPane.setUserOperation(true);this._parentPane.cssModel().setMediaText(media.styleSheetId,media.range,newContent).then(userCallback.bind(this));}
  229. _editingMediaTextCommittedForTest(){}
  230. _handleSelectorClick(event){if(UI.KeyboardShortcut.eventHasCtrlOrMeta((event))&&this.navigable&&event.target.classList.contains('simple-selector')){this._navigateToSelectorSource(event.target._selectorIndex,true);event.consume(true);return;}
  231. if(this.element.hasSelection()){return;}
  232. this._startEditingAtFirstPosition();event.consume(true);}
  233. _navigateToSelectorSource(index,focus){const cssModel=this._parentPane.cssModel();const rule=this._style.parentRule;const header=cssModel.styleSheetHeaderForId((rule.styleSheetId));if(!header){return;}
  234. const rawLocation=new SDK.CSSLocation(header,rule.lineNumberInSource(index),rule.columnNumberInSource(index));StylePropertiesSection._revealSelectorSource(rawLocation,focus);}
  235. static _revealSelectorSource(rawLocation,focus){const uiLocation=Bindings.cssWorkspaceBinding.rawLocationToUILocation(rawLocation);if(uiLocation){Common.Revealer.reveal(uiLocation,!focus);}}
  236. _startEditingAtFirstPosition(){if(!this.editable){return;}
  237. if(!this._style.parentRule){this.moveEditorFromSelector('forward');return;}
  238. this.startEditingSelector();}
  239. startEditingSelector(){const element=this._selectorElement;if(UI.isBeingEdited(element)){return;}
  240. element.scrollIntoViewIfNeeded(false);element.textContent=element.textContent.replace(/\s+/g,' ').trim();const config=new UI.InplaceEditor.Config(this.editingSelectorCommitted.bind(this),this.editingSelectorCancelled.bind(this));UI.InplaceEditor.startEditing(this._selectorElement,config);element.getComponentSelection().selectAllChildren(element);this._parentPane.setEditingStyle(true);if(element.classList.contains('simple-selector')){this._navigateToSelectorSource(0,false);}}
  241. moveEditorFromSelector(moveDirection){this._markSelectorMatches();if(!moveDirection){return;}
  242. if(moveDirection==='forward'){let firstChild=this.propertiesTreeOutline.firstChild();while(firstChild&&firstChild.inherited()){firstChild=firstChild.nextSibling;}
  243. if(!firstChild){this.addNewBlankProperty().startEditing();}else{firstChild.startEditing(firstChild.nameElement);}}else{const previousSection=this.previousEditableSibling();if(!previousSection){return;}
  244. previousSection.addNewBlankProperty().startEditing();}}
  245. editingSelectorCommitted(element,newContent,oldContent,context,moveDirection){this._editingSelectorEnded();if(newContent){newContent=newContent.trim();}
  246. if(newContent===oldContent){this._selectorElement.textContent=newContent;this.moveEditorFromSelector(moveDirection);return;}
  247. const rule=this._style.parentRule;if(!rule){return;}
  248. function headerTextCommitted(){this._parentPane.setUserOperation(false);this.moveEditorFromSelector(moveDirection);this._editingSelectorCommittedForTest();}
  249. this._parentPane.setUserOperation(true);this._setHeaderText(rule,newContent).then(headerTextCommitted.bind(this));}
  250. _setHeaderText(rule,newContent){function onSelectorsUpdated(rule,success){if(!success){return Promise.resolve();}
  251. return this._matchedStyles.recomputeMatchingSelectors(rule).then(updateSourceRanges.bind(this,rule));}
  252. function updateSourceRanges(rule){const doesAffectSelectedNode=this._matchedStyles.matchingSelectors(rule).length>0;this.propertiesTreeOutline.element.classList.toggle('no-affect',!doesAffectSelectedNode);this._matchedStyles.resetActiveProperties();this._parentPane._refreshUpdate(this);}
  253. console.assert(rule instanceof SDK.CSSStyleRule);const oldSelectorRange=rule.selectorRange();if(!oldSelectorRange){return Promise.resolve();}
  254. return rule.setSelectorText(newContent).then(onSelectorsUpdated.bind(this,(rule),oldSelectorRange));}
  255. _editingSelectorCommittedForTest(){}
  256. _updateRuleOrigin(){this._selectorRefElement.removeChildren();this._selectorRefElement.appendChild(StylePropertiesSection.createRuleOriginNode(this._matchedStyles,this._parentPane._linkifier,this._style.parentRule));}
  257. _editingSelectorEnded(){this._parentPane.setEditingStyle(false);}
  258. editingSelectorCancelled(){this._editingSelectorEnded();this._markSelectorMatches();}}
  259. StylePropertiesSection.MaxProperties=50;export class BlankStylePropertiesSection extends StylePropertiesSection{constructor(stylesPane,matchedStyles,defaultSelectorText,styleSheetId,ruleLocation,insertAfterStyle){const cssModel=(stylesPane.cssModel());const rule=SDK.CSSStyleRule.createDummyRule(cssModel,defaultSelectorText);super(stylesPane,matchedStyles,rule.style);this._normal=false;this._ruleLocation=ruleLocation;this._styleSheetId=styleSheetId;this._selectorRefElement.removeChildren();this._selectorRefElement.appendChild(StylePropertiesSection._linkifyRuleLocation(cssModel,this._parentPane._linkifier,styleSheetId,this._actualRuleLocation()));if(insertAfterStyle&&insertAfterStyle.parentRule){this._createMediaList(insertAfterStyle.parentRule.media);}
  260. this.element.classList.add('blank-section');}
  261. _actualRuleLocation(){const prefix=this._rulePrefix();const lines=prefix.split('\n');const editRange=new TextUtils.TextRange(0,0,lines.length-1,lines.peekLast().length);return this._ruleLocation.rebaseAfterTextEdit(TextUtils.TextRange.createFromLocation(0,0),editRange);}
  262. _rulePrefix(){return this._ruleLocation.startLine===0&&this._ruleLocation.startColumn===0?'':'\n\n';}
  263. get isBlank(){return!this._normal;}
  264. editingSelectorCommitted(element,newContent,oldContent,context,moveDirection){if(!this.isBlank){super.editingSelectorCommitted(element,newContent,oldContent,context,moveDirection);return;}
  265. function onRuleAdded(newRule){if(!newRule){this.editingSelectorCancelled();this._editingSelectorCommittedForTest();return Promise.resolve();}
  266. return this._matchedStyles.addNewRule(newRule,this._matchedStyles.node()).then(onAddedToCascade.bind(this,newRule));}
  267. function onAddedToCascade(newRule){const doesSelectorAffectSelectedNode=this._matchedStyles.matchingSelectors(newRule).length>0;this._makeNormal(newRule);if(!doesSelectorAffectSelectedNode){this.propertiesTreeOutline.element.classList.add('no-affect');}
  268. this._updateRuleOrigin();this._parentPane.setUserOperation(false);this._editingSelectorEnded();if(this.element.parentElement)
  269. {this.moveEditorFromSelector(moveDirection);}
  270. this._markSelectorMatches();this._editingSelectorCommittedForTest();}
  271. if(newContent){newContent=newContent.trim();}
  272. this._parentPane.setUserOperation(true);const cssModel=this._parentPane.cssModel();const ruleText=this._rulePrefix()+newContent+' {}';cssModel.addRule(this._styleSheetId,ruleText,this._ruleLocation).then(onRuleAdded.bind(this));}
  273. editingSelectorCancelled(){this._parentPane.setUserOperation(false);if(!this.isBlank){super.editingSelectorCancelled();return;}
  274. this._editingSelectorEnded();this._parentPane.removeSection(this);}
  275. _makeNormal(newRule){this.element.classList.remove('blank-section');this._style=newRule.style;this._normal=true;}}
  276. export class KeyframePropertiesSection extends StylePropertiesSection{constructor(stylesPane,matchedStyles,style){super(stylesPane,matchedStyles,style);this._selectorElement.className='keyframe-key';}
  277. _headerText(){return this._style.parentRule.key().text;}
  278. _setHeaderText(rule,newContent){function updateSourceRanges(success){if(!success){return;}
  279. this._parentPane._refreshUpdate(this);}
  280. console.assert(rule instanceof SDK.CSSKeyframeRule);const oldRange=rule.key().range;if(!oldRange){return Promise.resolve();}
  281. return rule.setKeyText(newContent).then(updateSourceRanges.bind(this));}
  282. isPropertyInherited(propertyName){return false;}
  283. _isPropertyOverloaded(property){return false;}
  284. _markSelectorHighlights(){}
  285. _markSelectorMatches(){this._selectorElement.textContent=this._style.parentRule.key().text;}
  286. _highlight(){}}
  287. export class CSSPropertyPrompt extends UI.TextPrompt{constructor(treeElement,isEditingName){super();this.initialize(this._buildPropertyCompletions.bind(this),UI.StyleValueDelimiters);this._isColorAware=SDK.cssMetadata().isColorAwareProperty(treeElement.property.name);this._cssCompletions=[];if(isEditingName){this._cssCompletions=SDK.cssMetadata().allProperties();if(!treeElement.node().isSVGNode()){this._cssCompletions=this._cssCompletions.filter(property=>!SDK.cssMetadata().isSVGProperty(property));}}else{this._cssCompletions=SDK.cssMetadata().propertyValues(treeElement.nameElement.textContent);}
  288. this._treeElement=treeElement;this._isEditingName=isEditingName;this._cssVariables=treeElement.matchedStyles().availableCSSVariables(treeElement.property.ownerStyle);if(this._cssVariables.length<1000){this._cssVariables.sort(String.naturalOrderComparator);}else{this._cssVariables.sort();}
  289. if(!isEditingName){this.disableDefaultSuggestionForEmptyInput();if(treeElement&&treeElement.valueElement){const cssValueText=treeElement.valueElement.textContent;const cmdOrCtrl=Host.isMac()?'Cmd':'Ctrl';if(cssValueText.match(/#[\da-f]{3,6}$/i)){this.setTitle(ls`Increment/decrement with mousewheel or up/down keys. ${cmdOrCtrl}: R ±1, Shift: G ±1, Alt: B ±1`);}else if(cssValueText.match(/\d+/)){this.setTitle(ls`Increment/decrement with mousewheel or up/down keys. ${cmdOrCtrl}: ±100, Shift: ±10, Alt: ±0.1`);}}}}
  290. onKeyDown(event){switch(event.key){case'ArrowUp':case'ArrowDown':case'PageUp':case'PageDown':if(!this.isSuggestBoxVisible()&&this._handleNameOrValueUpDown(event)){event.preventDefault();return;}
  291. break;case'Enter':if(event.shiftKey){return;}
  292. this.tabKeyPressed();event.preventDefault();return;}
  293. super.onKeyDown(event);}
  294. onMouseWheel(event){if(this._handleNameOrValueUpDown(event)){event.consume(true);return;}
  295. super.onMouseWheel(event);}
  296. tabKeyPressed(){this.acceptAutoComplete();return false;}
  297. _handleNameOrValueUpDown(event){function finishHandler(originalValue,replacementString){this._treeElement.applyStyleText(this._treeElement.nameElement.textContent+': '+this._treeElement.valueElement.textContent,false);}
  298. function customNumberHandler(prefix,number,suffix){if(number!==0&&!suffix.length&&SDK.cssMetadata().isLengthProperty(this._treeElement.property.name)){suffix='px';}
  299. return prefix+number+suffix;}
  300. if(!this._isEditingName&&this._treeElement.valueElement&&UI.handleElementValueModifications(event,this._treeElement.valueElement,finishHandler.bind(this),this._isValueSuggestion.bind(this),customNumberHandler.bind(this))){return true;}
  301. return false;}
  302. _isValueSuggestion(word){if(!word){return false;}
  303. word=word.toLowerCase();return this._cssCompletions.indexOf(word)!==-1||word.startsWith('--');}
  304. _buildPropertyCompletions(expression,query,force){const lowerQuery=query.toLowerCase();const editingVariable=!this._isEditingName&&expression.trim().endsWith('var(');if(!query&&!force&&!editingVariable&&(this._isEditingName||expression)){return Promise.resolve([]);}
  305. const prefixResults=[];const anywhereResults=[];if(!editingVariable){this._cssCompletions.forEach(completion=>filterCompletions.call(this,completion,false));}
  306. if(this._isEditingName){const nameValuePresets=SDK.cssMetadata().nameValuePresets(this._treeElement.node().isSVGNode());nameValuePresets.forEach(preset=>filterCompletions.call(this,preset,false,true));}
  307. if(this._isEditingName||editingVariable){this._cssVariables.forEach(variable=>filterCompletions.call(this,variable,true));}
  308. const results=prefixResults.concat(anywhereResults);if(!this._isEditingName&&!results.length&&query.length>1&&'!important'.startsWith(lowerQuery)){results.push({text:'!important'});}
  309. const userEnteredText=query.replace('-','');if(userEnteredText&&(userEnteredText===userEnteredText.toUpperCase())){for(let i=0;i<results.length;++i){if(!results[i].text.startsWith('--')){results[i].text=results[i].text.toUpperCase();}}}
  310. results.forEach(result=>{if(editingVariable){result.title=result.text;result.text+=')';return;}
  311. const valuePreset=SDK.cssMetadata().getValuePreset(this._treeElement.name,result.text);if(!this._isEditingName&&valuePreset){result.title=result.text;result.text=valuePreset.text;result.selectionRange={startColumn:valuePreset.startColumn,endColumn:valuePreset.endColumn};}});if(this._isColorAware&&!this._isEditingName){results.sort((a,b)=>{if(!!a.subtitleRenderer===!!b.subtitleRenderer){return 0;}
  312. return a.subtitleRenderer?-1:1;});}
  313. return Promise.resolve(results);function filterCompletions(completion,variable,nameValue){const index=completion.toLowerCase().indexOf(lowerQuery);const result={text:completion};if(variable){const computedValue=this._treeElement.matchedStyles().computeCSSVariable(this._treeElement.property.ownerStyle,completion);if(computedValue){const color=Common.Color.parse(computedValue);if(color){result.subtitleRenderer=swatchRenderer.bind(null,color);}}}
  314. if(nameValue){result.hideGhostText=true;}
  315. if(index===0){result.priority=this._isEditingName?SDK.cssMetadata().propertyUsageWeight(completion):1;prefixResults.push(result);}else if(index>-1){anywhereResults.push(result);}}
  316. function swatchRenderer(color){const swatch=InlineEditor.ColorSwatch.create();swatch.hideText(true);swatch.setColor(color);swatch.style.pointerEvents='none';return swatch;}}}
  317. export class StylesSidebarPropertyRenderer{constructor(rule,node,name,value){this._rule=rule;this._node=node;this._propertyName=name;this._propertyValue=value;this._colorHandler=null;this._bezierHandler=null;this._shadowHandler=null;this._gridHandler=null;this._varHandler=createTextNode;}
  318. setColorHandler(handler){this._colorHandler=handler;}
  319. setBezierHandler(handler){this._bezierHandler=handler;}
  320. setShadowHandler(handler){this._shadowHandler=handler;}
  321. setGridHandler(handler){this._gridHandler=handler;}
  322. setVarHandler(handler){this._varHandler=handler;}
  323. renderName(){const nameElement=createElement('span');nameElement.className='webkit-css-property';nameElement.textContent=this._propertyName;nameElement.normalize();return nameElement;}
  324. renderValue(){const valueElement=createElement('span');valueElement.className='value';if(!this._propertyValue){return valueElement;}
  325. if(this._shadowHandler&&(this._propertyName==='box-shadow'||this._propertyName==='text-shadow'||this._propertyName==='-webkit-box-shadow')&&!SDK.CSSMetadata.VariableRegex.test(this._propertyValue)){valueElement.appendChild(this._shadowHandler(this._propertyValue,this._propertyName));valueElement.normalize();return valueElement;}
  326. if(this._gridHandler&&SDK.cssMetadata().isGridAreaDefiningProperty(this._propertyName)){valueElement.appendChild(this._gridHandler(this._propertyValue,this._propertyName));valueElement.normalize();return valueElement;}
  327. const regexes=[SDK.CSSMetadata.VariableRegex,SDK.CSSMetadata.URLRegex];const processors=[this._varHandler,this._processURL.bind(this)];if(this._bezierHandler&&SDK.cssMetadata().isBezierAwareProperty(this._propertyName)){regexes.push(UI.Geometry.CubicBezier.Regex);processors.push(this._bezierHandler);}
  328. if(this._colorHandler&&SDK.cssMetadata().isColorAwareProperty(this._propertyName)){regexes.push(Common.Color.Regex);processors.push(this._colorHandler);}
  329. const results=TextUtils.TextUtils.splitStringByRegexes(this._propertyValue,regexes);for(let i=0;i<results.length;i++){const result=results[i];const processor=result.regexIndex===-1?createTextNode:processors[result.regexIndex];valueElement.appendChild(processor(result.value));}
  330. valueElement.normalize();return valueElement;}
  331. _processURL(text){let url=text.substring(4,text.length-1).trim();const isQuoted=/^'.*'$/.test(url)||/^".*"$/.test(url);if(isQuoted){url=url.substring(1,url.length-1);}
  332. const container=createDocumentFragment();container.createTextChild('url(');let hrefUrl=null;if(this._rule&&this._rule.resourceURL()){hrefUrl=Common.ParsedURL.completeURL(this._rule.resourceURL(),url);}else if(this._node){hrefUrl=this._node.resolveURL(url);}
  333. container.appendChild(Components.Linkifier.linkifyURL(hrefUrl||url,{text:url,preventClick:true}));container.createTextChild(')');return container;}}
  334. export class ButtonProvider{constructor(){this._button=new UI.ToolbarButton(Common.UIString('New Style Rule'),'largeicon-add');this._button.addEventListener(UI.ToolbarButton.Events.Click,this._clicked,this);const longclickTriangle=UI.Icon.create('largeicon-longclick-triangle','long-click-glyph');this._button.element.appendChild(longclickTriangle);new UI.LongClickController(this._button.element,this._longClicked.bind(this));UI.context.addFlavorChangeListener(SDK.DOMNode,onNodeChanged.bind(this));onNodeChanged.call(this);function onNodeChanged(){let node=UI.context.flavor(SDK.DOMNode);node=node?node.enclosingElementOrSelf():null;this._button.setEnabled(!!node);}}
  335. _clicked(event){StylesSidebarPane._instance._createNewRuleInViaInspectorStyleSheet();}
  336. _longClicked(e){StylesSidebarPane._instance._onAddButtonLongClick(e);}
  337. item(){return this._button;}}
  338. self.Elements=self.Elements||{};Elements=Elements||{};Elements.StylesSidebarPane=StylesSidebarPane;Elements.StylesSidebarPane._maxLinkLength=_maxLinkLength;Elements.StylesSidebarPane.CSSPropertyPrompt=CSSPropertyPrompt;Elements.StylesSidebarPane.ButtonProvider=ButtonProvider;Elements.SectionBlock=SectionBlock;Elements.StylePropertiesSection=StylePropertiesSection;Elements.BlankStylePropertiesSection=BlankStylePropertiesSection;Elements.KeyframePropertiesSection=KeyframePropertiesSection;Elements.StylesSidebarPropertyRenderer=StylesSidebarPropertyRenderer;