diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index fb8ecbb0c1..07f979a06f 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1,138 +1,154 @@ array( - 'path' => '/res/2ef90210/rsrc/css/aphront/dialog-view.css', + 'path' => '/res/771b987d/rsrc/css/aphront/dialog-view.css', 'type' => 'css', 'requires' => array( ), ), 'aphront-form-view-css' => array( - 'path' => '/res/517031e5/rsrc/css/aphront/form-view.css', + 'path' => '/res/20ebc99b/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( ), ), 'aphront-panel-view-css' => array( - 'path' => '/res/d96d5826/rsrc/css/aphront/panel-view.css', + 'path' => '/res/d1ce0c3d/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( ), ), 'aphront-side-nav-view-css' => array( - 'path' => '/res/89b99d7d/rsrc/css/aphront/side-nav-view.css', + 'path' => '/res/1a16f19a/rsrc/css/aphront/side-nav-view.css', 'type' => 'css', 'requires' => array( ), ), 'aphront-table-view-css' => array( - 'path' => '/res/639b3af2/rsrc/css/aphront/table-view.css', + 'path' => '/res/52b0191f/rsrc/css/aphront/table-view.css', 'type' => 'css', 'requires' => array( ), ), 'phabricator-standard-page-view' => array( - 'path' => '/res/f1a74aa4/rsrc/css/application/base/standard-page-view.css', + 'path' => '/res/0eef6905/rsrc/css/application/base/standard-page-view.css', 'type' => 'css', 'requires' => array( ), ), 'differential-changeset-view-css' => array( - 'path' => '/res/08a5c816/rsrc/css/application/differential/changeset-view.css', + 'path' => '/res/921d3a0c/rsrc/css/application/differential/changeset-view.css', 'type' => 'css', 'requires' => array( ), ), 'differential-core-view-css' => array( 'path' => '/res/f750b85d/rsrc/css/application/differential/core.css', 'type' => 'css', 'requires' => array( ), ), 'differential-table-of-contents-css' => array( - 'path' => '/res/cd5c966d/rsrc/css/application/differential/table-of-contents.css', + 'path' => '/res/ebf6641c/rsrc/css/application/differential/table-of-contents.css', 'type' => 'css', 'requires' => array( ), ), 'phabricator-directory-css' => array( - 'path' => '/res/795c7b4e/rsrc/css/application/directory/phabricator-directory.css', + 'path' => '/res/6a000601/rsrc/css/application/directory/phabricator-directory.css', 'type' => 'css', 'requires' => array( ), ), 'phabricator-core-buttons-css' => array( - 'path' => '/res/5f44fe89/rsrc/css/core/buttons.css', + 'path' => '/res/6e348ba4/rsrc/css/core/buttons.css', 'type' => 'css', 'requires' => array( ), ), 'phabricator-core-css' => array( 'path' => '/res/39ce37c2/rsrc/css/core/core.css', 'type' => 'css', 'requires' => array( ), ), + 'syntax-highlighting-css' => + array( + 'path' => '/res/fb673ece/rsrc/css/core/syntax.css', + 'type' => 'css', + 'requires' => + array( + ), + ), + 'javelin-behavior-differential-populate' => + array( + 'path' => '/res/b419291a/rsrc/js/application/differential/behavior-populate.js', + 'type' => 'js', + 'requires' => + array( + ), + ), 'javelin-init-dev' => array( 'path' => '/res/c57a9e89/rsrc/js/javelin/init.dev.js', 'type' => 'js', 'requires' => array( ), ), 'javelin-init-prod' => array( 'path' => '/res/f0172c54/rsrc/js/javelin/init.min.js', 'type' => 'js', 'requires' => array( ), ), 'javelin-lib-dev' => array( 'path' => '/res/3e747182/rsrc/js/javelin/javelin.dev.js', 'type' => 'js', 'requires' => array( ), ), 'javelin-lib-prod' => array( 'path' => '/res/9438670e/rsrc/js/javelin/javelin.min.js', 'type' => 'js', 'requires' => array( ), ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e663af492f..a413bd6734 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,233 +1,240 @@ array( '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', 'AphrontFileResponse' => 'aphront/response/file', 'AphrontFormControl' => 'view/form/control/base', 'AphrontFormFileControl' => 'view/form/control/file', 'AphrontFormMarkupControl' => 'view/form/control/markup', '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', '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', 'AphrontQueryException' => 'storage/exception/base', 'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing', 'AphrontQueryParameterException' => 'storage/exception/parameter', 'AphrontQueryRecoverableException' => 'storage/exception/recoverable', 'AphrontRedirectResponse' => 'aphront/response/redirect', 'AphrontRequest' => 'aphront/request', 'AphrontResponse' => 'aphront/response/base', 'AphrontSideNavView' => 'view/layout/sidenav', 'AphrontTableView' => 'view/control/table', 'AphrontURIMapper' => 'aphront/mapper', 'AphrontView' => 'view/base', 'AphrontWebpageResponse' => 'aphront/response/webpage', 'CelerityAPI' => 'infratructure/celerity/api', 'CelerityResourceController' => 'infratructure/celerity/controller', 'CelerityResourceMap' => 'infratructure/celerity/map', 'CelerityStaticResourceResponse' => 'infratructure/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', 'DifferentialAction' => 'applications/differential/constants/action', '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', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', 'DifferentialDiff' => 'applications/differential/storage/diff', 'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialRevision' => 'applications/differential/storage/revision', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem', 'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', + 'Javelin' => 'infratructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', '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', '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', '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', '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', 'PhabricatorUser' => 'applications/people/storage/user', 'PhabricatorUserDAO' => 'applications/people/storage/base', ), 'function' => array( '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', + 'celerity_gen_unique_node_id' => 'infratructure/celerity/api', 'celerity_register_resource_map' => 'infratructure/celerity/map', + 'javelin_render_tag' => 'infratructure/javelin/markup', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', 'queryfx_one' => 'storage/queryfx', 'require_celerity_resource' => 'infratructure/celerity/api', 'vqsprintf' => 'storage/qsprintf', 'vqueryfx' => 'storage/queryfx', 'xsprintf_query' => 'storage/qsprintf', ), 'requires_class' => array( 'Aphront404Response' => 'AphrontResponse', + 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormControl' => 'AphrontView', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontNullView' => 'AphrontView', 'AphrontPageView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontQueryConnectionException' => 'AphrontQueryException', 'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException', 'AphrontQueryCountException' => 'AphrontQueryException', 'AphrontQueryObjectMissingException' => 'AphrontQueryException', 'AphrontQueryParameterException' => 'AphrontQueryException', 'AphrontQueryRecoverableException' => 'AphrontQueryException', 'AphrontRedirectResponse' => 'AphrontResponse', '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', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', + 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialRevision' => 'DifferentialDAO', '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', 'PhabricatorFile' => 'PhabricatorFileDAO', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileViewController' => 'PhabricatorFileController', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorPHID' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController', 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorUser' => 'PhabricatorUserDAO', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', ), 'requires_interface' => array( ), )); diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index d6f7168334..67f624a94f 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -1,138 +1,138 @@ 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( '$' => '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', '/differential/' => array( 'diff/(?\d+)/$' => 'DifferentialDiffViewController', 'changeset/(?\d+)/$' => 'DifferentialChangesetViewController', ), '/res/' => array( - '(?[a-f0-9]{8})/(?[^.]+\.(?:css|js))$' + '(?[a-f0-9]{8})/(?.+\.(?:css|js))$' => 'CelerityResourceController', ), '.*' => 'AphrontDefaultApplicationController', ); } public function buildRequest() { $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($_GET + $_POST); 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->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->appendChild( '
'. $response->buildResponseString(). '
'); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } } return $response; } } diff --git a/src/infratructure/celerity/api/CelerityAPI.php b/src/aphront/response/ajax/AphrontAjaxResponse.php similarity index 54% copy from src/infratructure/celerity/api/CelerityAPI.php copy to src/aphront/response/ajax/AphrontAjaxResponse.php index 77ba73f10c..959e2cfc1d 100644 --- a/src/infratructure/celerity/api/CelerityAPI.php +++ b/src/aphront/response/ajax/AphrontAjaxResponse.php @@ -1,35 +1,45 @@ content = $content; + return $this; } -} + public function buildResponseString() { + $response = CelerityAPI::getStaticResourceResponse(); + return $response->renderAjaxResponse( + $this->content, + $this->error); + } + + public function getHeaders() { + return array( + array('Content-Type', 'text/plain; charset=UTF-8'), + ); + } -function require_celerity_resource($symbol) { - $response = CelerityAPI::getStaticResourceResponse(); - $response->requireResource($symbol); } diff --git a/src/aphront/response/ajax/__init__.php b/src/aphront/response/ajax/__init__.php new file mode 100644 index 0000000000..c0dd276bb7 --- /dev/null +++ b/src/aphront/response/ajax/__init__.php @@ -0,0 +1,13 @@ +id = $data['id']; } public function processRequest() { $changeset = id(new DifferentialChangeset())->load($this->id); if (!$changeset) { return new Aphront404Response(); } $changeset->attachHunks($changeset->loadHunks()); $parser = new DifferentialChangesetParser(); $parser->setChangeset($changeset); $output = $parser->render(); + $request = $this->getRequest(); + if ($request->isAjax()) { + return id(new AphrontAjaxResponse()) + ->setContent($output); + } + + $detail = new DifferentialChangesetDetailView(); + $detail->setChangeset($changeset); + $detail->appendChild($output); + // TODO: This is a bit of a hacky mess. $output = '
'. '
'. '
'. - '

'.phutil_escape_html($changeset->getDisplayFilename()).'

'. - '
'. - $output. + $detail->render(). '
'. '
'. '
'; return $this->buildStandardPageResponse( array( $output ), array( 'title' => 'Changeset View', )); } } diff --git a/src/applications/differential/controller/changesetview/__init__.php b/src/applications/differential/controller/changesetview/__init__.php index 8090d629af..f872d3acbd 100644 --- a/src/applications/differential/controller/changesetview/__init__.php +++ b/src/applications/differential/controller/changesetview/__init__.php @@ -1,18 +1,19 @@ id = $data['id']; } public function processRequest() { $diff = id(new DifferentialDiff())->load($this->id); if (!$diff) { return new Aphront404Response(); } $changesets = $diff->loadChangesets(); $changesets = msort($changesets, 'getSortKey'); $table_of_contents = id(new DifferentialDiffTableOfContentsView()) ->setChangesets($changesets); - $details = id(new DifferentialChangesetDetailView()) + $details = id(new DifferentialChangesetListView()) ->setChangesets($changesets); return $this->buildStandardPageResponse( array( $table_of_contents, $details, ), array( 'title' => 'Diff View', )); } } diff --git a/src/applications/differential/controller/diffview/__init__.php b/src/applications/differential/controller/diffview/__init__.php index 5a2715daa8..7303dd9ed7 100644 --- a/src/applications/differential/controller/diffview/__init__.php +++ b/src/applications/differential/controller/diffview/__init__.php @@ -1,17 +1,18 @@ changesets = $changesets; + public function setChangeset($changeset) { + $this->changeset = $changeset; return $this; } - public function render() { - $against = array(); // TODO - $edit = false; - - $changesets = $this->changesets; - foreach ($changesets as $key => $changeset) { - if (empty($against[$changeset->getID()])) { - $type = $changeset->getChangeType(); - if ($type == DifferentialChangeType::TYPE_MOVE_AWAY || - $type == DifferentialChangeType::TYPE_MULTICOPY) { - unset($changesets[$key]); - } - } - } - - $output = array(); - $mapping = array(); - foreach ($changesets as $key => $changeset) { - $file = $changeset->getFilename(); - $class = 'differential-changeset'; - if (!$edit) { - $class .= ' differential-changeset-noneditable'; - } - $id = $changeset->getID(); - if ($id) { - $against_id = idx($against, $id); - } else { - $against_id = null; - } - -/* - $detail_uri = URI($render_uri) - ->addQueryData(array( - 'changeset' => $id, - 'against' => $against_id, - 'whitespace' => $whitespace, - )); -*/ - $detail_uri = '/differential/changeset/'.$changeset->getID().'/'; - - $detail = phutil_render_tag( - 'a', - array( - 'style' => 'float: right', - 'class' => 'button small grey', - 'href' => $detail_uri, - 'target' => '_blank', - ), - 'Standalone View'); - -// $div =
Loading…
; + public function addButton($button) { + $this->buttons[] = $button; + return $this; + } - $display_filename = $changeset->getDisplayFilename(); - $output[] = - '
'. - '

'.$detail.phutil_escape_html($display_filename).'

'. - '
Loading...
'. - '
'; + public function render() { + require_celerity_resource('differential-changeset-view-css'); + require_celerity_resource('syntax-highlighting-css'); -/* -
getID()}> - {$detail} -

{$file}

- {$div} -
; -*/ -/* - $mapping[$div->requireUniqueId()] = array_filter( - array( - $changeset->getID(), - idx($against, $changeset->getID()), - )); + $edit = false; // TODO -*/ + $changeset = $this->changeset; + $class = 'differential-changeset'; + if (!$edit) { + $class .= ' differential-changeset-immutable'; } -/* - require_static('differential-diff-css'); - require_static('differential-syntax-css'); - - Javelin::initBehavior('differential-populate', array( - 'registry' => $mapping, - 'whitespace' => $whitespace, - 'uri' => $render_uri, - )); - Javelin::initBehavior('differential-context', array( - 'uri' => $render_uri, - )); - - if ($edit) { - require_static('remarkup-css'); - Javelin::initBehavior('differential-inline', array( - 'uri' => '/differential/feedback/'.$revision->getID().'/', - )); - } -*/ - return - '
'. - implode("\n", $output). - '
'; + $display_filename = $changeset->getDisplayFilename(); + $output = javelin_render_tag( + 'div', + array( + 'sigil' => 'differential-changeset', + 'class' => $class, + ), + '
'. + implode('', $this->buttons). + '

'.phutil_escape_html($display_filename).'

'. + '
'. + $this->renderChildren()); + + return $output; } } diff --git a/src/applications/differential/view/changesetdetailview/__init__.php b/src/applications/differential/view/changesetdetailview/__init__.php index 51175da167..575d0c87f4 100644 --- a/src/applications/differential/view/changesetdetailview/__init__.php +++ b/src/applications/differential/view/changesetdetailview/__init__.php @@ -1,16 +1,16 @@ changesets = $changesets; return $this; } public function render() { + require_celerity_resource('differential-changeset-view-css'); + $against = array(); // TODO $edit = false; $changesets = $this->changesets; foreach ($changesets as $key => $changeset) { if (empty($against[$changeset->getID()])) { $type = $changeset->getChangeType(); if ($type == DifferentialChangeType::TYPE_MOVE_AWAY || $type == DifferentialChangeType::TYPE_MULTICOPY) { unset($changesets[$key]); } } } $output = array(); $mapping = array(); foreach ($changesets as $key => $changeset) { $file = $changeset->getFilename(); $class = 'differential-changeset'; if (!$edit) { $class .= ' differential-changeset-noneditable'; } $id = $changeset->getID(); if ($id) { $against_id = idx($against, $id); } else { $against_id = null; } /* + TODO $detail_uri = URI($render_uri) ->addQueryData(array( 'changeset' => $id, 'against' => $against_id, 'whitespace' => $whitespace, )); */ $detail_uri = '/differential/changeset/'.$changeset->getID().'/'; - $detail = phutil_render_tag( + $detail_button = phutil_render_tag( 'a', array( 'style' => 'float: right', 'class' => 'button small grey', 'href' => $detail_uri, 'target' => '_blank', ), 'Standalone View'); -// $div =
Loading…
; - - $display_filename = $changeset->getDisplayFilename(); - $output[] = - '
'. - '

'.$detail.phutil_escape_html($display_filename).'

'. - '
Loading...
'. - '
'; - -/* -
getID()}> - {$detail} -

