/** * @provides javelin-behavior-conpherence-pontificate * @requires javelin-behavior * javelin-dom * javelin-util * javelin-workflow * javelin-stratcom */ 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()); }; JX.Stratcom.listen( ['submit', 'didSyntheticSubmit'], 'conpherence-pontificate', onsubmit); });