mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-23 07:12:41 +01:00
Conpherence - introduce ConpherenceThreadManager
Summary: Ref T7014. Fixes T7473. This adds a class to handle thread state about what thread is loaded and what transaction we've seen last. It is deployed 100% in the durable column and only partially deployed in the regular view. Future diff(s) should clean up regular view. Note ConpherenceThreadManager API might change a bit at that time. Also includes a bonus bug fix so logged out users can't toggle this column Test Plan: tried to use durable column while logged out and nothing happened. sent messages, aphlict-received messages, added people, and changed title from both views Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T7473, T7014 Differential Revision: https://secure.phabricator.com/D12029
This commit is contained in:
parent
dd501117e8
commit
2373185e9b
8 changed files with 466 additions and 417 deletions
|
@ -11,7 +11,7 @@ return array(
|
|||
'core.pkg.js' => '5a1c336d',
|
||||
'darkconsole.pkg.js' => '8ab24e01',
|
||||
'differential.pkg.css' => '1940be3f',
|
||||
'differential.pkg.js' => 'e62fe1cf',
|
||||
'differential.pkg.js' => '53c1ccc2',
|
||||
'diffusion.pkg.css' => '591664fa',
|
||||
'diffusion.pkg.js' => 'bfc0737b',
|
||||
'maniphest.pkg.css' => '68d4dd3d',
|
||||
|
@ -351,17 +351,18 @@ return array(
|
|||
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761',
|
||||
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
|
||||
'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de',
|
||||
'rsrc/js/application/conpherence/behavior-durable-column.js' => 'e4affa94',
|
||||
'rsrc/js/application/conpherence/behavior-menu.js' => '869e3445',
|
||||
'rsrc/js/application/conpherence/behavior-pontificate.js' => '86df5915',
|
||||
'rsrc/js/application/conpherence/behavior-widget-pane.js' => '40b1ff90',
|
||||
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => 'd0742f48',
|
||||
'rsrc/js/application/conpherence/behavior-durable-column.js' => '8cf41980',
|
||||
'rsrc/js/application/conpherence/behavior-menu.js' => '6bc52765',
|
||||
'rsrc/js/application/conpherence/behavior-pontificate.js' => '21ba5861',
|
||||
'rsrc/js/application/conpherence/behavior-widget-pane.js' => '2c1cd7f5',
|
||||
'rsrc/js/application/countdown/timer.js' => 'e4cc26b3',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '82439934',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
|
||||
'rsrc/js/application/differential/ChangesetViewManager.js' => '88be0133',
|
||||
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '1b772f31',
|
||||
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '0286a1db',
|
||||
'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18',
|
||||
'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d',
|
||||
'rsrc/js/application/differential/behavior-comment-preview.js' => '8e1389b5',
|
||||
|
@ -516,11 +517,12 @@ return array(
|
|||
'conpherence-menu-css' => 'c6ac5299',
|
||||
'conpherence-message-pane-css' => '5930260a',
|
||||
'conpherence-notification-css' => '04a6e10a',
|
||||
'conpherence-thread-manager' => 'd0742f48',
|
||||
'conpherence-update-css' => '1099a660',
|
||||
'conpherence-widget-pane-css' => '3d575438',
|
||||
'differential-changeset-view-css' => '6a8b172a',
|
||||
'differential-core-view-css' => '7ac3cabc',
|
||||
'differential-inline-comment-editor' => '1b772f31',
|
||||
'differential-inline-comment-editor' => '0286a1db',
|
||||
'differential-results-table-css' => '181aa9d9',
|
||||
'differential-revision-add-comment-css' => 'c478bcaa',
|
||||
'differential-revision-comment-css' => '48186045',
|
||||
|
@ -555,9 +557,9 @@ return array(
|
|||
'javelin-behavior-boards-dropdown' => '0ec56e1d',
|
||||
'javelin-behavior-choose-control' => '6153c708',
|
||||
'javelin-behavior-config-reorder-fields' => '14a827de',
|
||||
'javelin-behavior-conpherence-menu' => '869e3445',
|
||||
'javelin-behavior-conpherence-pontificate' => '86df5915',
|
||||
'javelin-behavior-conpherence-widget-pane' => '40b1ff90',
|
||||
'javelin-behavior-conpherence-menu' => '6bc52765',
|
||||
'javelin-behavior-conpherence-pontificate' => '21ba5861',
|
||||
'javelin-behavior-conpherence-widget-pane' => '2c1cd7f5',
|
||||
'javelin-behavior-countdown-timer' => 'e4cc26b3',
|
||||
'javelin-behavior-dark-console' => '08883e8b',
|
||||
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
|
||||
|
@ -582,7 +584,7 @@ return array(
|
|||
'javelin-behavior-diffusion-locate-file' => '6d3e1947',
|
||||
'javelin-behavior-diffusion-pull-lastmodified' => '2b228192',
|
||||
'javelin-behavior-doorkeeper-tag' => 'e5822781',
|
||||
'javelin-behavior-durable-column' => 'e4affa94',
|
||||
'javelin-behavior-durable-column' => '8cf41980',
|
||||
'javelin-behavior-error-log' => '6882e80a',
|
||||
'javelin-behavior-fancy-datepicker' => 'c51ae228',
|
||||
'javelin-behavior-global-drag-and-drop' => '07f199d8',
|
||||
|
@ -830,6 +832,14 @@ return array(
|
|||
'unhandled-exception-css' => '37d4f9a2',
|
||||
),
|
||||
'requires' => array(
|
||||
'0286a1db' => array(
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-install',
|
||||
'javelin-request',
|
||||
'javelin-workflow',
|
||||
),
|
||||
'029a133d' => array(
|
||||
'aphront-dialog-view-css',
|
||||
),
|
||||
|
@ -931,14 +941,6 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-keyboard-shortcut-manager',
|
||||
),
|
||||
'1b772f31' => array(
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-install',
|
||||
'javelin-request',
|
||||
'javelin-workflow',
|
||||
),
|
||||
'1d298e3a' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -968,6 +970,14 @@ return array(
|
|||
'phabricator-phtize',
|
||||
'changeset-view-manager',
|
||||
),
|
||||
'21ba5861' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-workflow',
|
||||
'javelin-stratcom',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'2290aeef' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1012,6 +1022,19 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
),
|
||||
'2c1cd7f5' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
'phabricator-notification',
|
||||
'javelin-behavior-device',
|
||||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'2c426492' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1067,18 +1090,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-reactor-dom',
|
||||
),
|
||||
'40b1ff90' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
'phabricator-notification',
|
||||
'javelin-behavior-device',
|
||||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
),
|
||||
42126667 => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1238,6 +1249,18 @@ return array(
|
|||
'69adf288' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'6bc52765' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-behavior-device',
|
||||
'javelin-history',
|
||||
'javelin-vector',
|
||||
'phabricator-shaped-request',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'6c2b09a2' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1447,24 +1470,6 @@ return array(
|
|||
'phabricator-tooltip',
|
||||
'changeset-view-manager',
|
||||
),
|
||||
'869e3445' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-behavior-device',
|
||||
'javelin-history',
|
||||
'javelin-vector',
|
||||
'phabricator-shaped-request',
|
||||
),
|
||||
'86df5915' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-workflow',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'87cb6b51' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1530,6 +1535,15 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-behavior',
|
||||
),
|
||||
'8cf41980' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-scrollbar',
|
||||
'javelin-quicksand',
|
||||
'phabricator-keyboard-shortcut',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'8e1389b5' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1754,6 +1768,16 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'phabricator-phtize',
|
||||
),
|
||||
'd0742f48' => array(
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-install',
|
||||
'javelin-workflow',
|
||||
'javelin-router',
|
||||
'javelin-behavior-device',
|
||||
'javelin-vector',
|
||||
),
|
||||
'd19198c8' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1836,14 +1860,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'e4affa94' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-scrollbar',
|
||||
'javelin-quicksand',
|
||||
'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'e4cc26b3' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
|
|
@ -46,7 +46,7 @@ final class ConpherenceViewController extends
|
|||
$content = array('messages' => $messages);
|
||||
} else {
|
||||
$header = $this->buildHeaderPaneContent($conpherence);
|
||||
$form = $this->renderFormContent($data['latest_transaction_id']);
|
||||
$form = $this->renderFormContent();
|
||||
$content = array(
|
||||
'header' => $header,
|
||||
'messages' => $messages,
|
||||
|
@ -77,7 +77,7 @@ final class ConpherenceViewController extends
|
|||
));
|
||||
}
|
||||
|
||||
private function renderFormContent($latest_transaction_id) {
|
||||
private function renderFormContent() {
|
||||
|
||||
$conpherence = $this->getConpherence();
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
@ -103,20 +103,6 @@ final class ConpherenceViewController extends
|
|||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Send')))
|
||||
->appendChild(
|
||||
javelin_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'latest_transaction_id',
|
||||
'value' => $latest_transaction_id,
|
||||
'sigil' => 'latest-transaction-id',
|
||||
'meta' => array(
|
||||
'threadPHID' => $conpherence->getPHID(),
|
||||
'threadID' => $conpherence->getID(),
|
||||
),
|
||||
),
|
||||
''))
|
||||
->render();
|
||||
|
||||
return $form;
|
||||
|
|
|
@ -82,10 +82,18 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
public function getShowDurableColumn() {
|
||||
$request = $this->getRequest();
|
||||
if ($request) {
|
||||
if (strncmp(
|
||||
$request->getRequestURI()->getPath(),
|
||||
'/conpherence',
|
||||
strlen('/conpherence')) === 0) {
|
||||
return false;
|
||||
}
|
||||
$viewer = $request->getUser();
|
||||
return PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorConpherenceApplication',
|
||||
if ($viewer->isLoggedIn()) {
|
||||
return PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorConpherenceApplication',
|
||||
$viewer);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
/**
|
||||
* @provides conpherence-thread-manager
|
||||
* @requires javelin-dom
|
||||
* javelin-util
|
||||
* javelin-stratcom
|
||||
* javelin-install
|
||||
* javelin-workflow
|
||||
* javelin-router
|
||||
* javelin-behavior-device
|
||||
* javelin-vector
|
||||
*/
|
||||
JX.install('ConpherenceThreadManager', {
|
||||
|
||||
construct : function() {
|
||||
if (__DEV__) {
|
||||
if (JX.ConpherenceThreadManager._instance) {
|
||||
JX.$E('ConpherenceThreadManager object is a singleton.');
|
||||
}
|
||||
}
|
||||
JX.ConpherenceThreadManager._instance = this;
|
||||
return this;
|
||||
},
|
||||
|
||||
members: {
|
||||
_loadThreadURI: null,
|
||||
_loadedThreadID: null,
|
||||
_loadedThreadPHID: null,
|
||||
_latestTransactionID: null,
|
||||
_updating: null,
|
||||
_minimalDisplay: false,
|
||||
_getMessagesNodeFunction: JX.bag,
|
||||
_getTitleNodeFunction: JX.bag,
|
||||
_willLoadThreadCallback: JX.bag,
|
||||
_didLoadThreadCallback: JX.bag,
|
||||
_willSendMessageCallback: JX.bag,
|
||||
_didSendMessageCallback: JX.bag,
|
||||
|
||||
setLoadThreadURI: function(uri) {
|
||||
this._loadThreadURI = uri;
|
||||
return this;
|
||||
},
|
||||
|
||||
getLoadThreadURI: function() {
|
||||
return this._loadThreadURI;
|
||||
},
|
||||
|
||||
isThreadLoaded: function() {
|
||||
return Boolean(this._loadedThreadID);
|
||||
},
|
||||
|
||||
isThreadIDLoaded: function(thread_id) {
|
||||
return this._loadedThreadID == thread_id;
|
||||
},
|
||||
|
||||
getLoadedThreadID: function() {
|
||||
return this._loadedThreadID;
|
||||
},
|
||||
|
||||
getLoadedThreadPHID: function() {
|
||||
return this._loadedThreadPHID;
|
||||
},
|
||||
|
||||
getLatestTransactionID: function() {
|
||||
return this._latestTransactionID;
|
||||
},
|
||||
|
||||
setLatestTransactionID: function(id) {
|
||||
this._latestTransactionID = id;
|
||||
return this;
|
||||
},
|
||||
|
||||
setMessagesNodeFunction: function(callback) {
|
||||
this._getMessagesNodeFunction = callback;
|
||||
return this;
|
||||
},
|
||||
|
||||
_getMessagesNode: function() {
|
||||
return this._getMessagesNodeFunction();
|
||||
},
|
||||
|
||||
setTitleNodeFunction: function(callback) {
|
||||
this._getTitleNodeFunction = callback;
|
||||
return this;
|
||||
},
|
||||
|
||||
_getTitleNode: function() {
|
||||
return this._getTitleNodeFunction();
|
||||
},
|
||||
|
||||
setMinimalDisplay: function(bool) {
|
||||
this._minimalDisplay = bool;
|
||||
return this;
|
||||
},
|
||||
|
||||
setWillLoadThreadCallback: function(callback) {
|
||||
this._willLoadThreadCallback = callback;
|
||||
return this;
|
||||
},
|
||||
|
||||
setDidLoadThreadCallback: function(callback) {
|
||||
this._didLoadThreadCallback = callback;
|
||||
return this;
|
||||
},
|
||||
|
||||
setWillSendMessageCallback: function(callback) {
|
||||
this._willSendMessageCallback = callback;
|
||||
return this;
|
||||
},
|
||||
|
||||
setDidSendMessageCallback: function(callback) {
|
||||
this._didSendMessageCallback = callback;
|
||||
return this;
|
||||
},
|
||||
|
||||
_getParams: function(base_params) {
|
||||
if (this._minimalDisplay) {
|
||||
base_params.minimal_display = true;
|
||||
}
|
||||
if (this._latestTransactionID) {
|
||||
base_params.latest_transaction_id = this._latestTransactionID;
|
||||
}
|
||||
return base_params;
|
||||
},
|
||||
start: function() {
|
||||
JX.Stratcom.listen(
|
||||
'aphlict-server-message',
|
||||
null,
|
||||
JX.bind(this, function(e) {
|
||||
var message = e.getData();
|
||||
|
||||
if (message.type != 'message') {
|
||||
// Not a message event.
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.threadPHID != this._loadedThreadPHID) {
|
||||
// Message event for some thread other than the visible one.
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.messageID <= this._latestTransactionID) {
|
||||
// Message event for something we already know about.
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're currently updating, wait for the update to complete.
|
||||
// If this notification tells us about a message which is newer than
|
||||
// the newest one we know to exist, keep track of it so we can
|
||||
// update once the in-flight update finishes.
|
||||
if (this._updating &&
|
||||
this._updating.threadPHID == this._loadedThreadPHID) {
|
||||
if (message.messageID > this._updating.knownID) {
|
||||
this._updating.knownID = message.messageID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._updateThread();
|
||||
}));
|
||||
},
|
||||
|
||||
_updateThread: function() {
|
||||
var params = this._getParams({
|
||||
action: 'load',
|
||||
});
|
||||
|
||||
var uri = '/conpherence/update/' + this._loadedThreadID + '/';
|
||||
|
||||
var workflow = new JX.Workflow(uri)
|
||||
.setData(params)
|
||||
.setHandler(JX.bind(this, function(r) {
|
||||
this._latestTransactionID = r.latest_transaction_id;
|
||||
|
||||
var messages = this._getMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
}));
|
||||
|
||||
this.syncWorkflow(workflow, 'finally');
|
||||
},
|
||||
|
||||
syncWorkflow: function(workflow, stage) {
|
||||
this._updating = {
|
||||
threadPHID: this._loadedThreadPHID,
|
||||
knownID: this._latestTransactionID
|
||||
};
|
||||
workflow.listen(stage, JX.bind(this, function() {
|
||||
// TODO - do we need to handle if we switch threads somehow?
|
||||
var need_sync = (this._updating.knownID > this._latestTransactionID);
|
||||
this._updating = null;
|
||||
if (need_sync) {
|
||||
this._updateThread();
|
||||
}
|
||||
}));
|
||||
workflow.start();
|
||||
},
|
||||
|
||||
runUpdateWorkflowFromLink: function(link, params) {
|
||||
params = this._getParams(params);
|
||||
|
||||
var workflow = new JX.Workflow.newFromLink(link)
|
||||
.setData(params)
|
||||
.setHandler(JX.bind(this, function(r) {
|
||||
this._latestTransactionID = r.latest_transaction_id;
|
||||
|
||||
var messages = this._getMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
JX.DOM.setContent(this._getTitleNode(), r.conpherence_title);
|
||||
}));
|
||||
this.syncWorkflow(workflow, params.stage);
|
||||
},
|
||||
|
||||
loadThreadByID: function(thread_id) {
|
||||
if (this.isThreadLoaded() &&
|
||||
this.isThreadIDLoaded(thread_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._willLoadThreadCallback();
|
||||
|
||||
var params = {};
|
||||
// We pick a thread from the server if not specified
|
||||
if (thread_id) {
|
||||
params.id = thread_id;
|
||||
}
|
||||
params = this._getParams(params);
|
||||
|
||||
var handler = JX.bind(this, function(r) {
|
||||
this._loadedThreadID = r.threadID;
|
||||
this._loadedThreadPHID = r.threadPHID;
|
||||
this._loadThreadID = r.threadID;
|
||||
this._latestTransactionID = r.latestTransactionID;
|
||||
|
||||
this._didLoadThreadCallback(r);
|
||||
});
|
||||
|
||||
// should this be sync'd too?
|
||||
new JX.Workflow(this.getLoadThreadURI())
|
||||
.setData(params)
|
||||
.setHandler(handler)
|
||||
.start();
|
||||
},
|
||||
|
||||
sendMessage: function(form, params) {
|
||||
params = this._getParams(params);
|
||||
|
||||
this._willSendMessageCallback();
|
||||
var workflow = JX.Workflow.newFromForm(form, params)
|
||||
.setHandler(JX.bind(this, function(r) {
|
||||
this._latestTransactionID = r.latest_transaction_id;
|
||||
this._didSendMessageCallback(r);
|
||||
}));
|
||||
this.syncWorkflow(workflow, 'finally');
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
_instance: null,
|
||||
|
||||
getInstance: function() {
|
||||
var self = JX.ConpherenceThreadManager;
|
||||
if (!self._instance) {
|
||||
return null;
|
||||
}
|
||||
return self._instance;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
|
@ -6,100 +6,20 @@
|
|||
* javelin-scrollbar
|
||||
* javelin-quicksand
|
||||
* phabricator-keyboard-shortcut
|
||||
* conpherence-thread-manager
|
||||
*/
|
||||
|
||||
JX.behavior('durable-column', function() {
|
||||
|
||||
var shouldInit = true;
|
||||
var show = false;
|
||||
var loadThreadID = null;
|
||||
var loadedThreadID = null;
|
||||
var loadedThreadPHID = null;
|
||||
var latestTransactionID = null;
|
||||
|
||||
var frame = JX.$('phabricator-standard-page');
|
||||
var quick = JX.$('phabricator-standard-page-body');
|
||||
var show = false;
|
||||
|
||||
|
||||
// TODO - this "upating" stuff is a copy from behavior-pontificate
|
||||
// TODO: This isn't very clean. When you submit a message, you may get a
|
||||
// notification about it back before you get the rendered message back. To
|
||||
// prevent this, we keep track of whether we're currently updating the
|
||||
// thread. If we are, we hold further updates until the response comes
|
||||
// back.
|
||||
|
||||
// After the response returns, we'll do another update if we know about
|
||||
// a transaction newer than the one we got back from the server.
|
||||
var updating = null;
|
||||
// Copy continues with slight modifications for how we store data now
|
||||
JX.Stratcom.listen('aphlict-server-message', null, function(e) {
|
||||
var message = e.getData();
|
||||
|
||||
if (message.type != 'message') {
|
||||
// Not a message event.
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.threadPHID != loadedThreadPHID) {
|
||||
// Message event for some thread other than the visible one.
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.messageID <= latestTransactionID) {
|
||||
// Message event for something we already know about.
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're currently updating, wait for the update to complete.
|
||||
// If this notification tells us about a message which is newer than the
|
||||
// newest one we know to exist, keep track of it so we can update once
|
||||
// the in-flight update finishes.
|
||||
if (updating && updating.threadPHID == loadedThreadPHID) {
|
||||
if (message.messageID > updating.knownID) {
|
||||
updating.knownID = message.messageID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
update_thread();
|
||||
});
|
||||
function update_thread() {
|
||||
var params = {
|
||||
action: 'load',
|
||||
latest_transaction_id: latestTransactionID,
|
||||
minimal_display: true
|
||||
};
|
||||
|
||||
var uri = '/conpherence/update/' + loadedThreadID + '/';
|
||||
|
||||
var workflow = new JX.Workflow(uri)
|
||||
.setData(params)
|
||||
.setHandler(function(r) {
|
||||
var messages = _getColumnMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
latestTransactionID = r.latest_transaction_id;
|
||||
});
|
||||
|
||||
sync_workflow(workflow);
|
||||
function _getColumnContentNode() {
|
||||
return JX.$('conpherence-durable-column-content');
|
||||
}
|
||||
function sync_workflow(workflow) {
|
||||
updating = {
|
||||
threadPHID: loadedThreadPHID,
|
||||
knownID: latestTransactionID
|
||||
};
|
||||
workflow.listen('finally', function() {
|
||||
var need_sync = (updating && updating.knownID > latestTransactionID);
|
||||
updating = null;
|
||||
if (need_sync) {
|
||||
update_thread();
|
||||
}
|
||||
});
|
||||
workflow.start();
|
||||
}
|
||||
// end copy / hack of stuff with big ole TODO on it
|
||||
|
||||
|
||||
function _toggleColumn() {
|
||||
if (window.location.pathname.indexOf('/conpherence/') === 0) {
|
||||
|
@ -110,7 +30,7 @@ JX.behavior('durable-column', function() {
|
|||
var column = JX.$('conpherence-durable-column');
|
||||
if (show) {
|
||||
JX.DOM.show(column);
|
||||
loadThreadContent(loadThreadID);
|
||||
threadManager.loadThreadByID(loadThreadID);
|
||||
} else {
|
||||
JX.DOM.hide(column);
|
||||
}
|
||||
|
@ -122,10 +42,48 @@ JX.behavior('durable-column', function() {
|
|||
.setHandler(_toggleColumn)
|
||||
.register();
|
||||
|
||||
new JX.Scrollbar(JX.$('conpherence-durable-column-content'));
|
||||
new JX.Scrollbar(_getColumnContentNode());
|
||||
|
||||
JX.Quicksand.start();
|
||||
|
||||
/* Conpherence Thread Manager configuration - lots of display
|
||||
* callbacks.
|
||||
*/
|
||||
var threadManager = new JX.ConpherenceThreadManager();
|
||||
threadManager.setMinimalDisplay(true);
|
||||
threadManager.setMessagesNodeFunction(_getColumnMessagesNode);
|
||||
threadManager.setTitleNodeFunction(_getColumnTitleNode);
|
||||
threadManager.setLoadThreadURI('/conpherence/columnview/');
|
||||
threadManager.setWillLoadThreadCallback(function () {
|
||||
_markLoading(true);
|
||||
});
|
||||
threadManager.setDidLoadThreadCallback(function (r) {
|
||||
var column = _getColumnNode();
|
||||
var new_column = JX.$H(r.content);
|
||||
JX.DOM.replace(column, new_column);
|
||||
JX.DOM.show(_getColumnNode());
|
||||
new JX.Scrollbar(_getColumnContentNode());
|
||||
_markLoading(false);
|
||||
loadThreadID = threadManager.getLoadedThreadID();
|
||||
});
|
||||
threadManager.setWillSendMessageCallback(function () {
|
||||
_markLoading(true);
|
||||
});
|
||||
threadManager.setDidSendMessageCallback(function (r) {
|
||||
var messages = _getColumnMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
var content = _getColumnContentNode();
|
||||
content.scrollTop = content.scrollHeight;
|
||||
|
||||
var textarea = _getColumnTextareaNode();
|
||||
textarea.value = '';
|
||||
|
||||
_markLoading(false);
|
||||
|
||||
_focusColumnTextareaNode();
|
||||
});
|
||||
threadManager.start();
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
'conpherence-durable-column-header-action',
|
||||
|
@ -139,61 +97,22 @@ JX.behavior('durable-column', function() {
|
|||
switch (action) {
|
||||
case 'metadata':
|
||||
JX.Stratcom.invoke('notification-panel-close');
|
||||
params = {
|
||||
action: action,
|
||||
latest_transaction_id: latestTransactionID,
|
||||
minimal_display: true,
|
||||
force_ajax: true
|
||||
};
|
||||
var workflow = new JX.Workflow.newFromLink(link)
|
||||
.setData(params)
|
||||
.setHandler(function(r) {
|
||||
var messages = _getColumnMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
var title = _getColumnTitleNode();
|
||||
JX.DOM.setContent(title, r.conpherence_title);
|
||||
|
||||
latestTransactionID = r.latest_transaction_id;
|
||||
// since this is a two step workflow, and the "finally" method
|
||||
// gets called on the first form load, restore "updating" if
|
||||
// necessary
|
||||
if (updating === null) {
|
||||
updating = {
|
||||
threadPHID: loadedThreadPHID,
|
||||
knownID: latestTransactionID
|
||||
};
|
||||
}
|
||||
threadManager.runUpdateWorkflowFromLink(
|
||||
link,
|
||||
{
|
||||
action: action,
|
||||
force_ajax: true,
|
||||
stage: 'submit'
|
||||
});
|
||||
sync_workflow(workflow);
|
||||
break;
|
||||
case 'add_person':
|
||||
JX.Stratcom.invoke('notification-panel-close');
|
||||
params = {
|
||||
action: action,
|
||||
latest_transaction_id: latestTransactionID,
|
||||
minimal_display: true
|
||||
};
|
||||
var workflow = new JX.Workflow.newFromLink(link)
|
||||
.setData(params)
|
||||
.setHandler(function(r) {
|
||||
var messages = _getColumnMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
latestTransactionID = r.latest_transaction_id;
|
||||
// since this is a two step workflow, and the "finally" method
|
||||
// gets called on the first form load, restore "updating" if
|
||||
// necessary
|
||||
if (updating === null) {
|
||||
updating = {
|
||||
threadPHID: loadedThreadPHID,
|
||||
knownID: latestTransactionID
|
||||
};
|
||||
}
|
||||
threadManager.runUpdateWorkflowFromLink(
|
||||
link,
|
||||
{
|
||||
action: action,
|
||||
stage: 'submit'
|
||||
});
|
||||
sync_workflow(workflow);
|
||||
break;
|
||||
case 'go_conpherence':
|
||||
JX.$U(link.href).go();
|
||||
|
@ -217,6 +136,7 @@ JX.behavior('durable-column', function() {
|
|||
'conpherence-durable-column-body');
|
||||
}
|
||||
|
||||
|
||||
function _getColumnMessagesNode() {
|
||||
var column = JX.$('conpherence-durable-column');
|
||||
return JX.DOM.find(
|
||||
|
@ -259,65 +179,10 @@ JX.behavior('durable-column', function() {
|
|||
JX.DOM.alterClass(column, 'loading', loading);
|
||||
}
|
||||
|
||||
function loadThreadContent(thread_id) {
|
||||
// loaded this thread already
|
||||
if (loadedThreadID !== null && loadedThreadID == thread_id) {
|
||||
return;
|
||||
}
|
||||
_markLoading(true);
|
||||
|
||||
var uri = '/conpherence/columnview/';
|
||||
var params = null;
|
||||
// We can pick a thread from the server the first time
|
||||
if (shouldInit) {
|
||||
shouldInit = false;
|
||||
} else {
|
||||
params = { id : thread_id };
|
||||
}
|
||||
var handler = function(r) {
|
||||
var column = _getColumnNode();
|
||||
var new_column = JX.$H(r.content);
|
||||
loadedThreadID = r.threadID;
|
||||
loadedThreadPHID = r.threadPHID;
|
||||
loadThreadID = r.threadID;
|
||||
latestTransactionID = r.latestTransactionID;
|
||||
JX.DOM.replace(column, new_column);
|
||||
JX.DOM.show(_getColumnNode());
|
||||
new JX.Scrollbar(JX.$('conpherence-durable-column-content'));
|
||||
_markLoading(false);
|
||||
};
|
||||
|
||||
new JX.Workflow(uri)
|
||||
.setData(params)
|
||||
.setHandler(handler)
|
||||
.start();
|
||||
}
|
||||
|
||||
function _sendMessage(e) {
|
||||
e.kill();
|
||||
_markLoading(true);
|
||||
|
||||
var form = _getColumnFormNode();
|
||||
var params = {
|
||||
latest_transaction_id : latestTransactionID,
|
||||
minimal_display : true
|
||||
};
|
||||
var workflow = JX.Workflow.newFromForm(form, params)
|
||||
.setHandler(function(r) {
|
||||
var messages = _getColumnMessagesNode();
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
var textarea = _getColumnTextareaNode();
|
||||
textarea.value = '';
|
||||
|
||||
latestTransactionID = r.latest_transaction_id;
|
||||
|
||||
_markLoading(false);
|
||||
|
||||
_focusColumnTextareaNode();
|
||||
});
|
||||
sync_workflow(workflow);
|
||||
threadManager.sendMessage(form, { minimal_display: true });
|
||||
}
|
||||
|
||||
JX.Stratcom.listen(
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
* javelin-history
|
||||
* javelin-vector
|
||||
* phabricator-shaped-request
|
||||
* conpherence-thread-manager
|
||||
*/
|
||||
|
||||
JX.behavior('conpherence-menu', function(config) {
|
||||
|
||||
/**
|
||||
* State for displayed thread.
|
||||
*/
|
||||
|
@ -22,6 +22,45 @@ JX.behavior('conpherence-menu', function(config) {
|
|||
node: null
|
||||
};
|
||||
|
||||
// TODO - move more logic into the ThreadManager
|
||||
var threadManager = new JX.ConpherenceThreadManager();
|
||||
threadManager.setMessagesNodeFunction(function () {
|
||||
return JX.DOM.find(document, 'div', 'conpherence-messages');
|
||||
});
|
||||
threadManager.setWillSendMessageCallback(function () {
|
||||
var root = JX.DOM.find(document, 'div', 'conpherence-layout');
|
||||
var form_root = JX.DOM.find(root, 'div', 'conpherence-form');
|
||||
markThreadLoading(true);
|
||||
JX.DOM.alterClass(form_root, 'loading', true);
|
||||
});
|
||||
threadManager.setDidSendMessageCallback(function (r) {
|
||||
var root = JX.DOM.find(document, 'div', 'conpherence-layout');
|
||||
var form_root = JX.DOM.find(root, 'div', 'conpherence-form');
|
||||
var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane');
|
||||
var messages = JX.DOM.find(messages_root, 'div', 'conpherence-messages');
|
||||
var fileWidget = null;
|
||||
try {
|
||||
fileWidget = JX.DOM.find(root, 'div', 'widgets-files');
|
||||
} catch (ex) {
|
||||
// Ignore; maybe no files widget
|
||||
}
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
if (fileWidget) {
|
||||
JX.DOM.setContent(
|
||||
fileWidget,
|
||||
JX.$H(r.file_widget)
|
||||
);
|
||||
}
|
||||
var textarea = JX.DOM.find(form_root, 'textarea');
|
||||
textarea.value = '';
|
||||
markThreadLoading(false);
|
||||
|
||||
setTimeout(function() { JX.DOM.focus(textarea); }, 100);
|
||||
});
|
||||
threadManager.start();
|
||||
|
||||
/**
|
||||
* Current role of this behavior. The two possible roles are to show a 'list'
|
||||
* of threads or a specific 'thread'. On devices, this behavior stays in the
|
||||
|
@ -65,9 +104,6 @@ JX.behavior('conpherence-menu', function(config) {
|
|||
function selectThread(node, update_page_data) {
|
||||
if (_thread.node) {
|
||||
JX.DOM.alterClass(_thread.node, 'conpherence-selected', false);
|
||||
// keep the unread-count hidden still. big TODO once we ajax in updates
|
||||
// to threads to make this work right and move threads between read /
|
||||
// unread
|
||||
}
|
||||
|
||||
JX.DOM.alterClass(node, 'conpherence-selected', true);
|
||||
|
|
|
@ -5,149 +5,16 @@
|
|||
* javelin-util
|
||||
* javelin-workflow
|
||||
* javelin-stratcom
|
||||
* conpherence-thread-manager
|
||||
*/
|
||||
|
||||
JX.behavior('conpherence-pontificate', function() {
|
||||
|
||||
// TODO: This isn't very clean. When you submit a message, you may get a
|
||||
// notification about it back before you get the rendered message back. To
|
||||
// prevent this, we keep track of whether we're currently updating the
|
||||
// thread. If we are, we hold further updates until the response comes
|
||||
// back.
|
||||
|
||||
// After the response returns, we'll do another update if we know about
|
||||
// a transaction newer than the one we got back from the server.
|
||||
var updating = null;
|
||||
|
||||
function get_thread_data() {
|
||||
// TODO: This is really, really gross.
|
||||
var infonode = JX.DOM.find(document, 'input', 'latest-transaction-id');
|
||||
var data = JX.Stratcom.getData(infonode);
|
||||
data.latestID = infonode.value;
|
||||
return data;
|
||||
}
|
||||
|
||||
function update_latest_transaction_id(id) {
|
||||
// TODO: Continued grossness from above.
|
||||
var infonode = JX.DOM.find(document, 'input', 'latest-transaction-id');
|
||||
infonode.value = id;
|
||||
}
|
||||
|
||||
JX.Stratcom.listen('aphlict-server-message', null, function(e) {
|
||||
var message = e.getData();
|
||||
|
||||
if (message.type != 'message') {
|
||||
// Not a message event.
|
||||
return;
|
||||
}
|
||||
|
||||
var data = get_thread_data();
|
||||
|
||||
if (message.threadPHID != data.threadPHID) {
|
||||
// Message event for some thread other than the visible one.
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.messageID <= data.latestID) {
|
||||
// Message event for something we already know about.
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're currently updating, wait for the update to complete.
|
||||
// If this notification tells us about a message which is newer than the
|
||||
// newest one we know to exist, keep track of it so we can update once
|
||||
// the in-flight update finishes.
|
||||
if (updating && updating.threadPHID == data.threadPHID) {
|
||||
if (message.messageID > updating.knownID) {
|
||||
updating.knownID = message.messageID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
update_thread(data);
|
||||
});
|
||||
|
||||
function update_thread(data) {
|
||||
var params = {
|
||||
action: 'load',
|
||||
latest_transaction_id: data.latestID
|
||||
};
|
||||
|
||||
var uri = '/conpherence/update/' + data.threadID + '/';
|
||||
|
||||
var workflow = new JX.Workflow(uri)
|
||||
.setData(params)
|
||||
.setHandler(function(r) {
|
||||
var messages = JX.DOM.find(document, 'div', 'conpherence-messages');
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
update_latest_transaction_id(r.latest_transaction_id);
|
||||
});
|
||||
|
||||
sync_workflow(workflow, data);
|
||||
}
|
||||
|
||||
function sync_workflow(workflow, data) {
|
||||
updating = {
|
||||
threadPHID: data.threadPHID,
|
||||
knownID: data.latestID
|
||||
};
|
||||
|
||||
workflow.listen('finally', function() {
|
||||
var new_data = get_thread_data();
|
||||
var need_sync = (updating.knownID > new_data.latestID);
|
||||
|
||||
updating = null;
|
||||
|
||||
if (need_sync) {
|
||||
update_thread(new_data);
|
||||
}
|
||||
});
|
||||
|
||||
workflow.start();
|
||||
}
|
||||
|
||||
var onsubmit = function(e) {
|
||||
e.kill();
|
||||
|
||||
var form = e.getNode('tag:form');
|
||||
|
||||
var root = e.getNode('conpherence-layout');
|
||||
var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane');
|
||||
var form_root = JX.DOM.find(root, 'div', 'conpherence-form');
|
||||
var messages = JX.DOM.find(messages_root, 'div', 'conpherence-messages');
|
||||
var fileWidget = null;
|
||||
try {
|
||||
fileWidget = JX.DOM.find(root, 'div', 'widgets-files');
|
||||
} catch (ex) {
|
||||
// Ignore; maybe no files widget
|
||||
}
|
||||
JX.DOM.alterClass(form_root, 'loading', true);
|
||||
|
||||
var workflow = JX.Workflow.newFromForm(form)
|
||||
.setHandler(JX.bind(this, function(r) {
|
||||
JX.DOM.appendContent(messages, JX.$H(r.transactions));
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
||||
if (fileWidget) {
|
||||
JX.DOM.setContent(
|
||||
fileWidget,
|
||||
JX.$H(r.file_widget)
|
||||
);
|
||||
}
|
||||
|
||||
update_latest_transaction_id(r.latest_transaction_id);
|
||||
|
||||
var textarea = JX.DOM.find(form, 'textarea');
|
||||
textarea.value = '';
|
||||
|
||||
JX.DOM.alterClass(form_root, 'loading', false);
|
||||
|
||||
setTimeout(function() { JX.DOM.focus(textarea); }, 100);
|
||||
}));
|
||||
|
||||
sync_workflow(workflow, get_thread_data());
|
||||
var threadManager = JX.ConpherenceThreadManager.getInstance();
|
||||
threadManager.sendMessage(form, {});
|
||||
};
|
||||
|
||||
JX.Stratcom.listen(
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* phuix-dropdown-menu
|
||||
* phuix-action-list-view
|
||||
* phuix-action-view
|
||||
* conpherence-thread-manager
|
||||
* @provides javelin-behavior-conpherence-widget-pane
|
||||
*/
|
||||
|
||||
|
@ -270,19 +271,18 @@ JX.behavior('conpherence-widget-pane', function(config) {
|
|||
href = create_data.customHref;
|
||||
}
|
||||
|
||||
var root = JX.DOM.find(document, 'div', 'conpherence-layout');
|
||||
var latest_transaction_dom = JX.DOM.find(
|
||||
root,
|
||||
'input',
|
||||
'latest-transaction-id');
|
||||
var threadManager = JX.ConpherenceThreadManager.getInstance();
|
||||
var latest_transaction_id = threadManager.getLatestTransactionID();
|
||||
var data = {
|
||||
latest_transaction_id : latest_transaction_dom.value,
|
||||
latest_transaction_id : latest_transaction_id,
|
||||
action : create_data.action
|
||||
};
|
||||
|
||||
new JX.Workflow(href, data)
|
||||
var workflow = new JX.Workflow(href, data)
|
||||
.setHandler(function (r) {
|
||||
latest_transaction_dom.value = r.latest_transaction_id;
|
||||
var threadManager = JX.ConpherenceThreadManager.getInstance();
|
||||
threadManager.setLatestTransactionID(r.latest_transaction_id);
|
||||
var root = JX.DOM.find(document, 'div', 'conpherence-layout');
|
||||
if (create_data.refreshFromResponse) {
|
||||
var messages = null;
|
||||
try {
|
||||
|
@ -315,8 +315,8 @@ JX.behavior('conpherence-widget-pane', function(config) {
|
|||
widget : widget_to_update
|
||||
});
|
||||
}
|
||||
})
|
||||
.start();
|
||||
});
|
||||
threadManager.syncWorkflow(workflow, 'submit');
|
||||
}
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue