Skip to content

Commit

Permalink
Dev: cleaning and doc
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisGac committed Jul 13, 2016
1 parent 5ff8fc3 commit ba04011
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 152 deletions.
145 changes: 145 additions & 0 deletions application/extensions/admin/grid/MassiveActionsWidget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Massive Action Widget

This widget is designed to be used with grid views. For now, in LimeSurvey core, it's used in the footer of the grids/
It generates a dropup button with massive actions, and the modal associated to each action (if needed).

When using it, you should then defined each element of the list, and the modal associated to it (if needed).

## Usage Example:

### Widget:
```php
$this->widget('ext.admin.grid.MassiveActionsWidget.MassiveActionsWidget', array(
'pk' => 'id', // The primary key identifier in the grid (for checkboxes)
'gridid' => 'question-grid', // The grid id
'dropupId' => 'muhListActions', // The dropup button id (optional)
'dropUpText' => gT('Selected question(s)...'), // The dropup text button

// The array containing the of actions and modals definition
'aActions' => array(
...
),
```

### Array of actions:
The array of actions and modals can accept different types of items :
- separator: to generate a separator in the dropup list
- dropdown-header: to generate a header un the dropup list
- action: to generate an action link, and the modal associated to it (if needed).

```php
'aActions' => array(
// Separator
array(

// li element
'type' => 'separator',
),

// Header
array(

// li element
'type' => 'dropdown-header',
'text' => "Muh Header",
),

array(
// li element
'type' => 'action',
...
),
),
```

### Actions:
The action definition consists in two parts: defining the link in the dropup list and the modal (if needed).
The link, to be defined, need a text, classes for the icon, the url of the action to apply, and the action type.
There is currently 3 action types (they are the result of the refactorisation of the old jQgrid massive actions) :

- **redirect** : when clicking on the action link, user will be redirected to the wanted url in a blank windows. The list of the checked items will be posted in a string separated by |. This is used only for tokens right now (send email...).
- **fill-session-and-redirect** : basically the same than before, but calling first an action on a controller to fill the session with the checked items before redirecting. THis is used only for tokens "add participant to CPDB" for now.
- **modal** : This is the most used case. It raises a modal to first confirm the action, then submit an ajax request to the defined url, and close the OR show an array of results.

```php
// Exemple of action
array(
// li element
'type' => 'action',
'action' => 'set-muhvalue',
'url' => App()->createUrl('/admin/controller/sa/setMultipleMuhValue/'), // The url to reach the action method
'iconClasses' => 'fa fa-muh-icon', // The class to define the icon that will be show net to the action link in the dropUp button
'text' => gT('Set muh value'), // The text of the action link in the dropUp button

// modal
'actionType' => 'modal', // the action type
...
),
```

#### Action type "modal":
The modal action is complex, and accept various parameters.

First, the modal title and its html body should be specified. Then a modal type should be defined. It correponds to a view in the widget modals/ directory. For now, only one type is available : yes-no The yes-no modal accepts parameters to change the text for "yes" and "no", and for example, to show "apply" and "cancel".

```php
// modal
'actionType' => 'modal',
'sModalTitle' => 'Muh Title', // The title of the modal
'htmlModalBody' => 'Are you sure?', // The modal text
'modalType' => 'yes-no', // The type of the modal (the view to use)
'yes' => gT('apply'), // Text replacement for yes
'no' => gT('cancel'), // Text replacement fo no
'keepopen' => 'no', // Should the modal stayed open after the ajax request ?
'grid-reload' => 'yes',
```

The modals accept a parameter **keepopen**. If it's set to true, the modal will remain opened after the ajax request, and its content will be updated to show the HTML return by the controller. For now, in LS, this behavior is used only for survey list (export) and for question deletion (can failed if conditions depends on it). Of course, it will be used for all the actions, because users love feedbacks. This can also be very useful when debugging.

It also accept a parameter **grid-reload** to define if the grid should be reloaded after the ajax request (eg: if you deleted some items, the grid will be reloaded so the deleted items will not be shown anymore).

### Form in modal:
Of course, the main interest of using a modal after clicking an action is to show a form so the user can set some values. This form, with its value, will be parsed to 'htmlModalBody'. For readability, in LS, this is done using a renderPartial :

```php
// modal
'actionType' => 'modal',
...
'htmlModalBody' => $this->renderPartial('my_view.php', array(...), true),
```

The form will not be posted to the url directly by the ajax request. Indeed, the listActions.js script will build its own post by agregating the checked items and the datas from inputs in the modals having the class "custom-data".

my_view.php:
```php
<form class="custom-modal-datas"> <!-- The form itself is optional-->
<div class="form-group">
<label class="col-sm-4 control-label"><?php eT("Muh Value:"); ?></label>
<div class="col-sm-8">
<!-- Thoses input have the class "custom-data", they will be posted by the ajax request -->
<input type="text" class="form-control custom-data" id="muhvalue" name="muhvalue" value="">
<input type="hidden" name="sid" value="<?php echo $_GET['surveyid']; ?>" class="custom-data"/>
</div>

<!-- This input doesn't have the class "custom-data", it will NOT be posted by the ajax request -->
<input type="useless" name="useless" id="useless" value="useless" />
</div>
</form>
```

