Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2894813
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
54 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/pholio/controller/PholioMockCommentController.php b/src/applications/pholio/controller/PholioMockCommentController.php
index d54b4677e5..a4f9daf886 100644
--- a/src/applications/pholio/controller/PholioMockCommentController.php
+++ b/src/applications/pholio/controller/PholioMockCommentController.php
@@ -1,81 +1,81 @@
<?php
final class PholioMockCommentController extends PholioController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
if (!$request->isFormPost()) {
return new Aphront400Response();
}
$mock = id(new PholioMockQuery())
->setViewer($viewer)
->withIDs(array($id))
->needImages(true)
->executeOne();
if (!$mock) {
return new Aphront404Response();
}
$is_preview = $request->isPreviewRequest();
$draft = PhabricatorDraft::buildFromRequest($request);
- $mock_uri = '/M'.$mock->getID();
+ $mock_uri = $mock->getURI();
$comment = $request->getStr('comment');
$xactions = array();
$inline_comments = id(new PholioTransactionComment())->loadAllWhere(
'authorphid = %s AND transactionphid IS NULL AND imageid IN (%Ld)',
$viewer->getPHID(),
- mpull($mock->getImages(), 'getID'));
+ mpull($mock->getActiveImages(), 'getID'));
if (!$inline_comments || strlen($comment)) {
$xactions[] = id(new PholioTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new PholioTransactionComment())
->setContent($comment));
}
foreach ($inline_comments as $inline_comment) {
$xactions[] = id(new PholioTransaction())
->setTransactionType(PholioMockInlineTransaction::TRANSACTIONTYPE)
->attachComment($inline_comment);
}
$editor = id(new PholioMockEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect($request->isContinueRequest())
->setIsPreview($is_preview);
try {
$xactions = $editor->applyTransactions($mock, $xactions);
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
return id(new PhabricatorApplicationTransactionNoEffectResponse())
->setCancelURI($mock_uri)
->setException($ex);
}
if ($draft) {
$draft->replaceOrDelete();
}
if ($request->isAjax() && $is_preview) {
return id(new PhabricatorApplicationTransactionResponse())
->setObject($mock)
->setViewer($viewer)
->setTransactions($xactions)
->setIsPreview($is_preview);
} else {
return id(new AphrontRedirectResponse())->setURI($mock_uri);
}
}
}
diff --git a/src/applications/pholio/controller/PholioMockEditController.php b/src/applications/pholio/controller/PholioMockEditController.php
index fd1df77a8e..6c0ea58d13 100644
--- a/src/applications/pholio/controller/PholioMockEditController.php
+++ b/src/applications/pholio/controller/PholioMockEditController.php
@@ -1,373 +1,373 @@
<?php
final class PholioMockEditController extends PholioController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
if ($id) {
$mock = id(new PholioMockQuery())
->setViewer($viewer)
->needImages(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->withIDs(array($id))
->executeOne();
if (!$mock) {
return new Aphront404Response();
}
$title = pht('Edit Mock: %s', $mock->getName());
$is_new = false;
- $mock_images = $mock->getImages();
+ $mock_images = $mock->getActiveImages();
$files = mpull($mock_images, 'getFile');
$mock_images = mpull($mock_images, null, 'getFilePHID');
} else {
$mock = PholioMock::initializeNewMock($viewer);
$title = pht('Create Mock');
$is_new = true;
$files = array();
$mock_images = array();
}
if ($is_new) {
$v_projects = array();
} else {
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
$mock->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
$v_projects = array_reverse($v_projects);
}
$e_name = true;
$e_images = count($mock_images) ? null : true;
$errors = array();
$posted_mock_images = array();
$v_name = $mock->getName();
$v_desc = $mock->getDescription();
$v_view = $mock->getViewPolicy();
$v_edit = $mock->getEditPolicy();
$v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$mock->getPHID());
$v_space = $mock->getSpacePHID();
if ($request->isFormPost()) {
$xactions = array();
$type_name = PholioMockNameTransaction::TRANSACTIONTYPE;
$type_desc = PholioMockDescriptionTransaction::TRANSACTIONTYPE;
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
$type_cc = PhabricatorTransactions::TYPE_SUBSCRIBERS;
$type_space = PhabricatorTransactions::TYPE_SPACE;
$v_name = $request->getStr('name');
$v_desc = $request->getStr('description');
$v_view = $request->getStr('can_view');
$v_edit = $request->getStr('can_edit');
$v_cc = $request->getArr('cc');
$v_projects = $request->getArr('projects');
$v_space = $request->getStr('spacePHID');
$mock_xactions = array();
$mock_xactions[$type_name] = $v_name;
$mock_xactions[$type_desc] = $v_desc;
$mock_xactions[$type_view] = $v_view;
$mock_xactions[$type_edit] = $v_edit;
$mock_xactions[$type_cc] = array('=' => $v_cc);
$mock_xactions[$type_space] = $v_space;
$file_phids = $request->getArr('file_phids');
if ($file_phids) {
$files = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs($file_phids)
->execute();
$files = mpull($files, null, 'getPHID');
$files = array_select_keys($files, $file_phids);
} else {
$files = array();
}
if (!$files) {
$e_images = pht('Required');
$errors[] = pht('You must add at least one image to the mock.');
} else {
$mock->setCoverPHID(head($files)->getPHID());
}
foreach ($mock_xactions as $type => $value) {
$xactions[$type] = id(new PholioTransaction())
->setTransactionType($type)
->setNewValue($value);
}
$order = $request->getStrList('imageOrder');
$sequence_map = array_flip($order);
$replaces = $request->getArr('replaces');
$replaces_map = array_flip($replaces);
/**
* Foreach file posted, check to see whether we are replacing an image,
* adding an image, or simply updating image metadata. Create
* transactions for these cases as appropos.
*/
foreach ($files as $file_phid => $file) {
$replaces_image_phid = null;
if (isset($replaces_map[$file_phid])) {
$old_file_phid = $replaces_map[$file_phid];
if ($old_file_phid != $file_phid) {
$old_image = idx($mock_images, $old_file_phid);
if ($old_image) {
$replaces_image_phid = $old_image->getPHID();
}
}
}
$existing_image = idx($mock_images, $file_phid);
$title = (string)$request->getStr('title_'.$file_phid);
$description = (string)$request->getStr('description_'.$file_phid);
$sequence = $sequence_map[$file_phid];
if ($replaces_image_phid) {
$replace_image = PholioImage::initializeNewImage()
->setAuthorPHID($viewer->getPHID())
->setReplacesImagePHID($replaces_image_phid)
->setFilePhid($file_phid)
->attachFile($file)
->setName(strlen($title) ? $title : $file->getName())
->setDescription($description)
->setSequence($sequence);
$xactions[] = id(new PholioTransaction())
->setTransactionType(
PholioImageReplaceTransaction::TRANSACTIONTYPE)
->setNewValue($replace_image);
$posted_mock_images[] = $replace_image;
} else if (!$existing_image) { // this is an add
$add_image = PholioImage::initializeNewImage()
->setAuthorPHID($viewer->getPHID())
->setFilePhid($file_phid)
->attachFile($file)
->setName(strlen($title) ? $title : $file->getName())
->setDescription($description)
->setSequence($sequence);
$xactions[] = id(new PholioTransaction())
->setTransactionType(PholioImageFileTransaction::TRANSACTIONTYPE)
->setNewValue(
array('+' => array($add_image)));
$posted_mock_images[] = $add_image;
} else {
$xactions[] = id(new PholioTransaction())
->setTransactionType(PholioImageNameTransaction::TRANSACTIONTYPE)
->setNewValue(
array($existing_image->getPHID() => $title));
$xactions[] = id(new PholioTransaction())
->setTransactionType(
PholioImageDescriptionTransaction::TRANSACTIONTYPE)
->setNewValue(
array($existing_image->getPHID() => $description));
$xactions[] = id(new PholioTransaction())
->setTransactionType(
PholioImageSequenceTransaction::TRANSACTIONTYPE)
->setNewValue(
array($existing_image->getPHID() => $sequence));
$posted_mock_images[] = $existing_image;
}
}
foreach ($mock_images as $file_phid => $mock_image) {
if (!isset($files[$file_phid]) && !isset($replaces[$file_phid])) {
// this is an outright delete
$xactions[] = id(new PholioTransaction())
->setTransactionType(PholioImageFileTransaction::TRANSACTIONTYPE)
->setNewValue(
array('-' => array($mock_image)));
}
}
if (!$errors) {
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$xactions[] = id(new PholioTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $proj_edge_type)
->setNewValue(array('=' => array_fuse($v_projects)));
$mock->openTransaction();
$editor = id(new PholioMockEditor())
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setActor($viewer);
$xactions = $editor->applyTransactions($mock, $xactions);
$mock->saveTransaction();
return id(new AphrontRedirectResponse())
->setURI('/M'.$mock->getID());
}
}
if ($id) {
$submit = id(new AphrontFormSubmitControl())
->addCancelButton('/M'.$id)
->setValue(pht('Save'));
} else {
$submit = id(new AphrontFormSubmitControl())
->addCancelButton($this->getApplicationURI())
->setValue(pht('Create'));
}
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($mock)
->execute();
// NOTE: Make this show up correctly on the rendered form.
$mock->setViewPolicy($v_view);
$mock->setEditPolicy($v_edit);
$image_elements = array();
if ($posted_mock_images) {
$display_mock_images = $posted_mock_images;
} else {
$display_mock_images = $mock_images;
}
foreach ($display_mock_images as $mock_image) {
$image_elements[] = id(new PholioUploadedImageView())
->setUser($viewer)
->setImage($mock_image)
->setReplacesPHID($mock_image->getFilePHID());
}
$list_id = celerity_generate_unique_node_id();
$drop_id = celerity_generate_unique_node_id();
$order_id = celerity_generate_unique_node_id();
$list_control = phutil_tag(
'div',
array(
'id' => $list_id,
'class' => 'pholio-edit-list',
),
$image_elements);
$drop_control = phutil_tag(
'a',
array(
'id' => $drop_id,
'class' => 'pholio-edit-drop',
),
pht('Click here, or drag and drop images to add them to the mock.'));
$order_control = phutil_tag(
'input',
array(
'type' => 'hidden',
'name' => 'imageOrder',
'id' => $order_id,
));
Javelin::initBehavior(
'pholio-mock-edit',
array(
'listID' => $list_id,
'dropID' => $drop_id,
'orderID' => $order_id,
'uploadURI' => '/file/dropupload/',
'renderURI' => $this->getApplicationURI('image/upload/'),
'pht' => array(
'uploading' => pht('Uploading Image...'),
'uploaded' => pht('Upload Complete...'),
'undo' => pht('Undo'),
'removed' => pht('This image will be removed from the mock.'),
),
));
require_celerity_resource('pholio-edit-css');
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild($order_control)
->appendChild(
id(new AphrontFormTextControl())
->setName('name')
->setValue($v_name)
->setLabel(pht('Name'))
->setError($e_name))
->appendChild(
id(new PhabricatorRemarkupControl())
->setName('description')
->setValue($v_desc)
->setLabel(pht('Description'))
->setUser($viewer))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Tags'))
->setName('projects')
->setValue($v_projects)
->setDatasource(new PhabricatorProjectDatasource()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Subscribers'))
->setName('cc')
->setValue($v_cc)
->setUser($viewer)
->setDatasource(new PhabricatorMetaMTAMailableDatasource()))
->appendChild(
id(new AphrontFormPolicyControl())
->setUser($viewer)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($mock)
->setPolicies($policies)
->setSpacePHID($v_space)
->setName('can_view'))
->appendChild(
id(new AphrontFormPolicyControl())
->setUser($viewer)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($mock)
->setPolicies($policies)
->setName('can_edit'))
->appendChild(
id(new AphrontFormMarkupControl())
->setValue($list_control))
->appendChild(
id(new AphrontFormMarkupControl())
->setValue($drop_control)
->setError($e_images))
->appendChild($submit);
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setFormErrors($errors)
->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
->setForm($form);
$crumbs = $this->buildApplicationCrumbs();
if (!$is_new) {
$crumbs->addTextCrumb($mock->getMonogram(), '/'.$mock->getMonogram());
}
$crumbs->addTextCrumb($title);
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setFooter($form_box);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->addQuicksandConfig(
array('mockEditConfig' => true))
->appendChild($view);
}
}
diff --git a/src/applications/pholio/query/PholioMockQuery.php b/src/applications/pholio/query/PholioMockQuery.php
index 9e3154ec5c..465f23d34b 100644
--- a/src/applications/pholio/query/PholioMockQuery.php
+++ b/src/applications/pholio/query/PholioMockQuery.php
@@ -1,176 +1,174 @@
<?php
final class PholioMockQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $authorPHIDs;
private $statuses;
private $needCoverFiles;
private $needImages;
private $needInlineComments;
private $needTokenCounts;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withAuthorPHIDs(array $author_phids) {
$this->authorPHIDs = $author_phids;
return $this;
}
public function withStatuses(array $statuses) {
$this->statuses = $statuses;
return $this;
}
public function needCoverFiles($need_cover_files) {
$this->needCoverFiles = $need_cover_files;
return $this;
}
public function needImages($need_images) {
$this->needImages = $need_images;
return $this;
}
public function needInlineComments($need_inline_comments) {
$this->needInlineComments = $need_inline_comments;
return $this;
}
public function needTokenCounts($need) {
$this->needTokenCounts = $need;
return $this;
}
public function newResultObject() {
return new PholioMock();
}
protected function loadPage() {
- $mocks = $this->loadStandardPage(new PholioMock());
+ $mocks = $this->loadStandardPage($this->newResultObject());
if ($mocks && $this->needImages) {
self::loadImages($this->getViewer(), $mocks, $this->needInlineComments);
}
if ($mocks && $this->needCoverFiles) {
$this->loadCoverFiles($mocks);
}
if ($mocks && $this->needTokenCounts) {
$this->loadTokenCounts($mocks);
}
return $mocks;
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'mock.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'mock.phid IN (%Ls)',
$this->phids);
}
if ($this->authorPHIDs !== null) {
$where[] = qsprintf(
$conn,
'mock.authorPHID in (%Ls)',
$this->authorPHIDs);
}
if ($this->statuses !== null) {
$where[] = qsprintf(
$conn,
'mock.status IN (%Ls)',
$this->statuses);
}
return $where;
}
public static function loadImages(
PhabricatorUser $viewer,
array $mocks,
$need_inline_comments) {
assert_instances_of($mocks, 'PholioMock');
$mock_map = mpull($mocks, null, 'getPHID');
$all_images = id(new PholioImageQuery())
->setViewer($viewer)
->setMockCache($mock_map)
->withMockPHIDs(array_keys($mock_map))
->needInlineComments($need_inline_comments)
->execute();
$image_groups = mgroup($all_images, 'getMockPHID');
foreach ($mocks as $mock) {
$mock_images = idx($image_groups, $mock->getPHID(), array());
- $mock->attachAllImages($mock_images);
- $active_images = mfilter($mock_images, 'getIsObsolete', true);
- $mock->attachImages(msort($active_images, 'getSequence'));
+ $mock->attachImages($mock_images);
}
}
private function loadCoverFiles(array $mocks) {
assert_instances_of($mocks, 'PholioMock');
$cover_file_phids = mpull($mocks, 'getCoverPHID');
$cover_files = id(new PhabricatorFileQuery())
->setViewer($this->getViewer())
->withPHIDs($cover_file_phids)
->execute();
$cover_files = mpull($cover_files, null, 'getPHID');
foreach ($mocks as $mock) {
$file = idx($cover_files, $mock->getCoverPHID());
if (!$file) {
$file = PhabricatorFile::loadBuiltin($this->getViewer(), 'missing.png');
}
$mock->attachCoverFile($file);
}
}
private function loadTokenCounts(array $mocks) {
assert_instances_of($mocks, 'PholioMock');
$phids = mpull($mocks, 'getPHID');
$counts = id(new PhabricatorTokenCountQuery())
->withObjectPHIDs($phids)
->execute();
foreach ($mocks as $mock) {
$mock->attachTokenCount(idx($counts, $mock->getPHID(), 0));
}
}
public function getQueryApplicationClass() {
return 'PhabricatorPholioApplication';
}
protected function getPrimaryTableAlias() {
return 'mock';
}
}
diff --git a/src/applications/pholio/query/PholioMockSearchEngine.php b/src/applications/pholio/query/PholioMockSearchEngine.php
index 2433484d69..cbb175b2de 100644
--- a/src/applications/pholio/query/PholioMockSearchEngine.php
+++ b/src/applications/pholio/query/PholioMockSearchEngine.php
@@ -1,153 +1,153 @@
<?php
final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Pholio Mocks');
}
public function getApplicationClassName() {
return 'PhabricatorPholioApplication';
}
public function newQuery() {
return id(new PholioMockQuery())
->needCoverFiles(true)
->needImages(true)
->needTokenCounts(true);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setKey('authorPHIDs')
->setAliases(array('authors'))
->setLabel(pht('Authors')),
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setOptions(
id(new PholioMock())
->getStatuses()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
return $query;
}
protected function getURI($path) {
return '/pholio/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'open' => pht('Open Mocks'),
'all' => pht('All Mocks'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'open':
return $query->setParameter(
'statuses',
array('open'));
case 'all':
return $query;
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $mocks,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($mocks, 'PholioMock');
$viewer = $this->requireViewer();
$handles = $viewer->loadHandles(mpull($mocks, 'getAuthorPHID'));
$xform = PhabricatorFileTransform::getTransformByKey(
PhabricatorFileThumbnailTransform::TRANSFORM_PINBOARD);
$board = new PHUIPinboardView();
foreach ($mocks as $mock) {
$image = $mock->getCoverFile();
$image_uri = $image->getURIForTransform($xform);
list($x, $y) = $xform->getTransformedDimensions($image);
$header = 'M'.$mock->getID().' '.$mock->getName();
$item = id(new PHUIPinboardItemView())
->setUser($viewer)
->setHeader($header)
->setObject($mock)
->setURI('/M'.$mock->getID())
->setImageURI($image_uri)
->setImageSize($x, $y)
->setDisabled($mock->isClosed())
- ->addIconCount('fa-picture-o', count($mock->getImages()))
+ ->addIconCount('fa-picture-o', count($mock->getActiveImages()))
->addIconCount('fa-trophy', $mock->getTokenCount());
if ($mock->getAuthorPHID()) {
$author_handle = $handles[$mock->getAuthorPHID()];
$datetime = phabricator_date($mock->getDateCreated(), $viewer);
$item->appendChild(
pht('By %s on %s', $author_handle->renderLink(), $datetime));
}
$board->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($board);
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Mock'))
->setHref('/pholio/create/')
->setColor(PHUIButtonView::GREEN);
$icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Upload sets of images for review with revision history and '.
'inline comments.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php
index a7e9a9b05d..0e61ffc2d1 100644
--- a/src/applications/pholio/storage/PholioMock.php
+++ b/src/applications/pholio/storage/PholioMock.php
@@ -1,291 +1,285 @@
<?php
final class PholioMock extends PholioDAO
implements
PhabricatorPolicyInterface,
PhabricatorSubscribableInterface,
PhabricatorTokenReceiverInterface,
PhabricatorFlaggableInterface,
PhabricatorApplicationTransactionInterface,
PhabricatorTimelineInterface,
PhabricatorProjectInterface,
PhabricatorDestructibleInterface,
PhabricatorSpacesInterface,
PhabricatorMentionableInterface,
PhabricatorFulltextInterface,
PhabricatorFerretInterface {
const STATUS_OPEN = 'open';
const STATUS_CLOSED = 'closed';
protected $authorPHID;
protected $viewPolicy;
protected $editPolicy;
protected $name;
protected $description;
protected $coverPHID;
protected $mailKey;
protected $status;
protected $spacePHID;
private $images = self::ATTACHABLE;
- private $allImages = self::ATTACHABLE;
private $coverFile = self::ATTACHABLE;
private $tokenCount = self::ATTACHABLE;
public static function initializeNewMock(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorPholioApplication'))
->executeOne();
$view_policy = $app->getPolicy(PholioDefaultViewCapability::CAPABILITY);
$edit_policy = $app->getPolicy(PholioDefaultEditCapability::CAPABILITY);
return id(new PholioMock())
->setAuthorPHID($actor->getPHID())
->attachImages(array())
->setStatus(self::STATUS_OPEN)
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
->setSpacePHID($actor->getDefaultSpacePHID());
}
public function getMonogram() {
return 'M'.$this->getID();
}
public function getURI() {
return '/'.$this->getMonogram();
}
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'text128',
'description' => 'text',
'mailKey' => 'bytes20',
'status' => 'text12',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
'phid' => array(
'columns' => array('phid'),
'unique' => true,
),
'authorPHID' => array(
'columns' => array('authorPHID'),
),
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID('MOCK');
}
public function save() {
if (!$this->getMailKey()) {
$this->setMailKey(Filesystem::readRandomCharacters(20));
}
return parent::save();
}
- /**
- * These should be the images currently associated with the Mock.
- */
public function attachImages(array $images) {
assert_instances_of($images, 'PholioImage');
+ $images = mpull($images, null, 'getPHID');
+ $images = msort($images, 'getSequence');
$this->images = $images;
return $this;
}
public function getImages() {
- $this->assertAttached($this->images);
- return $this->images;
+ return $this->assertAttached($this->images);
}
- /**
- * These should be *all* images associated with the Mock. This includes
- * images which have been removed and / or replaced from the Mock.
- */
- public function attachAllImages(array $images) {
- assert_instances_of($images, 'PholioImage');
- $this->allImages = $images;
- return $this;
- }
+ public function getActiveImages() {
+ $images = $this->getImages();
+
+ foreach ($images as $phid => $image) {
+ if ($image->getIsObsolete()) {
+ unset($images[$phid]);
+ }
+ }
- public function getAllImages() {
- $this->assertAttached($this->images);
- return $this->allImages;
+ return $images;
}
public function attachCoverFile(PhabricatorFile $file) {
$this->coverFile = $file;
return $this;
}
public function getCoverFile() {
$this->assertAttached($this->coverFile);
return $this->coverFile;
}
public function getTokenCount() {
$this->assertAttached($this->tokenCount);
return $this->tokenCount;
}
public function attachTokenCount($count) {
$this->tokenCount = $count;
return $this;
}
public function getImageHistorySet($image_id) {
- $images = $this->getAllImages();
+ $images = $this->getImages();
$images = mpull($images, null, 'getID');
$selected_image = $images[$image_id];
$replace_map = mpull($images, null, 'getReplacesImagePHID');
$phid_map = mpull($images, null, 'getPHID');
// find the earliest image
$image = $selected_image;
while (isset($phid_map[$image->getReplacesImagePHID()])) {
$image = $phid_map[$image->getReplacesImagePHID()];
}
// now build history moving forward
$history = array($image->getID() => $image);
while (isset($replace_map[$image->getPHID()])) {
$image = $replace_map[$image->getPHID()];
$history[$image->getID()] = $image;
}
return $history;
}
public function getStatuses() {
$options = array();
$options[self::STATUS_OPEN] = pht('Open');
$options[self::STATUS_CLOSED] = pht('Closed');
return $options;
}
public function isClosed() {
return ($this->getStatus() == 'closed');
}
/* -( PhabricatorSubscribableInterface Implementation )-------------------- */
public function isAutomaticallySubscribed($phid) {
return ($this->authorPHID == $phid);
}
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return ($viewer->getPHID() == $this->getAuthorPHID());
}
public function describeAutomaticCapability($capability) {
return pht("A mock's owner can always view and edit it.");
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new PholioMockEditor();
}
public function getApplicationTransactionTemplate() {
return new PholioTransaction();
}
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
public function getUsersToNotifyOfTokenGiven() {
return array(
$this->getAuthorPHID(),
);
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$images = id(new PholioImageQuery())
->setViewer($engine->getViewer())
->withMockIDs(array($this->getPHID()))
->execute();
foreach ($images as $image) {
$image->delete();
}
$this->delete();
$this->saveTransaction();
}
/* -( PhabricatorSpacesInterface )----------------------------------------- */
public function getSpacePHID() {
return $this->spacePHID;
}
/* -( PhabricatorFulltextInterface )--------------------------------------- */
public function newFulltextEngine() {
return new PholioMockFulltextEngine();
}
/* -( PhabricatorFerretInterface )----------------------------------------- */
public function newFerretEngine() {
return new PholioMockFerretEngine();
}
/* -( PhabricatorTimelineInterace )---------------------------------------- */
public function newTimelineEngine() {
return new PholioMockTimelineEngine();
}
}
diff --git a/src/applications/pholio/view/PholioMockEmbedView.php b/src/applications/pholio/view/PholioMockEmbedView.php
index 88f2f2ac55..38b375b68b 100644
--- a/src/applications/pholio/view/PholioMockEmbedView.php
+++ b/src/applications/pholio/view/PholioMockEmbedView.php
@@ -1,63 +1,63 @@
<?php
final class PholioMockEmbedView extends AphrontView {
private $mock;
private $images = array();
public function setMock(PholioMock $mock) {
$this->mock = $mock;
return $this;
}
public function setImages(array $images) {
$this->images = $images;
return $this;
}
public function render() {
if (!$this->mock) {
throw new PhutilInvalidStateException('setMock');
}
$mock = $this->mock;
$images_to_show = array();
$thumbnail = null;
if (!empty($this->images)) {
$images_to_show = array_intersect_key(
- $this->mock->getImages(), array_flip($this->images));
+ $this->mock->getActiveImages(), array_flip($this->images));
}
$xform = PhabricatorFileTransform::getTransformByKey(
PhabricatorFileThumbnailTransform::TRANSFORM_PINBOARD);
if ($images_to_show) {
$image = head($images_to_show);
$thumbfile = $image->getFile();
$header = 'M'.$mock->getID().' '.$mock->getName().
' (#'.$image->getID().')';
$uri = '/M'.$this->mock->getID().'/'.$image->getID().'/';
} else {
$thumbfile = $mock->getCoverFile();
$header = 'M'.$mock->getID().' '.$mock->getName();
$uri = '/M'.$this->mock->getID();
}
$thumbnail = $thumbfile->getURIForTransform($xform);
list($x, $y) = $xform->getTransformedDimensions($thumbfile);
$item = id(new PHUIPinboardItemView())
->setUser($this->getUser())
->setObject($mock)
->setHeader($header)
->setURI($uri)
->setImageURI($thumbnail)
->setImageSize($x, $y)
->setDisabled($mock->isClosed())
- ->addIconCount('fa-picture-o', count($mock->getImages()))
+ ->addIconCount('fa-picture-o', count($mock->getActiveImages()))
->addIconCount('fa-trophy', $mock->getTokenCount());
return $item;
}
}
diff --git a/src/applications/pholio/view/PholioMockImagesView.php b/src/applications/pholio/view/PholioMockImagesView.php
index d5ac41cd03..70f5fe8bb3 100644
--- a/src/applications/pholio/view/PholioMockImagesView.php
+++ b/src/applications/pholio/view/PholioMockImagesView.php
@@ -1,223 +1,223 @@
<?php
final class PholioMockImagesView extends AphrontView {
private $mock;
private $imageID;
private $requestURI;
private $commentFormID;
private $panelID;
private $viewportID;
private $behaviorConfig;
public function setCommentFormID($comment_form_id) {
$this->commentFormID = $comment_form_id;
return $this;
}
public function getCommentFormID() {
return $this->commentFormID;
}
public function setRequestURI(PhutilURI $request_uri) {
$this->requestURI = $request_uri;
return $this;
}
public function getRequestURI() {
return $this->requestURI;
}
public function setImageID($image_id) {
$this->imageID = $image_id;
return $this;
}
public function getImageID() {
return $this->imageID;
}
public function setMock(PholioMock $mock) {
$this->mock = $mock;
return $this;
}
public function getMock() {
return $this->mock;
}
public function __construct() {
$this->panelID = celerity_generate_unique_node_id();
$this->viewportID = celerity_generate_unique_node_id();
}
public function getBehaviorConfig() {
if (!$this->getMock()) {
throw new PhutilInvalidStateException('setMock');
}
if ($this->behaviorConfig === null) {
$this->behaviorConfig = $this->calculateBehaviorConfig();
}
return $this->behaviorConfig;
}
private function calculateBehaviorConfig() {
$mock = $this->getMock();
// TODO: We could maybe do a better job with tailoring this, which is the
// image shown on the review stage.
$viewer = $this->getUser();
$default = PhabricatorFile::loadBuiltin($viewer, 'image-100x100.png');
$images = array();
$current_set = 0;
- foreach ($mock->getAllImages() as $image) {
+ foreach ($mock->getImages() as $image) {
$file = $image->getFile();
$metadata = $file->getMetadata();
$x = idx($metadata, PhabricatorFile::METADATA_IMAGE_WIDTH);
$y = idx($metadata, PhabricatorFile::METADATA_IMAGE_HEIGHT);
$is_obs = (bool)$image->getIsObsolete();
if (!$is_obs) {
$current_set++;
}
$description = $image->getDescription();
if (strlen($description)) {
$description = new PHUIRemarkupView($viewer, $description);
}
$history_uri = '/pholio/image/history/'.$image->getID().'/';
$images[] = array(
'id' => $image->getID(),
'fullURI' => $file->getBestURI(),
'stageURI' => ($file->isViewableImage()
? $file->getBestURI()
: $default->getBestURI()),
'pageURI' => $this->getImagePageURI($image, $mock),
'downloadURI' => $file->getDownloadURI(),
'historyURI' => $history_uri,
'width' => $x,
'height' => $y,
'title' => $image->getName(),
'descriptionMarkup' => $description,
'isObsolete' => (bool)$image->getIsObsolete(),
'isImage' => $file->isViewableImage(),
'isViewable' => $file->isViewableInBrowser(),
);
}
- $ids = mpull($mock->getImages(), 'getID');
+ $ids = mpull($mock->getActiveImages(), 'getID');
if ($this->imageID && isset($ids[$this->imageID])) {
$selected_id = $this->imageID;
} else {
$selected_id = head_key($ids);
}
$navsequence = array();
- foreach ($mock->getImages() as $image) {
+ foreach ($mock->getActiveImages() as $image) {
$navsequence[] = $image->getID();
}
$full_icon = array(
javelin_tag('span', array('aural' => true), pht('View Raw File')),
id(new PHUIIconView())->setIcon('fa-file-image-o'),
);
$download_icon = array(
javelin_tag('span', array('aural' => true), pht('Download File')),
id(new PHUIIconView())->setIcon('fa-download'),
);
$login_uri = id(new PhutilURI('/login/'))
->setQueryParam('next', (string)$this->getRequestURI());
$config = array(
'mockID' => $mock->getID(),
'panelID' => $this->panelID,
'viewportID' => $this->viewportID,
'commentFormID' => $this->getCommentFormID(),
'images' => $images,
'selectedID' => $selected_id,
'loggedIn' => $this->getUser()->isLoggedIn(),
'logInLink' => (string)$login_uri,
'navsequence' => $navsequence,
'fullIcon' => hsprintf('%s', $full_icon),
'downloadIcon' => hsprintf('%s', $download_icon),
'currentSetSize' => $current_set,
);
return $config;
}
public function render() {
if (!$this->getMock()) {
throw new PhutilInvalidStateException('setMock');
}
$mock = $this->getMock();
require_celerity_resource('javelin-behavior-pholio-mock-view');
$panel_id = $this->panelID;
$viewport_id = $this->viewportID;
$config = $this->getBehaviorConfig();
Javelin::initBehavior(
'pholio-mock-view',
$this->getBehaviorConfig());
$mock_wrapper = javelin_tag(
'div',
array(
'id' => $this->viewportID,
'sigil' => 'mock-viewport',
'class' => 'pholio-mock-image-viewport',
),
'');
$image_header = javelin_tag(
'div',
array(
'id' => 'mock-image-header',
'class' => 'pholio-mock-image-header',
),
'');
$mock_wrapper = javelin_tag(
'div',
array(
'id' => $this->panelID,
'sigil' => 'mock-panel touchable',
'class' => 'pholio-mock-image-panel',
),
array(
$image_header,
$mock_wrapper,
));
$inline_comments_holder = javelin_tag(
'div',
array(
'id' => 'mock-image-description',
'sigil' => 'mock-image-description',
'class' => 'mock-image-description',
),
'');
return phutil_tag(
'div',
array(
'class' => 'pholio-mock-image-container',
'id' => 'pholio-mock-image-container',
),
array($mock_wrapper, $inline_comments_holder));
}
private function getImagePageURI(PholioImage $image, PholioMock $mock) {
$uri = '/M'.$mock->getID().'/'.$image->getID().'/';
return $uri;
}
}
diff --git a/src/applications/pholio/view/PholioMockThumbGridView.php b/src/applications/pholio/view/PholioMockThumbGridView.php
index 457d700f1f..b859eaaa9a 100644
--- a/src/applications/pholio/view/PholioMockThumbGridView.php
+++ b/src/applications/pholio/view/PholioMockThumbGridView.php
@@ -1,181 +1,181 @@
<?php
final class PholioMockThumbGridView extends AphrontView {
private $mock;
public function setMock(PholioMock $mock) {
$this->mock = $mock;
return $this;
}
public function render() {
$mock = $this->mock;
- $all_images = $mock->getAllImages();
+ $all_images = $mock->getImages();
$all_images = mpull($all_images, null, 'getPHID');
$history = mpull($all_images, 'getReplacesImagePHID', 'getPHID');
$replaced = array();
foreach ($history as $phid => $replaces_phid) {
if ($replaces_phid) {
$replaced[$replaces_phid] = true;
}
}
// Figure out the columns. Start with all the active images.
- $images = mpull($mock->getImages(), null, 'getPHID');
+ $images = mpull($mock->getActiveImages(), null, 'getPHID');
// Now, find deleted images: obsolete images which were not replaced.
- foreach ($mock->getAllImages() as $image) {
+ foreach ($mock->getImages() as $image) {
if (!$image->getIsObsolete()) {
// Image is current.
continue;
}
if (isset($replaced[$image->getPHID()])) {
// Image was replaced.
continue;
}
// This is an obsolete image which was not replaced, so it must be
// a deleted image.
$images[$image->getPHID()] = $image;
}
$cols = array();
$depth = 0;
foreach ($images as $image) {
$phid = $image->getPHID();
$col = array();
// If this is a deleted image, null out the final column.
if ($image->getIsObsolete()) {
$col[] = null;
}
$col[] = $phid;
while ($phid && isset($history[$phid])) {
$col[] = $history[$phid];
$phid = $history[$phid];
}
$cols[] = $col;
$depth = max($depth, count($col));
}
$grid = array();
$jj = $depth;
for ($ii = 0; $ii < $depth; $ii++) {
$row = array();
if ($depth == $jj) {
$row[] = phutil_tag(
'th',
array(
'valign' => 'middle',
'class' => 'pholio-history-header',
),
pht('Current Revision'));
} else {
$row[] = phutil_tag('th', array(), null);
}
foreach ($cols as $col) {
if (empty($col[$ii])) {
$row[] = phutil_tag('td', array(), null);
} else {
$thumb = $this->renderThumbnail($all_images[$col[$ii]]);
$row[] = phutil_tag('td', array(), $thumb);
}
}
$grid[] = phutil_tag('tr', array(), $row);
$jj--;
}
$grid = phutil_tag(
'table',
array(
'id' => 'pholio-mock-thumb-grid',
'class' => 'pholio-mock-thumb-grid',
),
$grid);
$grid = id(new PHUIBoxView())
->addClass('pholio-mock-thumb-grid-container')
->appendChild($grid);
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Mock History'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($grid);
}
private function renderThumbnail(PholioImage $image) {
$thumbfile = $image->getFile();
$preview_key = PhabricatorFileThumbnailTransform::TRANSFORM_THUMBGRID;
$xform = PhabricatorFileTransform::getTransformByKey($preview_key);
Javelin::initBehavior('phabricator-tooltips');
$attributes = array(
'class' => 'pholio-mock-thumb-grid-image',
'src' => $thumbfile->getURIForTransform($xform),
);
if ($image->getFile()->isViewableImage()) {
$dimensions = $xform->getTransformedDimensions($thumbfile);
if ($dimensions) {
list($x, $y) = $dimensions;
$attributes += array(
'width' => $x,
'height' => $y,
'style' => 'top: '.floor((100 - $y) / 2).'px',
);
}
} else {
// If this is a PDF or a text file or something, we'll end up using a
// generic thumbnail which is always sized correctly.
$attributes += array(
'width' => 100,
'height' => 100,
);
}
$tag = phutil_tag('img', $attributes);
$classes = array('pholio-mock-thumb-grid-item');
if ($image->getIsObsolete()) {
$classes[] = 'pholio-mock-thumb-grid-item-obsolete';
}
$inline_count = null;
if ($image->getInlineComments()) {
$inline_count[] = phutil_tag(
'span',
array(
'class' => 'pholio-mock-thumb-grid-comment-count',
),
pht('%s', phutil_count($image->getInlineComments())));
}
return javelin_tag(
'a',
array(
'sigil' => 'mock-thumbnail has-tooltip',
'class' => implode(' ', $classes),
'href' => '#',
'meta' => array(
'imageID' => $image->getID(),
'tip' => $image->getName(),
'align' => 'N',
),
),
array(
$tag,
$inline_count,
));
}
}
diff --git a/src/applications/pholio/view/PholioTransactionView.php b/src/applications/pholio/view/PholioTransactionView.php
index 69613c5428..1126db9c85 100644
--- a/src/applications/pholio/view/PholioTransactionView.php
+++ b/src/applications/pholio/view/PholioTransactionView.php
@@ -1,141 +1,141 @@
<?php
final class PholioTransactionView
extends PhabricatorApplicationTransactionView {
private $mock;
public function setMock($mock) {
$this->mock = $mock;
return $this;
}
public function getMock() {
return $this->mock;
}
protected function shouldGroupTransactions(
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
if ($u->getAuthorPHID() != $v->getAuthorPHID()) {
// Don't group transactions by different authors.
return false;
}
if (($v->getDateCreated() - $u->getDateCreated()) > 60) {
// Don't group if transactions happened more than 60s apart.
return false;
}
switch ($u->getTransactionType()) {
case PhabricatorTransactions::TYPE_COMMENT:
case PholioMockInlineTransaction::TRANSACTIONTYPE:
break;
default:
return false;
}
switch ($v->getTransactionType()) {
case PholioMockInlineTransaction::TRANSACTIONTYPE:
return true;
}
return parent::shouldGroupTransactions($u, $v);
}
protected function renderTransactionContent(
PhabricatorApplicationTransaction $xaction) {
$out = array();
$group = $xaction->getTransactionGroup();
$type = $xaction->getTransactionType();
if ($type == PholioMockInlineTransaction::TRANSACTIONTYPE) {
array_unshift($group, $xaction);
} else {
$out[] = parent::renderTransactionContent($xaction);
}
if (!$group) {
return $out;
}
$inlines = array();
foreach ($group as $xaction) {
switch ($xaction->getTransactionType()) {
case PholioMockInlineTransaction::TRANSACTIONTYPE:
$inlines[] = $xaction;
break;
default:
throw new Exception(pht('Unknown grouped transaction type!'));
}
}
if ($inlines) {
$icon = id(new PHUIIconView())
->setIcon('fa-comment bluegrey msr');
$header = phutil_tag(
'div',
array(
'class' => 'phabricator-transaction-subheader',
),
array($icon, pht('Inline Comments')));
$out[] = $header;
foreach ($inlines as $inline) {
if (!$inline->getComment()) {
continue;
}
$out[] = $this->renderInlineContent($inline);
}
}
return $out;
}
private function renderInlineContent(PholioTransaction $inline) {
$comment = $inline->getComment();
$mock = $this->getMock();
- $images = $mock->getAllImages();
+ $images = $mock->getImages();
$images = mpull($images, null, 'getID');
$image = idx($images, $comment->getImageID());
if (!$image) {
throw new Exception(pht('No image attached!'));
}
$file = $image->getFile();
if (!$file->isViewableImage()) {
throw new Exception(pht('File is not viewable.'));
}
$image_uri = $file->getBestURI();
$thumb = id(new PHUIImageMaskView())
->addClass('mrl')
->setImage($image_uri)
->setDisplayHeight(100)
->setDisplayWidth(200)
->withMask(true)
->centerViewOnPoint(
$comment->getX(), $comment->getY(),
$comment->getHeight(), $comment->getWidth());
$link = phutil_tag(
'a',
array(
'href' => '#',
'class' => 'pholio-transaction-inline-image-anchor',
),
$thumb);
$inline_comment = parent::renderTransactionContent($inline);
return phutil_tag(
'div',
array('class' => 'pholio-transaction-inline-comment'),
array($link, $inline_comment));
}
}
diff --git a/src/applications/pholio/xaction/PholioImageFileTransaction.php b/src/applications/pholio/xaction/PholioImageFileTransaction.php
index 5f68dad9f1..6d257c313e 100644
--- a/src/applications/pholio/xaction/PholioImageFileTransaction.php
+++ b/src/applications/pholio/xaction/PholioImageFileTransaction.php
@@ -1,120 +1,120 @@
<?php
final class PholioImageFileTransaction
extends PholioImageTransactionType {
const TRANSACTIONTYPE = 'image-file';
public function generateOldValue($object) {
- $images = $object->getImages();
+ $images = $object->getActiveImages();
return array_values(mpull($images, 'getPHID'));
}
public function generateNewValue($object, $value) {
$new_value = array();
foreach ($value as $key => $images) {
$new_value[$key] = mpull($images, 'getPHID');
}
$old = array_fuse($this->getOldValue());
return $this->getEditor()->getPHIDList($old, $new_value);
}
public function applyInternalEffects($object, $value) {
$old_map = array_fuse($this->getOldValue());
$new_map = array_fuse($this->getNewValue());
$obsolete_map = array_diff_key($old_map, $new_map);
- $images = $object->getImages();
+ $images = $object->getActiveImages();
foreach ($images as $seq => $image) {
if (isset($obsolete_map[$image->getPHID()])) {
$image->setIsObsolete(1);
$image->save();
unset($images[$seq]);
}
}
$object->attachImages($images);
}
public function getTitle() {
$old = $this->getOldValue();
$new = $this->getNewValue();
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
if ($add && $rem) {
return pht(
'%s edited image(s), added %d: %s; removed %d: %s.',
$this->renderAuthor(),
count($add),
$this->renderHandleList($add),
count($rem),
$this->renderHandleList($rem));
} else if ($add) {
return pht(
'%s added %d image(s): %s.',
$this->renderAuthor(),
count($add),
$this->renderHandleList($add));
} else {
return pht(
'%s removed %d image(s): %s.',
$this->renderAuthor(),
count($rem),
$this->renderHandleList($rem));
}
}
public function getTitleForFeed() {
$old = $this->getOldValue();
$new = $this->getNewValue();
return pht(
'%s updated images of %s.',
$this->renderAuthor(),
$this->renderObject());
}
public function getIcon() {
return 'fa-picture-o';
}
public function getColor() {
$old = $this->getOldValue();
$new = $this->getNewValue();
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
if ($add && $rem) {
return PhabricatorTransactions::COLOR_YELLOW;
} else if ($add) {
return PhabricatorTransactions::COLOR_GREEN;
} else {
return PhabricatorTransactions::COLOR_RED;
}
}
public function extractFilePHIDs($object, $value) {
$images = $this->getEditor()->getNewImages();
$images = mpull($images, null, 'getPHID');
$file_phids = array();
foreach ($value as $image_phid) {
$image = idx($images, $image_phid);
if (!$image) {
continue;
}
$file_phids[] = $image->getFilePHID();
}
return $file_phids;
}
public function mergeTransactions(
$object,
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
return $this->getEditor()->mergePHIDOrEdgeTransactions($u, $v);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 20:32 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128465
Default Alt Text
(54 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment