/** * @requires javelin-behavior * javelin-dom * javelin-stratcom * javelin-workflow * javelin-util * phabricator-notification * javelin-behavior-device * phabricator-dropdown-menu * phabricator-menu-item * @provides javelin-behavior-conpherence-widget-pane */ JX.behavior('conpherence-widget-pane', function(config) { /** * There can be race conditions around loading the messages or the widgets * first. Keep track of what widgets we've loaded with this variable. */ var _loadedWidgetsID = null; /** * At any given time there can be only one selected widget. Keep track of * which one it is by the user-facing name for ease of use with * PhabricatorDropdownMenuItems. */ var _selectedWidgetName = null; /** * This is potentially built each time the user switches conpherence threads * or when the result JX.Device.getDevice() changes from desktop to some * other value. */ var buildDeviceWidgetSelector = function (data) { var device_header = _getDeviceWidgetHeader(); if (!device_header) { return; } JX.DOM.show(device_header); var device_menu = new JX.PhabricatorDropdownMenu(device_header); data.deviceMenu = true; _buildWidgetSelector(device_menu, data); }; /** * This is potentially built each time the user switches conpherence threads * or when the result JX.Device.getDevice() changes from mobile or tablet to * desktop. */ var buildDesktopWidgetSelector = function (data) { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var widget_pane = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); var widget_header = JX.DOM.find(widget_pane, 'a', 'widgets-selector'); var menu = new JX.PhabricatorDropdownMenu(widget_header); menu.toggleAlignDropdownRight(false); data.deviceMenu = false; _buildWidgetSelector(menu, data); }; /** * Workhorse that actually builds the widget selector. Note some fancy bits * where we listen for the "open" event and enable / disable widgets as * appropos. */ var _buildWidgetSelector = function (menu, data) { _loadedWidgetsID = data.threadID; var widgets = config.widgetRegistry; for (var widget in widgets) { var widget_data = widgets[widget]; if (widget_data.deviceOnly && data.deviceMenu === false) { continue; } menu.addItem(new JX.PhabricatorMenuItem( widget_data.name, JX.bind(null, toggleWidget, { widget : widget }), '#' ).setDisabled(widget == data.widget)); } menu.listen( 'open', JX.bind(menu, function () { for (var ii = 0; ii < this._items.length; ii++) { var item = this._items[ii]; var name = item.getName(); if (name == _selectedWidgetName) { item.setDisabled(true); } else { item.setDisabled(false); } } })); }; /** * Since this is not always on the page, avoid having a repeat * try / catch block and consolidate into this helper function. */ var _getDeviceWidgetHeader = function () { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var device_header = null; try { device_header = JX.DOM.find( root, 'a', 'device-widgets-selector'); } catch (ex) { // is okay - no deviceWidgetHeader yet... but bail time } return device_header; }; /** * Responder to the 'conpherence-did-redraw-thread' event, this bad boy * hides or shows the device widget selector as appropros. */ var _didRedrawThread = function (data) { if (_loadedWidgetsID === null || _loadedWidgetsID != data.threadID) { return; } var device = JX.Device.getDevice(); var device_selector = _getDeviceWidgetHeader(); if (device == 'desktop') { JX.DOM.hide(device_selector); } else { JX.DOM.show(device_selector); } if (data.buildDeviceWidgetSelector) { buildDeviceWidgetSelector(data); } toggleWidget(data); }; JX.Stratcom.listen( 'conpherence-did-redraw-thread', null, function (e) { _didRedrawThread(e.getData()); } ); /** * Toggling a widget involves showing / hiding the appropriate widget * bodies as well as updating the selectors to have the label on the * newly selected widget. */ var toggleWidget = function (data) { var widgets = config.widgetRegistry; var widget_data = widgets[data.widget]; var device = JX.Device.getDevice(); var is_desktop = device == 'desktop'; if (widget_data.deviceOnly && is_desktop) { return; } _selectedWidgetName = widget_data.name; var device_header = _getDeviceWidgetHeader(); if (device_header) { // this is fragile but adding a sigil to this element is awkward var device_header_spans = JX.DOM.scry(device_header, 'span'); var device_header_span = device_header_spans[1]; JX.DOM.setContent( device_header_span, widget_data.name); } // don't update the non-device selector with device only widget stuff if (!widget_data.deviceOnly) { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var widget_pane = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); var widget_header = JX.DOM.find(widget_pane, 'a', 'widgets-selector'); var adder = JX.DOM.find(widget_pane, 'a', 'conpherence-widget-adder'); JX.DOM.setContent( widget_header, widget_data.name); JX.DOM.appendContent( widget_header, JX.$N('span', { className : 'caret' })); if (widget_data.hasCreate) { JX.DOM.show(adder); } else { JX.DOM.hide(adder); } } for (var widget in config.widgetRegistry) { widget_data = widgets[widget]; if (widget_data.deviceOnly && is_desktop) { // some one off code for conpherence messages which are device-only // as a widget, but shown always on the desktop if (widget == 'conpherence-message-pane') { JX.$(widget).style.display = 'block'; JX.Stratcom.invoke('conpherence-redraw-thread', null, {}); } continue; } if (widget == data.widget) { JX.$(widget).style.display = 'block'; // some one off code for conpherence messages - fancier refresh tech if (widget == 'conpherence-message-pane') { JX.Stratcom.invoke('conpherence-redraw-thread', null, {}); JX.Stratcom.invoke('conpherence-update-page-data', null, {}); } } else { JX.$(widget).style.display = 'none'; } } }; JX.Stratcom.listen( 'conpherence-update-widgets', null, function (e) { var data = e.getData(); if (data.buildSelectors) { buildDesktopWidgetSelector(data); buildDeviceWidgetSelector(data); } if (data.toggleWidget) { toggleWidget(data); } }); /** * Generified adding new stuff to widgets technology! */ JX.Stratcom.listen( ['click'], 'conpherence-widget-adder', function (e) { e.kill(); var widgets = config.widgetRegistry; // the widget key might be in node data, but otherwise use the // selected widget var event_data = e.getNodeData('conpherence-widget-adder'); var widget_key = _selectedWidgetName; if (event_data.widget) { widget_key = widgets[event_data.widget].name; } var widget_to_update = null; var create_data = null; for (var widget in widgets) { if (widgets[widget].name == widget_key) { create_data = widgets[widget].createData; widget_to_update = widget; break; } } // this should be impossible, but hey if (!widget_to_update) { return; } var href = config.widgetBaseUpdateURI + _loadedWidgetsID + '/'; if (create_data.customHref) { 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 data = { latest_transaction_id : latest_transaction_dom.value, action : create_data.action }; new JX.Workflow(href, data) .setHandler(function (r) { latest_transaction_dom.value = r.latest_transaction_id; if (create_data.refreshFromResponse) { var messages = null; try { messages = JX.DOM.find(root, 'div', 'conpherence-messages'); } catch (ex) { } if (messages) { JX.DOM.appendContent(messages, JX.$H(r.transactions)); messages.scrollTop = messages.scrollHeight; } if (r.people_widget) { try { var people_root = JX.DOM.find(root, 'div', 'widgets-people'); // update the people widget JX.DOM.setContent( people_root, JX.$H(r.people_widget)); } catch (ex) { } } // otherwise let's redraw the widget somewhat lazily } else { JX.Stratcom.invoke( 'conpherence-reload-widget', null, { threadID : _loadedWidgetsID, widget : widget_to_update }); } }) .start(); } ); JX.Stratcom.listen( ['touchstart', 'mousedown'], 'remove-person', function (e) { var href = config.widgetBaseUpdateURI + _loadedWidgetsID + '/'; var data = e.getNodeData('remove-person'); // we end up re-directing to conpherence home new JX.Workflow(href, data) .start(); } ); /* settings widget */ var onsubmitSettings = function (e) { e.kill(); var form = e.getNode('tag:form'); var button = JX.DOM.find(form, 'button'); JX.Workflow.newFromForm(form) .setHandler(JX.bind(this, function (r) { new JX.Notification() .setDuration(6000) .setContent(r) .show(); button.disabled = ''; JX.DOM.alterClass(button, 'disabled', false); })) .start(); }; JX.Stratcom.listen( ['submit', 'didSyntheticSubmit'], 'notifications-update', onsubmitSettings ); });