[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 /** 2 * @provides changeset-view-manager 3 * @requires javelin-dom 4 * javelin-util 5 * javelin-stratcom 6 * javelin-install 7 * javelin-workflow 8 * javelin-router 9 * javelin-behavior-device 10 * javelin-vector 11 */ 12 13 14 JX.install('ChangesetViewManager', { 15 16 construct : function(node) { 17 this._node = node; 18 19 var data = this._getNodeData(); 20 this._renderURI = data.renderURI; 21 this._ref = data.ref; 22 this._whitespace = data.whitespace; 23 this._renderer = data.renderer; 24 this._highlight = data.highlight; 25 this._encoding = data.encoding; 26 }, 27 28 members: { 29 _node: null, 30 _loaded: false, 31 _sequence: 0, 32 _stabilize: false, 33 34 _renderURI: null, 35 _ref: null, 36 _whitespace: null, 37 _renderer: null, 38 _highlight: null, 39 _encoding: null, 40 41 42 /** 43 * Has the content of this changeset been loaded? 44 * 45 * This method returns `true` if a request has been fired, even if the 46 * response has not returned yet. 47 * 48 * @return bool True if the content has been loaded. 49 */ 50 isLoaded: function() { 51 return this._loaded; 52 }, 53 54 55 /** 56 * Configure stabilization of the document position on content load. 57 * 58 * When we dump the changeset into the document, we can try to stabilize 59 * the document scroll position so that the user doesn't feel like they 60 * are jumping around as things load in. This is generally useful when 61 * populating initial changes. 62 * 63 * However, if a user explicitly requests a content load by clicking a 64 * "Load" link or using the dropdown menu, this stabilization generally 65 * feels unnatural, so we don't use it in response to explicit user action. 66 * 67 * @param bool True to stabilize the next content fill. 68 * @return this 69 */ 70 setStabilize: function(stabilize) { 71 this._stabilize = stabilize; 72 return this; 73 }, 74 75 76 /** 77 * Should this changeset load immediately when the page loads? 78 * 79 * Normally, changes load immediately, but if a diff or commit is very 80 * large we stop doing this and have the user load files explicitly, or 81 * choose to load everything. 82 * 83 * @return bool True if the changeset should load automatically when the 84 * page loads. 85 */ 86 shouldAutoload: function() { 87 return this._getNodeData().autoload; 88 }, 89 90 91 /** 92 * Load this changeset, if it isn't already loading. 93 * 94 * This fires a request to fill the content of this changeset, provided 95 * there isn't already a request in flight. To force a reload, use 96 * @{method:reload}. 97 * 98 * @return this 99 */ 100 load: function() { 101 if (this._loaded) { 102 return this; 103 } 104 105 return this.reload(); 106 }, 107 108 109 /** 110 * Reload the changeset content. 111 * 112 * This method always issues a request, even if the content is already 113 * loading. To load conditionally, use @{method:load}. 114 * 115 * @return this 116 */ 117 reload: function() { 118 this._loaded = true; 119 this._sequence++; 120 121 var params = { 122 ref: this._ref, 123 whitespace: this._whitespace || '', 124 renderer: this.getRenderer() || '', 125 highlight: this._highlight || '', 126 encoding: this._encoding || '' 127 }; 128 129 var workflow = new JX.Workflow(this._renderURI, params) 130 .setHandler(JX.bind(this, this._onresponse, this._sequence)); 131 132 var routable = workflow.getRoutable(); 133 134 routable 135 .setPriority(500) 136 .setType('content') 137 .setKey(this._getRoutableKey()); 138 139 JX.Router.getInstance().queue(routable); 140 141 JX.DOM.setContent( 142 this._getContentFrame(), 143 JX.$N( 144 'div', 145 {className: 'differential-loading'}, 146 'Loading...')); 147 148 return this; 149 }, 150 151 152 /** 153 * Get the active @{class:JX.Routable} for this changeset. 154 * 155 * After issuing a request with @{method:load} or @{method:reload}, you 156 * can adjust routable settings (like priority) by querying the routable 157 * with this method. Note that there may not be a current routable. 158 * 159 * @return JX.Routable|null Active routable, if one exists. 160 */ 161 getRoutable: function() { 162 return JX.Router.getInstance().getRoutableByKey(this._getRoutableKey()); 163 }, 164 165 setRenderer: function(renderer) { 166 this._renderer = renderer; 167 return this; 168 }, 169 170 getRenderer: function() { 171 if (this._renderer !== null) { 172 return this._renderer; 173 } 174 175 // TODO: This is a big pile of TODOs. 176 177 // NOTE: If you load the page at one device resolution and then resize to 178 // a different one we don't re-render the diffs, because it's a 179 // complicated mess and you could lose inline comments, cursor positions, 180 // etc. 181 var renderer = (JX.Device.getDevice() == 'desktop') ? '2up' : '1up'; 182 183 // TODO: Once 1up works better, figure out when to show it. 184 renderer = '2up'; 185 186 return renderer; 187 }, 188 189 setEncoding: function(encoding) { 190 this._encoding = encoding; 191 return this; 192 }, 193 194 getEncoding: function() { 195 return this._encoding; 196 }, 197 198 setHighlight: function(highlight) { 199 this._highlight = highlight; 200 return this; 201 }, 202 203 getHighlight: function() { 204 return this._highlight; 205 }, 206 207 _getNodeData: function() { 208 return JX.Stratcom.getData(this._node); 209 }, 210 211 212 _onresponse: function(sequence, response) { 213 if (sequence != this._sequence) { 214 // If this isn't the most recent request, ignore it. This normally 215 // means the user changed view settings between the time the page loaded 216 // and the content filled. 217 return; 218 } 219 220 // As we populate the changeset list, we try to hold the document scroll 221 // position steady, so that, e.g., users who want to leave a comment on a 222 // diff with a large number of changes don't constantly have the text 223 // area scrolled off the bottom of the screen until the entire diff loads. 224 // 225 // There are two three major cases here: 226 // 227 // - If we're near the top of the document, never scroll. 228 // - If we're near the bottom of the document, always scroll. 229 // - Otherwise, scroll if the changes were above the midline of the 230 // viewport. 231 232 var target = this._node; 233 234 var old_pos = JX.Vector.getScroll(); 235 var old_view = JX.Vector.getViewport(); 236 var old_dim = JX.Vector.getDocument(); 237 238 // Number of pixels away from the top or bottom of the document which 239 // count as "nearby". 240 var sticky = 480; 241 242 var near_top = (old_pos.y <= sticky); 243 var near_bot = ((old_pos.y + old_view.y) >= (old_dim.y - sticky)); 244 245 var target_pos = JX.Vector.getPos(target); 246 var target_dim = JX.Vector.getDim(target); 247 var target_mid = (target_pos.y + (target_dim.y / 2)); 248 249 var view_mid = (old_pos.y + (old_view.y / 2)); 250 var above_mid = (target_mid < view_mid); 251 252 var frame = this._getContentFrame(); 253 JX.DOM.setContent(frame, JX.$H(response.changeset)); 254 255 if (this._stabilize) { 256 if (!near_top) { 257 if (near_bot || above_mid) { 258 // Figure out how much taller the document got. 259 var delta = (JX.Vector.getDocument().y - old_dim.y); 260 window.scrollTo(old_pos.x, old_pos.y + delta); 261 } 262 } 263 this._stabilize = false; 264 } 265 266 if (response.coverage) { 267 for (var k in response.coverage) { 268 try { 269 JX.DOM.replace(JX.$(k), JX.$H(response.coverage[k])); 270 } catch (ignored) { 271 // Not terribly important. 272 } 273 } 274 } 275 }, 276 277 _getContentFrame: function() { 278 return JX.DOM.find(this._node, 'div', 'changeset-view-content'); 279 }, 280 281 _getRoutableKey: function() { 282 return 'changeset-view.' + this._ref + '.' + this._sequence; 283 } 284 285 }, 286 287 statics: { 288 getForNode: function(node) { 289 var data = JX.Stratcom.getData(node); 290 if (!data.changesetViewManager) { 291 data.changesetViewManager = new JX.ChangesetViewManager(node); 292 } 293 return data.changesetViewManager; 294 } 295 } 296 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |