Page MenuHomePhabricator

D12426.diff
No OneTemporary

D12426.diff

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
@@ -113,17 +113,49 @@
$this->requireResource('typeahead-browse-css');
$this->initBehavior('typeahead-browse');
- $markup = phutil_tag(
+ $input_id = celerity_generate_unique_node_id();
+ $frame_id = celerity_generate_unique_node_id();
+
+ $config = array(
+ 'inputID' => $input_id,
+ 'frameID' => $frame_id,
+ 'uri' => (string)$request->getRequestURI(),
+ );
+ $this->initBehavior('typeahead-search', $config);
+
+ $search = javelin_tag(
+ 'input',
+ array(
+ 'type' => 'text',
+ 'id' => $input_id,
+ 'class' => 'typeahead-browse-input',
+ 'autocomplete' => 'off',
+ 'placeholder' => $source->getPlaceholderText(),
+ ));
+
+ $frame = phutil_tag(
'div',
array(
'class' => 'typeahead-browse-frame',
+ 'id' => $frame_id,
),
$markup);
+ $browser = array(
+ phutil_tag(
+ 'div',
+ array(
+ 'class' => 'typeahead-browse-header',
+ ),
+ $search),
+ $frame,
+ );
+
return $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setRenderDialogAsDiv(true)
->setTitle(get_class($source)) // TODO: Provide nice names.
- ->appendChild($markup)
+ ->appendChild($browser)
->addCancelButton('/', pht('Close'));
}
diff --git a/webroot/rsrc/css/aphront/typeahead-browse.css b/webroot/rsrc/css/aphront/typeahead-browse.css
--- a/webroot/rsrc/css/aphront/typeahead-browse.css
+++ b/webroot/rsrc/css/aphront/typeahead-browse.css
@@ -32,3 +32,16 @@
height: 260px;
border: 1px solid {$lightgreyborder};
}
+
+.typeahead-browse-frame.loading {
+ opacity: 0.8;
+}
+
+.typeahead-browse-header {
+ padding: 4px 0;
+}
+
+input.typeahead-browse-input {
+ margin: 0;
+ width: 100%;
+}
diff --git a/webroot/rsrc/js/application/typeahead/behavior-typeahead-search.js b/webroot/rsrc/js/application/typeahead/behavior-typeahead-search.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/typeahead/behavior-typeahead-search.js
@@ -0,0 +1,56 @@
+/**
+ * @provides javelin-behavior-typeahead-search
+ * @requires javelin-behavior
+ * javelin-stratcom
+ * javelin-workflow
+ * javelin-dom
+ */
+
+JX.behavior('typeahead-search', function(config) {
+ var input = JX.$(config.inputID);
+ var frame = JX.$(config.frameID);
+ var last = input.value;
+
+ function update() {
+ if (input.value == last) {
+ // This is some kind of non-input keypress like an arrow key. Don't
+ // send a query to the server.
+ return;
+ }
+
+ // Call load() in a little while. If the user hasn't typed anything else,
+ // we'll send a request to get results.
+ setTimeout(JX.bind(null, load, input.value), 100);
+ }
+
+ function load(value) {
+ if (value != input.value) {
+ // The user has typed some more text, so don't send a request yet. We
+ // want to wait for them to stop typing.
+ return;
+ }
+
+ JX.DOM.alterClass(frame, 'loading', true);
+ new JX.Workflow(config.uri, {q: value})
+ .setHandler(function(r) {
+ if (value != input.value) {
+ // The user typed some more stuff while the request was in flight,
+ // so ignore the response.
+ return;
+ }
+
+ last = input.value;
+ JX.DOM.setContent(frame, JX.$H(r.markup));
+ JX.DOM.alterClass(frame, 'loading', false);
+ })
+ .start();
+ }
+
+ JX.DOM.listen(input, ['keydown', 'keypress', 'keyup'], null, function() {
+ // We need to delay this to actually read the value after the keypress.
+ setTimeout(update, 0);
+ });
+
+ JX.DOM.focus(input);
+
+});

File Metadata

Mime Type
text/plain
Expires
Wed, May 8, 11:13 PM (4 w, 21 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6273449
Default Alt Text
D12426.diff (4 KB)

Event Timeline