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

Conpherence - more threadManager stuff and get scrolling working

Summary: Ref T7014. The main conpherence view is kind of broken without this in subtle ways because of /conpherence/ versus /conpherence/x/ init'ing things differently; this fixes that. Moves more normal view conpherence logic into threadManager. Makes all the display code happen outside of threadManager, setting us up for some display manager later maybe.

Test Plan: sent messages, updated title, etc and the messages pane auto scrolled correctly!

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7014

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

+145 -107
+26 -26
resources/celerity/map.php
··· 207 207 'rsrc/externals/javelin/lib/Resource.js' => '44959b73', 208 208 'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692', 209 209 'rsrc/externals/javelin/lib/Router.js' => '29274e2b', 210 - 'rsrc/externals/javelin/lib/Scrollbar.js' => '1ed54a27', 210 + 'rsrc/externals/javelin/lib/Scrollbar.js' => '1feea462', 211 211 'rsrc/externals/javelin/lib/URI.js' => '6eff08aa', 212 212 'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8', 213 213 'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4', ··· 351 351 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761', 352 352 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 353 353 'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de', 354 - 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => 'd0742f48', 355 - 'rsrc/js/application/conpherence/behavior-durable-column.js' => '8cf41980', 354 + 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '11e2dcf2', 355 + 'rsrc/js/application/conpherence/behavior-durable-column.js' => '5fc7fac0', 356 356 'rsrc/js/application/conpherence/behavior-menu.js' => '6bc52765', 357 357 'rsrc/js/application/conpherence/behavior-pontificate.js' => '21ba5861', 358 358 'rsrc/js/application/conpherence/behavior-widget-pane.js' => '2c1cd7f5', ··· 517 517 'conpherence-menu-css' => 'c6ac5299', 518 518 'conpherence-message-pane-css' => '5930260a', 519 519 'conpherence-notification-css' => '04a6e10a', 520 - 'conpherence-thread-manager' => 'd0742f48', 520 + 'conpherence-thread-manager' => '11e2dcf2', 521 521 'conpherence-update-css' => '1099a660', 522 522 'conpherence-widget-pane-css' => '3d575438', 523 523 'differential-changeset-view-css' => '6a8b172a', ··· 584 584 'javelin-behavior-diffusion-locate-file' => '6d3e1947', 585 585 'javelin-behavior-diffusion-pull-lastmodified' => '2b228192', 586 586 'javelin-behavior-doorkeeper-tag' => 'e5822781', 587 - 'javelin-behavior-durable-column' => '8cf41980', 587 + 'javelin-behavior-durable-column' => '5fc7fac0', 588 588 'javelin-behavior-error-log' => '6882e80a', 589 589 'javelin-behavior-fancy-datepicker' => 'c51ae228', 590 590 'javelin-behavior-global-drag-and-drop' => '07f199d8', ··· 678 678 'javelin-resource' => '44959b73', 679 679 'javelin-routable' => 'b3e7d692', 680 680 'javelin-router' => '29274e2b', 681 - 'javelin-scrollbar' => '1ed54a27', 681 + 'javelin-scrollbar' => '1feea462', 682 682 'javelin-stratcom' => '6c53634d', 683 683 'javelin-tokenizer' => '7644823e', 684 684 'javelin-typeahead' => '70baed2f', ··· 899 899 'javelin-install', 900 900 'javelin-util', 901 901 ), 902 + '11e2dcf2' => array( 903 + 'javelin-dom', 904 + 'javelin-util', 905 + 'javelin-stratcom', 906 + 'javelin-install', 907 + 'javelin-workflow', 908 + 'javelin-router', 909 + 'javelin-behavior-device', 910 + 'javelin-vector', 911 + ), 902 912 '13c739ea' => array( 903 913 'javelin-behavior', 904 914 'javelin-stratcom', ··· 952 962 'javelin-dom', 953 963 'javelin-reactor-dom', 954 964 ), 955 - '1ed54a27' => array( 965 + '1feea462' => array( 956 966 'javelin-install', 957 967 'javelin-dom', 958 968 'javelin-stratcom', ··· 1209 1219 'javelin-dom', 1210 1220 'javelin-vector', 1211 1221 ), 1222 + '5fc7fac0' => array( 1223 + 'javelin-behavior', 1224 + 'javelin-dom', 1225 + 'javelin-stratcom', 1226 + 'javelin-scrollbar', 1227 + 'javelin-quicksand', 1228 + 'phabricator-keyboard-shortcut', 1229 + 'conpherence-thread-manager', 1230 + ), 1212 1231 '5fefb143' => array( 1213 1232 'javelin-behavior', 1214 1233 'javelin-dom', ··· 1535 1554 'javelin-stratcom', 1536 1555 'javelin-behavior', 1537 1556 ), 1538 - '8cf41980' => array( 1539 - 'javelin-behavior', 1540 - 'javelin-dom', 1541 - 'javelin-stratcom', 1542 - 'javelin-scrollbar', 1543 - 'javelin-quicksand', 1544 - 'phabricator-keyboard-shortcut', 1545 - 'conpherence-thread-manager', 1546 - ), 1547 1557 '8e1389b5' => array( 1548 1558 'javelin-behavior', 1549 1559 'javelin-stratcom', ··· 1767 1777 'javelin-dom', 1768 1778 'javelin-stratcom', 1769 1779 'phabricator-phtize', 1770 - ), 1771 - 'd0742f48' => array( 1772 - 'javelin-dom', 1773 - 'javelin-util', 1774 - 'javelin-stratcom', 1775 - 'javelin-install', 1776 - 'javelin-workflow', 1777 - 'javelin-router', 1778 - 'javelin-behavior-device', 1779 - 'javelin-vector', 1780 1780 ), 1781 1781 'd19198c8' => array( 1782 1782 'javelin-install',
+5
src/applications/conpherence/controller/ConpherenceUpdateController.php
··· 299 299 300 300 $need_widget_data = false; 301 301 $need_transactions = false; 302 + $need_participant_cache = false; 302 303 switch ($action) { 303 304 case ConpherenceUpdateActions::METADATA: 305 + $need_participant_cache = true; 306 + $need_transactions = true; 307 + break; 304 308 case ConpherenceUpdateActions::LOAD: 305 309 $need_transactions = true; 306 310 break; ··· 319 323 $conpherence = id(new ConpherenceThreadQuery()) 320 324 ->setViewer($user) 321 325 ->setAfterTransactionID($latest_transaction_id) 326 + ->needParticipantCache($need_participant_cache) 322 327 ->needWidgetData($need_widget_data) 323 328 ->needTransactions($need_transactions) 324 329 ->withIDs(array($conpherence_id))
+1
src/applications/conpherence/controller/ConpherenceViewController.php
··· 67 67 ->setHeader($header) 68 68 ->setMessages($messages) 69 69 ->setReplyForm($form) 70 + ->setLatestTransactionID($data['latest_transaction_id']) 70 71 ->setRole('thread'); 71 72 72 73 return $this->buildApplicationPage(
+2 -1
src/applications/conpherence/view/ConpherenceDurableColumnView.php
··· 73 73 74 74 $transactions = $this->buildTransactions(); 75 75 76 - $content = phutil_tag( 76 + $content = javelin_tag( 77 77 'div', 78 78 array( 79 79 'class' => 'conpherence-durable-column-main', 80 + 'sigil' => 'conpherence-durable-column-main', 80 81 ), 81 82 phutil_tag( 82 83 'div',
+8
src/applications/conpherence/view/ConpherenceLayoutView.php
··· 9 9 private $header; 10 10 private $messages; 11 11 private $replyForm; 12 + private $latestTransactionID; 12 13 13 14 public function setMessages($messages) { 14 15 $this->messages = $messages; ··· 49 50 return $this; 50 51 } 51 52 53 + public function setLatestTransactionID($id) { 54 + $this->latestTransactionID = $id; 55 + return $this; 56 + } 57 + 52 58 public function render() { 53 59 require_celerity_resource('conpherence-menu-css'); 54 60 require_celerity_resource('conpherence-message-pane-css'); ··· 71 77 'layoutID' => $layout_id, 72 78 'selectedID' => $selected_id, 73 79 'selectedThreadID' => $selected_thread_id, 80 + 'selectedThreadPHID' => $this->thread->getPHID(), 81 + 'latestTransactionID' => $this->latestTransactionID, 74 82 'role' => $this->role, 75 83 'hasThreadList' => (bool)$this->threadView, 76 84 'hasThread' => (bool)$this->messages,
+9
webroot/rsrc/externals/javelin/lib/Scrollbar.js
··· 377 377 clearTimeout(this._timeout); 378 378 this._timeout = null; 379 379 } 380 + }, 381 + 382 + scrollTo: function(scroll) { 383 + if (this._viewport !== null) { 384 + this._viewport.scrollTop = scroll; 385 + } else { 386 + this._frame.scrollTop = scroll; 387 + } 388 + return this; 380 389 } 381 390 } 382 391
+32 -33
webroot/rsrc/js/application/conpherence/ConpherenceThreadManager.js
··· 28 28 _latestTransactionID: null, 29 29 _updating: null, 30 30 _minimalDisplay: false, 31 - _getMessagesNodeFunction: JX.bag, 32 - _getTitleNodeFunction: JX.bag, 33 31 _willLoadThreadCallback: JX.bag, 34 32 _didLoadThreadCallback: JX.bag, 33 + _didUpdateThreadCallback: JX.bag, 35 34 _willSendMessageCallback: JX.bag, 36 35 _didSendMessageCallback: JX.bag, 36 + _willUpdateWorkflowCallback: JX.bag, 37 + _didUpdateWorkflowCallback: JX.bag, 37 38 38 39 setLoadThreadURI: function(uri) { 39 40 this._loadThreadURI = uri; ··· 56 57 return this._loadedThreadID; 57 58 }, 58 59 60 + setLoadedThreadID: function(id) { 61 + this._loadedThreadID = id; 62 + return this; 63 + }, 64 + 59 65 getLoadedThreadPHID: function() { 60 66 return this._loadedThreadPHID; 67 + }, 68 + 69 + setLoadedThreadPHID: function(phid) { 70 + this._loadedThreadPHID = phid; 71 + return this; 61 72 }, 62 73 63 74 getLatestTransactionID: function() { ··· 67 78 setLatestTransactionID: function(id) { 68 79 this._latestTransactionID = id; 69 80 return this; 70 - }, 71 - 72 - setMessagesNodeFunction: function(callback) { 73 - this._getMessagesNodeFunction = callback; 74 - return this; 75 - }, 76 - 77 - _getMessagesNode: function() { 78 - return this._getMessagesNodeFunction(); 79 - }, 80 - 81 - setTitleNodeFunction: function(callback) { 82 - this._getTitleNodeFunction = callback; 83 - return this; 84 - }, 85 - 86 - _getTitleNode: function() { 87 - return this._getTitleNodeFunction(); 88 81 }, 89 82 90 83 setMinimalDisplay: function(bool) { ··· 102 95 return this; 103 96 }, 104 97 98 + setDidUpdateThreadCallback: function(callback) { 99 + this._didUpdateThreadCallback = callback; 100 + return this; 101 + }, 102 + 105 103 setWillSendMessageCallback: function(callback) { 106 104 this._willSendMessageCallback = callback; 107 105 return this; ··· 112 110 return this; 113 111 }, 114 112 113 + setWillUpdateWorkflowCallback: function(callback) { 114 + this._willUpdateWorkflowCallback = callback; 115 + return this; 116 + }, 117 + 118 + setDidUpdateWorkflowCallback: function(callback) { 119 + this._didUpdateWorkflowCallback = callback; 120 + return this; 121 + }, 122 + 115 123 _getParams: function(base_params) { 116 124 if (this._minimalDisplay) { 117 125 base_params.minimal_display = true; ··· 121 129 } 122 130 return base_params; 123 131 }, 132 + 124 133 start: function() { 125 134 JX.Stratcom.listen( 126 135 'aphlict-server-message', ··· 142 151 // Message event for something we already know about. 143 152 return; 144 153 } 145 - 146 154 // If we're currently updating, wait for the update to complete. 147 155 // If this notification tells us about a message which is newer than 148 156 // the newest one we know to exist, keep track of it so we can ··· 170 178 .setData(params) 171 179 .setHandler(JX.bind(this, function(r) { 172 180 this._latestTransactionID = r.latest_transaction_id; 173 - 174 - var messages = this._getMessagesNode(); 175 - JX.DOM.appendContent(messages, JX.$H(r.transactions)); 176 - messages.scrollTop = messages.scrollHeight; 181 + this._didUpdateThreadCallback(r); 177 182 })); 178 183 179 184 this.syncWorkflow(workflow, 'finally'); ··· 197 202 198 203 runUpdateWorkflowFromLink: function(link, params) { 199 204 params = this._getParams(params); 200 - 205 + this._willUpdateWorkflowCallback(); 201 206 var workflow = new JX.Workflow.newFromLink(link) 202 207 .setData(params) 203 208 .setHandler(JX.bind(this, function(r) { 204 209 this._latestTransactionID = r.latest_transaction_id; 205 - 206 - var messages = this._getMessagesNode(); 207 - JX.DOM.appendContent(messages, JX.$H(r.transactions)); 208 - messages.scrollTop = messages.scrollHeight; 209 - 210 - JX.DOM.setContent(this._getTitleNode(), r.conpherence_title); 210 + this._didUpdateWorkflowCallback(r); 211 211 })); 212 212 this.syncWorkflow(workflow, params.stage); 213 213 }, ··· 230 230 var handler = JX.bind(this, function(r) { 231 231 this._loadedThreadID = r.threadID; 232 232 this._loadedThreadPHID = r.threadPHID; 233 - this._loadThreadID = r.threadID; 234 233 this._latestTransactionID = r.latestTransactionID; 235 234 236 235 this._didLoadThreadCallback(r);
+31 -19
webroot/rsrc/js/application/conpherence/behavior-durable-column.js
··· 13 13 14 14 var show = false; 15 15 var loadThreadID = null; 16 + var scrollbar = null; 16 17 17 18 var frame = JX.$('phabricator-standard-page'); 18 19 var quick = JX.$('phabricator-standard-page-body'); 19 20 20 - function _getColumnContentNode() { 21 - return JX.$('conpherence-durable-column-content'); 21 + function _getColumnNode() { 22 + return JX.$('conpherence-durable-column'); 23 + } 24 + 25 + function _getColumnScrollNode() { 26 + var column = _getColumnNode(); 27 + return JX.DOM.find(column, 'div', 'conpherence-durable-column-main'); 22 28 } 23 29 24 30 function _toggleColumn() { ··· 42 48 .setHandler(_toggleColumn) 43 49 .register(); 44 50 45 - new JX.Scrollbar(_getColumnContentNode()); 51 + scrollbar = new JX.Scrollbar(_getColumnScrollNode()); 46 52 47 53 JX.Quicksand.start(); 48 54 ··· 51 57 */ 52 58 var threadManager = new JX.ConpherenceThreadManager(); 53 59 threadManager.setMinimalDisplay(true); 54 - threadManager.setMessagesNodeFunction(_getColumnMessagesNode); 55 - threadManager.setTitleNodeFunction(_getColumnTitleNode); 56 60 threadManager.setLoadThreadURI('/conpherence/columnview/'); 57 - threadManager.setWillLoadThreadCallback(function () { 61 + threadManager.setWillLoadThreadCallback(function() { 58 62 _markLoading(true); 59 63 }); 60 - threadManager.setDidLoadThreadCallback(function (r) { 64 + threadManager.setDidLoadThreadCallback(function(r) { 61 65 var column = _getColumnNode(); 62 66 var new_column = JX.$H(r.content); 63 67 JX.DOM.replace(column, new_column); 64 68 JX.DOM.show(_getColumnNode()); 65 - new JX.Scrollbar(_getColumnContentNode()); 69 + var messages = _getColumnMessagesNode(); 70 + scrollbar = new JX.Scrollbar(_getColumnScrollNode()); 71 + scrollbar.scrollTo(messages.scrollHeight); 66 72 _markLoading(false); 67 73 loadThreadID = threadManager.getLoadedThreadID(); 68 74 }); 69 - threadManager.setWillSendMessageCallback(function () { 75 + threadManager.setDidUpdateThreadCallback(function(r) { 76 + var messages = _getColumnMessagesNode(); 77 + JX.DOM.appendContent(messages, JX.$H(r.transactions)); 78 + scrollbar.scrollTo(messages.scrollHeight); 79 + }); 80 + threadManager.setWillSendMessageCallback(function() { 70 81 _markLoading(true); 71 82 }); 72 - threadManager.setDidSendMessageCallback(function (r) { 83 + threadManager.setDidSendMessageCallback(function(r) { 73 84 var messages = _getColumnMessagesNode(); 74 85 JX.DOM.appendContent(messages, JX.$H(r.transactions)); 75 - var content = _getColumnContentNode(); 76 - content.scrollTop = content.scrollHeight; 86 + scrollbar.scrollTo(messages.scrollHeight); 77 87 78 88 var textarea = _getColumnTextareaNode(); 79 89 textarea.value = ''; ··· 82 92 83 93 _focusColumnTextareaNode(); 84 94 }); 95 + threadManager.setWillUpdateWorkflowCallback(function() { 96 + JX.Stratcom.invoke('notification-panel-close'); 97 + }); 98 + threadManager.setDidUpdateWorkflowCallback(function(r) { 99 + var messages = this._getMessagesNode(); 100 + JX.DOM.appendContent(messages, JX.$H(r.transactions)); 101 + scrollbar.scrollTo(messages.scrollHeight); 102 + JX.DOM.setContent(_getColumnTitleNode(), r.conpherence_title); 103 + }); 85 104 threadManager.start(); 86 105 87 106 JX.Stratcom.listen( ··· 96 115 97 116 switch (action) { 98 117 case 'metadata': 99 - JX.Stratcom.invoke('notification-panel-close'); 100 118 threadManager.runUpdateWorkflowFromLink( 101 119 link, 102 120 { ··· 106 124 }); 107 125 break; 108 126 case 'add_person': 109 - JX.Stratcom.invoke('notification-panel-close'); 110 127 threadManager.runUpdateWorkflowFromLink( 111 128 link, 112 129 { ··· 124 141 } 125 142 }); 126 143 127 - function _getColumnNode() { 128 - return JX.$('conpherence-durable-column'); 129 - } 130 - 131 144 function _getColumnBodyNode() { 132 145 var column = JX.$('conpherence-durable-column'); 133 146 return JX.DOM.find( ··· 135 148 'div', 136 149 'conpherence-durable-column-body'); 137 150 } 138 - 139 151 140 152 function _getColumnMessagesNode() { 141 153 var column = JX.$('conpherence-durable-column');
+31 -28
webroot/rsrc/js/application/conpherence/behavior-menu.js
··· 24 24 25 25 // TODO - move more logic into the ThreadManager 26 26 var threadManager = new JX.ConpherenceThreadManager(); 27 - threadManager.setMessagesNodeFunction(function () { 28 - return JX.DOM.find(document, 'div', 'conpherence-messages'); 27 + threadManager.setWillLoadThreadCallback(function() { 28 + markThreadLoading(true); 29 + }); 30 + threadManager.setDidLoadThreadCallback(function(r) { 31 + var header = JX.$H(r.header); 32 + var messages = JX.$H(r.messages); 33 + var form = JX.$H(r.form); 34 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 35 + var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); 36 + var messages_root = JX.DOM.find(root, 'div', 'conpherence-messages'); 37 + var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); 38 + JX.DOM.setContent(header_root, header); 39 + JX.DOM.setContent(messages_root, messages); 40 + JX.DOM.setContent(form_root, form); 41 + 42 + markThreadLoading(false); 43 + 44 + didRedrawThread(true); 45 + }); 46 + threadManager.setDidUpdateThreadCallback(function(r) { 47 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 48 + var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane'); 49 + var messages = JX.DOM.find(messages_root, 'div', 'conpherence-messages'); 50 + JX.DOM.appendContent(messages, JX.$H(r.transactions)); 51 + messages.scrollTop = messages.scrollHeight; 29 52 }); 30 53 threadManager.setWillSendMessageCallback(function () { 31 54 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); ··· 155 178 var data = JX.Stratcom.getData(_thread.node); 156 179 157 180 if (_thread.visible !== null || !config.hasThread) { 158 - markThreadLoading(true); 159 - var uri = config.baseURI + data.threadID + '/'; 160 - new JX.Workflow(uri, {}) 161 - .setHandler(JX.bind(null, onLoadThreadResponse, data.threadID)) 162 - .start(); 181 + threadManager.setLoadThreadURI('/conpherence/' + data.threadID + '/'); 182 + threadManager.loadThreadByID(data.threadID); 163 183 } else if (config.hasThread) { 184 + // we loaded the thread via the server so let the thread manager know 185 + threadManager.setLoadedThreadID(config.selectedThreadID); 186 + threadManager.setLoadedThreadPHID(config.selectedThreadPHID); 187 + threadManager.setLatestTransactionID(config.latestTransactionID); 164 188 _scrollMessageWindow(); 165 189 _focusTextarea(); 166 190 } else { ··· 268 292 widget = 'widgets-people'; 269 293 } 270 294 return widget; 271 - } 272 - 273 - function onLoadThreadResponse(thread_id, response) { 274 - // we got impatient and this is no longer the right answer :/ 275 - if (_thread.selected != thread_id) { 276 - return; 277 - } 278 - var header = JX.$H(response.header); 279 - var messages = JX.$H(response.messages); 280 - var form = JX.$H(response.form); 281 - var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 282 - var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); 283 - var messages_root = JX.DOM.find(root, 'div', 'conpherence-messages'); 284 - var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); 285 - JX.DOM.setContent(header_root, header); 286 - JX.DOM.setContent(messages_root, messages); 287 - JX.DOM.setContent(form_root, form); 288 - 289 - markThreadLoading(false); 290 - 291 - didRedrawThread(true); 292 295 } 293 296 294 297 /**