diff --git a/scripts/celerity_mapper.php b/scripts/celerity_mapper.php index 7fa40e2d87..4a30d205a6 100755 --- a/scripts/celerity_mapper.php +++ b/scripts/celerity_mapper.php @@ -1,172 +1,185 @@ #!/usr/bin/env php array( 'phabricator-core-css', 'phabricator-core-buttons-css', 'phabricator-standard-page-view', 'aphront-dialog-view-css', 'aphront-form-view-css', 'aphront-panel-view-css', 'aphront-side-nav-view-css', 'aphront-table-view-css', 'aphront-tokenizer-control-css', 'aphront-typeahead-control-css', 'phabricator-directory-css', + + 'phabricator-remarkup-css', + 'syntax-highlighting-css', ), 'differential.pkg.css' => array( 'differential-core-view-css', 'differential-changeset-view-css', 'differential-revision-detail-css', 'differential-revision-history-css', 'differential-table-of-contents-css', + 'differential-revision-comment-css', + 'differential-revision-add-comment-css', + 'differential-revision-comment-list-css', + ), + 'differential.pkg.js' => array( + 'javelin-behavior-differential-feedback-preview', + 'javelin-behavior-differential-edit-inline-comments', + 'javelin-behavior-differential-populate', + 'javelin-behavior-differential-show-more', + 'javelin-behavior-differential-diff-radios', ), ); require_once dirname(__FILE__).'/__init_script__.php'; if ($argc != 2) { $self = basename($argv[0]); echo "usage: {$self} \n"; exit(1); } phutil_require_module('phutil', 'filesystem'); phutil_require_module('phutil', 'filesystem/filefinder'); phutil_require_module('phutil', 'future/exec'); phutil_require_module('phutil', 'parser/docblock'); $root = Filesystem::resolvePath($argv[1]); echo "Finding static resources...\n"; $files = id(new FileFinder($root)) ->withType('f') ->withSuffix('js') ->withSuffix('css') ->setGenerateChecksums(true) ->find(); echo "Processing ".count($files)." files"; $file_map = array(); foreach ($files as $path => $hash) { echo "."; $name = '/'.Filesystem::readablePath($path, $root); $file_map[$name] = array( 'hash' => $hash, 'disk' => $path, ); } echo "\n"; $runtime_map = array(); $hash_map = array(); $parser = new PhutilDocblockParser(); foreach ($file_map as $path => $info) { $data = Filesystem::readFile($info['disk']); $matches = array(); $ok = preg_match('@/[*][*].*?[*]/@s', $data, $matches); if (!$ok) { throw new Exception( "File {$path} does not have a header doc comment. Encode dependency ". "data in a header docblock."); } list($description, $metadata) = $parser->parse($matches[0]); $provides = preg_split('/\s+/', trim(idx($metadata, 'provides'))); $requires = preg_split('/\s+/', trim(idx($metadata, 'requires'))); $provides = array_filter($provides); $requires = array_filter($requires); if (count($provides) !== 1) { throw new Exception( "File {$path} must @provide exactly one Celerity target."); } $provides = reset($provides); $type = 'js'; if (preg_match('/\.css$/', $path)) { $type = 'css'; } $uri = '/res/'.substr($info['hash'], 0, 8).$path; $hash_map[$provides] = $info['hash']; $runtime_map[$provides] = array( 'uri' => $uri, 'type' => $type, 'requires' => $requires, 'disk' => $path, ); } $package_map = array(); foreach ($package_spec as $name => $package) { $hashes = array(); $type = null; foreach ($package as $symbol) { if (empty($hash_map[$symbol])) { throw new Exception( "Package specification for '{$name}' includes '{$symbol}', but that ". "symbol is not defined anywhere."); } if ($type === null) { $type = $runtime_map[$symbol]['type']; } else { $ntype = $runtime_map[$symbol]['type']; if ($type !== $ntype) { throw new Exception( "Package specification for '{$name}' mixes resources of type ". "'{$type}' with resources of type '{$ntype}'. Each package may only ". "contain one type of resource."); } } $hashes[] = $symbol.':'.$hash_map[$symbol]; } $key = substr(md5(implode("\n", $hashes)), 0, 8); $package_map['packages'][$key] = array( 'name' => $name, 'symbols' => $package, 'uri' => '/res/pkg/'.$key.'/'.$name, 'type' => $type, ); foreach ($package as $symbol) { $package_map['reverse'][$symbol] = $key; } } $runtime_map = var_export($runtime_map, true); $runtime_map = preg_replace('/\s+$/m', '', $runtime_map); $runtime_map = preg_replace('/array \(/', 'array(', $runtime_map); $package_map = var_export($package_map, true); $pacakge_map = preg_replace('/\s+$/m', '', $package_map); $package_map = preg_replace('/array \(/', 'array(', $package_map); $resource_map = << array( 'uri' => '/res/056b0c12/rsrc/css/aphront/dark-console.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/dark-console.css', ), 'aphront-dialog-view-css' => array( 'uri' => '/res/a05107ae/rsrc/css/aphront/dialog-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/dialog-view.css', ), 'aphront-form-view-css' => array( 'uri' => '/res/785ac1c6/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/form-view.css', ), 'aphront-panel-view-css' => array( 'uri' => '/res/63672373/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/panel-view.css', ), 'aphront-request-failure-view-css' => array( 'uri' => '/res/97b8337a/rsrc/css/aphront/request-failure-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/request-failure-view.css', ), 'aphront-side-nav-view-css' => array( 'uri' => '/res/0fc0545c/rsrc/css/aphront/side-nav-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/side-nav-view.css', ), 'aphront-table-view-css' => array( 'uri' => '/res/6a70f0f0/rsrc/css/aphront/table-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/table-view.css', ), 'aphront-tokenizer-control-css' => array( 'uri' => '/res/a3d23074/rsrc/css/aphront/tokenizer.css', 'type' => 'css', 'requires' => array( 0 => 'aphront-typeahead-control-css', ), 'disk' => '/rsrc/css/aphront/tokenizer.css', ), 'aphront-typeahead-control-css' => array( 'uri' => '/res/928df9f0/rsrc/css/aphront/typeahead.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/typeahead.css', ), 'phabricator-standard-page-view' => array( 'uri' => '/res/fb02fb0e/rsrc/css/application/base/standard-page-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/base/standard-page-view.css', ), 'differential-revision-add-comment-css' => array( 'uri' => '/res/9be761de/rsrc/css/application/differential/add-comment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/add-comment.css', ), 'differential-changeset-view-css' => array( - 'uri' => '/res/4e0295a9/rsrc/css/application/differential/changeset-view.css', + 'uri' => '/res/8b893b8e/rsrc/css/application/differential/changeset-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/changeset-view.css', ), 'differential-core-view-css' => array( 'uri' => '/res/525d1a12/rsrc/css/application/differential/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/core.css', ), 'differential-revision-comment-list-css' => array( 'uri' => '/res/a1c117db/rsrc/css/application/differential/revision-comment-list.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-comment-list.css', ), 'differential-revision-comment-css' => array( 'uri' => '/res/274eb3f1/rsrc/css/application/differential/revision-comment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-comment.css', ), 'differential-revision-detail-css' => array( 'uri' => '/res/230a67c6/rsrc/css/application/differential/revision-detail.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-detail.css', ), 'differential-revision-history-css' => array( 'uri' => '/res/755f3da3/rsrc/css/application/differential/revision-history.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-history.css', ), 'differential-table-of-contents-css' => array( - 'uri' => '/res/a4a7b2b5/rsrc/css/application/differential/table-of-contents.css', + 'uri' => '/res/e68f6f05/rsrc/css/application/differential/table-of-contents.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/table-of-contents.css', ), 'phabricator-directory-css' => array( 'uri' => '/res/6a000601/rsrc/css/application/directory/phabricator-directory.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/directory/phabricator-directory.css', ), 'phabricator-core-buttons-css' => array( 'uri' => '/res/6e348ba4/rsrc/css/core/buttons.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/buttons.css', ), 'phabricator-core-css' => array( - 'uri' => '/res/39ce37c2/rsrc/css/core/core.css', + 'uri' => '/res/41c62455/rsrc/css/core/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/core.css', ), 'phabricator-core-dialog-css' => array( 'uri' => '/res/f66cec41/rsrc/css/core/dialog.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/dialog.css', ), 'phabricator-remarkup-css' => array( 'uri' => '/res/786989c3/rsrc/css/core/remarkup.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/remarkup.css', ), 'syntax-highlighting-css' => array( 'uri' => '/res/fb673ece/rsrc/css/core/syntax.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/syntax.css', ), 'javelin-behavior-dark-console' => array( 'uri' => '/res/020b0265/rsrc/js/application/core/behavior-dark-console.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/application/core/behavior-dark-console.js', ), 'javelin-behavior-aphront-basic-tokenizer' => array( 'uri' => '/res/8317d761/rsrc/js/application/core/behavior-tokenizer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/core/behavior-tokenizer.js', ), 'javelin-behavior-differential-feedback-preview' => array( 'uri' => '/res/8695d8b8/rsrc/js/application/differential/behavior-comment-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js', ), 'javelin-behavior-differential-diff-radios' => array( - 'uri' => '/res/ea6b0062/rsrc/js/application/differential/behavior-diff-radios.js', + 'uri' => '/res/fdeb3823/rsrc/js/application/differential/behavior-diff-radios.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-diff-radios.js', ), 'javelin-behavior-differential-edit-inline-comments' => array( 'uri' => '/res/74747b2e/rsrc/js/application/differential/behavior-edit-inline-comments.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-edit-inline-comments.js', ), 'javelin-behavior-differential-populate' => array( - 'uri' => '/res/f7efbf62/rsrc/js/application/differential/behavior-populate.js', + 'uri' => '/res/a13dcd7e/rsrc/js/application/differential/behavior-populate.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-populate.js', ), 'javelin-behavior-differential-show-more' => array( 'uri' => '/res/ea998002/rsrc/js/application/differential/behavior-show-more.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-show-more.js', ), 'javelin-magical-init' => array( 'uri' => '/res/76614f84/rsrc/js/javelin/init.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/init.dev.js', ), 'javelin-init-prod' => array( 'uri' => '/res/1267c868/rsrc/js/javelin/init.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/init.min.js', ), 'javelin-lib-dev' => array( 'uri' => '/res/a0e7a5e9/rsrc/js/javelin/javelin.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/javelin.dev.js', ), 'javelin-lib-prod' => array( 'uri' => '/res/2f2b3b2e/rsrc/js/javelin/javelin.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/javelin.min.js', ), 'javelin-typeahead-dev' => array( 'uri' => '/res/6de6ae59/rsrc/js/javelin/typeahead.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/typeahead.dev.js', ), 'javelin-typeahead-prod' => array( 'uri' => '/res/69d5fad1/rsrc/js/javelin/typeahead.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/typeahead.min.js', ), 'javelin-workflow-dev' => array( - 'uri' => '/res/7e690e16/rsrc/js/javelin/workflow.dev.js', + 'uri' => '/res/c6b17f93/rsrc/js/javelin/workflow.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/workflow.dev.js', ), 'javelin-workflow-prod' => array( 'uri' => '/res/b758e0a0/rsrc/js/javelin/workflow.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/workflow.min.js', ), ), array ( 'packages' => array ( - '1a33af6b' => + '85861df3' => array ( 'name' => 'core.pkg.css', 'symbols' => array ( 0 => 'phabricator-core-css', 1 => 'phabricator-core-buttons-css', 2 => 'phabricator-standard-page-view', 3 => 'aphront-dialog-view-css', 4 => 'aphront-form-view-css', 5 => 'aphront-panel-view-css', 6 => 'aphront-side-nav-view-css', 7 => 'aphront-table-view-css', 8 => 'aphront-tokenizer-control-css', 9 => 'aphront-typeahead-control-css', 10 => 'phabricator-directory-css', + 11 => 'phabricator-remarkup-css', + 12 => 'syntax-highlighting-css', ), - 'uri' => '/res/pkg/1a33af6b/core.pkg.css', + 'uri' => '/res/pkg/85861df3/core.pkg.css', 'type' => 'css', ), - '9d9c881c' => + '86498b42' => array ( 'name' => 'differential.pkg.css', 'symbols' => array ( 0 => 'differential-core-view-css', 1 => 'differential-changeset-view-css', 2 => 'differential-revision-detail-css', 3 => 'differential-revision-history-css', 4 => 'differential-table-of-contents-css', + 5 => 'differential-revision-comment-css', + 6 => 'differential-revision-add-comment-css', + 7 => 'differential-revision-comment-list-css', ), - 'uri' => '/res/pkg/9d9c881c/differential.pkg.css', + 'uri' => '/res/pkg/86498b42/differential.pkg.css', 'type' => 'css', ), + '30d594cf' => + array ( + 'name' => 'differential.pkg.js', + 'symbols' => + array ( + 0 => 'javelin-behavior-differential-feedback-preview', + 1 => 'javelin-behavior-differential-edit-inline-comments', + 2 => 'javelin-behavior-differential-populate', + 3 => 'javelin-behavior-differential-show-more', + 4 => 'javelin-behavior-differential-diff-radios', + ), + 'uri' => '/res/pkg/30d594cf/differential.pkg.js', + 'type' => 'js', + ), ), 'reverse' => array ( - 'phabricator-core-css' => '1a33af6b', - 'phabricator-core-buttons-css' => '1a33af6b', - 'phabricator-standard-page-view' => '1a33af6b', - 'aphront-dialog-view-css' => '1a33af6b', - 'aphront-form-view-css' => '1a33af6b', - 'aphront-panel-view-css' => '1a33af6b', - 'aphront-side-nav-view-css' => '1a33af6b', - 'aphront-table-view-css' => '1a33af6b', - 'aphront-tokenizer-control-css' => '1a33af6b', - 'aphront-typeahead-control-css' => '1a33af6b', - 'phabricator-directory-css' => '1a33af6b', - 'differential-core-view-css' => '9d9c881c', - 'differential-changeset-view-css' => '9d9c881c', - 'differential-revision-detail-css' => '9d9c881c', - 'differential-revision-history-css' => '9d9c881c', - 'differential-table-of-contents-css' => '9d9c881c', + 'phabricator-core-css' => '85861df3', + 'phabricator-core-buttons-css' => '85861df3', + 'phabricator-standard-page-view' => '85861df3', + 'aphront-dialog-view-css' => '85861df3', + 'aphront-form-view-css' => '85861df3', + 'aphront-panel-view-css' => '85861df3', + 'aphront-side-nav-view-css' => '85861df3', + 'aphront-table-view-css' => '85861df3', + 'aphront-tokenizer-control-css' => '85861df3', + 'aphront-typeahead-control-css' => '85861df3', + 'phabricator-directory-css' => '85861df3', + 'phabricator-remarkup-css' => '85861df3', + 'syntax-highlighting-css' => '85861df3', + 'differential-core-view-css' => '86498b42', + 'differential-changeset-view-css' => '86498b42', + 'differential-revision-detail-css' => '86498b42', + 'differential-revision-history-css' => '86498b42', + 'differential-table-of-contents-css' => '86498b42', + 'differential-revision-comment-css' => '86498b42', + 'differential-revision-add-comment-css' => '86498b42', + 'differential-revision-comment-list-css' => '86498b42', + 'javelin-behavior-differential-feedback-preview' => '30d594cf', + 'javelin-behavior-differential-edit-inline-comments' => '30d594cf', + 'javelin-behavior-differential-populate' => '30d594cf', + 'javelin-behavior-differential-show-more' => '30d594cf', + 'javelin-behavior-differential-diff-radios' => '30d594cf', ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0287bcc21c..a7ce107e3d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,376 +1,378 @@ array( 'Aphront400Response' => 'aphront/response/400', 'Aphront404Response' => 'aphront/response/404', 'AphrontAjaxResponse' => 'aphront/response/ajax', 'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration', 'AphrontController' => 'aphront/controller', 'AphrontDatabaseConnection' => 'storage/connection/base', 'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration', 'AphrontDefaultApplicationController' => 'aphront/default/controller', 'AphrontDialogResponse' => 'aphront/response/dialog', 'AphrontDialogView' => 'view/dialog', 'AphrontErrorView' => 'view/form/error', 'AphrontException' => 'aphront/exception/base', 'AphrontFileResponse' => 'aphront/response/file', 'AphrontFormCheckboxControl' => 'view/form/control/checkbox', 'AphrontFormControl' => 'view/form/control/base', + 'AphrontFormDividerControl' => 'view/form/control/divider', 'AphrontFormFileControl' => 'view/form/control/file', 'AphrontFormMarkupControl' => 'view/form/control/markup', 'AphrontFormPasswordControl' => 'view/form/control/password', 'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha', 'AphrontFormSelectControl' => 'view/form/control/select', 'AphrontFormStaticControl' => 'view/form/control/static', 'AphrontFormSubmitControl' => 'view/form/control/submit', 'AphrontFormTextAreaControl' => 'view/form/control/textarea', 'AphrontFormTextControl' => 'view/form/control/text', 'AphrontFormTokenizerControl' => 'view/form/control/tokenizer', 'AphrontFormView' => 'view/form/base', 'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql', 'AphrontNullView' => 'view/null', 'AphrontPageView' => 'view/page/base', 'AphrontPanelView' => 'view/layout/panel', 'AphrontQueryConnectionException' => 'storage/exception/connection', 'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost', 'AphrontQueryCountException' => 'storage/exception/count', 'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey', 'AphrontQueryException' => 'storage/exception/base', 'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing', 'AphrontQueryParameterException' => 'storage/exception/parameter', 'AphrontQueryRecoverableException' => 'storage/exception/recoverable', 'AphrontRedirectException' => 'aphront/exception/redirect', 'AphrontRedirectResponse' => 'aphront/response/redirect', 'AphrontRequest' => 'aphront/request', 'AphrontRequestFailureView' => 'view/page/failure', 'AphrontResponse' => 'aphront/response/base', 'AphrontSideNavView' => 'view/layout/sidenav', 'AphrontTableView' => 'view/control/table', 'AphrontURIMapper' => 'aphront/mapper', 'AphrontView' => 'view/base', 'AphrontWebpageResponse' => 'aphront/response/webpage', 'CelerityAPI' => 'infrastructure/celerity/api', 'CelerityResourceController' => 'infrastructure/celerity/controller', 'CelerityResourceMap' => 'infrastructure/celerity/map', 'CelerityStaticResourceResponse' => 'infrastructure/celerity/response', 'ConduitAPIMethod' => 'applications/conduit/method/base', 'ConduitAPIRequest' => 'applications/conduit/protocol/request', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect', 'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty', 'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload', 'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find', 'ConduitException' => 'applications/conduit/protocol/exception', 'DarkConsole' => 'aphront/console/api', 'DarkConsoleController' => 'aphront/console/controller', 'DarkConsoleCore' => 'aphront/console/core', 'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog', 'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api', 'DarkConsolePlugin' => 'aphront/console/plugin/base', 'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request', 'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services', 'DarkConsoleServicesPluginAPI' => 'aphront/console/plugin/services/api', 'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof', 'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api', 'DifferentialAction' => 'applications/differential/constants/action', 'DifferentialAddCommentView' => 'applications/differential/view/addcomment', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome', 'DifferentialChangeType' => 'applications/differential/constants/changetype', 'DifferentialChangeset' => 'applications/differential/storage/changeset', 'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview', 'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview', 'DifferentialChangesetParser' => 'applications/differential/parser/changeset', 'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview', 'DifferentialComment' => 'applications/differential/storage/comment', 'DifferentialCommentEditor' => 'applications/differential/editor/comment', 'DifferentialCommentMail' => 'applications/differential/mail/comment', 'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview', 'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', 'DifferentialDiff' => 'applications/differential/storage/diff', 'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent', 'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview', 'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialMail' => 'applications/differential/mail/base', 'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup', 'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff', 'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest', 'DifferentialRevision' => 'applications/differential/storage/revision', 'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist', 'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem', 'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail', 'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit', 'DifferentialRevisionEditor' => 'applications/differential/editor/revision', 'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist', 'DifferentialRevisionListData' => 'applications/differential/data/revisionlist', 'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory', 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', 'Javelin' => 'infrastructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'Phabricator404Controller' => 'applications/base/controller/404', 'PhabricatorAuthController' => 'applications/auth/controller/base', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/api', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console', 'PhabricatorConduitController' => 'applications/conduit/controller/base', 'PhabricatorConduitDAO' => 'applications/conduit/storage/base', 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorController' => 'applications/base/controller/base', 'PhabricatorDirectoryCategory' => 'applications/directory/storage/category', 'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete', 'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit', 'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist', 'PhabricatorDirectoryController' => 'applications/directory/controller/base', 'PhabricatorDirectoryDAO' => 'applications/directory/storage/base', 'PhabricatorDirectoryItem' => 'applications/directory/storage/item', 'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete', 'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit', 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorEmailLoginController' => 'applications/auth/controller/email', 'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken', 'PhabricatorEnv' => 'infrastructure/env', 'PhabricatorFacebookAuthController' => 'applications/auth/controller/facebookauth', 'PhabricatorFacebookAuthDiagnosticsController' => 'applications/auth/controller/facebookauth/diagnostics', 'PhabricatorFile' => 'applications/files/storage/file', 'PhabricatorFileController' => 'applications/files/controller/base', 'PhabricatorFileDAO' => 'applications/files/storage/base', 'PhabricatorFileListController' => 'applications/files/controller/list', 'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob', 'PhabricatorFileURI' => 'applications/files/uri', 'PhabricatorFileUploadController' => 'applications/files/controller/upload', 'PhabricatorFileViewController' => 'applications/files/controller/view', 'PhabricatorLiskDAO' => 'applications/base/storage/lisk', 'PhabricatorLoginController' => 'applications/auth/controller/login', 'PhabricatorLogoutController' => 'applications/auth/controller/logout', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/base', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base', 'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail', 'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist', 'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit', 'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists', 'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send', 'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view', 'PhabricatorObjectHandle' => 'applications/phid/handle', 'PhabricatorObjectHandleData' => 'applications/phid/handle/data', 'PhabricatorPHID' => 'applications/phid/storage/phid', 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate', 'PhabricatorPHIDController' => 'applications/phid/controller/base', 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', 'PhabricatorPHIDListController' => 'applications/phid/controller/list', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup', 'PhabricatorPHIDType' => 'applications/phid/storage/type', 'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit', 'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist', 'PhabricatorPeopleController' => 'applications/people/controller/base', 'PhabricatorPeopleEditController' => 'applications/people/controller/edit', 'PhabricatorPeopleListController' => 'applications/people/controller/list', 'PhabricatorPeopleProfileController' => 'applications/people/controller/profile', 'PhabricatorStandardPageView' => 'view/page/standard', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base', 'PhabricatorUser' => 'applications/people/storage/user', 'PhabricatorUserDAO' => 'applications/people/storage/base', 'PhabricatorXHProfController' => 'applications/xhprof/controller/base', 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile', 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol', 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel', ), 'function' => array( '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api', 'celerity_register_resource_map' => 'infrastructure/celerity/map', 'javelin_render_tag' => 'infrastructure/javelin/markup', 'phabricator_format_relative_time' => 'view/utils', 'phabricator_format_timestamp' => 'view/utils', 'phabricator_format_units_generic' => 'view/utils', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', 'queryfx_one' => 'storage/queryfx', 'require_celerity_resource' => 'infrastructure/celerity/api', 'vqsprintf' => 'storage/qsprintf', 'vqueryfx' => 'storage/queryfx', 'vqueryfx_all' => 'storage/queryfx', 'xsprintf_query' => 'storage/qsprintf', ), 'requires_class' => array( 'Aphront400Response' => 'AphrontResponse', 'Aphront404Response' => 'AphrontResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', + 'AphrontFormDividerControl' => 'AphrontFormControl', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontNullView' => 'AphrontView', 'AphrontPageView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontQueryConnectionException' => 'AphrontQueryException', 'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException', 'AphrontQueryCountException' => 'AphrontQueryException', 'AphrontQueryDuplicateKeyException' => 'AphrontQueryException', 'AphrontQueryObjectMissingException' => 'AphrontQueryException', 'AphrontQueryParameterException' => 'AphrontQueryException', 'AphrontQueryRecoverableException' => 'AphrontQueryException', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontSideNavView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontWebpageResponse' => 'AphrontResponse', 'CelerityResourceController' => 'AphrontController', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_find_Method' => 'ConduitAPIMethod', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => 'DifferentialDAO', 'DifferentialCommentMail' => 'DifferentialMail', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialInlineComment' => 'DifferentialDAO', 'DifferentialInlineCommentEditController' => 'DifferentialController', 'DifferentialInlineCommentPreviewController' => 'DifferentialController', 'DifferentialInlineCommentView' => 'AphrontView', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', 'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialRevision' => 'DifferentialDAO', 'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorController' => 'AphrontController', 'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailTokenController' => 'PhabricatorAuthController', 'PhabricatorFacebookAuthController' => 'PhabricatorAuthController', 'PhabricatorFacebookAuthDiagnosticsController' => 'PhabricatorAuthController', 'PhabricatorFile' => 'PhabricatorFileDAO', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileViewController' => 'PhabricatorFileController', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLoginController' => 'PhabricatorAuthController', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController', 'PhabricatorPHID' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController', 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorUser' => 'PhabricatorUserDAO', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHProfController' => 'PhabricatorController', 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', 'PhabricatorXHProfProfileSymbolView' => 'AphrontView', 'PhabricatorXHProfProfileTopLevelView' => 'AphrontView', ), 'requires_interface' => array( ), )); diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 52b9040d22..e78c6217b7 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -1,210 +1,211 @@ array( '$' => 'RepositoryListController', 'new/$' => 'RepositoryEditController', 'edit/(?\d+)/$' => 'RepositoryEditController', 'delete/(?\d+)/$' => 'RepositoryDeleteController', ), '/' => array( '$' => 'PhabricatorDirectoryMainController', ), '/directory/' => array( 'item/$' => 'PhabricatorDirectoryItemListController', 'item/edit/(?:(?\d+)/)?$' => 'PhabricatorDirectoryItemEditController', 'item/delete/(?\d+)/' => 'PhabricatorDirectoryItemDeleteController', 'category/$' => 'PhabricatorDirectoryCategoryListController', 'category/edit/(?:(?\d+)/)?$' => 'PhabricatorDirectoryCategoryEditController', 'category/delete/(?\d+)/' => 'PhabricatorDirectoryCategoryDeleteController', ), '/file/' => array( '$' => 'PhabricatorFileListController', 'upload/$' => 'PhabricatorFileUploadController', '(?info)/(?[^/]+)/' => 'PhabricatorFileViewController', '(?view)/(?[^/]+)/' => 'PhabricatorFileViewController', '(?download)/(?[^/]+)/' => 'PhabricatorFileViewController', ), '/phid/' => array( '$' => 'PhabricatorPHIDLookupController', 'list/$' => 'PhabricatorPHIDListController', 'type/$' => 'PhabricatorPHIDTypeListController', 'type/edit/(?:(?\d+)/)?$' => 'PhabricatorPHIDTypeEditController', 'new/$' => 'PhabricatorPHIDAllocateController', ), '/people/' => array( '$' => 'PhabricatorPeopleListController', 'edit/(?:(?\w+)/)?$' => 'PhabricatorPeopleEditController', ), '/p/(?\w+)/$' => 'PhabricatorPeopleProfileController', '/conduit/' => array( '$' => 'PhabricatorConduitConsoleController', 'method/(?[^/]+)$' => 'PhabricatorConduitConsoleController', 'log/$' => 'PhabricatorConduitLogController', ), '/api/(?[^/]+)$' => 'PhabricatorConduitAPIController', '/D(?\d+)' => 'DifferentialRevisionViewController', '/differential/' => array( '$' => 'DifferentialRevisionListController', 'filter/(?\w+)/$' => 'DifferentialRevisionListController', 'diff/(?\d+)/$' => 'DifferentialDiffViewController', 'changeset/$' => 'DifferentialChangesetViewController', 'revision/edit/(?:(?\d+)/)?$' => 'DifferentialRevisionEditController', 'comment/' => array( 'preview/(?\d+)/$' => 'DifferentialCommentPreviewController', 'save/$' => 'DifferentialCommentSaveController', 'inline/' => array( 'preview/(?\d+)/$' => 'DifferentialInlineCommentPreviewController', 'edit/(?\d+)/$' => 'DifferentialInlineCommentEditController', ), ), ), '/res/' => array( '(?pkg/)?(?[a-f0-9]{8})/(?.+\.(?:css|js))$' => 'CelerityResourceController', ), '/typeahead/' => array( 'common/(?\w+)/$' => 'PhabricatorTypeaheadCommonDatasourceController', ), '/mail/' => array( '$' => 'PhabricatorMetaMTAListController', 'send/$' => 'PhabricatorMetaMTASendController', 'view/(?\d+)/$' => 'PhabricatorMetaMTAViewController', 'lists/$' => 'PhabricatorMetaMTAMailingListsController', 'lists/edit/(?:(?\d+)/)?$' => 'PhabricatorMetaMTAMailingListEditController', ), '/login/' => array( '$' => 'PhabricatorLoginController', 'email/$' => 'PhabricatorEmailLoginController', 'etoken/(?\w+)/$' => 'PhabricatorEmailTokenController', ), '/logout/$' => 'PhabricatorLogoutController', '/facebook-auth/' => array( '$' => 'PhabricatorFacebookAuthController', 'diagnose/$' => 'PhabricatorFacebookAuthDiagnosticsController', ), '/xhprof/' => array( 'profile/(?[^/]+)/$' => 'PhabricatorXHProfProfileController', ), '/~/' => 'DarkConsoleController', ); } public function buildRequest() { $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($_GET + $_POST); $request->setApplicationConfiguration($this); return $request; } public function handleException(Exception $ex) { $class = phutil_escape_html(get_class($ex)); $message = phutil_escape_html($ex->getMessage()); $content = '
'. '

