diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -11,7 +11,7 @@ 'core.pkg.js' => '639b2433', 'darkconsole.pkg.js' => 'ca8671ce', 'differential.pkg.css' => 'fbf57382', - 'differential.pkg.js' => '74cb0d29', + 'differential.pkg.js' => 'eca39a2c', 'diffusion.pkg.css' => '3783278d', 'diffusion.pkg.js' => '077e3ad0', 'maniphest.pkg.css' => 'f88a8402', @@ -352,15 +352,16 @@ 'rsrc/js/application/countdown/timer.js' => '889c96f3', 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e', 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'fa187a68', + 'rsrc/js/application/differential/ChangesetViewManager.js' => 'db09a523', 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => 'f2441746', 'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => '533a187b', 'rsrc/js/application/differential/behavior-comment-jump.js' => '71755c79', 'rsrc/js/application/differential/behavior-comment-preview.js' => '127f2018', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', - 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '9f0dfafa', + 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '64a79839', 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '00861799', 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '173ce7e7', - 'rsrc/js/application/differential/behavior-populate.js' => 'dfdf9f34', + 'rsrc/js/application/differential/behavior-populate.js' => 'bdb3e4d0', 'rsrc/js/application/differential/behavior-show-all-comments.js' => '7c273581', 'rsrc/js/application/differential/behavior-show-field-details.js' => '441f2137', 'rsrc/js/application/differential/behavior-show-more.js' => 'dd7e8ef5', @@ -502,6 +503,7 @@ 'aphront-two-column-view-css' => '16ab3ad2', 'aphront-typeahead-control-css' => 'a989b5b3', 'auth-css' => '1e655982', + 'changeset-view-manager' => 'db09a523', 'config-options-css' => '7fedf08b', 'conpherence-menu-css' => 'e1e0fdf1', 'conpherence-message-pane-css' => '7703a9a9', @@ -554,11 +556,11 @@ 'javelin-behavior-differential-add-reviewers-and-ccs' => '533a187b', 'javelin-behavior-differential-comment-jump' => '71755c79', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', - 'javelin-behavior-differential-dropdown-menus' => '9f0dfafa', + 'javelin-behavior-differential-dropdown-menus' => '64a79839', 'javelin-behavior-differential-edit-inline-comments' => '00861799', 'javelin-behavior-differential-feedback-preview' => '127f2018', 'javelin-behavior-differential-keyboard-navigation' => '173ce7e7', - 'javelin-behavior-differential-populate' => 'dfdf9f34', + 'javelin-behavior-differential-populate' => 'bdb3e4d0', 'javelin-behavior-differential-show-field-details' => '441f2137', 'javelin-behavior-differential-show-more' => 'dd7e8ef5', 'javelin-behavior-differential-toggle-files' => 'ca3f91eb', @@ -1251,12 +1253,31 @@ 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), + '62e18640' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead-normalizer', + ), '6453c869' => array( 0 => 'javelin-install', 1 => 'javelin-dom', 2 => 'javelin-fx', ), + '64a79839' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-util', + 3 => 'javelin-stratcom', + 4 => 'phuix-dropdown-menu', + 5 => 'phuix-action-list-view', + 6 => 'phuix-action-view', + 7 => 'phabricator-phtize', + 8 => 'changeset-view-manager', + ), '64ef2fd2' => array( 0 => 'javelin-behavior', @@ -1309,13 +1330,6 @@ 0 => 'javelin-behavior', 1 => 'javelin-dom', ), - '62e18640' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-typeahead-normalizer', - ), '76f4ebed' => array( 0 => 'javelin-install', @@ -1552,17 +1566,6 @@ 2 => 'javelin-uri', 3 => 'javelin-request', ), - '9f0dfafa' => - array( - 0 => 'javelin-behavior', - 1 => 'javelin-dom', - 2 => 'javelin-util', - 3 => 'javelin-stratcom', - 4 => 'phuix-dropdown-menu', - 5 => 'phuix-action-list-view', - 6 => 'phuix-action-view', - 7 => 'phabricator-phtize', - ), 'a3e2244e' => array( 0 => 'javelin-behavior', @@ -1725,6 +1728,14 @@ 2 => 'javelin-util', 3 => 'javelin-request', ), + 'bdb3e4d0' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-stratcom', + 3 => 'phabricator-tooltip', + 4 => 'changeset-view-manager', + ), 'be81801d' => array( 0 => 'javelin-behavior', @@ -1883,6 +1894,17 @@ 1 => 'javelin-util', 2 => 'javelin-stratcom', ), + 'db09a523' => + array( + 0 => 'javelin-dom', + 1 => 'javelin-util', + 2 => 'javelin-stratcom', + 3 => 'javelin-install', + 4 => 'javelin-workflow', + 5 => 'javelin-router', + 6 => 'javelin-behavior-device', + 7 => 'javelin-vector', + ), 'dd7e8ef5' => array( 0 => 'javelin-behavior', @@ -1897,18 +1919,6 @@ 1 => 'javelin-dom', 2 => 'phabricator-prefab', ), - 'dfdf9f34' => - array( - 0 => 'javelin-behavior', - 1 => 'javelin-workflow', - 2 => 'javelin-util', - 3 => 'javelin-dom', - 4 => 'javelin-stratcom', - 5 => 'javelin-behavior-device', - 6 => 'javelin-vector', - 7 => 'javelin-router', - 8 => 'phabricator-tooltip', - ), 'e1ff79b1' => array( 0 => 'javelin-behavior', diff --git a/src/applications/differential/view/DifferentialChangesetDetailView.php b/src/applications/differential/view/DifferentialChangesetDetailView.php --- a/src/applications/differential/view/DifferentialChangesetDetailView.php +++ b/src/applications/differential/view/DifferentialChangesetDetailView.php @@ -8,6 +8,46 @@ private $symbolIndex; private $id; private $vsChangesetID; + private $renderURI; + private $whitespace; + private $renderingRef; + private $autoload; + + public function setAutoload($autoload) { + $this->autoload = $autoload; + return $this; + } + + public function getAutoload() { + return $this->autoload; + } + + public function setRenderingRef($rendering_ref) { + $this->renderingRef = $rendering_ref; + return $this; + } + + public function getRenderingRef() { + return $this->renderingRef; + } + + public function setWhitespace($whitespace) { + $this->whitespace = $whitespace; + return $this; + } + + public function getWhitespace() { + return $this->whitespace; + } + + public function setRenderURI($render_uri) { + $this->renderURI = $render_uri; + return $this; + } + + public function getRenderURI() { + return $this->renderURI; + } public function setChangeset($changeset) { $this->changeset = $changeset; @@ -36,6 +76,11 @@ return $this->id; } + public function setID($id) { + $this->id = $id; + return $this; + } + public function setVsChangesetID($vs_changeset_id) { $this->vsChangesetID = $vs_changeset_id; return $this; @@ -139,6 +184,12 @@ $this->getVsChangesetID(), $this->changeset->getID()), 'right' => $this->changeset->getID(), + 'renderURI' => $this->getRenderURI(), + 'whitespace' => $this->getWhitespace(), + 'highlight' => null, + 'renderer' => null, + 'ref' => $this->getRenderingRef(), + 'autoload' => $this->getAutoload(), ), 'class' => $class, 'id' => $id, @@ -154,9 +205,15 @@ 'class' => 'differential-file-icon-header'), array( $icon, - $display_filename)), - phutil_tag('div', array('style' => 'clear: both'), ''), - $this->renderChildren(), + $display_filename, + )), + javelin_tag( + 'div', + array( + 'class' => 'changeset-view-content', + 'sigil' => 'changeset-view-content', + ), + $this->renderChildren()), )); } diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -131,8 +131,9 @@ )); $output = array(); - $mapping = array(); + $ids = array(); foreach ($changesets as $key => $changeset) { + $file = $changeset->getFilename(); $class = 'differential-changeset'; if (!$this->inlineURI) { @@ -143,6 +144,9 @@ $detail = new DifferentialChangesetDetailView(); + $uniq_id = 'diff-'.$changeset->getAnchorName(); + $detail->setID($uniq_id); + $view_options = $this->renderViewOptionsDropdown( $detail, $ref, @@ -153,22 +157,24 @@ $detail->setSymbolIndex(idx($this->symbolIndexes, $key)); $detail->setVsChangesetID(idx($this->vsMap, $changeset->getID())); $detail->setEditable(true); + $detail->setRenderingRef($ref); + $detail->setAutoload(isset($this->visibleChangesets[$key])); + + $detail->setRenderURI($this->renderURI); + $detail->setWhitespace($this->whitespace); - $uniq_id = 'diff-'.$changeset->getAnchorName(); if (isset($this->visibleChangesets[$key])) { $load = 'Loading...'; - $mapping[$uniq_id] = $ref; } else { $load = javelin_tag( 'a', array( 'href' => '#'.$uniq_id, + 'sigil' => 'differential-load', 'meta' => array( - 'id' => $uniq_id, - 'ref' => $ref, + 'id' => $detail->getID(), 'kill' => true, ), - 'sigil' => 'differential-load', 'mustcapture' => true, ), pht('Load')); @@ -181,14 +187,14 @@ ), phutil_tag('div', array('class' => 'differential-loading'), $load))); $output[] = $detail->render(); + + $ids[] = $detail->getID(); } $this->requireResource('aphront-tooltip-css'); $this->initBehavior('differential-populate', array( - 'registry' => $mapping, - 'whitespace' => $this->whitespace, - 'uri' => $this->renderURI, + 'changesetViewIDs' => $ids, )); $this->initBehavior('differential-show-more', array( diff --git a/src/applications/differential/view/DifferentialDiffTableOfContentsView.php b/src/applications/differential/view/DifferentialDiffTableOfContentsView.php --- a/src/applications/differential/view/DifferentialDiffTableOfContentsView.php +++ b/src/applications/differential/view/DifferentialDiffTableOfContentsView.php @@ -312,11 +312,10 @@ 'a', array( 'href' => '#'.$changeset->getAnchorName(), + 'sigil' => 'differential-load', 'meta' => array( 'id' => 'diff-'.$changeset->getAnchorName(), - 'ref' => $ref, ), - 'sigil' => 'differential-load', ), $display_file); } diff --git a/webroot/rsrc/js/application/differential/ChangesetViewManager.js b/webroot/rsrc/js/application/differential/ChangesetViewManager.js new file mode 100644 --- /dev/null +++ b/webroot/rsrc/js/application/differential/ChangesetViewManager.js @@ -0,0 +1,269 @@ +/** + * @provides changeset-view-manager + * @requires javelin-dom + * javelin-util + * javelin-stratcom + * javelin-install + * javelin-workflow + * javelin-router + * javelin-behavior-device + * javelin-vector + */ + + +JX.install('ChangesetViewManager', { + + construct : function(node) { + this._node = node; + + var data = this._getNodeData(); + this._renderURI = data.renderURI; + this._ref = data.ref; + this._whitespace = data.whitespace; + this._renderer = data.renderer; + this._highlight = data.highlight; + }, + + members: { + _node: null, + _loaded: false, + _sequence: 0, + _stabilize: false, + + _renderURI: null, + _ref: null, + _whitespace: null, + _renderer: null, + _highlight: null, + + + /** + * Has the content of this changeset been loaded? + * + * This method returns `true` if a request has been fired, even if the + * response has not returned yet. + * + * @return bool True if the content has been loaded. + */ + isLoaded: function() { + return this._loaded; + }, + + + /** + * Configure stabilization of the document position on content load. + * + * When we dump the changeset into the document, we can try to stabilize + * the document scroll position so that the user doesn't feel like they + * are jumping around as things load in. This is generally useful when + * populating initial changes. + * + * However, if a user explicitly requests a content load by clicking a + * "Load" link or using the dropdown menu, this stabilization generally + * feels unnatural, so we don't use it in response to explicit user action. + * + * @param bool True to stabilize the next content fill. + * @return this + */ + setStabilize: function(stabilize) { + this._stabilize = stabilize; + return this; + }, + + + /** + * Should this changeset load immediately when the page loads? + * + * Normally, changes load immediately, but if a diff or commit is very + * large we stop doing this and have the user load files explicitly, or + * choose to load everything. + * + * @return bool True if the changeset should load automatically when the + * page loads. + */ + shouldAutoload: function() { + return this._getNodeData().autoload; + }, + + + /** + * Load this changeset, if it isn't already loading. + * + * This fires a request to fill the content of this changeset, provided + * there isn't already a request in flight. To force a reload, use + * @{method:reload}. + * + * @return this + */ + load: function() { + if (this._loaded) { + return this; + } + + return this.reload(); + }, + + + /** + * Reload the changeset content. + * + * This method always issues a request, even if the content is already + * loading. To load conditionally, use @{method:load}. + * + * @return this + */ + reload: function() { + this._loaded = true; + this._sequence++; + + var data = this._getNodeData(); + + var params = { + ref: this._ref, + whitespace: this._whitespace, + renderer: this._getRenderer() + }; + + var workflow = new JX.Workflow(this._renderURI, params) + .setHandler(JX.bind(this, this._onresponse, this._sequence)); + + var routable = workflow.getRoutable(); + + routable + .setPriority(500) + .setType('content') + .setKey(this._getRoutableKey()); + + JX.Router.getInstance().queue(routable); + + JX.DOM.setContent( + this._getContentFrame(), + JX.$N( + 'div', + {className: 'differential-loading'}, + 'Loading...')); + + return this; + }, + + + /** + * Get the active @{class:JX.Routable} for this changeset. + * + * After issuing a request with @{method:load} or @{method:reload}, you + * can adjust routable settings (like priority) by querying the routable + * with this method. Note that there may not be a current routable. + * + * @return JX.Routable|null Active routable, if one exists. + */ + getRoutable: function() { + return JX.Router.getInstance().getRoutableByKey(this._getRoutableKey()); + }, + + + _getRenderer: function() { + // TODO: This is a big pile of TODOs. + + // NOTE: If you load the page at one device resolution and then resize to + // a different one we don't re-render the diffs, because it's a + // complicated mess and you could lose inline comments, cursor positions, + // etc. + var renderer = (JX.Device.getDevice() == 'desktop') ? '2up' : '1up'; + + // TODO: Once 1up works better, figure out when to show it. + renderer = '2up'; + + return renderer; + }, + + + _getNodeData: function() { + return JX.Stratcom.getData(this._node); + }, + + + _onresponse: function(sequence, response) { + if (sequence != this._sequence) { + // If this isn't the most recent request, ignore it. This normally + // means the user changed view settings between the time the page loaded + // and the content filled. + return; + } + + // As we populate the changeset list, we try to hold the document scroll + // position steady, so that, e.g., users who want to leave a comment on a + // diff with a large number of changes don't constantly have the text + // area scrolled off the bottom of the screen until the entire diff loads. + // + // There are two three major cases here: + // + // - If we're near the top of the document, never scroll. + // - If we're near the bottom of the document, always scroll. + // - Otherwise, scroll if the changes were above the midline of the + // viewport. + + var target = this._node; + + var old_pos = JX.Vector.getScroll(); + var old_view = JX.Vector.getViewport(); + var old_dim = JX.Vector.getDocument(); + + // Number of pixels away from the top or bottom of the document which + // count as "nearby". + var sticky = 480; + + var near_top = (old_pos.y <= sticky); + var near_bot = ((old_pos.y + old_view.y) >= (old_dim.y - sticky)); + + var target_pos = JX.Vector.getPos(target); + var target_dim = JX.Vector.getDim(target); + var target_mid = (target_pos.y + (target_dim.y / 2)); + + var view_mid = (old_pos.y + (old_view.y / 2)); + var above_mid = (target_mid < view_mid); + + var frame = this._getContentFrame(); + JX.DOM.setContent(frame, JX.$H(response.changeset)); + + if (this._stabilize) { + if (!near_top) { + if (near_bot || above_mid) { + // Figure out how much taller the document got. + var delta = (JX.Vector.getDocument().y - old_dim.y); + window.scrollTo(old_pos.x, old_pos.y + delta); + } + } + this._stabilize = false; + } + + if (response.coverage) { + for (var k in response.coverage) { + try { + JX.DOM.replace(JX.$(k), JX.$H(response.coverage[k])); + } catch (ignored) { + // Not terribly important. + } + } + } + }, + + _getContentFrame: function() { + return JX.DOM.find(this._node, 'div', 'changeset-view-content'); + }, + + _getRoutableKey: function() { + return 'changeset-view.' + this._ref + '.' + this._sequence; + } + + }, + + statics: { + getForNode: function(node) { + var data = JX.Stratcom.getData(node); + if (!data.changesetViewManager) { + data.changesetViewManager = new JX.ChangesetViewManager(node); + } + return data.changesetViewManager; + } + } +}); diff --git a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js --- a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js +++ b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js @@ -8,6 +8,7 @@ * phuix-action-list-view * phuix-action-view * phabricator-phtize + * changeset-view-manager */ JX.behavior('differential-dropdown-menus', function(config) { @@ -97,8 +98,24 @@ }); list.addItem(visible_item); - add_link('fa-files-o', pht('Browse in Diffusion'), data.diffusionURI); + add_link('fa-file-text', pht('Browse in Diffusion'), data.diffusionURI); add_link('fa-file-o', pht('View Standalone'), data.standaloneURI); + + var up_item = new JX.PHUIXActionView() + .setHandler(function(e) { + var changeset = JX.DOM.findAbove( + button, + 'div', + 'differential-changeset'); + + var view = JX.ChangesetViewManager.getForNode(changeset); + view.reload(); + + e.prevent(); + menu.close(); + }); + list.addItem(up_item); + add_link('fa-arrow-left', pht('Show Raw File (Left)'), data.leftURI); add_link('fa-arrow-right', pht('Show Raw File (Right)'), data.rightURI); add_link('fa-pencil', pht('Open in Editor'), data.editor, true); @@ -108,6 +125,12 @@ menu.setContent(list.getNode()); menu.listen('open', function() { + var changeset = JX.DOM.findAbove( + button, + 'div', + 'differential-changeset'); + + var view = JX.ChangesetViewManager.getForNode(changeset); // When the user opens the menu, check if there are any "Show More" // links in the changeset body. If there aren't, disable the "Show @@ -132,8 +155,22 @@ .setHandler(function(e) { e.prevent(); }); } - visible_item.setDisabled(true); - visible_item.setName(pht("Can't Toggle Unloaded File")); + // TODO: This is temporary and just makes testing easier. It will do + // some mojo soon. + if (view.isLoaded()) { + up_item + .setIcon('fa-refresh') + .setName('Reload'); + } else { + up_item + .setIcon('fa-refresh') + .setName('Load'); + } + + visible_item + .setDisabled(true) + .setIcon('fa-expand') + .setName(pht("Can't Toggle Unloaded File")); var diffs = JX.DOM.scry( JX.$(data.containerID), 'table', diff --git a/webroot/rsrc/js/application/differential/behavior-populate.js b/webroot/rsrc/js/application/differential/behavior-populate.js --- a/webroot/rsrc/js/application/differential/behavior-populate.js +++ b/webroot/rsrc/js/application/differential/behavior-populate.js @@ -1,151 +1,44 @@ /** * @provides javelin-behavior-differential-populate * @requires javelin-behavior - * javelin-workflow - * javelin-util * javelin-dom * javelin-stratcom - * javelin-behavior-device - * javelin-vector - * javelin-router * phabricator-tooltip + * changeset-view-manager */ JX.behavior('differential-populate', function(config) { - function onresponse(target_id, response) { - // As we populate the diff, we try to hold the document scroll position - // steady, so that, e.g., users who want to leave a comment on a diff with a - // large number of changes don't constantly have the text area scrolled off - // the bottom of the screen until the entire diff loads. - // - // There are two three major cases here: - // - // - If we're near the top of the document, never scroll. - // - If we're near the bottom of the document, always scroll. - // - Otherwise, scroll if the changes were above the midline of the - // viewport. - var target = JX.$(target_id); - - var old_pos = JX.Vector.getScroll(); - var old_view = JX.Vector.getViewport(); - var old_dim = JX.Vector.getDocument(); - - // Number of pixels away from the top or bottom of the document which - // count as "nearby". - var sticky = 480; - - var near_top = (old_pos.y <= sticky); - var near_bot = ((old_pos.y + old_view.y) >= (old_dim.y - sticky)); - - var target_pos = JX.Vector.getPos(target); - var target_dim = JX.Vector.getDim(target); - var target_mid = (target_pos.y + (target_dim.y / 2)); - - var view_mid = (old_pos.y + (old_view.y / 2)); - var above_mid = (target_mid < view_mid); - - JX.DOM.replace(target, JX.$H(response.changeset)); - - if (!near_top) { - if (near_bot || above_mid) { - // Figure out how much taller the document got. - var delta = (JX.Vector.getDocument().y - old_dim.y); - - window.scrollTo(old_pos.x, old_pos.y + delta); - } - } - - if (response.coverage) { - for (var k in response.coverage) { - try { - JX.DOM.replace(JX.$(k), JX.$H(response.coverage[k])); - } catch (ignored) { - // Not terribly important. - } - } + for (var ii = 0; ii < config.changesetViewIDs.length; ii++) { + var id = config.changesetViewIDs[ii]; + var view = JX.ChangesetViewManager.getForNode(JX.$(id)); + if (view.shouldAutoload()) { + view.setStabilize(true).load(); } } - // NOTE: If you load the page at one device resolution and then resize to - // a different one we don't re-render the diffs, because it's a complicated - // mess and you could lose inline comments, cursor positions, etc. - var renderer = (JX.Device.getDevice() == 'desktop') ? '2up' : '1up'; - - // TODO: Once 1up works better, figure out when to show it. - renderer = '2up'; - - var get_key = function(id) { - return 'differential-populate.' + id; - }; - - var load = function(id, data) { - var routable = new JX.Workflow(config.uri, data) - .setHandler(JX.bind(null, onresponse, id)) - .getRoutable(); - - routable - .setPriority(500) - .setType('content') - .setKey(get_key(id)); - - JX.Router.getInstance().queue(routable); - - return routable; - }; - - for (var k in config.registry) { - var data = { - ref : config.registry[k], - whitespace: config.whitespace, - renderer: renderer - }; - - load(k, data); - } - - var highlighted = null; - var highlight_class = null; - JX.Stratcom.listen( 'click', 'differential-load', function(e) { var meta = e.getNodeData('differential-load'); - var diff; - try { - diff = JX.$(meta.id); - } catch (ex) { - // Already loaded. - } - if (diff) { - JX.DOM.setContent( - diff, - JX.$H('
Loading...
')); - - // When a user explicitly clicks "Load" (or clicks a link in the table - // of contents) prioritize this request if it already exists. If it - // doesn't, make a new high-priority request. - - var key = get_key(meta.id); - var routable = JX.Router.getInstance().getRoutableByKey(key); - - if (!routable) { - var data = { - ref : meta.ref, - whitespace : config.whitespace - }; - - routable = load(meta.id, data); - } + var changeset = JX.$(meta.id); + var view = JX.ChangesetViewManager.getForNode(changeset); + view.load(); + var routable = view.getRoutable(); + if (routable) { routable.setPriority(2000); } + if (meta.kill) { e.kill(); } }); + var highlighted = null; + var highlight_class = null; + JX.Stratcom.listen( ['mouseover', 'mouseout'], ['differential-changeset', 'tag:td'], @@ -202,5 +95,4 @@ }); - });