@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.

Merge branch 'master' into phutil_tag

(Final sync.)

+589 -201
+2 -1
conf/default.conf.php
··· 801 801 // Show stack traces when unhandled exceptions occur, force reloading of 802 802 // static resources (skipping the cache), show an error callout if a page 803 803 // generated PHP errors, warnings, or notices, force disk reads when 804 - // reloading. This option should not be enabled in production. 804 + // reloading, and generally make development easier. This option should not 805 + // be enabled in production. 805 806 'phabricator.developer-mode' => false, 806 807 807 808 // When users write comments which have URIs, they'll be automatically linked
+33
resources/sql/patches/20130201.revisionunsubscribed.php
··· 1 + <?php 2 + 3 + echo "Migrating Differential unsubscribed users to edges...\n"; 4 + $table = new DifferentialRevision(); 5 + $table->openTransaction(); 6 + 7 + // We couldn't use new LiskMigrationIterator($table) because the $unsubscribed 8 + // property gets deleted. 9 + $revs = queryfx_all( 10 + $table->establishConnection('w'), 11 + 'SELECT id, phid, unsubscribed FROM differential_revision'); 12 + 13 + foreach ($revs as $rev) { 14 + echo "."; 15 + 16 + $unsubscribed = json_decode($rev['unsubscribed']); 17 + if (!$unsubscribed) { 18 + continue; 19 + } 20 + 21 + $editor = new PhabricatorEdgeEditor(); 22 + $editor->setSuppressEvents(true); 23 + foreach ($unsubscribed as $user_phid => $_) { 24 + $editor->addEdge( 25 + $rev['phid'], 26 + PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER, 27 + $user_phid); 28 + } 29 + $editor->save(); 30 + } 31 + 32 + $table->saveTransaction(); 33 + echo "Done.\n";
+2
resources/sql/patches/20130201.revisionunsubscribed.sql
··· 1 + ALTER TABLE {$NAMESPACE}_differential.differential_revision 2 + DROP unsubscribed;
+2
src/__phutil_library_map__.php
··· 1226 1226 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 1227 1227 'PhabricatorSettingsPanelAccount' => 'applications/settings/panel/PhabricatorSettingsPanelAccount.php', 1228 1228 'PhabricatorSettingsPanelConduit' => 'applications/settings/panel/PhabricatorSettingsPanelConduit.php', 1229 + 'PhabricatorSettingsPanelDiffPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDiffPreferences.php', 1229 1230 'PhabricatorSettingsPanelDisplayPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDisplayPreferences.php', 1230 1231 'PhabricatorSettingsPanelEmailAddresses' => 'applications/settings/panel/PhabricatorSettingsPanelEmailAddresses.php', 1231 1232 'PhabricatorSettingsPanelEmailPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelEmailPreferences.php', ··· 2625 2626 'PhabricatorSettingsMainController' => 'PhabricatorController', 2626 2627 'PhabricatorSettingsPanelAccount' => 'PhabricatorSettingsPanel', 2627 2628 'PhabricatorSettingsPanelConduit' => 'PhabricatorSettingsPanel', 2629 + 'PhabricatorSettingsPanelDiffPreferences' => 'PhabricatorSettingsPanel', 2628 2630 'PhabricatorSettingsPanelDisplayPreferences' => 'PhabricatorSettingsPanel', 2629 2631 'PhabricatorSettingsPanelEmailAddresses' => 'PhabricatorSettingsPanel', 2630 2632 'PhabricatorSettingsPanelEmailPreferences' => 'PhabricatorSettingsPanel',
+14
src/applications/config/check/PhabricatorSetupCheckDatabase.php
··· 65 65 return; 66 66 } 67 67 68 + if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) { 69 + $mode_string = queryfx_one($conn_raw, "SELECT @@sql_mode"); 70 + $modes = explode(',', $mode_string['@@sql_mode']); 71 + if (!in_array('STRICT_ALL_TABLES', $modes)) { 72 + $message = pht( 73 + "The global sql_mode is not set to 'STRICT_ALL_TABLES'. It is ". 74 + "recommended that you set this mode while developing Phabricator."); 75 + 76 + $this->newIssue('mysql.mode') 77 + ->setName(pht('MySQL STRICT_ALL_TABLES mode not set.')) 78 + ->setMessage($message); 79 + } 80 + } 81 + 68 82 $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace'); 69 83 70 84 $databases = queryfx_all($conn_raw, 'SHOW DATABASES');
+13 -7
src/applications/conpherence/controller/ConpherenceListController.php
··· 77 77 'class' => 'conpherence-header-pane', 78 78 'id' => 'conpherence-header-pane', 79 79 ), 80 - ''), 80 + '' 81 + ), 81 82 phutil_tag( 82 83 'div', 83 84 array( 84 85 'class' => 'conpherence-widget-pane', 85 86 'id' => 'conpherence-widget-pane' 86 87 ), 87 - ''), 88 - phutil_tag( 88 + '' 89 + ), 90 + javelin_tag( 89 91 'div', 90 92 array( 91 93 'class' => 'conpherence-message-pane', ··· 98 100 'class' => 'conpherence-messages', 99 101 'id' => 'conpherence-messages' 100 102 ), 101 - ''), 103 + '' 104 + ), 102 105 phutil_tag( 103 106 'div', 104 107 array( 105 108 'id' => 'conpherence-form' 106 109 ), 107 - ''), 108 - )), 109 - )); 110 + '' 111 + ) 112 + ) 113 + ) 114 + ) 115 + ); 110 116 } 111 117 112 118
+1 -2
src/applications/conpherence/controller/ConpherenceNewController.php
··· 95 95 phutil_tag( 96 96 'p', 97 97 array(), 98 - pht('Message sent successfully.')) 99 - ); 98 + pht('Message sent successfully.'))); 100 99 $response = id(new AphrontDialogResponse()) 101 100 ->setDialog($dialog); 102 101 } else {
+137 -25
src/applications/conpherence/controller/ConpherenceViewController.php
··· 71 71 $edit_href = $this->getApplicationURI('update/'.$conpherence->getID().'/'); 72 72 73 73 $header = 74 - javelin_render_tag( 74 + javelin_tag( 75 75 'a', 76 76 array( 77 77 'class' => 'edit', ··· 80 80 ), 81 81 '' 82 82 ). 83 - phutil_render_tag( 83 + phutil_tag( 84 84 'div', 85 85 array( 86 86 'class' => 'header-image', ··· 88 88 ), 89 89 '' 90 90 ). 91 - phutil_render_tag( 91 + phutil_tag( 92 92 'div', 93 93 array( 94 94 'class' => 'title', 95 95 ), 96 - phutil_escape_html($display_data['title']) 96 + $display_data['title'] 97 97 ). 98 - phutil_render_tag( 98 + phutil_tag( 99 99 'div', 100 100 array( 101 101 'class' => 'subtitle', 102 102 ), 103 - phutil_escape_html($display_data['subtitle']) 103 + $display_data['subtitle'] 104 104 ); 105 105 106 106 return array('header' => $header); ··· 152 152 153 153 private function renderWidgetPaneContent() { 154 154 require_celerity_resource('conpherence-widget-pane-css'); 155 + require_celerity_resource('sprite-conpher-css'); 155 156 Javelin::initBehavior( 156 157 'conpherence-widget-pane', 157 158 array( ··· 165 166 166 167 $conpherence = $this->getConpherence(); 167 168 168 - $widgets = phutil_render_tag( 169 + $widgets = phutil_tag( 169 170 'div', 170 171 array( 171 172 'class' => 'widgets-header' ··· 175 176 'a', 176 177 array( 177 178 'sigil' => 'conpherence-change-widget', 178 - 'meta' => array('widget' => 'widgets-files') 179 + 'meta' => array( 180 + 'widget' => 'widgets-files', 181 + 'toggleClass' => 'conpher_files_on' 182 + ), 183 + 'id' => 'widgets-files-toggle', 184 + 'class' => 'sprite-conpher conpher_files_off first-icon' 179 185 ), 180 - pht('Files') 186 + '' 181 187 ), 182 - ' | ', 183 188 javelin_tag( 184 189 'a', 185 190 array( 186 191 'sigil' => 'conpherence-change-widget', 187 - 'meta' => array('widget' => 'widgets-tasks') 192 + 'meta' => array( 193 + 'widget' => 'widgets-tasks', 194 + 'toggleClass' => 'conpher_list_on' 195 + ), 196 + 'id' => 'widgets-tasks-toggle', 197 + 'class' => 'sprite-conpher conpher_list_off conpher_list_on', 188 198 ), 189 - pht('Tasks') 199 + '' 190 200 ), 191 - ' | ', 192 201 javelin_tag( 193 202 'a', 194 203 array( 195 204 'sigil' => 'conpherence-change-widget', 196 - 'meta' => array('widget' => 'widgets-calendar') 205 + 'meta' => array( 206 + 'widget' => 'widgets-calendar', 207 + 'toggleClass' => 'conpher_calendar_on' 208 + ), 209 + 'id' => 'widgets-calendar-toggle', 210 + 'class' => 'sprite-conpher conpher_calendar_off', 197 211 ), 198 - pht('Calendar') 199 - ), 212 + '' 213 + ) 200 214 ) 201 215 ). 202 - phutil_render_tag( 216 + phutil_tag( 203 217 'div', 204 218 array( 205 219 'class' => 'widgets-body', ··· 208 222 ), 209 223 $this->renderFilesWidgetPaneContent() 210 224 ). 211 - phutil_render_tag( 225 + phutil_tag( 212 226 'div', 213 227 array( 214 228 'class' => 'widgets-body', ··· 216 230 ), 217 231 $this->renderTaskWidgetPaneContent() 218 232 ). 219 - phutil_render_tag( 233 + phutil_tag( 220 234 'div', 221 235 array( 222 236 'class' => 'widgets-body', ··· 253 267 ->setNoDataString(pht('No files attached to conpherence.')) 254 268 ->setHeaders(array('', pht('Name'))) 255 269 ->setColumnClasses(array('', 'wide')); 256 - return $header->render() . $table->render(); 270 + return new PhutilSafeHTML($header->render() . $table->render()); 257 271 } 258 272 259 273 private function renderTaskWidgetPaneContent() { ··· 279 293 array( 280 294 'href' => '/T'.$task->getID() 281 295 ), 282 - $task->getTitle()), 296 + $task->getTitle() 297 + ) 283 298 ); 284 299 } 285 300 $table = id(new AphrontTableView($data)) ··· 288 303 ->setColumnClasses(array('', 'wide')); 289 304 $content[] = $table->render(); 290 305 } 291 - return implode('', $content); 306 + return new PhutilSafeHTML(implode('', $content)); 292 307 } 293 308 294 309 private function renderCalendarWidgetPaneContent() { 295 - $header = id(new PhabricatorHeaderView()) 296 - ->setHeader(pht('Calendar')); 297 - return $header->render() . 'TODO'; 310 + $user = $this->getRequest()->getUser(); 311 + 312 + $conpherence = $this->getConpherence(); 313 + $widget_data = $conpherence->getWidgetData(); 314 + $statuses = $widget_data['statuses']; 315 + $handles = $conpherence->getHandles(); 316 + $content = array(); 317 + $timestamps = $this->getCalendarWidgetWeekTimestamps(); 318 + $one_day = 24 * 60 * 60; 319 + foreach ($timestamps as $time => $day) { 320 + // build a header for the new day 321 + $content[] = id(new PhabricatorHeaderView()) 322 + ->setHeader($day->format('l')) 323 + ->render(); 324 + 325 + $day->setTime(0, 0, 0); 326 + $epoch_start = $day->format('U'); 327 + $day->modify('+1 day'); 328 + $epoch_end = $day->format('U'); 329 + 330 + // keep looking through statuses where we last left off 331 + foreach ($statuses as $status) { 332 + if ($status->getDateFrom() >= $epoch_end) { 333 + // This list is sorted, so we can stop looking. 334 + break; 335 + } 336 + if ($status->getDateFrom() < $epoch_end && 337 + $status->getDateTo() > $epoch_start) { 338 + $timespan = $status->getDateTo() - $status->getDateFrom(); 339 + if ($timespan > $one_day) { 340 + $time_str = 'm/d'; 341 + } else { 342 + $time_str = 'h:i A'; 343 + } 344 + $epoch_range = phabricator_format_local_time( 345 + $status->getDateFrom(), 346 + $user, 347 + $time_str 348 + ) . ' - ' . phabricator_format_local_time( 349 + $status->getDateTo(), 350 + $user, 351 + $time_str 352 + ); 353 + 354 + $content[] = phutil_tag( 355 + 'div', 356 + array( 357 + 'class' => 'user-status '.$status->getTextStatus(), 358 + ), 359 + array( 360 + phutil_tag( 361 + 'div', 362 + array( 363 + 'class' => 'epoch-range' 364 + ), 365 + $epoch_range 366 + ), 367 + phutil_tag( 368 + 'div', 369 + array( 370 + 'class' => 'icon', 371 + ), 372 + '' 373 + ), 374 + phutil_tag( 375 + 'div', 376 + array( 377 + 'class' => 'description' 378 + ), 379 + $status->getTerseSummary($user) 380 + ), 381 + phutil_tag( 382 + 'div', 383 + array( 384 + 'class' => 'participant' 385 + ), 386 + $handles[$status->getUserPHID()]->getName() 387 + ) 388 + ) 389 + ); 390 + } 391 + } 392 + } 393 + 394 + return new PhutilSafeHTML(implode('', $content)); 395 + } 396 + 397 + private function getCalendarWidgetWeekTimestamps() { 398 + $user = $this->getRequest()->getUser(); 399 + $timezone = new DateTimeZone($user->getTimezoneIdentifier()); 400 + 401 + $timestamps = array(); 402 + for ($day = 0; $day < 7; $day++) { 403 + $timestamps[] = new DateTime( 404 + sprintf('today +%d days', $day), 405 + $timezone 406 + ); 407 + } 408 + 409 + return $timestamps; 298 410 } 299 411 300 412 }
+13 -5
src/applications/conpherence/query/ConpherenceThreadQuery.php
··· 141 141 $tasks = mgroup($tasks, 'getOwnerPHID'); 142 142 143 143 // statuses of everyone currently in the conpherence 144 - // until the beginning of the next work week. 145 - // NOTE: this is a bit boring on the weekends. 144 + // for a rolling one week window 145 + $start_of_week = phabricator_format_local_time( 146 + strtotime('today'), 147 + $this->getViewer(), 148 + 'U' 149 + ); 146 150 $end_of_week = phabricator_format_local_time( 147 - strtotime('Monday midnight'), 151 + strtotime('midnight +1 week'), 148 152 $this->getViewer(), 149 153 'U' 150 154 ); 151 155 $statuses = id(new PhabricatorUserStatus()) 152 156 ->loadAllWhere( 153 - 'userPHID in (%Ls) AND dateTo <= %d', 157 + 'userPHID in (%Ls) AND dateTo >= %d AND dateFrom <= %d', 154 158 $participant_phids, 159 + $start_of_week, 155 160 $end_of_week 156 161 ); 157 162 $statuses = mgroup($statuses, 'getUserPHID'); ··· 168 173 169 174 foreach ($conpherences as $phid => $conpherence) { 170 175 $participant_phids = array_keys($conpherence->getParticipants()); 176 + $statuses = array_select_keys($statuses, $participant_phids); 177 + $statuses = array_mergev($statuses); 178 + $statuses = msort($statuses, 'getDateFrom'); 171 179 $widget_data = array( 172 180 'tasks' => array_select_keys($tasks, $participant_phids), 173 - 'statuses' => array_select_keys($statuses, $participant_phids), 181 + 'statuses' => $statuses, 174 182 'files' => array_select_keys($files, $conpherence->getFilePHIDs()), 175 183 ); 176 184 $conpherence->attachWidgetData($widget_data);
+2 -2
src/applications/conpherence/view/ConpherenceTransactionView.php
··· 85 85 } 86 86 87 87 $transaction_view 88 - ->appendChild(phutil_render_tag( 88 + ->appendChild(phutil_tag( 89 89 'div', 90 90 array( 91 91 'class' => $content_class 92 92 ), 93 - $content) 93 + new PhutilSafeHTML($content)) 94 94 ); 95 95 96 96 return $transaction_view->render();
+28 -15
src/applications/differential/controller/DifferentialRevisionViewController.php
··· 408 408 ->setAnchorName('top') 409 409 ->setNavigationMarker(true); 410 410 411 - $nav = id(new DifferentialChangesetFileTreeSideNavBuilder()) 412 - ->setAnchorName('top') 413 - ->setTitle('D'.$revision->getID()) 414 - ->setBaseURI(new PhutilURI('/D'.$revision->getID())) 415 - ->build($changesets); 416 - $nav->appendChild( 417 - array( 418 - $reviewer_warning, 419 - $top_anchor, 420 - $revision_detail, 421 - $page_pane, 422 - )); 423 - 411 + $content = array( 412 + $reviewer_warning, 413 + $top_anchor, 414 + $revision_detail, 415 + $page_pane, 416 + ); 424 417 425 418 $crumbs = $this->buildApplicationCrumbs(); 426 419 $crumbs->addCrumb( 427 420 id(new PhabricatorCrumbView()) 428 421 ->setName($object_id) 429 422 ->setHref('/'.$object_id)); 430 - $nav->setCrumbs($crumbs); 423 + 424 + $prefs = $user->loadPreferences(); 425 + 426 + $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; 427 + if ($prefs->getPreference($pref_filetree)) { 428 + $collapsed = $prefs->getPreference( 429 + PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED, 430 + false); 431 + 432 + $nav = id(new DifferentialChangesetFileTreeSideNavBuilder()) 433 + ->setAnchorName('top') 434 + ->setTitle('D'.$revision->getID()) 435 + ->setBaseURI(new PhutilURI('/D'.$revision->getID())) 436 + ->setCollapsed((bool)$collapsed) 437 + ->build($changesets); 438 + $nav->appendChild($content); 439 + $nav->setCrumbs($crumbs); 440 + $content = $nav; 441 + } else { 442 + array_unshift($content, $crumbs); 443 + } 431 444 432 445 return $this->buildApplicationPage( 433 - $nav, 446 + $content, 434 447 array( 435 448 'title' => $object_id.' '.$revision->getTitle(), 436 449 ));
+9 -13
src/applications/differential/editor/DifferentialRevisionEditor.php
··· 238 238 $diff); 239 239 $adapter->setExplicitCCs($new['ccs']); 240 240 $adapter->setExplicitReviewers($new['rev']); 241 - $adapter->setForbiddenCCs($revision->getUnsubscribedPHIDs()); 241 + $adapter->setForbiddenCCs($revision->loadUnsubscribedPHIDs()); 242 242 243 243 $xscript = HeraldEngine::loadAndApplyRules($adapter); 244 244 $xscript_uri = '/herald/transcript/'.$xscript->getID().'/'; ··· 500 500 501 501 self::addCC($revision, $phid, $reason); 502 502 503 - $unsubscribed = $revision->getUnsubscribed(); 504 - if (isset($unsubscribed[$phid])) { 505 - unset($unsubscribed[$phid]); 506 - $revision->setUnsubscribed($unsubscribed); 507 - $revision->save(); 508 - } 503 + $type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER; 504 + id(new PhabricatorEdgeEditor()) 505 + ->removeEdge($revision->getPHID(), $type, $phid) 506 + ->save(); 509 507 } 510 508 511 509 public static function removeCCAndUpdateRevision( ··· 515 513 516 514 self::removeCC($revision, $phid, $reason); 517 515 518 - $unsubscribed = $revision->getUnsubscribed(); 519 - if (empty($unsubscribed[$phid])) { 520 - $unsubscribed[$phid] = true; 521 - $revision->setUnsubscribed($unsubscribed); 522 - $revision->save(); 523 - } 516 + $type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER; 517 + id(new PhabricatorEdgeEditor()) 518 + ->addEdge($revision->getPHID(), $type, $phid) 519 + ->save(); 524 520 } 525 521 526 522 public static function addCC(
+4 -3
src/applications/differential/storage/DifferentialRevision.php
··· 17 17 18 18 protected $lineCount; 19 19 protected $attached = array(); 20 - protected $unsubscribed = array(); 21 20 22 21 protected $mailKey; 23 22 protected $branchName; ··· 264 263 return idx($this->relationships, $relation, array()); 265 264 } 266 265 267 - public function getUnsubscribedPHIDs() { 268 - return array_keys($this->getUnsubscribed()); 266 + public function loadUnsubscribedPHIDs() { 267 + return PhabricatorEdgeQuery::loadDestinationPHIDs( 268 + $this->phid, 269 + PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER); 269 270 } 270 271 271 272 public function getPrimaryReviewer() {
+9
src/applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php
··· 5 5 private $title; 6 6 private $baseURI; 7 7 private $anchorName; 8 + private $collapsed = false; 8 9 9 10 public function setAnchorName($anchor_name) { 10 11 $this->anchorName = $anchor_name; ··· 30 31 return $this->title; 31 32 } 32 33 34 + public function setCollapsed($collapsed) { 35 + $this->collapsed = $collapsed; 36 + return $this; 37 + } 38 + 33 39 public function build(array $changesets) { 34 40 assert_instances_of($changesets, 'DifferentialChangeset'); 35 41 36 42 $nav = new AphrontSideNavFilterView(); 37 43 $nav->setBaseURI($this->getBaseURI()); 38 44 $nav->setFlexible(true); 45 + $nav->setCollapsed($this->collapsed); 39 46 40 47 $anchor = $this->getAnchorName(); 41 48 ··· 122 129 'class' => 'phabricator-filetree', 123 130 ), 124 131 $filetree); 132 + 133 + Javelin::initBehavior('phabricator-file-tree', array()); 125 134 126 135 $nav->addLabel(pht('Changed Files')); 127 136 $nav->addCustomBlock($filetree);
+1 -6
src/applications/differential/view/DifferentialChangesetListView.php
··· 127 127 $ref, 128 128 $changeset); 129 129 130 - $prefs = $this->user->loadPreferences(); 131 - $pref_symbols = $prefs->getPreference( 132 - PhabricatorUserPreferences::PREFERENCE_DIFFUSION_SYMBOLS); 133 130 $detail->setChangeset($changeset); 134 131 $detail->addButton($view_options); 135 - if ($pref_symbols != 'disabled') { 136 - $detail->setSymbolIndex(idx($this->symbolIndexes, $key)); 137 - } 132 + $detail->setSymbolIndex(idx($this->symbolIndexes, $key)); 138 133 $detail->setVsChangesetID(idx($this->vsMap, $changeset->getID())); 139 134 $detail->setEditable(true); 140 135
+1 -4
src/applications/diffusion/controller/DiffusionBrowseFileController.php
··· 251 251 252 252 $lang = last(explode('.', $drequest->getPath())); 253 253 254 - $prefs = $this->getRequest()->getUser()->loadPreferences(); 255 - $pref_symbols = $prefs->getPreference( 256 - PhabricatorUserPreferences::PREFERENCE_DIFFUSION_SYMBOLS); 257 - if (isset($langs[$lang]) && $pref_symbols != 'disabled') { 254 + if (isset($langs[$lang])) { 258 255 Javelin::initBehavior( 259 256 'repository-crossreference', 260 257 array(
+8 -1
src/applications/diffusion/controller/DiffusionCommitController.php
··· 327 327 'commit' => true, 328 328 )); 329 329 330 - if ($changesets) { 330 + $prefs = $user->loadPreferences(); 331 + $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; 332 + $pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED; 333 + $show_filetree = $prefs->getPreference($pref_filetree); 334 + $collapsed = $prefs->getPreference($pref_collapse); 335 + 336 + if ($changesets && $show_filetree) { 331 337 $nav = id(new DifferentialChangesetFileTreeSideNavBuilder()) 332 338 ->setAnchorName('top') 333 339 ->setTitle($short_name) 334 340 ->setBaseURI(new PhutilURI('/'.$commit_id)) 335 341 ->build($changesets) 336 342 ->setCrumbs($crumbs) 343 + ->setCollapsed((bool)$collapsed) 337 344 ->appendChild($content); 338 345 $content = $nav; 339 346 } else {
+24 -13
src/applications/directory/controller/PhabricatorDirectoryController.php
··· 79 79 $is_hide = ($tile_display == PhabricatorApplication::TILE_HIDE); 80 80 if ($is_hide) { 81 81 $show_item_id = celerity_generate_unique_node_id(); 82 - $show_tiles_id = celerity_generate_unique_node_id(); 82 + $hide_item_id = celerity_generate_unique_node_id(); 83 83 84 84 $show_item = id(new PhabricatorMenuItemView()) 85 85 ->setName(pht('Show More Applications')) ··· 90 90 $hide_item = id(new PhabricatorMenuItemView()) 91 91 ->setName(pht('Show Fewer Applications')) 92 92 ->setHref('#') 93 + ->setStyle('display: none') 94 + ->setID($hide_item_id) 93 95 ->addSigil('home-hide-applications'); 94 96 95 97 $nav->addMenuItem($show_item); 96 - $nav->addCustomBlock( 97 - hsprintf( 98 - '<div id="%s" style="display: none;">', 99 - $show_tiles_id)); 100 - 101 - Javelin::initBehavior('phabricator-home-reveal-tiles', array( 102 - 'tilesID' => $show_tiles_id, 103 - 'showID' => $show_item_id, 104 - )); 98 + $tile_ids = array($hide_item_id); 105 99 } 106 100 107 101 foreach ($tile_group as $group => $application_list) { ··· 124 118 while (count($tiles) % 3) { 125 119 $tiles[] = id(new PhabricatorApplicationLaunchView()); 126 120 } 127 - $nav->addLabel($groups[$group]); 121 + $label = id(new PhabricatorMenuItemView()) 122 + ->setType(PhabricatorMenuItemView::TYPE_LABEL) 123 + ->setName($groups[$group]); 124 + 125 + if ($is_hide) { 126 + $label->setStyle('display: none'); 127 + $label_id = celerity_generate_unique_node_id(); 128 + $label->setID($label_id); 129 + $tile_ids[] = $label_id; 130 + } 131 + 132 + $nav->addMenuItem($label); 128 133 } 129 134 135 + $group_id = celerity_generate_unique_node_id(); 136 + $tile_ids[] = $group_id; 130 137 $nav->addCustomBlock( 131 138 phutil_tag( 132 139 'div', 133 140 array( 134 141 'class' => 'application-tile-group', 142 + 'id' => $group_id, 143 + 'style' => ($is_hide ? 'display: none' : null), 135 144 ), 136 145 mpull($tiles, 'render'))); 137 146 } 138 147 139 - $is_hide = ($tile_display == PhabricatorApplication::TILE_HIDE); 140 148 if ($is_hide) { 149 + Javelin::initBehavior('phabricator-home-reveal-tiles', array( 150 + 'tileIDs' => $tile_ids, 151 + 'showID' => $show_item_id, 152 + )); 141 153 $nav->addMenuItem($hide_item); 142 - $nav->addCustomBlock(hsprintf('</div>')); 143 154 } 144 155 } 145 156
+5 -6
src/applications/files/storage/PhabricatorFile.php
··· 271 271 } 272 272 273 273 274 - public static function newFromFileDownload($uri, $name) { 274 + public static function newFromFileDownload($uri, array $params) { 275 275 $uri = new PhutilURI($uri); 276 276 277 277 $protocol = $uri->getProtocol(); ··· 286 286 287 287 $timeout = 5; 288 288 289 - $file_data = HTTPSFuture::loadContent($uri, $timeout); 290 - if ($file_data === false) { 291 - return null; 292 - } 289 + list($file_data) = id(new HTTPSFuture($uri)) 290 + ->setTimeout($timeout) 291 + ->resolvex(); 293 292 294 - return self::newFromFileData($file_data, array('name' => $name)); 293 + return self::newFromFileData($file_data, $params); 295 294 } 296 295 297 296 public static function normalizeFileName($file_name) {
-15
src/applications/macro/storage/PhabricatorFileImageMacro.php
··· 19 19 PhabricatorPHIDConstants::PHID_TYPE_MCRO); 20 20 } 21 21 22 - static public function newFromImageURI($uri, $file_name, $image_macro_name) { 23 - $file = PhabricatorFile::newFromFileDownload($uri, $file_name); 24 - 25 - if (!$file) { 26 - return null; 27 - } 28 - 29 - $image_macro = new PhabricatorFileImageMacro(); 30 - $image_macro->setName($image_macro_name); 31 - $image_macro->setFilePHID($file->getPHID()); 32 - $image_macro->save(); 33 - 34 - return $image_macro; 35 - } 36 - 37 22 public function isAutomaticallySubscribed($phid) { 38 23 return false; 39 24 }
+2 -2
src/applications/maniphest/controller/ManiphestTaskListController.php
··· 330 330 $group = $query->getParameter('group'); 331 331 $order = $query->getParameter('order'); 332 332 $is_draggable = 333 - ($group == 'priority') || 334 - ($group == 'none' && $order == 'priority'); 333 + ($order == 'priority') && 334 + ($group == 'none' || $group == 'priority'); 335 335 336 336 $lists = new AphrontNullView(); 337 337 $lists->appendChild('<div class="maniphest-group-container">');
+2 -1
src/applications/phame/controller/blog/PhameBlogEditController.php
··· 122 122 ->setName('description') 123 123 ->setValue($blog->getDescription()) 124 124 ->setID('blog-description') 125 - ->setUser($user)) 125 + ->setUser($user) 126 + ->setDisableMacros(true)) 126 127 ->appendChild( 127 128 id(new AphrontFormPolicyControl()) 128 129 ->setUser($user)
+1
src/applications/phame/controller/post/PhamePostEditController.php
··· 133 133 ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) 134 134 ->setID('post-body') 135 135 ->setUser($user) 136 + ->setDisableMacros(true) 136 137 ) 137 138 ->appendChild( 138 139 id(new AphrontFormSelectControl())
+72
src/applications/settings/panel/PhabricatorSettingsPanelDiffPreferences.php
··· 1 + <?php 2 + 3 + final class PhabricatorSettingsPanelDiffPreferences 4 + extends PhabricatorSettingsPanel { 5 + 6 + public function getPanelKey() { 7 + return 'diff'; 8 + } 9 + 10 + public function getPanelName() { 11 + return pht('Diff Preferences'); 12 + } 13 + 14 + public function getPanelGroup() { 15 + return pht('Application Settings'); 16 + } 17 + 18 + public function processRequest(AphrontRequest $request) { 19 + $user = $request->getUser(); 20 + $preferences = $user->loadPreferences(); 21 + 22 + $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; 23 + 24 + if ($request->isFormPost()) { 25 + $preferences->setPreference( 26 + $pref_filetree, 27 + $request->getInt($pref_filetree)); 28 + 29 + $preferences->save(); 30 + return id(new AphrontRedirectResponse()) 31 + ->setURI($this->getPanelURI('?saved=true')); 32 + } 33 + 34 + $form = id(new AphrontFormView()) 35 + ->setUser($user) 36 + ->appendChild( 37 + id(new AphrontFormSelectControl()) 38 + ->setLabel(pht('Show Filetree')) 39 + ->setName($pref_filetree) 40 + ->setValue($preferences->getPreference($pref_filetree)) 41 + ->setOptions( 42 + array( 43 + 0 => pht('Disable Filetree'), 44 + 1 => pht('Enable Filetree'), 45 + )) 46 + ->setCaption( 47 + pht("When looking at a revision or commit, show affected files ". 48 + "in a sidebar."))) 49 + ->appendChild( 50 + id(new AphrontFormSubmitControl()) 51 + ->setValue(pht('Save Preferences'))); 52 + 53 + $panel = new AphrontPanelView(); 54 + $panel->setHeader(pht('Diff Preferences')); 55 + $panel->appendChild($form); 56 + $panel->setNoBackground(); 57 + 58 + $error_view = null; 59 + if ($request->getBool('saved')) { 60 + $error_view = id(new AphrontErrorView()) 61 + ->setTitle(pht('Preferences Saved')) 62 + ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) 63 + ->setErrors(array(pht('Your preferences have been saved.'))); 64 + } 65 + 66 + return array( 67 + $error_view, 68 + $panel, 69 + ); 70 + } 71 + } 72 +
-15
src/applications/settings/panel/PhabricatorSettingsPanelDisplayPreferences.php
··· 24 24 $pref_editor = PhabricatorUserPreferences::PREFERENCE_EDITOR; 25 25 $pref_multiedit = PhabricatorUserPreferences::PREFERENCE_MULTIEDIT; 26 26 $pref_titles = PhabricatorUserPreferences::PREFERENCE_TITLES; 27 - $pref_symbols = 28 - PhabricatorUserPreferences::PREFERENCE_DIFFUSION_SYMBOLS; 29 27 $pref_monospaced_textareas = 30 28 PhabricatorUserPreferences::PREFERENCE_MONOSPACED_TEXTAREAS; 31 29 ··· 40 38 $preferences->setPreference( 41 39 $pref_multiedit, 42 40 $request->getStr($pref_multiedit)); 43 - $preferences->setPreference( 44 - $pref_symbols, 45 - $request->getStr($pref_symbols)); 46 41 $preferences->setPreference($pref_monospaced, $monospaced); 47 42 $preferences->setPreference( 48 43 $pref_monospaced_textareas, ··· 74 69 $font_default = PhabricatorEnv::getEnvConfig('style.monospace'); 75 70 $font_default = phutil_escape_html($font_default); 76 71 77 - $pref_symbols_value = $preferences->getPreference($pref_symbols); 78 72 $pref_monospaced_textareas_value = $preferences 79 73 ->getPreference($pref_monospaced_textareas); 80 74 if (!$pref_monospaced_textareas_value) { ··· 132 126 '<pre class="PhabricatorMonospaced">'. 133 127 phutil_escape_html($example_string). 134 128 '</pre>')) 135 - ->appendChild( 136 - id(new AphrontFormRadioButtonControl()) 137 - ->setLabel('Symbol Links') 138 - ->setName($pref_symbols) 139 - ->setValue($pref_symbols_value ? $pref_symbols_value : 'enabled') 140 - ->addButton('enabled', 'Enabled (default)', 141 - 'Use this setting to disable linking symbol names in Differential '. 142 - 'and Diffusion to their definitions. This is enabled by default.') 143 - ->addButton('disabled', 'Disabled', null)) 144 129 ->appendChild( 145 130 id(new AphrontFormRadioButtonControl()) 146 131 ->setLabel('Monospaced Textareas')
+47 -26
src/applications/settings/panel/PhabricatorSettingsPanelProfile.php
··· 46 46 $user->setTranslation($request->getStr('translation')); 47 47 48 48 $default_image = $request->getExists('default_image'); 49 + $gravatar_email = $request->getStr('gravatar'); 49 50 if ($default_image) { 50 51 $profile->setProfileImagePHID(null); 51 52 $user->setProfileImagePHID(null); 52 - } else if (!empty($_FILES['image'])) { 53 - $err = idx($_FILES['image'], 'error'); 54 - if ($err != UPLOAD_ERR_NO_FILE) { 53 + } else if (!empty($gravatar_email) || $request->getFileExists('image')) { 54 + $file = null; 55 + if (!empty($gravatar_email)) { 56 + // These steps recommended by: 57 + // https://en.gravatar.com/site/implement/hash/ 58 + $trimmed = trim($gravatar_email); 59 + $lower_cased = strtolower($trimmed); 60 + $hash = md5($lower_cased); 61 + $url = 'http://www.gravatar.com/avatar/'.($hash).'?s=200'; 62 + $file = PhabricatorFile::newFromFileDownload( 63 + $url, 64 + array( 65 + 'name' => 'gravatar', 66 + 'authorPHID' => $user->getPHID(), 67 + )); 68 + } else if ($request->getFileExists('image')) { 55 69 $file = PhabricatorFile::newFromPHPUpload( 56 70 $_FILES['image'], 57 71 array( 58 72 'authorPHID' => $user->getPHID(), 59 73 )); 60 - $okay = $file->isTransformableImage(); 61 - if ($okay) { 62 - $xformer = new PhabricatorImageTransformer(); 74 + } 75 + 76 + $okay = $file->isTransformableImage(); 77 + if ($okay) { 78 + $xformer = new PhabricatorImageTransformer(); 63 79 64 - // Generate the large picture for the profile page. 65 - $large_xformed = $xformer->executeProfileTransform( 66 - $file, 67 - $width = 280, 68 - $min_height = 140, 69 - $max_height = 420); 70 - $profile->setProfileImagePHID($large_xformed->getPHID()); 80 + // Generate the large picture for the profile page. 81 + $large_xformed = $xformer->executeProfileTransform( 82 + $file, 83 + $width = 280, 84 + $min_height = 140, 85 + $max_height = 420); 86 + $profile->setProfileImagePHID($large_xformed->getPHID()); 71 87 72 - // Generate the small picture for comments, etc. 73 - $small_xformed = $xformer->executeProfileTransform( 74 - $file, 75 - $width = 50, 76 - $min_height = 50, 77 - $max_height = 50); 78 - $user->setProfileImagePHID($small_xformed->getPHID()); 79 - } else { 80 - $e_image = 'Not Supported'; 81 - $errors[] = 82 - 'This server only supports these image formats: '. 83 - implode(', ', $supported_formats).'.'; 84 - } 88 + // Generate the small picture for comments, etc. 89 + $small_xformed = $xformer->executeProfileTransform( 90 + $file, 91 + $width = 50, 92 + $min_height = 50, 93 + $max_height = 50); 94 + $user->setProfileImagePHID($small_xformed->getPHID()); 95 + } else { 96 + $e_image = 'Not Supported'; 97 + $errors[] = 98 + 'This server only supports these image formats: '. 99 + implode(', ', $supported_formats).'.'; 85 100 } 86 101 } 87 102 ··· 190 205 ->setName('image') 191 206 ->setError($e_image) 192 207 ->setCaption('Supported formats: '.implode(', ', $supported_formats))) 208 + ->appendChild( 209 + id(new AphrontFormTextControl()) 210 + ->setLabel('Import Gravatar') 211 + ->setName('gravatar') 212 + ->setError($e_image) 213 + ->setCaption('Enter gravatar email address')) 193 214 ->appendChild( 194 215 id(new AphrontFormSubmitControl()) 195 216 ->setValue('Save')
+3 -1
src/applications/settings/storage/PhabricatorUserPreferences.php
··· 18 18 const PREFERENCE_SEARCH_SHORTCUT = 'search-shortcut'; 19 19 20 20 const PREFERENCE_DIFFUSION_VIEW = 'diffusion-view'; 21 - const PREFERENCE_DIFFUSION_SYMBOLS = 'diffusion-symbols'; 22 21 22 + const PREFERENCE_NAV_COLLAPSED = 'nav-collapsed'; 23 23 const PREFERENCE_NAV_WIDTH = 'nav-width'; 24 24 const PREFERENCE_APP_TILES = 'app-tiles'; 25 + 26 + const PREFERENCE_DIFF_FILETREE = 'diff-filetree'; 25 27 26 28 protected $userPHID; 27 29 protected $preferences = array();
+2 -8
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 153 153 PhabricatorLiskDAO $object, 154 154 PhabricatorApplicationTransaction $xaction) { 155 155 switch ($xaction->getTransactionType()) { 156 - case PhabricatorTransactions::TYPE_COMMENT: 157 - break; 158 156 case PhabricatorTransactions::TYPE_VIEW_POLICY: 159 157 $object->setViewPolicy($xaction->getNewValue()); 160 158 break; 161 159 case PhabricatorTransactions::TYPE_EDIT_POLICY: 162 160 $object->setEditPolicy($xaction->getNewValue()); 163 161 break; 164 - default: 165 - return $this->applyCustomInternalTransaction($object, $xaction); 166 162 } 163 + return $this->applyCustomInternalTransaction($object, $xaction); 167 164 } 168 165 169 166 private function applyExternalEffects( 170 167 PhabricatorLiskDAO $object, 171 168 PhabricatorApplicationTransaction $xaction) { 172 169 switch ($xaction->getTransactionType()) { 173 - case PhabricatorTransactions::TYPE_COMMENT: 174 - break; 175 170 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 176 171 $subeditor = id(new PhabricatorSubscriptionsEditor()) 177 172 ->setObject($object) ··· 179 174 ->subscribeExplicit($xaction->getNewValue()) 180 175 ->save(); 181 176 break; 182 - default: 183 - return $this->applyCustomExternalTransaction($object, $xaction); 184 177 } 178 + return $this->applyCustomExternalTransaction($object, $xaction); 185 179 } 186 180 187 181 protected function applyCustomInternalTransaction(
+1 -1
src/infrastructure/markup/rule/PhabricatorRemarkupRuleImageMacro.php
··· 34 34 if ($file) { 35 35 $src_uri = $file->getBestURI(); 36 36 $file_data = $file->getMetadata(); 37 - $height = idx($file_data,PhabricatorFile::METADATA_IMAGE_HEIGHT); 37 + $height = idx($file_data, PhabricatorFile::METADATA_IMAGE_HEIGHT); 38 38 $width = idx($file_data, PhabricatorFile::METADATA_IMAGE_WIDTH); 39 39 if ($height && $width) { 40 40 $style = sprintf(
+8
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1097 1097 'type' => 'sql', 1098 1098 'name' => $this->getPatchPath('20130127.altheraldtranscript.sql'), 1099 1099 ), 1100 + '20130201.revisionunsubscribed.php' => array( 1101 + 'type' => 'php', 1102 + 'name' => $this->getPatchPath('20130201.revisionunsubscribed.php'), 1103 + ), 1104 + '20130201.revisionunsubscribed.sql' => array( 1105 + 'type' => 'sql', 1106 + 'name' => $this->getPatchPath('20130201.revisionunsubscribed.sql'), 1107 + ), 1100 1108 ); 1101 1109 } 1102 1110
-1
src/view/form/control/AphrontFormImageControl.php
··· 15 15 array( 16 16 'type' => 'file', 17 17 'name' => $this->getName(), 18 - 'class' => 'image', 19 18 )). 20 19 '<div style="clear: both;">'. 21 20 phutil_tag(
+15 -10
src/view/form/control/PhabricatorRemarkupControl.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl { 4 - 4 + private $disableMacro = false; 5 + public function setDisableMacros($disable) { 6 + $this->disableMacro = $disable; 7 + return $this; 8 + } 5 9 protected function renderInput() { 6 10 $id = $this->getID(); 7 11 if (!$id) { ··· 48 52 ), 49 53 'table' => array( 50 54 'tip' => pht('Table'), 51 - ), 52 - array( 55 + ) 56 + ); 57 + if (!$this->disableMacro and function_exists('imagettftext')) { 58 + $actions[] = array( 53 59 'spacer' => true, 54 - ), 55 - 'meme' => array( 60 + ); 61 + $actions['meme'] = array( 56 62 'tip' => pht('Meme'), 57 - ), 58 - 'help' => array( 63 + ); 64 + } 65 + $actions['help'] = array( 59 66 'tip' => pht('Help'), 60 67 'align' => 'right', 61 68 'href' => PhabricatorEnv::getDoclink( 62 69 'article/Remarkup_Reference.html'), 63 - ), 64 - ); 70 + ); 65 71 66 72 $buttons = array(); 67 73 foreach ($actions as $action => $spec) { ··· 74 80 ''); 75 81 continue; 76 82 } 77 - 78 83 $classes = array(); 79 84 $classes[] = 'remarkup-assist-button'; 80 85 if (idx($spec, 'align') == 'right') {
+14 -3
src/view/layout/AphrontSideNavFilterView.php
··· 21 21 private $baseURI; 22 22 private $selectedFilter = false; 23 23 private $flexible; 24 + private $collapsed = false; 24 25 private $active; 25 26 private $menu; 26 27 private $crumbs; ··· 67 68 68 69 public function setFlexible($flexible) { 69 70 $this->flexible = $flexible; 71 + return $this; 72 + } 73 + 74 + public function setCollapsed($collapsed) { 75 + $this->collapsed = $collapsed; 70 76 return $this; 71 77 } 72 78 ··· 196 202 $main_id = celerity_generate_unique_node_id(); 197 203 198 204 if ($this->flexible) { 199 - $nav_classes[] = 'has-drag-nav'; 200 205 $drag_id = celerity_generate_unique_node_id(); 201 206 $flex_bar = phutil_tag( 202 207 'div', ··· 213 218 if ($this->menu->getItems()) { 214 219 $local_id = celerity_generate_unique_node_id(); 215 220 $background_id = celerity_generate_unique_node_id(); 216 - $nav_classes[] = 'has-local-nav'; 221 + 222 + if (!$this->collapsed) { 223 + $nav_classes[] = 'has-local-nav'; 224 + } 217 225 218 226 $menu_background = phutil_tag( 219 227 'div', ··· 243 251 } 244 252 245 253 if ($this->flexible) { 246 - $nav_classes[] = 'has-drag-nav'; 254 + if (!$this->collapsed) { 255 + $nav_classes[] = 'has-drag-nav'; 256 + } 247 257 248 258 Javelin::initBehavior( 249 259 'phabricator-nav', ··· 253 263 'dragID' => $drag_id, 254 264 'contentID' => $content_id, 255 265 'backgroundID' => $background_id, 266 + 'collapsed' => $this->collapsed, 256 267 )); 257 268 258 269 if ($this->active) {
-4
webroot/rsrc/css/aphront/form-view.css
··· 187 187 max-width: 400px; 188 188 } 189 189 190 - .aphront-form-control-image .image { 191 - width: 164px; 192 - } 193 - 194 190 .aphront-form-control-image span { 195 191 margin: 0px 4px 0px 2px; 196 192 }
+79
webroot/rsrc/css/application/conpherence/widget-pane.css
··· 12 12 border-color: #CCC; 13 13 border-style: solid; 14 14 background: url('/rsrc/image/texture/dust_background.jpg'); 15 + overflow-y: auto; 15 16 } 16 17 17 18 .conpherence-widget-pane .aphront-form-input { 18 19 margin: 0; 19 20 width: 100%; 20 21 } 22 + 23 + .conpherence-widget-pane .widgets-header { 24 + height: 40px; 25 + width: 127px; 26 + margin: 0px auto 0px auto; 27 + } 28 + 29 + .conpherence-widget-pane .widgets-header .sprite-conpher { 30 + display: block; 31 + width: 29px; 32 + height: 33px; 33 + margin: 4px 0px 0px 20px; 34 + float: left; 35 + clear: none; 36 + } 37 + .conpherence-widget-pane .widgets-header .first-icon { 38 + margin-left: 0px; 39 + } 40 + 41 + .conpherence-widget-pane .widgets-body { 42 + position: fixed; 43 + overflow-y: auto; 44 + top: 165px; 45 + bottom: 0px; 46 + width: 320px; 47 + } 48 + 49 + /* calendar widget */ 50 + 51 + .conpherence-widget-pane #widgets-calendar { 52 + } 53 + 54 + .conpherence-widget-pane #widgets-calendar .user-status { 55 + height: 60px; 56 + } 57 + 58 + .conpherence-widget-pane #widgets-calendar .user-status .icon { 59 + border-radius: 10px; 60 + position: relative; 61 + top: 24px; 62 + left: 12px; 63 + height: 16px; 64 + width: 16px; 65 + box-shadow: 0px 0px 1px #000; 66 + } 67 + 68 + .conpherence-widget-pane #widgets-calendar .sporadic .icon { 69 + background-color: rgb(222, 226, 232); 70 + } 71 + 72 + .conpherence-widget-pane #widgets-calendar .away .icon { 73 + background-color: rgb(102, 204, 255); 74 + } 75 + 76 + .conpherence-widget-pane #widgets-calendar .user-status .epoch-range { 77 + float: right; 78 + font-style: italic; 79 + position: relative; 80 + top: 24px; 81 + right: 8px; 82 + font-size: 11px; 83 + } 84 + 85 + .conpherence-widget-pane #widgets-calendar .user-status .description { 86 + position: relative; 87 + left: 40px; 88 + top: 0px; 89 + width: 260px; 90 + } 91 + 92 + .conpherence-widget-pane #widgets-calendar .user-status .participant { 93 + position: relative; 94 + left: 40px; 95 + top: 0px; 96 + font-style: italic; 97 + font-size: 11px; 98 + width: 260px; 99 + }
+2 -2
webroot/rsrc/css/sprite-conph.css
··· 4 4 */ 5 5 6 6 .sprite-conpher { 7 - background-image: url(/rsrc/image/sprite-conpher.png); 7 + background-image: url(/rsrc/image/sprite-conph.png); 8 8 background-repeat: no-repeat; 9 9 } 10 10 ··· 12 12 only screen and (min-device-pixel-ratio: 1.5), 13 13 only screen and (-webkit-min-device-pixel-ratio: 1.5) { 14 14 .sprite-conpher { 15 - background-image: url(/rsrc/image/sprite-conpher-X2.png); 15 + background-image: url(/rsrc/image/sprite-conph-X2.png); 16 16 background-size: 132px 132px; 17 17 } 18 18 }
+7
webroot/rsrc/js/application/conpherence/behavior-widget-pane.js
··· 16 16 for (var widget in config.widgetRegistery) { 17 17 if (widget == data.widget) { 18 18 JX.$(widget).style.display = 'block'; 19 + JX.DOM.alterClass(e.getTarget(), data.toggleClass, true); 19 20 } else { 20 21 JX.$(widget).style.display = 'none'; 22 + var cur_toggle = JX.$(widget + '-toggle'); 23 + JX.DOM.alterClass( 24 + cur_toggle, 25 + JX.Stratcom.getData(cur_toggle).toggleClass, 26 + false 27 + ); 21 28 } 22 29 } 23 30 }
+16
webroot/rsrc/js/application/core/behavior-file-tree.js
··· 1 + /** 2 + * @provides javelin-behavior-phabricator-file-tree 3 + * @requires javelin-behavior 4 + * phabricator-keyboard-shortcut 5 + * javelin-stratcom 6 + */ 7 + 8 + JX.behavior('phabricator-file-tree', function(config) { 9 + 10 + new JX.KeyboardShortcut('f', 'Toggle file tree.') 11 + .setHandler(function(manager) { 12 + JX.Stratcom.invoke('differential-filetree-toggle'); 13 + }) 14 + .register(); 15 + 16 + });
+6 -2
webroot/rsrc/js/application/core/behavior-home-reveal-tiles.js
··· 13 13 function(e) { 14 14 e.kill(); 15 15 16 - JX.DOM.show(JX.$(config.tilesID)); 16 + for (var ii = 0; ii < config.tileIDs.length; ii++) { 17 + JX.DOM.show(JX.$(config.tileIDs[ii])); 18 + } 17 19 JX.DOM.hide(JX.$(config.showID)); 18 20 }); 19 21 ··· 23 25 function(e) { 24 26 e.kill(); 25 27 26 - JX.DOM.hide(JX.$(config.tilesID)); 28 + for (var ii = 0; ii < config.tileIDs.length; ii++) { 29 + JX.DOM.hide(JX.$(config.tileIDs[ii])); 30 + } 27 31 JX.DOM.show(JX.$(config.showID)); 28 32 }); 29 33 });
+4 -1
webroot/rsrc/js/application/core/behavior-phabricator-nav.js
··· 109 109 content.style.marginLeft = ''; 110 110 } 111 111 112 - var collapsed = false; 112 + var collapsed = config.collapsed; 113 113 JX.Stratcom.listen('differential-filetree-toggle', null, function(e) { 114 114 collapsed = !collapsed; 115 115 JX.DOM.alterClass(main, 'has-local-nav', !collapsed); 116 116 JX.DOM.alterClass(main, 'has-drag-nav', !collapsed); 117 117 resetdrag(); 118 + new JX.Request('/settings/adjust/', JX.Bag) 119 + .setData({ key : 'nav-collapsed', value : (collapsed ? 1 : 0) }) 120 + .send(); 118 121 }); 119 122 120 123
-6
webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
··· 264 264 }) 265 265 .register(); 266 266 267 - new JX.KeyboardShortcut('f', 'Toggle file tree.') 268 - .setHandler(function(manager) { 269 - JX.Stratcom.invoke('differential-filetree-toggle'); 270 - }) 271 - .register(); 272 - 273 267 if (config.haunt) { 274 268 new JX.KeyboardShortcut('z', 'Cycle comment panel haunting modes.') 275 269 .setHandler(haunt)