Unhandled Exception "'.$class.'": '.$message.'

'. ''.phutil_escape_html((string)$ex).''. '
'; $view = new PhabricatorStandardPageView(); $view->setRequest($this->getRequest()); $view->appendChild($content); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } public function willSendResponse(AphrontResponse $response) { $request = $this->getRequest(); if ($response instanceof AphrontDialogResponse) { if (!$request->isAjax()) { $view = new PhabricatorStandardPageView(); + $view->setRequest($request); $view->appendChild( '
'. $response->buildResponseString(). '
'); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } else { return id(new AphrontAjaxResponse()) ->setContent(array( 'dialog' => $response->buildResponseString(), )); } } else if ($response instanceof Aphront404Response) { $failure = new AphrontRequestFailureView(); $failure->setHeader('404 Not Found'); $failure->appendChild( '

The page you requested was not found.

'); $view = new PhabricatorStandardPageView(); $view->setTitle('404 Not Found'); $view->setRequest($this->getRequest()); $view->appendChild($failure); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); $response->setHTTPResponseCode(404); return $response; } return $response; } public function build404Controller() { return array(new Phabricator404Controller($this->getRequest()), array()); } } diff --git a/src/applications/differential/controller/inlinecommentedit/DifferentialInlineCommentEditController.php b/src/applications/differential/controller/inlinecommentedit/DifferentialInlineCommentEditController.php index 7134a83220..23315323bc 100644 --- a/src/applications/differential/controller/inlinecommentedit/DifferentialInlineCommentEditController.php +++ b/src/applications/differential/controller/inlinecommentedit/DifferentialInlineCommentEditController.php @@ -1,193 +1,194 @@ revisionID = $data['id']; } public function processRequest() { $request = $this->getRequest(); $changeset = $request->getInt('changeset'); $is_new = $request->getInt('is_new'); $on_right = $request->getInt('on_right'); $number = $request->getInt('number'); $length = $request->getInt('length'); $text = $request->getStr('text'); $op = $request->getStr('op'); $inline_id = $request->getInt('id'); $user = $request->getUser(); $submit_uri = '/differential/comment/inline/edit/'.$this->revisionID.'/'; $edit_dialog = new AphrontDialogView(); $edit_dialog->setUser($user); $edit_dialog->setSubmitURI($submit_uri); $edit_dialog->addHiddenInput('on_right', $on_right); $edit_dialog->addSubmitButton(); $edit_dialog->addCancelButton('#'); $inline = null; if ($inline_id) { $inline = id(new DifferentialInlineComment()) ->load($inline_id); if (!$inline || $inline->getAuthorPHID() != $user->getPHID() || $inline->getCommentID() || $inline->getRevisionID() != $this->revisionID) { throw new Exception("That comment is not editable!"); } } switch ($op) { case 'delete': if (!$inline) { return new Aphront400Response(); } if ($request->isFormPost()) { $inline->delete(); return $this->buildDeletedResponse(); } $edit_dialog->setTitle('Really delete this comment?'); $edit_dialog->addHiddenInput('id', $inline_id); $edit_dialog->addHiddenInput('op', 'delete'); $edit_dialog->appendChild( '

