@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 - make the JS layer a bit better

Summary: this diff tries to polish the poo out of the JS layer while achieving fixes T3157 accolades.

Test Plan: introduced sleeps in the various controllers and clicked about. verified good "loading" UI in the menu / message / widget section as appropros. Loaded up in device size and resize and desktop sized and resized and all was good.

Reviewers: epriestley

Reviewed By: epriestley

CC: chad, aran, Korvin

Maniphest Tasks: T3164, T3157

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

+587 -244
+11 -12
src/__celerity_resource_map__.php
··· 918 918 ), 919 919 'conpherence-menu-css' => 920 920 array( 921 - 'uri' => '/res/c955650e/rsrc/css/application/conpherence/menu.css', 921 + 'uri' => '/res/60f38fbd/rsrc/css/application/conpherence/menu.css', 922 922 'type' => 'css', 923 923 'requires' => 924 924 array( ··· 927 927 ), 928 928 'conpherence-message-pane-css' => 929 929 array( 930 - 'uri' => '/res/383af93e/rsrc/css/application/conpherence/message-pane.css', 930 + 'uri' => '/res/d9e90066/rsrc/css/application/conpherence/message-pane.css', 931 931 'type' => 'css', 932 932 'requires' => 933 933 array( ··· 945 945 ), 946 946 'conpherence-widget-pane-css' => 947 947 array( 948 - 'uri' => '/res/6f836b19/rsrc/css/application/conpherence/widget-pane.css', 948 + 'uri' => '/res/b218398a/rsrc/css/application/conpherence/widget-pane.css', 949 949 'type' => 'css', 950 950 'requires' => 951 951 array( ··· 1294 1294 ), 1295 1295 'javelin-behavior-conpherence-menu' => 1296 1296 array( 1297 - 'uri' => '/res/7181099a/rsrc/js/application/conpherence/behavior-menu.js', 1297 + 'uri' => '/res/478fc4f3/rsrc/js/application/conpherence/behavior-menu.js', 1298 1298 'type' => 'js', 1299 1299 'requires' => 1300 1300 array( 1301 1301 0 => 'javelin-behavior', 1302 1302 1 => 'javelin-dom', 1303 1303 2 => 'javelin-util', 1304 - 3 => 'javelin-request', 1305 - 4 => 'javelin-stratcom', 1306 - 5 => 'javelin-workflow', 1307 - 6 => 'javelin-behavior-device', 1308 - 7 => 'javelin-history', 1309 - 8 => 'javelin-vector', 1304 + 3 => 'javelin-stratcom', 1305 + 4 => 'javelin-workflow', 1306 + 5 => 'javelin-behavior-device', 1307 + 6 => 'javelin-history', 1308 + 7 => 'javelin-vector', 1310 1309 ), 1311 1310 'disk' => '/rsrc/js/application/conpherence/behavior-menu.js', 1312 1311 ), 1313 1312 'javelin-behavior-conpherence-pontificate' => 1314 1313 array( 1315 - 'uri' => '/res/88ac3361/rsrc/js/application/conpherence/behavior-pontificate.js', 1314 + 'uri' => '/res/d6c5860f/rsrc/js/application/conpherence/behavior-pontificate.js', 1316 1315 'type' => 'js', 1317 1316 'requires' => 1318 1317 array( ··· 1326 1325 ), 1327 1326 'javelin-behavior-conpherence-widget-pane' => 1328 1327 array( 1329 - 'uri' => '/res/3d426c01/rsrc/js/application/conpherence/behavior-widget-pane.js', 1328 + 'uri' => '/res/232893cf/rsrc/js/application/conpherence/behavior-widget-pane.js', 1330 1329 'type' => 'js', 1331 1330 'requires' => 1332 1331 array(
+10 -1
src/applications/conpherence/controller/ConpherenceController.php
··· 50 50 ->setHref($this->getApplicationURI('update/'.$conpherence->getID().'/')) 51 51 ->setWorkflow(true)); 52 52 53 - return $crumbs; 53 + return hsprintf( 54 + '%s', 55 + array( 56 + phutil_tag( 57 + 'div', 58 + array( 59 + 'class' => 'header-loading-mask' 60 + ), 61 + ''), 62 + $crumbs)); 54 63 } 55 64 56 65 protected function renderConpherenceTransactions(
+6
src/applications/conpherence/controller/ConpherenceListController.php
··· 154 154 ->setThreadView($thread_view) 155 155 ->setRole('list'); 156 156 if ($conpherence) { 157 + $layout->setHeader($this->buildHeaderPaneContent($conpherence)); 157 158 $layout->setThread($conpherence); 159 + } else { 160 + $layout->setHeader( 161 + $this->buildHeaderPaneContent( 162 + id(new ConpherenceThread()) 163 + ->makeEphemeral())); 158 164 } 159 165 $response = $this->buildApplicationPage( 160 166 $layout,
+1 -10
src/applications/conpherence/controller/ConpherenceViewController.php
··· 70 70 $form = null; 71 71 $content = array('messages' => $messages); 72 72 } else { 73 - $header = $this->renderHeaderPaneContent(); 73 + $header = $this->buildHeaderPaneContent($conpherence); 74 74 $form = $this->renderFormContent($data['latest_transaction_id']); 75 75 $content = array( 76 76 'header' => $header, ··· 103 103 )); 104 104 } 105 105 106 - private function renderHeaderPaneContent() { 107 - $conpherence = $this->getConpherence(); 108 - $header = $this->buildHeaderPaneContent($conpherence); 109 - return hsprintf('%s', $header); 110 - } 111 - 112 - 113 106 private function renderMessagePaneContent( 114 107 array $transactions, 115 108 $oldest_transaction_id) { 116 - 117 - require_celerity_resource('conpherence-message-pane-css'); 118 109 119 110 $scrollbutton = ''; 120 111 if ($oldest_transaction_id) {
+1 -2
src/applications/conpherence/controller/ConpherenceWidgetController.php
··· 61 61 } 62 62 63 63 private function renderWidgetPaneContent() { 64 - require_celerity_resource('conpherence-widget-pane-css'); 65 64 require_celerity_resource('sprite-conpherence-css'); 66 65 $conpherence = $this->getConpherence(); 67 66 ··· 73 72 ), 74 73 id(new PhabricatorActionHeaderView()) 75 74 ->setHeaderColor(PhabricatorActionHeaderView::HEADER_GREY) 76 - ->setHeaderTitle('') 75 + ->setHeaderTitle(pht('Participants')) 77 76 ->setHeaderHref('#') 78 77 ->setDropdown(true) 79 78 ->addHeaderSigil('widgets-selector'));
+56 -5
src/applications/conpherence/view/ConpherenceLayoutView.php
··· 51 51 52 52 public function render() { 53 53 require_celerity_resource('conpherence-menu-css'); 54 + require_celerity_resource('conpherence-message-pane-css'); 55 + require_celerity_resource('conpherence-widget-pane-css'); 54 56 55 57 $layout_id = celerity_generate_unique_node_id(); 56 58 59 + $selected_id = null; 60 + $selected_thread_id = null; 61 + if ($this->thread) { 62 + $selected_id = $this->thread->getPHID() . '-nav-item'; 63 + $selected_thread_id = $this->thread->getID(); 64 + } 57 65 Javelin::initBehavior('conpherence-menu', 58 66 array( 59 - 'base_uri' => $this->baseURI, 67 + 'baseURI' => $this->baseURI, 60 68 'layoutID' => $layout_id, 61 - 'selectedID' => ($this->thread ? $this->thread->getID() : null), 69 + 'selectedID' => $selected_id, 70 + 'selectedThreadID' => $selected_thread_id, 62 71 'role' => $this->role, 63 72 'hasThreadList' => (bool)$this->threadView, 64 73 'hasThread' => (bool)$this->messages, ··· 92 101 ), 93 102 ))); 94 103 104 + 105 + $icon_48 = celerity_get_resource_uri('/rsrc/image/loading/loading_48.gif'); 106 + $loading_style = 'background-image: url('.$icon_48.');'; 95 107 return javelin_tag( 96 108 'div', 97 109 array( ··· 114 126 'class' => 'conpherence-menu-pane phabricator-side-menu', 115 127 'sigil' => 'conpherence-menu-pane', 116 128 ), 117 - nonempty($this->threadView, '')), 129 + nonempty( 130 + $this->threadView, 131 + phutil_tag( 132 + 'div', 133 + array( 134 + 'class' => 'menu-loading-icon', 135 + 'style' => $loading_style), 136 + ''))), 118 137 javelin_tag( 119 138 'div', 120 139 array( ··· 159 178 'id' => 'conpherence-widget-pane', 160 179 'sigil' => 'conpherence-widget-pane', 161 180 ), 162 - ''), 181 + array( 182 + phutil_tag( 183 + 'div', 184 + array( 185 + 'class' => 'widgets-loading-mask' 186 + ), 187 + ''), 188 + phutil_tag( 189 + 'div', 190 + array( 191 + 'class' => 'widgets-loading-icon', 192 + 'style' => $loading_style, 193 + ), 194 + ''), 195 + javelin_tag( 196 + 'div', 197 + array( 198 + 'sigil' => 'conpherence-widgets-holder' 199 + ), 200 + ''))), 163 201 javelin_tag( 164 202 'div', 165 203 array( 166 204 'class' => 'conpherence-message-pane', 167 - 'id' => 'conpherence-message-pane' 205 + 'id' => 'conpherence-message-pane', 206 + 'sigil' => 'conpherence-message-pane' 168 207 ), 169 208 array( 170 209 javelin_tag( ··· 175 214 'sigil' => 'conpherence-messages', 176 215 ), 177 216 nonempty($this->messages, '')), 217 + phutil_tag( 218 + 'div', 219 + array( 220 + 'class' => 'messages-loading-mask', 221 + ), 222 + ''), 223 + phutil_tag( 224 + 'div', 225 + array( 226 + 'class' => 'messages-loading-icon', 227 + 'style' => $loading_style, 228 + )), 178 229 javelin_tag( 179 230 'div', 180 231 array(
+3 -1
src/applications/conpherence/view/ConpherenceThreadListView.php
··· 84 84 $unread_count = $data['unread_count']; 85 85 $epoch = $data['epoch']; 86 86 $image = $data['image']; 87 + $dom_id = $thread->getPHID().'-nav-item'; 87 88 88 89 return id(new ConpherenceMenuItemView()) 89 90 ->setUser($user) ··· 98 99 ->setMetadata( 99 100 array( 100 101 'title' => $data['js_title'], 101 - 'id' => $thread->getID(), 102 + 'id' => $dom_id, 103 + 'threadID' => $thread->getID(), 102 104 )); 103 105 } 104 106
+19 -2
webroot/rsrc/css/application/conpherence/menu.css
··· 21 21 margin: 0px 0px 16px 0px; 22 22 } 23 23 24 - .conpherence-menu-pane { 24 + .conpherence-menu-pane .menu-loading-icon { 25 + background-repeat: no-repeat; 26 + background-position: center center; 27 + } 28 + 29 + .conpherence-menu-pane, 30 + .loading .menu-loading-icon { 25 31 width: 100%; 26 32 position: absolute; 27 33 overflow-x: hidden; ··· 30 36 bottom: 0; 31 37 } 32 38 .device-desktop .conpherence-layout .conpherence-menu-pane, 33 - .device-desktop .conpherence-layout .phabricator-nav-column-background { 39 + .device-desktop .conpherence-layout .phabricator-nav-column-background, 40 + .device-desktop .loading .menu-loading-icon { 34 41 width: 280px; 35 42 } 36 43 .device .conpherence-menu-pane { ··· 63 70 } 64 71 65 72 .conpherence-content-pane { 73 + display: none; 66 74 margin-left: 0px; 67 75 position: relative; 76 + } 77 + 78 + .device-desktop .conpherence-content-pane, 79 + .device .conpherence-role-thread .conpherence-content-pane { 80 + display: block; 68 81 } 69 82 70 83 .conpherence-menu .conpherence-menu-item-view { ··· 83 96 .conpherence-menu .conpherence-selected { 84 97 background: rgba(0, 0, 0, .6); 85 98 border-left: 2px solid #66CCFF; 99 + } 100 + 101 + .conpherence-menu .loading { 102 + font-style: italic; 86 103 } 87 104 88 105 .device-desktop .conpherence-menu .conpherence-menu-item-view:hover {
+36 -4
webroot/rsrc/css/application/conpherence/message-pane.css
··· 2 2 * @provides conpherence-message-pane-css 3 3 */ 4 4 5 - .conpherence-message-pane { 5 + .conpherence-message-pane, 6 + .loading .messages-loading-mask, 7 + .loading .messages-loading-icon { 6 8 position: fixed; 7 9 left: 280px; 8 10 right: 241px; 9 11 top: 76px; 12 + bottom: 0px; 10 13 min-width: 300px; 11 14 width: auto; 12 - height: 100%; 13 15 } 14 16 15 - .device .conpherence-message-pane { 17 + .device .conpherence-message-pane, 18 + .device .loading .messages-loading-mask, 19 + .device .loading .messages-loading-icon { 16 20 left: 0; 17 21 right: 0; 18 22 width: 100%; 19 23 } 20 24 21 - 22 25 .conpherence-show-older-messages { 23 26 display: block; 24 27 background: #e0e3ec; ··· 26 29 text-align: center; 27 30 padding: 10px; 28 31 color: #18559D; 32 + } 33 + 34 + .conpherence-show-older-messages-loading { 35 + font-style: italic; 29 36 } 30 37 31 38 .conpherence-message-pane .conpherence-messages { ··· 45 52 bottom: 3em; 46 53 width: 100%; 47 54 box-shadow: none; 55 + } 56 + 57 + .conpherence-message-pane .messages-loading-mask { 58 + opacity: .22; 59 + background: #222; 60 + display: none; 61 + } 62 + .conpherence-message-pane .messages-loading-icon { 63 + background-repeat: no-repeat; 64 + background-position: center center; 65 + } 66 + 67 + .loading .messages-loading-mask, 68 + .loading .messages-loading-icon { 69 + display: block; 70 + z-index: 500; 71 + } 72 + 73 + .loading .header-loading-mask { 74 + height: 31px; 75 + position: absolute; 76 + width: 100%; 77 + z-index: 5; 78 + background: #222; 79 + opacity: .22; 48 80 } 49 81 50 82 .conpherence-message-pane .phabricator-form-view {
+27 -3
webroot/rsrc/css/application/conpherence/widget-pane.css
··· 2 2 * @provides conpherence-widget-pane-css 3 3 */ 4 4 5 - .conpherence-widget-pane { 5 + .conpherence-widget-pane, 6 + .loading .widgets-loading-mask, 7 + .loading .widgets-loading-icon { 6 8 position: fixed; 7 9 right: 0px; 8 10 top: 74px; 11 + bottom: 0px; 9 12 width: 240px; 10 - height: 100%; 11 13 border-width: 0 0 0 1px; 12 14 border-color: #CCC; 13 15 border-style: solid; ··· 15 17 -webkit-overflow-scrolling: touch; 16 18 } 17 19 18 - .device .conpherence-widget-pane { 20 + .device .conpherence-widget-pane, 21 + .device .loading .widgets-loading-mask, 22 + .device .loading .widgets-loading-icon { 19 23 top: 44px; 20 24 width: 100%; 25 + } 26 + 27 + .conpherence-widget-pane .widgets-loading-mask { 28 + opacity: .22; 29 + background: #222; 30 + display: none; 31 + } 32 + .conpherence-widget-pane .widgets-loading-icon { 33 + background-repeat: no-repeat; 34 + background-position: center center; 35 + } 36 + 37 + .loading .widgets-loading-mask, 38 + .loading .widgets-loading-icon { 39 + display: block; 40 + z-index: 500; 21 41 } 22 42 23 43 .conpherence-widget-pane .aphront-form-input { ··· 79 99 padding: 20px; 80 100 text-align: center; 81 101 color: #555; 102 + } 103 + .device .conpherence-widget-pane #widgets-files .no-files { 104 + width: 60px; 105 + margin: 0px auto 0px auto; 82 106 } 83 107 .conpherence-widget-pane #widgets-files .file-entry { 84 108 padding: 10px 0;
+246 -141
webroot/rsrc/js/application/conpherence/behavior-menu.js
··· 3 3 * @requires javelin-behavior 4 4 * javelin-dom 5 5 * javelin-util 6 - * javelin-request 7 6 * javelin-stratcom 8 7 * javelin-workflow 9 8 * javelin-behavior-device ··· 13 12 14 13 JX.behavior('conpherence-menu', function(config) { 15 14 16 - var thread = { 15 + /** 16 + * State for displayed thread. 17 + */ 18 + var _thread = { 17 19 selected: null, 18 - node: null, 19 - visible: null 20 + visible: null, 21 + node: null 20 22 }; 21 23 22 - function selectthreadid(id, updatePageData) { 23 - var threads = JX.DOM.scry(document.body, 'a', 'conpherence-menu-click'); 24 - for (var ii = 0; ii < threads.length; ii++) { 25 - var data = JX.Stratcom.getData(threads[ii]); 26 - if (data.id == id) { 27 - selectthread(threads[ii], updatePageData); 28 - return; 29 - } 24 + /** 25 + * Current role of this behavior. The two possible roles are to show a 'list' 26 + * of threads or a specific 'thread'. On devices, this behavior stays in the 27 + * 'list' role indefinitely, treating clicks normally and the next page 28 + * loads the behavior with role = 'thread'. On desktop, this behavior 29 + * auto-loads a thread as part of the 'list' role. As the thread loads the 30 + * role is changed to 'thread'. 31 + */ 32 + var _currentRole = null; 33 + 34 + /** 35 + * When _oldDevice is null the code is executing for the first time. 36 + */ 37 + var _oldDevice = null; 38 + 39 + /** 40 + * Initializes this behavior based on all the configuraton jonx and the 41 + * result of JX.Device.getDevice(); 42 + */ 43 + function init() { 44 + _currentRole = config.role; 45 + 46 + if (_currentRole == 'thread') { 47 + markThreadsLoading(true); 48 + } else { 49 + markThreadLoading(true); 30 50 } 51 + markWidgetLoading(true); 52 + onDeviceChange(); 31 53 } 54 + init(); 32 55 33 - function selectthread(node, updatePageData) { 56 + /** 57 + * Selecting threads 58 + */ 59 + JX.Stratcom.listen( 60 + 'conpherence-selectthread', 61 + null, 62 + function (e) { 63 + selectThreadByID(e.getData().id); 64 + } 65 + ); 34 66 35 - if (thread.node) { 36 - JX.DOM.alterClass(thread.node, 'conpherence-selected', false); 67 + function selectThreadByID(id, update_page_data) { 68 + var thread = JX.$(id); 69 + selectThread(thread, update_page_data); 70 + } 71 + 72 + function selectThread(node, update_page_data) { 73 + if (_thread.node) { 74 + JX.DOM.alterClass(_thread.node, 'conpherence-selected', false); 37 75 // keep the unread-count hidden still. big TODO once we ajax in updates 38 76 // to threads to make this work right and move threads between read / 39 77 // unread ··· 42 80 JX.DOM.alterClass(node, 'conpherence-selected', true); 43 81 JX.DOM.alterClass(node, 'hide-unread-count', true); 44 82 45 - thread.node = node; 83 + _thread.node = node; 46 84 47 85 var data = JX.Stratcom.getData(node); 48 - thread.selected = data.id; 86 + _thread.selected = data.threadID; 49 87 50 - if (updatePageData) { 51 - updatepagedata(data); 88 + if (update_page_data) { 89 + updatePageData(data); 52 90 } 53 91 54 - redrawthread(); 92 + redrawThread(); 55 93 } 56 94 57 - JX.Stratcom.listen( 58 - 'conpherence-selectthread', 59 - null, 60 - function (e) { 61 - var node = JX.$(e.getData().id); 62 - selectthread(node); 63 - } 64 - ); 65 - 66 - function updatepagedata(data) { 67 - var uri_suffix = thread.selected + '/'; 95 + function updatePageData(data) { 96 + var uri_suffix = _thread.selected + '/'; 68 97 if (data.use_base_uri) { 69 98 uri_suffix = ''; 70 99 } 71 - JX.History.replace(config.base_uri + uri_suffix); 100 + JX.History.replace(config.baseURI + uri_suffix); 72 101 if (data.title) { 73 102 document.title = data.title; 74 - } else if (thread.node) { 75 - var threadData = JX.Stratcom.getData(thread.node); 103 + } else if (_thread.node) { 104 + var threadData = JX.Stratcom.getData(_thread.node); 76 105 document.title = threadData.title; 77 106 } 78 107 } ··· 81 110 'conpherence-update-page-data', 82 111 null, 83 112 function (e) { 84 - updatepagedata(e.getData()); 113 + updatePageData(e.getData()); 85 114 } 86 115 ); 87 116 88 - function redrawthread() { 89 - if (!thread.node) { 117 + function redrawThread() { 118 + if (!_thread.node) { 90 119 return; 91 120 } 92 121 93 - if (thread.visible == thread.selected) { 122 + if (_thread.visible == _thread.selected) { 94 123 return; 95 124 } 96 125 97 - var data = JX.Stratcom.getData(thread.node); 126 + var data = JX.Stratcom.getData(_thread.node); 98 127 99 - if (thread.visible !== null || !config.hasThread) { 100 - var uri = config.base_uri + data.id + '/'; 128 + if (_thread.visible !== null || !config.hasThread) { 129 + markThreadLoading(true); 130 + var uri = config.baseURI + data.threadID + '/'; 101 131 new JX.Workflow(uri, {}) 102 - .setHandler(onloadthreadresponse) 132 + .setHandler(JX.bind(null, onLoadThreadResponse, data.threadID)) 103 133 .start(); 134 + } else if (config.hasThread) { 135 + _scrollMessageWindow(); 104 136 } else { 105 - didredrawthread(); 137 + didRedrawThread(); 106 138 } 107 139 108 - if (thread.visible !== null || !config.hasWidgets) { 109 - var widget_uri = config.base_uri + 'widget/' + data.id + '/'; 140 + if (_thread.visible !== null || !config.hasWidgets) { 141 + markWidgetLoading(true); 142 + var widget_uri = config.baseURI + 'widget/' + data.threadID + '/'; 110 143 new JX.Workflow(widget_uri, {}) 111 - .setHandler(onwidgetresponse) 144 + .setHandler(JX.bind(null, onWidgetResponse, data.threadID)) 112 145 .start(); 113 146 } else { 114 - updatetoggledwidget(); 147 + JX.Stratcom.invoke( 148 + 'conpherence-update-widgets', 149 + null, 150 + { 151 + widget : getDefaultWidget(), 152 + buildSelectors : false, 153 + toggleWidget : true, 154 + threadID : _thread.selected 155 + }); 115 156 } 116 157 117 - thread.visible = thread.selected; 158 + _thread.visible = _thread.selected; 159 + } 160 + 161 + function markThreadsLoading(loading) { 162 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 163 + var menu = JX.DOM.find(root, 'div', 'conpherence-menu-pane'); 164 + JX.DOM.alterClass(menu, 'loading', loading); 165 + } 166 + 167 + function markThreadLoading(loading) { 168 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 169 + var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); 170 + var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane'); 171 + var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); 172 + 173 + JX.DOM.alterClass(header_root, 'loading', loading); 174 + JX.DOM.alterClass(messages_root, 'loading', loading); 175 + JX.DOM.alterClass(form_root, 'loading', loading); 176 + 177 + try { 178 + var textarea = JX.DOM.find(form, 'textarea'); 179 + textarea.disabled = loading; 180 + var button = JX.DOM.find(form, 'button'); 181 + button.disabled = loading; 182 + } catch (ex) { 183 + // haven't loaded it yet! 184 + } 118 185 } 119 186 120 - function onwidgetresponse(response) { 187 + function markWidgetLoading(loading) { 121 188 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 122 - var widgetsRoot = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); 123 - JX.DOM.setContent(widgetsRoot, JX.$H(response.widgets)); 124 - updatetoggledwidget(); 189 + var widgets_root = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); 190 + 191 + JX.DOM.alterClass(widgets_root, 'loading', loading); 125 192 } 126 193 127 - function updatetoggledwidget(no_toggle) { 194 + function onWidgetResponse(thread_id, response) { 195 + // we got impatient and this is no longer the right answer :/ 196 + if (_thread.selected != thread_id) { 197 + return; 198 + } 199 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 200 + var widgets_root = JX.DOM.find(root, 'div', 'conpherence-widgets-holder'); 201 + JX.DOM.setContent(widgets_root, JX.$H(response.widgets)); 202 + 128 203 JX.Stratcom.invoke( 129 - 'conpherence-toggle-widget', 204 + 'conpherence-update-widgets', 130 205 null, 131 206 { 132 - widget : getdefaultwidget(), 133 - no_toggle : no_toggle 207 + widget : getDefaultWidget(), 208 + buildSelectors : true, 209 + toggleWidget : true, 210 + threadID : _thread.selected 134 211 }); 212 + 213 + markWidgetLoading(false); 135 214 } 136 215 137 - function getdefaultwidget() { 216 + function getDefaultWidget() { 138 217 var device = JX.Device.getDevice(); 139 218 var widget = 'conpherence-message-pane'; 140 219 if (device == 'desktop') { ··· 143 222 return widget; 144 223 } 145 224 146 - function onloadthreadresponse(response) { 225 + function onLoadThreadResponse(thread_id, response) { 226 + // we got impatient and this is no longer the right answer :/ 227 + if (_thread.selected != thread_id) { 228 + return; 229 + } 147 230 var header = JX.$H(response.header); 148 231 var messages = JX.$H(response.messages); 149 232 var form = JX.$H(response.form); 150 233 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 151 - var headerRoot = JX.DOM.find(root, 'div', 'conpherence-header-pane'); 152 - var messagesRoot = JX.DOM.find(root, 'div', 'conpherence-messages'); 153 - var formRoot = JX.DOM.find(root, 'div', 'conpherence-form'); 154 - JX.DOM.setContent(headerRoot, header); 155 - JX.DOM.setContent(messagesRoot, messages); 156 - JX.DOM.setContent(formRoot, form); 234 + var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); 235 + var messages_root = JX.DOM.find(root, 'div', 'conpherence-messages'); 236 + var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); 237 + JX.DOM.setContent(header_root, header); 238 + JX.DOM.setContent(messages_root, messages); 239 + JX.DOM.setContent(form_root, form); 240 + 241 + markThreadLoading(false); 157 242 158 - didredrawthread(); 243 + didRedrawThread(true); 159 244 } 160 245 161 - function didredrawthread() { 246 + /** 247 + * This function is a wee bit tricky. Internally, we want to scroll the 248 + * message window and let other stuff - notably widgets - redraw / build if 249 + * necessary. Externally, we want a hook to scroll the message window 250 + * - notably when the widget selector is used to invoke the message pane. 251 + * The following three functions get 'er done. 252 + */ 253 + function didRedrawThread(build_device_widget_selector) { 254 + _scrollMessageWindow(); 255 + JX.Stratcom.invoke( 256 + 'conpherence-did-redraw-thread', 257 + null, 258 + { 259 + widget : getDefaultWidget(), 260 + threadID : _thread.selected, 261 + buildDeviceWidgetSelector : build_device_widget_selector 262 + }); 263 + } 264 + function _scrollMessageWindow() { 162 265 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 163 - var messagesRoot = JX.DOM.find(root, 'div', 'conpherence-messages'); 164 - messagesRoot.scrollTop = messagesRoot.scrollHeight; 165 - 166 - try { 167 - var device = JX.Device.getDevice(); 168 - var deviceWidgetSelector = JX.DOM.find( 169 - root, 170 - 'a', 171 - 'device-widgets-selector'); 172 - if (device != 'desktop') { 173 - JX.DOM.show(deviceWidgetSelector); 174 - updatetoggledwidget(true); 175 - } else { 176 - JX.DOM.hide(deviceWidgetSelector); 177 - } 178 - } catch (ex) { 179 - // not here yet 180 - } 266 + var messages_root = JX.DOM.find(root, 'div', 'conpherence-messages'); 267 + messages_root.scrollTop = messages_root.scrollHeight; 181 268 } 182 - 183 269 JX.Stratcom.listen( 184 270 'conpherence-redraw-thread', 185 271 null, 186 272 function (e) { 187 - didredrawthread(); 273 + _scrollMessageWindow(); 188 274 } 189 275 ); 190 276 ··· 202 288 } 203 289 204 290 e.kill(); 205 - selectthread(e.getNode('conpherence-menu-click'), true); 291 + selectThread(e.getNode('conpherence-menu-click'), true); 206 292 }); 207 293 208 294 JX.Stratcom.listen('click', 'conpherence-edit-metadata', function (e) { ··· 241 327 .start(); 242 328 }); 243 329 330 + var _loadingTransactionID = null; 244 331 JX.Stratcom.listen('click', 'show-older-messages', function(e) { 245 332 e.kill(); 246 333 var data = e.getNodeData('show-older-messages'); 247 - var oldest_transaction_id = data.oldest_transaction_id; 248 - var conf_id = thread.selected; 249 - JX.DOM.remove(e.getNode('show-older-messages')); 334 + if (data.oldest_transaction_id == _loadingTransactionID) { 335 + return; 336 + } 337 + _loadingTransactionID = data.oldest_transaction_id; 338 + var node = e.getNode('show-older-messages'); 339 + JX.DOM.setContent(node, 'Loading...'); 340 + JX.DOM.alterClass(node, 'conpherence-show-older-messages-loading', true); 341 + 342 + var conf_id = _thread.selected; 250 343 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 251 344 var messages_root = JX.DOM.find(root, 'div', 'conpherence-messages'); 252 - new JX.Request(config.base_uri + conf_id + '/', function(r) { 345 + new JX.Workflow(config.baseURI + conf_id + '/', data) 346 + .setHandler(function(r) { 347 + JX.DOM.remove(node); 253 348 var messages = JX.$H(r.messages); 254 349 JX.DOM.prependContent( 255 350 messages_root, 256 351 JX.$H(messages)); 257 - }).setData({ oldest_transaction_id : oldest_transaction_id }).send(); 352 + }).start(); 258 353 }); 259 354 260 - // On mobile, we just show a thread list, so we don't want to automatically 261 - // select or load any threads. On Desktop, we automatically select the first 262 - // thread. 263 - var old_device = null; 264 - function ondevicechange() { 355 + /** 356 + * On devices, we just show a thread list, so we don't want to automatically 357 + * select or load any threads. On desktop, we automatically select the first 358 + * thread, changing the _currentRole from list to thread. 359 + */ 360 + function onDeviceChange() { 265 361 var new_device = JX.Device.getDevice(); 266 - if (new_device === old_device) { 362 + if (new_device === _oldDevice) { 267 363 return; 268 364 } 269 365 270 - if (old_device === null) { 271 - old_device = new_device; 272 - if (config.role == 'list') { 366 + if (_oldDevice === null) { 367 + _oldDevice = new_device; 368 + if (_currentRole == 'list') { 273 369 if (new_device != 'desktop') { 274 370 return; 275 371 } 276 372 } else { 277 - loadthreads(); 373 + loadThreads(); 278 374 return; 279 375 } 280 376 } 281 377 var update_toggled_widget = 282 - new_device == 'desktop' || old_device == 'desktop'; 283 - old_device = new_device; 378 + new_device == 'desktop' || _oldDevice == 'desktop'; 379 + _oldDevice = new_device; 284 380 285 - if (thread.visible !== null && update_toggled_widget) { 286 - updatetoggledwidget(); 381 + if (_thread.visible !== null && update_toggled_widget) { 382 + JX.Stratcom.invoke( 383 + 'conpherence-did-redraw-thread', 384 + null, 385 + { 386 + widget : getDefaultWidget(), 387 + threadID : _thread.selected 388 + }); 287 389 } 288 390 289 - if (config.role == 'list') { 290 - didloadthreads(); 291 - config.role = 'thread'; 391 + if (_currentRole == 'list' && new_device == 'desktop') { 392 + // this selects a thread and loads it 393 + didLoadThreads(); 394 + _currentRole = 'thread'; 292 395 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 293 396 JX.DOM.alterClass(root, 'conpherence-role-list', false); 294 397 JX.DOM.alterClass(root, 'conpherence-role-thread', true); 295 398 } 296 399 } 297 - 298 - JX.Stratcom.listen('phabricator-device-change', null, ondevicechange); 299 - ondevicechange(); 400 + JX.Stratcom.listen('phabricator-device-change', null, onDeviceChange); 300 401 301 - function loadthreads() { 302 - var uri = config.base_uri + 'thread/' + config.selectedID + '/'; 402 + function loadThreads() { 403 + markThreadsLoading(true); 404 + var uri = config.baseURI + 'thread/' + config.selectedThreadID + '/'; 303 405 new JX.Workflow(uri) 304 - .setHandler(onloadthreadsresponse) 406 + .setHandler(onLoadThreadsResponse) 305 407 .start(); 306 408 } 307 409 308 - function onloadthreadsresponse(r) { 410 + function onLoadThreadsResponse(r) { 309 411 var layout = JX.$(config.layoutID); 310 412 var menu = JX.DOM.find(layout, 'div', 'conpherence-menu-pane'); 311 413 JX.DOM.setContent(menu, JX.$H(r)); 312 414 313 - config.selectedID && selectthreadid(config.selectedID); 415 + config.selectedID && selectThreadByID(config.selectedID); 314 416 315 - thread.node.scrollIntoView(); 417 + _thread.node.scrollIntoView(); 418 + 419 + markThreadsLoading(false); 316 420 } 317 421 318 - function didloadthreads() { 422 + function didLoadThreads() { 319 423 // If there's no thread selected yet, select the current thread or the 320 424 // first thread. 321 - if (!thread.selected) { 425 + if (!_thread.selected) { 322 426 if (config.selectedID) { 323 - selectthreadid(config.selectedID, true); 427 + selectThreadByID(config.selectedID, true); 324 428 } else { 325 429 var layout = JX.$(config.layoutID); 326 430 var threads = JX.DOM.scry(layout, 'a', 'conpherence-menu-click'); 327 431 if (threads.length) { 328 - selectthread(threads[0]); 432 + selectThread(threads[0]); 329 433 } else { 330 434 var nothreads = JX.DOM.find(layout, 'div', 'conpherence-no-threads'); 331 435 nothreads.style.display = 'block'; 332 436 } 333 437 } 334 438 } 335 - redrawthread(); 336 439 } 337 440 338 - var handlethreadscrollers = function (e) { 441 + var handleThreadScrollers = function (e) { 339 442 e.kill(); 340 443 341 444 var data = e.getNodeData('conpherence-menu-scroller'); 342 445 var scroller = e.getNode('conpherence-menu-scroller'); 446 + JX.DOM.alterClass(scroller, 'loading', true); 447 + JX.DOM.setContent(scroller.firstChild, 'Loading...'); 343 448 new JX.Workflow(scroller.href, data) 344 449 .setHandler( 345 - JX.bind(null, threadscrollerresponse, scroller, data.direction)) 450 + JX.bind(null, threadScrollerResponse, scroller, data.direction)) 346 451 .start(); 347 452 }; 348 453 349 - var threadscrollerresponse = function (scroller, direction, r) { 454 + var threadScrollerResponse = function (scroller, direction, r) { 350 455 var html = JX.$H(r.html); 351 456 352 - var threadPhids = r.phids; 353 - var reselectId = null; 457 + var thread_phids = r.phids; 458 + var reselect_id = null; 354 459 // remove any threads that are in the list that we just got back 355 460 // in the result set; things have changed and they'll be in the 356 461 // right place soon 357 - for (var ii = 0; ii < threadPhids.length; ii++) { 462 + for (var ii = 0; ii < thread_phids.length; ii++) { 358 463 try { 359 - var nodeId = threadPhids[ii] + '-nav-item'; 360 - var node = JX.$(nodeId); 361 - var nodeData = JX.Stratcom.getData(node); 362 - if (nodeData.id == thread.selected) { 363 - reselectId = nodeId; 464 + var node_id = thread_phids[ii] + '-nav-item'; 465 + var node = JX.$(node_id); 466 + var node_data = JX.Stratcom.getData(node); 467 + if (node_data.id == _thread.selected) { 468 + reselect_id = node_id; 364 469 } 365 470 JX.DOM.remove(node); 366 471 } catch (ex) { ··· 369 474 } 370 475 371 476 var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 372 - var menuRoot = JX.DOM.find(root, 'div', 'conpherence-menu-pane'); 373 - var scrollY = 0; 477 + var menu_root = JX.DOM.find(root, 'div', 'conpherence-menu-pane'); 478 + var scroll_y = 0; 374 479 // we have to do some hyjinx in the up case to make the menu scroll to 375 480 // where it should 376 481 if (direction == 'up') { ··· 382 487 document.body.appendChild(test_size); 383 488 var html_size = JX.Vector.getDim(test_size); 384 489 JX.DOM.remove(test_size); 385 - scrollY = html_size.y; 490 + scroll_y = html_size.y; 386 491 } 387 492 JX.DOM.replace(scroller, html); 388 - menuRoot.scrollTop += scrollY; 493 + menu_root.scrollTop += scroll_y; 389 494 390 - if (reselectId) { 495 + if (reselect_id) { 391 496 JX.Stratcom.invoke( 392 497 'conpherence-selectthread', 393 498 null, 394 - { id : reselectId } 499 + { id : reselect_id } 395 500 ); 396 501 } 397 502 }; ··· 399 504 JX.Stratcom.listen( 400 505 ['click'], 401 506 'conpherence-menu-scroller', 402 - handlethreadscrollers 507 + handleThreadScrollers 403 508 ); 404 509 405 510 });
+12 -2
webroot/rsrc/js/application/conpherence/behavior-pontificate.js
··· 14 14 var form = e.getNode('tag:form'); 15 15 16 16 var root = e.getNode('conpherence-layout'); 17 - var messages = JX.DOM.find(root, 'div', 'conpherence-messages'); 17 + var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane'); 18 + var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); 19 + var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); 20 + var messages = JX.DOM.find(messages_root, 'div', 'conpherence-messages'); 18 21 var fileWidget = null; 19 22 try { 20 23 fileWidget = JX.DOM.find(root, 'div', 'widgets-files'); 21 24 } catch (ex) { 22 25 // Ignore; maybe no files widget 23 26 } 27 + JX.DOM.alterClass(header_root, 'loading', true); 28 + JX.DOM.alterClass(messages_root, 'loading', true); 29 + JX.DOM.alterClass(form_root, 'loading', true); 24 30 25 31 JX.Workflow.newFromForm(form) 26 32 .setHandler(JX.bind(this, function(r) { ··· 49 55 'conpherence-selectthread', 50 56 null, 51 57 { id : r.conpherence_phid + '-nav-item' } 52 - ); 58 + ); 59 + 60 + JX.DOM.alterClass(header_root, 'loading', false); 61 + JX.DOM.alterClass(messages_root, 'loading', false); 62 + JX.DOM.alterClass(form_root, 'loading', false); 53 63 })) 54 64 .start(); 55 65 };
+159 -61
webroot/rsrc/js/application/conpherence/behavior-widget-pane.js
··· 13 13 14 14 JX.behavior('conpherence-widget-pane', function(config) { 15 15 16 - var build_widget_selector = function (data) { 17 - var widgets = config.widgetRegistry; 18 - var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 19 - var widgetPane = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); 20 - var widgetHeader = JX.DOM.find(widgetPane, 'a', 'widgets-selector'); 21 - var mobileWidgetHeader = null; 22 - try { 23 - mobileWidgetHeader = JX.DOM.find( 24 - root, 25 - 'a', 26 - 'device-widgets-selector'); 27 - } catch (ex) { 28 - // is okay - no mobileWidgetHeader yet... 16 + /** 17 + * There can be race conditions around loading the messages or the widgets 18 + * first. Keep track of what widgets we've loaded with this variable. 19 + */ 20 + var _loadedWidgetsID = null; 21 + 22 + /** 23 + * At any given time there can be only one selected widget. Keep track of 24 + * which one it is by the user-facing name for ease of use with 25 + * PhabricatorDropdownMenuItems. 26 + */ 27 + var _selectedWidgetName = null; 28 + 29 + /** 30 + * This is potentially built each time the user switches conpherence threads 31 + * or when the result JX.Device.getDevice() changes from desktop to some 32 + * other value. 33 + */ 34 + var buildDeviceWidgetSelector = function (data) { 35 + var device_header = _getDeviceWidgetHeader(); 36 + if (!device_header) { 37 + return; 29 38 } 30 - var widgetData = widgets[data.widget]; 31 - JX.DOM.setContent( 32 - widgetHeader, 33 - widgetData.name); 34 - JX.DOM.appendContent( 35 - widgetHeader, 36 - JX.$N('span', { className : 'caret' })); 37 - if (mobileWidgetHeader) { 38 - // this is fragile but adding a sigil to this element is awkward 39 - var mobileWidgetHeaderSpans = JX.DOM.scry(mobileWidgetHeader, 'span'); 40 - var mobileWidgetHeaderSpan = mobileWidgetHeaderSpans[1]; 41 - JX.DOM.setContent( 42 - mobileWidgetHeaderSpan, 43 - widgetData.name); 44 - } 39 + JX.DOM.show(device_header); 40 + var device_menu = new JX.PhabricatorDropdownMenu(device_header); 41 + data.deviceMenu = true; 42 + _buildWidgetSelector(device_menu, data); 43 + }; 45 44 46 - var menu = new JX.PhabricatorDropdownMenu(widgetHeader); 45 + /** 46 + * This is potentially built each time the user switches conpherence threads 47 + * or when the result JX.Device.getDevice() changes from mobile or tablet to 48 + * desktop. 49 + */ 50 + var buildDesktopWidgetSelector = function (data) { 51 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 52 + var widget_pane = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); 53 + var widget_header = JX.DOM.find(widget_pane, 'a', 'widgets-selector'); 54 + var menu = new JX.PhabricatorDropdownMenu(widget_header); 47 55 menu.toggleAlignDropdownRight(false); 48 - var deviceMenu = null; 49 - if (mobileWidgetHeader) { 50 - deviceMenu = new JX.PhabricatorDropdownMenu(mobileWidgetHeader); 51 - } 56 + data.deviceMenu = false; 57 + _buildWidgetSelector(menu, data); 58 + }; 52 59 60 + /** 61 + * Workhorse that actually builds the widget selector. Note some fancy bits 62 + * where we listen for the "open" event and enable / disable widgets as 63 + * appropos. 64 + */ 65 + var _buildWidgetSelector = function (menu, data) { 66 + _loadedWidgetsID = data.threadID; 67 + var widgets = config.widgetRegistry; 53 68 for (var widget in widgets) { 54 - widgetData = widgets[widget]; 55 - if (mobileWidgetHeader) { 56 - deviceMenu.addItem(new JX.PhabricatorMenuItem( 57 - widgetData.name, 58 - JX.bind(null, build_widget_selector, { widget : widget }), 59 - '#' 60 - ).setDisabled(widget == data.widget)); 61 - } 62 - if (widgetData.deviceOnly) { 69 + var widget_data = widgets[widget]; 70 + if (widget_data.deviceOnly && data.deviceMenu === false) { 63 71 continue; 64 72 } 65 73 menu.addItem(new JX.PhabricatorMenuItem( 66 - widgetData.name, 67 - JX.bind(null, build_widget_selector, { widget : widget }), 74 + widget_data.name, 75 + JX.bind(null, toggleWidget, { widget : widget }), 68 76 '#' 69 77 ).setDisabled(widget == data.widget)); 70 78 } 71 - if (data.no_toggle) { 79 + 80 + menu.listen( 81 + 'open', 82 + JX.bind(menu, function () { 83 + for (var ii = 0; ii < this._items.length; ii++) { 84 + var item = this._items[ii]; 85 + var name = item.getName(); 86 + if (name == _selectedWidgetName) { 87 + item.setDisabled(true); 88 + } else { 89 + item.setDisabled(false); 90 + } 91 + } 92 + })); 93 + }; 94 + 95 + /** 96 + * Since this is not always on the page, avoid having a repeat 97 + * try / catch block and consolidate into this helper function. 98 + */ 99 + var _getDeviceWidgetHeader = function () { 100 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 101 + var device_header = null; 102 + try { 103 + device_header = JX.DOM.find( 104 + root, 105 + 'a', 106 + 'device-widgets-selector'); 107 + } catch (ex) { 108 + // is okay - no deviceWidgetHeader yet... but bail time 109 + } 110 + return device_header; 111 + }; 112 + 113 + /** 114 + * Responder to the 'conpherence-did-redraw-thread' event, this bad boy 115 + * hides or shows the device widget selector as appropros. 116 + */ 117 + var _didRedrawThread = function (data) { 118 + if (_loadedWidgetsID === null || _loadedWidgetsID != data.threadID) { 72 119 return; 73 120 } 74 - toggle_widget(data); 121 + var device = JX.Device.getDevice(); 122 + var device_selector = _getDeviceWidgetHeader(); 123 + if (device == 'desktop') { 124 + JX.DOM.hide(device_selector); 125 + } else { 126 + JX.DOM.show(device_selector); 127 + } 128 + if (data.buildDeviceWidgetSelector) { 129 + buildDeviceWidgetSelector(data); 130 + } 131 + toggleWidget(data); 75 132 }; 133 + JX.Stratcom.listen( 134 + 'conpherence-did-redraw-thread', 135 + null, 136 + function (e) { 137 + _didRedrawThread(e.getData()); 138 + } 139 + ); 76 140 77 - var toggle_widget = function (data) { 141 + /** 142 + * Toggling a widget involves showing / hiding the appropriate widget 143 + * bodies as well as updating the selectors to have the label on the 144 + * newly selected widget. 145 + */ 146 + var toggleWidget = function (data) { 78 147 var widgets = config.widgetRegistry; 79 - var widgetData = widgets[data.widget]; 148 + var widget_data = widgets[data.widget]; 80 149 var device = JX.Device.getDevice(); 81 150 var is_desktop = device == 'desktop'; 82 151 83 - if (widgetData.deviceOnly && is_desktop) { 152 + if (widget_data.deviceOnly && is_desktop) { 84 153 return; 85 154 } 155 + _selectedWidgetName = widget_data.name; 156 + 157 + var device_header = _getDeviceWidgetHeader(); 158 + if (device_header) { 159 + // this is fragile but adding a sigil to this element is awkward 160 + var device_header_spans = JX.DOM.scry(device_header, 'span'); 161 + var device_header_span = device_header_spans[1]; 162 + JX.DOM.setContent( 163 + device_header_span, 164 + widget_data.name); 165 + } 166 + 167 + // don't update the non-device selector with device only widget stuff 168 + if (!widget_data.deviceOnly) { 169 + var root = JX.DOM.find(document, 'div', 'conpherence-layout'); 170 + var widget_pane = JX.DOM.find(root, 'div', 'conpherence-widget-pane'); 171 + var widget_header = JX.DOM.find(widget_pane, 'a', 'widgets-selector'); 172 + JX.DOM.setContent( 173 + widget_header, 174 + widget_data.name); 175 + JX.DOM.appendContent( 176 + widget_header, 177 + JX.$N('span', { className : 'caret' })); 178 + } 86 179 87 180 for (var widget in config.widgetRegistry) { 88 - widgetData = widgets[widget]; 89 - if (widgetData.deviceOnly && is_desktop) { 181 + widget_data = widgets[widget]; 182 + if (widget_data.deviceOnly && is_desktop) { 90 183 // some one off code for conpherence messages which are device-only 91 184 // as a widget, but shown always on the desktop 92 185 if (widget == 'conpherence-message-pane') { ··· 109 202 }; 110 203 111 204 JX.Stratcom.listen( 112 - 'conpherence-toggle-widget', 205 + 'conpherence-update-widgets', 113 206 null, 114 207 function (e) { 115 - build_widget_selector(e.getData()); 116 - } 117 - ); 118 - 208 + var data = e.getData(); 209 + if (data.buildSelectors) { 210 + buildDesktopWidgetSelector(data); 211 + buildDeviceWidgetSelector(data); 212 + } 213 + if (data.toggleWidget) { 214 + toggleWidget(data); 215 + } 216 + }); 119 217 120 218 /* people widget */ 121 219 JX.Stratcom.listen( ··· 126 224 var root = e.getNode('conpherence-layout'); 127 225 var form = e.getNode('tag:form'); 128 226 var data = e.getNodeData('add-person'); 129 - var peopleRoot = e.getNode('widgets-people'); 227 + var people_root = e.getNode('widgets-people'); 130 228 var messages = null; 131 229 try { 132 230 messages = JX.DOM.find(root, 'div', 'conpherence-messages'); 133 231 } catch (ex) { 134 232 } 135 - var latestTransactionData = JX.Stratcom.getData( 233 + var latest_transaction_data = JX.Stratcom.getData( 136 234 JX.DOM.find( 137 235 root, 138 236 'input', 139 237 'latest-transaction-id' 140 238 )); 141 - data.latest_transaction_id = latestTransactionData.id; 239 + data.latest_transaction_id = latest_transaction_data.id; 142 240 JX.Workflow.newFromForm(form, data) 143 241 .setHandler(JX.bind(this, function (r) { 144 242 if (messages) { ··· 148 246 149 247 // update the people widget 150 248 JX.DOM.setContent( 151 - peopleRoot, 249 + people_root, 152 250 JX.$H(r.people_widget) 153 251 ); 154 252 })) ··· 160 258 ['touchstart', 'mousedown'], 161 259 'remove-person', 162 260 function (e) { 163 - var peopleRoot = e.getNode('widgets-people'); 261 + var people_root = e.getNode('widgets-people'); 164 262 var form = JX.DOM.find(peopleRoot, 'form'); 165 263 var data = e.getNodeData('remove-person'); 166 264 // we end up re-directing to conpherence home