@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Calendar event datepicker should auto-complete end time to be an hour from start time unless end time has been edited.

Summary: Ref T8031, Calendar event datepicker should auto-complete end time to be an hour from start time unless end time has been edited

Test Plan: Create event, edit start time, end time should adjust to an hour from start time.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Maniphest Tasks: T8031

Differential Revision: https://secure.phabricator.com/D12960

+115 -19
+10 -10
resources/celerity/map.php
··· 466 466 'rsrc/js/core/behavior-scrollbar.js' => '834a1173', 467 467 'rsrc/js/core/behavior-search-typeahead.js' => '048330fa', 468 468 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 469 - 'rsrc/js/core/behavior-time-typeahead.js' => '3416cef7', 469 + 'rsrc/js/core/behavior-time-typeahead.js' => '8bfbb401', 470 470 'rsrc/js/core/behavior-toggle-class.js' => '5d7c9f33', 471 471 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 472 472 'rsrc/js/core/behavior-tooltip.js' => '3ee3408b', ··· 641 641 'javelin-behavior-slowvote-embed' => '887ad43f', 642 642 'javelin-behavior-stripe-payment-form' => '3f5d6dbf', 643 643 'javelin-behavior-test-payment-form' => 'fc91ab6c', 644 - 'javelin-behavior-time-typeahead' => '3416cef7', 644 + 'javelin-behavior-time-typeahead' => '8bfbb401', 645 645 'javelin-behavior-toggle-class' => '5d7c9f33', 646 646 'javelin-behavior-typeahead-browse' => '635de1ec', 647 647 'javelin-behavior-typeahead-search' => '93d0c9e3', ··· 1041 1041 '331b1611' => array( 1042 1042 'javelin-install', 1043 1043 ), 1044 - '3416cef7' => array( 1045 - 'javelin-behavior', 1046 - 'javelin-util', 1047 - 'javelin-dom', 1048 - 'javelin-stratcom', 1049 - 'javelin-vector', 1050 - 'javelin-typeahead-static-source', 1051 - ), 1052 1044 '3975b470' => array( 1053 1045 'javelin-behavior', 1054 1046 'javelin-dom', ··· 1494 1486 'javelin-util', 1495 1487 'javelin-request', 1496 1488 'javelin-typeahead-source', 1489 + ), 1490 + '8bfbb401' => array( 1491 + 'javelin-behavior', 1492 + 'javelin-util', 1493 + 'javelin-dom', 1494 + 'javelin-stratcom', 1495 + 'javelin-vector', 1496 + 'javelin-typeahead-static-source', 1497 1497 ), 1498 1498 '8ce821c5' => array( 1499 1499 'phabricator-notification',
+7 -5
src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
··· 21 21 $error_end_date = true; 22 22 $validation_exception = null; 23 23 24 + $all_day_id = celerity_generate_unique_node_id(); 25 + $start_date_id = celerity_generate_unique_node_id(); 26 + $end_date_id = null; 27 + 24 28 if ($this->isCreate()) { 25 29 $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user); 26 30 list($start_value, $end_value) = $this->getDefaultTimeValues($user); ··· 31 35 $subscribers = array(); 32 36 $invitees = array($user_phid); 33 37 $cancel_uri = $this->getApplicationURI(); 38 + $end_date_id = celerity_generate_unique_node_id(); 34 39 } else { 35 40 $event = id(new PhabricatorCalendarEventQuery()) 36 41 ->setViewer($user) ··· 178 183 } 179 184 } 180 185 181 - $all_day_id = celerity_generate_unique_node_id(); 182 - $start_date_id = celerity_generate_unique_node_id(); 183 - $end_date_id = celerity_generate_unique_node_id(); 184 - 185 186 Javelin::initBehavior('event-all-day', array( 186 187 'allDayID' => $all_day_id, 187 188 'startDateID' => $start_date_id, ··· 209 210 ->setError($error_start_date) 210 211 ->setValue($start_value) 211 212 ->setID($start_date_id) 212 - ->setIsTimeDisabled($is_all_day); 213 + ->setIsTimeDisabled($is_all_day) 214 + ->setEndDateID($end_date_id); 213 215 214 216 $end_control = id(new AphrontFormDateControl()) 215 217 ->setUser($user)
+8 -1
src/view/form/control/AphrontFormDateControl.php
··· 13 13 private $continueOnInvalidDate = false; 14 14 private $isTimeDisabled; 15 15 private $isDisabled; 16 + private $endDateID; 16 17 17 18 public function setAllowNull($allow_null) { 18 19 $this->allowNull = $allow_null; ··· 21 22 22 23 public function setIsTimeDisabled($is_disabled) { 23 24 $this->isTimeDisabled = $is_disabled; 25 + return $this; 26 + } 27 + 28 + public function setEndDateID($value) { 29 + $this->endDateID = $value; 24 30 return $this; 25 31 } 26 32 ··· 274 280 275 281 $time_id = celerity_generate_unique_node_id(); 276 282 Javelin::initBehavior('time-typeahead', array( 277 - 'timeID' => $time_id, 283 + 'startTimeID' => $time_id, 284 + 'endTimeID' => $this->endDateID, 278 285 'timeValues' => $values, 279 286 )); 280 287
+90 -3
webroot/rsrc/js/core/behavior-time-typeahead.js
··· 9 9 */ 10 10 11 11 JX.behavior('time-typeahead', function(config) { 12 - var root = JX.$(config.timeID); 12 + var start_date_control = JX.$(config.startTimeID); 13 + var end_date_control = config.endTimeID ? JX.$(config.endTimeID) : null; 14 + 15 + var end_date_tampered = false; 16 + 13 17 var datasource = new JX.TypeaheadStaticSource(config.timeValues); 14 18 datasource.setTransformer(function(v) { 15 19 var attributes = {'className' : 'phui-time-typeahead-value'}; ··· 29 33 }); 30 34 datasource.setMaximumResultCount(24); 31 35 var typeahead = new JX.Typeahead( 32 - root, 33 - JX.DOM.find(root, 'input', null)); 36 + start_date_control, 37 + JX.DOM.find(start_date_control, 'input', null)); 34 38 typeahead.setDatasource(datasource); 39 + 40 + if (!end_date_control) { 41 + typeahead.start(); 42 + return; 43 + } 44 + 45 + var start_time_control = JX.DOM.find( 46 + start_date_control, 47 + 'input', 48 + 'time-input'); 49 + var end_time_control = JX.DOM.find( 50 + end_date_control, 51 + 'input', 52 + 'time-input'); 53 + 54 + JX.DOM.listen(start_time_control, 'input', null, function() { 55 + if (end_date_tampered) { 56 + return; 57 + } 58 + var time = start_time_control.value; 59 + var end_value = getNewValue(time); 60 + if (end_value) { 61 + end_time_control.value = end_value; 62 + } 63 + }); 64 + 65 + typeahead.listen('choose', function(e) { 66 + if (end_date_tampered) { 67 + return; 68 + } 69 + var time = e.name; 70 + var end_value = getNewValue(time); 71 + if (end_value) { 72 + end_time_control.value = end_value; 73 + } 74 + }); 75 + 76 + JX.DOM.listen(end_date_control, 'input', null, function() { 77 + end_date_tampered = true; 78 + }); 79 + 80 + 81 + function getNewValue(time) { 82 + var regex = /^([01]?\d)(?::([0-5]\d))?\s*((am|pm))?$/i; 83 + 84 + if (!regex.test(time)) { 85 + return null; 86 + } 87 + 88 + var results = regex.exec(time); 89 + var hours = parseInt(results[1], 10); 90 + var minutes = parseInt(results[2], 10) ? parseInt(results[2], 10) : 0; 91 + 92 + var real_time = 0; 93 + 94 + if (/pm/i.test(results[3])) { 95 + real_time = 12*60; 96 + } else if (/am/i.test(results[3]) && hours == 12) { 97 + hours = 0; 98 + } 99 + 100 + real_time = real_time + (hours * 60) + minutes; 101 + 102 + var end_time = real_time + 60; 103 + 104 + var end_meridian = 'AM'; 105 + var end_hours = Math.floor(end_time / 60); 106 + 107 + if (end_hours == 12) { 108 + end_meridian = 'PM'; 109 + } else if (end_hours > 12 && end_hours < 24) { 110 + end_hours = end_hours - 12; 111 + end_meridian = 'PM'; 112 + } else if (end_hours == 24) { 113 + end_hours = end_hours - 12; 114 + } 115 + 116 + var end_minutes = end_time%60; 117 + end_minutes = (end_minutes > 9) ? end_minutes : ('0' + end_minutes); 118 + var end_value = end_hours + ':' + end_minutes + ' ' + end_meridian; 119 + return end_value; 120 + } 121 + 35 122 typeahead.start(); 36 123 });