@@ -51,6 +51,9 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
51
51
this . _boundNodeChangedAnimationEnd = this . _nodeChangedAnimationEnd . bind ( this ) ;
52
52
53
53
node . addEventListener ( WI . DOMNode . Event . EnabledPseudoClassesChanged , this . _nodePseudoClassesDidChange , this ) ;
54
+
55
+ this . _ignoreSingleTextChild = false ;
56
+ this . _forceUpdateTitle = false ;
54
57
}
55
58
56
59
// Static
@@ -825,7 +828,12 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
825
828
{
826
829
let node = this . representedObject ;
827
830
828
- // FIXME: <https://webkit.org/b/179042> Web Inspector: add contextmenu item to arbitrarily add HTML/Child to DOMTree
831
+ let isEditableNode = node . nodeType ( ) === Node . ELEMENT_NODE && this . editable ;
832
+ let forbiddenClosingTag = WI . DOMTreeElement . ForbiddenClosingTagElements . has ( node . nodeNameInCorrectCase ( ) ) ;
833
+ subMenus . add . appendItem ( WI . UIString ( "Child" ) , this . _addHTML . bind ( this ) , forbiddenClosingTag || ! isEditableNode ) ;
834
+ subMenus . add . appendItem ( WI . UIString ( "Previous Sibling" ) , this . _addPreviousSibling . bind ( this ) , ! isEditableNode ) ;
835
+ subMenus . add . appendItem ( WI . UIString ( "Next Sibling" ) , this . _addNextSibling . bind ( this ) , ! isEditableNode ) ;
836
+
829
837
subMenus . edit . appendItem ( WI . UIString ( "HTML" ) , this . _editAsHTML . bind ( this ) , ! this . editable ) ;
830
838
subMenus . copy . appendItem ( WI . UIString ( "HTML" ) , this . _copyHTML . bind ( this ) , node . isPseudoElement ( ) ) ;
831
839
subMenus . delete . appendItem ( WI . UIString ( "Node" ) , this . remove . bind ( this ) , ! this . editable ) ;
@@ -950,7 +958,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
950
958
}
951
959
952
960
var tagName = tagNameElement . textContent ;
953
- if ( WI . DOMTreeElement . EditTagBlacklist [ tagName . toLowerCase ( ) ] )
961
+ if ( WI . DOMTreeElement . EditTagBlacklist . has ( tagName . toLowerCase ( ) ) )
954
962
return false ;
955
963
956
964
if ( WI . isBeingEdited ( tagNameElement ) )
@@ -988,27 +996,39 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
988
996
return true ;
989
997
}
990
998
991
- _startEditingAsHTML ( commitCallback , error , initialValue )
999
+ _startEditingAsHTML ( commitCallback , options = { } )
992
1000
{
993
- if ( error )
994
- return ;
995
1001
if ( this . _htmlEditElement && WI . isBeingEdited ( this . _htmlEditElement ) )
996
1002
return ;
997
1003
998
- this . _htmlEditElement = document . createElement ( "div" ) ;
999
- this . _htmlEditElement . textContent = initialValue ;
1004
+ if ( options . hideExistingElements ) {
1005
+ let child = this . listItemElement . firstChild ;
1006
+ while ( child ) {
1007
+ child . style . display = "none" ;
1008
+ child = child . nextSibling ;
1009
+ }
1010
+ if ( this . _childrenListNode )
1011
+ this . _childrenListNode . style . display = "none" ;
1012
+ }
1013
+
1014
+ let positionInside = options . position === "afterbegin" || options . position === "beforeend" ;
1015
+ if ( positionInside && this . _childrenListNode ) {
1016
+ this . _htmlEditElement = document . createElement ( "li" ) ;
1017
+
1018
+ let referenceNode = options . position === "afterbegin" ? this . _childrenListNode . firstElementChild : this . _childrenListNode . lastElementChild ;
1019
+ this . _childrenListNode . insertBefore ( this . _htmlEditElement , referenceNode ) ;
1020
+ } else if ( options . position && ! positionInside ) {
1021
+ this . _htmlEditElement = document . createElement ( "li" ) ;
1000
1022
1001
- // Hide header items.
1002
- var child = this . listItemElement . firstChild ;
1003
- while ( child ) {
1004
- child . style . display = "none" ;
1005
- child = child . nextSibling ;
1023
+ let targetNode = ( options . position === "afterend" && this . _childrenListNode ) ? this . _childrenListNode : this . listItemElement ;
1024
+ targetNode . insertAdjacentElement ( options . position , this . _htmlEditElement ) ;
1025
+ } else {
1026
+ this . _htmlEditElement = document . createElement ( "div" ) ;
1027
+ this . listItemElement . appendChild ( this . _htmlEditElement ) ;
1006
1028
}
1007
- // Hide children item.
1008
- if ( this . _childrenListNode )
1009
- this . _childrenListNode . style . display = "none" ;
1010
- // Append editor.
1011
- this . listItemElement . appendChild ( this . _htmlEditElement ) ;
1029
+
1030
+ if ( options . initialValue )
1031
+ this . _htmlEditElement . textContent = options . initialValue ;
1012
1032
1013
1033
this . updateSelectionArea ( ) ;
1014
1034
@@ -1023,16 +1043,17 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1023
1043
this . _editing = false ;
1024
1044
1025
1045
// Remove editor.
1026
- this . listItemElement . removeChild ( this . _htmlEditElement ) ;
1046
+ this . _htmlEditElement . remove ( ) ;
1027
1047
this . _htmlEditElement = null ;
1028
- // Unhide children item.
1029
- if ( this . _childrenListNode )
1030
- this . _childrenListNode . style . removeProperty ( "display" ) ;
1031
- // Unhide header items.
1032
- var child = this . listItemElement . firstChild ;
1033
- while ( child ) {
1034
- child . style . removeProperty ( "display" ) ;
1035
- child = child . nextSibling ;
1048
+
1049
+ if ( options . hideExistingElements ) {
1050
+ if ( this . _childrenListNode )
1051
+ this . _childrenListNode . style . removeProperty ( "display" ) ;
1052
+ let child = this . listItemElement . firstChild ;
1053
+ while ( child ) {
1054
+ child . style . removeProperty ( "display" ) ;
1055
+ child = child . nextSibling ;
1056
+ }
1036
1057
}
1037
1058
1038
1059
this . updateSelectionArea ( ) ;
@@ -1041,6 +1062,16 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1041
1062
var config = new WI . EditingConfig ( commit . bind ( this ) , dispose . bind ( this ) ) ;
1042
1063
config . setMultiline ( true ) ;
1043
1064
this . _editing = WI . startEditing ( this . _htmlEditElement , config ) ;
1065
+
1066
+ if ( ! isNaN ( options . startPosition ) ) {
1067
+ let range = document . createRange ( ) ;
1068
+ range . setStart ( this . _htmlEditElement . firstChild , options . startPosition ) ;
1069
+ range . collapse ( true ) ;
1070
+
1071
+ let selection = window . getSelection ( ) ;
1072
+ selection . removeAllRanges ( ) ;
1073
+ selection . addRange ( range ) ;
1074
+ }
1044
1075
}
1045
1076
1046
1077
_attributeEditingCommitted ( element , newText , oldText , attributeName , moveDirection )
@@ -1220,7 +1251,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1220
1251
{
1221
1252
// If we are editing, return early to prevent canceling the edit.
1222
1253
// After editing is committed updateTitle will be called.
1223
- if ( this . _editing )
1254
+ if ( this . _editing && ! this . _forceUpdateTitle )
1224
1255
return ;
1225
1256
1226
1257
if ( onlySearchQueryChanged ) {
@@ -1388,7 +1419,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1388
1419
var textChild = this . _singleTextChild ( node ) ;
1389
1420
var showInlineText = textChild && textChild . nodeValue ( ) . length < WI . DOMTreeElement . MaximumInlineTextChildLength ;
1390
1421
1391
- if ( ! this . expanded && ( ! showInlineText && ( this . treeOutline . isXMLMimeType || ! WI . DOMTreeElement . ForbiddenClosingTagElements [ tagName ] ) ) ) {
1422
+ if ( ! this . expanded && ( ! showInlineText && ( this . treeOutline . isXMLMimeType || ! WI . DOMTreeElement . ForbiddenClosingTagElements . has ( tagName ) ) ) ) {
1392
1423
if ( this . hasChildren ) {
1393
1424
var textNodeElement = info . titleDOM . createChild ( "span" , "html-text-node" ) ;
1394
1425
textNodeElement . textContent = ellipsis ;
@@ -1473,7 +1504,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1473
1504
1474
1505
_singleTextChild ( node )
1475
1506
{
1476
- if ( ! node )
1507
+ if ( ! node || this . _ignoreSingleTextChild )
1477
1508
return null ;
1478
1509
1479
1510
var firstChild = node . firstChild ;
@@ -1564,6 +1595,80 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1564
1595
this . representedObject . removeNode ( removeNodeCallback ) ;
1565
1596
}
1566
1597
1598
+ _insertAdjacentHTML ( position , options = { } )
1599
+ {
1600
+ let hasChildren = this . hasChildren ;
1601
+
1602
+ let commitCallback = ( value ) => {
1603
+ this . _ignoreSingleTextChild = false ;
1604
+
1605
+ if ( ! value . length ) {
1606
+ if ( ! hasChildren ) {
1607
+ this . _forceUpdateTitle = true ;
1608
+ this . hasChildren = false ;
1609
+ this . _forceUpdateTitle = false ;
1610
+ }
1611
+ return ;
1612
+ }
1613
+
1614
+ this . representedObject . insertAdjacentHTML ( position , value ) ;
1615
+ } ;
1616
+
1617
+ if ( position === "afterbegin" || position === "beforeend" ) {
1618
+ this . _ignoreSingleTextChild = true ;
1619
+ this . hasChildren = true ;
1620
+ this . expand ( ) ;
1621
+ }
1622
+
1623
+ this . _startEditingAsHTML ( commitCallback , Object . shallowMerge ( options , { position} ) ) ;
1624
+ }
1625
+
1626
+ _addHTML ( event )
1627
+ {
1628
+ let options = { } ;
1629
+ switch ( this . representedObject . nodeNameInCorrectCase ( ) ) {
1630
+ case "ul" :
1631
+ case "ol" :
1632
+ options . initialValue = "<li></li>" ;
1633
+ options . startPosition = 4 ;
1634
+ break ;
1635
+ case "table" :
1636
+ case "thead" :
1637
+ case "tbody" :
1638
+ case "tfoot" :
1639
+ options . initialValue = "<tr></tr>" ;
1640
+ options . startPosition = 4 ;
1641
+ break ;
1642
+ case "tr" :
1643
+ options . initializing = "<td></td>" ;
1644
+ options . startPosition = 4 ;
1645
+ break ;
1646
+ }
1647
+ this . _insertAdjacentHTML ( "beforeend" , options ) ;
1648
+ }
1649
+
1650
+ _addPreviousSibling ( event )
1651
+ {
1652
+ let options = { } ;
1653
+ let nodeName = this . representedObject . nodeNameInCorrectCase ( ) ;
1654
+ if ( nodeName === "li" || nodeName === "tr" || nodeName === "th" || nodeName === "td" ) {
1655
+ options . initialValue = `<${ nodeName } ></${ nodeName } >` ;
1656
+ options . startPosition = nodeName . length + 2 ;
1657
+ }
1658
+ this . _insertAdjacentHTML ( "beforebegin" , options ) ;
1659
+ }
1660
+
1661
+ _addNextSibling ( event )
1662
+ {
1663
+ let options = { } ;
1664
+ let nodeName = this . representedObject . nodeNameInCorrectCase ( ) ;
1665
+ if ( nodeName === "li" || nodeName === "tr" || nodeName === "th" || nodeName === "td" ) {
1666
+ options . initialValue = `<${ nodeName } ></${ nodeName } >` ;
1667
+ options . startPosition = nodeName . length + 2 ;
1668
+ }
1669
+ this . _insertAdjacentHTML ( "afterend" , options ) ;
1670
+ }
1671
+
1567
1672
_editAsHTML ( )
1568
1673
{
1569
1674
var treeOutline = this . treeOutline ;
@@ -1598,7 +1703,15 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
1598
1703
node . setOuterHTML ( value , selectNode ) ;
1599
1704
}
1600
1705
1601
- node . getOuterHTML ( this . _startEditingAsHTML . bind ( this , commitChange ) ) ;
1706
+ node . getOuterHTML ( ( error , initialValue ) => {
1707
+ if ( error )
1708
+ return ;
1709
+
1710
+ this . _startEditingAsHTML ( commitChange , {
1711
+ initialValue,
1712
+ hideExistingElements : true ,
1713
+ } ) ;
1714
+ } ) ;
1602
1715
}
1603
1716
1604
1717
_copyHTML ( )
@@ -1775,20 +1888,16 @@ WI.DOMTreeElement.MaximumInlineTextChildLength = 80;
1775
1888
1776
1889
// A union of HTML4 and HTML5-Draft elements that explicitly
1777
1890
// or implicitly (for HTML5) forbid the closing tag.
1778
- WI . DOMTreeElement . ForbiddenClosingTagElements = [
1891
+ WI . DOMTreeElement . ForbiddenClosingTagElements = new Set ( [
1779
1892
"area" , "base" , "basefont" , "br" , "canvas" , "col" , "command" , "embed" , "frame" ,
1780
1893
"hr" , "img" , "input" , "keygen" , "link" , "meta" , "param" , "source" ,
1781
1894
"wbr" , "track" , "menuitem"
1782
- ] . keySet ( ) ;
1895
+ ] ) ;
1783
1896
1784
1897
// These tags we do not allow editing their tag name.
1785
- WI . DOMTreeElement . EditTagBlacklist = [
1898
+ WI . DOMTreeElement . EditTagBlacklist = new Set ( [
1786
1899
"html" , "head" , "body"
1787
- ] . keySet ( ) ;
1788
-
1789
- WI . DOMTreeElement . ChangeType = {
1790
- Attribute : "dom-tree-element-change-type-attribute"
1791
- } ;
1900
+ ] ) ;
1792
1901
1793
1902
WI . DOMTreeElement . BreakpointStatus = {
1794
1903
None : Symbol ( "none" ) ,
0 commit comments