## Special cases with special classes:
To fit LimeSurvey specifities, two special cases has been added to make the code dryer:
- A special case for defining question attributes (adding a class "attributes-to-update" to a custom-data)
- A special case for BootstrapSwitches ( to manage its value and reload behaviour)

### Question attributes
Instead of using a custom method for each set of question attributes to update (like setMultipleStatisticsOptions to set public_statistics, statistics_showgraph, statistics_graphtype), all question attribute editing can call the same method : question::setMultipleAttributes()

Then, in the modal form, the list of a attributes to set should not only have the class "custom-data" but also the class "attributes-to-update".
See Questions massive actions for detailed example.

### BootstrapSwitches
Bootstrap switches are often used in forms. They needed to be reloaded when the grid is updated. This has been automatized in the widget.
Also, Bootstrap switches always provides a boolean value {true, false}, whereas sometimes an integer {1,0} or a string {Y,N} can be necessary. Usually, the value is converted on the action side. But to preserver the unity and simplicity of question::setMultipleAttributes, this can be done by the listActions.js script.
To reload automatically the bootrstrap switches on grid reload, and/or convert its values, add to the switch one of the classes bootstrap-switch-boolean or bootstrap-switch-integer.
See Questions massive actions for detailed example.
6 changes: 3 additions & 3 deletions application/models/QuestionAttribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function setQuestionAttribute($iQuestionID,$sAttributeName, $sValue)
*
* @var $iSid the sid to update (only to check permission)
* @var $aQidsAndLang an array containing the list of primary keys for questions ( {qid, lang} )
* @var $aAttributesToUpdate array continaing the list of attribute to update
* @var $aAttributesToUpdate array continaing the list of attributes to update
* @var $aValidQuestionTypes the question types we can update for those attributes
*/
public function setMultiple($iSid, $aQidsAndLang, $aAttributesToUpdate, $aValidQuestionTypes)
Expand All @@ -125,8 +125,8 @@ public function setMultiple($iSid, $aQidsAndLang, $aAttributesToUpdate, $aValidQ
$iQid = $aQidAndLang[0]; // Those pairs are generated by CGridView
$sLanguage = $aQidAndLang[1];

// We need to generate a question object to then check for the question type
// So, we can also force the sid: we don't allow to update questions on different survey at the same time (permission check is by survey)
// We need to generate a question object to check for the question type
// So, we can also force the sid: we don't allow to update questions on different surveys at the same time (permission check is by survey)
$oQuestion = Question::model()->find('qid=:qid and language=:language and sid=:sid',array(":qid"=>$iQid,":language"=>$sLanguage, ":sid"=>$iSid));

// For each attribute
Expand Down
148 changes: 7 additions & 141 deletions application/views/admin/survey/Question/massive_actions/_selector.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
'no' => gT('cancel'),
'keepopen' => 'no',
'sModalTitle' => gT('Set mandatory state'),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_questions_mandatory', array('model'=>$model, 'oSurvey'=>$oSurvey), true),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_questions_mandatory', array(), true),
),

// Set CSS Class
Expand All @@ -99,7 +99,7 @@
'no' => gT('cancel'),
'keepopen' => 'no',
'sModalTitle' => gT('Set "CSS" class'),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_css_class', array('model'=>$model, 'oSurvey'=>$oSurvey), true),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_css_class', array(), true),
),

// Set Statistics
Expand All @@ -119,11 +119,9 @@
'no' => gT('cancel'),
'keepopen' => 'no',
'sModalTitle' => gT('Set statistics options'),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_statistics_options', array('model'=>$model, 'oSurvey'=>$oSurvey), true),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_statistics_options', array(), true),
),



// Separator
array(

Expand All @@ -133,15 +131,14 @@

// Download header
array(

// li element
'type' => 'dropdown-header',
'text' => gT("Advanced").' '.'('.gT("only apply to certain question types").')',
),


// Set other
// DEPEND IF SURVEY IS ACTIVE !!!!
// DEPEND IF SURVEY IS ACTIVE !!!! (checked by /admin/questions/sa/setMultipleOther/ )
// TODO: don't show that action if survey is active
array(
// li element
'type' => 'action',
Expand All @@ -158,7 +155,7 @@
'no' => gT('cancel'),
'keepopen' => 'no',
'sModalTitle' => gT('Set "other" state'),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_questions_other', array('model'=>$model, 'oSurvey'=>$oSurvey), true),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_questions_other', array(), true),
),

// Set subquestions/answers sort options
Expand All @@ -178,7 +175,7 @@
'no' => gT('cancel'),
'keepopen' => 'false',
'sModalTitle' => gT('Present subquestions/answer options in random order'),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_subquestansw_order', array('model'=>$model, 'oSurvey'=>$oSurvey), true),
'htmlModalBody' => $this->renderPartial('./survey/Question/massive_actions/_set_subquestansw_order', array(), true),
// for question types : !ABCEFHKLMOPQRWZ1:;
),

