@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refine more Differential review state behaviors

Summary:
Ref T13516.

- Add an "Add Comment" navigation anchor.
- Make selection state more clear.
- Make hidden state tidier and more clear.
- Hide "View Options" in the hidden state to dodge all the weird behaviors it implies.
- Click to select/deselect changesets.
- When you open the view dropdown menu, then press "h", close the dropdown menu.

Test Plan: Fiddled with all these behaviors.

Maniphest Tasks: T13516

Differential Revision: https://secure.phabricator.com/D21161

+202 -103
+31 -30
resources/celerity/map.php
··· 11 11 'conpherence.pkg.js' => '020aebcf', 12 12 'core.pkg.css' => '61b7e380', 13 13 'core.pkg.js' => 'fc49f65b', 14 - 'differential.pkg.css' => 'cb99cd21', 15 - 'differential.pkg.js' => 'ae77bf85', 14 + 'differential.pkg.css' => '9b5ee013', 15 + 'differential.pkg.js' => '1043ee5a', 16 16 'diffusion.pkg.css' => '42c75c37', 17 17 'diffusion.pkg.js' => 'a98c0bf7', 18 18 'maniphest.pkg.css' => '35995d6d', ··· 62 62 'rsrc/css/application/diff/diff-tree-view.css' => 'e2d3e222', 63 63 'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d', 64 64 'rsrc/css/application/differential/add-comment.css' => '7e5900d9', 65 - 'rsrc/css/application/differential/changeset-view.css' => '489b6995', 65 + 'rsrc/css/application/differential/changeset-view.css' => '5fb26c90', 66 66 'rsrc/css/application/differential/core.css' => '7300a73e', 67 67 'rsrc/css/application/differential/phui-inline-comment.css' => '48acce5b', 68 68 'rsrc/css/application/differential/revision-comment.css' => '7dbc8d1d', ··· 155 155 'rsrc/css/phui/phui-fontkit.css' => '1ec937e5', 156 156 'rsrc/css/phui/phui-form-view.css' => '01b796c0', 157 157 'rsrc/css/phui/phui-form.css' => '1f177cb7', 158 - 'rsrc/css/phui/phui-formation-view.css' => '82a3b73e', 158 + 'rsrc/css/phui/phui-formation-view.css' => '9a1eff7e', 159 159 'rsrc/css/phui/phui-head-thing.css' => 'd7f293df', 160 160 'rsrc/css/phui/phui-header-view.css' => '36c86a58', 161 161 'rsrc/css/phui/phui-hovercard.css' => '6ca90fa0', ··· 378 378 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be', 379 379 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 380 380 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', 381 - 'rsrc/js/application/diff/DiffChangeset.js' => '27305b60', 382 - 'rsrc/js/application/diff/DiffChangesetList.js' => '62a3a351', 381 + 'rsrc/js/application/diff/DiffChangeset.js' => '9a713ba5', 382 + 'rsrc/js/application/diff/DiffChangesetList.js' => 'adf069cd', 383 383 'rsrc/js/application/diff/DiffInline.js' => '16e97ebc', 384 384 'rsrc/js/application/diff/DiffPathView.js' => '8207abf9', 385 385 'rsrc/js/application/diff/DiffTreeView.js' => '5d83623b', ··· 559 559 'conpherence-transaction-css' => '3a3f5e7e', 560 560 'd3' => '9d068042', 561 561 'diff-tree-view-css' => 'e2d3e222', 562 - 'differential-changeset-view-css' => '489b6995', 562 + 'differential-changeset-view-css' => '5fb26c90', 563 563 'differential-core-view-css' => '7300a73e', 564 564 'differential-revision-add-comment-css' => '7e5900d9', 565 565 'differential-revision-comment-css' => '7dbc8d1d', ··· 775 775 'phabricator-darklog' => '3b869402', 776 776 'phabricator-darkmessage' => '26cd4b73', 777 777 'phabricator-dashboard-css' => '5a205b9d', 778 - 'phabricator-diff-changeset' => '27305b60', 779 - 'phabricator-diff-changeset-list' => '62a3a351', 778 + 'phabricator-diff-changeset' => '9a713ba5', 779 + 'phabricator-diff-changeset-list' => 'adf069cd', 780 780 'phabricator-diff-inline' => '16e97ebc', 781 781 'phabricator-diff-path-view' => '8207abf9', 782 782 'phabricator-diff-tree-view' => '5d83623b', ··· 846 846 'phui-fontkit-css' => '1ec937e5', 847 847 'phui-form-css' => '1f177cb7', 848 848 'phui-form-view-css' => '01b796c0', 849 - 'phui-formation-view-css' => '82a3b73e', 849 + 'phui-formation-view-css' => '9a1eff7e', 850 850 'phui-head-thing-view-css' => 'd7f293df', 851 851 'phui-header-view-css' => '36c86a58', 852 852 'phui-hovercard' => '074f0783', ··· 1146 1146 'javelin-json', 1147 1147 'phabricator-prefab', 1148 1148 ), 1149 - '27305b60' => array( 1150 - 'javelin-dom', 1151 - 'javelin-util', 1152 - 'javelin-stratcom', 1153 - 'javelin-install', 1154 - 'javelin-workflow', 1155 - 'javelin-router', 1156 - 'javelin-behavior-device', 1157 - 'javelin-vector', 1158 - 'phabricator-diff-inline', 1159 - 'phabricator-diff-path-view', 1160 - ), 1161 1149 '289bf236' => array( 1162 1150 'javelin-install', 1163 1151 'javelin-util', ··· 1333 1321 'javelin-workflow', 1334 1322 'javelin-dom', 1335 1323 'phabricator-draggable-list', 1336 - ), 1337 - '489b6995' => array( 1338 - 'phui-inline-comment-view-css', 1339 1324 ), 1340 1325 '48fe33d0' => array( 1341 1326 'javelin-behavior', ··· 1518 1503 '5faf27b9' => array( 1519 1504 'phuix-form-control-view', 1520 1505 ), 1506 + '5fb26c90' => array( 1507 + 'phui-inline-comment-view-css', 1508 + ), 1521 1509 '60cd9241' => array( 1522 1510 'javelin-behavior', 1523 1511 ), 1524 - '62a3a351' => array( 1525 - 'javelin-install', 1526 - 'phuix-button-view', 1527 - 'phabricator-diff-tree-view', 1528 - ), 1529 1512 '65bb0011' => array( 1530 1513 'javelin-behavior', 1531 1514 'javelin-dom', ··· 1814 1797 'javelin-request', 1815 1798 'javelin-util', 1816 1799 ), 1800 + '9a713ba5' => array( 1801 + 'javelin-dom', 1802 + 'javelin-util', 1803 + 'javelin-stratcom', 1804 + 'javelin-install', 1805 + 'javelin-workflow', 1806 + 'javelin-router', 1807 + 'javelin-behavior-device', 1808 + 'javelin-vector', 1809 + 'phabricator-diff-inline', 1810 + 'phabricator-diff-path-view', 1811 + 'phuix-button-view', 1812 + ), 1817 1813 '9aae2b66' => array( 1818 1814 'javelin-install', 1819 1815 'javelin-util', ··· 1938 1934 'javelin-request', 1939 1935 'javelin-typeahead-ondemand-source', 1940 1936 'javelin-util', 1937 + ), 1938 + 'adf069cd' => array( 1939 + 'javelin-install', 1940 + 'phuix-button-view', 1941 + 'phabricator-diff-tree-view', 1941 1942 ), 1942 1943 'aec8e38c' => array( 1943 1944 'javelin-dom',
+12 -1
src/applications/differential/engine/DifferentialFileTreeEngine.php
··· 77 77 ->setHref('#')); 78 78 $flank_view->setHead($head_view); 79 79 80 - $tail_view = id(new PHUIListView()) 80 + $tail_view = id(new PHUIListView()); 81 + 82 + if ($viewer->isLoggedIn()) { 83 + $tail_view->addMenuItem( 84 + id(new PHUIListItemView()) 85 + ->setIcon('fa-comment-o') 86 + ->setName(pht('Add Comment')) 87 + ->setKeyCommand('x') 88 + ->setHref('#')); 89 + } 90 + 91 + $tail_view 81 92 ->addMenuItem( 82 93 id(new PHUIListItemView()) 83 94 ->setIcon('fa-chevron-left')
+3 -1
src/applications/differential/view/DifferentialChangesetDetailView.php
··· 270 270 ->setNavigationMarker(true) 271 271 ->render(), 272 272 $buttons, 273 - phutil_tag('h1', 273 + javelin_tag( 274 + 'h1', 274 275 array( 275 276 'class' => 'differential-file-icon-header', 277 + 'sigil' => 'changeset-header', 276 278 ), 277 279 array( 278 280 $icon,
+8 -9
src/applications/differential/view/DifferentialChangesetListView.php
··· 261 261 'Open in Editor' => pht('Open in Editor'), 262 262 'Show All Context' => pht('Show All Context'), 263 263 'All Context Shown' => pht('All Context Shown'), 264 - "Can't Toggle Unloaded File" => pht("Can't Toggle Unloaded File"), 265 264 'Expand File' => pht('Expand File'), 266 - 'Collapse File' => pht('Collapse File'), 265 + 'Hide Changeset' => pht('Hide Changeset'), 267 266 'Show Path in Repository' => pht('Show Path in Repository'), 268 267 'Show Directory in Repository' => pht('Show Directory in Repository'), 269 268 'View Standalone' => pht('View Standalone'), ··· 318 317 'Jump to previous inline comment, including collapsed comments.' => 319 318 pht('Jump to previous inline comment, including collapsed comments.'), 320 319 321 - 'This file content has been collapsed.' => 322 - pht('This file content has been collapsed.'), 323 - 'Show Content' => pht('Show Content'), 324 - 325 - 'Hide or show the current file.' => 326 - pht('Hide or show the current file.'), 320 + 'Hide or show the current changeset.' => 321 + pht('Hide or show the current changeset.'), 327 322 'You must select a file to hide or show.' => 328 323 pht('You must select a file to hide or show.'), 329 324 ··· 365 360 pht('Show path in repository.'), 366 361 'Show directory in repository.' => 367 362 pht('Show directory in repository.'), 363 + 364 + 'Jump to the comment area.' => 365 + pht('Jump to the comment area.'), 366 + 367 + 'Show Changeset' => pht('Show Changeset'), 368 368 ), 369 369 )); 370 370 ··· 439 439 ->setHref(idx($meta, 'detailURI', '#')) 440 440 ->setMetadata($meta) 441 441 ->addSigil('differential-view-options'); 442 - 443 442 } 444 443 445 444 private function appendDefaultQueryParams(PhutilURI $uri, array $params) {
+4
src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php
··· 270 270 271 271 $badge_view = $this->renderBadgeView(); 272 272 273 + $anchor = id(new PhabricatorAnchorView()) 274 + ->setAnchorName('reply'); 275 + 273 276 $comment_box = id(new PHUIObjectBoxView()) 274 277 ->setFlush(true) 275 278 ->addClass('phui-comment-form-view') 276 279 ->addSigil('phui-comment-form') 280 + ->appendChild($anchor) 277 281 ->appendChild( 278 282 phutil_tag( 279 283 'h3',
+16 -18
webroot/rsrc/css/application/differential/changeset-view.css
··· 5 5 6 6 .differential-changeset { 7 7 position: relative; 8 - margin: 0; 9 - padding-top: 16px; 10 8 overflow-x: auto; 11 9 12 10 /* Fixes what seems to be a layout bug in Firefox which causes scrollbars, ··· 312 310 border-top: none; 313 311 } 314 312 315 - .differential-changeset h1 { 313 + .differential-changeset .differential-file-icon-header { 316 314 font-size: {$biggestfontsize}; 317 - padding: 2px 0 20px 12px; 315 + padding: 18px 0 20px 12px; 316 + margin-top: 4px; 318 317 line-height: 20px; 319 318 color: {$blacktext}; 319 + cursor: pointer; 320 320 } 321 321 322 - .device-phone .differential-changeset h1 { 322 + .device-phone .differential-changeset .differential-file-icon-header { 323 323 word-break: break-word; 324 324 margin-right: 8px; 325 325 } ··· 343 343 text-align: center; 344 344 } 345 345 346 - .differential-collapse-undo { 347 - color: {$darkbluetext}; 348 - padding: 12px; 349 - border: 1px solid {$blue}; 350 - text-align: center; 351 - background-color: {$lightblue}; 352 - margin: 8px; 353 - } 354 - 355 - .differential-collapse-undo a { 356 - font-weight: bold; 357 - } 358 - 359 346 .differential-file-icon-header .phui-icon-view { 360 347 display: inline-block; 361 348 margin: 0 6px 2px 0; ··· 369 356 370 357 .differential-changeset-buttons { 371 358 float: right; 359 + margin-top: 16px; 372 360 margin-right: 12px; 373 361 } 374 362 ··· 484 472 -webkit-user-select: none; 485 473 user-select: none; 486 474 } 475 + 476 + .changeset-content-hidden .differential-file-icon-header { 477 + background: {$lightgreybackground}; 478 + color: {$greytext}; 479 + } 480 + 481 + .changeset-selected .differential-file-icon-header { 482 + background: {$lightyellow}; 483 + color: {$blacktext}; 484 + }
+10
webroot/rsrc/css/phui/phui-formation-view.css
··· 181 181 padding: 0; 182 182 color: {$lightgreytext}; 183 183 } 184 + 185 + .phui-flank-view-head .phui-list-view { 186 + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); 187 + padding-bottom: 4px; 188 + } 189 + 190 + .phui-flank-view-tail .phui-list-view { 191 + box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.1); 192 + padding-top: 4px; 193 + }
+78 -28
webroot/rsrc/js/application/diff/DiffChangeset.js
··· 10 10 * javelin-vector 11 11 * phabricator-diff-inline 12 12 * phabricator-diff-path-view 13 + * phuix-button-view 13 14 * @javelin 14 15 */ 15 16 ··· 48 49 if (data.changesetState) { 49 50 this._loadChangesetState(data.changesetState); 50 51 } 52 + 53 + var onselect = JX.bind(this, this._onClickHeader); 54 + JX.DOM.listen(this._node, 'mousedown', 'changeset-header', onselect); 51 55 }, 52 56 53 57 members: { ··· 70 74 _inlines: null, 71 75 _visible: true, 72 76 73 - _undoNode: null, 74 77 _displayPath: null, 75 78 76 79 _changesetList: null, ··· 88 91 _isLowImportance: null, 89 92 _isOwned: null, 90 93 _isHidden: null, 94 + _isSelected: false, 95 + _viewMenu: null, 91 96 92 97 getEditorURI: function() { 93 98 return this._editorURI; ··· 115 120 116 121 setChangesetList: function(list) { 117 122 this._changesetList = list; 123 + return this; 124 + }, 125 + 126 + setViewMenu: function(menu) { 127 + this._viewMenu = menu; 118 128 return this; 119 129 }, 120 130 ··· 871 881 JX.DOM.alterClass(node, 'diff-tree-path-inlines-completed', is_completed); 872 882 }, 873 883 884 + _onClickHeader: function(e) { 885 + e.prevent(); 886 + 887 + if (this._isSelected) { 888 + this.getChangesetList().selectChangeset(null); 889 + } else { 890 + this.select(false); 891 + } 892 + }, 893 + 874 894 toggleVisibility: function() { 875 895 this.setVisible(!this._visible); 876 896 ··· 888 908 setVisible: function(visible) { 889 909 this._visible = visible; 890 910 891 - var diff = JX.DOM.find(this._node, 'table', 'differential-diff'); 892 - var undo = this._getUndoNode(); 911 + var diff = this._getDiffNode(); 912 + var options = this._getViewButtonNode(); 913 + var show = this._getShowButtonNode(); 893 914 894 915 if (this._visible) { 895 916 JX.DOM.show(diff); 896 - JX.DOM.remove(undo); 917 + JX.DOM.show(options); 918 + JX.DOM.hide(show); 897 919 } else { 898 920 JX.DOM.hide(diff); 899 - JX.DOM.appendContent(diff.parentNode, undo); 921 + JX.DOM.hide(options); 922 + JX.DOM.show(show); 923 + 924 + if (this._viewMenu) { 925 + this._viewMenu.close(); 926 + } 900 927 } 901 928 902 929 JX.Stratcom.invoke('resize'); 903 930 931 + var node = this._node; 932 + JX.DOM.alterClass(node, 'changeset-content-hidden', !this._visible); 933 + 904 934 this.getPathView().setIsHidden(!this._visible); 905 935 }, 906 936 907 - isVisible: function() { 908 - return this._visible; 909 - }, 937 + setIsSelected: function(is_selected) { 938 + this._isSelected = !!is_selected; 910 939 911 - _getUndoNode: function() { 912 - if (!this._undoNode) { 913 - var pht = this.getChangesetList().getTranslations(); 940 + var node = this._node; 941 + JX.DOM.alterClass(node, 'changeset-selected', this._isSelected); 914 942 915 - var link_attributes = { 916 - href: '#' 917 - }; 943 + return this; 944 + }, 918 945 919 - var undo_link = JX.$N('a', link_attributes, pht('Show Content')); 946 + _getDiffNode: function() { 947 + if (!this._diffNode) { 948 + this._diffNode = JX.DOM.find(this._node, 'table', 'differential-diff'); 949 + } 950 + return this._diffNode; 951 + }, 920 952 921 - var onundo = JX.bind(this, this._onundo); 922 - JX.DOM.listen(undo_link, 'click', null, onundo); 953 + _getViewButtonNode: function() { 954 + if (!this._viewButtonNode) { 955 + this._viewButtonNode = JX.DOM.find( 956 + this._node, 957 + 'a', 958 + 'differential-view-options'); 959 + } 960 + return this._viewButtonNode; 961 + }, 923 962 924 - var node_attributes = { 925 - className: 'differential-collapse-undo' 926 - }; 963 + _getShowButtonNode: function() { 964 + if (!this._showButtonNode) { 965 + var pht = this.getChangesetList().getTranslations(); 966 + 967 + var show_button = new JX.PHUIXButtonView() 968 + .setIcon('fa-angle-double-down') 969 + .setText(pht('Show Changeset')) 970 + .setColor('grey'); 927 971 928 - var node_content = [ 929 - pht('This file content has been collapsed.'), 930 - ' ', 931 - undo_link 932 - ]; 972 + var button_node = show_button.getNode(); 973 + this._getViewButtonNode().parentNode.appendChild(button_node); 933 974 934 - var undo_node = JX.$N('div', node_attributes, node_content); 975 + var onshow = JX.bind(this, this._onClickShowButton); 976 + JX.DOM.listen(button_node, 'click', null, onshow); 935 977 936 - this._undoNode = undo_node; 978 + this._showButtonNode = button_node; 937 979 } 980 + return this._showButtonNode; 981 + }, 938 982 939 - return this._undoNode; 983 + _onClickShowButton: function(e) { 984 + e.prevent(); 985 + this.setVisible(true); 986 + }, 987 + 988 + isVisible: function() { 989 + return this._visible; 940 990 }, 941 991 942 992 _onundo: function(e) {
+40 -16
webroot/rsrc/js/application/diff/DiffChangesetList.js
··· 124 124 _dropdownMenu: null, 125 125 _menuButton: null, 126 126 _menuItems: null, 127 + _selectedChangeset: null, 127 128 128 129 sleep: function() { 129 130 this._asleep = true; ··· 165 166 if (!standalone) { 166 167 label = pht('Jump to the table of contents.'); 167 168 this._installKey('t', 'diff-nav', label, this._ontoc); 169 + 170 + label = pht('Jump to the comment area.'); 171 + this._installKey('x', 'diff-nav', label, this._oncomments); 168 172 } 169 173 170 174 label = pht('Jump to next change.'); ··· 203 207 } 204 208 205 209 if (!standalone) { 206 - label = pht('Hide or show the current file.'); 210 + label = pht('Hide or show the current changeset.'); 207 211 this._installKey('h', 'diff-vis', label, this._onkeytogglefile); 208 212 } 209 213 ··· 327 331 _ontoc: function(manager) { 328 332 var toc = JX.$('toc'); 329 333 manager.scrollTo(toc); 334 + }, 335 + 336 + _oncomments: function(manager) { 337 + var reply = JX.$('reply'); 338 + manager.scrollTo(reply); 330 339 }, 331 340 332 341 getSelectedInline: function() { ··· 703 712 704 713 if (cursor !== null) { 705 714 this._setSelectionState(items[cursor], scroll); 715 + } else { 716 + this._setSelectionState(null, false); 706 717 } 707 718 708 719 return this; ··· 731 742 return; 732 743 } 733 744 745 + var changeset = cursor.changeset; 746 + 734 747 var tree = this._getTreeView(); 735 - if (cursor.changeset) { 748 + if (changeset) { 736 749 tree.setSelectedPath(cursor.changeset.getPathView()); 737 750 } else { 738 751 tree.setSelectedPath(null); 739 752 } 753 + 754 + this._selectChangeset(changeset); 740 755 741 756 this.setFocus(cursor.nodes.begin, cursor.nodes.end); 742 757 ··· 1047 1062 1048 1063 visible_item 1049 1064 .setDisabled(true) 1050 - .setIcon('fa-expand') 1051 - .setName(pht('Can\'t Toggle Unloaded File')); 1065 + .setIcon('fa-eye-slash') 1066 + .setName(pht('Hide Changeset')); 1067 + 1052 1068 var diffs = JX.DOM.scry( 1053 1069 JX.$(data.containerID), 1054 1070 'table', ··· 1059 1075 'More than one node with sigil "differential-diff" was found in "'+ 1060 1076 data.containerID+'."'); 1061 1077 } else if (diffs.length == 1) { 1062 - var diff = diffs[0]; 1063 1078 visible_item.setDisabled(false); 1064 - if (!changeset.isVisible()) { 1065 - visible_item 1066 - .setName(pht('Expand File')) 1067 - .setIcon('fa-expand'); 1068 - } else { 1069 - visible_item 1070 - .setName(pht('Collapse File')) 1071 - .setIcon('fa-compress'); 1072 - } 1073 1079 } else { 1074 1080 // Do nothing when there is no diff shown in the table. For example, 1075 1081 // the file is binary. ··· 1078 1084 }); 1079 1085 1080 1086 data.menu = menu; 1087 + changeset.setViewMenu(menu); 1081 1088 menu.open(); 1082 1089 }, 1083 1090 ··· 1224 1231 if (!node) { 1225 1232 var tree = this._getTreeView(); 1226 1233 tree.setSelectedPath(null); 1234 + this._selectChangeset(null); 1227 1235 } 1228 1236 1229 1237 this._focusStart = node; ··· 1231 1239 this._redrawFocus(); 1232 1240 }, 1233 1241 1242 + _selectChangeset: function(changeset) { 1243 + if (this._selectedChangeset === changeset) { 1244 + return; 1245 + } 1246 + 1247 + if (this._selectedChangeset !== null) { 1248 + this._selectedChangeset.setIsSelected(false); 1249 + this._selectedChangeset = null; 1250 + } 1251 + 1252 + this._selectedChangeset = changeset; 1253 + if (this._selectedChangeset !== null) { 1254 + this._selectedChangeset.setIsSelected(true); 1255 + } 1256 + }, 1257 + 1234 1258 _redrawFocus: function() { 1235 1259 var node = this._focusStart; 1236 1260 var extended_node = this._focusEnd || node; ··· 1247 1271 var s = JX.Vector.getAggregateScrollForNode(node); 1248 1272 var d = JX.Vector.getDim(node); 1249 1273 1250 - p.add(s).add(d.x + 1, 0).setPos(reticle); 1274 + p.add(s).add(d.x + 1, 4).setPos(reticle); 1251 1275 // Compute the size we need to extend to the full extent of the focused 1252 1276 // nodes. 1253 1277 JX.Vector.getPos(extended_node) 1254 1278 .add(-p.x, -p.y) 1255 1279 .add(0, JX.Vector.getDim(extended_node).y) 1256 - .add(10, 0) 1280 + .add(10, -4) 1257 1281 .setDim(reticle); 1258 1282 1259 1283 JX.DOM.getContentFrame().appendChild(reticle);