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

Allow pages to use new "flexible" nav

Summary:
This allows the nav to be laid out with divs instead of tables and for the navigation column to be made flexible. Design is non-final, this is just a step toward reactive menus that work on tablets/phones and an application menu.

I'm going to play around with flexible nav and document navigation and see if that goes anywhere.

Test Plan: Will attach screenshots.

Reviewers: btrahan, vrana, chad

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1569

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

+296 -13
+30
src/__celerity_resource_map__.php
··· 35 35 'disk' => '/rsrc/image/credit_cards.png', 36 36 'type' => 'png', 37 37 ), 38 + '/rsrc/image/divot.png' => 39 + array( 40 + 'hash' => '3be267bd11ea375bf68e808893718e0e', 41 + 'uri' => '/res/3be267bd/rsrc/image/divot.png', 42 + 'disk' => '/rsrc/image/divot.png', 43 + 'type' => 'png', 44 + ), 38 45 '/rsrc/image/glyph_sprite.png' => 39 46 array( 40 47 'hash' => '0a1ea7c048be9f0b76ab2c807a9a1c0d', ··· 1402 1409 ), 1403 1410 'disk' => '/rsrc/js/application/core/behavior-keyboard-shortcuts.js', 1404 1411 ), 1412 + 'javelin-behavior-phabricator-nav' => 1413 + array( 1414 + 'uri' => '/res/adaae8ae/rsrc/js/application/core/behavior-phabricator-nav.js', 1415 + 'type' => 'js', 1416 + 'requires' => 1417 + array( 1418 + 0 => 'javelin-behavior', 1419 + 1 => 'javelin-stratcom', 1420 + 2 => 'javelin-dom', 1421 + 3 => 'javelin-magical-init', 1422 + 4 => 'javelin-vector', 1423 + ), 1424 + 'disk' => '/rsrc/js/application/core/behavior-phabricator-nav.js', 1425 + ), 1405 1426 'javelin-behavior-phabricator-notification-example' => 1406 1427 array( 1407 1428 'uri' => '/res/df97e4b3/rsrc/js/application/uiexample/notification-example.js', ··· 2284 2305 1 => 'javelin-dom', 2285 2306 ), 2286 2307 'disk' => '/rsrc/js/application/core/DropdownMenuItem.js', 2308 + ), 2309 + 'phabricator-nav-view-css' => 2310 + array( 2311 + 'uri' => '/res/3443576d/rsrc/css/aphront/phabricator-nav-view.css', 2312 + 'type' => 'css', 2313 + 'requires' => 2314 + array( 2315 + ), 2316 + 'disk' => '/rsrc/css/aphront/phabricator-nav-view.css', 2287 2317 ), 2288 2318 'phabricator-notification' => 2289 2319 array(
+14
src/view/layout/AphrontSideNavFilterView.php
··· 40 40 private $items = array(); 41 41 private $baseURI; 42 42 private $selectedFilter = false; 43 + private $flexNav; 44 + private $flexible; 45 + 46 + public function setFlexNav($flex_nav) { 47 + $this->flexNav = $flex_nav; 48 + return $this; 49 + } 50 + 51 + public function setFlexible($flexible) { 52 + $this->flexible = $flexible; 53 + return $this; 54 + } 43 55 44 56 public function addFilter($key, $name, $uri = null, $relative = false) { 45 57 $this->items[] = array( ··· 102 114 } 103 115 104 116 $view = new AphrontSideNavView(); 117 + $view->setFlexNav($this->flexNav); 118 + $view->setFlexible($this->flexible); 105 119 foreach ($this->items as $item) { 106 120 list($type, $key, $name) = $item; 107 121 switch ($type) {
+72 -13
src/view/layout/AphrontSideNavView.php
··· 1 1 <?php 2 2 3 3 /* 4 - * Copyright 2011 Facebook, Inc. 4 + * Copyright 2012 Facebook, Inc. 5 5 * 6 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 7 * you may not use this file except in compliance with the License. ··· 19 19 final class AphrontSideNavView extends AphrontView { 20 20 21 21 protected $items = array(); 22 + protected $flexNav; 23 + protected $isFlexible; 22 24 23 25 public function addNavItem($item) { 24 26 $this->items[] = $item; 25 27 return $this; 26 28 } 27 29 30 + public function setFlexNav($flex) { 31 + $this->flexNav = $flex; 32 + return $this; 33 + } 34 + 35 + public function setFlexible($flexible) { 36 + $this->flexible = $flexible; 37 + return $this; 38 + } 39 + 28 40 public function render() { 29 41 $view = new AphrontNullView(); 30 42 $view->appendChild($this->items); 31 43 32 - require_celerity_resource('aphront-side-nav-view-css'); 44 + if ($this->flexNav) { 45 + require_celerity_resource('phabricator-nav-view-css'); 46 + 47 + $nav_id = celerity_generate_unique_node_id(); 48 + $drag_id = celerity_generate_unique_node_id(); 49 + $content_id = celerity_generate_unique_node_id(); 50 + 51 + if ($this->flexible) { 52 + Javelin::initBehavior( 53 + 'phabricator-nav', 54 + array( 55 + 'navID' => $nav_id, 56 + 'dragID' => $drag_id, 57 + 'contentID' => $content_id, 58 + )); 59 + $flex_bar = phutil_render_tag( 60 + 'div', 61 + array( 62 + 'class' => 'phabricator-nav-drag', 63 + 'id' => $drag_id, 64 + ), 65 + ''); 66 + } else { 67 + $flex_bar = null; 68 + } 69 + 70 + return 71 + '<div class="phabricator-nav">'. 72 + phutil_render_tag( 73 + 'div', 74 + array( 75 + 'class' => 'phabricator-nav-col', 76 + 'id' => $nav_id, 77 + ), 78 + $view->render()). 79 + $flex_bar. 80 + phutil_render_tag( 81 + 'div', 82 + array( 83 + 'class' => 'phabricator-nav-content', 84 + 'id' => $content_id, 85 + ), 86 + $this->renderChildren()). 87 + '</div>'; 88 + } else { 33 89 34 - return 35 - '<table class="aphront-side-nav-view">'. 36 - '<tr>'. 37 - '<th class="aphront-side-nav-navigation">'. 38 - $view->render(). 39 - '</th>'. 40 - '<td class="aphront-side-nav-content">'. 41 - $this->renderChildren(). 42 - '</td>'. 43 - '</tr>'. 44 - '</table>'; 90 + require_celerity_resource('aphront-side-nav-view-css'); 91 + 92 + return 93 + '<table class="aphront-side-nav-view">'. 94 + '<tr>'. 95 + '<th class="aphront-side-nav-navigation">'. 96 + $view->render(). 97 + '</th>'. 98 + '<td class="aphront-side-nav-content">'. 99 + $this->renderChildren(). 100 + '</td>'. 101 + '</tr>'. 102 + '</table>'; 103 + } 45 104 } 46 105 47 106 }
+83
webroot/rsrc/css/aphront/phabricator-nav-view.css
··· 1 + /** 2 + * @provides phabricator-nav-view-css 3 + */ 4 + 5 + .jx-drag-col { 6 + cursor: col-resize; 7 + } 8 + 9 + .phabricator-nav-col { 10 + position: fixed; 11 + top: 44px; 12 + left: 0; 13 + bottom: 0; 14 + width: 179px; 15 + 16 + background: #e3e3e3; 17 + border-right: 1px solid #999c9e; 18 + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.20); 19 + 20 + overflow-y: auto; 21 + overflow-x: hidden; 22 + 23 + white-space: nowrap; 24 + } 25 + 26 + .phabricator-nav-drag { 27 + position: fixed; 28 + top: 44px; 29 + left: 177px; 30 + width: 7px; 31 + bottom: 0; 32 + z-index: 5; 33 + 34 + cursor: col-resize; 35 + background: #f5f5f5; 36 + border-style: solid; 37 + border-width: 0 1px 0 1px; 38 + border-color: #fff #999c9e #fff #999c9e; 39 + 40 + box-shadow: inset -1px 0px 2px rgba(0, 0, 0, 0.15); 41 + 42 + background-image: url(/rsrc/image/divot.png); 43 + background-position: center; 44 + background-repeat: no-repeat; 45 + } 46 + 47 + .device-tablet .phabricator-nav-drag, 48 + .device-phone .phabricator-nav-drag { 49 + display: none; 50 + } 51 + 52 + .phabricator-nav-col a, 53 + .phabricator-nav-col span { 54 + display: block; 55 + } 56 + 57 + .phabricator-nav-content { 58 + margin-left: 180px; 59 + } 60 + 61 + 62 + .phabricator-nav-col span { 63 + display: block; 64 + font-weight: bold; 65 + padding: 6px 6px 6px 12px; 66 + color: #222222; 67 + } 68 + 69 + .phabricator-nav-col a { 70 + display: block; 71 + padding: 3px 6px 3px 24px; 72 + font-weight: bold; 73 + text-decoration: none; 74 + } 75 + 76 + .phabricator-nav-col a.aphront-side-nav-selected { 77 + background: #a1bbe5; 78 + } 79 + 80 + .phabricator-nav-col a:hover { 81 + background: #3875d7; 82 + color: #ffffff; 83 + }
webroot/rsrc/image/divot.png

This is a binary file and will not be displayed.

+97
webroot/rsrc/js/application/core/behavior-phabricator-nav.js
··· 1 + /** 2 + * @provides javelin-behavior-phabricator-nav 3 + * @requires javelin-behavior 4 + * javelin-stratcom 5 + * javelin-dom 6 + * javelin-magical-init 7 + * javelin-vector 8 + * @javelin 9 + */ 10 + 11 + JX.behavior('phabricator-nav', function(config) { 12 + 13 + var dragging; 14 + var track; 15 + 16 + var nav = JX.$(config.navID); 17 + var drag = JX.$(config.dragID); 18 + var content = JX.$(config.contentID); 19 + 20 + JX.enableDispatch(document.body, 'mousemove'); 21 + 22 + JX.DOM.listen(drag, 'mousedown', null, function(e) { 23 + dragging = JX.$V(e); 24 + 25 + // Show the "col-resize" cursor on the whole document while we're 26 + // dragging, since the mouse will slip off the actual bar fairly often and 27 + // we don't want it to flicker. 28 + JX.DOM.alterClass(document.body, 'jx-drag-col', true); 29 + 30 + track = [ 31 + { 32 + element: nav, 33 + parameter: 'width', 34 + start: JX.Vector.getDim(nav).x, 35 + scale: 1, 36 + 37 + width: JX.Vector.getDim(nav).x, 38 + minWidth: 150, 39 + minScale: 1 40 + }, 41 + { 42 + element: drag, 43 + parameter: 'left', 44 + start: JX.$V(drag).x, 45 + scale: 1 46 + }, 47 + { 48 + element: content, 49 + parameter: 'marginLeft', 50 + start: parseInt(getComputedStyle(content).marginLeft, 10), 51 + scale: 1, 52 + 53 + width: JX.Vector.getDim(content).x, 54 + minWidth: 300, 55 + minScale: -1 56 + } 57 + ]; 58 + 59 + e.kill(); 60 + }); 61 + 62 + JX.Stratcom.listen('mousemove', null, function(e) { 63 + if (!dragging) { 64 + return; 65 + } 66 + 67 + var dx = JX.$V(e).x - dragging.x; 68 + var panel; 69 + 70 + for (var k = 0; k < track.length; k++) { 71 + panel = track[k]; 72 + if (!panel.minWidth) { 73 + continue; 74 + } 75 + var new_width = panel.width + (dx * panel.minScale); 76 + if (new_width < panel.minWidth) { 77 + dx = (panel.minWidth - panel.width) * panel.minScale; 78 + } 79 + } 80 + 81 + for (var k = 0; k < track.length; k++) { 82 + panel = track[k]; 83 + var v = (panel.start + (dx * panel.scale)); 84 + panel.element.style[panel.parameter] = v + 'px'; 85 + } 86 + }); 87 + 88 + JX.Stratcom.listen('mouseup', null, function(e) { 89 + if (!dragging) { 90 + return; 91 + } 92 + 93 + JX.DOM.alterClass(document.body, 'jx-drag-col', false); 94 + dragging = false; 95 + }); 96 + 97 + });