1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-15 10:00:55 +01:00

(stable) Promote 2017 Week 22

This commit is contained in:
epriestley 2017-06-02 13:19:38 -07:00
commit 557c432794
87 changed files with 1489 additions and 1667 deletions

View file

@ -93,6 +93,7 @@ return array(
'phabricator-core-css',
'phabricator-zindex-css',
'phui-button-css',
'phui-button-simple-css',
'phui-theme-css',
'phabricator-standard-page-view',
'aphront-dialog-view-css',
@ -203,9 +204,6 @@ return array(
'javelin-behavior-differential-user-select',
'javelin-behavior-aphront-more',
'phabricator-scroll-objective',
'phabricator-scroll-objective-list',
'phabricator-diff-inline',
'phabricator-diff-changeset',
'phabricator-diff-changeset-list',

View file

@ -728,8 +728,10 @@ phutil_register_library_map(array(
'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php',
'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php',
'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php',
'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php',
'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php',
'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php',
'DiffusionHistoryView' => 'applications/diffusion/view/DiffusionHistoryView.php',
'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php',
'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php',
'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php',
@ -1393,10 +1395,6 @@ phutil_register_library_map(array(
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
'HeraldUtilityActionGroup' => 'applications/herald/action/HeraldUtilityActionGroup.php',
'Javelin' => 'infrastructure/javelin/Javelin.php',
'JavelinReactorUIExample' => 'applications/uiexample/examples/JavelinReactorUIExample.php',
'JavelinUIExample' => 'applications/uiexample/examples/JavelinUIExample.php',
'JavelinViewExampleServerView' => 'applications/uiexample/examples/JavelinViewExampleServerView.php',
'JavelinViewUIExample' => 'applications/uiexample/examples/JavelinViewUIExample.php',
'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php',
'LegalpadCreateDocumentsCapability' => 'applications/legalpad/capability/LegalpadCreateDocumentsCapability.php',
'LegalpadDAO' => 'applications/legalpad/storage/LegalpadDAO.php',
@ -1808,6 +1806,7 @@ phutil_register_library_map(array(
'PHUIUserAvailabilityView' => 'applications/calendar/view/PHUIUserAvailabilityView.php',
'PHUIWorkboardView' => 'view/phui/PHUIWorkboardView.php',
'PHUIWorkpanelView' => 'view/phui/PHUIWorkpanelView.php',
'PHUIXComponentsExample' => 'applications/uiexample/examples/PHUIXComponentsExample.php',
'PassphraseAbstractKey' => 'applications/passphrase/keys/PassphraseAbstractKey.php',
'PassphraseConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseConduitAPIMethod.php',
'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php',
@ -2144,7 +2143,6 @@ phutil_register_library_map(array(
'PhabricatorBadgesTransactionComment' => 'applications/badges/storage/PhabricatorBadgesTransactionComment.php',
'PhabricatorBadgesTransactionQuery' => 'applications/badges/query/PhabricatorBadgesTransactionQuery.php',
'PhabricatorBadgesViewController' => 'applications/badges/controller/PhabricatorBadgesViewController.php',
'PhabricatorBarePageUIExample' => 'applications/uiexample/examples/PhabricatorBarePageUIExample.php',
'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php',
'PhabricatorBaseURISetupCheck' => 'applications/config/check/PhabricatorBaseURISetupCheck.php',
'PhabricatorBcryptPasswordHasher' => 'infrastructure/util/password/PhabricatorBcryptPasswordHasher.php',
@ -2159,7 +2157,6 @@ phutil_register_library_map(array(
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
'PhabricatorBusyUIExample' => 'applications/uiexample/examples/PhabricatorBusyUIExample.php',
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php',
'PhabricatorCacheEngineExtension' => 'applications/system/engine/PhabricatorCacheEngineExtension.php',
@ -2522,6 +2519,7 @@ phutil_register_library_map(array(
'PhabricatorCustomFieldStorageQuery' => 'infrastructure/customfield/query/PhabricatorCustomFieldStorageQuery.php',
'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php',
'PhabricatorCustomLogoConfigType' => 'applications/config/custom/PhabricatorCustomLogoConfigType.php',
'PhabricatorCustomUIFooterConfigType' => 'applications/config/custom/PhabricatorCustomUIFooterConfigType.php',
'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php',
'PhabricatorDaemonBulkJobController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobController.php',
'PhabricatorDaemonBulkJobListController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobListController.php',
@ -3027,7 +3025,6 @@ phutil_register_library_map(array(
'PhabricatorLiskFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorLiskFulltextEngineExtension.php',
'PhabricatorLiskSearchEngineExtension' => 'applications/search/engineextension/PhabricatorLiskSearchEngineExtension.php',
'PhabricatorLiskSerializer' => 'infrastructure/storage/lisk/PhabricatorLiskSerializer.php',
'PhabricatorListFilterUIExample' => 'applications/uiexample/examples/PhabricatorListFilterUIExample.php',
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php',
'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php',
'PhabricatorLocaleScopeGuard' => 'infrastructure/internationalization/scope/PhabricatorLocaleScopeGuard.php',
@ -3993,7 +3990,6 @@ phutil_register_library_map(array(
'PhabricatorSlowvoteVoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteVoteController.php',
'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php',
'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php',
'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php',
'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php',
'PhabricatorSpaceEditField' => 'applications/transactions/editfield/PhabricatorSpaceEditField.php',
'PhabricatorSpacesApplication' => 'applications/spaces/application/PhabricatorSpacesApplication.php',
@ -4157,7 +4153,6 @@ phutil_register_library_map(array(
'PhabricatorTokensCurtainExtension' => 'applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php',
'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php',
'PhabricatorTokensToken' => 'applications/tokens/storage/PhabricatorTokensToken.php',
'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php',
'PhabricatorTransactionChange' => 'applications/transactions/data/PhabricatorTransactionChange.php',
'PhabricatorTransactionRemarkupChange' => 'applications/transactions/data/PhabricatorTransactionRemarkupChange.php',
'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php',
@ -5704,8 +5699,10 @@ phutil_register_library_map(array(
),
'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionHistoryController' => 'DiffusionController',
'DiffusionHistoryListView' => 'DiffusionHistoryView',
'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionHistoryTableView' => 'DiffusionView',
'DiffusionHistoryTableView' => 'DiffusionHistoryView',
'DiffusionHistoryView' => 'DiffusionView',
'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController',
'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController',
@ -6478,10 +6475,6 @@ phutil_register_library_map(array(
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
'HeraldUtilityActionGroup' => 'HeraldActionGroup',
'Javelin' => 'Phobject',
'JavelinReactorUIExample' => 'PhabricatorUIExample',
'JavelinUIExample' => 'PhabricatorUIExample',
'JavelinViewExampleServerView' => 'AphrontView',
'JavelinViewUIExample' => 'PhabricatorUIExample',
'LegalpadController' => 'PhabricatorController',
'LegalpadCreateDocumentsCapability' => 'PhabricatorPolicyCapability',
'LegalpadDAO' => 'PhabricatorLiskDAO',
@ -6946,6 +6939,7 @@ phutil_register_library_map(array(
'PHUIUserAvailabilityView' => 'AphrontTagView',
'PHUIWorkboardView' => 'AphrontTagView',
'PHUIWorkpanelView' => 'AphrontTagView',
'PHUIXComponentsExample' => 'PhabricatorUIExample',
'PassphraseAbstractKey' => 'Phobject',
'PassphraseConduitAPIMethod' => 'ConduitAPIMethod',
'PassphraseController' => 'PhabricatorController',
@ -7337,7 +7331,6 @@ phutil_register_library_map(array(
'PhabricatorBadgesTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PhabricatorBadgesTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorBadgesViewController' => 'PhabricatorBadgesProfileController',
'PhabricatorBarePageUIExample' => 'PhabricatorUIExample',
'PhabricatorBarePageView' => 'AphrontPageView',
'PhabricatorBaseURISetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorBcryptPasswordHasher' => 'PhabricatorPasswordHasher',
@ -7352,7 +7345,6 @@ phutil_register_library_map(array(
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
'PhabricatorBusyUIExample' => 'PhabricatorUIExample',
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
'PhabricatorCacheEngine' => 'Phobject',
'PhabricatorCacheEngineExtension' => 'Phobject',
@ -7779,6 +7771,7 @@ phutil_register_library_map(array(
'PhabricatorCustomFieldStorageQuery' => 'Phobject',
'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
'PhabricatorCustomLogoConfigType' => 'PhabricatorConfigOptionType',
'PhabricatorCustomUIFooterConfigType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorDaemon' => 'PhutilDaemon',
'PhabricatorDaemonBulkJobController' => 'PhabricatorDaemonController',
'PhabricatorDaemonBulkJobListController' => 'PhabricatorDaemonBulkJobController',
@ -8352,7 +8345,6 @@ phutil_register_library_map(array(
'PhabricatorLiskFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
'PhabricatorLiskSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorLiskSerializer' => 'Phobject',
'PhabricatorListFilterUIExample' => 'PhabricatorUIExample',
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase',
'PhabricatorLocaleScopeGuard' => 'Phobject',
@ -9517,7 +9509,6 @@ phutil_register_library_map(array(
'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController',
'PhabricatorSlug' => 'Phobject',
'PhabricatorSlugTestCase' => 'PhabricatorTestCase',
'PhabricatorSortTableUIExample' => 'PhabricatorUIExample',
'PhabricatorSourceCodeView' => 'AphrontView',
'PhabricatorSpaceEditField' => 'PhabricatorEditField',
'PhabricatorSpacesApplication' => 'PhabricatorApplication',
@ -9698,7 +9689,6 @@ phutil_register_library_map(array(
'PhabricatorFlaggableInterface',
'PhabricatorConduitResultInterface',
),
'PhabricatorTooltipUIExample' => 'PhabricatorUIExample',
'PhabricatorTransactionChange' => 'Phobject',
'PhabricatorTransactionRemarkupChange' => 'PhabricatorTransactionChange',
'PhabricatorTransactions' => 'Phobject',

View file

@ -103,7 +103,7 @@ final class PhabricatorAuthListController
$button = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::SIMPLE)
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->setHref($this->getApplicationURI('config/new/'))
->setIcon('fa-plus')
->setDisabled(!$can_manage)

View file

@ -0,0 +1,41 @@
<?php
final class PhabricatorCustomUIFooterConfigType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
if (!is_array($value)) {
throw new Exception(
pht(
'Footer configuration is not valid: value must be a list of '.
'items.'));
}
foreach ($value as $idx => $item) {
if (!is_array($item)) {
throw new Exception(
pht(
'Footer item with index "%s" is invalid: each item must be a '.
'dictionary describing a footer item.',
$idx));
}
try {
PhutilTypeSpec::checkMap(
$item,
array(
'name' => 'string',
'href' => 'optional string',
));
} catch (Exception $ex) {
throw new Exception(
pht(
'Footer item with index "%s" is invalid: %s',
$idx,
$ex->getMessage()));
}
}
}
}

View file

@ -46,6 +46,7 @@ final class PhabricatorUIConfigOptions
EOJSON;
$logo_type = 'custom:PhabricatorCustomLogoConfigType';
$footer_type = 'custom:PhabricatorCustomUIFooterConfigType';
return array(
$this->newOption('ui.header-color', 'enum', 'blindigo')
@ -63,7 +64,7 @@ EOJSON;
"Phabricator logo in the site header.\n\n".
" - **Wordmark**: Choose new text to display next to the logo. ".
"By default, the header displays //Phabricator//.\n\n")),
$this->newOption('ui.footer-items', 'list<wild>', array())
$this->newOption('ui.footer-items', $footer_type, array())
->setSummary(
pht(
'Allows you to add footer links on most pages.'))

View file

@ -204,7 +204,6 @@ final class DifferentialChangesetDetailView extends AphrontView {
'loaded' => $this->getLoaded(),
'undoTemplates' => hsprintf('%s', $renderer->renderUndoTemplates()),
'displayPath' => hsprintf('%s', $display_parts),
'objectiveName' => basename($display_filename),
'icon' => $display_icon,
),
'class' => $class,

View file

@ -203,15 +203,11 @@ final class DifferentialChangesetListView extends AphrontView {
$this->requireResource('aphront-tooltip-css');
$show_objectives =
PhabricatorEnv::getEnvConfig('phabricator.show-prototypes');
$this->initBehavior(
'differential-populate',
array(
'changesetViewIDs' => $ids,
'inlineURI' => $this->inlineURI,
'showObjectives' => $show_objectives,
'pht' => array(
'Open in Editor' => pht('Open in Editor'),
'Show All Context' => pht('Show All Context'),

View file

@ -26,11 +26,6 @@ final class DiffusionHistoryController extends DiffusionController {
'limit' => $pager->getPageSize() + 1,
);
if (!$request->getBool('copies')) {
$params['needDirectChanges'] = true;
$params['needChildChanges'] = true;
}
$history_results = $this->callConduitWithDiffusionRequest(
'diffusion.historyquery',
$params);
@ -39,27 +34,12 @@ final class DiffusionHistoryController extends DiffusionController {
$history = $pager->sliceResults($history);
$show_graph = !strlen($drequest->getPath());
$history_table = id(new DiffusionHistoryTableView())
->setUser($request->getUser())
$history_list = id(new DiffusionHistoryListView())
->setViewer($viewer)
->setDiffusionRequest($drequest)
->setHistory($history);
$history_table->loadRevisions();
if ($show_graph) {
$history_table->setParents($history_results['parents']);
$history_table->setIsHead(!$pager->getOffset());
$history_table->setIsTail(!$pager->getHasMorePages());
}
$history_header = $this->buildHistoryHeader($drequest);
$history_panel = id(new PHUIObjectBoxView())
->setHeader($history_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table)
->setPager($pager);
$history_list->loadRevisions();
$header = $this->buildHeader($drequest);
$crumbs = $this->buildCrumbs(
@ -70,44 +50,32 @@ final class DiffusionHistoryController extends DiffusionController {
));
$crumbs->setBorder(true);
$title = array(
pht('History'),
$repository->getDisplayName(),
);
$pager = id(new PHUIBoxView())
->addClass('mlb')
->appendChild($pager);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$history_panel,
$history_list,
$pager,
));
return $this->newPage()
->setTitle(
array(
pht('History'),
$repository->getDisplayName(),
))
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array(
$view,
));
->appendChild($view);
}
private function buildHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$tag = $this->renderCommitHashTag($drequest);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setPolicyObject($drequest->getRepository())
->addTag($tag)
->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
->setHeaderIcon('fa-clock-o');
return $header;
}
private function buildHistoryHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$browse_uri = $drequest->generateURI(
array(
'action' => 'browse',
@ -117,36 +85,18 @@ final class DiffusionHistoryController extends DiffusionController {
->setTag('a')
->setText(pht('Browse'))
->setHref($browse_uri)
->setIcon('fa-files-o');
// TODO: Sometimes we do have a change view, we need to look at the most
// recent history entry to figure it out.
$request = $this->getRequest();
if ($request->getBool('copies')) {
$branch_name = pht('Hide Copies/Branches');
$branch_uri = $request->getRequestURI()
->alter('offset', null)
->alter('copies', null);
} else {
$branch_name = pht('Show Copies/Branches');
$branch_uri = $request->getRequestURI()
->alter('offset', null)
->alter('copies', true);
}
$branch_button = id(new PHUIButtonView())
->setTag('a')
->setText($branch_name)
->setIcon('fa-code-fork')
->setHref($branch_uri);
->setIcon('fa-code');
$header = id(new PHUIHeaderView())
->setHeader(pht('History'))
->addActionLink($browse_button)
->addActionLink($branch_button);
->setUser($viewer)
->setPolicyObject($drequest->getRepository())
->addTag($tag)
->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
->setHeaderIcon('fa-clock-o')
->addActionLink($browse_button);
return $header;
}
}

View file

@ -25,6 +25,28 @@ final class DiffusionCommitListView extends AphrontView {
return $this->commits;
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
private function getRequiredHandlePHIDs() {
$phids = array();
foreach ($this->history as $item) {
$data = $item->getCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
if ($data->getCommitDetail('committerPHID')) {
$phids[$data->getCommitDetail('committerPHID')] = true;
}
}
}
return array_keys($phids);
}
private function getCommitDescription($phid) {
if ($this->commits === null) {
return pht('(Unknown Commit)');
@ -114,12 +136,10 @@ final class DiffusionCommitListView extends AphrontView {
if ($author_phid) {
$author_name = $handles[$author_phid]->renderLink();
$author_image_uri = $handles[$author_phid]->getImageURI();
$author_image_href = $handles[$author_phid]->getURI();
} else {
$author_name = $commit->getCommitData()->getAuthorName();
$author_image_uri =
celerity_get_resource_uri('/rsrc/image/people/user0.png');
$author_image_href = null;
}
$commit_tag = id(new PHUITagView())
@ -134,7 +154,6 @@ final class DiffusionCommitListView extends AphrontView {
->setDisabled($commit->isUnreachable())
->setDescription($message)
->setImageURI($author_image_uri)
->setImageHref($author_image_href)
->addByline(pht('Author: %s', $author_name))
->addIcon('none', $committed)
->addAttribute($commit_tag);

View file

@ -0,0 +1,181 @@
<?php
final class DiffusionHistoryListView extends DiffusionHistoryView {
public function render() {
$drequest = $this->getDiffusionRequest();
$viewer = $this->getUser();
$repository = $drequest->getRepository();
require_celerity_resource('diffusion-history-css');
Javelin::initBehavior('phabricator-tooltips');
$buildables = $this->loadBuildables(
mpull($this->getHistory(), 'getCommit'));
$show_revisions = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorDifferentialApplication',
$viewer);
$handles = $viewer->loadHandles($this->getRequiredHandlePHIDs());
$show_builds = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorHarbormasterApplication',
$this->getUser());
$cur_date = null;
$view = array();
foreach ($this->getHistory() as $history) {
$epoch = $history->getEpoch();
$new_date = phabricator_date($history->getEpoch(), $viewer);
if ($cur_date !== $new_date) {
$date = ucfirst(
phabricator_relative_date($history->getEpoch(), $viewer));
$header = id(new PHUIHeaderView())
->setHeader($date);
$list = id(new PHUIObjectItemListView())
->setFlush(true)
->addClass('diffusion-history-list');
$view[] = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($list);
}
if ($epoch) {
$committed = $viewer->formatShortDateTime($epoch);
} else {
$committed = null;
}
$data = $history->getCommitData();
$author_phid = $committer = $committer_phid = null;
if ($data) {
$author_phid = $data->getCommitDetail('authorPHID');
$committer_phid = $data->getCommitDetail('committerPHID');
$committer = $data->getCommitDetail('committer');
}
if ($author_phid && isset($handles[$author_phid])) {
$author_name = $handles[$author_phid]->renderLink();
$author_image = $handles[$author_phid]->getImageURI();
} else {
$author_name = self::renderName($history->getAuthorName());
$author_image =
celerity_get_resource_uri('/rsrc/image/people/user0.png');
}
$different_committer = false;
if ($committer_phid) {
$different_committer = ($committer_phid != $author_phid);
} else if ($committer != '') {
$different_committer = ($committer != $history->getAuthorName());
}
if ($different_committer) {
if ($committer_phid && isset($handles[$committer_phid])) {
$committer = $handles[$committer_phid]->renderLink();
} else {
$committer = self::renderName($committer);
}
$author_name = hsprintf('%s / %s', $author_name, $committer);
}
// We can show details once the message and change have been imported.
$partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE |
PhabricatorRepositoryCommit::IMPORTED_CHANGE;
$commit = $history->getCommit();
if ($commit && $commit->isPartiallyImported($partial_import) && $data) {
$commit_desc = $history->getSummary();
} else {
$commit_desc = phutil_tag('em', array(), pht("Importing\xE2\x80\xA6"));
}
$browse_button = $this->linkBrowse(
$history->getPath(),
array(
'commit' => $history->getCommitIdentifier(),
'branch' => $drequest->getBranch(),
'type' => $history->getFileType(),
),
true);
$diff_tag = null;
if ($show_revisions && $commit) {
$d_id = idx($this->getRevisions(), $commit->getPHID());
if ($d_id) {
$diff_tag = id(new PHUITagView())
->setName('D'.$d_id)
->setType(PHUITagView::TYPE_SHADE)
->setColor(PHUITagView::COLOR_BLUE)
->setHref('/D'.$d_id)
->addClass('diffusion-differential-tag')
->setSlimShady(true);
}
}
$build_view = null;
if ($show_builds) {
$buildable = idx($buildables, $commit->getPHID());
if ($buildable !== null) {
$status = $buildable->getBuildableStatus();
$icon = HarbormasterBuildable::getBuildableStatusIcon($status);
$color = HarbormasterBuildable::getBuildableStatusColor($status);
$name = HarbormasterBuildable::getBuildableStatusName($status);
$build_view = id(new PHUIButtonView())
->setTag('a')
->setText($name)
->setIcon($icon)
->setColor($color)
->setHref('/'.$buildable->getMonogram())
->addClass('mmr')
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->addClass('diffusion-list-build-status');
}
}
$message = null;
$commit_link = $repository->getCommitURI(
$history->getCommitIdentifier());
$commit_name = $repository->formatCommitName(
$history->getCommitIdentifier(), $local = true);
$committed = phabricator_datetime($commit->getEpoch(), $viewer);
$author_name = phutil_tag(
'strong',
array(
'class' => 'diffusion-history-author-name',
),
$author_name);
$authored = pht('%s on %s.', $author_name, $committed);
$commit_tag = id(new PHUITagView())
->setName($commit_name)
->setType(PHUITagView::TYPE_SHADE)
->setColor(PHUITagView::COLOR_INDIGO)
->setSlimShady(true);
$item = id(new PHUIObjectItemView())
->setHeader($commit_desc)
->setHref($commit_link)
->setDisabled($commit->isUnreachable())
->setDescription($message)
->setImageURI($author_image)
->addAttribute(array($commit_tag, ' ', $diff_tag)) // For Copy Pasta
->addAttribute($authored)
->setSideColumn(array(
$build_view,
$browse_button,
));
$list->addItem($item);
$cur_date = $new_date;
}
return $view;
}
}

View file

@ -1,87 +1,14 @@
<?php
final class DiffusionHistoryTableView extends DiffusionView {
private $history;
private $revisions = array();
private $handles = array();
private $isHead;
private $isTail;
private $parents;
private $filterParents;
public function setHistory(array $history) {
assert_instances_of($history, 'DiffusionPathChange');
$this->history = $history;
return $this;
}
public function loadRevisions() {
$commit_phids = array();
foreach ($this->history as $item) {
if ($item->getCommit()) {
$commit_phids[] = $item->getCommit()->getPHID();
}
}
// TODO: Get rid of this.
$this->revisions = id(new DifferentialRevision())
->loadIDsByCommitPHIDs($commit_phids);
return $this;
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
private function getRequiredHandlePHIDs() {
$phids = array();
foreach ($this->history as $item) {
$data = $item->getCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
if ($data->getCommitDetail('committerPHID')) {
$phids[$data->getCommitDetail('committerPHID')] = true;
}
}
}
return array_keys($phids);
}
public function setParents(array $parents) {
$this->parents = $parents;
return $this;
}
public function setIsHead($is_head) {
$this->isHead = $is_head;
return $this;
}
public function setIsTail($is_tail) {
$this->isTail = $is_tail;
return $this;
}
public function setFilterParents($filter_parents) {
$this->filterParents = $filter_parents;
return $this;
}
public function getFilterParents() {
return $this->filterParents;
}
final class DiffusionHistoryTableView extends DiffusionHistoryView {
public function render() {
$drequest = $this->getDiffusionRequest();
$viewer = $this->getUser();
$buildables = $this->loadBuildables(mpull($this->history, 'getCommit'));
$buildables = $this->loadBuildables(
mpull($this->getHistory(), 'getCommit'));
$has_any_build = false;
$show_revisions = PhabricatorApplication::isClassInstalledForViewer(
@ -91,14 +18,14 @@ final class DiffusionHistoryTableView extends DiffusionView {
$handles = $viewer->loadHandles($this->getRequiredHandlePHIDs());
$graph = null;
if ($this->parents) {
$parents = $this->parents;
if ($this->getParents()) {
$parents = $this->getParents();
// If we're filtering parents, remove relationships which point to
// commits that are not part of the visible graph. Otherwise, we get
// a big tree of nonsense when viewing release branches like "stable"
// versus "master".
if ($this->filterParents) {
if ($this->getFilterParents()) {
foreach ($parents as $key => $nodes) {
foreach ($nodes as $nkey => $node) {
if (empty($parents[$node])) {
@ -109,8 +36,8 @@ final class DiffusionHistoryTableView extends DiffusionView {
}
$graph = id(new PHUIDiffGraphView())
->setIsHead($this->isHead)
->setIsTail($this->isTail)
->setIsHead($this->getIsHead())
->setIsTail($this->getIsTail())
->renderGraph($parents);
}
@ -120,7 +47,7 @@ final class DiffusionHistoryTableView extends DiffusionView {
$rows = array();
$ii = 0;
foreach ($this->history as $history) {
foreach ($this->getHistory() as $history) {
$epoch = $history->getEpoch();
if ($epoch) {
@ -209,7 +136,7 @@ final class DiffusionHistoryTableView extends DiffusionView {
$build,
$audit_view,
($commit ?
self::linkRevision(idx($this->revisions, $commit->getPHID())) :
self::linkRevision(idx($this->getRevisions(), $commit->getPHID())) :
null),
$author,
$summary,

View file

@ -0,0 +1,101 @@
<?php
abstract class DiffusionHistoryView extends DiffusionView {
private $history;
private $revisions = array();
private $handles = array();
private $isHead;
private $isTail;
private $parents;
private $filterParents;
public function setHistory(array $history) {
assert_instances_of($history, 'DiffusionPathChange');
$this->history = $history;
return $this;
}
public function getHistory() {
return $this->history;
}
public function loadRevisions() {
$commit_phids = array();
foreach ($this->history as $item) {
if ($item->getCommit()) {
$commit_phids[] = $item->getCommit()->getPHID();
}
}
// TODO: Get rid of this.
$this->revisions = id(new DifferentialRevision())
->loadIDsByCommitPHIDs($commit_phids);
return $this;
}
public function getRevisions() {
return $this->revisions;
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
public function getRequiredHandlePHIDs() {
$phids = array();
foreach ($this->history as $item) {
$data = $item->getCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
if ($data->getCommitDetail('committerPHID')) {
$phids[$data->getCommitDetail('committerPHID')] = true;
}
}
}
return array_keys($phids);
}
public function setParents(array $parents) {
$this->parents = $parents;
return $this;
}
public function getParents() {
return $this->parents;
}
public function setIsHead($is_head) {
$this->isHead = $is_head;
return $this;
}
public function getIsHead() {
return $this->isHead;
}
public function setIsTail($is_tail) {
$this->isTail = $is_tail;
return $this;
}
public function getIsTail() {
return $this->isTail;
}
public function setFilterParents($filter_parents) {
$this->filterParents = $filter_parents;
return $this;
}
public function getFilterParents() {
return $this->filterParents;
}
public function render() {}
}

View file

@ -58,7 +58,10 @@ abstract class DiffusionView extends AphrontView {
id(new PHUIIconView())->setIcon('fa-history bluegrey'));
}
final public function linkBrowse($path, array $details = array()) {
final public function linkBrowse(
$path,
array $details = array(),
$button = false) {
require_celerity_resource('diffusion-icons-css');
Javelin::initBehavior('phabricator-tooltips');
@ -111,6 +114,15 @@ abstract class DiffusionView extends AphrontView {
);
}
if ($button) {
return id(new PHUIButtonView())
->setText(pht('Browse'))
->setIcon('fa-code')
->setHref($href)
->setTag('a')
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE);
}
return javelin_tag(
'a',
array(
@ -168,7 +180,7 @@ abstract class DiffusionView extends AphrontView {
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $email->getAddress(),
'align' => 'E',
'align' => 'S',
'size' => 'auto',
),
),
@ -177,30 +189,24 @@ abstract class DiffusionView extends AphrontView {
return hsprintf('%s', $name);
}
final protected function renderBuildable(HarbormasterBuildable $buildable) {
final protected function renderBuildable(
HarbormasterBuildable $buildable) {
$status = $buildable->getBuildableStatus();
Javelin::initBehavior('phabricator-tooltips');
$icon = HarbormasterBuildable::getBuildableStatusIcon($status);
$color = HarbormasterBuildable::getBuildableStatusColor($status);
$name = HarbormasterBuildable::getBuildableStatusName($status);
$icon_view = id(new PHUIIconView())
->setIcon($icon.' '.$color);
return id(new PHUIIconView())
->setIcon($icon.' '.$color)
->addSigil('has-tooltip')
->setHref('/'.$buildable->getMonogram())
->setMetadata(
array(
'tip' => $name,
));
$tooltip_view = javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array('tip' => $name),
),
$icon_view);
Javelin::initBehavior('phabricator-tooltips');
return phutil_tag(
'a',
array('href' => '/'.$buildable->getMonogram()),
$tooltip_view);
}
final protected function loadBuildables(array $commits) {

View file

@ -30,7 +30,7 @@ final class PhabricatorGuideListView extends AphrontView {
->setText(pht('Skip'))
->setTag('a')
->setHref($skip_href)
->setColor(PHUIButtonView::SIMPLE);
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE);
$list_item->setSideColumn($skip);
}
$list->addItem($list_item);

View file

@ -40,6 +40,22 @@ final class ManiphestTransaction
return parent::shouldGenerateOldValue();
}
public function shouldHideForFeed() {
// NOTE: Modular transactions don't currently support this, and it has
// very few callsites, and it's publish-time rather than display-time.
// This should probably become a supported, display-time behavior. For
// discussion, see T12787.
// Hide "alice created X, a task blocking Y." from feed because it
// will almost always appear adjacent to "alice created Y".
$is_new = $this->getMetadataValue('blocker.new');
if ($is_new) {
return true;
}
return parent::shouldHideForFeed();
}
public function getRequiredHandlePHIDs() {
$phids = parent::getRequiredHandlePHIDs();

View file

@ -17,10 +17,6 @@ final class ManiphestTaskPointsTransaction
$object->setPoints($value);
}
public function shouldHideForFeed() {
return true;
}
public function shouldHide() {
if (!ManiphestTaskPoints::getIsEnabled()) {
return true;

View file

@ -9,15 +9,6 @@ final class ManiphestTaskUnblockTransaction
return null;
}
public function shouldHideForFeed() {
// Hide "alice created X, a task blocking Y." from feed because it
// will almost always appear adjacent to "alice created Y".
$is_new = $this->getMetadataValue('blocker.new');
if ($is_new) {
return true;
}
}
public function getActionName() {
$old = $this->getOldValue();
$new = $this->getNewValue();

View file

@ -85,12 +85,12 @@ final class PhabricatorNotificationSearchEngine
$viewer = $this->requireViewer();
$image = id(new PHUIIconView())
->setIcon('fa-eye-slash');
->setIcon('fa-bell-o');
$button = id(new PHUIButtonView())
->setTag('a')
->addSigil('workflow')
->setColor(PHUIButtonView::SIMPLE)
->setColor(PHUIButtonView::GREY)
->setIcon($image)
->setText(pht('Mark All Read'));

View file

@ -18,11 +18,6 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication {
return true;
}
public function isLaunchable() {
// Try to hide this even more for now.
return false;
}
public function getBaseURI() {
return '/nuance/';
}

View file

@ -398,13 +398,36 @@ final class PhabricatorOwnersPackageQuery
}
}
// At each strength level, drop weak packages if there are also strong
// packages of the same strength.
$strength_map = igroup($matches, 'strength');
foreach ($strength_map as $strength => $package_list) {
$any_strong = false;
foreach ($package_list as $package_id => $package) {
if (!$package['weak']) {
$any_strong = true;
break;
}
}
if ($any_strong) {
foreach ($package_list as $package_id => $package) {
if ($package['weak']) {
unset($matches[$package_id]);
}
}
}
}
$matches = isort($matches, 'strength');
$matches = array_reverse($matches);
$first_id = null;
$strongest = null;
foreach ($matches as $package_id => $match) {
if ($first_id === null) {
$first_id = $package_id;
if ($strongest === null) {
$strongest = $match['strength'];
}
if ($match['strength'] === $strongest) {
continue;
}

View file

@ -297,27 +297,54 @@ final class PhabricatorOwnersPackage
// a more specific package.
if ($weak) {
foreach ($path_packages as $match => $packages) {
// Group packages by length.
$length_map = array();
foreach ($packages as $package_id => $package) {
$length_map[$package['length']][$package_id] = $package;
}
// For each path length, remove all weak packages if there are any
// strong packages of the same length. This makes sure that if there
// are one or more strong claims on a particular path, only those
// claims stand.
foreach ($length_map as $package_list) {
$any_strong = false;
foreach ($package_list as $package_id => $package) {
if (!isset($weak[$package_id])) {
$any_strong = true;
break;
}
}
if ($any_strong) {
foreach ($package_list as $package_id => $package) {
if (isset($weak[$package_id])) {
unset($packages[$package_id]);
}
}
}
}
$packages = isort($packages, 'length');
$packages = array_reverse($packages, true);
$first = null;
$best_length = null;
foreach ($packages as $package_id => $package) {
// If this is the first package we've encountered, note it and
// continue. We're iterating over the packages from longest to
// shortest match, so this package always has the strongest claim
// on the path.
if ($first === null) {
$first = $package_id;
// If this is the first package we've encountered, note its length.
// We're iterating over the packages from longest to shortest match,
// so packages of this length always have the best claim on the path.
if ($best_length === null) {
$best_length = $package['length'];
}
// If this package has the same length as the best length, its claim
// stands.
if ($package['length'] === $best_length) {
continue;
}
// If this is the first package we saw, its claim stands even if it
// is a weak package.
if ($first === $package_id) {
continue;
}
// If this is a weak package and not the first package we saw,
// If this is a weak package and does not have the best length,
// cede its claim to the stronger package.
if (isset($weak[$package_id])) {
unset($packages[$package_id]);

View file

@ -100,6 +100,95 @@ final class PhabricatorOwnersPackageTestCase extends PhabricatorTestCase {
PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths));
// Test cases where multiple packages own the same path, with various
// dominion rules.
$main_c = 'src/applications/main/main.c';
$rules = array(
// All claims strong.
array(
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
),
// All claims weak.
array(
PhabricatorOwnersPackage::DOMINION_WEAK,
PhabricatorOwnersPackage::DOMINION_WEAK,
PhabricatorOwnersPackage::DOMINION_WEAK,
),
// Mixture of strong and weak claims, strong first.
array(
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_WEAK,
),
// Mixture of strong and weak claims, weak first.
array(
PhabricatorOwnersPackage::DOMINION_WEAK,
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
),
);
foreach ($rules as $rule_idx => $rule) {
$rows = array(
array(
'id' => 1,
'excluded' => 0,
'dominion' => $rule[0],
'path' => $main_c,
),
array(
'id' => 2,
'excluded' => 0,
'dominion' => $rule[1],
'path' => $main_c,
),
array(
'id' => 3,
'excluded' => 0,
'dominion' => $rule[2],
'path' => $main_c,
),
);
$paths = array(
$main_c => $pvalue,
);
// If one or more packages have strong dominion, they should own the
// path. If not, all the packages with weak dominion should own the
// path.
$strong = array();
$weak = array();
foreach ($rule as $idx => $dominion) {
if ($dominion == PhabricatorOwnersPackage::DOMINION_STRONG) {
$strong[] = $idx + 1;
} else {
$weak[] = $idx + 1;
}
}
if ($strong) {
$expect = $strong;
} else {
$expect = $weak;
}
$expect = array_fill_keys($expect, strlen($main_c));
$actual = PhabricatorOwnersPackage::findLongestPathsPerPackage(
$rows,
$paths);
ksort($actual);
$this->assertEqual(
$expect,
$actual,
pht('Ruleset "%s" for Identical Ownership', $rule_idx));
}
}
}

View file

@ -61,6 +61,7 @@ final class PhabricatorPeopleProfileTasksController
->withStatuses($open)
->needProjectPHIDs(true)
->setLimit(100)
->setGroupBy(ManiphestTaskQuery::GROUP_PRIORITY)
->execute();
$handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);

View file

@ -98,7 +98,7 @@ final class PhameBlogSearchEngine
->setTag('a')
->setText('New Post')
->setHref($this->getApplicationURI('/post/edit/?blog='.$id))
->setColor(PHUIButtonView::SIMPLE);
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE);
$item->setSideColumn($button);
}

View file

@ -62,7 +62,19 @@ final class PholioImageReplaceTransaction
}
public function extractFilePHIDs($object, $value) {
return array($value);
$file_phids = array();
$editor = $this->getEditor();
$images = $editor->getNewImages();
foreach ($images as $image) {
if ($image->getPHID() !== $value) {
continue;
}
$file_phids[] = $image->getFilePHID();
}
return $file_phids;
}
}

View file

@ -22,10 +22,6 @@ final class PhabricatorSettingsApplication extends PhabricatorApplication {
return false;
}
public function isLaunchable() {
return false;
}
public function getRoutes() {
$panel_pattern = '(?:page/(?P<pageKey>[^/]+)/(?:(?P<formSaved>saved)/)?)?';

View file

@ -17,9 +17,14 @@ final class PhabricatorUIExampleRenderController extends PhabricatorController {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI('view/')));
foreach ($classes as $class => $obj) {
$name = $obj->getName();
$nav->addFilter($class, $name);
$groups = mgroup($classes, 'getCategory');
ksort($groups);
foreach ($groups as $group => $group_classes) {
$nav->addLabel($group);
foreach ($group_classes as $class => $obj) {
$name = $obj->getName();
$nav->addFilter($class, $name);
}
}
$selected = $nav->selectFilter($id, head_key($classes));

View file

@ -1,95 +0,0 @@
<?php
final class JavelinReactorUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Javelin Reactor');
}
public function getDescription() {
return pht('Lots of code');
}
public function renderExample() {
$rows = array();
$examples = array(
array(
pht('Reactive button only generates a stream of events'),
'ReactorButtonExample',
'phabricator-uiexample-reactor-button',
array(),
),
array(
pht('Reactive checkbox generates a boolean dynamic value'),
'ReactorCheckboxExample',
'phabricator-uiexample-reactor-checkbox',
array('checked' => true),
),
array(
pht('Reactive focus detector generates a boolean dynamic value'),
'ReactorFocusExample',
'phabricator-uiexample-reactor-focus',
array(),
),
array(
pht('Reactive input box, with normal and calmed output'),
'ReactorInputExample',
'phabricator-uiexample-reactor-input',
array('init' => 'Initial value'),
),
array(
pht('Reactive mouseover detector generates a boolean dynamic value'),
'ReactorMouseoverExample',
'phabricator-uiexample-reactor-mouseover',
array(),
),
array(
pht('Reactive radio buttons generate a string dynamic value'),
'ReactorRadioExample',
'phabricator-uiexample-reactor-radio',
array(),
),
array(
pht('Reactive select box generates a string dynamic value'),
'ReactorSelectExample',
'phabricator-uiexample-reactor-select',
array(),
),
array(
pht(
'%s makes the class of an element a string dynamic value',
'sendclass'),
'ReactorSendClassExample',
'phabricator-uiexample-reactor-sendclass',
array(),
),
array(
pht(
'%s makes some properties of an object into dynamic values',
'sendproperties'),
'ReactorSendPropertiesExample',
'phabricator-uiexample-reactor-sendproperties',
array(),
),
);
foreach ($examples as $example) {
list($desc, $name, $resource, $params) = $example;
$template = new AphrontJavelinView();
$template
->setName($name)
->setParameters($params)
->setCelerityResource($resource);
$rows[] = array($desc, $template->render());
}
$table = new AphrontTableView($rows);
$panel = new PHUIObjectBoxView();
$panel->setHeaderText(pht('Example'));
$panel->appendChild($table);
return $panel;
}
}

View file

@ -1,66 +0,0 @@
<?php
final class JavelinUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Javelin UI');
}
public function getDescription() {
return pht('Here are some Javelin UI elements that you could use.');
}
public function renderExample() {
$request = $this->getRequest();
$user = $request->getUser();
// toggle-class
$container_id = celerity_generate_unique_node_id();
$button_red_id = celerity_generate_unique_node_id();
$button_blue_id = celerity_generate_unique_node_id();
$button_red = javelin_tag(
'a',
array(
'class' => 'button',
'sigil' => 'jx-toggle-class',
'href' => '#',
'id' => $button_red_id,
'meta' => array(
'map' => array(
$container_id => 'jxui-red-border',
$button_red_id => 'jxui-active',
),
),
),
pht('Toggle Red Border'));
$button_blue = javelin_tag(
'a',
array(
'class' => 'button jxui-active',
'sigil' => 'jx-toggle-class',
'href' => '#',
'id' => $button_blue_id,
'meta' => array(
'state' => true,
'map' => array(
$container_id => 'jxui-blue-background',
$button_blue_id => 'jxui-active',
),
),
),
pht('Toggle Blue Background'));
$div = phutil_tag(
'div',
array(
'id' => $container_id,
'class' => 'jxui-example-container jxui-blue-background',
),
array($button_red, $button_blue));
return array($div);
}
}

View file

@ -1,14 +0,0 @@
<?php
final class JavelinViewExampleServerView extends AphrontView {
public function render() {
return phutil_tag(
'div',
array(
'class' => 'server-view',
),
$this->renderChildren());
}
}

View file

@ -1,45 +0,0 @@
<?php
final class JavelinViewUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Javelin Views');
}
public function getDescription() {
return pht('Mix and match client and server views.');
}
public function renderExample() {
$request = $this->getRequest();
$init = $request->getStr('init');
$parent_server_template = new JavelinViewExampleServerView();
$parent_client_template = new AphrontJavelinView();
$parent_client_template
->setName('JavelinViewExample')
->setCelerityResource('phabricator-uiexample-javelin-view');
$child_server_template = new JavelinViewExampleServerView();
$child_client_template = new AphrontJavelinView();
$child_client_template
->setName('JavelinViewExample')
->setCelerityResource('phabricator-uiexample-javelin-view');
$parent_server_template->appendChild($parent_client_template);
$parent_client_template->appendChild($child_server_template);
$child_server_template->appendChild($child_client_template);
$child_client_template->appendChild(pht('Hey, it worked.'));
$panel = new PHUIObjectBoxView();
$panel->setHeaderText(pht('Example'));
$panel->appendChild(
phutil_tag_div('ml', $parent_server_template));
return $panel;
}
}

View file

@ -3,11 +3,15 @@
final class MacroEmojiExample extends PhabricatorUIExample {
public function getName() {
return pht('Emoji Support');
return pht('Emoji');
}
public function getDescription() {
return pht('Shiny happy people holding hands');
return pht('Shiny happy people holding hands.');
}
public function getCategory() {
return pht('Catalogs');
}
public function renderExample() {

View file

@ -10,6 +10,10 @@ final class PHUIBadgeExample extends PhabricatorUIExample {
return pht('Celebrate the moments of your life.');
}
public function getCategory() {
return pht('Single Use');
}
public function renderExample() {
$badges1 = array();

View file

@ -62,11 +62,11 @@ final class PHUIBoxExample extends PhabricatorUIExample {
);
$button = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::SIMPLE)
->setIcon('fa-heart')
->setText(pht('Such Wow'))
->addClass(PHUI::MARGIN_SMALL_RIGHT);
->setTag('a')
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->setIcon('fa-heart')
->setText(pht('Such Wow'))
->addClass(PHUI::MARGIN_SMALL_RIGHT);
$badge1 = id(new PHUIBadgeMiniView())
->setIcon('fa-bug')

View file

@ -36,7 +36,7 @@ final class PHUIButtonBarExample extends PhabricatorUIExample {
foreach ($icons as $text => $icon) {
$button = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::SIMPLE)
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->setTitle($text)
->setText($text);
@ -47,7 +47,7 @@ final class PHUIButtonBarExample extends PhabricatorUIExample {
foreach ($icons as $text => $icon) {
$button = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::SIMPLE)
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->setTitle($text)
->setTooltip($text)
->setIcon($icon);

View file

@ -106,18 +106,61 @@ final class PHUIButtonExample extends PhabricatorUIExample {
$column = array();
$icons = array(
'Comment' => 'fa-comment',
'Give Token' => 'fa-trophy',
'Reverse Time' => 'fa-clock-o',
'Implode Earth' => 'fa-exclamation-triangle red',
array(
'text' => pht('Comment'),
'icon' => 'fa-comment',
),
array(
'text' => pht('Give Token'),
'icon' => 'fa-trophy',
),
array(
'text' => pht('Reverse Time'),
'icon' => 'fa-clock-o',
),
array(
'text' => pht('Implode Earth'),
'icon' => 'fa-exclamation-triangle',
),
array(
'icon' => 'fa-rocket',
),
array(
'icon' => 'fa-clipboard',
),
array(
'icon' => 'fa-upload',
),
array(
'icon' => 'fa-street-view',
),
array(
'text' => pht('Copy "Quack" to Clipboard'),
'icon' => 'fa-clipboard',
'copy' => pht('Quack'),
),
);
foreach ($icons as $text => $icon) {
$column[] = id(new PHUIButtonView())
foreach ($icons as $text => $spec) {
$button = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::GREY)
->setIcon($icon)
->setText($text)
->setIcon(idx($spec, 'icon'))
->setText(idx($spec, 'text'))
->addClass(PHUI::MARGIN_SMALL_RIGHT);
$copy = idx($spec, 'copy');
if ($copy !== null) {
Javelin::initBehavior('phabricator-clipboard-copy');
$button->addClass('clipboard-copy');
$button->addSigil('clipboard-copy');
$button->setMetadata(
array(
'text' => $copy,
));
}
$column[] = $button;
}
$layout3 = id(new AphrontMultiColumnView())
@ -129,18 +172,22 @@ final class PHUIButtonExample extends PhabricatorUIExample {
'Subscribe' => 'fa-check-circle bluegrey',
'Edit' => 'fa-pencil bluegrey',
);
$colors = array(
PHUIButtonView::SIMPLE,
$designs = array(
PHUIButtonView::BUTTONTYPE_SIMPLE,
);
$colors = array('', 'red', 'green', 'yellow');
$column = array();
foreach ($colors as $color) {
foreach ($icons as $text => $icon) {
$column[] = id(new PHUIButtonView())
->setTag('a')
->setColor($color)
->setIcon($icon)
->setText($text)
->addClass(PHUI::MARGIN_SMALL_RIGHT);
foreach ($designs as $design) {
foreach ($colors as $color) {
foreach ($icons as $text => $icon) {
$column[] = id(new PHUIButtonView())
->setTag('a')
->setButtonType($design)
->setColor($color)
->setIcon($icon)
->setText($text)
->addClass(PHUI::MARGIN_SMALL_RIGHT);
}
}
}

View file

@ -10,6 +10,10 @@ final class PHUIColorPalletteExample extends PhabricatorUIExample {
return pht('A Standard Palette of Colors for use.');
}
public function getCategory() {
return pht('Catalogs');
}
public function renderExample() {
$colors = array(

View file

@ -8,7 +8,11 @@ final class PHUIFeedStoryExample extends PhabricatorUIExample {
public function getDescription() {
return pht(
'An outlandish exaggeration of intricate tales from around the realm');
'An outlandish exaggeration of intricate tales from around the realm.');
}
public function getCategory() {
return pht('Single Use');
}
public function renderExample() {

View file

@ -12,6 +12,10 @@ final class PHUIHovercardUIExample extends PhabricatorUIExample {
phutil_tag('tt', array(), 'PHUIHovercardView'));
}
public function getCategory() {
return pht('Single Use');
}
public function renderExample() {
$request = $this->getRequest();
$user = $request->getUser();

View file

@ -10,6 +10,10 @@ final class PHUIIconExample extends PhabricatorUIExample {
return pht('Easily render icons or images with links and sprites.');
}
public function getCategory() {
return pht('Catalogs');
}
private function listTransforms() {
return array(
'ph-rotate-90',

View file

@ -0,0 +1,139 @@
<?php
final class PHUIXComponentsExample extends PhabricatorUIExample {
public function getName() {
return pht('PHUIX Components');
}
public function getDescription() {
return pht('Copy/paste to make design maintenance twice as difficult.');
}
public function getCategory() {
return pht('PHUIX');
}
public function renderExample() {
$content = array();
$icons = array(
array(
'icon' => 'fa-rocket',
),
array(
'icon' => 'fa-cloud',
'color' => 'indigo',
),
);
foreach ($icons as $spec) {
$icon = new PHUIIconView();
$icon->setIcon(idx($spec, 'icon'), idx($spec, 'color'));
$client_id = celerity_generate_unique_node_id();
$server_view = $icon;
$client_view = javelin_tag(
'div',
array(
'id' => $client_id,
));
Javelin::initBehavior(
'phuix-example',
array(
'type' => 'icon',
'id' => $client_id,
'spec' => $spec,
));
$content[] = id(new AphrontMultiColumnView())
->addColumn($server_view)
->addColumn($client_view);
}
$buttons = array(
array(
'text' => pht('Submit'),
),
array(
'text' => pht('Activate'),
'icon' => 'fa-rocket',
),
array(
'type' => PHUIButtonView::BUTTONTYPE_SIMPLE,
'text' => pht('3 / 5 Comments'),
'icon' => 'fa-comment',
),
array(
'color' => PHUIButtonView::GREEN,
'text' => pht('Environmental!'),
),
array(
'icon' => 'fa-cog',
),
array(
'icon' => 'fa-cog',
'type' => PHUIButtonView::BUTTONTYPE_SIMPLE,
),
array(
'text' => array('2 + 2', ' ', '=', ' ', '4'),
),
array(
'color' => PHUIButtonView::GREY,
'text' => pht('Cancel'),
),
array(
'text' => array('<strong />'),
),
);
foreach ($buttons as $spec) {
$button = new PHUIButtonView();
if (idx($spec, 'text') !== null) {
$button->setText($spec['text']);
}
if (idx($spec, 'icon') !== null) {
$button->setIcon($spec['icon']);
}
if (idx($spec, 'type') !== null) {
$button->setButtonType($spec['type']);
}
if (idx($spec, 'color') !== null) {
$button->setColor($spec['color']);
}
$client_id = celerity_generate_unique_node_id();
$server_view = $button;
$client_view = javelin_tag(
'div',
array(
'id' => $client_id,
));
Javelin::initBehavior(
'phuix-example',
array(
'type' => 'button',
'id' => $client_id,
'spec' => $spec,
));
$content[] = id(new AphrontMultiColumnView())
->addColumn($server_view)
->addColumn($client_view);
}
return id(new PHUIBoxView())
->appendChild($content)
->addMargin(PHUI::MARGIN_LARGE);
}
}

View file

@ -1,25 +0,0 @@
<?php
final class PhabricatorBarePageUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Bare Page');
}
public function getDescription() {
return pht('This is a bare page.');
}
public function renderExample() {
$view = new PhabricatorBarePageView();
$view->appendChild(
phutil_tag(
'h1',
array(),
$this->getDescription()));
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
}

View file

@ -1,17 +0,0 @@
<?php
final class PhabricatorBusyUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Busy');
}
public function getDescription() {
return pht('Busy.');
}
public function renderExample() {
Javelin::initBehavior('phabricator-busy-example');
return null;
}
}

View file

@ -3,13 +3,17 @@
final class PhabricatorFilesComposeAvatarExample extends PhabricatorUIExample {
public function getName() {
return pht('Generate Avatar Images');
return pht('Avatars');
}
public function getDescription() {
return pht('Tests various color palettes and sizes.');
}
public function getCategory() {
return pht('Technical');
}
public function renderExample() {
$request = $this->getRequest();
$viewer = $request->getUser();

View file

@ -14,6 +14,10 @@ final class PhabricatorGestureUIExample extends PhabricatorUIExample {
phutil_tag('tt', array(), 'touchable'));
}
public function getCategory() {
return pht('Technical');
}
public function renderExample() {
$id = celerity_generate_unique_node_id();

View file

@ -1,35 +0,0 @@
<?php
final class PhabricatorListFilterUIExample extends PhabricatorUIExample {
public function getName() {
return pht('ListFilter');
}
public function getDescription() {
return pht(
'Use %s to layout controls for filtering '.
'and manipulating lists of objects.',
phutil_tag('tt', array(), 'AphrontListFilterView'));
}
public function renderExample() {
$filter = new AphrontListFilterView();
$form = new AphrontFormView();
$form->setUser($this->getRequest()->getUser());
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Query')))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Search')));
$filter->appendChild($form);
return $filter;
}
}

View file

@ -12,6 +12,10 @@ final class PhabricatorNotificationUIExample extends PhabricatorUIExample {
phutil_tag('tt', array(), 'JX.Notification'));
}
public function getCategory() {
return pht('Technical');
}
public function renderExample() {
require_celerity_resource('phabricator-notification-css');
Javelin::initBehavior('phabricator-notification-example');

View file

@ -11,6 +11,10 @@ final class PhabricatorRemarkupUIExample extends PhabricatorUIExample {
'Demonstrates the visual appearance of various Remarkup elements.');
}
public function getCategory() {
return pht('Technical');
}
public function renderExample() {
$viewer = $this->getRequest()->getUser();

View file

@ -10,6 +10,10 @@ final class PhabricatorSetupIssueUIExample extends PhabricatorUIExample {
return pht('Setup errors and warnings.');
}
public function getCategory() {
return pht('Single Use');
}
public function renderExample() {
$request = $this->getRequest();
$user = $request->getUser();

View file

@ -1,96 +0,0 @@
<?php
final class PhabricatorSortTableUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Sortable Tables');
}
public function getDescription() {
return pht('Using sortable tables.');
}
public function renderExample() {
$rows = array(
array(
'make' => 'Honda',
'model' => 'Civic',
'year' => 2004,
'price' => 3199,
'color' => pht('Blue'),
),
array(
'make' => 'Ford',
'model' => 'Focus',
'year' => 2001,
'price' => 2549,
'color' => pht('Red'),
),
array(
'make' => 'Toyota',
'model' => 'Camry',
'year' => 2009,
'price' => 4299,
'color' => pht('Black'),
),
array(
'make' => 'NASA',
'model' => 'Shuttle',
'year' => 1998,
'price' => 1000000000,
'color' => pht('White'),
),
);
$request = $this->getRequest();
$orders = array(
'make',
'model',
'year',
'price',
);
$sort = $request->getStr('sort');
list($sort, $reverse) = AphrontTableView::parseSort($sort);
if (!in_array($sort, $orders)) {
$sort = 'make';
}
$rows = isort($rows, $sort);
if ($reverse) {
$rows = array_reverse($rows);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
pht('Make'),
pht('Model'),
pht('Year'),
pht('Price'),
pht('Color'),
));
$table->setColumnClasses(
array(
'',
'wide',
'n',
'n',
'',
));
$table->makeSortable(
$request->getRequestURI(),
'sort',
$sort,
$reverse,
$orders);
$panel = new PHUIObjectBoxView();
$panel->setHeaderText(pht('Sortable Table of Vehicles'));
$panel->setTable($table);
return $panel;
}
}

View file

@ -1,102 +0,0 @@
<?php
final class PhabricatorTooltipUIExample extends PhabricatorUIExample {
public function getName() {
return pht('Tooltips');
}
public function getDescription() {
return pht(
'Use %s to create tooltips.',
phutil_tag('tt', array(), 'JX.Tooltip'));
}
public function renderExample() {
Javelin::initBehavior('phabricator-tooltips');
require_celerity_resource('aphront-tooltip-css');
$style = 'width: 200px; '.
'text-align: center; '.
'margin: 20px; '.
'background: #dfdfdf; '.
'padding: 20px 10px; '.
'border: 1px solid black; ';
$lorem = <<<EOTEXT
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
EOTEXT;
$overflow = str_repeat('M', 1024);
$metas = array(
'hi' => array(
'tip' => 'Hi',
),
'lorem (north)' => array(
'tip' => $lorem,
),
'lorem (east)' => array(
'tip' => $lorem,
'align' => 'E',
),
'lorem (south)' => array(
'tip' => $lorem,
'align' => 'S',
),
'lorem (west)' => array(
'tip' => $lorem,
'align' => 'W',
),
'lorem (large, north)' => array(
'tip' => $lorem,
'size' => 300,
),
'lorem (large, east)' => array(
'tip' => $lorem,
'size' => 300,
'align' => 'E',
),
'lorem (large, west)' => array(
'tip' => $lorem,
'size' => 300,
'align' => 'W',
),
'lorem (large, south)' => array(
'tip' => $lorem,
'size' => 300,
'align' => 'S',
),
'overflow (north)' => array(
'tip' => $overflow,
),
'overflow (east)' => array(
'tip' => $overflow,
'align' => 'E',
),
'overflow (south)' => array(
'tip' => $overflow,
'align' => 'S',
),
'overflow (west)' => array(
'tip' => $overflow,
'align' => 'W',
),
);
$content = array();
foreach ($metas as $key => $meta) {
$content[] = javelin_tag(
'div',
array(
'sigil' => 'has-tooltip',
'meta' => $meta,
'style' => $style,
),
$key);
}
return $content;
}
}

View file

@ -17,6 +17,10 @@ abstract class PhabricatorUIExample extends Phobject {
abstract public function getDescription();
abstract public function renderExample();
public function getCategory() {
return pht('General');
}
protected function createBasicDummyHandle($name, $type, $fullname = null,
$uri = null) {

View file

@ -324,7 +324,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
javelin_tag(
'a',
array(
'class' => 'grey button dropdown has-icon policy-control',
'class' => 'grey button dropdown has-icon has-text policy-control',
'href' => '#',
'mustcapture' => true,
'sigil' => 'policy-control',

View file

@ -29,7 +29,7 @@ final class PHUIButtonBarView extends AphrontTagView {
}
protected function getTagContent() {
require_celerity_resource('phui-button-css');
require_celerity_resource('phui-button-bar-css');
$i = 1;
$j = count($this->buttons);

View file

@ -5,11 +5,13 @@ final class PHUIButtonView extends AphrontTagView {
const GREEN = 'green';
const GREY = 'grey';
const DISABLED = 'disabled';
const SIMPLE = 'simple';
const SMALL = 'small';
const BIG = 'big';
const BUTTONTYPE_DEFAULT = 'buttontype.default';
const BUTTONTYPE_SIMPLE = 'buttontype.simple';
private $size;
private $text;
private $subtext;
@ -25,6 +27,7 @@ final class PHUIButtonView extends AphrontTagView {
private $tooltip;
private $noCSS;
private $hasCaret;
private $buttonType = self::BUTTONTYPE_DEFAULT;
public function setName($name) {
$this->name = $name;
@ -103,6 +106,15 @@ final class PHUIButtonView extends AphrontTagView {
return $this->hasCaret;
}
public function setButtonType($button_type) {
$this->buttonType = $button_type;
return $this;
}
public function getButtonType() {
return $this->buttonType;
}
public function setIcon($icon, $first = true) {
if (!($icon instanceof PHUIIconView)) {
$icon = id(new PHUIIconView())
@ -141,6 +153,7 @@ final class PHUIButtonView extends AphrontTagView {
protected function getTagAttributes() {
require_celerity_resource('phui-button-css');
require_celerity_resource('phui-button-simple-css');
$classes = array();
$classes[] = 'button';
@ -161,6 +174,10 @@ final class PHUIButtonView extends AphrontTagView {
$classes[] = 'has-icon';
}
if ($this->text !== null) {
$classes[] = 'has-text';
}
if ($this->iconFirst == false) {
$classes[] = 'icon-last';
}
@ -169,6 +186,15 @@ final class PHUIButtonView extends AphrontTagView {
$classes[] = 'disabled';
}
switch ($this->getButtonType()) {
case self::BUTTONTYPE_DEFAULT:
// Nothing special for default buttons.
break;
case self::BUTTONTYPE_SIMPLE:
$classes[] = 'simple';
break;
}
$sigil = null;
$meta = null;
if ($this->tooltip) {
@ -204,10 +230,24 @@ final class PHUIButtonView extends AphrontTagView {
$subtext = null;
if ($this->subtext) {
$subtext = phutil_tag(
'div', array('class' => 'phui-button-subtext'), $this->subtext);
'div',
array(
'class' => 'phui-button-subtext',
),
$this->subtext);
}
if ($this->text !== null) {
$text = phutil_tag(
'div',
array(
'class' => 'phui-button-text',
),
array(
$text,
$subtext,
));
}
$text = phutil_tag(
'div', array('class' => 'phui-button-text'), array($text, $subtext));
}
$caret = null;

View file

@ -79,7 +79,7 @@ final class PHUIDocumentViewPro extends AphrontTagView {
$toc[] = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-align-left')
->setColor(PHUIButtonView::SIMPLE)
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->addClass('phui-document-toc')
->addSigil('jx-toggle-class')
->setMetaData(array(

View file

@ -181,4 +181,5 @@ a.jx-tokenizer-token-invalid:hover {
.button.tokenizer-browse-button .phui-icon-view {
top: 7px;
left: 9px;
position: absolute;
}

View file

@ -247,6 +247,7 @@ a.phabricator-core-user-menu .caret:before {
font-size: 15px;
top: 4px;
left: 8px;
position: absolute;
}
.phabricator-main-menu-search-dropdown .caret {

View file

@ -409,36 +409,7 @@ tr.differential-inline-loading {
color: {$greytext};
}
.scroll-objective-list {
position: fixed;
right: 0;
width: 24px;
top: 48px;
bottom: 48px;
background: rgba(255, 255, 255, 0.50);
border-style: solid;
border-color: rgba(255, 255, 255, 0.95);
border-width: 1px 0 1px 1px;
box-shadow: -1px 0 2px rgba(255, 255, 255, 0.10);
overflow: hidden;
}
.scroll-objective-list.has-aesthetic-scrollbar {
/* For now, hide this element on systems with aesthetic scrollbars. */
display: none;
}
.scroll-objective {
display: block;
position: absolute;
box-sizing: border-box;
cursor: pointer;
text-align: middle;
left: 7px;
}
.scroll-objective .phui-icon-view {
text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.25);
display: block;
height: 14px;
.diff-banner-has-unsaved,
.diff-banner-has-unsubmitted {
background: {$sh-yellowbackground};
}

View file

@ -3,7 +3,7 @@
*/
.diffusion-history-list .phui-oi-link {
color: {$darkbluetext};
color: #000;
font-size: {$biggerfontsize};
}
@ -11,6 +11,10 @@
border-color: transparent;
}
.diffusion-history-list .phui-oi-attribute .phui-tag-indigo a {
color: {$indigo};
}
.diffusion-history-message {
background-color: {$bluebackground};
padding: 16px;
@ -18,3 +22,21 @@
border-radius: 5px;
color: {$darkbluetext};
}
.diffusion-history-list .phui-oi-attribute {
font-size: {$smallerfontsize};
letter-spacing: 0.01em;
}
.diffusion-history-author-name a {
color: {$darkbluetext};
}
.diffusion-history-list .diffusion-differential-tag {
margin-left: 4px;
}
a.phui-tag-view:hover.diffusion-differential-tag .phui-tag-core {
border-color: transparent;
text-decoration: underline;
}

View file

@ -173,3 +173,16 @@ hr {
height: 2px;
background: {$sky};
}
.clipboard-copy {
visibility: hidden;
}
.supports-clipboard .clipboard-copy {
visibility: visible;
}
.clipboard-buffer {
position: absolute;
left: -9999px;
}

View file

@ -97,10 +97,6 @@ div.phui-calendar-day-event {
z-index: 6;
}
.scroll-objective-list {
z-index: 6;
}
.conpherence-durable-column {
z-index: 7;
}

View file

@ -0,0 +1,61 @@
/**
* @provides phui-button-bar-css
* @requires phui-button-css
* @requires phui-button-simple-css
*/
.phui-button-bar-borderless .button {
border: 0;
background-color: transparent;
background-image: none;
padding-left: 10px;
padding-right: 10px;
}
.phui-button-bar-borderless .button .phui-icon-view {
font-size: 15px;
color: rgba({$alphagrey},.4);
}
.phui-button-bar-borderless .button:hover {
background-color: transparent;
background-image: none;
border-radius: 3px;
}
.phui-button-bar-borderless .button:hover .phui-icon-view {
color: rgba({$alphagrey},.9);
}
.phui-button-bar-borderless .button {
border: 0;
}
.phui-button-bar .phui-button-bar-first {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
}
.phui-button-bar .phui-button-bar-middle {
border-radius: 0;
border-left: none;
}
.phui-button-bar .phui-button-bar-last {
border-left: none;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
.phui-button-bar .button.simple:hover {
border-color: {$lightblueborder};
background-color: #fff;
background-image: none;
color: {$sky};
}
.phui-button-bar .button.simple:hover .phui-icon-view {
border-color: {$lightblueborder};
color: {$sky};
background-image: none;
}

View file

@ -0,0 +1,131 @@
/**
* @provides phui-button-simple-css
* @requires phui-button-css
*/
/* - Basic -------------------------------------------------------------------*/
button.simple,
input[type="submit"].simple,
a.simple,
a.simple:visited {
background: #fff;
color: {$bluetext};
border: 1px solid {$lightblueborder};
}
button.simple .phui-icon-view,
input[type="submit"].simple .phui-icon-view,
a.simple .phui-icon-view,
a.simple:visited .phui-icon-view {
color: {$lightbluetext};
}
a.button.simple:hover,
button.simple:hover {
border-color: {$blueborder};
background-image: none;
background-color: #fff;
transition: 0s;
}
a.simple.current {
background: {$lightblue};
}
/* - Red --------------------------------------------------------------------*/
button.simple.red,
input[type="submit"].simple.red,
a.simple.red,
a.simple.red:visited {
background: {$sh-redbackground};
color: {$redtext};
border: 1px solid {$sh-redborder};
}
button.simple.red .phui-icon-view,
input[type="submit"].simple.red .phui-icon-view,
a.simple.red .phui-icon-view,
a.simple.red:visited .phui-icon-view {
color: {$redtext};
}
a.button.simple.red:hover,
button.simple.red:hover {
border-color: {$sh-redtext};
background-image: none;
background-color: {$sh-redbackground};
transition: 0s;
}
/* - Green ------------------------------------------------------------------*/
button.simple.green,
input[type="submit"].simple.green,
a.simple.green,
a.simple.green:visited {
background: {$sh-greenbackground};
color: {$greentext};
border: 1px solid {$sh-greenborder};
}
button.simple.green .phui-icon-view,
input[type="submit"].simple.green .phui-icon-view,
a.simple.green .phui-icon-view,
a.simple.green:visited .phui-icon-view {
color: {$greentext};
}
a.button.simple.green:hover,
button.simple.green:hover {
border-color: {$sh-greentext};
background-image: none;
background-color: {$sh-greenbackground};
transition: 0s;
}
/* - Yellow -----------------------------------------------------------------*/
button.simple.yellow,
input[type="submit"].simple.yellow,
a.simple.yellow,
a.simple.yellow:visited {
background-color: {$sh-yellowbackground};
color: {$sh-yellowtext};
border: 1px solid {$sh-yellowborder};
}
button.simple.yellow .phui-icon-view,
input[type="submit"].simple.yellow .phui-icon-view,
a.simple.yellow .phui-icon-view,
a.simple.yellow:visited .phui-icon-view {
color: {$sh-yellowicon};
}
a.button.simple.yellow:hover,
button.simple.yellow:hover {
border-color: {$sh-yellowtext};
background-image: none;
background-color: {$sh-yellowbackground};
transition: 0s;
}
/* - Misc -------------------------------------------------------------------*/
a.button.simple .phui-icon-view {
border: none;
}
a.button.simple.phuix-dropdown-open {
background-color: #fff;
color: {$blue};
box-shadow: none;
}
a.button.simple.phuix-dropdown-open:hover .phui-icon-view {
color: {$blue};
}

View file

@ -41,7 +41,7 @@ input[type="submit"] {
font-weight: bold;
font-size: {$normalfontsize};
display: inline-block;
padding: 4px 16px 5px;
padding: 4px 14px 5px;
text-align: center;
white-space: nowrap;
border-radius: 3px;
@ -69,8 +69,8 @@ a.icon:visited {
}
button.green,
a.green,
a.green:visited {
a.green.button,
a.green.button:visited {
background-color: {$green};
border-color: {$green};
background-image: linear-gradient(to bottom, #23BB5B, #139543);
@ -86,26 +86,6 @@ a.grey:visited {
color: {$darkgreytext};
}
button.simple,
input[type="submit"].simple,
a.simple,
a.simple:visited {
background: #fff;
color: {$bluetext};
border: 1px solid {$lightblueborder};
}
a.simple.current {
background: {$lightblue};
}
button.simple .phui-icon-view,
input[type="submit"].simple .phui-icon-view,
a.simple .phui-icon-view,
a.simple:visited .phui-icon-view {
color: {$lightbluetext};
}
a.disabled,
button.disabled,
button[disabled] {
@ -143,34 +123,6 @@ button.green:hover {
transition: 0.1s;
}
a.button.simple:hover,
button.simple:hover {
background-color: {$lightblue};
background-image: linear-gradient(to bottom, {$blue}, {$blue});
color: #fff;
transition: 0s;
}
a.button.simple:hover .phui-icon-view,
button.simple:hover .phui-icon-view {
color: #fff;
transition: 0.1s;
}
a.button.simple .phui-icon-view {
border: none;
}
a.button.simple.phuix-dropdown-open {
background-color: #fff;
color: {$blue};
box-shadow: none;
}
a.button.simple.phuix-dropdown-open:hover .phui-icon-view {
color: {$blue};
}
body a.button.disabled:hover,
body button.disabled:hover,
body a.button.disabled:active,
@ -301,7 +253,7 @@ a.policy-control .phui-button-text {
position: relative;
}
.button .phui-icon-view {
.button.has-text .phui-icon-view {
display: inline-block;
position: absolute;
top: 7px;
@ -313,10 +265,6 @@ a.policy-control .phui-button-text {
right: 10px;
}
.phui-button-bar .button .phui-icon-view {
left: 14px;
}
.button.has-icon .phui-button-text {
margin-left: 16px;
}
@ -345,66 +293,3 @@ a.policy-control .phui-button-text {
font-weight: normal;
}
/* PHUI Button Bar */
.phui-button-bar-borderless .button {
border: 0;
background-color: transparent;
background-image: none;
padding-left: 10px;
padding-right: 10px;
}
.phui-button-bar-borderless .button .phui-icon-view {
font-size: 15px;
color: rgba({$alphagrey},.4);
}
.phui-button-bar-borderless .button:hover {
background-color: transparent;
background-image: none;
border-radius: 3px;
}
.phui-button-bar-borderless .button:hover .phui-icon-view {
color: rgba({$alphagrey},.9);
}
.phui-button-bar-borderless .button {
border: 0;
}
.phui-button-bar a.button.has-icon {
display: inline-block;
height: 18px;
width: 6px;
}
.phui-button-bar .phui-button-bar-first {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
}
.phui-button-bar .phui-button-bar-middle {
border-radius: 0;
border-left: none;
}
.phui-button-bar .phui-button-bar-last {
border-left: none;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
.phui-button-bar .button.simple:hover {
border-color: {$lightblueborder};
background-color: #fff;
background-image: none;
color: {$sky};
}
.phui-button-bar .button.simple:hover .phui-icon-view {
border-color: {$lightblueborder};
color: {$sky};
background-image: none;
}

View file

@ -182,6 +182,10 @@ ul.phui-oi-list-view {
vertical-align: top;
}
.phui-oi-col2.phui-oi-side-column {
width: 200px;
}
.device-phone .phui-oi-col1,
.device-phone .phui-oi-col2 {
display: block;

View file

@ -144,7 +144,7 @@ a.phui-icon-circle.hover-red:hover .phui-icon-view {
color: {$red};
}
a.phui-icon-circle .phui-icon-view.phui-icon-circle-state-icon {
.phui-icon-circle .phui-icon-view.phui-icon-circle-state-icon {
position: absolute;
width: 14px;
height: 14px;

View file

@ -32,7 +32,6 @@ JX.install('DiffChangeset', {
this._rightID = data.right;
this._displayPath = JX.$H(data.displayPath);
this._objectiveName = data.objectiveName;
this._icon = data.icon;
this._inlines = [];
@ -62,8 +61,6 @@ JX.install('DiffChangeset', {
_displayPath: null,
_changesetList: null,
_objective: null,
_objectiveName: null,
_icon: null,
getLeftChangesetID: function() {
@ -76,23 +73,9 @@ JX.install('DiffChangeset', {
setChangesetList: function(list) {
this._changesetList = list;
var objectives = list.getObjectives();
this._objective = objectives.newObjective()
.setAnchor(this._node);
this._updateObjective();
return this;
},
_updateObjective: function() {
this._objective
.setIcon(this.getIcon())
.setColor(this.getColor())
.setTooltip(this.getObjectiveName());
},
getIcon: function() {
if (!this._visible) {
return 'fa-file-o';
@ -109,10 +92,6 @@ JX.install('DiffChangeset', {
return 'blue';
},
getObjectiveName: function() {
return this._objectiveName;
},
getChangesetList: function() {
return this._changesetList;
},
@ -501,12 +480,17 @@ JX.install('DiffChangeset', {
// diff with a large number of changes don't constantly have the text
// area scrolled off the bottom of the screen until the entire diff loads.
//
// There are two three major cases here:
// There are several major cases here:
//
// - If we're near the top of the document, never scroll.
// - If we're near the bottom of the document, always scroll.
// - Otherwise, scroll if the changes were above the midline of the
// viewport.
// - If we're near the bottom of the document, always scroll, unless
// we have an anchor.
// - Otherwise, scroll if the changes were above (or, at least,
// almost entirely above) the viewport.
//
// We don't scroll if the changes were just near the top of the viewport
// because this makes us scroll incorrectly when an anchored change is
// visible. See T12779.
var target = this._node;
@ -529,17 +513,39 @@ JX.install('DiffChangeset', {
var target_pos = JX.Vector.getPos(target);
var target_dim = JX.Vector.getDim(target);
var target_mid = (target_pos.y + (target_dim.y / 2));
var target_bot = (target_pos.y + target_dim.y);
var view_mid = (old_pos.y + (old_view.y / 2));
var above_mid = (target_mid < view_mid);
// Detect if the changeset is entirely (or, at least, almost entirely)
// above us. The height here is roughly the height of the persistent
// banner.
var above_screen = (target_bot < old_pos.y + 64);
// If we have a URL anchor and are currently nearby, stick to it
// no matter what.
var on_target = null;
if (window.location.hash) {
try {
var anchor = JX.$(window.location.hash.replace('#', ''));
if (anchor) {
var anchor_pos = JX.$V(anchor);
if ((anchor_pos.y > old_pos.y) &&
(anchor_pos.y < old_pos.y + 96)) {
on_target = anchor;
}
}
} catch (ignored) {
// If we have a bogus anchor, just ignore it.
}
}
var frame = this._getContentFrame();
JX.DOM.setContent(frame, JX.$H(response.changeset));
if (this._stabilize) {
if (!near_top) {
if (near_bot || above_mid) {
if (on_target) {
JX.DOM.scrollToPosition(old_pos.x, JX.$V(on_target).y - 60);
} else if (!near_top) {
if (near_bot || above_screen) {
// Figure out how much taller the document got.
var delta = (JX.Vector.getDocument().y - old_dim.y);
JX.DOM.scrollToPosition(old_pos.x, old_pos.y + delta);
@ -570,7 +576,6 @@ JX.install('DiffChangeset', {
JX.Stratcom.invoke('differential-inline-comment-refresh');
this._objective.show();
this._rebuildAllInlines();
JX.Stratcom.invoke('resize');
@ -695,6 +700,11 @@ JX.install('DiffChangeset', {
return null;
},
getInlines: function() {
this._rebuildAllInlines();
return this._inlines;
},
_rebuildAllInlines: function() {
var rows = JX.DOM.scry(this._node, 'tr');
for (var ii = 0; ii < rows.length; ii++) {
@ -723,11 +733,6 @@ JX.install('DiffChangeset', {
JX.DOM.appendContent(diff.parentNode, undo);
}
this._updateObjective();
for (var ii = 0; ii < this._inlines.length; ii++) {
this._inlines[ii].updateObjective();
}
JX.Stratcom.invoke('resize');
},

View file

@ -1,7 +1,6 @@
/**
* @provides phabricator-diff-changeset-list
* @requires javelin-install
* phabricator-scroll-objective-list
* @javelin
*/
@ -9,7 +8,6 @@ JX.install('DiffChangesetList', {
construct: function() {
this._changesets = [];
this._objectives = new JX.ScrollObjectiveList();
var onload = JX.bind(this, this._ifawake, this._onload);
JX.Stratcom.listen('click', 'differential-load', onload);
@ -70,7 +68,7 @@ JX.install('DiffChangesetList', {
var onrangedown = JX.bind(this, this._ifawake, this._onrangedown);
JX.Stratcom.listen(
['touchstart', 'mousedown'],
'mousedown',
['differential-changeset', 'tag:th'],
onrangedown);
@ -80,15 +78,9 @@ JX.install('DiffChangesetList', {
['differential-changeset', 'tag:th'],
onrangemove);
var onrangetouchmove = JX.bind(this, this._ifawake, this._onrangetouchmove);
JX.Stratcom.listen(
'touchmove',
null,
onrangetouchmove);
var onrangeup = JX.bind(this, this._ifawake, this._onrangeup);
JX.Stratcom.listen(
['touchend', 'mouseup'],
'mouseup',
null,
onrangeup);
},
@ -102,7 +94,6 @@ JX.install('DiffChangesetList', {
_initialized: false,
_asleep: true,
_changesets: null,
_objectives: null,
_cursorItem: null,
@ -120,7 +111,6 @@ JX.install('DiffChangesetList', {
_rangeTarget: null,
_bannerNode: null,
_showObjectives: false,
sleep: function() {
this._asleep = true;
@ -128,8 +118,6 @@ JX.install('DiffChangesetList', {
this._redrawFocus();
this._redrawSelection();
this.resetHover();
this._objectives.hide();
},
wake: function() {
@ -138,10 +126,6 @@ JX.install('DiffChangesetList', {
this._redrawFocus();
this._redrawSelection();
if (this._showObjectives) {
this._objectives.show();
}
if (this._initialized) {
return;
}
@ -198,19 +182,10 @@ JX.install('DiffChangesetList', {
this._installKey('q', label, this._onkeyhide);
},
setShowObjectives: function(show) {
this._showObjectives = show;
return this;
},
isAsleep: function() {
return this._asleep;
},
getObjectives: function() {
return this._objectives;
},
newChangesetForNode: function(node) {
var changeset = JX.DiffChangeset.getForNode(node);
@ -538,24 +513,9 @@ JX.install('DiffChangesetList', {
},
_setSelectionState: function(item, manager) {
// If we had an inline selected before, we need to update it after
// changing our selection to clear the selected state. Then, update the
// new one to add the selected state.
var old_inline = this.getSelectedInline();
this._cursorItem = item;
this._redrawSelection(manager, true);
var new_inline = this.getSelectedInline();
if (old_inline) {
old_inline.updateObjective();
}
if (new_inline) {
new_inline.updateObjective();
}
return this;
},
@ -858,6 +818,11 @@ JX.install('DiffChangesetList', {
this._redrawSelection();
this._redrawHover();
// Force a banner redraw after a resize event. Particularly, this makes
// sure the inline state updates immediately after an inline edit
// operation, even if the changeset itself has not changed.
this._bannerChangeset = null;
this._redrawBanner();
},
@ -1181,8 +1146,8 @@ JX.install('DiffChangesetList', {
},
_onrangedown: function(e) {
// NOTE: We're allowing touch events through, including "touchstart". We
// need to kill the "touchstart" event so the page doesn't scroll.
// NOTE: We're allowing "mousedown" from a touch event through so users
// can leave inlines on a single line.
if (e.isRightButton()) {
return;
}
@ -1272,31 +1237,6 @@ JX.install('DiffChangesetList', {
this._setHoverRange(this._rangeOrigin, this._rangeTarget);
},
_onrangetouchmove: function(e) {
if (!this._rangeActive) {
return;
}
// NOTE: The target of a "touchmove" event is bogus. Use dark magic to
// identify the actual target. Some day, this might move into the core
// libraries. If this doesn't work, just bail.
var target;
try {
var raw_event = e.getRawEvent();
var touch = raw_event.touches[0];
target = document.elementFromPoint(touch.clientX, touch.clientY);
} catch (ex) {
return;
}
if (!JX.DOM.isType(target, 'th')) {
return;
}
this._updateRange(target, false);
},
_onrangeup: function(e) {
if (!this._rangeActive) {
return;
@ -1343,6 +1283,43 @@ JX.install('DiffChangesetList', {
return;
}
var changesets = this._changesets;
var unsaved = [];
var unsubmitted = [];
var undone = [];
var all = [];
for (var ii = 0; ii < changesets.length; ii++) {
var inlines = changesets[ii].getInlines();
for (var jj = 0; jj < inlines.length; jj++) {
var inline = inlines[jj];
if (inline.isDeleted()) {
continue;
}
all.push(inline);
if (inline.isEditing()) {
unsaved.push(inline);
} else if (inline.isDraft()) {
unsubmitted.push(inline);
} else if (!inline.isDone()) {
undone.push(inline);
}
}
}
JX.DOM.alterClass(
node,
'diff-banner-has-unsaved',
!!unsaved.length);
JX.DOM.alterClass(
node,
'diff-banner-has-unsubmitted',
!!unsubmitted.length);
var icon = new JX.PHUIXIconView()
.setIcon(changeset.getIcon())
.getNode();

View file

@ -29,7 +29,6 @@ JX.install('DiffInline', {
_isLoading: false,
_changeset: null,
_objective: null,
_isDraft: null,
_isFixed: null,
@ -38,7 +37,6 @@ JX.install('DiffInline', {
bindToRow: function(row) {
this._row = row;
this._objective.setAnchor(this._row);
var row_data = JX.Stratcom.getData(row);
row_data.inline = this;
@ -80,11 +78,25 @@ JX.install('DiffInline', {
this.setInvisible(false);
this.updateObjective();
return this;
},
isDraft: function() {
return this._isDraft;
},
isDone: function() {
return this._isFixed;
},
isEditing: function() {
return this._isEditing;
},
isDeleted: function() {
return this._isDeleted;
},
bindToRange: function(data) {
this._displaySide = data.displaySide;
this._number = parseInt(data.number, 10);
@ -171,14 +183,6 @@ JX.install('DiffInline', {
setChangeset: function(changeset) {
this._changeset = changeset;
var objectives = changeset.getChangesetList().getObjectives();
// Create this inline's objective, but don't show it yet.
this._objective = objectives.newObjective()
.setCallback(JX.bind(this, this._onobjective))
.hide();
return this;
},
@ -188,84 +192,9 @@ JX.install('DiffInline', {
setEditing: function(editing) {
this._isEditing = editing;
this.updateObjective();
return this;
},
_onobjective: function() {
this.getChangeset().getChangesetList().selectInline(this);
},
updateObjective: function() {
var objective = this._objective;
if (this.isHidden() || this._isDeleted) {
objective.hide();
return;
}
// If this is a new comment which we aren't editing, don't show anything:
// the use started a comment or reply, then cancelled it.
if (this._isNew && !this._isEditing) {
objective.hide();
return;
}
var changeset = this.getChangeset();
if (!changeset.isVisible()) {
objective.hide();
return;
}
var pht = changeset.getChangesetList().getTranslations();
var icon = 'fa-comment';
var color = 'bluegrey';
var tooltip = this._snippet;
var anchor = this._row;
var should_stack = false;
if (this._isEditing) {
icon = 'fa-star';
color = 'pink';
tooltip = pht('Editing Comment');
// If we're editing, anchor to the row with the editor instead of the
// actual comment row (which is invisible and can have a misleading
// position).
anchor = this._row.nextSibling;
} else if (this._isDraft) {
// This inline is an unsubmitted draft.
icon = 'fa-pencil';
color = 'indigo';
} else if (this._isFixed) {
// This inline has been marked done.
icon = 'fa-check';
color = 'grey';
} else if (this._isGhost) {
icon = 'fa-comment-o';
color = 'grey';
} else if (this._replyToCommentPHID) {
icon = 'fa-reply';
should_stack = true;
}
if (changeset.getChangesetList().getSelectedInline() === this) {
// TODO: Maybe add some other kind of effect here, since we're only
// using color to show this?
color = 'yellow';
}
objective
.setAnchor(anchor)
.setIcon(icon)
.setColor(color)
.setTooltip(tooltip)
.setShouldStack(should_stack)
.show();
},
canReply: function() {
if (!this._hasAction('reply')) {
return false;
@ -316,7 +245,6 @@ JX.install('DiffInline', {
JX.Stratcom.getData(row).inline = this;
this._row = row;
this._objective.setAnchor(this._row);
this._id = null;
this._phid = null;
@ -759,8 +687,6 @@ JX.install('DiffInline', {
this.getChangeset().getChangesetList().redrawPreview();
}
this.updateObjective();
this.getChangeset().getChangesetList().redrawCursor();
this.getChangeset().getChangesetList().resetHover();

View file

@ -1,141 +0,0 @@
/**
* @provides phabricator-scroll-objective
* @requires javelin-dom
* javelin-util
* javelin-stratcom
* javelin-install
* javelin-workflow
* @javelin
*/
JX.install('ScrollObjective', {
construct : function() {
var node = this.getNode();
var onclick = JX.bind(this, this._onclick);
JX.DOM.listen(node, 'click', null, onclick);
},
members: {
_list: null,
_node: null,
_anchor: null,
_visible: false,
_callback: false,
_stack: false,
getNode: function() {
if (!this._node) {
var attributes = {
className: 'scroll-objective'
};
var content = this._getIconObject().getNode();
var node = JX.$N('div', attributes, content);
this._node = node;
}
return this._node;
},
setCallback: function(callback) {
this._callback = callback;
return this;
},
setObjectiveList: function(list) {
this._list = list;
return this;
},
_getIconObject: function() {
if (!this._iconObject) {
this._iconObject = new JX.PHUIXIconView();
}
return this._iconObject;
},
_onclick: function(e) {
(this._callback && this._callback(e));
if (e.getPrevented()) {
return;
}
e.kill();
// This is magic to account for the banner, and should probably be made
// less hard-coded.
var buffer = 48;
JX.DOM.scrollToPosition(null, JX.$V(this.getAnchor()).y - buffer);
},
setAnchor: function(node) {
this._anchor = node;
return this;
},
getAnchor: function() {
return this._anchor;
},
setIcon: function(icon) {
this._getIconObject().setIcon(icon);
return this;
},
setColor: function(color) {
this._getIconObject().setColor(color);
return this;
},
setTooltip: function(tip) {
var node = this._getIconObject().getNode();
JX.Stratcom.addSigil(node, 'has-tooltip');
JX.Stratcom.getData(node).tip = tip;
JX.Stratcom.getData(node).align = 'W';
JX.Stratcom.getData(node).size = 'auto';
return this;
},
/**
* Should this objective always stack immediately under the previous
* objective?
*
* This allows related objectives (like "comment, reply, reply") to be
* rendered in a tight sequence.
*/
setShouldStack: function(stack) {
this._stack = stack;
return this;
},
shouldStack: function() {
return this._stack;
},
show: function() {
this._visible = true;
return this;
},
hide: function() {
this._visible = false;
return this;
},
isVisible: function() {
return this._visible;
}
}
});

View file

@ -1,150 +0,0 @@
/**
* @provides phabricator-scroll-objective-list
* @requires javelin-dom
* javelin-util
* javelin-stratcom
* javelin-install
* javelin-workflow
* javelin-scrollbar
* phabricator-scroll-objective
* @javelin
*/
JX.install('ScrollObjectiveList', {
construct : function() {
this._objectives = [];
var onresize = JX.bind(this, this._dirty);
JX.Stratcom.listen('resize', null, onresize);
},
members: {
_objectives: null,
_visible: false,
_trigger: null,
newObjective: function() {
var objective = new JX.ScrollObjective()
.setObjectiveList(this);
this._objectives.push(objective);
this._getNode().appendChild(objective.getNode());
this._dirty();
return objective;
},
show: function() {
this._visible = true;
this._dirty();
return this;
},
hide: function() {
this._visible = false;
this._dirty();
return this;
},
_getNode: function() {
if (!this._node) {
var node = new JX.$N('div', {className: 'scroll-objective-list'});
this._node = node;
}
return this._node;
},
_dirty: function() {
if (this._trigger !== null) {
return;
}
this._trigger = setTimeout(JX.bind(this, this._redraw), 0);
},
_redraw: function() {
this._trigger = null;
var node = this._getNode();
var is_visible =
(this._visible) &&
(JX.Device.getDevice() == 'desktop') &&
(this._objectives.length);
if (!is_visible) {
JX.DOM.remove(node);
return;
}
document.body.appendChild(node);
// If we're on OSX without a mouse or some other system with zero-width
// trackpad-style scrollbars, adjust the display appropriately.
var aesthetic = (JX.Scrollbar.getScrollbarControlWidth() === 0);
JX.DOM.alterClass(node, 'has-aesthetic-scrollbar', aesthetic);
var d = JX.Vector.getDocument();
var list_dimensions = JX.Vector.getDim(node);
var icon_height = 16;
var list_y = (list_dimensions.y - icon_height);
var ii;
var offset;
// First, build a list of all the items we're going to show.
var items = [];
for (ii = 0; ii < this._objectives.length; ii++) {
var objective = this._objectives[ii];
var objective_node = objective.getNode();
var anchor = objective.getAnchor();
if (!anchor || !objective.isVisible()) {
JX.DOM.remove(objective_node);
continue;
}
offset = (JX.$V(anchor).y / d.y) * (list_y);
items.push({
offset: offset,
node: objective_node,
objective: objective
});
}
// Now, sort it from top to bottom.
items.sort(function(u, v) {
return u.offset - v.offset;
});
// Lay out the items in the objective list, leaving a minimum amount
// of space between them so they do not overlap.
var min = null;
for (ii = 0; ii < items.length; ii++) {
var item = items[ii];
offset = item.offset;
if (min !== null) {
if (item.objective.shouldStack()) {
offset = min;
} else {
offset = Math.max(offset, min);
}
}
min = offset + 15;
item.node.style.top = offset + 'px';
node.appendChild(item.node);
}
}
}
});

View file

@ -60,8 +60,7 @@ JX.behavior('differential-populate', function(config, statics) {
var changeset_list = new JX.DiffChangesetList()
.setTranslations(JX.phtize(config.pht))
.setInlineURI(config.inlineURI)
.setShowObjectives(config.showObjectives);
.setInlineURI(config.inlineURI);
// Install and activate the current page.
var page_id = JX.Quicksand.getCurrentPageID();

View file

@ -1,19 +0,0 @@
/**
* @provides phabricator-uiexample-javelin-view
* @requires javelin-install
* javelin-dom
* javelin-view
*/
JX.install('JavelinViewExample', {
extend: 'View',
members: {
render: function(rendered_children) {
return JX.$N(
'div',
{ className: 'client-view' },
rendered_children
);
}
}
});

View file

@ -1,38 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-button
* @requires javelin-install
* javelin-dom
* javelin-util
* javelin-dynval
* javelin-reactor-dom
*/
JX.install('ReactorButtonExample', {
extend: 'View',
members: {
render: function() {
var button = JX.$N('button', {}, 'Fun');
var clicks = JX.RDOM.clickPulses(button);
var time = JX.RDOM.time();
// function snapshot(pulses, dynval) {
// return new DynVal(
// pulses.transform(JX.bind(dynval, dynval.getValueNow)),
// dynval.getValueNow()
// );
// }
//
// Below could be...
// time.snapshot(clicks)
// clicks.snapshot(time)
var snapshot_time = new JX.DynVal(
clicks.transform(JX.bind(time, time.getValueNow)),
time.getValueNow()
);
return [button, JX.RDOM.$DT(snapshot_time)];
}
}
});

View file

@ -1,17 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-checkbox
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorCheckboxExample', {
extend: 'View',
members: {
render: function() {
var checkbox = JX.$N('input', {type: 'checkbox'});
return [checkbox, JX.RDOM.$DT(JX.RDOM.checkbox(checkbox))];
}
}
});

View file

@ -1,16 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-focus
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorFocusExample', {
extend: 'View',
members: {
render: function() {
var input = JX.$N('input');
return [input, JX.RDOM.$DT(JX.RDOM.hasFocus(input))];
}
}
});

View file

@ -1,32 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-input
* @requires javelin-install
* javelin-reactor-dom
* javelin-view-html
* javelin-view-interpreter
* javelin-view-renderer
*/
JX.install('ReactorInputExample', {
extend: 'View',
members: {
render: function() {
var html = JX.HTMLView.registerToInterpreter(new JX.ViewInterpreter());
var raw_input = JX.ViewRenderer.render(
html.input({ value: this.getAttr('init') })
);
var input = JX.RDOM.input(raw_input);
return JX.ViewRenderer.render(
html.div(
raw_input,
html.br(),
html.span(JX.RDOM.$DT(input)),
html.br(),
html.span(JX.RDOM.$DT(input.calm(500)))
)
);
}
}
});

View file

@ -1,16 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-mouseover
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorMouseoverExample', {
extend: 'View',
members: {
render: function() {
var target = JX.$N('span', 'mouseover me ');
return [target, JX.RDOM.$DT(JX.RDOM.isMouseOver(target))];
}
}
});

View file

@ -1,24 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-radio
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorRadioExample', {
extend: 'View',
members: {
render: function() {
var radio_one = JX.$N('input', {type: 'radio', name: 'n', value: 'one'});
var radio_two = JX.$N('input', {type: 'radio', name: 'n', value: 'two'});
radio_one.checked = true;
return [
radio_one,
radio_two,
JX.RDOM.$DT(JX.RDOM.radio([radio_one, radio_two]))
];
}
}
});

View file

@ -1,21 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-select
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorSelectExample', {
extend: 'View',
members: {
render: function() {
var select = JX.$N('select', {}, [
JX.$N('option', { value: 'goat' }, 'Goat'),
JX.$N('option', { value: 'bat' }, 'Bat'),
JX.$N('option', { value: 'duck' }, 'Duck')
]);
return [select, JX.RDOM.$DT(JX.RDOM.select(select))];
}
}
});

View file

@ -1,18 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-sendclass
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorSendClassExample', {
extend: 'View',
members: {
render: function() {
var input = JX.$N('input', { type: 'checkbox' });
var span = JX.$N('a', 'Hey');
JX.RDOM.sendClass(JX.RDOM.checkbox(input), span, 'disabled');
return [input, span];
}
}
});

View file

@ -1,26 +0,0 @@
/**
* @provides phabricator-uiexample-reactor-sendproperties
* @requires javelin-install
* javelin-dom
* javelin-reactor-dom
*/
JX.install('ReactorSendPropertiesExample', {
extend: 'View',
members: {
render: function() {
var color = JX.$N('input', {value: '#fff000'});
var title = JX.$N('input', {value: 'seen on hover'});
var target = JX.$N('span', 'Change my color and title');
JX.RDOM.sendProps(target, {
style: {
backgroundColor: JX.RDOM.input(color)
},
title: JX.RDOM.input(title)
});
return [color, title, target];
}
}
});

View file

@ -1,9 +0,0 @@
/**
* @provides javelin-behavior-phabricator-busy-example
* @requires phabricator-busy
* javelin-behavior
*/
JX.behavior('phabricator-busy-example', function() {
JX.Busy.start();
});

View file

@ -0,0 +1,43 @@
/**
* @provides javelin-behavior-phabricator-clipboard-copy
* @requires javelin-behavior
* javelin-dom
* javelin-stratcom
* @javelin
*/
JX.behavior('phabricator-clipboard-copy', function() {
if (!document.queryCommandSupported) {
return;
}
if (!document.queryCommandSupported('copy')) {
return;
}
JX.DOM.alterClass(document.body, 'supports-clipboard', true);
JX.Stratcom.listen('click', 'clipboard-copy', function(e) {
e.kill();
var data = e.getNodeData('clipboard-copy');
var attr = {
value: data.text || '',
className: 'clipboard-buffer'
};
var node = JX.$N('textarea', attr);
document.body.appendChild(node);
try {
node.select();
document.execCommand('copy');
} catch (ignored) {
// Ignore any errors we hit.
}
JX.DOM.remove(node);
});
});

View file

@ -0,0 +1,110 @@
/**
* @provides phuix-button-view
* @requires javelin-install
* javelin-dom
*/
JX.install('PHUIXButtonView', {
statics: {
BUTTONTYPE_DEFAULT: 'buttontype.default',
BUTTONTYPE_SIMPLE: 'buttontype.simple'
},
members: {
_node: null,
_textNode: null,
_iconView: null,
_color: null,
_buttonType: null,
setIcon: function(icon) {
this.getIconView().setIcon(icon);
return this;
},
getIconView: function() {
if (!this._iconView) {
this._iconView = new JX.PHUIXIconView();
this._redraw();
}
return this._iconView;
},
setColor: function(color) {
var node = this.getNode();
if (this._color) {
JX.DOM.alterClass(node, this._color, false);
}
this._color = color;
JX.DOM.alterClass(node, this._color, true);
return this;
},
setButtonType: function(button_type) {
var self = JX.PHUIXButtonView;
this._buttonType = button_type;
var node = this.getNode();
var is_simple = (this._buttonType == self.BUTTONTYPE_SIMPLE);
JX.DOM.alterClass(node, 'simple', is_simple);
return this;
},
setText: function(text) {
JX.DOM.setContent(this._getTextNode(), text);
return this;
},
getNode: function() {
if (!this._node) {
var attrs = {
className: 'button'
};
this._node = JX.$N('button', attrs);
this._redraw();
}
return this._node;
},
_getTextNode: function() {
if (!this._textNode) {
var attrs = {
className: 'phui-button-text'
};
this._textNode = JX.$N('div', attrs);
}
return this._textNode;
},
_redraw: function() {
var node = this.getNode();
var icon = this._iconView;
var text = this._textNode;
var content = [];
if (icon) {
content.push(icon.getNode());
}
if (text) {
content.push(text);
}
JX.DOM.alterClass(node, 'has-icon', !!icon);
JX.DOM.alterClass(node, 'has-text', !!text);
JX.DOM.setContent(node, content);
}
}
});

View file

@ -0,0 +1,65 @@
/**
* @provides javelin-behavior-phuix-example
* @requires javelin-install
* javelin-dom
* phuix-button-view
*/
JX.behavior('phuix-example', function(config) {
var node;
var spec;
var defaults;
switch (config.type) {
case 'button':
var button = new JX.PHUIXButtonView();
defaults = {
text: null,
icon: null,
type: null,
color: null
};
spec = JX.copy(defaults, config.spec);
if (spec.text !== null) {
button.setText(spec.text);
}
if (spec.icon !== null) {
button.setIcon(spec.icon);
}
if (spec.type !== null) {
button.setButtonType(spec.type);
}
if (spec.color !== null) {
button.setColor(spec.color);
}
node = button.getNode();
break;
case 'icon':
var icon = new JX.PHUIXIconView();
defaults = {
icon: null,
color: null
};
spec = JX.copy(defaults, config.spec);
if (spec.icon !== null) {
icon.setIcon(spec.icon);
}
if (spec.color !== null) {
icon.setColor(spec.color);
}
node = icon.getNode();
break;
}
JX.DOM.setContent(JX.$(config.id), node);
});