{$file}

- {$div} -
; -*/ -/* - $mapping[$div->requireUniqueId()] = array_filter( - array( - $changeset->getID(), - idx($against, $changeset->getID()), - )); - -*/ + $uniq_id = celerity_generate_unique_node_id(); + + $detail = new DifferentialChangesetDetailView(); + $detail->setChangeset($changeset); + $detail->addButton($detail_button); + $detail->appendChild( + phutil_render_tag( + 'div', + array( + 'id' => $uniq_id, + ), + '
Loading...
')); + $output[] = $detail->render(); + + $mapping[$uniq_id] = array($changeset->getID()); } -/* - require_static('differential-diff-css'); - require_static('differential-syntax-css'); + $whitespace = null; Javelin::initBehavior('differential-populate', array( 'registry' => $mapping, 'whitespace' => $whitespace, - 'uri' => $render_uri, + 'uri' => '/differential/changeset/',//$render_uri, )); + +/* + + Javelin::initBehavior('differential-context', array( 'uri' => $render_uri, )); if ($edit) { require_static('remarkup-css'); Javelin::initBehavior('differential-inline', array( 'uri' => '/differential/feedback/'.$revision->getID().'/', )); } */ return '
'. implode("\n", $output). '
'; } } diff --git a/src/applications/differential/view/changesetdetailview/__init__.php b/src/applications/differential/view/changesetlistview/__init__.php similarity index 53% copy from src/applications/differential/view/changesetdetailview/__init__.php copy to src/applications/differential/view/changesetlistview/__init__.php index 51175da167..f7d535542a 100644 --- a/src/applications/differential/view/changesetdetailview/__init__.php +++ b/src/applications/differential/view/changesetlistview/__init__.php @@ -1,16 +1,19 @@ changesets = $changesets; return $this; } public function render() { + require_celerity_resource('differential-table-of-contents-css'); $rows = array(); $changesets = $this->changesets; foreach ($changesets as $changeset) { $file = $changeset->getFilename(); $display_file = $changeset->getDisplayFilename(); $type = $changeset->getChangeType(); $ftype = $changeset->getFileType(); if (DifferentialChangeType::isOldLocationChangeType($type)) { $link = phutil_escape_html($display_file); $away = $changeset->getAwayPaths(); if (count($away) > 1) { $meta = array(); if ($type == DifferentialChangeType::TYPE_MULTICOPY) { $meta[] = 'Deleted after being copied to multiple locations:'; } else { $meta[] = 'Copied to multiple locations:'; } foreach ($away as $path) { $meta[] = $path; } $meta = implode('
', $meta); } else { if ($type == DifferentialChangeType::TYPE_MOVE_AWAY) { $meta = 'Moved to '.reset($away); } else { $meta = 'Copied to '.reset($away); } } } else { $link = phutil_render_tag( 'a', array( 'href' => '#', // TODO: filename normalizer ), phutil_escape_html($display_file)); if ($type == DifferentialChangeType::TYPE_MOVE_HERE) { $meta = 'Moved from '.phutil_escape_html($changeset->getOldFile()); } else if ($type == DifferentialChangeType::TYPE_COPY_HERE) { $meta = 'Copied from '.phutil_escape_html($changeset->getOldFile()); } else { $meta = null; } } $line_count = $changeset->getAffectedLineCount(); if ($line_count == 0) { $lines = null; } else if ($line_count == 1) { $lines = ' (1 line)'; } else { $lines = ' ('.$line_count.' lines)'; } $char = DifferentialChangeType::getSummaryCharacterForChangeType($type); $chartitle = DifferentialChangeType::getFullNameForChangeType($type); $desc = DifferentialChangeType::getShortNameForFileType($ftype); if ($desc) { $desc = '('.$desc.')'; } $pchar = ($changeset->getOldProperties() === $changeset->getNewProperties()) ? null : 'M'; $rows[] = ''. ''.$char.''. ''.$pchar.''. ''.$desc.''. ''.$link.$lines.''. ''; if ($meta) { $rows[] = ''. ''. ''.$meta.''. ''; } } return '
'. '

Table of Contents

'. ''. implode("\n", $rows). '
'. '
'; } } diff --git a/src/applications/differential/view/difftableofcontents/__init__.php b/src/applications/differential/view/difftableofcontents/__init__.php index 6981924676..da5da976d1 100644 --- a/src/applications/differential/view/difftableofcontents/__init__.php +++ b/src/applications/differential/view/difftableofcontents/__init__.php @@ -1,15 +1,16 @@ requireResource($symbol); } + +function celerity_generate_unique_node_id() { + static $uniq = 0; + $response = CelerityAPI::getStaticResourceResponse(); + $block = $response->getMetadataBlock(); + + return 'UQ'.$block.'_'.($uniq++); +} + diff --git a/src/infratructure/celerity/response/CelerityStaticResourceResponse.php b/src/infratructure/celerity/response/CelerityStaticResourceResponse.php index 59d9c8a00e..2207602a8a 100644 --- a/src/infratructure/celerity/response/CelerityStaticResourceResponse.php +++ b/src/infratructure/celerity/response/CelerityStaticResourceResponse.php @@ -1,63 +1,145 @@ metadataBlock = (int)$_REQUEST['__metablock__']; + } + } + + public function addMetadata($metadata) { + $id = count($this->metadata); + $this->metadata[$id] = $metadata; + return $this->metadataBlock.'_'.$id; + } + + public function getMetadataBlock() { + return $this->metadataBlock; + } + + public function initBehavior($behavior, array $config = array()) { + $this->requireResource('javelin-behavior-'.$behavior); + $this->behaviors[$behavior][] = $config; + return $this; + } public function requireResource($symbol) { $this->symbols[$symbol] = true; $this->needsResolve = true; return $this; } private function resolveResources() { if ($this->needsResolve) { $map = CelerityResourceMap::getInstance(); $this->resolved = $map->resolveResources(array_keys($this->symbols)); $this->needsResolve = false; } return $this; } public function renderResourcesOfType($type) { $this->resolveResources(); $output = array(); foreach ($this->resolved as $resource) { if ($resource['type'] == $type) { $output[] = $this->renderResource($resource); } } return implode("\n", $output); } private function renderResource(array $resource) { switch ($resource['type']) { case 'css': $path = phutil_escape_html($resource['path']); return ''; case 'js': $path = phutil_escape_html($resource['path']); - return ''; } throw new Exception("Unable to render resource."); } + public function renderHTMLFooter() { + $data = array(); + if ($this->metadata) { + $json_metadata = json_encode($this->metadata); + $this->metadata = array(); + } else { + $json_metadata = '{}'; + } + // Even if there is no metadata on the page, Javelin uses the mergeData() + // call to start dispatching the event queue. + $data[] = 'JX.Stratcom.mergeData('.$this->metadataBlock.', '. + $json_metadata.');'; + + $onload = array(); + if ($this->behaviors) { + $behavior = json_encode($this->behaviors); + $onload[] = 'JX.initBehaviors('.$behavior.')'; + $this->behaviors = array(); + } + + if ($onload) { + foreach ($onload as $func) { + $data[] = 'JX.onload(function(){'.$func.'});'; + } + } + + if ($data) { + $data = implode("\n", $data); + return ''; + } else { + return ''; + } + } + + public function renderAjaxResponse($payload, $error = null) { + $response = array( + 'error' => $error, + 'payload' => $payload, + ); + + if ($this->metadata) { + $response['javelin_metadata'] = $this->metadata; + $this->metadata = array(); + } + + if ($this->behaviors) { + $response['javelin_behaviors'] = $this->behaviors; + $this->behaviors = array(); + } + + $response = 'for (;;);'.json_encode($response); + return $response; + } + + } diff --git a/src/infratructure/celerity/api/CelerityAPI.php b/src/infratructure/javelin/api/Javelin.php similarity index 61% copy from src/infratructure/celerity/api/CelerityAPI.php copy to src/infratructure/javelin/api/Javelin.php index 77ba73f10c..b6e2a3d9cf 100644 --- a/src/infratructure/celerity/api/CelerityAPI.php +++ b/src/infratructure/javelin/api/Javelin.php @@ -1,35 +1,24 @@ initBehavior($behavior, $config); } - -} - -function require_celerity_resource($symbol) { - $response = CelerityAPI::getStaticResourceResponse(); - $response->requireResource($symbol); } diff --git a/src/infratructure/javelin/api/__init__.php b/src/infratructure/javelin/api/__init__.php new file mode 100644 index 0000000000..59283cfb85 --- /dev/null +++ b/src/infratructure/javelin/api/__init__.php @@ -0,0 +1,12 @@ + $v) { + switch ($k) { + case 'sigil': + $classes[] = 'FN_'.$v; + unset($attributes[$k]); + break; + case 'meta': + $response = CelerityAPI::getStaticResourceResponse(); + $id = $response->addMetadata($v); + $classes[] = 'FD_'.$id; + unset($attributes[$k]); + break; + case 'mustcapture': + $classes[] = 'FI_CAPTURE'; + unset($attributes[$k]); + break; + } + } + + if (isset($attributes['class'])) { + $classes[] = $attributes['class']; + } + + $attributes['class'] = implode(' ', $classes); + } + + return phutil_render_tag($tag, $attributes, $content); +} diff --git a/src/view/page/standard/PhabricatorStandardPageView.php b/src/view/page/standard/PhabricatorStandardPageView.php index 235df76475..e8e544d43b 100755 --- a/src/view/page/standard/PhabricatorStandardPageView.php +++ b/src/view/page/standard/PhabricatorStandardPageView.php @@ -1,130 +1,130 @@ applicationName = $application_name; return $this; } public function getApplicationName() { return $this->applicationName; } public function setBaseURI($base_uri) { $this->baseURI = $base_uri; return $this; } public function getBaseURI() { return $this->baseURI; } public function setTabs(array $tabs, $selected_tab) { $this->tabs = $tabs; $this->selectedTab = $selected_tab; return $this; } public function getTitle() { return $this->getGlyph().' '.parent::getTitle(); } protected function willRenderPage() { require_celerity_resource('phabricator-core-css'); require_celerity_resource('phabricator-core-buttons-css'); require_celerity_resource('phabricator-standard-page-view'); + require_celerity_resource('javelin-lib-dev'); + $this->bodyContent = $this->renderChildren(); } protected function getHead() { $response = CelerityAPI::getStaticResourceResponse(); return $response->renderResourcesOfType('css'). ''. ''; } public function setGlyph($glyph) { $this->glyph = $glyph; return $this; } public function getGlyph() { return $this->glyph; } protected function getBody() { $tabs = array(); foreach ($this->tabs as $name => $tab) { $tabs[] = phutil_render_tag( 'a', array( 'href' => idx($tab, 'href'), 'class' => ($name == $this->selectedTab) ? 'phabricator-selected-tab' : null, ), phutil_escape_html(idx($tab, 'name'))); } $tabs = implode('', $tabs); if ($tabs) { $tabs = ''.$tabs.''; } return '
'. '
'. 'Phabricator '. phutil_render_tag( 'a', array( 'href' => $this->getBaseURI(), 'class' => 'phabricator-head-appname', ), phutil_escape_html($this->getApplicationName())). $tabs. '
'. $this->bodyContent. '
'. '
'; } protected function getTail() { $response = CelerityAPI::getStaticResourceResponse(); return $response->renderResourcesOfType('js'). - ''; + $response->renderHTMLFooter(); } } diff --git a/webroot/rsrc/css/core/syntax.css b/webroot/rsrc/css/core/syntax.css new file mode 100644 index 0000000000..e7ca2ce578 --- /dev/null +++ b/webroot/rsrc/css/core/syntax.css @@ -0,0 +1,122 @@ +/** + * @provides syntax-highlighting-css + */ +.remarkup-code .uu { /* Forbidden Unicode */ + color: #aa0066; +} + +.remarkup-code .over-the-line { + color: #aa0066; + margin-right: 1px; +} + +.remarkup-code td span { + padding: 1px 0 3px; +} + + +.remarkup-code .hll { + background-color: #ffffcc; +} + +.remarkup-code .c, /* Comment */ +.remarkup-code .cm, /* Comment.Multiline */ +.remarkup-code .c1, /* Comment.Single */ +.remarkup-code .cs { /* Comment.Special */ + color: #666666; +} + +.remarkup-code .sd, /* Literal.String.Doc */ +.remarkup-code .sh { /* Literal.String.Heredoc */ + color: #000000; +} + +.remarkup-code .s, /* Literal.String */ +.remarkup-code .sb, /* Literal.String.Backtick */ +.remarkup-code .sc, /* Literal.String.Char */ +.remarkup-code .s2, /* Literal.String.Double */ +.remarkup-code .s1, /* Literal.String.Single */ +.remarkup-code .sx { /* Literal.String.Other */ + color: #766510; +} + +.remarkup-code .sr { /* Literal.String.Regex */ + color: #BB6688; +} + +.remarkup-code .nv, /* Name.Variable */ +.remarkup-code .vi, /* Name.Variable.Instance */ +.remarkup-code .vg { /* Name.Variable.Global */ + color: #001294; +} + +.remarkup-code .na { /* Name.Attribute */ + color: #354BB3; +} + +.remarkup-code .kc, /* Keyword.Constant */ +.remarkup-code .no { /* Name.Constant */ + color: #000A65; +} + +.remarkup-code .k, /* Keyword */ +.remarkup-code .kd, /* Keyword.Declaration */ +.remarkup-code .kn, /* Keyword.Namespace */ +.remarkup-code .kt { /* Keyword.Type */ + color: #AA4000; +} + +.remarkup-code .cp, /* Comment.Preproc */ +.remarkup-code .kp, /* Keyword.Pseudo */ +.remarkup-code .kr, /* Keyword.Reserved */ +.remarkup-code .nb, /* Name.Builtin */ +.remarkup-code .bp { /* Name.Builtin.Pseudo */ + color: #304A96; +} + +.remarkup-code .nc, /* Name.Class */ +.remarkup-code .nt, /* Name.Tag */ +.remarkup-code .vc { /* Name.Variable.Class */ + color: #00702A; +} + +.remarkup-code .nf, /* Name.Function */ +.remarkup-code .nx { /* Name.Other */ + color: #004012; +} + +.remarkup-code .o, /* Operator */ +.remarkup-code .ss { /* Literal.String.Symbol */ + color: #AA2211; +} + +.remarkup-code .m, /* Literal.Number */ +.remarkup-code .mf, /* Literal.Number.Float */ +.remarkup-code .mh, /* Literal.Number.Hex */ +.remarkup-code .mi, /* Literal.Number.Integer */ +.remarkup-code .mo, /* Literal.Number.Oct */ +.remarkup-code .il { /* Literal.Number.Integer.Long */ + color: #601200; +} + +.remarkup-code .gd { color: #A00000 } /* Generic.Deleted */ +.remarkup-code .ge { } /* Generic.Emph */ +.remarkup-code .gr { color: #FF0000 } /* Generic.Error */ +.remarkup-code .gh { color: #000080; } /* Generic.Heading */ +.remarkup-code .gi { color: #00A000 } /* Generic.Inserted */ +.remarkup-code .go { color: #808080 } /* Generic.Output */ +.remarkup-code .gp { color: #000080 } /* Generic.Prompt */ +.remarkup-code .gs { } /* Generic.Strong */ +.remarkup-code .gu { color: #800080 } /* Generic.Subheading */ +.remarkup-code .gt { color: #0040D0 } /* Generic.Traceback */ +.remarkup-code .nd { color: #AA22FF } /* Name.Decorator */ +.remarkup-code .ni { color: #999999 } /* Name.Entity */ +.remarkup-code .ne { color: #D2413A } /* Name.Exception */ +.remarkup-code .nl { color: #A0A000 } /* Name.Label */ +.remarkup-code .nn { color: #0000FF } /* Name.Namespace */ +.remarkup-code .ow { color: #AA22FF } /* Operator.Word */ +.remarkup-code .w { color: #bbbbbb } /* Text.Whitespace */ +.remarkup-code .se { color: #BB6622 } /* Literal.String.Escape */ +.remarkup-code .si { color: #BB6688 } /* Literal.String.Interpol */ + + diff --git a/webroot/rsrc/js/application/differential/behavior-populate.js b/webroot/rsrc/js/application/differential/behavior-populate.js new file mode 100644 index 0000000000..14be5b2f8d --- /dev/null +++ b/webroot/rsrc/js/application/differential/behavior-populate.js @@ -0,0 +1,22 @@ +/** + * @provides javelin-behavior-differential-populate + */ + +JX.behavior('differential-populate', function(config) { + + function onresponse(target, response) { + JX.DOM.replace(JX.$(target), JX.HTML(response)); + } + + var uri; + for (var k in config.registry) { + uri = config.uri + config.registry[k][0] + '/'; + new JX.Request(uri, JX.bind(null, onresponse, k)) + .setData({ + against: config.registry[k][1], + whitespace: config.whitespace + }) + .send(); + } + +});