Skip to content

Commit

Permalink
Merge pull request #55 from istolar/OI-40-voting-api
Browse files Browse the repository at this point in the history
OI-40 Voting api
  • Loading branch information
db-Matroskeen authored Jun 25, 2020
2 parents eced1a1 + 6f0c3a6 commit 723a7e7
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 77 deletions.
20 changes: 18 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@
{
"type": "composer",
"url": "https://asset-packagist.org"
},
{
"type": "package",
"package": {
"name": "antennaio/jquery-bar-rating",
"version": "1.2.2",
"type": "drupal-library",
"dist": {
"type": "zip",
"url": "https://github.com/antennaio/jquery-bar-rating/archive/v1.2.2.zip"
}
}
}
],
"require": {
Expand Down Expand Up @@ -50,9 +62,10 @@
"drupal/ultimate_cron": "^2.0@alpha",
"drupal/userpoints": "^1.0@alpha",
"drupal/user_registrationpassword": "1.x-dev",
"drupal/votingapi_widgets": "^1.0",
"drupal/votingapi": "3.x-dev",
"drupal/votingapi_widgets": "1.x-dev",
"npm-asset/dropzone": "^5.7",
"npm-asset/jquery-bar-rating": "^1.2",
"antennaio/jquery-bar-rating": "1.2.2",
"oomphinc/composer-installers-extender": "^1.1"
},
"config": {
Expand All @@ -66,6 +79,9 @@
"Dispatch events for changing content moderation states": "https://www.drupal.org/files/issues/2018-11-06/2873287-50.patch",
"Entity reference error messages are not user friendly": "https://www.drupal.org/files/issues/2020-06-04/3138631-9.patch"
},
"drupal/votingapi": {
"Vote rollover settings are missing the 'Never' option": "https://www.drupal.org/files/issues/2020-05-17/2791129-22-finish-port-of-settings-form.patch"
},
"drupal/votingapi_widgets": {
"Previewing a Voting API formatter causes the fatals": "https://www.drupal.org/files/issues/2019-01-09/3024465-votingwidgets-4.patch"
}
Expand Down
5 changes: 3 additions & 2 deletions config/install/field.field.node.idea.field_voting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ translatable: false
default_value:
-
status: '1'
value: 0
default_value_callback: ''
settings:
anonymous_window: '3600'
user_window: '3600'
anonymous_window: '604800'
user_window: '0'
result_function: vote_average
widget_format: fivestar
field_type: voting_api_field
2 changes: 1 addition & 1 deletion config/install/votingapi.settings.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
anonymous_window: 86400
anonymous_window: 604800
user_window: -1
calculation_schedule: immediate
delete_everywhere: false
4 changes: 2 additions & 2 deletions modules/openideal_idea/css/openideal_idea_useful.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
.votingapi-widgets.openideal-idea-useful .openideal-useful-rating a {
.votingapi-widgets.like .like-rating a {
border: none !important;
margin-right: .5em;
display: inline-block;
}

.votingapi-widgets.openideal-idea-useful .openideal-useful-rating a.disabled {
.votingapi-widgets.like .like-rating a.disabled {
opacity: 0.5;
}
26 changes: 12 additions & 14 deletions modules/openideal_idea/js/openideal_idea_useful.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
/**
* @file
* Attaches is openideal_idea_useful rating.
* Attaches like rating.
*/

(function ($, Drupal) {
Drupal.behaviors.openidealIdeaUsefulRating = {
Drupal.behaviors.likeRating = {
attach: function (context, settings) {
$('body').find('.openideal-idea-useful').each(function () {
$('body').find('.like').each(function () {
var $this = $(this);
$(this).find('select').once('processed').each(function () {
$this.find('[type=submit]').hide();
var $select = $(this);
$select.after('<div class="openideal-useful-rating"><a href="#"><i class="fa fa-thumbs-up"></a></i></div>').hide();
$this.find('.openideal-useful-rating a').eq(0).each(function () {
var isPreview = $select.data('is-edit');
$select.after('<div class="like-rating"><a href="#"><i class="fa fa-thumbs-up"></i></a></div>').hide();
$this.find('.like-rating a').eq(0).each(function () {
$(this).bind('click',function (e) {
if (isPreview) {
return;
}
// Depending on vote status - trigger appropriate button.
var find = settings.openidealUser.voted ? '.openideal-votes-like-delete' : '.openideal-votes-like-submit';
e.preventDefault();
$select.get(0).selectedIndex = 0;
$this.find('[type=submit]').trigger('click');
$this.find('a').addClass('disabled');
})
})
$this.find('.openideal-useful-rating a').eq(1).each(function () {
$(this).bind('click',function (e) {
e.preventDefault();
$select.get(0).selectedIndex = 1;
$this.find('[type=submit]').trigger('click');
$this.find(find).trigger('click');
$this.find('a').addClass('disabled');
})
})
Expand Down
15 changes: 15 additions & 0 deletions modules/openideal_idea/openideal_idea.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

/**
* @file
* Installation functions for Openideal Idea module.
*/

/**
* Implements hook_install().
*/
function openideal_idea_install() {
// Assign a fairly low weight to ensure our implementation of
// hook_entity_type_build() is run among the last ones.
module_set_weight('openideal_idea', 10);
}
30 changes: 20 additions & 10 deletions modules/openideal_idea/openideal_idea.module
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Drupal\openideal_idea\Form\OpenidealBaseRatingForm;

/**
* Implements hook_form_alter().
*/
function openideal_idea_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if ($form_id == 'node_idea_form') {
// Check challenge query parameter.
if ($challenge_id = \Drupal::request()->get('challenge')) {
if ($challenge_id = Drupal::request()->get('challenge')) {
// Load predefined challenge node.
$predefined_challenge = \Drupal::entityTypeManager()
$predefined_challenge = Drupal::entityTypeManager()
->getStorage('node')
->load($challenge_id);
if (!empty($predefined_challenge)) {
Expand Down Expand Up @@ -64,7 +65,7 @@ function openideal_idea_node_insert(EntityInterface $entity) {
try {
// Create the group for the node.
/** @var \Drupal\group\Entity\Group $group */
$group = \Drupal::entityTypeManager()->getStorage('group')
$group = Drupal::entityTypeManager()->getStorage('group')
->create([
'label' => $entity->label(),
'type' => 'idea',
Expand All @@ -76,8 +77,8 @@ function openideal_idea_node_insert(EntityInterface $entity) {
// Add the entity to the group.
$group->addContent($entity, $plugin_id);
}
catch (\Exception $e) {
\Drupal::logger('openideal_idea')->error($e->getMessage());
catch (Exception $e) {
Drupal::logger('openideal_idea')->error($e->getMessage());
}
}
}
Expand Down Expand Up @@ -111,7 +112,7 @@ function openideal_idea_entity_access(EntityInterface $entity, $operation, Accou
*/
function openideal_idea_comment_create_access(AccountInterface $account, array $context, $entity_bundle) {
/** @var \Drupal\node\NodeInterface $node */
$node = \Drupal::routeMatch()->getParameter('node');
$node = Drupal::routeMatch()->getParameter('node');
if ($node instanceof NodeInterface && $node->bundle() === 'idea') {
return AccessResult::forbiddenIf(!$node->get('field_duplicate_of')->isEmpty());
}
Expand All @@ -125,15 +126,15 @@ function openideal_idea_menu_local_tasks_alter(&$data, $route_name, RefinableCac
return;
}

$node = \Drupal::routeMatch()->getParameter('node');
$node = Drupal::routeMatch()->getParameter('node');
if ($node->bundle() === 'idea' && $group = _openideal_idea_get_group_by_entity($node)) {
$data['tabs'][0]['group.members'] = [
'#theme' => 'menu_local_task',
'#link' => [
'title' => t('Group Members'),
'url' => Url::fromRoute('view.group_members.page_1', ['group' => $group->id()]),
],
'#access' => $group->hasPermission('administer members', \Drupal::currentUser()),
'#access' => $group->hasPermission('administer members', Drupal::currentUser()),
];

// The tab we're adding is dependent on a user's access to add content.
Expand All @@ -153,7 +154,7 @@ function openideal_idea_menu_local_tasks_alter(&$data, $route_name, RefinableCac
function _openideal_idea_get_group_by_entity($entity) {
// In our case we will have one node per group.
// We get all group ids but return just the first one.
$group_contents = \Drupal::entityTypeManager()
$group_contents = Drupal::entityTypeManager()
->getStorage('group_content')
->loadByEntity($entity);
foreach ($group_contents as $group_content) {
Expand All @@ -179,7 +180,7 @@ function openideal_idea_form_views_exposed_form_alter(&$form, FormStateInterface
unset($form['phase']['#options']['Life Cycle Phases']);
}
// Get the list of published and opened challenges.
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
$node_storage = Drupal::entityTypeManager()->getStorage('node');
$query = $node_storage->getQuery()
->condition('type', 'challenge', '=')
->condition('field_is_open', TRUE, '=')
Expand All @@ -206,3 +207,12 @@ function openideal_idea_form_views_exposed_form_alter(&$form, FormStateInterface
'#options' => $options,
];
}

/**
* Implements hook_entity_type_build().
*/
function openideal_idea_entity_type_build(array &$entity_types) {
// Replace default form for OpenidealLikeWidget widget plugin.
// To add "un-like" ability to the Idea bundle.
$entity_types['vote']->setFormClass('votingapi_openideal_useful', OpenidealBaseRatingForm::class);
}
109 changes: 109 additions & 0 deletions modules/openideal_idea/src/Form/OpenidealBaseRatingForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace Drupal\openideal_idea\Form;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\votingapi_widgets\Form\BaseRatingForm;
use Drupal\votingapi\VoteResultFunctionManager;

/**
* Form controller for OpenidealBaseRatingForm class.
*
* Extend the votingapi_widgets module base form
* and add the ability to cancel/delete the vote,
* in like widget.
*
* @Todo: remove once the ability to cancel/delete vote will be added.
* https://www.drupal.org/project/votingapi_widgets/issues/3051783
* https://www.drupal.org/project/votingapi_widgets/issues/2831545
*/
class OpenidealBaseRatingForm extends BaseRatingForm {

/**
* {@inheritDoc}
*/
public function __construct(VoteResultFunctionManager $votingapi_result, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
parent::__construct($votingapi_result, $entity_repository);
}

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Add the ability to delete vote.
$form = parent::buildForm($form, $form_state);

$form['delete'] = [
'#type' => 'submit',
'#value' => $this->t('delete'),
'#attributes' => ['class' => ['openideal-votes-like-delete', 'hidden']],
'#ajax' => [
'callback' => [$this, 'ajaxSubmitDelete'],
'event' => 'click',
'wrapper' => $form['#attributes']['id'],
'progress' => [
'type' => NULL,
],
],
];
$form['submit']['#attributes']['class'][] = 'openideal-votes-like-submit';
$form['#attached']['drupalSettings']['openidealUser']['voted'] = !$this->getEntity()->isNew();

return $form;
}

/**
* Ajax deletion submit handler.
*/
public function ajaxSubmitDelete(array $form, FormStateInterface $form_state) {
// Delete the vote and recalcute results via voting plugin manager.
$entity = $this->getEntity();
$entity->delete();
$this->votingapiResult->recalculateResults($entity->getVotedEntityType(), $entity->getVotedEntityId(), $entity->getEntityTypeId());

// Values taken from parent::ajaxSubmit with appropriate adjustments.
$settings = $form_state->get('settings');
$result_function = $this->getResultFunction($form_state);
$plugin = $form_state->get('plugin');
$result_value = $this->getResults($result_function, TRUE);

$form['value']['#attributes']['data-show-own-vote'] = 'true';
$form['value']['#default_value'] = 0;

if ($settings['show_own_vote'] == '0') {
$form['value']['#attributes']['data-show-own-vote'] = 'false';
$form['value']['#default_value'] = $result_value;
}

$form['value']['#attributes']['data-vote-value'] = 0;
$form['value']['#attributes']['data-result-value'] = $result_value;
if ($settings['show_results'] == '1') {
$form['result']['#children']['result'] = $plugin->getVoteSummary($entity);
}

$form['#attached']['drupalSettings']['openidealUser']['voted'] = FALSE;

return $form;
}

/**
* {@inheritDoc}
*/
public function ajaxSubmit(array $form, FormStateInterface $form_state) {
$form = parent::ajaxSubmit($form, $form_state);
// The validation provided by module not working because value in
// settings is integer and compared that value with string. Comparison
// executes with strict comparison - "===".
if ($form_state->get('settings')['show_results'] == '1') {
$form['result']['#children']['result'] = $form_state->get('plugin')->getVoteSummary($this->getEntity());
}

$form['#attached']['drupalSettings']['openidealUser']['voted'] = TRUE;

return $form;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Drupal\openideal_idea\Plugin\votingapi_widget;

use Drupal\votingapi_widgets\Plugin\votingapi_widget\LikeWidget;

/**
* Openideal Useful Widget.
*
* @VotingApiWidget(
* id = "openideal_useful",
* label = @Translation("Openideal Like"),
* values = {
* 1 = @Translation("Opdenideal Like"),
* },
* )
*/
class OpenidealLikeWidget extends LikeWidget {

/**
* {@inheritdoc}
*/
public function buildForm($entity_type, $entity_bundle, $entity_id, $vote_type, $field_name, $settings) {
$form = parent::buildForm($entity_type, $entity_bundle, $entity_id, $vote_type, $field_name, $settings);
$form['#attached']['library'] = ['openideal_idea/useful'];
return $form;
}

}
Loading

0 comments on commit 723a7e7

Please sign in to comment.