Delete this inline comment?

'); return id(new AphrontDialogResponse())->setDialog($edit_dialog); case 'edit': if (!$inline) { return new Aphront400Response(); } if ($request->isFormPost()) { if (strlen($text)) { $inline->setContent($text); $inline->setCache(null); $inline->save(); return $this->buildRenderedCommentResponse( $inline, $on_right); } else { $inline->delete(); return $this->buildDeletedResponse(); } } $edit_dialog->setTitle('Edit Inline Comment'); $edit_dialog->addHiddenInput('id', $inline_id); $edit_dialog->addHiddenInput('op', 'edit'); $edit_dialog->appendChild( $this->renderTextArea( $inline->getContent())); return id(new AphrontDialogResponse())->setDialog($edit_dialog); case 'create': if (!$request->isFormPost() || !strlen($text)) { return new AphrontAjaxResponse(); } $inline = id(new DifferentialInlineComment()) ->setRevisionID($this->revisionID) ->setChangesetID($changeset) ->setCommentID(null) ->setAuthorPHID($user->getPHID()) ->setLineNumber($number) ->setLineLength($length) ->setIsNewFile($is_new) ->setContent($text) ->save(); return $this->buildRenderedCommentResponse($inline, $on_right); default: $edit_dialog->setTitle('New Inline Comment'); $edit_dialog->addHiddenInput('op', 'create'); $edit_dialog->addHiddenInput('changeset', $changeset); $edit_dialog->addHiddenInput('is_new', $is_new); $edit_dialog->addHiddenInput('number', $number); $edit_dialog->addHiddenInput('length', $length); $edit_dialog->appendChild($this->renderTextArea('')); return id(new AphrontDialogResponse())->setDialog($edit_dialog); } } private function buildRenderedCommentResponse( DifferentialInlineComment $inline, $on_right) { $request = $this->getRequest(); $user = $request->getUser(); $factory = new DifferentialMarkupEngineFactory(); $engine = $factory->newDifferentialCommentMarkupEngine(); $phids = array($user->getPHID()); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $view = new DifferentialInlineCommentView(); $view->setInlineComment($inline); $view->setOnRight($on_right); $view->setBuildScaffolding(true); $view->setMarkupEngine($engine); $view->setHandles($handles); $view->setEditable(true); return id(new AphrontAjaxResponse()) ->setContent( array( 'inlineCommentID' => $inline->getID(), 'markup' => $view->render(), )); } private function buildDeletedResponse() { return id(new AphrontAjaxResponse()) ->setContent( array( 'markup' => '', )); } private function renderTextArea($text) { return phutil_render_tag( 'textarea', array( + 'class' => 'differential-inline-comment-edit-textarea', 'name' => 'text', ), $text); } } diff --git a/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php b/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php index 5f4822db12..3e1ce67956 100644 --- a/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php +++ b/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php @@ -1,208 +1,227 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); if (!$this->id) { $this->id = $request->getInt('revisionID'); } if ($this->id) { $revision = id(new DifferentialRevision())->load($this->id); if (!$revision) { return new Aphront404Response(); } } else { $revision = new DifferentialRevision(); } $diff_id = $request->getInt('diffID'); if ($diff_id) { $diff = id(new DifferentialDiff())->load($diff_id); if (!$diff) { return new Aphront404Response(); } if ($diff->getRevisionID()) { // TODO: Redirect? throw new Exception("This diff is already attached to a revision!"); } } else { $diff = null; } $e_title = true; $e_testplan = true; $errors = array(); $revision->loadRelationships(); if ($request->isFormPost() && !$request->getStr('viaDiffView')) { $revision->setTitle($request->getStr('title')); $revision->setSummary($request->getStr('summary')); $revision->setTestPlan($request->getStr('testplan')); $revision->setBlameRevision($request->getStr('blame')); $revision->setRevertPlan($request->getStr('revert')); if (!strlen(trim($revision->getTitle()))) { $errors[] = 'You must provide a title.'; $e_title = 'Required'; } if (!strlen(trim($revision->getTestPlan()))) { $errors[] = 'You must provide a test plan.'; $e_testplan = 'Required'; } $user_phid = $request->getUser()->getPHID(); if (in_array($user_phid, $request->getArr('reviewers'))) { $errors[] = 'You may not review your own revision.'; } if (!$errors) { $editor = new DifferentialRevisionEditor($revision, $user_phid); if ($diff) { $editor->addDiff($diff, $request->getStr('comments')); } $editor->setCCPHIDs($request->getArr('cc')); $editor->setReviewers($request->getArr('reviewers')); $editor->save(); return id(new AphrontRedirectResponse()) ->setURI('/D'.$revision->getID()); } $reviewer_phids = $request->getArr('reviewers'); $cc_phids = $request->getArr('cc'); } else { $reviewer_phids = $revision->getReviewers(); $cc_phids = $revision->getCCPHIDs(); } $phids = array_merge($reviewer_phids, $cc_phids); $phids = array_unique($phids); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $handles = mpull($handles, 'getFullName', 'getPHID'); $reviewer_map = array_select_keys($handles, $reviewer_phids); $cc_map = array_select_keys($handles, $cc_phids); $form = new AphrontFormView(); $form->setUser($request->getUser()); if ($diff) { $form->addHiddenInput('diffID', $diff->getID()); } if ($revision->getID()) { $form->setAction('/differential/revision/edit/'.$revision->getID().'/'); } else { $form->setAction('/differential/revision/edit/'); } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } + if ($diff && $revision->getID()) { + $form + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Comments') + ->setName('comments') + ->setCaption("Explain what's new in this diff.") + ->setValue($request->getStr('comments'))) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Save')) + ->appendChild( + id(new AphrontFormDividerControl())); + } + $form ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Title') ->setName('title') ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) ->setValue($revision->getTitle()) ->setError($e_title)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Summary') ->setName('summary') ->setValue($revision->getSummary())) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Test Plan') ->setName('testplan') ->setValue($revision->getTestPlan()) ->setError($e_testplan)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Reviewers') ->setName('reviewers') ->setDatasource('/typeahead/common/users/') ->setValue($reviewer_map)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('CC') ->setName('cc') ->setDatasource('/typeahead/common/mailable/') ->setValue($cc_map)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Blame Revision') ->setName('blame') ->setValue($revision->getBlameRevision()) ->setCaption('Revision which broke the stuff which this '. 'change fixes.')) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Revert Plan') ->setName('revert') ->setValue($revision->getRevertPlan()) ->setCaption('Special steps required to safely revert this change.')); $submit = id(new AphrontFormSubmitControl()) ->setValue('Save'); if ($diff) { $submit->addCancelButton('/differential/diff/'.$diff->getID().'/'); } else { $submit->addCancelButton('/D'.$revision->getID()); } $form->appendChild($submit); $panel = new AphrontPanelView(); if ($revision->getID()) { - $panel->setHeader('Edit Differential Revision'); + if ($diff) { + $panel->setHeader('Update Differential Revision'); + } else { + $panel->setHeader('Edit Differential Revision'); + } } else { $panel->setHeader('Create New Differential Revision'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit Differential Revision', )); } } diff --git a/src/applications/differential/controller/revisionedit/__init__.php b/src/applications/differential/controller/revisionedit/__init__.php index 805b2c0977..456f221fef 100644 --- a/src/applications/differential/controller/revisionedit/__init__.php +++ b/src/applications/differential/controller/revisionedit/__init__.php @@ -1,25 +1,26 @@ revisionID = $data['id']; } public function processRequest() { $request = $this->getRequest(); $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { return new Aphront404Response(); } $revision->loadRelationships(); $diffs = $revision->loadDiffs(); $diff_vs = $request->getInt('vs'); $target = end($diffs); $diffs = mpull($diffs, null, 'getID'); if (empty($diffs[$diff_vs])) { $diff_vs = null; } list($changesets, $vs_map) = $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target); $comments = $revision->loadComments(); $comments = array_merge( $this->getImplicitComments($revision), $comments); $inlines = $this->loadInlineComments($comments, $changesets); $object_phids = array_merge( $revision->getReviewers(), $revision->getCCPHIDs(), array( $revision->getAuthorPHID(), $request->getUser()->getPHID(), ), mpull($comments, 'getAuthorPHID')); $object_phids = array_unique($object_phids); $handles = id(new PhabricatorObjectHandleData($object_phids)) ->loadHandles(); $revision_detail = new DifferentialRevisionDetailView(); $revision_detail->setRevision($revision); $properties = $this->getRevisionProperties($revision, $target, $handles); $revision_detail->setProperties($properties); $actions = $this->getRevisionActions($revision); $revision_detail->setActions($actions); $comment_view = new DifferentialRevisionCommentListView(); $comment_view->setComments($comments); $comment_view->setHandles($handles); $comment_view->setInlineComments($inlines); $comment_view->setChangesets($changesets); $diff_history = new DifferentialRevisionUpdateHistoryView(); $diff_history->setDiffs($diffs); $diff_history->setSelectedVersusDiffID($diff_vs); $diff_history->setSelectedDiffID($target->getID()); $toc_view = new DifferentialDiffTableOfContentsView(); $toc_view->setChangesets($changesets); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($changesets); $changeset_view->setEditable(true); $changeset_view->setRevision($revision); $changeset_view->setVsMap($vs_map); $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $comment_form->setActions($this->getRevisionCommentActions($revision)); $comment_form->setActionURI('/differential/comment/save/'); $comment_form->setUser($request->getUser()); return $this->buildStandardPageResponse( '
'. $revision_detail->render(). $comment_view->render(). $diff_history->render(). $toc_view->render(). $changeset_view->render(). $comment_form->render(). '
', array( 'title' => $revision->getTitle(), )); } private function getImplicitComments(DifferentialRevision $revision) { $template = new DifferentialComment(); $template->setAuthorPHID($revision->getAuthorPHID()); $template->setRevisionID($revision->getID()); $template->setDateCreated($revision->getDateCreated()); $comments = array(); if (strlen($revision->getSummary())) { $summary_comment = clone $template; $summary_comment->setContent($revision->getSummary()); $summary_comment->setAction(DifferentialAction::ACTION_SUMMARIZE); $comments[] = $summary_comment; } if (strlen($revision->getTestPlan())) { $testplan_comment = clone $template; $testplan_comment->setContent($revision->getTestPlan()); $testplan_comment->setAction(DifferentialAction::ACTION_TESTPLAN); $comments[] = $testplan_comment; } return $comments; } private function getRevisionProperties( DifferentialRevision $revision, DifferentialDiff $diff, array $handles) { $properties = array(); $status = $revision->getStatus(); $status = DifferentialRevisionStatus::getNameForRevisionStatus($status); $properties['Revision Status'] = ''.$status.''; $author = $handles[$revision->getAuthorPHID()]; $properties['Author'] = $author->renderLink(); $properties['Reviewers'] = $this->renderHandleLinkList( array_select_keys( $handles, $revision->getReviewers())); $properties['CCs'] = $this->renderHandleLinkList( array_select_keys( $handles, $revision->getCCPHIDs())); + $host = $diff->getSourceMachine(); + if ($host) { + $properties['Host'] = phutil_escape_html($host); + } + $path = $diff->getSourcePath(); if ($path) { - $branch = $diff->getBranch() ? ' (' . $diff->getBranch() . ')' : ''; - $host = $diff->getSourceMachine(); - if ($host) { - $host .= ':'; - } - $properties['Path'] = phutil_escape_html("{$host}{$path} {$branch}"); + $branch = $diff->getBranch() ? ' ('.$diff->getBranch().')' : ''; + $properties['Path'] = phutil_escape_html("{$path} {$branch}"); } + $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); + $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); + $properties['Lint'] = $lstar.' '.$lmsg; - $properties['Lint'] = 'TODO'; - $properties['Unit'] = 'TODO'; + $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff); + $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff); + $properties['Unit'] = $ustar.' '.$umsg; return $properties; } private function getRevisionActions(DifferentialRevision $revision) { $viewer_phid = $this->getRequest()->getUser()->getPHID(); $viewer_is_owner = ($revision->getAuthorPHID() == $viewer_phid); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); $viewer_is_cc = in_array($viewer_phid, $revision->getCCPHIDs()); $status = $revision->getStatus(); $revision_id = $revision->getID(); $revision_phid = $revision->getPHID(); $links = array(); if ($viewer_is_owner) { $links[] = array( 'class' => 'revision-edit', 'href' => "/differential/revision/edit/{$revision_id}/", 'name' => 'Edit Revision', ); } if (!$viewer_is_owner && !$viewer_is_reviewer) { $action = $viewer_is_cc ? 'rem' : 'add'; $links[] = array( 'class' => $viewer_is_cc ? 'subscribe-rem' : 'subscribe-add', 'href' => "/differential/subscribe/{$action}/{$revision_id}/", 'name' => $viewer_is_cc ? 'Unsubscribe' : 'Subscribe', ); } else { $links[] = array( 'class' => 'subscribe-rem unavailable', 'name' => 'Automatically Subscribed', ); } $links[] = array( 'class' => 'transcripts-metamta', 'name' => 'MetaMTA Transcripts', 'href' => "/mail/?phid={$revision_phid}", ); return $links; } private function renderHandleLinkList(array $list) { if (empty($list)) { return 'None'; } return implode(', ', mpull($list, 'renderLink')); } private function getRevisionCommentActions(DifferentialRevision $revision) { $actions = array( DifferentialAction::ACTION_COMMENT => true, ); $viewer_phid = $this->getRequest()->getUser()->getPHID(); $viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID()); if ($viewer_is_owner) { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ABANDON] = true; break; case DifferentialRevisionStatus::NEEDS_REVISION: case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; break; case DifferentialRevisionStatus::COMMITTED: break; case DifferentialRevisionStatus::ABANDONED: $actions[DifferentialAction::ACTION_RECLAIM] = true; break; } } else { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = true; break; case DifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ACCEPT] = true; break; case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_REJECT] = true; break; case DifferentialRevisionStatus::COMMITTED: case DifferentialRevisionStatus::ABANDONED: break; } } $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true; return array_keys($actions); } private function loadInlineComments(array $comments, array &$changesets) { $inline_comments = array(); $comment_ids = array_filter(mpull($comments, 'getID')); if (!$comment_ids) { return $inline_comments; } $inline_comments = id(new DifferentialInlineComment()) ->loadAllWhere( 'commentID in (%Ld)', $comment_ids); $load_changesets = array(); foreach ($inline_comments as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { continue; } $load_changesets[$changeset_id] = true; } $more_changesets = array(); if ($load_changesets) { $changeset_ids = array_keys($load_changesets); $more_changesets += id(new DifferentialChangeset()) ->loadAllWhere( 'id IN (%Ld)', $changeset_ids); } if ($more_changesets) { $changesets += $more_changesets; $changesets = msort($changesets, 'getSortKey'); } return $inline_comments; } private function loadChangesetsAndVsMap(array $diffs, $diff_vs, $target) { $load_ids = array(); if ($diff_vs) { $load_ids[] = $diff_vs; } $load_ids[] = $target->getID(); $raw_changesets = id(new DifferentialChangeset()) ->loadAllWhere( 'diffID IN (%Ld)', $load_ids); $changeset_groups = mgroup($raw_changesets, 'getDiffID'); $changesets = idx($changeset_groups, $target->getID(), array()); $changesets = mpull($changesets, null, 'getID'); $vs_map = array(); if ($diff_vs) { $vs_changesets = idx($changeset_groups, $diff_vs, array()); $vs_changesets = mpull($vs_changesets, null, 'getFilename'); foreach ($changesets as $key => $changeset) { $file = $changeset->getFilename(); if (isset($vs_changesets[$file])) { $vs_map[$changeset->getID()] = $vs_changesets[$file]->getID(); unset($vs_changesets[$file]); } } foreach ($vs_changesets as $changeset) { $changesets[$changeset->getID()] = $changeset; $vs_map[$changeset->getID()] = -1; } } $changesets = msort($changesets, 'getSortKey'); return array($changesets, $vs_map); } } /* protected function getRevisionActions(DifferentialRevision $revision) { $viewer_id = $this->getRequest()->getViewerContext()->getUserID(); $viewer_is_owner = ($viewer_id == $revision->getOwnerID()); $viewer_is_reviewer = ((array_search($viewer_id, $revision->getReviewers())) !== false); $viewer_is_cc = ((array_search($viewer_id, $revision->getCCFBIDs())) !== false); $status = $revision->getStatus(); $links = array(); if (!$viewer_is_owner && !$viewer_is_reviewer) { $action = $viewer_is_cc ? 'rem' : 'add'; $revision_id = $revision->getID(); $href = "/differential/subscribe/{$action}/{$revision_id}"; $links[] = array( $viewer_is_cc ? 'subscribe-disabled' : 'subscribe-enabled', {$viewer_is_cc ? 'Unsubscribe' : 'Subscribe'}, ); } else { $links[] = array( 'subscribe-disabled unavailable', Automatically Subscribed, ); } $blast_uri = RedirectURI( '/intern/differential/?action=tasks&fbid='.$revision->getFBID()) ->setTier('intern'); $links[] = array( 'tasks', Edit Tasks, ); $engineering_repository_id = RepositoryRef::getByCallsign('E')->getID(); $svn_revision = $revision->getSVNRevision(); if ($status == DifferentialConstants::COMMITTED && $svn_revision && $revision->getRepositoryID() == $engineering_repository_id) { $href = '/intern/push/request.php?rev='.$svn_revision; $href = RedirectURI($href)->setTier('intern'); $links[] = array( 'merge', Ask for Merge, ); } $links[] = array( 'herald-transcript', getFBID()} >Herald Transcripts, ); $links[] = array( 'metamta-transcript', getFBID()} >MetaMTA Transcripts, ); $list =
    ; foreach ($links as $link) { list($class, $tag) = $link; $list->appendChild(
  • {$tag}
  • ); } return $list; /* // TODO // $sandcastle = $this->getSandcastleURI($diff); // if ($sandcastle) { // $fields['Sandcastle'] = {$sandcastle}; // } $path = $diff->getSourcePath(); if ($path) { $host = $diff->getSourceMachine(); $branch = $diff->getGitBranch() ? ' (' . $diff->getGitBranch() . ')' : ''; if ($host) { // TODO // $user = $handles[$this->getRequest()->getViewerContext()->getUserID()] // ->getName(); $user = 'TODO'; $fields['Path'] = {$host}:{$path}{$branch} ; } else { $fields['Path'] = $path; } } $ccs = $revision->getCCFBIDs(); if ($ccs) { $links = array(); foreach ($ccs as $cc) { $links[] = ; } $fields['CCs'] = array_implode(', ', $links); } $blame_rev = $revision->getSvnBlameRevision(); if ($blame_rev) { if ($revision->getRepositoryRef() && is_numeric($blame_rev)) { $ref = new RevisionRef($revision->getRepositoryRef(), $blame_rev); $fields['Blame Revision'] = getDetailURL())}> {$ref->getName()} ; } else { $fields['Blame Revision'] = $blame_rev; } } $tasks = $revision->getTaskHandles(); if ($tasks) { $links = array(); foreach ($tasks as $task) { $links[] = ; } $fields['Tasks'] = array_implode(
    , $links); } $bugzilla_id = $revision->getBugzillaID(); if ($bugzilla_id) { $href = 'http://bugs.developers.facebook.com/show_bug.cgi?id='. $bugzilla_id; $fields['Bugzilla'] = {'#'.$bugzilla_id}; } $fields['Apply Patch'] = arc patch --revision {$revision->getID()}; if ($diff->getParentRevisionID()) { $parent = id(new DifferentialRevision())->load( $diff->getParentRevisionID()); if ($parent) { $fields['Depends On'] = getURI()}> D{$parent->getID()}: {$parent->getName()} ; } } $star = {"\xE2\x98\x85"}; Javelin::initBehavior('differential-star-more'); switch ($diff->getLinted()) { case Diff::LINT_FAIL: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Failures {$more} ; break; case Diff::LINT_WARNINGS: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Warnings {$more} ; break; case Diff::LINT_OKAY: $fields['Lint'] = {$star} Lint Free; break; default: case Diff::LINT_NO: $fields['Lint'] = {$star} Not Linted; break; } $unit_details = false; switch ($diff->getUnitTested()) { case Diff::UNIT_FAIL: $fields['Unit Tests'] = {$star} Unit Test Failures; $unit_details = true; break; case Diff::UNIT_WARN: $fields['Unit Tests'] = {$star} Unit Test Warnings; $unit_details = true; break; case Diff::UNIT_OKAY: $fields['Unit Tests'] = {$star} Unit Tests Passed; $unit_details = true; break; case Diff::UNIT_NO_TESTS: $fields['Unit Tests'] = {$star} No Test Coverage; break; case Diff::UNIT_NO: default: $fields['Unit Tests'] = {$star} Not Unit Tested; break; } if ($unit_details) { $fields['Unit Tests'] = {$fields['Unit Tests']} {$this->renderDiffPropertyMoreLink($diff, 'unit')} ; } $platform_impact = $revision->getPlatformImpact(); if ($platform_impact) { $fields['Platform Impact'] = {$platform_impact}; } return $fields; } } /* protected function getSandcastleURI(Diff $diff) { $uri = $this->getDiffProperty($diff, 'facebook:sandcastle_uri'); if (!$uri) { $uri = $diff->getSandboxURL(); } return $uri; } protected function getDiffProperty(Diff $diff, $property, $default = null) { $diff_id = $diff->getID(); if (empty($this->diffProperties[$diff_id])) { $props = id(new DifferentialDiffProperty()) ->loadAllWhere('diffID = %s', $diff_id); $dict = array_pull($props, 'getData', 'getName'); $this->diffProperties[$diff_id] = $dict; } return idx($this->diffProperties[$diff_id], $property, $default); } public function process() { $uri = $this->getRequest()->getPath(); if (starts_with($uri, '/d')) { return ; } $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { throw new Exception("Bad revision ID."); } $diffs = id(new Diff())->loadAllWhere( 'revisionID = %d', $revision->getID()); $diffs = array_psort($diffs, 'getID'); $request = $this->getRequest(); $new = $request->getInt('new'); $old = $request->getInt('old'); if (($new || $old) && $new <= $old) { throw new Exception( "You can only view the diff of an older update relative to a newer ". "update."); } if ($new && empty($diffs[$new])) { throw new Exception( "The 'new' diff does not exist."); } else if ($new) { $diff = $diffs[$new]; } else { $diff = end($diffs); if (!$diff) { throw new Exception("No diff attached to this revision?"); } $new = $diff->getID(); } $target_diff = $diff; if ($old && empty($diffs[$old])) { throw new Exception( "The 'old' diff does not exist."); } $rows = array(array('Base', '', true, false, null, $diff->getSourceControlBaseRevision() ? $diff->getSourceControlBaseRevision() : Master)); $idx = 0; foreach ($diffs as $cdiff) { $rows[] = array( 'Diff '.(++$idx), $cdiff->getID(), $cdiff->getID() != max(array_pull($diffs, 'getID')), true, $cdiff->getDateCreated(), $cdiff->getDescription() ? $cdiff->getDescription() : No description available., $cdiff->getUnitTested(), $cdiff->getLinted()); } $diff_table =
    Diff Diff ID Description Age Lint Unit
    ; $ii = 0; $old_ids = array(); foreach ($rows as $row) { $xold = null; if ($row[2]) { $lradio = = $new} checked={$old == $row[1]} />; if ($old == $row[1]) { $xold = 'old-now'; } $old_ids[] = $lradio->requireUniqueID(); } else { $lradio = null; } $xnew = null; if ($row[3]) { $rradio = ; if ($new == $row[1]) { $xnew = 'new-now'; } } else { $rradio = null; } if ($row[3]) { $unit_star = 'star-none'; switch ($row[6]) { case Diff::UNIT_FAIL: case Diff::UNIT_WARN: $unit_star = 'star-warn'; break; case Diff::UNIT_OKAY: $unit_star = 'star-okay'; break; } $lint_star = 'star-none'; switch ($row[7]) { case Diff::LINT_FAIL: case Diff::LINT_WARNINGS: $lint_star = 'star-warn'; break; case Diff::LINT_OKAY: $lint_star = 'star-okay'; break; } $star = "\xE2\x98\x85"; $unit_star = {$star} ; $lint_star = {$star} ; } else { $unit_star = null; $lint_star = null; } $diff_table->appendChild( {$row[0]} {$row[1]} {$row[5]} {$row[4] ? ago(time() - $row[4]) : null} {$lint_star} {$unit_star} {$lradio} {$rradio} ); } Javelin::initBehavior('differential-diff-radios', array( 'radios' => $old_ids, )); $diff_table->appendChild( {id('; return '
    '. '

    Revision Update History

    '. '
    '. ''. ''. ''. ''. ''. - ''. + ''. ''. ''. ''. implode("\n", $rows). ''. ''. ''. '
    DiffIDDescriptionAgeCreatedLintUnit
    '. ''. ''. '
    '. '
    '. '
    '; } + + const STAR_NONE = 'none'; + const STAR_OKAY = 'okay'; + const STAR_WARN = 'warn'; + const STAR_FAIL = 'fail'; + const STAR_SKIP = 'skip'; + + public static function renderDiffLintStar(DifferentialDiff $diff) { + static $map = array( + DifferentialLintStatus::LINT_NONE => self::STAR_NONE, + DifferentialLintStatus::LINT_OKAY => self::STAR_OKAY, + DifferentialLintStatus::LINT_WARN => self::STAR_WARN, + DifferentialLintStatus::LINT_FAIL => self::STAR_FAIL, + DifferentialLintStatus::LINT_SKIP => self::STAR_SKIP, + ); + + $star = idx($map, $diff->getLintStatus(), self::STAR_FAIL); + + return self::renderDiffStar($star); + } + + public static function renderDiffUnitStar(DifferentialDiff $diff) { + static $map = array( + DifferentialUnitStatus::UNIT_NONE => self::STAR_NONE, + DifferentialUnitStatus::UNIT_OKAY => self::STAR_OKAY, + DifferentialUnitStatus::UNIT_WARN => self::STAR_WARN, + DifferentialUnitStatus::UNIT_FAIL => self::STAR_FAIL, + DifferentialUnitStatus::UNIT_SKIP => self::STAR_SKIP, + ); + + $star = idx($map, $diff->getUnitStatus(), self::STAR_FAIL); + + return self::renderDiffStar($star); + } + + public static function getDiffLintMessage(DifferentialDiff $diff) { + switch ($diff->getLintStatus()) { + case DifferentialLintStatus::LINT_NONE: + return 'No Linters Available'; + case DifferentialLintStatus::LINT_OKAY: + return 'Lint OK'; + case DifferentialLintStatus::LINT_WARN: + return 'Lint Warnings'; + case DifferentialLintStatus::LINT_FAIL: + return 'Lint Errors'; + case DifferentialLintStatus::LINT_SKIP: + return 'Lint Skipped'; + } + return '???'; + } + + public static function getDiffUnitMessage(DifferentialDiff $diff) { + switch ($diff->getUnitStatus()) { + case DifferentialUnitStatus::UNIT_NONE: + return 'No Unit Test Coverage'; + case DifferentialUnitStatus::UNIT_OKAY: + return 'Unit Tests OK'; + case DifferentialUnitStatus::UNIT_WARN: + return 'Unit Test Warnings'; + case DifferentialUnitStatus::UNIT_FAIL: + return 'Unit Test Errors'; + case DifferentialUnitStatus::UNIT_SKIP: + return 'Unit Tests Skipped'; + } + return '???'; + } + + private static function renderDiffStar($star) { + $class = 'diff-star-'.$star; + return + ''. + "\xE2\x98\x85". + ''; + } + } diff --git a/src/applications/differential/view/revisionupdatehistory/__init__.php b/src/applications/differential/view/revisionupdatehistory/__init__.php index ab2bc66cee..ee163ad5cf 100644 --- a/src/applications/differential/view/revisionupdatehistory/__init__.php +++ b/src/applications/differential/view/revisionupdatehistory/__init__.php @@ -1,17 +1,21 @@ id = $data['id']; } public function processRequest() { $category = id(new PhabricatorDirectoryCategory())->load($this->id); if (!$category) { return new Aphront404Response(); } $request = $this->getRequest(); if ($request->isFormPost()) { $category->delete(); return id(new AphrontRedirectResponse()) ->setURI('/directory/category/'); } $dialog = new AphrontDialogView(); + $dialog->setUser($request->getUser()); $dialog->setTitle('Really delete this category?'); $dialog->appendChild("Are you sure you want to delete this category?"); $dialog->addSubmitButton('Delete'); $dialog->addCancelButton('/directory/category/'); $dialog->setSubmitURI($request->getPath()); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php b/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php index 076c73ced1..4c55f61246 100644 --- a/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php +++ b/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php @@ -1,51 +1,52 @@ id = $data['id']; } public function processRequest() { $item = id(new PhabricatorDirectoryItem())->load($this->id); if (!$item) { return new Aphront404Response(); } $request = $this->getRequest(); if ($request->isFormPost()) { $item->delete(); return id(new AphrontRedirectResponse()) ->setURI('/directory/item/'); } $dialog = new AphrontDialogView(); + $dialog->setUser($request->getUser()); $dialog->setTitle('Really delete this item?'); $dialog->appendChild("Are you sure you want to delete this item?"); $dialog->addSubmitButton('Delete'); $dialog->addCancelButton('/directory/item/'); $dialog->setSubmitURI($request->getPath()); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/xhprof/view/toplevel/PhabricatorXHProfProfileTopLevelView.php b/src/applications/xhprof/view/toplevel/PhabricatorXHProfProfileTopLevelView.php index ac6732802a..55d873bd2f 100644 --- a/src/applications/xhprof/view/toplevel/PhabricatorXHProfProfileTopLevelView.php +++ b/src/applications/xhprof/view/toplevel/PhabricatorXHProfProfileTopLevelView.php @@ -1,124 +1,125 @@ profileData = $data; return $this; } public function setLimit($limit) { $this->limit = $limit; return $this; } public function setBaseURI($uri) { $this->baseURI = $uri; return $this; } public function render() { DarkConsoleXHProfPluginAPI::includeXHProfLib(); $GLOBALS['display_calls'] = true; $totals = array(); $flat = xhprof_compute_flat_info($this->profileData, $totals); unset($GLOBALS['display_calls']); $aggregated = array(); foreach ($flat as $call => $counters) { - $agg_call = reset(explode('@', $call, 2)); + $parts = explode('@', $call, 2); + $agg_call = reset($parts); if (empty($aggregated[$agg_call])) { $aggregated[$agg_call] = $counters; } else { foreach ($aggregated[$agg_call] as $key => $val) { if ($key != 'wt') { $aggregated[$agg_call][$key] += $counters[$key]; } } } } $flat = $aggregated; $flat = isort($flat, 'wt'); $flat = array_reverse($flat); $rows = array(); $rows[] = array( 'Total', number_format($totals['ct']), number_format($totals['wt']).' us', '100.0%', number_format($totals['wt']).' us', '100.0%', ); if ($this->limit) { $flat = array_slice($flat, 0, $this->limit); } $base_uri = $this->baseURI; foreach ($flat as $call => $counters) { $rows[] = array( phutil_render_tag( 'a', array( 'href' => $base_uri.'?symbol='.$call, ), phutil_escape_html($call)), number_format($counters['ct']), number_format($counters['wt']).' us', sprintf('%.1f%%', 100 * $counters['wt'] / $totals['wt']), number_format($counters['excl_wt']).' us', sprintf('%.1f%%', 100 * $counters['excl_wt'] / $totals['wt']), ); } $table = new AphrontTableView($rows); $table->setHeaders( array( 'Symbol', 'Count', 'Incl Wall Time', '%', 'Excl Wall Time', '%', )); $table->setColumnClasses( array( 'wide pri', 'n', 'n', 'n', 'n', 'n', )); $panel = new AphrontPanelView(); $panel->setHeader('XHProf Profile'); $panel->appendChild($table); return $panel->render(); } } diff --git a/src/view/dialog/AphrontDialogView.php b/src/view/dialog/AphrontDialogView.php index 83433b88b1..510574b9db 100755 --- a/src/view/dialog/AphrontDialogView.php +++ b/src/view/dialog/AphrontDialogView.php @@ -1,126 +1,129 @@ user = $user; return $this; } public function setSubmitURI($uri) { $this->submitURI = $uri; return $this; } public function setTitle($title) { $this->title = $title; return $this; } public function getTitle() { return $this->title; } public function addSubmitButton($text = 'Okay') { $this->submitButton = $text; return $this; } public function addCancelButton($uri) { $this->cancelURI = $uri; return $this; } public function addHiddenInput($key, $value) { $this->hidden[$key] = $value; return $this; } final public function render() { require_celerity_resource('aphront-dialog-view-css'); $buttons = array(); if ($this->submitButton) { - $buttons[] = - ''; + $buttons[] = phutil_render_tag( + 'button', + array( + 'name' => '__submit__', + 'sigil' => '__default__', + ), + phutil_escape_html($this->submitButton)); } if ($this->cancelURI) { $buttons[] = javelin_render_tag( 'a', array( 'href' => $this->cancelURI, 'class' => 'button grey', 'name' => '__cancel__', 'sigil' => 'jx-workflow-button', ), 'Cancel'); } if (!$this->user) { throw new Exception( "You must call setUser() when rendering an AphrontDialogView."); } $csrf = $this->user->getCSRFToken(); $hidden_inputs = array(); foreach ($this->hidden as $key => $value) { $hidden_inputs[] = phutil_render_tag( 'input', array( 'type' => 'hidden', 'name' => $key, 'value' => $value, )); } $hidden_inputs = implode("\n", $hidden_inputs); return javelin_render_tag( 'form', array( 'class' => 'aphront-dialog-view', 'action' => $this->submitURI, 'method' => 'post', 'sigil' => 'jx-dialog', ), ''. ''. $hidden_inputs. '
    '. phutil_escape_html($this->title). '
    '. '
    '. $this->renderChildren(). '
    '. '
    '. implode('', $buttons). '
    '. '
    '); } } diff --git a/src/view/form/control/divider/AphrontFormDividerControl.php b/src/view/form/control/divider/AphrontFormDividerControl.php new file mode 100755 index 0000000000..31c6dd81fc --- /dev/null +++ b/src/view/form/control/divider/AphrontFormDividerControl.php @@ -0,0 +1,29 @@ +'; + } + +} diff --git a/src/view/form/control/divider/__init__.php b/src/view/form/control/divider/__init__.php new file mode 100644 index 0000000000..4e96679f5c --- /dev/null +++ b/src/view/form/control/divider/__init__.php @@ -0,0 +1,12 @@ + $scale && count($labels)) { $remainder += ($n % $scale) * $accum; $n /= $scale; $accum *= $scale; $label = array_shift($labels); if (!count($scales)) { break; } $scale = array_shift($scales); } if ($is_negative) { $n = -$n; $remainder = -$remainder; } if ($precision) { $num_string = number_format($n, $precision); } else { $num_string = (int)floor($n); } if ($label) { $num_string .= ' '.$label; } return $num_string; } diff --git a/webroot/rsrc/css/application/differential/changeset-view.css b/webroot/rsrc/css/application/differential/changeset-view.css index de9fa3004d..aaa5e7ae4a 100644 --- a/webroot/rsrc/css/application/differential/changeset-view.css +++ b/webroot/rsrc/css/application/differential/changeset-view.css @@ -1,166 +1,172 @@ /** * @provides differential-changeset-view-css */ .differential-diff { background: #ffffff; font-family: "Menlo", "Consolas", "Monaco", monospace; font-size: 10px; width: 100%; } .differential-diff td { /* using monospace fonts makes ex/em most useful: * * Unfortunately, firefox 3.6 renders diffs columns for added and removed * files "way-too-wide" when given em as the dimension measurement, so we * use an eyeballed ex equivalent and reset it to the ch character width * measurement for browsers that support that css3 measurement. */ width: 88ex; width: 81ch; /* Disable ligatures in Firefox. Firefox 3 has fancypants ligature support, but it gets applied to monospaced fonts, which sucks because it means that the "fi" ligature only takes up one character, e.g. It's probably the font's fault that it even specifies ligatures (seriously, what the hell?) but that's hard to fix and this is "easy" to "fix": custom letter spacing disables ligatures, as long as it's at least 0.008333-repeating pixels of custom letter spacing. I have no idea where this number comes from, but note that .83333.. = 5/6. -epriestley */ letter-spacing: 0.0083334px; vertical-align: top; white-space: pre; padding: 0 8px 1px; line-height: 16px; overflow: hidden; } .differential-diff th { text-align: right; padding: 2px 6px; width: 44px; vertical-align: top; background: #eeeeee; color: #888888; cursor: pointer; border-style: solid; border-width: 0px 1px; border-color: #eeeeee #999999 #eeeeee #dddddd; font-weight: bold; font-family: "Verdana"; font-size: 11px; overflow: hidden; } .differential-diff td.old { background: #ffd0d0; color: #161111; } .differential-diff td.new { background: #d0ffd0; color: #111611; } .differential-diff td.old-full, .differential-diff td.old span.bright { background: #ffaaaa; color: #221111; } .differential-diff td.new-full, .differential-diff td.new span.bright { background: #aaffaa; color: #112211; } .differential-diff td.show-more, .differential-diff td.differential-shield { background: #ffffee; padding: 1em; text-align: center; font-family: "Verdana"; font-size: 11px; border: 1px solid #ccccaa; white-space: normal; } .differential-diff td.show-more { color: #999966; } .differential-diff td.differential-shield { text-align: center; max-width: 1160px; } .differential-diff td.differential-shield a { font-weight: bold; } .differential-meta-notice { border: 1px solid #ffdd99; background: #ffeeaa; font-family: "Verdana"; font-size: 11px; padding: 1em; margin: 0 0 6px 0; } .differential-changeset h1 { font-size: 14px; font-weight: bold; padding: 2px 0 8px; } .differential-changeset { margin: 0.5em 0; padding: 10px 0px 20px; } .differential-reticle { background: #ffeeaa; border: 1px solid #ffcc00; position: absolute; z-index: 2; opacity: 0.5; top: 0px; left: 0px; } .differential-inline-comment { background: #f9f9f1; border: 1px solid #aaaa88; font-family: Verdana; font-size: 11px; margin: 4px 0px; max-width: 81ch; padding: 8px 10px; width: 100%; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } .differential-inline-comment-head { font-weight: bold; color: #333333; border-bottom: 1px solid #ccccaa; padding-bottom: 6px; margin-bottom: 4px; } .differential-inline-comment-links, .differential-inline-comment-line { font-weight: normal; font-style: italic; color: #666666; float: right; white-space: nowrap; } .differential-inline-comment-links { margin-left: 8px; font-style: normal; } + + +.differential-inline-comment-edit-textarea { + width: 100%; + height: 12em; +} diff --git a/webroot/rsrc/css/application/differential/table-of-contents.css b/webroot/rsrc/css/application/differential/table-of-contents.css index c79d38a955..06d459e015 100644 --- a/webroot/rsrc/css/application/differential/table-of-contents.css +++ b/webroot/rsrc/css/application/differential/table-of-contents.css @@ -1,25 +1,47 @@ /** * @provides differential-table-of-contents-css */ .differential-toc-meta { color: #666666; padding-left: 1em; } .differential-toc-char, .differential-toc-prop { width: 1.25em; text-align: center; font-weight: bold; } .differential-toc-ftype { padding: 0 .5em; text-align: center; color: #666666; } .differential-toc-file { color: #444444; } + +.diff-star-none { + color: #666666; +} + +.diff-star-okay { + color: #ff9700; +} + +/* TODO: 'warn' and 'fail' are both red, but we can't make 'warn' yellow since + 'okay' is a "gold star". */ +.diff-star-warn { + color: #aa0000; +} + +.diff-star-fail { + color: #aa0000; +} + +.diff-star-skip { + color: #ff00aa; +} diff --git a/webroot/rsrc/js/javelin/workflow.dev.js b/webroot/rsrc/js/javelin/workflow.dev.js index 94710abf32..a7f4a5b29b 100644 --- a/webroot/rsrc/js/javelin/workflow.dev.js +++ b/webroot/rsrc/js/javelin/workflow.dev.js @@ -1,240 +1,242 @@ /** @provides javelin-workflow-dev */ /** * @requires javelin-install javelin-vector javelin-dom * @provides javelin-mask * @javelin */ /** * Show a transparent "mask" over the page; used by Workflow to draw visual * attention to modal dialogs. */ JX.install('Mask', { statics : { _depth : 0, _mask : null, show : function() { if (!JX.Mask._depth) { JX.Mask._mask = JX.$N('div', {className: 'jx-mask'}); document.body.appendChild(JX.Mask._mask); JX.$V.getDocument().setDim(JX.Mask._mask); } ++JX.Mask._depth; }, hide : function() { --JX.Mask._depth; if (!JX.Mask._depth) { JX.DOM.remove(JX.Mask._mask); JX.Mask._mask = null; } } } }); /** * @requires javelin-stratcom * javelin-request * javelin-dom * javelin-vector * javelin-install * javelin-util * javelin-mask * @provides javelin-workflow * @javelin */ JX.install('Workflow', { construct : function(uri, data) { if (__DEV__) { if (!uri || uri == '#') { throw new Error( 'new JX.Workflow(, ...): '+ 'bogus URI provided when creating workflow.'); } } this.setURI(uri); this.setData(data || {}); }, events : ['error', 'finally', 'submit'], statics : { _stack : [], newFromForm : function(form, data) { var inputs = [].concat( JX.DOM.scry(form, 'input'), JX.DOM.scry(form, 'button'), JX.DOM.scry(form, 'textarea')); for (var ii = 0; ii < inputs.length; ii++) { if (inputs[ii].disabled) { delete inputs[ii]; } else { inputs[ii].disabled = true; } } var workflow = new JX.Workflow( form.getAttribute('action'), JX.copy(data || {}, JX.DOM.serialize(form))); workflow.setMethod(form.getAttribute('method')); workflow.listen('finally', function() { for (var ii = 0; ii < inputs.length; ii++) { inputs[ii] && (inputs[ii].disabled = false); } }); return workflow; }, newFromLink : function(link) { var workflow = new JX.Workflow(link.href); return workflow; }, _push : function(workflow) { JX.Mask.show(); JX.Workflow._stack.push(workflow); }, _pop : function() { var dialog = JX.Workflow._stack.pop(); (dialog.getCloseHandler() || JX.bag)(); dialog._destroy(); JX.Mask.hide(); }, disable : function() { JX.Workflow._disabled = true; }, _onbutton : function(event) { if (JX.Stratcom.pass()) { return; } if (JX.Workflow._disabled) { return; } var t = event.getTarget(); if (t.name == '__cancel__' || t.name == '__close__') { JX.Workflow._pop(); } else { var form = event.getNode('jx-dialog'); var data = JX.DOM.serialize(form); data[t.name] = true; data.__wflow__ = true; var active = JX.Workflow._stack[JX.Workflow._stack.length - 1]; var e = active.invoke('submit', {form: form, data: data}); if (!e.getStopped()) { active._destroy(); active .setURI(form.getAttribute('action') || active.getURI()) .setData(data) .start(); } } event.prevent(); } }, members : { _root : null, _pushed : false, _onload : function(r) { // It is permissible to send back a falsey redirect to force a page // reload, so we need to take this branch if the key is present. if (r && (typeof r.redirect != 'undefined')) { JX.go(r.redirect, true); } else if (r && r.dialog) { this._push(); this._root = JX.$N( 'div', {className: 'jx-client-dialog'}, JX.HTML(r.dialog)); JX.DOM.listen( this._root, 'click', [['jx-workflow-button'], ['tag:button']], JX.Workflow._onbutton); document.body.appendChild(this._root); var d = JX.$V.getDim(this._root); var v = JX.$V.getViewport(); var s = JX.$V.getScroll(); JX.$V((v.x - d.x) / 2, s.y + 100).setPos(this._root); try { - JX.DOM.focus(JX.DOM.find(this._root, 'button', '__default__')); + try { + JX.DOM.focus(JX.DOM.find(this._root, 'button', '__default__')); + } catch (_ignored) {} var inputs = JX.DOM.scry(this._root, 'input') .concat(JX.DOM.scry(this._root, 'textarea')); var miny = Number.POSITIVE_INFINITY; var target = null; for (var ii = 0; ii < inputs.length; ++ii) { if (inputs[ii].type != 'hidden') { // Find the topleft-most displayed element. var p = JX.$V(inputs[ii]); if (p.y < miny) { miny = p.y; target = inputs[ii]; } } } target && JX.DOM.focus(target); } catch (_ignored) {} } else if (this.getHandler()) { this.getHandler()(r); this._pop(); } else if (r) { if (__DEV__) { throw new Error('Response to workflow request went unhandled.'); } } }, _push : function() { if (!this._pushed) { this._pushed = true; JX.Workflow._push(this); } }, _pop : function() { if (this._pushed) { this._pushed = false; JX.Workflow._pop(); } }, _destroy : function() { if (this._root) { JX.DOM.remove(this._root); this._root = null; } }, start : function() { var uri = this.getURI(); var method = this.getMethod(); var r = new JX.Request(uri, JX.bind(this, this._onload)); r.setData(this.getData()); r.setDataSerializer(this.getDataSerializer()); if (method) { r.setMethod(method); } r.listen('finally', JX.bind(this, this.invoke, 'finally')); r.listen('error', JX.bind(this, function(error) { var e = this.invoke('error', error); if (e.getStopped()) { return; } // TODO: Default error behavior? On Facebook Lite, we just shipped the // user to "/error/". We could emit a blanket 'workflow-failed' type // event instead. })); r.send(); } }, properties : { handler : null, closeHandler : null, data : null, dataSerializer : null, method : null, URI : null } });