diff --git a/resources/celerity/map.php b/resources/celerity/map.php index dabb6f1d5b..56ee3d5d45 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,8 +9,8 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => '15191c65', - 'core.pkg.css' => '3fd3b7b8', - 'core.pkg.js' => 'b9b4a943', + 'core.pkg.css' => '1dd5fa4b', + 'core.pkg.js' => '1ea38af8', 'differential.pkg.css' => '113e692c', 'differential.pkg.js' => 'f6d809c0', 'diffusion.pkg.css' => 'a2d17c7d', @@ -112,7 +112,7 @@ return array( 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => '62fa3ace', - 'rsrc/css/core/remarkup.css' => 'b375546d', + 'rsrc/css/core/remarkup.css' => '1828e2ad', 'rsrc/css/core/syntax.css' => 'cae95e89', 'rsrc/css/core/z-index.css' => '9d8f7c4b', 'rsrc/css/diviner/diviner-shared.css' => '896f1d43', @@ -392,7 +392,7 @@ return array( 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '1db13e70', 'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef', - 'rsrc/js/application/files/behavior-document-engine.js' => 'd3f8623c', + 'rsrc/js/application/files/behavior-document-engine.js' => '9108ee1a', 'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', 'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '191b4909', @@ -508,8 +508,8 @@ return array( 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', - 'rsrc/js/phuix/PHUIXActionView.js' => 'ed18356a', - 'rsrc/js/phuix/PHUIXAutocomplete.js' => '7fa5c915', + 'rsrc/js/phuix/PHUIXActionView.js' => '8d4a8c72', + 'rsrc/js/phuix/PHUIXAutocomplete.js' => 'df1bbd34', 'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '04b2ae03', 'rsrc/js/phuix/PHUIXExample.js' => '68af71ca', @@ -607,7 +607,7 @@ return array( 'javelin-behavior-diffusion-jump-to' => '73d09eef', 'javelin-behavior-diffusion-locate-file' => '6d3e1947', 'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc', - 'javelin-behavior-document-engine' => 'd3f8623c', + 'javelin-behavior-document-engine' => '9108ee1a', 'javelin-behavior-doorkeeper-tag' => '1db13e70', 'javelin-behavior-drydock-live-operation-status' => '901935ef', 'javelin-behavior-durable-column' => '2ae077e1', @@ -780,7 +780,7 @@ return array( 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => '77b0ae28', - 'phabricator-remarkup-css' => 'b375546d', + 'phabricator-remarkup-css' => '1828e2ad', 'phabricator-search-results-css' => '505dd8cf', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', @@ -864,8 +864,8 @@ return array( 'phui-workcard-view-css' => 'cca5fa92', 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', - 'phuix-action-view' => 'ed18356a', - 'phuix-autocomplete' => '7fa5c915', + 'phuix-action-view' => '8d4a8c72', + 'phuix-autocomplete' => 'df1bbd34', 'phuix-button-view' => '8a91e1ac', 'phuix-dropdown-menu' => '04b2ae03', 'phuix-form-control-view' => '210a16c1', @@ -1553,12 +1553,6 @@ return array( '7f243deb' => array( 'javelin-install', ), - '7fa5c915' => array( - 'javelin-install', - 'javelin-dom', - 'phuix-icon-view', - 'phabricator-prefab', - ), '834a1173' => array( 'javelin-behavior', 'javelin-scrollbar', @@ -1620,6 +1614,11 @@ return array( 'javelin-stratcom', 'javelin-install', ), + '8d4a8c72' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-util', + ), '8e1baf68' => array( 'phui-button-css', ), @@ -1645,6 +1644,11 @@ return array( 'javelin-stratcom', 'javelin-vector', ), + '9108ee1a' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + ), '92b9ec77' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2002,11 +2006,6 @@ return array( 'd254d646' => array( 'javelin-util', ), - 'd3f8623c' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - ), 'd4505101' => array( 'javelin-stratcom', 'javelin-install', @@ -2047,6 +2046,12 @@ return array( 'javelin-typeahead-ondemand-source', 'javelin-dom', ), + 'df1bbd34' => array( + 'javelin-install', + 'javelin-dom', + 'phuix-icon-view', + 'phabricator-prefab', + ), 'e1d25dfb' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2125,11 +2130,6 @@ return array( 'javelin-stratcom', 'javelin-vector', ), - 'ed18356a' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-util', - ), 'edf8a145' => array( 'javelin-behavior', 'javelin-uri', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index b1afef3600..447d4a534e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4020,6 +4020,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php', 'PhabricatorRepositoryManagementReparseWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php', 'PhabricatorRepositoryManagementThawWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php', + 'PhabricatorRepositoryManagementUnpublishWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementUnpublishWorkflow.php', 'PhabricatorRepositoryManagementUpdateWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php', 'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php', @@ -6525,6 +6526,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorConduitResultInterface', + 'PhabricatorDestructibleInterface', ), 'HarbormasterBuildAbortedException' => 'Exception', 'HarbormasterBuildActionController' => 'HarbormasterController', @@ -6532,6 +6534,7 @@ phutil_register_library_map(array( 'HarbormasterBuildArtifact' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', + 'PhabricatorDestructibleInterface', ), 'HarbormasterBuildArtifactPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -6564,6 +6567,7 @@ phutil_register_library_map(array( 'HarbormasterBuildMessage' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', + 'PhabricatorDestructibleInterface', ), 'HarbormasterBuildMessageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildPHIDType' => 'PhabricatorPHIDType', @@ -6614,6 +6618,7 @@ phutil_register_library_map(array( 'HarbormasterBuildTarget' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', + 'PhabricatorDestructibleInterface', ), 'HarbormasterBuildTargetPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -6628,6 +6633,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'HarbormasterBuildableInterface', + 'PhabricatorDestructibleInterface', ), 'HarbormasterBuildableActionController' => 'HarbormasterController', 'HarbormasterBuildableListController' => 'HarbormasterController', @@ -8558,7 +8564,10 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', ), - 'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO', + 'PhabricatorFeedStoryData' => array( + 'PhabricatorFeedDAO', + 'PhabricatorDestructibleInterface', + ), 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryPublisher' => 'Phobject', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', @@ -9809,6 +9818,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementReparseWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementThawWorkflow' => 'PhabricatorRepositoryManagementWorkflow', + 'PhabricatorRepositoryManagementUnpublishWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementUpdateWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', diff --git a/src/applications/differential/xaction/DifferentialRevisionUpdateTransaction.php b/src/applications/differential/xaction/DifferentialRevisionUpdateTransaction.php index c89c3c79e1..189ed2f2ba 100644 --- a/src/applications/differential/xaction/DifferentialRevisionUpdateTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionUpdateTransaction.php @@ -137,7 +137,34 @@ final class DifferentialRevisionUpdateTransaction continue; } - if ($diff->getRevisionID()) { + $is_attached = + ($diff->getRevisionID()) && + ($diff->getRevisionID() == $object->getID()); + if ($is_attached) { + $is_active = ($diff_phid == $object->getActiveDiffPHID()); + } else { + $is_active = false; + } + + if ($is_attached) { + if ($is_active) { + // This is a no-op: we're reattaching the current active diff to the + // revision it is already attached to. This is valid and will just + // be dropped later on in the process. + } else { + // At least for now, there's no support for "undoing" a diff and + // reverting to an older proposed change without just creating a + // new diff from whole cloth. + $errors[] = $this->newInvalidError( + pht( + 'You can not update this revision with the specified diff '. + '("%s") because this diff is already attached to the revision '. + 'as an older version of the change.', + $diff_phid), + $xaction); + continue; + } + } else if ($diff->getRevisionID()) { $errors[] = $this->newInvalidError( pht( 'You can not update this revision with the specified diff ("%s") '. diff --git a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php index cc4526dbdc..dd5777b2b0 100644 --- a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php +++ b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php @@ -126,7 +126,6 @@ final class DiffusionCommitHookEngine extends Phobject { public function execute() { $ref_updates = $this->findRefUpdates(); - $all_updates = $ref_updates; $caught = null; try { @@ -140,21 +139,32 @@ final class DiffusionCommitHookEngine extends Phobject { throw $ex; } - $this->applyHeraldRefRules($ref_updates, $all_updates); - $content_updates = $this->findContentUpdates($ref_updates); + $all_updates = array_merge($ref_updates, $content_updates); + + // If this is an "initial import" (a sizable push to a previously empty + // repository) we'll allow enormous changes and disable Herald rules. + // These rulesets can consume a large amount of time and memory and are + // generally not relevant when importing repository history. + $is_initial_import = $this->isInitialImport($all_updates); + + if (!$is_initial_import) { + $this->applyHeraldRefRules($ref_updates); + } try { - $this->rejectEnormousChanges($content_updates); + if (!$is_initial_import) { + $this->rejectEnormousChanges($content_updates); + } } catch (DiffusionCommitHookRejectException $ex) { // If we're rejecting enormous changes, flag everything. $this->rejectCode = PhabricatorRepositoryPushLog::REJECT_ENORMOUS; throw $ex; } - $all_updates = array_merge($all_updates, $content_updates); - - $this->applyHeraldContentRules($content_updates, $all_updates); + if (!$is_initial_import) { + $this->applyHeraldContentRules($content_updates); + } // Run custom scripts in `hook.d/` directories. $this->applyCustomHooks($all_updates); @@ -186,12 +196,10 @@ final class DiffusionCommitHookEngine extends Phobject { throw $caught; } - // If this went through cleanly, detect pushes which are actually imports - // of an existing repository rather than an addition of new commits. If - // this push is importing a bunch of stuff, set the importing flag on - // the repository. It will be cleared once we fully process everything. + // If this went through cleanly and was an import, set the importing flag + // on the repository. It will be cleared once we fully process everything. - if ($this->isInitialImport($all_updates)) { + if ($is_initial_import) { $repository = $this->getRepository(); $repository->markImporting(); } @@ -281,28 +289,21 @@ final class DiffusionCommitHookEngine extends Phobject { /* -( Herald )------------------------------------------------------------- */ - private function applyHeraldRefRules( - array $ref_updates, - array $all_updates) { + private function applyHeraldRefRules(array $ref_updates) { $this->applyHeraldRules( $ref_updates, - new HeraldPreCommitRefAdapter(), - $all_updates); + new HeraldPreCommitRefAdapter()); } - private function applyHeraldContentRules( - array $content_updates, - array $all_updates) { + private function applyHeraldContentRules(array $content_updates) { $this->applyHeraldRules( $content_updates, - new HeraldPreCommitContentAdapter(), - $all_updates); + new HeraldPreCommitContentAdapter()); } private function applyHeraldRules( array $updates, - HeraldAdapter $adapter_template, - array $all_updates) { + HeraldAdapter $adapter_template) { if (!$updates) { return; diff --git a/src/applications/drydock/management/DrydockManagementCommandWorkflow.php b/src/applications/drydock/management/DrydockManagementCommandWorkflow.php index bc66966f8c..ae0bd711b2 100644 --- a/src/applications/drydock/management/DrydockManagementCommandWorkflow.php +++ b/src/applications/drydock/management/DrydockManagementCommandWorkflow.php @@ -57,8 +57,8 @@ final class DrydockManagementCommandWorkflow array($interface, 'execx'), array('%Ls', $argv)); - fprintf(STDOUT, $stdout); - fprintf(STDERR, $stderr); + fwrite(STDOUT, $stdout); + fwrite(STDERR, $stderr); return 0; } diff --git a/src/applications/feed/storage/PhabricatorFeedStoryData.php b/src/applications/feed/storage/PhabricatorFeedStoryData.php index 33d19fa616..0513590023 100644 --- a/src/applications/feed/storage/PhabricatorFeedStoryData.php +++ b/src/applications/feed/storage/PhabricatorFeedStoryData.php @@ -1,6 +1,8 @@ storyData, $key, $default); } + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + + $this->openTransaction(); + $conn = $this->establishConnection('w'); + + queryfx( + $conn, + 'DELETE FROM %T WHERE chronologicalKey = %s', + id(new PhabricatorFeedStoryNotification())->getTableName(), + $this->getChronologicalKey()); + + queryfx( + $conn, + 'DELETE FROM %T WHERE chronologicalKey = %s', + id(new PhabricatorFeedStoryReference())->getTableName(), + $this->getChronologicalKey()); + + $this->delete(); + $this->saveTransaction(); + } + } diff --git a/src/applications/files/controller/PhabricatorFileDocumentController.php b/src/applications/files/controller/PhabricatorFileDocumentController.php index b74d98f48e..15fadaa289 100644 --- a/src/applications/files/controller/PhabricatorFileDocumentController.php +++ b/src/applications/files/controller/PhabricatorFileDocumentController.php @@ -7,6 +7,10 @@ final class PhabricatorFileDocumentController private $engine; private $ref; + public function shouldAllowPublic() { + return true; + } + public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); @@ -39,6 +43,16 @@ final class PhabricatorFileDocumentController $engine = $engines[$engine_key]; $this->engine = $engine; + $encode_setting = $request->getStr('encode'); + if (strlen($encode_setting)) { + $engine->setEncodingConfiguration($encode_setting); + } + + $highlight_setting = $request->getStr('highlight'); + if (strlen($highlight_setting)) { + $engine->setHighlightingConfiguration($highlight_setting); + } + try { $content = $engine->newDocument($ref); } catch (Exception $ex) { diff --git a/src/applications/files/controller/PhabricatorFileViewController.php b/src/applications/files/controller/PhabricatorFileViewController.php index 5251fdd8f1..9d32ff6fb1 100644 --- a/src/applications/files/controller/PhabricatorFileViewController.php +++ b/src/applications/files/controller/PhabricatorFileViewController.php @@ -422,6 +422,16 @@ final class PhabricatorFileViewController extends PhabricatorFileController { $engine->setHighlightedLines(range($lines[0], $lines[1])); } + $encode_setting = $request->getStr('encode'); + if (strlen($encode_setting)) { + $engine->setEncodingConfiguration($encode_setting); + } + + $highlight_setting = $request->getStr('highlight'); + if (strlen($highlight_setting)) { + $engine->setHighlightingConfiguration($highlight_setting); + } + $views = array(); foreach ($engines as $candidate_key => $candidate_engine) { $label = $candidate_engine->getViewAsLabel($ref); @@ -443,6 +453,8 @@ final class PhabricatorFileViewController extends PhabricatorFileController { 'engineURI' => $candidate_engine->getRenderURI($ref), 'viewURI' => $view_uri, 'loadingMarkup' => hsprintf('%s', $loading), + 'canEncode' => $candidate_engine->canConfigureEncoding($ref), + 'canHighlight' => $candidate_engine->CanConfigureHighlighting($ref), ); } @@ -474,6 +486,18 @@ final class PhabricatorFileViewController extends PhabricatorFileController { 'viewKey' => $engine->getDocumentEngineKey(), 'views' => $views, 'standaloneURI' => $engine->getRenderURI($ref), + 'encode' => array( + 'icon' => 'fa-font', + 'name' => pht('Change Text Encoding...'), + 'uri' => '/services/encoding/', + 'value' => $encode_setting, + ), + 'highlight' => array( + 'icon' => 'fa-lightbulb-o', + 'name' => pht('Highlight As...'), + 'uri' => '/services/highlight/', + 'value' => $highlight_setting, + ), ); $view_button = id(new PHUIButtonView()) diff --git a/src/applications/files/document/PhabricatorDocumentEngine.php b/src/applications/files/document/PhabricatorDocumentEngine.php index a225d55ea9..c3a1a7317a 100644 --- a/src/applications/files/document/PhabricatorDocumentEngine.php +++ b/src/applications/files/document/PhabricatorDocumentEngine.php @@ -5,6 +5,8 @@ abstract class PhabricatorDocumentEngine private $viewer; private $highlightedLines = array(); + private $encodingConfiguration; + private $highlightingConfiguration; final public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; @@ -28,6 +30,32 @@ abstract class PhabricatorDocumentEngine return $this->canRenderDocumentType($ref); } + public function canConfigureEncoding(PhabricatorDocumentRef $ref) { + return false; + } + + public function canConfigureHighlighting(PhabricatorDocumentRef $ref) { + return false; + } + + final public function setEncodingConfiguration($config) { + $this->encodingConfiguration = $config; + return $this; + } + + final public function getEncodingConfiguration() { + return $this->encodingConfiguration; + } + + final public function setHighlightingConfiguration($config) { + $this->highlightingConfiguration = $config; + return $this; + } + + final public function getHighlightingConfiguration() { + return $this->highlightingConfiguration; + } + public function shouldRenderAsync(PhabricatorDocumentRef $ref) { return false; } diff --git a/src/applications/files/document/PhabricatorJupyterDocumentEngine.php b/src/applications/files/document/PhabricatorJupyterDocumentEngine.php index f960f5c8c0..90b9d33c0e 100644 --- a/src/applications/files/document/PhabricatorJupyterDocumentEngine.php +++ b/src/applications/files/document/PhabricatorJupyterDocumentEngine.php @@ -196,7 +196,7 @@ final class PhabricatorJupyterDocumentEngine $content = implode('', $content); $content = PhabricatorSyntaxHighlighter::highlightWithLanguage( - 'python', + 'py', $content); $outputs = array(); @@ -260,9 +260,8 @@ final class PhabricatorJupyterDocumentEngine $raw_data = $data[$image_format]; if (!is_array($raw_data)) { - continue; + $raw_data = array($raw_data); } - $raw_data = implode('', $raw_data); $content = phutil_tag( diff --git a/src/applications/files/document/PhabricatorSourceDocumentEngine.php b/src/applications/files/document/PhabricatorSourceDocumentEngine.php index 1c3e54575a..cd7c2af92b 100644 --- a/src/applications/files/document/PhabricatorSourceDocumentEngine.php +++ b/src/applications/files/document/PhabricatorSourceDocumentEngine.php @@ -9,6 +9,10 @@ final class PhabricatorSourceDocumentEngine return pht('View as Source'); } + public function canConfigureHighlighting(PhabricatorDocumentRef $ref) { + return true; + } + protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) { return 'fa-code'; } @@ -20,9 +24,16 @@ final class PhabricatorSourceDocumentEngine protected function newDocumentContent(PhabricatorDocumentRef $ref) { $content = $this->loadTextData($ref); - $content = PhabricatorSyntaxHighlighter::highlightWithFilename( - $ref->getName(), - $content); + $highlighting = $this->getHighlightingConfiguration(); + if ($highlighting !== null) { + $content = PhabricatorSyntaxHighlighter::highlightWithLanguage( + $highlighting, + $content); + } else { + $content = PhabricatorSyntaxHighlighter::highlightWithFilename( + $ref->getName(), + $content); + } return $this->newTextDocumentContent($content); } diff --git a/src/applications/files/document/PhabricatorTextDocumentEngine.php b/src/applications/files/document/PhabricatorTextDocumentEngine.php index 4fb8d052e1..08a5cabe54 100644 --- a/src/applications/files/document/PhabricatorTextDocumentEngine.php +++ b/src/applications/files/document/PhabricatorTextDocumentEngine.php @@ -3,10 +3,16 @@ abstract class PhabricatorTextDocumentEngine extends PhabricatorDocumentEngine { + private $encodingMessage = null; + protected function canRenderDocumentType(PhabricatorDocumentRef $ref) { return $ref->isProbablyText(); } + public function canConfigureEncoding(PhabricatorDocumentRef $ref) { + return true; + } + protected function newTextDocumentContent($content) { $lines = phutil_split_lines($content); @@ -14,19 +20,69 @@ abstract class PhabricatorTextDocumentEngine ->setHighlights($this->getHighlightedLines()) ->setLines($lines); + $message = null; + if ($this->encodingMessage !== null) { + $message = $this->newMessage($this->encodingMessage); + } + $container = phutil_tag( 'div', array( 'class' => 'document-engine-text', ), - $view); + array( + $message, + $view, + )); return $container; } protected function loadTextData(PhabricatorDocumentRef $ref) { $content = $ref->loadData(); - $content = phutil_utf8ize($content); + + $encoding = $this->getEncodingConfiguration(); + if ($encoding !== null) { + if (function_exists('mb_convert_encoding')) { + $content = mb_convert_encoding($content, 'UTF-8', $encoding); + $this->encodingMessage = pht( + 'This document was converted from %s to UTF8 for display.', + $encoding); + } else { + $this->encodingMessage = pht( + 'Unable to perform text encoding conversion: mbstring extension '. + 'is not available.'); + } + } else { + if (!phutil_is_utf8($content)) { + if (function_exists('mb_detect_encoding')) { + $try_encodings = array( + 'JIS' => pht('JIS'), + 'EUC-JP' => pht('EUC-JP'), + 'SJIS' => pht('Shift JIS'), + 'ISO-8859-1' => pht('ISO-8859-1 (Latin 1)'), + ); + + $guess = mb_detect_encoding($content, array_keys($try_encodings)); + if ($guess) { + $content = mb_convert_encoding($content, 'UTF-8', $guess); + $this->encodingMessage = pht( + 'This document is not UTF8. It was detected as %s and '. + 'converted to UTF8 for display.', + idx($try_encodings, $guess, $guess)); + } + } + } + } + + if (!phutil_is_utf8($content)) { + $content = phutil_utf8ize($content); + $this->encodingMessage = pht( + 'This document is not UTF8 and its text encoding could not be '. + 'detected automatically. Use "Change Text Encoding..." to choose '. + 'an encoding.'); + } + return $content; } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildMessage.php b/src/applications/harbormaster/storage/HarbormasterBuildMessage.php index 1066a93610..34aab3957e 100644 --- a/src/applications/harbormaster/storage/HarbormasterBuildMessage.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildMessage.php @@ -6,8 +6,11 @@ * conditions where we receive a message before a build plan is ready to * accept it. */ -final class HarbormasterBuildMessage extends HarbormasterDAO - implements PhabricatorPolicyInterface { +final class HarbormasterBuildMessage + extends HarbormasterDAO + implements + PhabricatorPolicyInterface, + PhabricatorDestructibleInterface { protected $authorPHID; protected $receiverPHID; @@ -74,4 +77,13 @@ final class HarbormasterBuildMessage extends HarbormasterDAO return pht('Build messages have the same policies as their receivers.'); } + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + $this->delete(); + } + } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildable.php b/src/applications/harbormaster/storage/HarbormasterBuildable.php index 5de2159e8d..3a092900eb 100644 --- a/src/applications/harbormaster/storage/HarbormasterBuildable.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildable.php @@ -1,10 +1,12 @@ getViewer(); + + $this->openTransaction(); + $builds = id(new HarbormasterBuildQuery()) + ->setViewer($viewer) + ->withBuildablePHIDs(array($this->getPHID())) + ->execute(); + foreach ($builds as $build) { + $engine->destroyObject($build); + } + + $messages = id(new HarbormasterBuildMessageQuery()) + ->setViewer($viewer) + ->withReceiverPHIDs(array($this->getPHID())) + ->execute(); + foreach ($messages as $message) { + $engine->destroyObject($message); + } + + $this->delete(); + $this->saveTransaction(); + } + } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuild.php b/src/applications/harbormaster/storage/build/HarbormasterBuild.php index d43b19d71f..ae0f6b13f3 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuild.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuild.php @@ -4,7 +4,8 @@ final class HarbormasterBuild extends HarbormasterDAO implements PhabricatorApplicationTransactionInterface, PhabricatorPolicyInterface, - PhabricatorConduitResultInterface { + PhabricatorConduitResultInterface, + PhabricatorDestructibleInterface { protected $buildablePHID; protected $buildPlanPHID; @@ -455,4 +456,33 @@ final class HarbormasterBuild extends HarbormasterDAO ); } + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + $viewer = $engine->getViewer(); + + $this->openTransaction(); + $targets = id(new HarbormasterBuildTargetQuery()) + ->setViewer($viewer) + ->withBuildPHIDs(array($this->getPHID())) + ->execute(); + foreach ($targets as $target) { + $engine->destroyObject($target); + } + + $messages = id(new HarbormasterBuildMessageQuery()) + ->setViewer($viewer) + ->withReceiverPHIDs(array($this->getPHID())) + ->execute(); + foreach ($messages as $message) { + $engine->destroyObject($message); + } + + $this->delete(); + $this->saveTransaction(); + } + + } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php b/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php index 461ef4b06f..7cd8d60b6a 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php @@ -1,7 +1,10 @@ getViewer(); + + $this->openTransaction(); + $this->releaseArtifact($viewer); + $this->delete(); + $this->saveTransaction(); + } + } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php index 8b47bdfc21..b559a66198 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php @@ -1,7 +1,10 @@ getViewer(); + + $this->openTransaction(); + + $lint_message = new HarbormasterBuildLintMessage(); + $conn = $lint_message->establishConnection('w'); + queryfx( + $conn, + 'DELETE FROM %T WHERE buildTargetPHID = %s', + $lint_message->getTableName(), + $this->getPHID()); + + $unit_message = new HarbormasterBuildUnitMessage(); + $conn = $unit_message->establishConnection('w'); + queryfx( + $conn, + 'DELETE FROM %T WHERE buildTargetPHID = %s', + $unit_message->getTableName(), + $this->getPHID()); + + $logs = id(new HarbormasterBuildLogQuery()) + ->setViewer($viewer) + ->withBuildTargetPHIDs(array($this->getPHID())) + ->execute(); + foreach ($logs as $log) { + $engine->destroyObject($log); + } + + $artifacts = id(new HarbormasterBuildArtifactQuery()) + ->setViewer($viewer) + ->withBuildTargetPHIDs(array($this->getPHID())) + ->execute(); + foreach ($artifacts as $artifact) { + $engine->destroyObject($artifact); + } + + $messages = id(new HarbormasterBuildMessageQuery()) + ->setViewer($viewer) + ->withReceiverPHIDs(array($this->getPHID())) + ->execute(); + foreach ($messages as $message) { + $engine->destroyObject($message); + } + + $this->delete(); + $this->saveTransaction(); + } + + } diff --git a/src/applications/owners/storage/PhabricatorOwnersPackage.php b/src/applications/owners/storage/PhabricatorOwnersPackage.php index 56dd51a3c6..c76864702c 100644 --- a/src/applications/owners/storage/PhabricatorOwnersPackage.php +++ b/src/applications/owners/storage/PhabricatorOwnersPackage.php @@ -393,19 +393,22 @@ final class PhabricatorOwnersPackage } public static function splitPath($path) { - $trailing_slash = preg_match('@/$@', $path) ? '/' : ''; - $path = trim($path, '/'); + $result = array( + '/', + ); + $parts = explode('/', $path); + $buffer = '/'; + foreach ($parts as $part) { + if (!strlen($part)) { + continue; + } - $result = array(); - while (count($parts)) { - $result[] = '/'.implode('/', $parts).$trailing_slash; - $trailing_slash = '/'; - array_pop($parts); + $buffer = $buffer.$part.'/'; + $result[] = $buffer; } - $result[] = '/'; - return array_reverse($result); + return $result; } public function attachPaths(array $paths) { diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementUnpublishWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementUnpublishWorkflow.php new file mode 100644 index 0000000000..5a6afb8c6e --- /dev/null +++ b/src/applications/repository/management/PhabricatorRepositoryManagementUnpublishWorkflow.php @@ -0,0 +1,273 @@ +setName('unpublish') + ->setExamples( + '**unpublish** [__options__] __repository__') + ->setSynopsis( + pht( + 'Unpublish all feed stories and notifications that a repository '. + 'has generated. Keep expectations low; can not rewind time.')) + ->setArguments( + array( + array( + 'name' => 'force', + 'help' => pht('Do not prompt for confirmation.'), + ), + array( + 'name' => 'dry-run', + 'help' => pht('Do not perform any writes.'), + ), + array( + 'name' => 'repositories', + 'wildcard' => true, + ), + )); + } + + public function execute(PhutilArgumentParser $args) { + $viewer = $this->getViewer(); + $is_force = $args->getArg('force'); + $is_dry_run = $args->getArg('dry-run'); + + $repositories = $this->loadLocalRepositories($args, 'repositories'); + if (count($repositories) !== 1) { + throw new PhutilArgumentUsageException( + pht('Specify exactly one repository to unpublish.')); + } + $repository = head($repositories); + + if (!$is_force) { + echo tsprintf( + "%s\n", + pht( + 'This script will unpublish all feed stories and notifications '. + 'which a repository generated during import. This action can not '. + 'be undone.')); + + $prompt = pht( + 'Permanently unpublish "%s"?', + $repository->getDisplayName()); + if (!phutil_console_confirm($prompt)) { + throw new PhutilArgumentUsageException( + pht('User aborted workflow.')); + } + } + + $commits = id(new DiffusionCommitQuery()) + ->setViewer($viewer) + ->withRepositoryPHIDs(array($repository->getPHID())) + ->execute(); + + echo pht("Will unpublish %s commits.\n", count($commits)); + + foreach ($commits as $commit) { + $this->unpublishCommit($commit, $is_dry_run); + } + + return 0; + } + + private function unpublishCommit( + PhabricatorRepositoryCommit $commit, + $is_dry_run) { + $viewer = $this->getViewer(); + + echo tsprintf( + "%s\n", + pht( + 'Unpublishing commit "%s".', + $commit->getMonogram())); + + $stories = id(new PhabricatorFeedQuery()) + ->setViewer($viewer) + ->withFilterPHIDs(array($commit->getPHID())) + ->execute(); + + if ($stories) { + echo tsprintf( + "%s\n", + pht( + 'Found %s feed storie(s).', + count($stories))); + + if (!$is_dry_run) { + $engine = new PhabricatorDestructionEngine(); + foreach ($stories as $story) { + $story_data = $story->getStoryData(); + $engine->destroyObject($story_data); + } + + echo tsprintf( + "%s\n", + pht( + 'Destroyed %s feed storie(s).', + count($stories))); + } + } + + $edge_types = array( + PhabricatorObjectMentionsObjectEdgeType::EDGECONST => true, + DiffusionCommitHasTaskEdgeType::EDGECONST => true, + DiffusionCommitHasRevisionEdgeType::EDGECONST => true, + DiffusionCommitRevertsCommitEdgeType::EDGECONST => true, + ); + + $query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(array($commit->getPHID())) + ->withEdgeTypes(array_keys($edge_types)); + $edges = $query->execute(); + + foreach ($edges[$commit->getPHID()] as $type => $edge_list) { + foreach ($edge_list as $edge) { + $dst = $edge['dst']; + + echo tsprintf( + "%s\n", + pht( + 'Commit "%s" has edge of type "%s" to object "%s".', + $commit->getMonogram(), + $type, + $dst)); + + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($dst)) + ->executeOne(); + if ($object) { + if ($object instanceof PhabricatorApplicationTransactionInterface) { + $this->unpublishEdgeTransaction( + $commit, + $type, + $object, + $is_dry_run); + } + } + } + } + } + + private function unpublishEdgeTransaction( + $src, + $type, + PhabricatorApplicationTransactionInterface $dst, + $is_dry_run) { + $viewer = $this->getViewer(); + + $query = PhabricatorApplicationTransactionQuery::newQueryForObject($dst) + ->setViewer($viewer) + ->withObjectPHIDs(array($dst->getPHID())); + + $xactions = id(clone $query) + ->withTransactionTypes( + array( + PhabricatorTransactions::TYPE_EDGE, + )) + ->execute(); + + $type_obj = PhabricatorEdgeType::getByConstant($type); + $inverse_type = $type_obj->getInverseEdgeConstant(); + + $engine = new PhabricatorDestructionEngine(); + foreach ($xactions as $xaction) { + $edge_type = $xaction->getMetadataValue('edge:type'); + if ($edge_type != $inverse_type) { + // Some other type of edge was edited. + continue; + } + + $record = PhabricatorEdgeChangeRecord::newFromTransaction($xaction); + $changed = $record->getChangedPHIDs(); + if ($changed !== array($src->getPHID())) { + // Affected objects were not just the object we're unpublishing. + continue; + } + + echo tsprintf( + "%s\n", + pht( + 'Found edge transaction "%s" on object "%s" for type "%s".', + $xaction->getPHID(), + $dst->getPHID(), + $type)); + + if (!$is_dry_run) { + $engine->destroyObject($xaction); + + echo tsprintf( + "%s\n", + pht( + 'Destroyed transaction "%s" on object "%s".', + $xaction->getPHID(), + $dst->getPHID())); + } + } + + if ($type === DiffusionCommitHasTaskEdgeType::EDGECONST) { + $xactions = id(clone $query) + ->withTransactionTypes( + array( + ManiphestTaskStatusTransaction::TRANSACTIONTYPE, + )) + ->execute(); + + if ($xactions) { + foreach ($xactions as $xaction) { + $metadata = $xaction->getMetadata(); + if (idx($metadata, 'commitPHID') === $src->getPHID()) { + echo tsprintf( + "%s\n", + pht( + 'MANUAL Task "%s" was likely closed improperly by "%s".', + $dst->getMonogram(), + $src->getMonogram())); + } + } + } + } + + if ($type === DiffusionCommitHasRevisionEdgeType::EDGECONST) { + $xactions = id(clone $query) + ->withTransactionTypes( + array( + DifferentialRevisionCloseTransaction::TRANSACTIONTYPE, + )) + ->execute(); + + if ($xactions) { + foreach ($xactions as $xaction) { + $metadata = $xaction->getMetadata(); + if (idx($metadata, 'isCommitClose')) { + if (idx($metadata, 'commitPHID') === $src->getPHID()) { + echo tsprintf( + "%s\n", + pht( + 'MANUAL Revision "%s" was likely closed improperly by "%s".', + $dst->getMonogram(), + $src->getMonogram())); + } + } + } + } + } + + if (!$is_dry_run) { + id(new PhabricatorEdgeEditor()) + ->removeEdge($src->getPHID(), $type, $dst->getPHID()) + ->save(); + echo tsprintf( + "%s\n", + pht( + 'Destroyed edge of type "%s" between "%s" and "%s".', + $type, + $src->getPHID(), + $dst->getPHID())); + } + } + + +} diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 8184eafb50..e4a13de54e 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -1120,6 +1120,11 @@ abstract class PhabricatorApplicationTransactionEditor // We are the Herald editor, so stop work here and return the updated // transactions. return $xactions; + } else if ($this->getIsInverseEdgeEditor()) { + // Do not run Herald if we're just recording that this object was + // mentioned elsewhere. This tends to create Herald side effects which + // feel arbitrary, and can really slow down edits which mention a large + // number of other objects. See T13114. } else if ($this->shouldApplyHeraldRules($object, $xactions)) { // We are not the Herald editor, so try to apply Herald rules. $herald_xactions = $this->applyHeraldRules($object, $xactions); diff --git a/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php b/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php index 1153f82a34..27b8276c85 100644 --- a/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php +++ b/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php @@ -7,6 +7,7 @@ final class PhabricatorCustomFieldEditField private $httpParameterType; private $conduitParameterType; private $bulkParameterType; + private $commentAction; public function setCustomField(PhabricatorCustomField $custom_field) { $this->customField = $custom_field; @@ -47,6 +48,16 @@ final class PhabricatorCustomFieldEditField return $this->bulkParameterType; } + public function setCustomFieldCommentAction( + PhabricatorEditEngineCommentAction $comment_action) { + $this->commentAction = $comment_action; + return $this; + } + + public function getCustomFieldCommentAction() { + return $this->commentAction; + } + protected function buildControl() { if ($this->getIsConduitOnly()) { return null; @@ -77,6 +88,19 @@ final class PhabricatorCustomFieldEditField return $clone->getNewValueForApplicationTransactions(); } + protected function getValueForCommentAction($value) { + $field = $this->getCustomField(); + $clone = clone $field; + $clone->setValueFromApplicationTransactions($value); + + // TODO: This is somewhat bogus because only StandardCustomFields + // implement a getFieldValue() method -- not all CustomFields. Today, + // only StandardCustomFields can ever actually generate a comment action + // so we never reach this method with other field types. + + return $clone->getFieldValue(); + } + protected function getValueExistsInSubmit(AphrontRequest $request, $key) { return true; } @@ -110,6 +134,16 @@ final class PhabricatorCustomFieldEditField return null; } + protected function newCommentAction() { + $action = $this->getCustomFieldCommentAction(); + + if ($action) { + return clone $action; + } + + return null; + } + protected function newConduitParameterType() { $type = $this->getCustomFieldConduitParameterType(); diff --git a/src/infrastructure/customfield/field/PhabricatorCustomField.php b/src/infrastructure/customfield/field/PhabricatorCustomField.php index 818bf119ff..36db8f239b 100644 --- a/src/infrastructure/customfield/field/PhabricatorCustomField.php +++ b/src/infrastructure/customfield/field/PhabricatorCustomField.php @@ -1127,6 +1127,16 @@ abstract class PhabricatorCustomField extends Phobject { $field->setCustomFieldBulkParameterType($bulk_type); } + $comment_action = $this->getCommentAction(); + if ($comment_action) { + $field + ->setCustomFieldCommentAction($comment_action) + ->setCommentActionLabel( + pht( + 'Change %s', + $this->getFieldName())); + } + return $field; } @@ -1459,6 +1469,17 @@ abstract class PhabricatorCustomField extends Phobject { return null; } + public function getCommentAction() { + return $this->newCommentAction(); + } + + protected function newCommentAction() { + if ($this->proxy) { + return $this->proxy->newCommentAction(); + } + return null; + } + /* -( Herald )------------------------------------------------------------- */ diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php index 9bf59d41f6..3c5268d65b 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php @@ -143,4 +143,26 @@ abstract class PhabricatorStandardCustomFieldTokenizer ->setDatasource($datasource); } + protected function newCommentAction() { + $viewer = $this->getViewer(); + + $datasource = $this->getDatasource() + ->setViewer($viewer); + + $action = id(new PhabricatorEditEngineTokenizerCommentAction()) + ->setDatasource($datasource); + + $limit = $this->getFieldConfigValue('limit'); + if ($limit) { + $action->setLimit($limit); + } + + $value = $this->getFieldValue(); + if ($value !== null) { + $action->setInitialValue($value); + } + + return $action; + } + } diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css index 949deadbe4..990c6f0bab 100644 --- a/webroot/rsrc/css/core/remarkup.css +++ b/webroot/rsrc/css/core/remarkup.css @@ -724,6 +724,11 @@ var.remarkup-assist-textarea { color: {$darkgreytext}; } +.phuix-autocomplete-list a.jx-result .tokenizer-result-closed { + color: {$lightgreytext}; + text-decoration: line-through; +} + .phuix-autocomplete-list a.jx-result .phui-icon-view { margin-right: 4px; color: {$lightbluetext}; diff --git a/webroot/rsrc/js/application/files/behavior-document-engine.js b/webroot/rsrc/js/application/files/behavior-document-engine.js index 4cb7d17723..ccbd41ca92 100644 --- a/webroot/rsrc/js/application/files/behavior-document-engine.js +++ b/webroot/rsrc/js/application/files/behavior-document-engine.js @@ -52,6 +52,61 @@ JX.behavior('document-engine', function(config, statics) { }); } + list.addItem( + new JX.PHUIXActionView() + .setDivider(true)); + + var encode_item = new JX.PHUIXActionView() + .setName(data.encode.name) + .setIcon(data.encode.icon); + + var onencode = JX.bind(null, function(data, e) { + e.prevent(); + + if (encode_item.getDisabled()) { + return; + } + + new JX.Workflow(data.encode.uri, {encoding: data.encode.value}) + .setHandler(function(r) { + data.encode.value = r.encoding; + onview(data); + }) + .start(); + + menu.close(); + + }, data); + + encode_item.setHandler(onencode); + + list.addItem(encode_item); + + var highlight_item = new JX.PHUIXActionView() + .setName(data.highlight.name) + .setIcon(data.highlight.icon); + + var onhighlight = JX.bind(null, function(data, e) { + e.prevent(); + + if (highlight_item.getDisabled()) { + return; + } + + new JX.Workflow(data.highlight.uri, {highlight: data.highlight.value}) + .setHandler(function(r) { + data.highlight.value = r.highlight; + onview(data); + }) + .start(); + + menu.close(); + }, data); + + highlight_item.setHandler(onhighlight); + + list.addItem(highlight_item); + menu.setContent(list.getNode()); menu.listen('open', function() { @@ -61,6 +116,11 @@ JX.behavior('document-engine', function(config, statics) { // Highlight the current rendering engine. var is_selected = (engine.spec.viewKey == data.viewKey); engine.view.setSelected(is_selected); + + if (is_selected) { + encode_item.setDisabled(!engine.spec.canEncode); + highlight_item.setDisabled(!engine.spec.canHighlight); + } } }); @@ -68,14 +128,38 @@ JX.behavior('document-engine', function(config, statics) { menu.open(); } + function add_params(uri, data) { + uri = JX.$U(uri); + + if (data.highlight.value) { + uri.setQueryParam('highlight', data.highlight.value); + } + + if (data.encode.value) { + uri.setQueryParam('encode', data.encode.value); + } + + return uri.toString(); + } + function onview(data, spec, immediate) { + if (!spec) { + for (var ii = 0; ii < data.views.length; ii++) { + if (data.views[ii].viewKey == data.viewKey) { + spec = data.views[ii]; + break; + } + } + } + data.sequence = (data.sequence || 0) + 1; var handler = JX.bind(null, onrender, data, data.sequence); data.viewKey = spec.viewKey; - JX.History.replace(spec.viewURI); - new JX.Request(spec.engineURI, handler) + var uri = add_params(spec.engineURI, data); + + new JX.Request(uri, handler) .send(); if (data.loadingView) { @@ -91,6 +175,12 @@ JX.behavior('document-engine', function(config, statics) { var load = JX.bind(null, onloading, data, spec); data.loadTimer = setTimeout(load, 333); + + // Replace the URI with the URI for the specific rendering the user + // has selected. + + var view_uri = add_params(spec.viewURI, data); + JX.History.replace(view_uri); } } @@ -128,16 +218,10 @@ JX.behavior('document-engine', function(config, statics) { statics.initialized = true; } - if (config.renderControlID) { + if (config && config.renderControlID) { var control = JX.$(config.renderControlID); var data = JX.Stratcom.getData(control); - - for (var ii = 0; ii < data.views.length; ii++) { - if (data.views[ii].viewKey == data.viewKey) { - onview(data, data.views[ii], true); - break; - } - } + onview(data, null, true); } }); diff --git a/webroot/rsrc/js/phuix/PHUIXActionView.js b/webroot/rsrc/js/phuix/PHUIXActionView.js index 7967fa7366..97e746c2c5 100644 --- a/webroot/rsrc/js/phuix/PHUIXActionView.js +++ b/webroot/rsrc/js/phuix/PHUIXActionView.js @@ -34,6 +34,10 @@ JX.install('PHUIXActionView', { return this; }, + getDisabled: function() { + return this._disabled; + }, + setLabel: function(label) { this._label = label; JX.DOM.alterClass( diff --git a/webroot/rsrc/js/phuix/PHUIXAutocomplete.js b/webroot/rsrc/js/phuix/PHUIXAutocomplete.js index 8f062d900e..f46e7666e2 100644 --- a/webroot/rsrc/js/phuix/PHUIXAutocomplete.js +++ b/webroot/rsrc/js/phuix/PHUIXAutocomplete.js @@ -185,7 +185,10 @@ JX.install('PHUIXAutocomplete', { .getNode(); } - map.display = [icon, map.displayName]; + var display = JX.$N('span', {}, [icon, map.displayName]); + JX.DOM.alterClass(display, 'tokenizer-result-closed', !!map.closed); + + map.display = display; return map; },