Page MenuHomePhabricator

D11472.diff
No OneTemporary

D11472.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,7 +7,7 @@
*/
return array(
'names' => array(
- 'core.pkg.css' => 'd7209022',
+ 'core.pkg.css' => '4517260e',
'core.pkg.js' => '2d9bfc06',
'darkconsole.pkg.js' => '8ab24e01',
'differential.pkg.css' => '8af45893',
@@ -39,7 +39,7 @@
'rsrc/css/application/base/main-menu-view.css' => '3cf893a9',
'rsrc/css/application/base/notification-menu.css' => '6aa0a74b',
'rsrc/css/application/base/phabricator-application-launch-view.css' => '5d71008f',
- 'rsrc/css/application/base/standard-page-view.css' => '2c96cfb5',
+ 'rsrc/css/application/base/standard-page-view.css' => '98cc4c75',
'rsrc/css/application/chatlog/chatlog.css' => '852140ff',
'rsrc/css/application/config/config-options.css' => '7fedf08b',
'rsrc/css/application/config/config-template.css' => '25d446d6',
@@ -104,14 +104,15 @@
'rsrc/css/application/slowvote/slowvote.css' => '266df6a1',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
- 'rsrc/css/core/core.css' => 'ca42b69f',
+ 'rsrc/css/core/core.css' => 'd7f6ec35',
'rsrc/css/core/remarkup.css' => '0ee3d256',
'rsrc/css/core/syntax.css' => '56c1ba38',
- 'rsrc/css/core/z-index.css' => '27a9a1be',
+ 'rsrc/css/core/z-index.css' => 'a39e6f5a',
'rsrc/css/diviner/diviner-shared.css' => '38813222',
'rsrc/css/font/font-awesome.css' => '0c10d96b',
'rsrc/css/font/font-source-sans-pro.css' => '91d53463',
'rsrc/css/font/phui-font-icon-base.css' => '3dad2ae3',
+ 'rsrc/css/layout/phabricator-crumbs-view.css' => 'd5aa87e4',
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
'rsrc/css/layout/phabricator-hovercard-view.css' => '893f4783',
'rsrc/css/layout/phabricator-side-menu-view.css' => '7e8c6341',
@@ -124,7 +125,6 @@
'rsrc/css/phui/phui-action-list.css' => '9ee9910a',
'rsrc/css/phui/phui-box.css' => '7b3a2eed',
'rsrc/css/phui/phui-button.css' => '008ba5e2',
- 'rsrc/css/phui/phui-crumbs-view.css' => '1705bce6',
'rsrc/css/phui/phui-document.css' => 'bbeb1890',
'rsrc/css/phui/phui-feed-story.css' => '582f0ec9',
'rsrc/css/phui/phui-fontkit.css' => '9c3d2dce',
@@ -152,7 +152,7 @@
'rsrc/css/sprite-gradient.css' => '4bdb98a7',
'rsrc/css/sprite-login.css' => 'a355d921',
'rsrc/css/sprite-main-header.css' => '92720ee2',
- 'rsrc/css/sprite-menu.css' => '661b879f',
+ 'rsrc/css/sprite-menu.css' => '0ca5a908',
'rsrc/css/sprite-projects.css' => 'b0d9e24f',
'rsrc/css/sprite-tokens.css' => '1706b943',
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '579d3140',
@@ -199,6 +199,7 @@
'rsrc/externals/javelin/lib/Resource.js' => '44959b73',
'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692',
'rsrc/externals/javelin/lib/Router.js' => '29274e2b',
+ 'rsrc/externals/javelin/lib/Scrollbar.js' => '5dd3e41b',
'rsrc/externals/javelin/lib/URI.js' => '6eff08aa',
'rsrc/externals/javelin/lib/Vector.js' => 'cc1bd0b0',
'rsrc/externals/javelin/lib/WebSocket.js' => '3f840822',
@@ -414,7 +415,7 @@
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
'rsrc/js/application/repository/repository-crossreference.js' => 'f9539603',
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
- 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => 'd6f54db0',
+ 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'bde958eb',
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => '9f7309fb',
'rsrc/js/application/transactions/behavior-transaction-list.js' => '13c739ea',
@@ -476,6 +477,7 @@
'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45',
'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e',
'rsrc/js/core/behavior-reveal-content.js' => '60821bc7',
+ 'rsrc/js/core/behavior-scrollbar.js' => '77607b63',
'rsrc/js/core/behavior-search-typeahead.js' => '724b1247',
'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6',
'rsrc/js/core/behavior-toggle-class.js' => 'e566f52c',
@@ -641,9 +643,10 @@
'javelin-behavior-reorder-applications' => '76b9fc3e',
'javelin-behavior-reorder-columns' => 'e1d25dfb',
'javelin-behavior-repository-crossreference' => 'f9539603',
+ 'javelin-behavior-scrollbar' => '77607b63',
'javelin-behavior-search-reorder-queries' => 'e9581f08',
'javelin-behavior-select-on-click' => '4e3e79a6',
- 'javelin-behavior-slowvote-embed' => 'd6f54db0',
+ 'javelin-behavior-slowvote-embed' => '887ad43f',
'javelin-behavior-stripe-payment-form' => '3f5d6dbf',
'javelin-behavior-test-payment-form' => 'fc91ab6c',
'javelin-behavior-toggle-class' => 'e566f52c',
@@ -670,6 +673,7 @@
'javelin-resource' => '44959b73',
'javelin-routable' => 'b3e7d692',
'javelin-router' => '29274e2b',
+ 'javelin-scrollbar' => '5dd3e41b',
'javelin-stratcom' => '8b0ad945',
'javelin-tokenizer' => '7644823e',
'javelin-typeahead' => '70baed2f',
@@ -705,8 +709,9 @@
'phabricator-busy' => '6453c869',
'phabricator-chatlog-css' => '852140ff',
'phabricator-content-source-view-css' => '4b8b05d4',
- 'phabricator-core-css' => 'ca42b69f',
+ 'phabricator-core-css' => 'd7f6ec35',
'phabricator-countdown-css' => '86b7b0a0',
+ 'phabricator-crumbs-view-css' => 'd5aa87e4',
'phabricator-dashboard-css' => 'a2bfdcbf',
'phabricator-drag-and-drop-file-upload' => '8c49f386',
'phabricator-draggable-list' => 'a16ec1c6',
@@ -734,7 +739,7 @@
'phabricator-side-menu-view-css' => '7e8c6341',
'phabricator-slowvote-css' => '266df6a1',
'phabricator-source-code-view-css' => '7d346aa4',
- 'phabricator-standard-page-view' => '2c96cfb5',
+ 'phabricator-standard-page-view' => '98cc4c75',
'phabricator-textareautils' => '5c93c52c',
'phabricator-title' => '5c1c758c',
'phabricator-tooltip' => '1d298e3a',
@@ -750,7 +755,7 @@
'phabricator-uiexample-reactor-select' => 'a155550f',
'phabricator-uiexample-reactor-sendclass' => '1def2711',
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
- 'phabricator-zindex-css' => '27a9a1be',
+ 'phabricator-zindex-css' => 'a39e6f5a',
'phame-css' => '19ecc703',
'pholio-css' => '95174bdd',
'pholio-edit-css' => '3ad9d1ee',
@@ -767,7 +772,6 @@
'phui-calendar-day-css' => 'de035c8a',
'phui-calendar-list-css' => 'c1d0ca59',
'phui-calendar-month-css' => 'a92e47d2',
- 'phui-crumbs-view-css' => '1705bce6',
'phui-document-view-css' => 'bbeb1890',
'phui-feed-story-css' => '582f0ec9',
'phui-font-icon-base-css' => '3dad2ae3',
@@ -815,7 +819,7 @@
'sprite-gradient-css' => '4bdb98a7',
'sprite-login-css' => 'a355d921',
'sprite-main-header-css' => '92720ee2',
- 'sprite-menu-css' => '661b879f',
+ 'sprite-menu-css' => '0ca5a908',
'sprite-projects-css' => 'b0d9e24f',
'sprite-tokens-css' => '1706b943',
'syntax-highlighting-css' => '56c1ba38',
@@ -1206,6 +1210,12 @@
'javelin-dom',
'javelin-vector',
),
+ '5dd3e41b' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'javelin-stratcom',
+ 'javelin-vector',
+ ),
'5fefb143' => array(
'javelin-behavior',
'javelin-dom',
@@ -1328,6 +1338,10 @@
'javelin-reactor',
'javelin-util',
),
+ '77607b63' => array(
+ 'javelin-behavior',
+ 'javelin-scrollbar',
+ ),
'7814b593' => array(
'javelin-request',
'javelin-behavior',
@@ -1425,6 +1439,12 @@
'javelin-view-interpreter',
'javelin-view-renderer',
),
+ '887ad43f' => array(
+ 'javelin-behavior',
+ 'javelin-request',
+ 'javelin-stratcom',
+ 'javelin-dom',
+ ),
'8a41885b' => array(
'javelin-install',
'javelin-dom',
@@ -1729,12 +1749,6 @@
'javelin-dom',
'javelin-stratcom',
),
- 'd6f54db0' => array(
- 'javelin-behavior',
- 'javelin-request',
- 'javelin-stratcom',
- 'javelin-dom',
- ),
'd75709e6' => array(
'javelin-behavior',
'javelin-workflow',
@@ -2007,7 +2021,7 @@
'phabricator-filetree-view-css',
'phabricator-nav-view-css',
'phabricator-side-menu-view-css',
- 'phui-crumbs-view-css',
+ 'phabricator-crumbs-view-css',
'phui-object-item-list-view-css',
'global-drag-and-drop-css',
'phui-spacing-css',
diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php
--- a/src/view/page/PhabricatorStandardPageView.php
+++ b/src/view/page/PhabricatorStandardPageView.php
@@ -340,10 +340,16 @@
}
}
- return phutil_tag(
+ Javelin::initBehavior(
+ 'scrollbar',
+ array(
+ 'nodeID' => 'phabricator-standard-page',
+ ));
+
+ $main_page = phutil_tag(
'div',
array(
- 'id' => 'base-page',
+ 'id' => 'phabricator-standard-page',
'class' => 'phabricator-standard-page',
),
array(
@@ -356,6 +362,15 @@
$this->renderFooter(),
)),
));
+
+ return phutil_tag(
+ 'div',
+ array(
+ 'class' => 'main-page-frame',
+ ),
+ array(
+ $main_page,
+ ));
}
protected function getTail() {
diff --git a/webroot/rsrc/css/application/base/standard-page-view.css b/webroot/rsrc/css/application/base/standard-page-view.css
--- a/webroot/rsrc/css/application/base/standard-page-view.css
+++ b/webroot/rsrc/css/application/base/standard-page-view.css
@@ -112,3 +112,73 @@
display: inline-block;
margin: 2px 2px -2px 0;
}
+
+.main-page-frame {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ overflow: hidden;
+}
+
+.jx-scrollbar-frame {
+ position: relative;
+ height: 100%;
+ overflow: hidden;
+}
+
+.jx-scrollbar-viewport {
+ position: absolute;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+
+.jx-scrollbar-test {
+ position: absolute;
+ left: -300px;
+}
+
+.jx-scrollbar-bar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 7px;
+ width: 11px;
+}
+
+.jx-scrollbar-bar .jx-scrollbar-handle {
+ position: absolute;
+ right: 2px;
+ -webkit-border-radius: 7px;
+ -moz-border-radius: 7px;
+ border-radius: 7px;
+ min-height: 10px;
+ width: 7px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ -ms-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+ background: #6c6e71;
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+}
+
+.jx-scrollbar-bar:hover .jx-scrollbar-handle {
+ opacity: 0.7;
+ -webkit-transition: opacity 0 linear;
+ -moz-transition: opacity 0 linear;
+ -o-transition: opacity 0 linear;
+ -ms-transition: opacity 0 linear;
+ transition: opacity 0 linear;
+}
+
+.jx-scrollbar-bar .jx-scrollbar-visible {
+ opacity: 0.7;
+}
diff --git a/webroot/rsrc/css/core/core.css b/webroot/rsrc/css/core/core.css
--- a/webroot/rsrc/css/core/core.css
+++ b/webroot/rsrc/css/core/core.css
@@ -2,16 +2,6 @@
* @provides phabricator-core-css
*/
-body {
- /* Always show the vertical scrollbar so that going from a page without a
- scrollbar to a page with a scrollbar doesn't make content jump a few
- pixels left when the viewport narrows. */
- overflow-y: scroll;
- /* reset behavior in ie7, as it will add an extra scrollbar regardless
- selector * targets ie6 and ie7 only */
- *overflow-y: auto;
-}
-
.device-phone {
/* By default, the iPhone zooms all text on the page by some percentage when
you rotate from portrait mode to landscape mode. Disable this, since it
diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css
--- a/webroot/rsrc/css/core/z-index.css
+++ b/webroot/rsrc/css/core/z-index.css
@@ -129,6 +129,10 @@
z-index: 17;
}
+.jx-scrollbar {
+ z-index: 18;
+}
+
.pholio-device-lightbox {
z-index: 20;
}
diff --git a/webroot/rsrc/externals/javelin/lib/Scrollbar.js b/webroot/rsrc/externals/javelin/lib/Scrollbar.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/externals/javelin/lib/Scrollbar.js
@@ -0,0 +1,273 @@
+/**
+ * @provides javelin-scrollbar
+ * @requires javelin-install
+ * javelin-dom
+ * javelin-stratcom
+ * javelin-vector
+ * @javelin
+ */
+
+/**
+ * Provides an aesthetic scrollbar.
+ *
+ * This shoves an element's scrollbar under a hidden overflow and draws a
+ * pretty looking fake one in its place. This makes complex UIs with multiple
+ * independently scrollable panels less hideous by (a) making the scrollbar
+ * itself prettier and (b) reclaiming the space occupied by the scrollbar.
+ *
+ * Note that on OSX the heavy scrollbars are normally drawn only if you have
+ * a mouse connected. OSX uses more aesthetic touchpad scrollbars normally,
+ * which these scrollbars emulate.
+ *
+ * This class was initially adapted from "Trackpad Scroll Emulator", by
+ * Jonathan Nicol. See <https://github.com/jnicol/trackpad-scroll-emulator>.
+ */
+JX.install('Scrollbar', {
+
+ construct: function(frame) {
+ // Wrap the frame content in a bunch of nodes. The frame itself stays on
+ // the outside so that any positioning information the node had isn't
+ // disrupted.
+
+ // We put a "viewport" node inside of it, which is what actually scrolls.
+ // This is the node that gets a scrollbar, but we make the viewport very
+ // slightly too wide for the frame. That hides the scrollbar underneath
+ // the edge of the frame.
+
+ // We put a "content" node inside of the viewport. This allows us to
+ // measure the content height so we can resize and offset the scrollbar
+ // handle properly.
+
+ // We move all the actual frame content into the "content" node. So it
+ // ends up wrapped by the "content" node, then by the "viewport" node,
+ // and finally by the original "frame" node.
+
+ JX.DOM.alterClass(frame, 'jx-scrollbar-frame', true);
+
+ var content = JX.$N('div', {className: 'jx-scrollbar-content'});
+ while (frame.firstChild) {
+ JX.DOM.appendContent(content, frame.firstChild);
+ }
+
+ var viewport = JX.$N('div', {className: 'jx-scrollbar-viewport'}, content);
+ JX.DOM.appendContent(frame, viewport);
+
+ this._frame = frame;
+ this._viewport = viewport;
+ this._content = content;
+
+ // The handle is the visible node which you can click and drag.
+ this._handle = JX.$N('div', {className: 'jx-scrollbar-handle'});
+
+ // The bar is the area the handle slides up and down in.
+ this._bar = JX.$N('div', {className: 'jx-scrollbar-bar'}, this._handle);
+
+ JX.DOM.prependContent(frame, this._bar);
+
+ JX.DOM.listen(this._handle, 'mousedown', null, JX.bind(this, this._ondrag));
+ JX.DOM.listen(this._bar, 'mousedown', null, JX.bind(this, this._onjump));
+
+ JX.enableDispatch(document.body, 'mouseenter');
+ JX.enableDispatch(document.body, 'mousemove');
+
+ JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter));
+ JX.DOM.listen(frame, 'scroll', null, JX.bind(this, this._onscroll));
+
+ JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter));
+ JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter));
+
+ JX.Stratcom.listen('mousemove', null, JX.bind(this, this._onmove));
+ JX.Stratcom.listen('mouseup', null, JX.bind(this, this._ondrop));
+ JX.Stratcom.listen('resize', null, JX.bind(this, this._onresize));
+
+ this._resizeViewport();
+ this._resizeBar();
+ },
+
+ statics: {
+ _controlWidth: null,
+
+ /**
+ * Compute the width of the browser's scrollbar control, in pixels.
+ */
+ _getScrollbarControlWidth: function() {
+ var self = JX.Scrollbar;
+
+ if (self._controlWidth === null) {
+ var tmp = JX.$N('div', {className: 'jx-scrollbar-test'}, '-');
+ document.body.appendChild(tmp);
+ var d1 = JX.Vector.getDim(tmp);
+ tmp.style.overflowY = 'scroll';
+ var d2 = JX.Vector.getDim(tmp);
+ JX.DOM.remove(tmp);
+
+ self._controlWidth = (d2.x - d1.x);
+ }
+
+ return self._controlWidth;
+ }
+
+ },
+
+ members: {
+ _frame: null,
+ _viewport: null,
+ _content: null,
+
+ _bar: null,
+ _handle: null,
+
+ _timeout: null,
+ _dragOrigin: null,
+
+
+ /**
+ * After the user scrolls the page, show the scrollbar to give them
+ * feedback about their position.
+ */
+ _onscroll: function() {
+ this._showBar();
+ },
+
+
+ /**
+ * When the user mouses over the viewport, show the scrollbar.
+ */
+ _onenter: function() {
+ this._showBar();
+ },
+
+
+ /**
+ * When the user resizes the window, recalculate everything.
+ */
+ _onresize: function() {
+ this._resizeViewport();
+ this._resizeBar();
+ },
+
+
+ /**
+ * When the user clicks the bar area (but not the handle), jump up or
+ * down a page.
+ */
+ _onjump: function(e) {
+ if (e.getTarget() === this._handle) {
+ return;
+ }
+
+ var distance = JX.Vector.getDim(this._viewport).y * (7/8);
+ var epos = JX.$V(e);
+ var hpos = JX.$V(this._handle);
+
+ if (epos.y > hpos.y) {
+ this._viewport.scrollTop += distance;
+ } else {
+ this._viewport.scrollTop -= distance;
+ }
+ },
+
+
+ /**
+ * When the user clicks the scroll handle, begin dragging it.
+ */
+ _ondrag: function(e) {
+ e.kill();
+ this._dragOrigin = JX.$V(e).y;
+ },
+
+
+ /**
+ * As the user drags the scroll handle up or down, scroll the viewport.
+ */
+ _onmove: function(e) {
+ if (this._dragOrigin === null) {
+ return;
+ }
+
+ var offset = (JX.$V(e).y - this._dragOrigin);
+ var ratio = offset / JX.Vector.getDim(this._bar).y;
+ var target = ratio * JX.Vector.getDim(this._content).y;
+
+ this._viewport.scrollTop = target;
+ },
+
+
+ /**
+ * When the user releases the mouse after a drag, stop moving the
+ * viewport.
+ */
+ _ondrop: function() {
+ this._dragOrigin = null;
+ },
+
+
+ /**
+ * Shove the scrollbar on the viewport under the edge of the frame so the
+ * user can't see it.
+ */
+ _resizeViewport: function() {
+ var fdim = JX.Vector.getDim(this._frame);
+ fdim.x += JX.Scrollbar._getScrollbarControlWidth();
+ fdim.setDim(this._viewport);
+ },
+
+
+ /**
+ * Figure out the correct size and offset of the scrollbar handle.
+ */
+ _resizeBar: function() {
+ var cdim = JX.Vector.getDim(this._content);
+ var spos = JX.Vector.getAggregateScrollForNode(this._viewport);
+ var bdim = JX.Vector.getDim(this._bar);
+
+ var ratio = bdim.y / cdim.y;
+
+ var offset = Math.round(ratio * spos.y) + 2;
+ var size = Math.floor(ratio * (bdim.y - 2)) - 2;
+
+ if (size < cdim.y) {
+ this._handle.style.top = offset + 'px';
+ this._handle.style.height = size + 'px';
+
+ JX.DOM.show(this._handle);
+ } else {
+ JX.DOM.hide(this._handle);
+ }
+ },
+
+
+ /**
+ * Show the scrollbar for the next second.
+ */
+ _showBar: function() {
+ this._resizeBar();
+
+ JX.DOM.alterClass(this._handle, 'jx-scrollbar-visible', true);
+
+ this._clearTimeout();
+ this._timeout = setTimeout(JX.bind(this, this._hideBar), 1000);
+ },
+
+
+ /**
+ * Hide the scrollbar.
+ */
+ _hideBar: function() {
+ JX.DOM.alterClass(this._handle, 'jx-scrollbar-visible', false);
+ this._clearTimeout();
+ },
+
+
+ /**
+ * Clear the scrollbar hide timeout, if one is set.
+ */
+ _clearTimeout: function() {
+ if (this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ }
+ }
+
+});
diff --git a/webroot/rsrc/js/application/slowvote/behavior-slowvote-embed.js b/webroot/rsrc/js/application/slowvote/behavior-slowvote-embed.js
--- a/webroot/rsrc/js/application/slowvote/behavior-slowvote-embed.js
+++ b/webroot/rsrc/js/application/slowvote/behavior-slowvote-embed.js
@@ -20,7 +20,7 @@
var request = new JX.Request(voteURI, function(r) {
var updated_poll = JX.$H(r.contentHTML);
- var root = JX.$('base-page');
+ var root = JX.$('phabricator-standard-page');
var polls = JX.DOM.scry(root, 'div', 'slowvote-embed');
diff --git a/webroot/rsrc/js/core/behavior-scrollbar.js b/webroot/rsrc/js/core/behavior-scrollbar.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/core/behavior-scrollbar.js
@@ -0,0 +1,9 @@
+/**
+ * @provides javelin-behavior-scrollbar
+ * @requires javelin-behavior
+ * javelin-scrollbar
+ */
+
+JX.behavior('scrollbar', function(config) {
+ new JX.Scrollbar(JX.$(config.nodeID));
+});

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 28, 5:11 PM (35 m, 49 s)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6940449
Default Alt Text
D11472.diff (20 KB)

Event Timeline