Expand All @@ -199,134 +196,3 @@
});
});
</script>

<?php /*
<div class="col-sm-4 pull-left dropup listActions" data-pk="id" data-grid-id="question-grid" id="questionListActions">
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<?php eT('Selected question(s)...');?>
<span class="caret"></span>
</button>
<ul class="dropdown-menu listActions" aria-labelledby="questionListActions">
<li class="dropdown-header"> <?php eT("General");?></li>
<li>
<a
href = "#"
data-url = "<?php echo App()->createUrl('/admin/questions/sa/deleteMultiple/');?>"
data-action = "delete"
data-action-title = "<?php eT('Delete questions'); ?>"
data-modal-warning-title = "<?php eT('Warning');?>"
data-modal-warning-text = "<?php eT('Are you sure you want to delete all those questions?');?>"
>
<span class="fa-stack small">
<i class="text-danger glyphicon glyphicon-trash fa-stack-1x "></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT('Delete');?>
</a>
</li>
<li>
<a
href = "#"
data-url = "<?php echo App()->createUrl('/admin/questions/sa/setMultipleQuestionGroup/');?>"
data-action = "set-group"
data-custom-modal = "setquestiongroup"
data-keepopen = "no"
>
<span class="fa-stack small">
<i class="fa fa-folder-open fa-stack-1x small"></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT("Set question group and position");?>
</a>
</li>
<li>
<a href="#"
data-url="<?php echo App()->createUrl('/admin/questions/sa/setMultipleMandatory/');?>"
data-action="set-mandatory"
data-modal-warning-title="<?php eT('Mandatory option');?>"
data-modal-warning-text="<?php eT('blablabla');?> <?php eT('Continue?');?>">
<span class="fa-stack small">
<i class="fa fa-asterisk fa-stack-1x small text-danger"></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT("Set mandatory option (on/off)");?>
</a>
</li>
<li>
<a href="#"
data-url="<?php echo App()->createUrl('/admin/questions/sa/setMultipleStats/');?>"
data-action="set-group"
data-modal-warning-title="<?php eT('Set statistics options for those question(s))');?>"
data-modal-warning-text="<?php eT('This will CCCCC.');?> <?php eT('Continue?');?>">
<span class="fa-stack small">
<i class="fa fa-bar-chart fa-stack-1x small"></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT("Set statistics options for those question(s)");?>
</a>
</li>
<li role="separator" class="divider"></li>
<li class="dropdown-header"> <?php eT("Advanced");?></li>
<li>
<a href="#"
data-url="<?php echo App()->createUrl('/admin/questions/sa/setMultipleOther/');?>"
data-action="set-other"
data-modal-warning-title="<?php eT('Set questions "other" option ');?>"
data-modal-warning-text="<?php eT('This will make AAAAAAAAAAAAAAAAA.');?> <?php eT('Continue?');?>">
<span class="fa-stack small">
<i class="fa fa-dot-circle-o fa-stack-1x small"></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT("Set 'Other' options");?> <!-- mandatory, text, etc -->
</a>
</li>
<li>
<a href="#"
data-url="<?php echo App()->createUrl('/admin/questions/sa/setMultipleOther/');?>"
data-action="set-other"
data-modal-warning-title="<?php eT('Set questions "other" option ');?>"
data-modal-warning-text="<?php eT('This will make AAAAAAAAAAAAAAAAA.');?> <?php eT('Continue?');?>">
<span class="fa-stack small">
<i class="fa fa-css3 fa-stack-1x small"></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT("CSS class(es)");?> <!-- mandatory, text, etc -->
</a>
</li>
<li>
<a href="#"
data-url="<?php echo App()->createUrl('/admin/questions/sa/setMultipleOther/');?>"
data-action="set-other"
data-modal-warning-title="<?php eT('Set questions "other" option ');?>"
data-modal-warning-text="<?php eT('This will make AAAAAAAAAAAAAAAAA.');?> <?php eT('Continue?');?>">
<span class="fa-stack small">
<i class="fa fa-sort fa-stack-1x small"></i>
<i class="fa fa-circle-o fa-stack-2x hidden"></i>
</span>
<?php eT("Answers/Subquestions sort options");?> <!-- mandatory, text, etc -->
</a>
</li>
<!-- Random order, CSS class(es),Sort answers alphabetically -->
</ul>
</div>
*/?>
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php
/**
* Set question css classes (parsed to massive action widget)
* @var $model The question model
* @var $oSurvey The survey object
*/
?>
<form class="custom-modal-datas">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php
/**
* Set question group and position modal body (parsed to massive action widget)
* @var $model The question model
* @var $oSurvey The survey object
*/
?>
<form class="custom-modal-datas">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php
/**
* Set question group and position modal body (parsed to massive action widget)
* @var $model The question model
* @var $oSurvey The survey object
*/
?>
<form class="custom-modal-datas">
Expand Down

0 comments on commit ba04011

Please sign in to comment.