Page MenuHomePhabricator

D12425.id29834.diff
No OneTemporary

D12425.id29834.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -30,6 +30,7 @@
'rsrc/css/aphront/tokenizer.css' => '82ce2142',
'rsrc/css/aphront/tooltip.css' => '7672b60f',
'rsrc/css/aphront/two-column.css' => '16ab3ad2',
+ 'rsrc/css/aphront/typeahead-browse.css' => '252b1ac4',
'rsrc/css/aphront/typeahead.css' => '0e403212',
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
'rsrc/css/application/auth/auth.css' => '1e655982',
@@ -425,6 +426,7 @@
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => '9f7309fb',
'rsrc/js/application/transactions/behavior-transaction-list.js' => '13c739ea',
+ 'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '635de1ec',
'rsrc/js/application/uiexample/JavelinViewExample.js' => 'd4a14807',
'rsrc/js/application/uiexample/ReactorButtonExample.js' => 'd19198c8',
'rsrc/js/application/uiexample/ReactorCheckboxExample.js' => '519705ea',
@@ -657,6 +659,7 @@
'javelin-behavior-stripe-payment-form' => '3f5d6dbf',
'javelin-behavior-test-payment-form' => 'fc91ab6c',
'javelin-behavior-toggle-class' => 'e566f52c',
+ 'javelin-behavior-typeahead-browse' => '635de1ec',
'javelin-behavior-view-placeholder' => '47830651',
'javelin-behavior-workflow' => '0a3f3021',
'javelin-color' => '7e41274a',
@@ -833,6 +836,7 @@
'sprite-tokens-css' => '1706b943',
'syntax-highlighting-css' => '56c1ba38',
'tokens-css' => '3d0f239e',
+ 'typeahead-browse-css' => '252b1ac4',
'unhandled-exception-css' => '37d4f9a2',
),
'requires' => array(
@@ -1267,6 +1271,12 @@
'javelin-install',
'javelin-util',
),
+ '635de1ec' => array(
+ 'javelin-behavior',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'javelin-dom',
+ ),
'6882e80a' => array(
'javelin-dom',
),
diff --git a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
--- a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
+++ b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
@@ -37,9 +37,18 @@
->setQuery($query)
->setRawQuery($raw_query);
+ $hard_limit = 1000;
+
if ($is_browse) {
$limit = 10;
$offset = $request->getInt('offset');
+
+ if (($offset + $limit) >= $hard_limit) {
+ // Offset-based paging is intrinsically slow; hard-cap how far we're
+ // willing to go with it.
+ return new Aphront404Response();
+ }
+
$composite
->setLimit($limit + 1)
->setOffset($offset);
@@ -49,15 +58,32 @@
if ($is_browse) {
$next_link = null;
+
if (count($results) > $limit) {
$results = array_slice($results, 0, $limit, $preserve_keys = true);
- $next_link = phutil_tag(
- 'a',
- array(
- 'href' => id(new PhutilURI($request->getRequestURI()))
- ->setQueryParam('offset', $offset + $limit),
- ),
- pht('Next Page'));
+ if (($offset + (2 * $limit)) < $hard_limit) {
+ $next_uri = id(new PhutilURI($request->getRequestURI()))
+ ->setQueryParam('offset', $offset + $limit);
+
+ $next_link = javelin_tag(
+ 'a',
+ array(
+ 'href' => $next_uri,
+ 'class' => 'typeahead-browse-more',
+ 'sigil' => 'typeahead-browse-more',
+ 'mustcapture' => true,
+ ),
+ pht('More Results'));
+ } else {
+ // If the user has paged through more than 1K results, don't
+ // offer to page any further.
+ $next_link = javelin_tag(
+ 'div',
+ array(
+ 'class' => 'typeahead-browse-hard-limit',
+ ),
+ pht('You reach the edge of the abyss.'));
+ }
}
$items = array();
@@ -72,11 +98,32 @@
$token);
}
+ $markup = array(
+ $items,
+ $next_link,
+ );
+
+ if ($request->isAjax()) {
+ $content = array(
+ 'markup' => hsprintf('%s', $markup),
+ );
+ return id(new AphrontAjaxResponse())->setContent($content);
+ }
+
+ $this->requireResource('typeahead-browse-css');
+ $this->initBehavior('typeahead-browse');
+
+ $markup = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'typeahead-browse-frame',
+ ),
+ $markup);
+
return $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FORM)
->setTitle(get_class($source)) // TODO: Provide nice names.
- ->appendChild($items)
- ->appendChild($next_link)
+ ->appendChild($markup)
->addCancelButton('/', pht('Close'));
}
diff --git a/webroot/rsrc/css/aphront/typeahead-browse.css b/webroot/rsrc/css/aphront/typeahead-browse.css
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/css/aphront/typeahead-browse.css
@@ -0,0 +1,34 @@
+/**
+ * @provides typeahead-browse-css
+ */
+
+.typeahead-browse-more,
+.typeahead-browse-hard-limit {
+ display: block;
+ padding: 8px;
+ margin: 8px 0 0;
+ text-align: center;
+}
+
+.typeahead-browse-more {
+ background: {$lightblue};
+ border: 1px solid {$lightblueborder};
+}
+
+.typeahead-browse-more.loading {
+ opacity: 0.8;
+}
+
+.typeahead-browse-hard-limit {
+ background: {$lightgreybackground};
+ border: 1px solid {$lightgreyborder};
+ color: {$lightgreytext};
+}
+
+.typeahead-browse-frame {
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 4px;
+ height: 260px;
+ border: 1px solid {$lightgreyborder};
+}
diff --git a/webroot/rsrc/js/application/typeahead/behavior-typeahead-browse.js b/webroot/rsrc/js/application/typeahead/behavior-typeahead-browse.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/typeahead/behavior-typeahead-browse.js
@@ -0,0 +1,31 @@
+/**
+ * @provides javelin-behavior-typeahead-browse
+ * @requires javelin-behavior
+ * javelin-stratcom
+ * javelin-workflow
+ * javelin-dom
+ */
+
+JX.behavior('typeahead-browse', function() {
+ var loading = false;
+
+ JX.Stratcom.listen('click', 'typeahead-browse-more', function(e) {
+ e.kill();
+
+ if (loading) {
+ return;
+ }
+ var link = e.getTarget();
+
+ loading = true;
+ JX.DOM.alterClass(link, 'loading', true);
+
+ JX.Workflow.newFromLink(link)
+ .setHandler(function(r) {
+ loading = false;
+ JX.DOM.replace(link, JX.$H(r.markup));
+ })
+ .start();
+ });
+
+});

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 9, 5:54 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6763294
Default Alt Text
D12425.id29834.diff (6 KB)

Event Timeline