[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/webroot/rsrc/js/application/differential/ -> ChangesetViewManager.js (source)

   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  });


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1