From 6b1d13bfaf3dec8bfc1957dddeb45a965011b79e Mon Sep 17 00:00:00 2001 From: lkassianik Date: Wed, 20 May 2015 09:51:26 -0700 Subject: [PATCH] Time control typeaheads. Summary: Ref T8031, Time control typeaheads Test Plan: Edit an event, type '3', typeahead should suggest, '3:00 AM', '3:30 AM', '3:00 PM', '3:30 PM'. Reviewers: chad, epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin, epriestley Maniphest Tasks: T8031 Differential Revision: https://secure.phabricator.com/D12953 --- resources/celerity/map.php | 28 +++++++++----- .../form/control/AphrontFormDateControl.php | 38 ++++++++++++++++++- webroot/rsrc/css/phui/phui-form-view.css | 15 +++++++- .../typeahead/source/TypeaheadStaticSource.js | 8 ++-- .../rsrc/js/core/behavior-time-typeahead.js | 36 ++++++++++++++++++ 5 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 webroot/rsrc/js/core/behavior-time-typeahead.js diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e150725a0e..1502be2eac 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,7 +7,7 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'e3ba62e8', + 'core.pkg.css' => '36142bff', 'core.pkg.js' => '328799d0', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => 'bb338e4b', @@ -134,7 +134,7 @@ return array( 'rsrc/css/phui/phui-document.css' => '94d5dcd8', 'rsrc/css/phui/phui-feed-story.css' => 'c9f3a0b5', 'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27', - 'rsrc/css/phui/phui-form-view.css' => '94ae3032', + 'rsrc/css/phui/phui-form-view.css' => '79793450', 'rsrc/css/phui/phui-form.css' => 'f535f938', 'rsrc/css/phui/phui-header-view.css' => '75aaf372', 'rsrc/css/phui/phui-icon.css' => 'bc766998', @@ -231,7 +231,7 @@ return array( 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '8b3fd187', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '2818f5ce', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '316b8fa1', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa', 'rsrc/externals/raphael/g.raphael.js' => '40dde778', 'rsrc/externals/raphael/g.raphael.line.js' => '40da039e', 'rsrc/externals/raphael/raphael.js' => '51ee6b43', @@ -466,6 +466,7 @@ return array( 'rsrc/js/core/behavior-scrollbar.js' => '834a1173', 'rsrc/js/core/behavior-search-typeahead.js' => '048330fa', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', + 'rsrc/js/core/behavior-time-typeahead.js' => '8cf340fd', 'rsrc/js/core/behavior-toggle-class.js' => '5d7c9f33', 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 'rsrc/js/core/behavior-tooltip.js' => '3ee3408b', @@ -640,6 +641,7 @@ return array( 'javelin-behavior-slowvote-embed' => '887ad43f', 'javelin-behavior-stripe-payment-form' => '3f5d6dbf', 'javelin-behavior-test-payment-form' => 'fc91ab6c', + 'javelin-behavior-time-typeahead' => '8cf340fd', 'javelin-behavior-toggle-class' => '5d7c9f33', 'javelin-behavior-typeahead-browse' => '635de1ec', 'javelin-behavior-typeahead-search' => '93d0c9e3', @@ -677,7 +679,7 @@ return array( 'javelin-typeahead-ondemand-source' => '8b3fd187', 'javelin-typeahead-preloaded-source' => '54f314a0', 'javelin-typeahead-source' => '2818f5ce', - 'javelin-typeahead-static-source' => '316b8fa1', + 'javelin-typeahead-static-source' => '6c0e62fa', 'javelin-uri' => '6eff08aa', 'javelin-util' => '93cc50d6', 'javelin-vector' => '2caa8fb8', @@ -772,7 +774,7 @@ return array( 'phui-font-icon-base-css' => '3dad2ae3', 'phui-fontkit-css' => 'dd8ddf27', 'phui-form-css' => 'f535f938', - 'phui-form-view-css' => '94ae3032', + 'phui-form-view-css' => '79793450', 'phui-header-view-css' => '75aaf372', 'phui-icon-view-css' => 'bc766998', 'phui-image-mask-css' => '5a8b09c8', @@ -1036,10 +1038,6 @@ return array( 'javelin-install', 'javelin-event', ), - '316b8fa1' => array( - 'javelin-install', - 'javelin-typeahead-source', - ), '331b1611' => array( 'javelin-install', ), @@ -1307,6 +1305,10 @@ return array( '69adf288' => array( 'javelin-install', ), + '6c0e62fa' => array( + 'javelin-install', + 'javelin-typeahead-source', + ), '6c2b09a2' => array( 'javelin-install', 'javelin-util', @@ -1482,6 +1484,14 @@ return array( 'javelin-stratcom', 'javelin-behavior', ), + '8cf340fd' => array( + 'javelin-behavior', + 'javelin-util', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-vector', + 'javelin-typeahead-static-source', + ), '8cf6d262' => array( 'javelin-install', 'javelin-dom', diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php index 84de3b3215..df0efe2c4a 100644 --- a/src/view/form/control/AphrontFormDateControl.php +++ b/src/view/form/control/AphrontFormDateControl.php @@ -270,9 +270,19 @@ final class AphrontFormDateControl extends AphrontFormControl { ), $cicon); + $values = $this->getTimeTypeaheadValues(); + + $time_id = celerity_generate_unique_node_id(); + Javelin::initBehavior('time-typeahead', array( + 'timeID' => $time_id, + 'timeValues' => $values, + )); + + $time_sel = javelin_tag( 'input', array( + 'autocomplete' => 'off', 'name' => $this->getTimeInputName(), 'sigil' => 'time-input', 'value' => $this->getTimeInputValue(), @@ -281,6 +291,14 @@ final class AphrontFormDateControl extends AphrontFormControl { ), ''); + $time_div = javelin_tag( + 'div', + array( + 'id' => $time_id, + 'class' => 'aphront-form-date-time-input-container', + ), + $time_sel); + Javelin::initBehavior('fancy-datepicker', array()); $classes = array(); @@ -308,7 +326,7 @@ final class AphrontFormDateControl extends AphrontFormControl { $months_sel, $years_sel, $cal_icon, - $time_sel, + $time_div, )); } @@ -359,4 +377,22 @@ final class AphrontFormDateControl extends AphrontFormControl { return $value; } + private function getTimeTypeaheadValues() { + $times = array(); + $am_pm_list = array('AM', 'PM'); + + foreach ($am_pm_list as $am_pm) { + for ($hour = 0; $hour < 12; $hour++) { + $actual_hour = ($hour == 0) ? 12 : $hour; + $times[] = $actual_hour.':00 '.$am_pm; + $times[] = $actual_hour.':30 '.$am_pm; + } + } + + foreach ($times as $key => $time) { + $times[$key] = array($key, $time); + } + return $times; + } + } diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css index 5a3180d8b0..2600de81ac 100644 --- a/webroot/rsrc/css/phui/phui-form-view.css +++ b/webroot/rsrc/css/phui/phui-form-view.css @@ -334,9 +334,22 @@ table.aphront-form-control-checkbox-layout th { font-size: 16px; } +.aphront-form-date-container .aphront-form-date-time-input-container { + position: relative; + display: inline-block; + width: 7em; +} + .aphront-form-date-container input.aphront-form-date-time-input { width: 7em; - display: inline; +} + +.aphront-form-date-time-input-container div.jx-typeahead-results a.jx-result { + border: none; +} + +.phui-time-typeahead-value { + padding: 4px; } .fancy-datepicker { diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js index 765074ff27..9bd6bff8f4 100644 --- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js +++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js @@ -16,19 +16,19 @@ JX.install('TypeaheadStaticSource', { construct : function(data) { JX.TypeaheadSource.call(this); - this._data = data; + this.data = data; }, members : { - _data : null, + data : null, didChange : function(value) { this.matchResults(value); }, didStart : function() { - for (var ii = 0; ii < this._data.length; ii++) { - this.addResult(this._data[ii]); + for (var ii = 0; ii < this.data.length; ii++) { + this.addResult(this.data[ii]); } } } diff --git a/webroot/rsrc/js/core/behavior-time-typeahead.js b/webroot/rsrc/js/core/behavior-time-typeahead.js new file mode 100644 index 0000000000..158b8fbd4b --- /dev/null +++ b/webroot/rsrc/js/core/behavior-time-typeahead.js @@ -0,0 +1,36 @@ +/** + * @provides javelin-behavior-time-typeahead + * @requires javelin-behavior + * javelin-util + * javelin-dom + * javelin-stratcom + * javelin-vector + * javelin-typeahead-static-source + */ + +JX.behavior('time-typeahead', function(config) { + var root = JX.$(config.timeID); + var datasource = new JX.TypeaheadStaticSource(config.timeValues); + datasource.setTransformer(function(v) { + var attributes = {'className' : 'phui-time-typeahead-value'}; + var display = JX.$N('div', attributes, v[1]); + var object = { + 'id' : v[0], + 'name' : v[1], + 'display' : display, + 'uri' : null + }; + return object; + }); + datasource.setSortHandler(function(value, list) { + list.sort(function(u,v){ + return (u.id > v.id) ? 1 : -1; + }); + }); + datasource.setMaximumResultCount(24); + var typeahead = new JX.Typeahead( + root, + JX.DOM.find(root, 'input', null)); + typeahead.setDatasource(datasource); + typeahead.start(); +});