mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-01 19:22:42 +01:00
Add "buoyant" headers to Differential
Summary: As you scroll through a diff, add a fixed-position header to the top of the document to provide context. This is particularly useful with keyboard navigation. The technical implementation is that we seed the document with invisible markers. When the user scrolls past one, we show a header with that text until they scroll past another. Test Plan: Scrolled through a revision, was presented with context. https://secure.phabricator.com/file/data/5xhh2jmoon6ukr5qjkh3/PHID-FILE-463ituscyhyw7utnox7m/Screen_Shot_2012-02-22_at_2.48.19_PM.png Reviewers: btrahan Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T696 Differential Revision: https://secure.phabricator.com/D1673
This commit is contained in:
parent
cdd55eda14
commit
bf3dd8663c
6 changed files with 235 additions and 86 deletions
2
externals/javelin
vendored
2
externals/javelin
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit f25470da2c98cd37fbac435a56128b1d465f7667
|
Subproject commit 45fa775fea5cc7fa1d834a04b9d25a08bcfa4812
|
|
@ -330,30 +330,6 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/javelin/lib/behavior.js',
|
'disk' => '/rsrc/js/javelin/lib/behavior.js',
|
||||||
),
|
),
|
||||||
'javelin-behavior-aphront-drag-and-drop' =>
|
|
||||||
array(
|
|
||||||
'uri' => '/res/ac21045a/rsrc/js/application/core/behavior-drag-and-drop.js',
|
|
||||||
'type' => 'js',
|
|
||||||
'requires' =>
|
|
||||||
array(
|
|
||||||
0 => 'javelin-behavior',
|
|
||||||
1 => 'javelin-dom',
|
|
||||||
2 => 'javelin-util',
|
|
||||||
3 => 'phabricator-drag-and-drop-file-upload',
|
|
||||||
),
|
|
||||||
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop.js',
|
|
||||||
),
|
|
||||||
0 =>
|
|
||||||
array(
|
|
||||||
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
|
||||||
'type' => 'js',
|
|
||||||
'requires' =>
|
|
||||||
array(
|
|
||||||
0 => 'javelin-uri',
|
|
||||||
1 => 'javelin-php-serializer',
|
|
||||||
),
|
|
||||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
|
||||||
),
|
|
||||||
'javelin-behavior-aphront-basic-tokenizer' =>
|
'javelin-behavior-aphront-basic-tokenizer' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/9be30797/rsrc/js/application/core/behavior-tokenizer.js',
|
'uri' => '/res/9be30797/rsrc/js/application/core/behavior-tokenizer.js',
|
||||||
|
@ -370,6 +346,19 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/core/behavior-tokenizer.js',
|
'disk' => '/rsrc/js/application/core/behavior-tokenizer.js',
|
||||||
),
|
),
|
||||||
|
'javelin-behavior-aphront-drag-and-drop' =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/ac21045a/rsrc/js/application/core/behavior-drag-and-drop.js',
|
||||||
|
'type' => 'js',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
0 => 'javelin-behavior',
|
||||||
|
1 => 'javelin-dom',
|
||||||
|
2 => 'javelin-util',
|
||||||
|
3 => 'phabricator-drag-and-drop-file-upload',
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop.js',
|
||||||
|
),
|
||||||
'javelin-behavior-aphront-drag-and-drop-textarea' =>
|
'javelin-behavior-aphront-drag-and-drop-textarea' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/fa7527f9/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
'uri' => '/res/fa7527f9/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
||||||
|
@ -394,6 +383,19 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/core/behavior-form.js',
|
'disk' => '/rsrc/js/application/core/behavior-form.js',
|
||||||
),
|
),
|
||||||
|
'javelin-behavior-buoyant' =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/e7581db1/rsrc/js/application/core/behavior-buoyant.js',
|
||||||
|
'type' => 'js',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
0 => 'javelin-behavior',
|
||||||
|
1 => 'javelin-stratcom',
|
||||||
|
2 => 'javelin-vector',
|
||||||
|
3 => 'javelin-dom',
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/js/application/core/behavior-buoyant.js',
|
||||||
|
),
|
||||||
'javelin-behavior-countdown-timer' =>
|
'javelin-behavior-countdown-timer' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/5ee9cb13/rsrc/js/application/countdown/timer.js',
|
'uri' => '/res/5ee9cb13/rsrc/js/application/countdown/timer.js',
|
||||||
|
@ -869,7 +871,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-dom' =>
|
'javelin-dom' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/b2e8a5b6/rsrc/js/javelin/lib/DOM.js',
|
'uri' => '/res/4c86aaeb/rsrc/js/javelin/lib/DOM.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -952,7 +954,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-magical-init' =>
|
'javelin-magical-init' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/0e72d59b/rsrc/js/javelin/core/init.js',
|
'uri' => '/res/d6832060/rsrc/js/javelin/core/init.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1023,7 +1025,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-request' =>
|
'javelin-request' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/b3257b7d/rsrc/js/javelin/lib/Request.js',
|
'uri' => '/res/6ccc1d5a/rsrc/js/javelin/lib/Request.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1051,7 +1053,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-stratcom' =>
|
'javelin-stratcom' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/d7a3d1e9/rsrc/js/javelin/core/Stratcom.js',
|
'uri' => '/res/3afdac66/rsrc/js/javelin/core/Stratcom.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1064,7 +1066,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-tokenizer' =>
|
'javelin-tokenizer' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/1b1c2148/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js',
|
'uri' => '/res/2b91543e/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1140,7 +1142,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-typeahead-source' =>
|
'javelin-typeahead-source' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/8606f519/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js',
|
'uri' => '/res/e99c0c1d/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1174,7 +1176,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-vector' =>
|
'javelin-vector' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/50535cb8/rsrc/js/javelin/lib/Vector.js',
|
'uri' => '/res/f240bdb3/rsrc/js/javelin/lib/Vector.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1549,6 +1551,17 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/core/ShapedRequest.js',
|
'disk' => '/rsrc/js/application/core/ShapedRequest.js',
|
||||||
),
|
),
|
||||||
|
0 =>
|
||||||
|
array(
|
||||||
|
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||||
|
'type' => 'js',
|
||||||
|
'requires' =>
|
||||||
|
array(
|
||||||
|
0 => 'javelin-uri',
|
||||||
|
1 => 'javelin-php-serializer',
|
||||||
|
),
|
||||||
|
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||||
|
),
|
||||||
'phabricator-slowvote-css' =>
|
'phabricator-slowvote-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css',
|
'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css',
|
||||||
|
@ -1560,7 +1573,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-standard-page-view' =>
|
'phabricator-standard-page-view' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/ec5acaed/rsrc/css/application/base/standard-page-view.css',
|
'uri' => '/res/7e09bbfc/rsrc/css/application/base/standard-page-view.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1785,6 +1798,22 @@ celerity_register_resource_map(array(
|
||||||
'uri' => '/res/pkg/03ef179e/diffusion.pkg.css',
|
'uri' => '/res/pkg/03ef179e/diffusion.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
|
'080edee4' =>
|
||||||
|
array(
|
||||||
|
'name' => 'typeahead.pkg.js',
|
||||||
|
'symbols' =>
|
||||||
|
array(
|
||||||
|
0 => 'javelin-typeahead',
|
||||||
|
1 => 'javelin-typeahead-normalizer',
|
||||||
|
2 => 'javelin-typeahead-source',
|
||||||
|
3 => 'javelin-typeahead-preloaded-source',
|
||||||
|
4 => 'javelin-typeahead-ondemand-source',
|
||||||
|
5 => 'javelin-tokenizer',
|
||||||
|
6 => 'javelin-behavior-aphront-basic-tokenizer',
|
||||||
|
),
|
||||||
|
'uri' => '/res/pkg/080edee4/typeahead.pkg.js',
|
||||||
|
'type' => 'js',
|
||||||
|
),
|
||||||
'46547a92' =>
|
'46547a92' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'core.pkg.js',
|
'name' => 'core.pkg.js',
|
||||||
|
@ -1824,23 +1853,7 @@ celerity_register_resource_map(array(
|
||||||
'uri' => '/res/pkg/4c3b1b11/differential.pkg.css',
|
'uri' => '/res/pkg/4c3b1b11/differential.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'540effd7' =>
|
'4fbae2af' =>
|
||||||
array(
|
|
||||||
'name' => 'typeahead.pkg.js',
|
|
||||||
'symbols' =>
|
|
||||||
array(
|
|
||||||
0 => 'javelin-typeahead',
|
|
||||||
1 => 'javelin-typeahead-normalizer',
|
|
||||||
2 => 'javelin-typeahead-source',
|
|
||||||
3 => 'javelin-typeahead-preloaded-source',
|
|
||||||
4 => 'javelin-typeahead-ondemand-source',
|
|
||||||
5 => 'javelin-tokenizer',
|
|
||||||
6 => 'javelin-behavior-aphront-basic-tokenizer',
|
|
||||||
),
|
|
||||||
'uri' => '/res/pkg/540effd7/typeahead.pkg.js',
|
|
||||||
'type' => 'js',
|
|
||||||
),
|
|
||||||
'b164acea' =>
|
|
||||||
array(
|
array(
|
||||||
'name' => 'javelin.pkg.js',
|
'name' => 'javelin.pkg.js',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -1856,10 +1869,10 @@ celerity_register_resource_map(array(
|
||||||
8 => 'javelin-json',
|
8 => 'javelin-json',
|
||||||
9 => 'javelin-uri',
|
9 => 'javelin-uri',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/b164acea/javelin.pkg.js',
|
'uri' => '/res/pkg/4fbae2af/javelin.pkg.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
),
|
),
|
||||||
'da9f8734' =>
|
'6a6def05' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'core.pkg.css',
|
'name' => 'core.pkg.css',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -1880,7 +1893,7 @@ celerity_register_resource_map(array(
|
||||||
13 => 'phabricator-remarkup-css',
|
13 => 'phabricator-remarkup-css',
|
||||||
14 => 'syntax-highlighting-css',
|
14 => 'syntax-highlighting-css',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/da9f8734/core.pkg.css',
|
'uri' => '/res/pkg/6a6def05/core.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'ef420ead' =>
|
'ef420ead' =>
|
||||||
|
@ -1910,16 +1923,16 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'reverse' =>
|
'reverse' =>
|
||||||
array(
|
array(
|
||||||
'aphront-crumbs-view-css' => 'da9f8734',
|
'aphront-crumbs-view-css' => '6a6def05',
|
||||||
'aphront-dialog-view-css' => 'da9f8734',
|
'aphront-dialog-view-css' => '6a6def05',
|
||||||
'aphront-form-view-css' => 'da9f8734',
|
'aphront-form-view-css' => '6a6def05',
|
||||||
'aphront-headsup-action-list-view-css' => '4c3b1b11',
|
'aphront-headsup-action-list-view-css' => '4c3b1b11',
|
||||||
'aphront-list-filter-view-css' => 'da9f8734',
|
'aphront-list-filter-view-css' => '6a6def05',
|
||||||
'aphront-panel-view-css' => 'da9f8734',
|
'aphront-panel-view-css' => '6a6def05',
|
||||||
'aphront-side-nav-view-css' => 'da9f8734',
|
'aphront-side-nav-view-css' => '6a6def05',
|
||||||
'aphront-table-view-css' => 'da9f8734',
|
'aphront-table-view-css' => '6a6def05',
|
||||||
'aphront-tokenizer-control-css' => 'da9f8734',
|
'aphront-tokenizer-control-css' => '6a6def05',
|
||||||
'aphront-typeahead-control-css' => 'da9f8734',
|
'aphront-typeahead-control-css' => '6a6def05',
|
||||||
'differential-changeset-view-css' => '4c3b1b11',
|
'differential-changeset-view-css' => '4c3b1b11',
|
||||||
'differential-core-view-css' => '4c3b1b11',
|
'differential-core-view-css' => '4c3b1b11',
|
||||||
'differential-inline-comment-editor' => 'ef420ead',
|
'differential-inline-comment-editor' => 'ef420ead',
|
||||||
|
@ -1931,8 +1944,8 @@ celerity_register_resource_map(array(
|
||||||
'differential-revision-history-css' => '4c3b1b11',
|
'differential-revision-history-css' => '4c3b1b11',
|
||||||
'differential-table-of-contents-css' => '4c3b1b11',
|
'differential-table-of-contents-css' => '4c3b1b11',
|
||||||
'diffusion-commit-view-css' => '03ef179e',
|
'diffusion-commit-view-css' => '03ef179e',
|
||||||
'javelin-behavior' => 'b164acea',
|
'javelin-behavior' => '4fbae2af',
|
||||||
'javelin-behavior-aphront-basic-tokenizer' => '540effd7',
|
'javelin-behavior-aphront-basic-tokenizer' => '080edee4',
|
||||||
'javelin-behavior-aphront-drag-and-drop' => 'ef420ead',
|
'javelin-behavior-aphront-drag-and-drop' => 'ef420ead',
|
||||||
'javelin-behavior-aphront-drag-and-drop-textarea' => 'ef420ead',
|
'javelin-behavior-aphront-drag-and-drop-textarea' => 'ef420ead',
|
||||||
'javelin-behavior-aphront-form-disable-on-submit' => '46547a92',
|
'javelin-behavior-aphront-form-disable-on-submit' => '46547a92',
|
||||||
|
@ -1950,34 +1963,34 @@ celerity_register_resource_map(array(
|
||||||
'javelin-behavior-phabricator-watch-anchor' => '46547a92',
|
'javelin-behavior-phabricator-watch-anchor' => '46547a92',
|
||||||
'javelin-behavior-refresh-csrf' => '46547a92',
|
'javelin-behavior-refresh-csrf' => '46547a92',
|
||||||
'javelin-behavior-workflow' => '46547a92',
|
'javelin-behavior-workflow' => '46547a92',
|
||||||
'javelin-dom' => 'b164acea',
|
'javelin-dom' => '4fbae2af',
|
||||||
'javelin-event' => 'b164acea',
|
'javelin-event' => '4fbae2af',
|
||||||
'javelin-install' => 'b164acea',
|
'javelin-install' => '4fbae2af',
|
||||||
'javelin-json' => 'b164acea',
|
'javelin-json' => '4fbae2af',
|
||||||
'javelin-mask' => '46547a92',
|
'javelin-mask' => '46547a92',
|
||||||
'javelin-request' => 'b164acea',
|
'javelin-request' => '4fbae2af',
|
||||||
'javelin-stratcom' => 'b164acea',
|
'javelin-stratcom' => '4fbae2af',
|
||||||
'javelin-tokenizer' => '540effd7',
|
'javelin-tokenizer' => '080edee4',
|
||||||
'javelin-typeahead' => '540effd7',
|
'javelin-typeahead' => '080edee4',
|
||||||
'javelin-typeahead-normalizer' => '540effd7',
|
'javelin-typeahead-normalizer' => '080edee4',
|
||||||
'javelin-typeahead-ondemand-source' => '540effd7',
|
'javelin-typeahead-ondemand-source' => '080edee4',
|
||||||
'javelin-typeahead-preloaded-source' => '540effd7',
|
'javelin-typeahead-preloaded-source' => '080edee4',
|
||||||
'javelin-typeahead-source' => '540effd7',
|
'javelin-typeahead-source' => '080edee4',
|
||||||
'javelin-uri' => 'b164acea',
|
'javelin-uri' => '4fbae2af',
|
||||||
'javelin-util' => 'b164acea',
|
'javelin-util' => '4fbae2af',
|
||||||
'javelin-vector' => 'b164acea',
|
'javelin-vector' => '4fbae2af',
|
||||||
'javelin-workflow' => '46547a92',
|
'javelin-workflow' => '46547a92',
|
||||||
'phabricator-content-source-view-css' => '4c3b1b11',
|
'phabricator-content-source-view-css' => '4c3b1b11',
|
||||||
'phabricator-core-buttons-css' => 'da9f8734',
|
'phabricator-core-buttons-css' => '6a6def05',
|
||||||
'phabricator-core-css' => 'da9f8734',
|
'phabricator-core-css' => '6a6def05',
|
||||||
'phabricator-directory-css' => 'da9f8734',
|
'phabricator-directory-css' => '6a6def05',
|
||||||
'phabricator-drag-and-drop-file-upload' => 'ef420ead',
|
'phabricator-drag-and-drop-file-upload' => 'ef420ead',
|
||||||
'phabricator-keyboard-shortcut' => '46547a92',
|
'phabricator-keyboard-shortcut' => '46547a92',
|
||||||
'phabricator-keyboard-shortcut-manager' => '46547a92',
|
'phabricator-keyboard-shortcut-manager' => '46547a92',
|
||||||
'phabricator-object-selector-css' => '4c3b1b11',
|
'phabricator-object-selector-css' => '4c3b1b11',
|
||||||
'phabricator-remarkup-css' => 'da9f8734',
|
'phabricator-remarkup-css' => '6a6def05',
|
||||||
'phabricator-shaped-request' => 'ef420ead',
|
'phabricator-shaped-request' => 'ef420ead',
|
||||||
'phabricator-standard-page-view' => 'da9f8734',
|
'phabricator-standard-page-view' => '6a6def05',
|
||||||
'syntax-highlighting-css' => 'da9f8734',
|
'syntax-highlighting-css' => '6a6def05',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -96,6 +96,10 @@ class DifferentialChangesetDetailView extends AphrontView {
|
||||||
}
|
}
|
||||||
|
|
||||||
$display_filename = $changeset->getDisplayFilename();
|
$display_filename = $changeset->getDisplayFilename();
|
||||||
|
|
||||||
|
$buoyant_begin = $this->renderBuoyant($display_filename);
|
||||||
|
$buoyant_end = $this->renderBuoyant(null);
|
||||||
|
|
||||||
$output = javelin_render_tag(
|
$output = javelin_render_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
|
@ -109,6 +113,7 @@ class DifferentialChangesetDetailView extends AphrontView {
|
||||||
'class' => $class,
|
'class' => $class,
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
),
|
),
|
||||||
|
$buoyant_begin.
|
||||||
phutil_render_tag(
|
phutil_render_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
|
@ -118,9 +123,29 @@ class DifferentialChangesetDetailView extends AphrontView {
|
||||||
$buttons.
|
$buttons.
|
||||||
'<h1>'.phutil_escape_html($display_filename).'</h1>'.
|
'<h1>'.phutil_escape_html($display_filename).'</h1>'.
|
||||||
'<div style="clear: both;"></div>'.
|
'<div style="clear: both;"></div>'.
|
||||||
$this->renderChildren());
|
$this->renderChildren().
|
||||||
|
$buoyant_end);
|
||||||
|
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function renderBuoyant($text) {
|
||||||
|
return javelin_render_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'sigil' => 'buoyant',
|
||||||
|
'meta' => array(
|
||||||
|
'text' => $text,
|
||||||
|
),
|
||||||
|
'style' => ($text === null)
|
||||||
|
// Current CSS spacing rules cause the "end" anchor to appear too
|
||||||
|
// late in the display document. Shift it up a bit so we drop the
|
||||||
|
// buoyant header sooner. This reduces confusion when using keystroke
|
||||||
|
// navigation.
|
||||||
|
? 'bottom: 60px; position: absolute;'
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
'');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,8 @@ class DifferentialChangesetListView extends AphrontView {
|
||||||
array());
|
array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Javelin::initBehavior('buoyant', array());
|
||||||
|
|
||||||
$output = array();
|
$output = array();
|
||||||
$mapping = array();
|
$mapping = array();
|
||||||
$repository = $this->repository;
|
$repository = $this->repository;
|
||||||
|
|
|
@ -190,3 +190,21 @@ a.handle-disabled {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-family: "Verdana";
|
font-family: "Verdana";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.buoyant {
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
z-index: 8;
|
||||||
|
|
||||||
|
padding: 6px;
|
||||||
|
color: #dddddd;
|
||||||
|
font-size: 11px;
|
||||||
|
opacity: 0.90;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
background: #222222;
|
||||||
|
border-bottom: 1px solid #dfdfdf;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
91
webroot/rsrc/js/application/core/behavior-buoyant.js
Normal file
91
webroot/rsrc/js/application/core/behavior-buoyant.js
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* @provides javelin-behavior-buoyant
|
||||||
|
* @requires javelin-behavior
|
||||||
|
* javelin-stratcom
|
||||||
|
* javelin-vector
|
||||||
|
* javelin-dom
|
||||||
|
*/
|
||||||
|
|
||||||
|
JX.behavior('buoyant', function() {
|
||||||
|
|
||||||
|
// The display element which shows the "buoyant" header to the user.
|
||||||
|
var element = JX.$N('div', {className : 'buoyant'});
|
||||||
|
|
||||||
|
// Keeps track of whether we're currently showing anything or not.
|
||||||
|
var visible = false;
|
||||||
|
|
||||||
|
// If we're showing something, the positional DOM element that triggered the
|
||||||
|
// currently shown header.
|
||||||
|
var active_marker = null;
|
||||||
|
|
||||||
|
// When the header is clicked, jump to the element that triggered it.
|
||||||
|
JX.DOM.listen(element, 'click', null, function(e) {
|
||||||
|
window.scrollTo(0, JX.$V(active_marker).y - 40);
|
||||||
|
});
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
if (visible) {
|
||||||
|
JX.DOM.remove(element);
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(text) {
|
||||||
|
if (!visible) {
|
||||||
|
document.body.appendChild(element);
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
JX.DOM.setContent(element, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
var onviewportchange = function(e) {
|
||||||
|
|
||||||
|
// If we're currently showing a header but we've scrolled back up past its
|
||||||
|
// marker, hide it.
|
||||||
|
|
||||||
|
var scroll_position = JX.Vector.getScroll().y;
|
||||||
|
if (visible && (scroll_position < JX.$V(active_marker).y)) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all the markers in the document.
|
||||||
|
|
||||||
|
var markers = JX.DOM.scry(document.body, 'div', 'buoyant');
|
||||||
|
|
||||||
|
// Sort the markers by Y position, descending.
|
||||||
|
|
||||||
|
var markinfo = [];
|
||||||
|
for (var ii = 0; ii < markers.length; ii++) {
|
||||||
|
markinfo.push({
|
||||||
|
marker: markers[ii],
|
||||||
|
position: JX.$V(markers[ii]).y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
markinfo.sort(function(u, v) { return (v.position - u.position); });
|
||||||
|
|
||||||
|
// Find the first marker above the current scroll position.
|
||||||
|
|
||||||
|
for (var ii = 0; ii < markinfo.length; ii++) {
|
||||||
|
if (markinfo[ii].position > scroll_position) {
|
||||||
|
// This marker is below the current scroll position, so ignore it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've found a marker. Display it as appropriate;
|
||||||
|
|
||||||
|
active_marker = markinfo[ii].marker;
|
||||||
|
var text = JX.Stratcom.getData(active_marker).text;
|
||||||
|
if (text) {
|
||||||
|
show(text);
|
||||||
|
} else {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JX.Stratcom.listen('scroll', null, onviewportchange);
|
||||||
|
JX.Stratcom.listen('resize', null, onviewportchange);
|
||||||
|
});
|
Loading…
Reference in a new issue