Matthias Mullie has uploaded a new change for review.
https://gerrit.wikimedia.org/r/89012
Change subject: Add link to history
......................................................................
Add link to history
* link to history added behind "timestamp"
* add edit post icon
* only display hide/delete/censor in flagging flyout
* hide flag icon if no actions are available to the user
* refactored PostActionMenu, it was impractical to build multiple different
buttons per actions (still not entirely happy with the new class, but it's an
improvement)
* removed "timestamp" border-bottom, should probably only show underline, on
hover, if there's a link
Change-Id: Ifff327500780998c0faea12f5a6f2fbb0daa4b61
---
M includes/Model/PostRevision.php
M includes/Templating.php
M includes/View/PostActionMenu.php
M modules/base/styles/various.less
M modules/discussion/forms.js
M modules/discussion/styles/post.less
M modules/discussion/ui.js
M templates/post.html.php
8 files changed, 228 insertions(+), 95 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow
refs/changes/12/89012/1
diff --git a/includes/Model/PostRevision.php b/includes/Model/PostRevision.php
index d6f6e71..d5d4fe7 100644
--- a/includes/Model/PostRevision.php
+++ b/includes/Model/PostRevision.php
@@ -159,6 +159,7 @@
return false;
}
}
+
public function isAllowedToEdit( $user ) {
if ( $user->isAnon() ) {
return false;
diff --git a/includes/Templating.php b/includes/Templating.php
index f647189..b254c3a 100644
--- a/includes/Templating.php
+++ b/includes/Templating.php
@@ -88,6 +88,8 @@
}
public function renderPost( PostRevision $post, Block $block, $return =
true ) {
+ global $wgUser, $wgFlowTokenSalt;
+
return $this->render(
'flow:post.html.php',
array(
@@ -95,7 +97,13 @@
'post' => $post,
// An ideal world may pull this from the
container, but for now this is fine. This templating
// class has too many responsibilities to keep
receiving all required objects in the constructor.
- 'postActionMenu' => new PostActionMenu(
$this->urlGenerator ),
+ 'postActionMenu' => new PostActionMenu(
+ $this->urlGenerator,
+ $wgUser,
+ $block,
+ $post,
+ $wgUser->getEditToken( $wgFlowTokenSalt
)
+ ),
),
$return
);
diff --git a/includes/View/PostActionMenu.php b/includes/View/PostActionMenu.php
index 9c41ce9..43d1ea9 100644
--- a/includes/View/PostActionMenu.php
+++ b/includes/View/PostActionMenu.php
@@ -6,85 +6,171 @@
use Flow\Model\PostRevision;
use Flow\UrlGenerator;
use Html;
+use User;
class PostActionMenu {
// Received via constructor
protected $urlGenerator;
-
- // Received for each call of self::get
protected $block;
protected $editToken;
protected $post;
protected $user;
- public function __construct( UrlGenerator $urlGenerator ) {
+ public function __construct( UrlGenerator $urlGenerator, User $user,
Block $block, PostRevision $post, $editToken ) {
$this->urlGenerator = $urlGenerator;
- }
-
- public function get( $user, Block $block, PostRevision $post,
$editToken ) {
- // For this type of shared-state to remain consistent self::get
*must* be the only public methodctio
$this->user = $user;
$this->block = $block;
$this->post = $post;
$this->editToken = $editToken;
-
- $actions = array();
-
- switch( $post->getModerationState() ) {
- case $post::MODERATED_NONE:
- if ( $user->isAllowed( 'flow-hide' ) ) {
- $actions['hide'] = $this->postAction(
'hide-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-hide-post-link mw-ui-destructive mw-ui-destructive-low' );
- }
- if ( $user->isAllowed( 'flow-delete' ) ) {
- $actions['delete'] = $this->postAction(
'delete-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-delete-post-link mw-ui-destructive mw-ui-destructive-medium' );
- }
- if ( $user->isAllowed( 'flow-censor' ) ) {
- $actions['censor'] = $this->postAction(
'censor-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-censor-post-link mw-ui-destructive' );
- }
- $actions['history'] = $this->getAction( 'post-history'
);
- if ( $post->isAllowedToEdit( $user ) ) {
- $actions['edit-post'] = $this->getAction(
'edit-post' );
- }
- break;
-
- case $post::MODERATED_HIDDEN:
- if ( $user->isAllowed( 'flow-hide' ) ) {
- $actions['restore'] = $this->postAction(
'restore-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-restore-post-link mw-ui-constructive mw-ui-destructive-low' );
- }
- if ( $user->isAllowed( 'flow-delete' ) ) {
- $actions['delete'] = $this->postAction(
'delete-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-delete-post-link mw-ui-destructive mw-ui-destructive-medium' );
- }
- if ( $user->isAllowed( 'flow-censor' ) ) {
- $actions['censor'] = $this->postAction(
'censor-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-censor-post-link mw-ui-destructive' );
- }
- $actions['history'] = $this->getAction( 'post-history'
);
- break;
-
- case $post::MODERATED_DELETED:
- if ( $user->isAllowedAny( 'flow-delete', 'flow-censor'
) ) {
- $actions['restore'] = $this->postAction(
'restore-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-restore-post-link mw-ui-constructive' );
- }
- $actions['history'] = $this->getAction( 'post-history'
);
- break;
-
- case $post::MODERATED_CENSORED:
- if ( !$user->isAllowed( 'flow-censor' ) ) {
- // no children, no nothing
- return;
- }
- $actions['restore'] = $this->postAction(
'restore-post', array( 'postId' => $post->getPostId()->getHex() ),
'flow-restore-post-link mw-ui-constructive' );
- $actions['history'] = $this->getAction( 'post-history'
);
- break;
- }
-
- // Default always-available actions
- $actions['permalink'] = $this->getAction( 'view' );
-
- return $actions;
}
- protected function postAction( $action, array $data = array(), $class )
{
- // actions that change things must be post requests
+ /**
+ * Returns action details.
+ *
+ * @param string $action
+ * @return array|bool Array of action details or false if invalid
+ */
+ protected function getActionDetails( $action ) {
+ $actions = array(
+ 'hide-post' => array(
+ 'method' => 'POST',
+ 'permissions' => array(
+ PostRevision::MODERATED_NONE =>
'flow-hide',
+ PostRevision::MODERATED_HIDDEN =>
'flow-hide',
+ ),
+ ),
+ 'delete-post' => array(
+ 'method' => 'POST',
+ 'permissions' => array(
+ PostRevision::MODERATED_NONE =>
'flow-delete',
+ PostRevision::MODERATED_HIDDEN =>
'flow-delete',
+ ),
+ ),
+ 'censor-post' => array(
+ 'method' => 'POST',
+ 'permissions' => array(
+ PostRevision::MODERATED_NONE =>
'flow-censor',
+ PostRevision::MODERATED_HIDDEN =>
'flow-censor',
+ ),
+ ),
+ 'restore-post' => array(
+ 'method' => 'POST',
+ 'permissions' => array(
+ PostRevision::MODERATED_DELETED =>
array( 'flow-delete', 'flow-censor' ),
+ PostRevision::MODERATED_CENSORED =>
'flow-censor',
+ ),
+ ),
+ 'post-history' => array(
+ 'method' => 'GET',
+ 'permissions' => array(
+ PostRevision::MODERATED_NONE => '',
+ PostRevision::MODERATED_HIDDEN => '',
+ PostRevision::MODERATED_DELETED => '',
+ PostRevision::MODERATED_CENSORED =>
'flow-censor',
+ ),
+ ),
+ 'edit-post' => array(
+ 'method' => 'GET',
+ 'permissions' => array(
+ // no permissions needed for own posts
+ PostRevision::MODERATED_NONE =>
$this->post->isAllowedToEdit( $this->user ) ? '' : 'flow-edit-post',
+ PostRevision::MODERATED_HIDDEN =>
$this->post->isAllowedToEdit( $this->user ) ? '' : 'flow-edit-post',
+ PostRevision::MODERATED_DELETED =>
$this->post->isAllowedToEdit( $this->user ) ? '' : 'flow-edit-post',
+ PostRevision::MODERATED_CENSORED =>
$this->post->isAllowedToEdit( $this->user ) ? '' : 'flow-edit-post',
+ ),
+ ),
+ 'view' => array(
+ 'method' => 'GET',
+ 'permissions' => array(
+ PostRevision::MODERATED_NONE => '',
+ PostRevision::MODERATED_HIDDEN => '',
+ PostRevision::MODERATED_DELETED => '',
+ PostRevision::MODERATED_CENSORED => '',
+ ),
+ ),
+ );
+
+ return isset( $actions[$action] ) ? $actions[$action] : false;
+ }
+
+ /**
+ * Build a button for a certain action
+ *
+ * @param string $action
+ * @param string $content Make sure $content is safe HTML!
+ * @param string $class
+ * @return string|bool Button HTML or false on failure
+ */
+ public function getButton( $action, $content, $class ) {
+ $details = $this->getActionDetails( $action );
+
+ if ( !$this->isAllowed( $action ) ) {
+ return false;
+ }
+
+ $data = array( $this->block->getName() . '[postId]' =>
$this->post->getPostId()->getHex() );
+ if ( $details['method'] === 'POST' ) {
+ return $this->postAction( $action, $data, $content,
$class );
+ } else {
+ return $this->getAction( $action, $data, $content,
$class );
+ }
+ }
+
+ /**
+ * Check if a user is allowed to perform (a) certain action(s).
+ *
+ * @param string $action
+ * @param string[optional] $action2 Overloadable to check if either of
the provided actions are allowed
+ * @return bool
+ */
+ public function isAllowed( $action /* [, $action2 [, ... ]] */ ) {
+ $details = $this->getActionDetails( $action );
+
+ // check if permission is set for this action
+ if ( !isset(
$details['permissions'][$this->post->getModerationState()] ) ) {
+ return false;
+ }
+
+ // check if user is allowed to perform action
+ return call_user_func_array(
+ array( $this->user, 'isAllowedAny' ),
+ (array)
$details['permissions'][$this->post->getModerationState()]
+ );
+ }
+
+ /**
+ * Check if a user is allowed to perform certain actions.
+ *
+ * @param string $action
+ * @param string[optional] $action2 Overloadable to check if either of
the provided actions are allowed
+ * @return bool
+ */
+ public function isAllowedAny( $action /* [, $action2 [, ... ]] */ ) {
+ $actions = func_get_args();
+ $allowed = false;
+
+ foreach ( $actions as $action ) {
+ $allowed |= $this->isAllowed( $action );
+
+ // as soon as we've found one that is allowed, break
+ if ( $allowed ) {
+ break;
+ }
+ }
+
+ return $allowed;
+ }
+
+ /**
+ * Create form for actions that require POST.
+ *
+ * @param string $action
+ * @param array $data
+ * @param string $content
+ * @param string $class
+ * @return string
+ */
+ protected function postAction( $action, array $data, $content, $class )
{
$output = array(
Html::openElement( 'form', array(
'method' => 'POST',
@@ -96,37 +182,44 @@
foreach ( $data as $name => $value ) {
$output[] = Html::element( 'input', array(
'type' => 'hidden',
- 'name' => $this->block->getName() . "[$name]",
+ 'name' => $name,
'value' => $value,
) );
}
- // Messages: flow-post-action-censor-post,
flow-post-action-delete-post,
- // flow-post-action-hide-post, flow-post-action-restore-post
+
$output[] = Html::element( 'input', array(
'type' => 'submit',
- 'class' => "mw-ui-button $class",
- 'value' => wfMessage( "flow-post-action-$action"
)->plain(),
+ 'class' => $class,
+ 'value' => $content,
) ) .
Html::closeElement( 'form' );
return implode( '', $output );
}
- protected function getAction( $action ) {
+ /**
+ * Create link for actions that require GET.
+ *
+ * @param string $action
+ * @param array $data
+ * @param string $content
+ * @param string $class
+ * @return string
+ */
+ protected function getAction( $action, array $data, $content, $class ) {
$url = $this->urlGenerator->generateUrl(
$this->block->getWorkflowId(),
$action,
- array(
- $this->block->getName() . '[postId]' =>
$this->post->getPostId()->getHex(),
- )
+ $data
);
- // Messages: flow-post-action-view,
flow-post-action-post-history, flow-post-action-edit-post
- return Html::element(
+
+ return Html::rawElement(
'a',
array(
'href' => $url,
+ 'class' => $class,
),
- wfMessage( "flow-post-action-$action" )->plain()
+ $content
);
}
}
diff --git a/modules/base/styles/various.less b/modules/base/styles/various.less
index f5ddcec..773c6c4 100644
--- a/modules/base/styles/various.less
+++ b/modules/base/styles/various.less
@@ -12,9 +12,4 @@
.flow-datestamp {
color: #aaa;
-
- span {
- line-height: 18px;
- border-bottom: 1px solid #ccc;
- }
}
diff --git a/modules/discussion/forms.js b/modules/discussion/forms.js
index cd9327f..7ec80dc 100644
--- a/modules/discussion/forms.js
+++ b/modules/discussion/forms.js
@@ -79,7 +79,7 @@
);
// Overload 'edit post' link.
- $container.find( '.flow-action-edit-post a' )
+ $container.find( '.flow-edit-post-link' )
.click( function ( e ) {
e.preventDefault();
var $postContainer = $( this ).closest( '.flow-post' ),
diff --git a/modules/discussion/styles/post.less
b/modules/discussion/styles/post.less
index 4f1c1d7..6b713de 100644
--- a/modules/discussion/styles/post.less
+++ b/modules/discussion/styles/post.less
@@ -20,9 +20,29 @@
padding-bottom: 20px;
}
+ .flow-edit-post-link {
+ margin-top: -60px; // default -40px + -20px to be pushed up
(because of .flow-post-content bottom padding)
+
+ background-position: center;
+ background-size: 20px auto;
+ background-repeat: no-repeat;
+ }
+
+ &:hover .flow-edit-post-link {
+ .background-image-svg('../../base/images/edit_normal.svg',
'../../base/images/edit_normal.png');
+
+ &:hover {
+
.background-image-svg('../../base/images/edit_hover.svg',
'../../base/images/edit_hover.png');
+ }
+ }
+
.flow-datestamp {
float: right;
padding-right: 22px;
+
+ a.flow-action-history-link {
+ color: inherit;
+ }
}
.flow-actions {
diff --git a/modules/discussion/ui.js b/modules/discussion/ui.js
index b5a68ab..e863619 100644
--- a/modules/discussion/ui.js
+++ b/modules/discussion/ui.js
@@ -22,8 +22,8 @@
// Set up timestamp on-hover
$container.find( '.flow-topic-datestamp, .flow-datestamp' )
.hover(function () {
- $(this).children( '.flow-agotime' ).toggle();
- $(this).children( '.flow-utctime' ).toggle();
+ $(this).find( '.flow-agotime' ).toggle();
+ $(this).find( '.flow-utctime' ).toggle();
} );
// Set up post creator on-hover
diff --git a/templates/post.html.php b/templates/post.html.php
index ec68a02..2b6c5ca 100644
--- a/templates/post.html.php
+++ b/templates/post.html.php
@@ -38,8 +38,6 @@
Html::closeElement( 'form' );
}
-$actions = array();
-
// The actual output
echo Html::openElement( 'div', array(
@@ -76,14 +74,25 @@
<div class="flow-post-content">
<?php echo $post->getContent( $user, 'html' );
?>
</div>
+ <?php if ( $postActionMenu->isAllowed( 'edit-post' ) ) {
+ echo $postActionMenu->getButton( 'edit-post',
wfMessage( 'flow-post-action-edit-post' )->plain(), 'flow-edit-post-link
flow-icon flow-icon-bottom-aligned' );
+ }
+ ?>
<p class="flow-datestamp">
- <span class="flow-agotime" style="display:
inline">
- <?php echo
$post->getPostId()->getHumanTimestamp(); ?>
- </span>
- <span class="flow-utctime" style="display:
none">
- <?php echo
$post->getPostId()->getTimestampObj()->getTimestamp( TS_RFC2822 ); ?>
- </span>
+ <?php
+ // timestamp html
+ $content = '
+ <span class="flow-agotime"
style="display: inline">'. $post->getPostId()->getHumanTimestamp() .'</span>
+ <span class="flow-utctime"
style="display: none">'. $post->getPostId()->getTimestampObj()->getTimestamp(
TS_RFC2822 ) .'</span>';
+
+ // build history button with timestamp
html as content
+ if ( $postActionMenu->isAllowed(
'post-history' ) ) {
+ echo
$postActionMenu->getButton( 'post-history', $content,
'flow-action-history-link' );
+ } else {
+ echo $content;
+ }
+ ?>
</p>
<div class="flow-post-interaction">
@@ -102,19 +111,26 @@
</div>
</div>
+ <?php if ( $postActionMenu->isAllowedAny( 'hide-post',
'delete-post', 'censor-post' ) ): ?>
<div class="flow-actions">
<a class="flow-actions-link flow-icon
flow-icon-bottom-aligned" href="#"><?php echo wfMessage( 'flow-post-actions'
)->escaped(); ?></a>
<div class="flow-actions-flyout">
<ul>
<?php
- foreach( $postActionMenu->get( $user,
$block, $post, $editToken ) as $key => $action ) {
- // @todo: $actions currently
includes a lot of actions, design only wants censor actions here; figure out
where others belong
- echo "<li
class=\"flow-action-$key\">$action</li>";
+ if ( $postActionMenu->isAllowed(
'hide-post' ) ) {
+ echo '<li
class="flow-action-hide">'. $postActionMenu->getButton( 'hide-post', wfMessage(
'flow-post-action-hide-post' )->plain(), 'flow-hide-post-link mw-ui-button
mw-ui-destructive mw-ui-destructive-low' ) .'</li>';
+ }
+ if ( $postActionMenu->isAllowed(
'delete-post' ) ) {
+ echo '<li
class="flow-action-delete">'. $postActionMenu->getButton( 'delete-post',
wfMessage( 'flow-post-action-delete-post' )->plain(), 'flow-delete-post-link
mw-ui-button mw-ui-destructive mw-ui-destructive-medium' ) .'</li>';
+ }
+ if ( $postActionMenu->isAllowed(
'censor-post' ) ) {
+ echo '<li
class="flow-action-censor">'. $postActionMenu->getButton( 'censor-post',
wfMessage( 'flow-post-action-censor-post' )->plain(), 'flow-censor-post-link
mw-ui-button mw-ui-destructive' ) .'</li>';
}
?>
</ul>
</div>
</div>
+ <?php endif; ?>
</div>
--
To view, visit https://gerrit.wikimedia.org/r/89012
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifff327500780998c0faea12f5a6f2fbb0daa4b61
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: Matthias Mullie <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits