@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.

Move most Differetial keyboard shortcuts into DiffChangesetList

Summary: Ref T12616. This moves most keyboard shortcuts into DiffChangesetList. It breaks some shortcuts that I plan to restore later, noted in T12616 (toggle file, edit inline, reply to inline), since I think ripping them out now and rebuilding them in a little bit will make things much simpler.

Test Plan:
- Used j, k, n, p, J, K shortcuts to navigate a revision.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12616

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

+273 -296
+19 -28
resources/celerity/map.php
··· 13 13 'core.pkg.js' => '2ff7879f', 14 14 'darkconsole.pkg.js' => '1f9a31bc', 15 15 'differential.pkg.css' => '58712637', 16 - 'differential.pkg.js' => '6375358e', 16 + 'differential.pkg.js' => 'e6129b80', 17 17 'diffusion.pkg.css' => 'b93d9b8c', 18 18 'diffusion.pkg.js' => '84c8f8fd', 19 19 'favicon.ico' => '30672e08', ··· 390 390 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173', 391 391 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 392 392 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 393 - 'rsrc/js/application/diff/DiffChangeset.js' => '4c9c47ad', 394 - 'rsrc/js/application/diff/DiffChangesetList.js' => '589a30aa', 393 + 'rsrc/js/application/diff/DiffChangeset.js' => '3d4b3c5e', 394 + 'rsrc/js/application/diff/DiffChangesetList.js' => 'e2c315d9', 395 395 'rsrc/js/application/diff/DiffInline.js' => '98c12b2f', 396 396 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 397 397 'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d', 398 398 'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76', 399 399 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', 400 400 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '89d11432', 401 - 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '92904457', 402 401 'rsrc/js/application/differential/behavior-populate.js' => '5e41c819', 403 402 'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb', 404 403 'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d', ··· 624 623 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 625 624 'javelin-behavior-differential-edit-inline-comments' => '89d11432', 626 625 'javelin-behavior-differential-feedback-preview' => 'b064af76', 627 - 'javelin-behavior-differential-keyboard-navigation' => '92904457', 628 626 'javelin-behavior-differential-populate' => '5e41c819', 629 627 'javelin-behavior-differential-toggle-files' => 'ca3f91eb', 630 628 'javelin-behavior-differential-user-select' => 'a8d8459d', ··· 783 781 'phabricator-darklog' => 'c8e1ffe3', 784 782 'phabricator-darkmessage' => 'c48cccdd', 785 783 'phabricator-dashboard-css' => 'fe5b1869', 786 - 'phabricator-diff-changeset' => '4c9c47ad', 787 - 'phabricator-diff-changeset-list' => '589a30aa', 784 + 'phabricator-diff-changeset' => '3d4b3c5e', 785 + 'phabricator-diff-changeset-list' => 'e2c315d9', 788 786 'phabricator-diff-inline' => '98c12b2f', 789 787 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 790 788 'phabricator-draggable-list' => 'bea6e7f4', ··· 1160 1158 'javelin-util', 1161 1159 'javelin-uri', 1162 1160 ), 1161 + '3d4b3c5e' => array( 1162 + 'javelin-dom', 1163 + 'javelin-util', 1164 + 'javelin-stratcom', 1165 + 'javelin-install', 1166 + 'javelin-workflow', 1167 + 'javelin-router', 1168 + 'javelin-behavior-device', 1169 + 'javelin-vector', 1170 + 'phabricator-diff-inline', 1171 + ), 1163 1172 '3dbf94d5' => array( 1164 1173 'javelin-behavior', 1165 1174 'javelin-dom', ··· 1270 1279 'javelin-uri', 1271 1280 'phabricator-notification', 1272 1281 ), 1273 - '4c9c47ad' => array( 1274 - 'javelin-dom', 1275 - 'javelin-util', 1276 - 'javelin-stratcom', 1277 - 'javelin-install', 1278 - 'javelin-workflow', 1279 - 'javelin-router', 1280 - 'javelin-behavior-device', 1281 - 'javelin-vector', 1282 - 'phabricator-diff-inline', 1283 - ), 1284 1282 '4d863052' => array( 1285 1283 'javelin-dom', 1286 1284 'javelin-util', ··· 1348 1346 'javelin-vector', 1349 1347 'javelin-dom', 1350 1348 ), 1351 - '589a30aa' => array( 1352 - 'javelin-install', 1353 - ), 1354 1349 '58dea2fa' => array( 1355 1350 'javelin-install', 1356 1351 'javelin-util', ··· 1629 1624 'javelin-dom', 1630 1625 'javelin-request', 1631 1626 ), 1632 - 92904457 => array( 1633 - 'javelin-behavior', 1634 - 'javelin-dom', 1635 - 'javelin-stratcom', 1636 - 'phabricator-keyboard-shortcut', 1637 - ), 1638 1627 '92b9ec77' => array( 1639 1628 'javelin-behavior', 1640 1629 'javelin-stratcom', ··· 2119 2108 'javelin-stratcom', 2120 2109 'javelin-dom', 2121 2110 ), 2111 + 'e2c315d9' => array( 2112 + 'javelin-install', 2113 + ), 2122 2114 'e2e0a072' => array( 2123 2115 'javelin-behavior', 2124 2116 'javelin-stratcom', ··· 2440 2432 'javelin-behavior-differential-populate', 2441 2433 'javelin-behavior-differential-diff-radios', 2442 2434 'javelin-behavior-differential-comment-jump', 2443 - 'javelin-behavior-differential-keyboard-navigation', 2444 2435 'javelin-behavior-aphront-drag-and-drop-textarea', 2445 2436 'javelin-behavior-phabricator-object-selector', 2446 2437 'javelin-behavior-repository-crossreference',
-1
resources/celerity/packages.php
··· 197 197 'javelin-behavior-differential-populate', 198 198 'javelin-behavior-differential-diff-radios', 199 199 'javelin-behavior-differential-comment-jump', 200 - 'javelin-behavior-differential-keyboard-navigation', 201 200 'javelin-behavior-aphront-drag-and-drop-textarea', 202 201 'javelin-behavior-phabricator-object-selector', 203 202 'javelin-behavior-repository-crossreference',
-1
src/applications/differential/controller/DifferentialRevisionViewController.php
··· 465 465 } 466 466 467 467 Javelin::initBehavior('differential-user-select'); 468 - Javelin::initBehavior('differential-keyboard-navigation'); 469 468 470 469 $view = id(new PHUITwoColumnView()) 471 470 ->setHeader($header)
+10
src/applications/differential/view/DifferentialChangesetListView.php
··· 234 234 'Highlight As...' => pht('Highlight As...'), 235 235 236 236 'Loading...' => pht('Loading...'), 237 + 238 + 'Jump to next change.' => pht('Jump to next change.'), 239 + 'Jump to previous change.' => pht('Jump to previous change.'), 240 + 'Jump to next file.' => pht('Jump to next file.'), 241 + 'Jump to previous file.' => pht('Jump to previous file.'), 242 + 'Jump to next inline comment.' => pht('Jump to next inline comment.'), 243 + 'Jump to previous inline comment.' => 244 + pht('Jump to previous inline comment.'), 245 + 'Jump to the table of contents.' => 246 + pht('Jump to the table of contents.'), 237 247 ), 238 248 )); 239 249
-2
src/applications/diffusion/controller/DiffusionCommitController.php
··· 720 720 $request = $this->getRequest(); 721 721 $viewer = $request->getUser(); 722 722 723 - Javelin::initBehavior('differential-keyboard-navigation'); 724 - 725 723 // TODO: This is pretty awkward, unify the CSS between Diffusion and 726 724 // Differential better. 727 725 require_celerity_resource('differential-core-view-css');
+82
webroot/rsrc/js/application/diff/DiffChangeset.js
··· 318 318 return this._highlight; 319 319 }, 320 320 321 + getSelectableItems: function() { 322 + var items = []; 323 + 324 + items.push({ 325 + type: 'file', 326 + changeset: this, 327 + target: this, 328 + nodes: { 329 + begin: this._node, 330 + end: null 331 + } 332 + }); 333 + 334 + var rows = JX.DOM.scry(this._node, 'tr'); 335 + 336 + var blocks = []; 337 + var block; 338 + var ii; 339 + for (ii = 0; ii < rows.length; ii++) { 340 + var type = this._getRowType(rows[ii]); 341 + 342 + if (!block || (block.type !== type)) { 343 + block = { 344 + type: type, 345 + items: [] 346 + }; 347 + blocks.push(block); 348 + } 349 + 350 + block.items.push(rows[ii]); 351 + } 352 + 353 + for (ii = 0; ii < blocks.length; ii++) { 354 + block = blocks[ii]; 355 + 356 + if (block.type == 'change') { 357 + items.push({ 358 + type: block.type, 359 + changeset: this, 360 + target: block.items[0], 361 + nodes: { 362 + begin: block.items[0], 363 + end: block.items[block.items.length - 1] 364 + } 365 + }); 366 + } 367 + 368 + if (block.type == 'comment') { 369 + for (var jj = 0; jj < block.items.length; jj++) { 370 + items.push({ 371 + type: block.type, 372 + changeset: this, 373 + target: block.items[jj], 374 + nodes: { 375 + begin: block.items[jj], 376 + end: block.items[jj] 377 + } 378 + }); 379 + } 380 + } 381 + } 382 + 383 + return items; 384 + }, 385 + 386 + _getRowType: function(row) { 387 + // NOTE: Don't do "className.indexOf()" elsewhere. This is evil legacy 388 + // magic. 389 + 390 + if (row.className.indexOf('inline') !== -1) { 391 + return 'comment'; 392 + } 393 + 394 + var cells = JX.DOM.scry(row, 'td'); 395 + for (var ii = 0; ii < cells.length; ii++) { 396 + if (cells[ii].className.indexOf('old') !== -1 || 397 + cells[ii].className.indexOf('new') !== -1) { 398 + return 'change'; 399 + } 400 + } 401 + }, 402 + 321 403 _getNodeData: function() { 322 404 return JX.Stratcom.getData(this._node); 323 405 },
+162
webroot/rsrc/js/application/diff/DiffChangesetList.js
··· 55 55 }, 56 56 57 57 members: { 58 + _initialized: false, 58 59 _asleep: true, 59 60 _changesets: null, 61 + 62 + _cursorItem: null, 63 + _lastKeyboardManager: null, 60 64 61 65 sleep: function() { 62 66 this._asleep = true; ··· 64 68 65 69 wake: function() { 66 70 this._asleep = false; 71 + 72 + if (this._initialized) { 73 + return; 74 + } 75 + 76 + this._initialized = true; 77 + var pht = this.getTranslations(); 78 + 79 + var label; 80 + 81 + label = pht('Jump to next change.'); 82 + this._installJumpKey('j', label, 1); 83 + 84 + label = pht('Jump to previous change.'); 85 + this._installJumpKey('k', label, -1); 86 + 87 + label = pht('Jump to next file.'); 88 + this._installJumpKey('J', label, 1, 'file'); 89 + 90 + label = pht('Jump to previous file.'); 91 + this._installJumpKey('K', label, -1, 'file'); 92 + 93 + label = pht('Jump to next inline comment.'); 94 + this._installJumpKey('n', label, 1, 'comment'); 95 + 96 + label = pht('Jump to previous inline comment.'); 97 + this._installJumpKey('p', label, -1, 'comment'); 98 + 99 + label = pht('Jump to the table of contents.'); 100 + this._installKey('t', label, this._ontoc); 67 101 }, 68 102 69 103 isAsleep: function() { ··· 130 164 if (routable) { 131 165 routable.setPriority(2000); 132 166 } 167 + }, 168 + 169 + _installKey: function(key, label, handler) { 170 + handler = JX.bind(this, this._ifawake, handler); 171 + 172 + return new JX.KeyboardShortcut(key, label) 173 + .setHandler(handler) 174 + .register(); 175 + }, 176 + 177 + _installJumpKey: function(key, label, delta, filter) { 178 + filter = filter || null; 179 + var handler = JX.bind(this, this._onjumpkey, delta, filter); 180 + return this._installKey(key, label, handler); 181 + }, 182 + 183 + _ontoc: function(manager) { 184 + var toc = JX.$('toc'); 185 + manager.scrollTo(toc); 186 + }, 187 + 188 + _onjumpkey: function(delta, filter, manager) { 189 + var state = this._getSelectionState(); 190 + 191 + var cursor = state.cursor; 192 + var items = state.items; 193 + 194 + // If there's currently no selection and the user tries to go back, 195 + // don't do anything. 196 + if ((cursor === null) && (delta < 0)) { 197 + return; 198 + } 199 + 200 + while (true) { 201 + if (cursor === null) { 202 + cursor = 0; 203 + } else { 204 + cursor = cursor + delta; 205 + } 206 + 207 + // If we've gone backward past the first change, bail out. 208 + if (cursor < 0) { 209 + return; 210 + } 211 + 212 + // If we've gone forward off the end of the list, bail out. 213 + if (cursor >= items.length) { 214 + return; 215 + } 216 + 217 + // If we're selecting things of a particular type (like only files) 218 + // and the next item isn't of that type, move past it. 219 + if (filter !== null) { 220 + if (items[cursor].type !== filter) { 221 + continue; 222 + } 223 + } 224 + 225 + // Otherwise, we've found a valid item to select. 226 + break; 227 + } 228 + 229 + this._setSelectionState(items[cursor], manager); 230 + }, 231 + 232 + _getSelectionState: function() { 233 + var items = this._getSelectableItems(); 234 + 235 + var cursor = null; 236 + if (this._cursorItem !== null) { 237 + for (var ii = 0; ii < items.length; ii++) { 238 + var item = items[ii]; 239 + if (this._cursorItem.target === item.target) { 240 + cursor = ii; 241 + break; 242 + } 243 + } 244 + } 245 + 246 + return { 247 + cursor: cursor, 248 + items: items 249 + }; 250 + }, 251 + 252 + _setSelectionState: function(item, manager) { 253 + this._cursorItem = item; 254 + 255 + this._redrawSelection(manager, true); 256 + 257 + return this; 258 + }, 259 + 260 + _redrawSelection: function(manager, scroll) { 261 + manager = manager || this._lastKeyboardManager; 262 + this._lastKeyboardManager = manager; 263 + 264 + if (this.isAsleep()) { 265 + manager.focusOn(null); 266 + return; 267 + } 268 + 269 + var cursor = this._cursorItem; 270 + if (!cursor) { 271 + manager.focusOn(null); 272 + return; 273 + } 274 + 275 + manager.focusOn(cursor.nodes.begin, cursor.nodes.end); 276 + 277 + if (scroll) { 278 + manager.scrollTo(cursor.nodes.begin); 279 + } 280 + 281 + return this; 282 + }, 283 + 284 + _getSelectableItems: function() { 285 + var result = []; 286 + 287 + for (var ii = 0; ii < this._changesets.length; ii++) { 288 + var items = this._changesets[ii].getSelectableItems(); 289 + for (var jj = 0; jj < items.length; jj++) { 290 + result.push(items[jj]); 291 + } 292 + } 293 + 294 + return result; 133 295 }, 134 296 135 297 _onmore: function(e) {
-264
webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
··· 1 - /** 2 - * @provides javelin-behavior-differential-keyboard-navigation 3 - * @requires javelin-behavior 4 - * javelin-dom 5 - * javelin-stratcom 6 - * phabricator-keyboard-shortcut 7 - */ 8 - 9 - JX.behavior('differential-keyboard-navigation', function(config) { 10 - 11 - var cursor = -1; 12 - var changesets; 13 - 14 - var selection_begin = null; 15 - var selection_end = null; 16 - 17 - var refreshFocus = function() {}; 18 - 19 - function init() { 20 - if (changesets) { 21 - return; 22 - } 23 - changesets = JX.DOM.scry(document.body, 'div', 'differential-changeset'); 24 - } 25 - 26 - function getBlocks(cursor) { 27 - // TODO: This might not be terribly fast; we can't currently memoize it 28 - // because it can change as ajax requests come in (e.g., content loads). 29 - 30 - var rows = JX.DOM.scry(changesets[cursor], 'tr'); 31 - var blocks = [[changesets[cursor], changesets[cursor]]]; 32 - var start = null; 33 - var type; 34 - var ii; 35 - 36 - // Don't show code blocks inside a collapsed file. 37 - var diff = JX.DOM.scry(changesets[cursor], 'table', 'differential-diff'); 38 - if (diff.length == 1 && JX.Stratcom.getData(diff[0]).hidden) { 39 - return blocks; 40 - } 41 - 42 - function push() { 43 - if (start) { 44 - blocks.push([start, rows[ii - 1]]); 45 - } 46 - start = null; 47 - } 48 - 49 - for (ii = 0; ii < rows.length; ii++) { 50 - type = getRowType(rows[ii]); 51 - if (type == 'comment') { 52 - // If we see these types of rows, make a block for each one. 53 - push(); 54 - } 55 - if (!type) { 56 - push(); 57 - } else if (type && !start) { 58 - start = rows[ii]; 59 - } 60 - } 61 - push(); 62 - 63 - return blocks; 64 - } 65 - 66 - function getRowType(row) { 67 - // NOTE: Being somewhat over-general here to allow other types of objects 68 - // to be easily focused in the future (inline comments, 'show more..'). 69 - 70 - if (row.className.indexOf('inline') !== -1) { 71 - return 'comment'; 72 - } 73 - 74 - if (row.className.indexOf('differential-changeset') !== -1) { 75 - return 'file'; 76 - } 77 - 78 - var cells = JX.DOM.scry(row, 'td'); 79 - 80 - for (var ii = 0; ii < cells.length; ii++) { 81 - // NOTE: The semantic use of classnames here is for performance; don't 82 - // emulate this elsewhere since it's super terrible. 83 - if (cells[ii].className.indexOf('old') !== -1 || 84 - cells[ii].className.indexOf('new') !== -1) { 85 - return 'change'; 86 - } 87 - } 88 - 89 - return null; 90 - } 91 - 92 - function jump(manager, delta, jump_to_type) { 93 - init(); 94 - 95 - if (cursor < 0) { 96 - if (delta < 0) { 97 - // If the user goes "back" without a selection, just reject the action. 98 - return; 99 - } else { 100 - cursor = 0; 101 - } 102 - } 103 - 104 - while (true) { 105 - var blocks = getBlocks(cursor); 106 - var focus; 107 - if (delta < 0) { 108 - focus = blocks.length; 109 - } else { 110 - focus = -1; 111 - } 112 - 113 - for (var ii = 0; ii < blocks.length; ii++) { 114 - if (blocks[ii][0] == selection_begin) { 115 - focus = ii; 116 - break; 117 - } 118 - } 119 - 120 - while (true) { 121 - focus += delta; 122 - 123 - if (blocks[focus]) { 124 - var row_type = getRowType(blocks[focus][0]); 125 - if (jump_to_type && row_type != jump_to_type) { 126 - continue; 127 - } 128 - 129 - selection_begin = blocks[focus][0]; 130 - selection_end = blocks[focus][1]; 131 - 132 - manager.scrollTo(selection_begin); 133 - 134 - refreshFocus = function() { 135 - manager.focusOn(selection_begin, selection_end); 136 - }; 137 - 138 - refreshFocus(); 139 - 140 - return; 141 - } else { 142 - var adjusted = (cursor + delta); 143 - if (adjusted < 0 || adjusted >= changesets.length) { 144 - // Stop cursor movement when the user reaches either end. 145 - return; 146 - } 147 - cursor = adjusted; 148 - 149 - // Break the inner loop and go to the next file. 150 - break; 151 - } 152 - } 153 - } 154 - 155 - } 156 - 157 - // When inline comments are updated, wipe out our cache of blocks since 158 - // comments may have been added or deleted. 159 - JX.Stratcom.listen( 160 - null, 161 - 'differential-inline-comment-update', 162 - function() { 163 - changesets = null; 164 - }); 165 - // Same thing when a file is hidden or shown; don't want to highlight 166 - // invisible code. 167 - JX.Stratcom.listen( 168 - 'differential-toggle-file-toggled', 169 - null, 170 - function() { 171 - changesets = null; 172 - init(); 173 - refreshFocus(); 174 - }); 175 - 176 - new JX.KeyboardShortcut('j', 'Jump to next change.') 177 - .setHandler(function(manager) { 178 - jump(manager, 1); 179 - }) 180 - .register(); 181 - 182 - new JX.KeyboardShortcut('k', 'Jump to previous change.') 183 - .setHandler(function(manager) { 184 - jump(manager, -1); 185 - }) 186 - .register(); 187 - 188 - new JX.KeyboardShortcut('J', 'Jump to next file.') 189 - .setHandler(function(manager) { 190 - jump(manager, 1, 'file'); 191 - }) 192 - .register(); 193 - 194 - new JX.KeyboardShortcut('K', 'Jump to previous file.') 195 - .setHandler(function(manager) { 196 - jump(manager, -1, 'file'); 197 - }) 198 - .register(); 199 - 200 - new JX.KeyboardShortcut('n', 'Jump to next inline comment.') 201 - .setHandler(function(manager) { 202 - jump(manager, 1, 'comment'); 203 - }) 204 - .register(); 205 - 206 - new JX.KeyboardShortcut('p', 'Jump to previous inline comment.') 207 - .setHandler(function(manager) { 208 - jump(manager, -1, 'comment'); 209 - }) 210 - .register(); 211 - 212 - 213 - new JX.KeyboardShortcut('t', 'Jump to the table of contents.') 214 - .setHandler(function(manager) { 215 - var toc = JX.$('toc'); 216 - manager.scrollTo(toc); 217 - }) 218 - .register(); 219 - 220 - new JX.KeyboardShortcut( 221 - 'h', 222 - 'Collapse or expand the file display (after jump).') 223 - .setHandler(function() { 224 - if (!changesets || !changesets[cursor]) { 225 - return; 226 - } 227 - JX.Stratcom.invoke('differential-toggle-file', null, { 228 - diff: JX.DOM.scry(changesets[cursor], 'table', 'differential-diff') 229 - }); 230 - }) 231 - .register(); 232 - 233 - 234 - function inline_op(node, op) { 235 - // nothing selected 236 - if (!node) { 237 - return; 238 - } 239 - if (!JX.DOM.scry(node, 'a', 'differential-inline-' + op)) { 240 - // No link for this operation, e.g. editing a comment you can't edit. 241 - return; 242 - } 243 - 244 - var data = { 245 - node: JX.DOM.find(node, 'div', 'differential-inline-comment'), 246 - op: op 247 - }; 248 - 249 - JX.Stratcom.invoke('differential-inline-action', null, data); 250 - } 251 - 252 - new JX.KeyboardShortcut('r', 'Reply to selected inline comment.') 253 - .setHandler(function() { 254 - inline_op(selection_begin, 'reply'); 255 - }) 256 - .register(); 257 - 258 - new JX.KeyboardShortcut('e', 'Edit selected inline comment.') 259 - .setHandler(function() { 260 - inline_op(selection_begin, 'edit'); 261 - }) 262 - .register(); 263 - 264 - });