2011-01-16 22:51:39 +01:00
|
|
|
<?php
|
|
|
|
|
2012-10-16 19:33:47 +02:00
|
|
|
/**
|
|
|
|
* This is a standard Phabricator page with menus, Javelin, DarkConsole, and
|
|
|
|
* basic styles.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
2011-01-16 22:51:39 +01:00
|
|
|
|
|
|
|
private $baseURI;
|
|
|
|
private $applicationName;
|
|
|
|
private $glyph;
|
2012-07-31 15:18:38 +02:00
|
|
|
private $menuContent;
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
private $showChrome = true;
|
2011-07-09 18:45:19 +02:00
|
|
|
private $disableConsole;
|
2012-06-14 02:28:21 +02:00
|
|
|
private $pageObjects = array();
|
2012-12-07 22:34:44 +01:00
|
|
|
private $applicationMenu;
|
|
|
|
|
2013-06-05 17:41:43 +02:00
|
|
|
public function setApplicationMenu(PHUIListView $application_menu) {
|
2012-12-07 22:34:44 +01:00
|
|
|
$this->applicationMenu = $application_menu;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationMenu() {
|
|
|
|
return $this->applicationMenu;
|
|
|
|
}
|
2011-01-16 22:51:39 +01:00
|
|
|
|
|
|
|
public function setApplicationName($application_name) {
|
|
|
|
$this->applicationName = $application_name;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-07-09 18:45:19 +02:00
|
|
|
public function setDisableConsole($disable) {
|
|
|
|
$this->disableConsole = $disable;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
public function getApplicationName() {
|
|
|
|
return $this->applicationName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setBaseURI($base_uri) {
|
|
|
|
$this->baseURI = $base_uri;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBaseURI() {
|
|
|
|
return $this->baseURI;
|
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
public function setShowChrome($show_chrome) {
|
|
|
|
$this->showChrome = $show_chrome;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getShowChrome() {
|
|
|
|
return $this->showChrome;
|
|
|
|
}
|
|
|
|
|
2012-06-14 02:28:21 +02:00
|
|
|
public function appendPageObjects(array $objs) {
|
|
|
|
foreach ($objs as $obj) {
|
|
|
|
$this->pageObjects[] = $obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
public function getTitle() {
|
2011-03-31 04:21:09 +02:00
|
|
|
$use_glyph = true;
|
2013-05-15 17:38:56 +02:00
|
|
|
|
2011-03-31 04:21:09 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
|
|
|
if ($user && $user->loadPreferences()->getPreference(
|
|
|
|
PhabricatorUserPreferences::PREFERENCE_TITLES) !== 'glyph') {
|
|
|
|
$use_glyph = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 17:38:56 +02:00
|
|
|
$title = parent::getTitle();
|
|
|
|
|
|
|
|
$prefix = null;
|
|
|
|
if ($use_glyph) {
|
|
|
|
$prefix = $this->getGlyph();
|
|
|
|
} else {
|
|
|
|
$application_name = $this->getApplicationName();
|
|
|
|
if (strlen($application_name)) {
|
|
|
|
$prefix = '['.$application_name.']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen($prefix)) {
|
|
|
|
$title = $prefix.' '.$title;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $title;
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
2011-01-25 20:31:40 +01:00
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
protected function willRenderPage() {
|
2012-10-16 19:33:47 +02:00
|
|
|
parent::willRenderPage();
|
2011-02-02 22:48:52 +01:00
|
|
|
|
|
|
|
if (!$this->getRequest()) {
|
|
|
|
throw new Exception(
|
2013-03-02 00:37:32 +01:00
|
|
|
pht(
|
2014-06-09 20:36:49 +02:00
|
|
|
'You must set the Request to render a PhabricatorStandardPageView.'));
|
2011-02-02 22:48:52 +01:00
|
|
|
}
|
|
|
|
|
2011-07-09 18:45:19 +02:00
|
|
|
$console = $this->getConsole();
|
2011-02-02 22:48:52 +01:00
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
require_celerity_resource('phabricator-core-css');
|
2012-12-30 18:30:21 +01:00
|
|
|
require_celerity_resource('phabricator-zindex-css');
|
2013-06-13 03:23:35 +02:00
|
|
|
require_celerity_resource('phui-button-css');
|
|
|
|
require_celerity_resource('phui-spacing-css');
|
|
|
|
require_celerity_resource('phui-form-css');
|
2012-12-07 22:35:49 +01:00
|
|
|
require_celerity_resource('sprite-gradient-css');
|
2011-01-25 20:31:40 +01:00
|
|
|
require_celerity_resource('phabricator-standard-page-view');
|
|
|
|
|
2012-11-20 02:05:10 +01:00
|
|
|
Javelin::initBehavior('workflow', array());
|
|
|
|
|
Prevent CSRF uploads via /file/dropupload/
Summary:
We don't currently validate CSRF tokens on this workflow. This allows an
attacker to upload arbitrary files on the user's behalf. Although I believe the
tight list of servable mime-types means that's more or less the end of the
attack, this is still a vulnerability.
In the long term, the right solution is probably to pass CSRF tokens on all Ajax
requests in an HTTP header (or just a GET param) or something like that.
However, this endpoint is unique and this is the quickest and most direct way to
close the hole.
Test Plan:
- Drop-uploaded files to Files, Maniphest, Phriction and Differential.
- Modified CSRF vaidator to use __csrf__.'x' and verified uploads and form
submissions don't work.
Reviewers: andrewjcg, aran, jungejason, tuomaspelkonen, erling
Commenters: andrewjcg, pedram
CC: aran, epriestley, andrewjcg, pedram
Differential Revision: 758
2011-08-02 05:23:01 +02:00
|
|
|
$request = $this->getRequest();
|
2013-01-29 03:12:09 +01:00
|
|
|
$user = null;
|
Prevent CSRF uploads via /file/dropupload/
Summary:
We don't currently validate CSRF tokens on this workflow. This allows an
attacker to upload arbitrary files on the user's behalf. Although I believe the
tight list of servable mime-types means that's more or less the end of the
attack, this is still a vulnerability.
In the long term, the right solution is probably to pass CSRF tokens on all Ajax
requests in an HTTP header (or just a GET param) or something like that.
However, this endpoint is unique and this is the quickest and most direct way to
close the hole.
Test Plan:
- Drop-uploaded files to Files, Maniphest, Phriction and Differential.
- Modified CSRF vaidator to use __csrf__.'x' and verified uploads and form
submissions don't work.
Reviewers: andrewjcg, aran, jungejason, tuomaspelkonen, erling
Commenters: andrewjcg, pedram
CC: aran, epriestley, andrewjcg, pedram
Differential Revision: 758
2011-08-02 05:23:01 +02:00
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
|
|
|
}
|
|
|
|
|
2013-01-29 03:12:09 +01:00
|
|
|
if ($user) {
|
|
|
|
$default_img_uri =
|
2014-07-25 00:19:52 +02:00
|
|
|
celerity_get_resource_uri(
|
|
|
|
'rsrc/image/icon/fatcow/document_black.png');
|
2013-01-30 20:30:38 +01:00
|
|
|
$download_form = phabricator_form(
|
2013-01-29 03:12:09 +01:00
|
|
|
$user,
|
|
|
|
array(
|
|
|
|
'action' => '#',
|
|
|
|
'method' => 'POST',
|
|
|
|
'class' => 'lightbox-download-form',
|
|
|
|
'sigil' => 'download',
|
|
|
|
),
|
|
|
|
phutil_tag(
|
|
|
|
'button',
|
|
|
|
array(),
|
|
|
|
pht('Download')));
|
|
|
|
|
|
|
|
Javelin::initBehavior(
|
|
|
|
'lightbox-attachments',
|
|
|
|
array(
|
|
|
|
'defaultImageUri' => $default_img_uri,
|
|
|
|
'downloadForm' => $download_form,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
Javelin::initBehavior('aphront-form-disable-on-submit');
|
2012-07-31 01:08:42 +02:00
|
|
|
Javelin::initBehavior('toggle-class', array());
|
2012-08-22 17:20:23 +02:00
|
|
|
Javelin::initBehavior('konami', array());
|
2013-03-01 03:58:00 +01:00
|
|
|
Javelin::initBehavior('history-install');
|
Add support for device swipe events
Summary:
Ref T2700. Allow JS to listen for swipes on devices.
There are a bunch of tricky cases here and I probably didn't get them all totally right, but this interaction broadly looks like this:
- We implement gesture recognition for the mouse in device modes (narrow browser), and for touch events from an actual device.
- The sigil `touchable` indicates that a node wants to react to touch events.
- When the user touches a `touchable` node, we start listening for moves. They might be tapping/clicking (in which case we don't care), but they might also be gesturing.
- Once the user moves their finger/pointer far enough away from the tap origin, we recognize it as a gesture. I hardcoded this at 20px; I wasn't able to find any "official" Apple value, but 20px seems like a common default.
- At this point, we look at where their finger has moved.
- If they moved it mostly up/down, we interpret the gesture as "scroll" and just stop listening. The device does its own thing.
- However, if they moved it mostly left/right, we interpret it as a "swipe". We start killing the moves so the device doesn't scroll.
- Once we've recognized that a gesture is underway, we send a "gesture.swipe.start" event and then "gesture.swipe.move" events for every move.
- When the user ends the gesture, we send "gesture.swipe.end".
- If the user cancels the gesture (currently, only by tapping with a second finger), we send "gesture.swipe.cancel".
- Gesture events have raw position data and some convenience fields.
Test Plan:
Wrote UI example and used it from the Desktop, iPhone simulator, and a real iphone.
- The code always seems to get "scroll" vs "swipe" correct (i.e., consistent with my intentions).
- The threshold feels pretty good to me.
- Tapping with a second finger cancels the action.
Reviewers: chad, btrahan
Reviewed By: chad
CC: aran
Maniphest Tasks: T2700
Differential Revision: https://secure.phabricator.com/D5308
2013-03-09 22:53:15 +01:00
|
|
|
Javelin::initBehavior('phabricator-gesture');
|
2013-01-29 03:12:09 +01:00
|
|
|
|
|
|
|
$current_token = null;
|
|
|
|
if ($user) {
|
|
|
|
$current_token = $user->getCSRFToken();
|
|
|
|
}
|
|
|
|
|
Prevent CSRF uploads via /file/dropupload/
Summary:
We don't currently validate CSRF tokens on this workflow. This allows an
attacker to upload arbitrary files on the user's behalf. Although I believe the
tight list of servable mime-types means that's more or less the end of the
attack, this is still a vulnerability.
In the long term, the right solution is probably to pass CSRF tokens on all Ajax
requests in an HTTP header (or just a GET param) or something like that.
However, this endpoint is unique and this is the quickest and most direct way to
close the hole.
Test Plan:
- Drop-uploaded files to Files, Maniphest, Phriction and Differential.
- Modified CSRF vaidator to use __csrf__.'x' and verified uploads and form
submissions don't work.
Reviewers: andrewjcg, aran, jungejason, tuomaspelkonen, erling
Commenters: andrewjcg, pedram
CC: aran, epriestley, andrewjcg, pedram
Differential Revision: 758
2011-08-02 05:23:01 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'refresh-csrf',
|
|
|
|
array(
|
|
|
|
'tokenName' => AphrontRequest::getCSRFTokenName(),
|
|
|
|
'header' => AphrontRequest::getCSRFHeaderName(),
|
|
|
|
'current' => $current_token,
|
|
|
|
));
|
2013-01-29 03:12:09 +01:00
|
|
|
|
2012-12-11 23:01:51 +01:00
|
|
|
Javelin::initBehavior('device');
|
2012-03-15 04:47:17 +01:00
|
|
|
|
2014-04-28 02:31:11 +02:00
|
|
|
if ($user->hasSession()) {
|
|
|
|
$hisec = ($user->getSession()->getHighSecurityUntil() - time());
|
|
|
|
if ($hisec > 0) {
|
2014-07-13 04:03:17 +02:00
|
|
|
$remaining_time = phutil_format_relative_time($hisec);
|
2014-04-28 02:31:11 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'high-security-warning',
|
|
|
|
array(
|
|
|
|
'uri' => '/auth/session/downgrade/',
|
|
|
|
'message' => pht(
|
|
|
|
'Your session is in high security mode. When you '.
|
|
|
|
'finish using it, click here to leave.',
|
|
|
|
$remaining_time),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
if ($console) {
|
|
|
|
require_celerity_resource('aphront-dark-console-css');
|
2013-02-09 22:29:47 +01:00
|
|
|
|
|
|
|
$headers = array();
|
2013-02-10 00:47:55 +01:00
|
|
|
if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
|
2013-02-09 22:29:47 +01:00
|
|
|
$headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
|
|
|
|
}
|
2013-11-19 23:10:45 +01:00
|
|
|
if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) {
|
|
|
|
$headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true;
|
|
|
|
}
|
2013-02-09 22:29:47 +01:00
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'dark-console',
|
|
|
|
array(
|
2013-08-08 01:09:25 +02:00
|
|
|
// NOTE: We use a generic label here to prevent input reflection
|
|
|
|
// and mitigate compression attacks like BREACH. See discussion in
|
|
|
|
// T3684.
|
|
|
|
'uri' => pht('Main Request'),
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
'selected' => $user ? $user->getConsoleTab() : null,
|
|
|
|
'visible' => $user ? (int)$user->getConsoleVisible() : true,
|
2013-02-09 22:29:47 +01:00
|
|
|
'headers' => $headers,
|
2011-02-02 22:48:52 +01:00
|
|
|
));
|
2011-04-05 21:24:21 +02:00
|
|
|
|
|
|
|
// Change this to initBehavior when there is some behavior to initialize
|
|
|
|
require_celerity_resource('javelin-behavior-error-log');
|
2011-02-02 22:48:52 +01:00
|
|
|
}
|
|
|
|
|
2013-10-13 02:08:47 +02:00
|
|
|
if ($user) {
|
|
|
|
$viewer = $user;
|
|
|
|
} else {
|
|
|
|
$viewer = new PhabricatorUser();
|
|
|
|
}
|
|
|
|
|
2012-12-07 22:34:44 +01:00
|
|
|
$menu = id(new PhabricatorMainMenuView())
|
Replace "search scope" with selectable default behavior
Summary:
Fixes T4365. See discussion in D8123.
This implements the most conservative solution of approaches discussed in D8123. Basically:
- When you search in primary search, we overwrite "query" in your default (topmost) search filter, and execute that.
This doesn't implement any of the other "sticky" stuff, where the query sticks around. Maybe we'll do that eventually, but it gets messy and could be confusing. Practically, this addresses the major use case in the wild, which is to make the menu bar search mean "Open Tasks" by default.
This also removes the old, obsolete "search scope" stuff. A long time ago, searching from within Maniphest would search tasks, etc., but this was pretty weird and confusing and is no longer used, and no one complained when we got rid of it.
Test Plan: Dragged "Open Tasks" to my top search, searched for "asdf", got "asdf in open tasks" results.
Reviewers: btrahan, chad
Reviewed By: btrahan
CC: bigo, aran
Maniphest Tasks: T4365
Differential Revision: https://secure.phabricator.com/D8135
2014-02-03 23:29:49 +01:00
|
|
|
->setUser($viewer);
|
2012-12-07 22:34:44 +01:00
|
|
|
|
2012-12-08 00:29:41 +01:00
|
|
|
if ($this->getController()) {
|
|
|
|
$menu->setController($this->getController());
|
|
|
|
}
|
|
|
|
|
2012-12-07 22:34:44 +01:00
|
|
|
if ($this->getApplicationMenu()) {
|
|
|
|
$menu->setApplicationMenu($this->getApplicationMenu());
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->menuContent = $menu->render();
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
protected function getHead() {
|
2012-07-07 00:39:43 +02:00
|
|
|
$monospaced = PhabricatorEnv::getEnvConfig('style.monospace');
|
2013-04-01 22:48:57 +02:00
|
|
|
$monospaced_win = PhabricatorEnv::getEnvConfig('style.monospace.windows');
|
2011-03-31 04:21:09 +02:00
|
|
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
|
|
|
if ($user) {
|
2013-04-01 22:48:57 +02:00
|
|
|
$pref = $user->loadPreferences()->getPreference(
|
|
|
|
PhabricatorUserPreferences::PREFERENCE_MONOSPACED);
|
|
|
|
$monospaced = nonempty($pref, $monospaced);
|
|
|
|
$monospaced_win = nonempty($pref, $monospaced_win);
|
2011-03-31 04:21:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-16 19:33:47 +02:00
|
|
|
$response = CelerityAPI::getStaticResourceResponse();
|
2012-07-25 20:51:27 +02:00
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
return hsprintf(
|
2014-03-06 20:39:48 +01:00
|
|
|
'%s<style type="text/css">'.
|
2013-04-18 20:49:54 +02:00
|
|
|
'.PhabricatorMonospaced, '.
|
|
|
|
'.phabricator-remarkup .remarkup-code-block { font: %s; } '.
|
|
|
|
'.platform-windows .PhabricatorMonospaced, '.
|
|
|
|
'.platform-windows .phabricator-remarkup '.
|
|
|
|
'.remarkup-code-block { font: %s; }'.
|
2013-04-01 22:48:57 +02:00
|
|
|
'</style>%s',
|
2012-10-16 19:33:47 +02:00
|
|
|
parent::getHead(),
|
2013-02-13 23:50:15 +01:00
|
|
|
phutil_safe_html($monospaced),
|
2013-04-01 22:48:57 +02:00
|
|
|
phutil_safe_html($monospaced_win),
|
2014-01-01 16:46:18 +01:00
|
|
|
$response->renderSingleResource('javelin-magical-init', 'phabricator'));
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function setGlyph($glyph) {
|
|
|
|
$this->glyph = $glyph;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getGlyph() {
|
|
|
|
return $this->glyph;
|
|
|
|
}
|
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
protected function willSendResponse($response) {
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
$request = $this->getRequest();
|
2012-10-16 19:33:47 +02:00
|
|
|
$response = parent::willSendResponse($response);
|
|
|
|
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
$console = $request->getApplicationConfiguration()->getConsole();
|
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
if ($console) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$response = PhutilSafeHTML::applyFunction(
|
|
|
|
'str_replace',
|
|
|
|
hsprintf('<darkconsole />'),
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
$console->render($request),
|
2011-02-02 22:48:52 +01:00
|
|
|
$response);
|
|
|
|
}
|
2012-10-16 19:33:47 +02:00
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
protected function getBody() {
|
2011-07-09 18:45:19 +02:00
|
|
|
$console = $this->getConsole();
|
2011-01-16 22:51:39 +01:00
|
|
|
|
2011-02-27 05:57:21 +01:00
|
|
|
$user = null;
|
2013-01-18 01:25:47 +01:00
|
|
|
$request = $this->getRequest();
|
2011-01-26 02:17:19 +01:00
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
2011-01-26 22:21:12 +01:00
|
|
|
}
|
2011-02-05 21:20:18 +01:00
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
$header_chrome = null;
|
|
|
|
if ($this->getShowChrome()) {
|
2012-07-31 15:18:38 +02:00
|
|
|
$header_chrome = $this->menuContent;
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
}
|
|
|
|
|
2012-01-04 16:35:52 +01:00
|
|
|
$developer_warning = null;
|
2013-02-01 18:34:06 +01:00
|
|
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') &&
|
2012-01-04 16:35:52 +01:00
|
|
|
DarkConsoleErrorLogPluginAPI::getErrors()) {
|
2013-11-09 19:48:19 +01:00
|
|
|
$developer_warning = phutil_tag_div(
|
|
|
|
'aphront-developer-error-callout',
|
2013-01-29 03:42:57 +01:00
|
|
|
pht(
|
|
|
|
'This page raised PHP errors. Find them in DarkConsole '.
|
|
|
|
'or the error log.'));
|
2012-01-04 16:35:52 +01:00
|
|
|
}
|
|
|
|
|
2013-01-18 01:25:47 +01:00
|
|
|
// Render the "you have unresolved setup issues..." warning.
|
|
|
|
$setup_warning = null;
|
|
|
|
if ($user && $user->getIsAdmin()) {
|
2013-01-19 17:39:27 +01:00
|
|
|
$open = PhabricatorSetupCheck::getOpenSetupIssueCount();
|
|
|
|
if ($open) {
|
2013-11-09 19:48:19 +01:00
|
|
|
$setup_warning = phutil_tag_div(
|
|
|
|
'setup-warning-callout',
|
2013-01-25 14:50:50 +01:00
|
|
|
phutil_tag(
|
2013-01-19 17:39:27 +01:00
|
|
|
'a',
|
2013-01-18 01:25:47 +01:00
|
|
|
array(
|
2013-01-19 17:39:27 +01:00
|
|
|
'href' => '/config/issue/',
|
2013-01-18 01:25:47 +01:00
|
|
|
),
|
2013-01-19 17:39:27 +01:00
|
|
|
pht('You have %d unresolved setup issue(s)...', $open)));
|
2013-01-18 01:25:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
return
|
2013-02-13 23:50:15 +01:00
|
|
|
phutil_tag(
|
2012-07-25 20:51:27 +02:00
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'id' => 'base-page',
|
2012-12-11 23:01:51 +01:00
|
|
|
'class' => 'phabricator-standard-page',
|
2012-07-25 20:51:27 +02:00
|
|
|
),
|
2013-11-09 19:48:19 +01:00
|
|
|
array(
|
|
|
|
$developer_warning,
|
|
|
|
$setup_warning,
|
|
|
|
$header_chrome,
|
|
|
|
phutil_tag_div('phabricator-standard-page-body', array(
|
|
|
|
($console ? hsprintf('<darkconsole />') : null),
|
|
|
|
parent::getBody(),
|
|
|
|
phutil_tag('div', array('style' => 'clear: both;')),
|
|
|
|
)),
|
|
|
|
));
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getTail() {
|
2012-07-31 01:09:14 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
$tail = array(
|
|
|
|
parent::getTail(),
|
|
|
|
);
|
2012-07-31 01:09:14 +02:00
|
|
|
|
2014-06-07 23:04:52 +02:00
|
|
|
$response = CelerityAPI::getStaticResourceResponse();
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
if (PhabricatorEnv::getEnvConfig('notification.enabled')) {
|
|
|
|
if ($user && $user->isLoggedIn()) {
|
|
|
|
|
|
|
|
$aphlict_object_id = celerity_generate_unique_node_id();
|
|
|
|
$aphlict_container_id = celerity_generate_unique_node_id();
|
|
|
|
|
|
|
|
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
|
|
|
|
$client_uri = new PhutilURI($client_uri);
|
|
|
|
if ($client_uri->getDomain() == 'localhost') {
|
|
|
|
$this_host = $this->getRequest()->getHost();
|
|
|
|
$this_host = new PhutilURI('http://'.$this_host.'/');
|
|
|
|
$client_uri->setDomain($this_host->getDomain());
|
|
|
|
}
|
|
|
|
|
2014-06-07 23:04:52 +02:00
|
|
|
$map = CelerityResourceMap::getNamedInstance('phabricator');
|
2014-06-13 14:47:06 +02:00
|
|
|
$swf_uri = $response->getURI($map, 'rsrc/swf/aphlict.swf', true);
|
2014-06-07 23:04:52 +02:00
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
$enable_debug = PhabricatorEnv::getEnvConfig('notification.debug');
|
2014-06-11 21:17:18 +02:00
|
|
|
|
|
|
|
$subscriptions = $this->pageObjects;
|
|
|
|
if ($user) {
|
|
|
|
$subscriptions[] = $user->getPHID();
|
|
|
|
}
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'aphlict-listen',
|
|
|
|
array(
|
2014-06-11 21:17:18 +02:00
|
|
|
'id' => $aphlict_object_id,
|
|
|
|
'containerID' => $aphlict_container_id,
|
|
|
|
'server' => $client_uri->getDomain(),
|
|
|
|
'port' => $client_uri->getPort(),
|
|
|
|
'debug' => $enable_debug,
|
|
|
|
'swfURI' => $swf_uri,
|
|
|
|
'pageObjects' => array_fill_keys($this->pageObjects, true),
|
|
|
|
'subscriptions' => $subscriptions,
|
2014-06-07 22:05:01 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
$tail[] = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'id' => $aphlict_container_id,
|
|
|
|
'style' =>
|
|
|
|
'position: absolute; width: 0; height: 0; overflow: hidden;',
|
|
|
|
),
|
|
|
|
'');
|
|
|
|
}
|
2012-07-31 01:09:14 +02:00
|
|
|
}
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
$tail[] = $response->renderHTMLFooter();
|
2012-10-16 19:33:47 +02:00
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
return $tail;
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
protected function getBodyClasses() {
|
|
|
|
$classes = array();
|
|
|
|
|
|
|
|
if (!$this->getShowChrome()) {
|
|
|
|
$classes[] = 'phabricator-chromeless-page';
|
|
|
|
}
|
|
|
|
|
2013-02-10 00:01:57 +01:00
|
|
|
$agent = AphrontRequest::getHTTPHeader('User-Agent');
|
2012-12-11 23:01:51 +01:00
|
|
|
|
|
|
|
// Try to guess the device resolution based on UA strings to avoid a flash
|
|
|
|
// of incorrectly-styled content.
|
|
|
|
$device_guess = 'device-desktop';
|
|
|
|
if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) {
|
|
|
|
$device_guess = 'device-phone device';
|
|
|
|
} else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) {
|
|
|
|
$device_guess = 'device-tablet device';
|
|
|
|
}
|
|
|
|
|
|
|
|
$classes[] = $device_guess;
|
|
|
|
|
2013-04-01 22:48:57 +02:00
|
|
|
if (preg_match('@Windows@', $agent)) {
|
|
|
|
$classes[] = 'platform-windows';
|
|
|
|
} else if (preg_match('@Macintosh@', $agent)) {
|
|
|
|
$classes[] = 'platform-mac';
|
|
|
|
} else if (preg_match('@X11@', $agent)) {
|
|
|
|
$classes[] = 'platform-linux';
|
|
|
|
}
|
|
|
|
|
2013-10-19 23:23:19 +02:00
|
|
|
if ($this->getRequest()->getStr('__print__')) {
|
|
|
|
$classes[] = 'printable';
|
|
|
|
}
|
|
|
|
|
Add support for aural-only and visual-only elements
Summary:
Ref T4843. This adds support to `javelin_tag()` for an `aural` attribute. When specified, `true` values mean "this content is aural-only", while `false` values mean "this content is not aural".
- I've attempted to find the best modern approaches for marking this content, but the `aural` attribute should let us change the mechanism later.
- Make the "beta" markers on application navigation visual only (see T4843). This information is of very low importance, the application navigation is accessed frequently, and the information is available on the application list.
- Partially convert the main navigation. This is mostly to test things, since I want to get more concrete feedback about approaches here.
- Add a `?__aural__=1` attribute, which renders the page with aural-only elements visible and visual-only elements colored.
Test Plan: {F146476}
Reviewers: btrahan, scp, chad
Reviewed By: chad
Subscribers: aklapper, qgil, epriestley
Maniphest Tasks: T4843
Differential Revision: https://secure.phabricator.com/D8830
2014-05-01 16:18:18 +02:00
|
|
|
if ($this->getRequest()->getStr('__aural__')) {
|
|
|
|
$classes[] = 'audible';
|
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
return implode(' ', $classes);
|
|
|
|
}
|
|
|
|
|
2011-07-09 18:45:19 +02:00
|
|
|
private function getConsole() {
|
|
|
|
if ($this->disableConsole) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $this->getRequest()->getApplicationConfiguration()->getConsole();
|
|
|
|
}
|
2012-07-31 01:09:14 +02:00
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|