Customer portal : LinkedSet widget UX improvements part 2 (Collapsing widget)

SVN:trunk[4088]
This commit is contained in:
Guillaume Lajarige
2016-05-14 17:23:43 +00:00
parent 5540fdb7db
commit 3c112eb078
5 changed files with 176 additions and 82 deletions

View File

@@ -58,10 +58,20 @@ class BsLinkedSetFieldRenderer extends FieldRenderer
if (!$this->oField->GetHidden())
{
// Rendering field
$sCollapseTogglerVisibleClass = 'glyphicon-menu-right';
$sCollapseTogglerHiddenClass = 'glyphicon-menu-down';
$sCollapseTogglerId = 'form_linkedset_toggler_' . $this->oField->GetGlobalId();
$sFieldWrapperId = 'form_linkedset_wrapper_' . $this->oField->GetGlobalId();
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>');
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')
->AddHtml($this->oField->GetLabel(), true)
->AddHtml('<a id="' . $sCollapseTogglerId . '" class="form_linkedset_toggler" data-toggle="collapse" href="#' . $sFieldWrapperId . '" aria-expanded="false" aria-controls="' . $sFieldWrapperId . '">')
->AddHtml('<span class="text">' . count($aItemIds) . '</span>')
->AddHtml('<span class="glyphicon ' . $sCollapseTogglerHiddenClass . '"></>')
->AddHtml('</a>')
->AddHtml('</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
@@ -71,7 +81,7 @@ class BsLinkedSetFieldRenderer extends FieldRenderer
// - Output
$oOutput->AddHtml(
<<<EOF
<div class="form_linkedset_wrapper">
<div class="form_linkedset_wrapper collapse" id="{$sFieldWrapperId}">
<div class="row">
<div class="col-xs-12">
<input type="hidden" id="{$this->oField->GetGlobalId()}" name="{$this->oField->GetId()}" value="{$sItemIdsAsJson}" />
@@ -89,11 +99,32 @@ EOF
$sEmptyTableLabel = htmlentities(Dict::S(($this->oField->GetReadOnly()) ? 'Portal:Datatables:Language:EmptyTable' : 'UI:Message:EmptyList:UseAdd'), ENT_QUOTES, 'UTF-8');
$sLabelGeneralCheckbox = htmlentities(Dict::S('Core:BulkExport:CheckAll') . ' / ' . Dict::S('Core:BulkExport:UncheckAll'), ENT_QUOTES, 'UTF-8');
$sSelectionOptionHtml = ($this->oField->GetReadOnly()) ? 'false' : '{"style": "multi"}';
$sSelectionInputGlobalHtml = ($this->oField->GetReadOnly()) ? '' : '<span class="row_input"><input type="checkbox" id="' . $this->oField->GetId() . '_check_all" name="' . $this->oField->GetId() . '_check_all" title="' . $sLabelGeneralCheckbox . '" /></span>';
$sSelectionInputHtml = ($this->oField->GetReadOnly()) ? '' : '<span class="row_input"><input type="checkbox" name="' . $this->oField->GetId() . '" /></span>';
$sSelectionInputGlobalHtml = ($this->oField->GetReadOnly()) ? '' : '<span class="row_input"><input type="checkbox" id="' . $this->oField->GetGlobalId() . '_check_all" name="' . $this->oField->GetGlobalId() . '_check_all" title="' . $sLabelGeneralCheckbox . '" /></span>';
$sSelectionInputHtml = ($this->oField->GetReadOnly()) ? '' : '<span class="row_input"><input type="checkbox" name="' . $this->oField->GetGlobalId() . '" /></span>';
// - Output
$oOutput->AddJs(
<<<EOF
// Collapse handlers
// - Collapsing by default to optimize form space
// It would be better to be able to construct the widget as collapsed, but in this ase, datatables thinks the container is very small and therefore renders the table as if it was in microbox.
$('#{$sFieldWrapperId}').collapse({toggle: false});
// - Change toggle icon class
$('#{$sFieldWrapperId}').on('shown.bs.collapse', function(){
// Creating the table if null (first expand). If we create it on start, it will be displayed as if it was in a micro screen due to the div being "display: none;"
if(oTable_{$this->oField->GetGlobalId()} === undefined)
{
buildTable_{$this->oField->GetGlobalId()}();
}
$('#{$sCollapseTogglerId} > span.glyphicon').removeClass('{$sCollapseTogglerHiddenClass}').addClass('{$sCollapseTogglerVisibleClass}');
})
.on('hidden.bs.collapse', function(){
$('#{$sCollapseTogglerId} > span.glyphicon').removeClass('{$sCollapseTogglerVisibleClass}').addClass('{$sCollapseTogglerHiddenClass}');
});
// Places a loader in the empty datatables
$('#{$sTableId} > tbody').html('<tr><td class="datatables_overlay" colspan="100">' + $('#page_overlay').html() + '</td></tr>');
// Prepares data for datatables
var oColumnProperties_{$this->oField->GetGlobalId()} = {$sAttributesToDisplayAsJson};
var oRawDatas_{$this->oField->GetGlobalId()} = {$sItemsAsJson};
var oTable_{$this->oField->GetGlobalId()};
@@ -147,22 +178,78 @@ EOF
return aColumnsDefinition;
};
// Helper to build the datatable
// Note : Those options should be externalized in an library so we can use them on any DataTables for the portal.
// We would just have to override / complete the necessary elements
oTable_{$this->oField->GetGlobalId()} = $('#{$sTableId}').DataTable({
"language": {
"emptyTable": "{$sEmptyTableLabel}"
},
"displayLength": -1,
"scrollY": "300px",
"scrollCollapse": true,
"order": [[1, "asc"]],
"dom": 't',
"columns": getColumnsDefinition_{$this->oField->GetGlobalId()}(),
"select": {$sSelectionOptionHtml},
"rowId": "id",
"data": oRawDatas_{$this->oField->GetGlobalId()},
});
var buildTable_{$this->oField->GetGlobalId()} = function()
{
// Instanciates datatables
oTable_{$this->oField->GetGlobalId()} = $('#{$sTableId}').DataTable({
"language": {
"emptyTable": "{$sEmptyTableLabel}"
},
"displayLength": -1,
"scrollY": "300px",
"scrollCollapse": true,
"order": [[1, "asc"]],
"dom": 't',
"columns": getColumnsDefinition_{$this->oField->GetGlobalId()}(),
"select": {$sSelectionOptionHtml},
"rowId": "id",
"data": oRawDatas_{$this->oField->GetGlobalId()},
});
// Handles items selection/deselection
// - Directly on the table
oTable_{$this->oField->GetGlobalId()}.off('select').on('select', function(oEvent, dt, type, indexes){
var aData = oTable_{$this->oField->GetGlobalId()}.rows(indexes).data().toArray();
// Checking input
$('#{$sTableId} tbody tr[role="row"].selected td:first-child input').prop('checked', true);
// Saving values in temp array
for(var i in aData)
{
var iItemId = aData[i].id;
if(!(iItemId in oSelectedItems_{$this->oField->GetGlobalId()}))
{
oSelectedItems_{$this->oField->GetGlobalId()}[iItemId] = aData[i].name;
}
}
// Updating remove button
updateRemoveButtonState_{$this->oField->GetGlobalId()}();
});
oTable_{$this->oField->GetGlobalId()}.off('deselect').on('deselect', function(oEvent, dt, type, indexes){
var aData = oTable_{$this->oField->GetGlobalId()}.rows(indexes).data().toArray();
// Checking input
$('#{$sTableId} tbody tr[role="row"]:not(.selected) td:first-child input').prop('checked', false);
// Saving values in temp array
for(var i in aData)
{
var iItemId = aData[i].id;
if(iItemId in oSelectedItems_{$this->oField->GetGlobalId()})
{
delete oSelectedItems_{$this->oField->GetGlobalId()}[iItemId];
}
}
// Unchecking global checkbox
$('#{$this->oField->GetGlobalId()}_check_all').prop('checked', false);
// Updating remove button
updateRemoveButtonState_{$this->oField->GetGlobalId()}();
});
// - From the global button
$('#{$this->oField->GetGlobalId()}_check_all').off('click').on('click', function(oEvent){
if($(this).prop('checked'))
{
oTable_{$this->oField->GetGlobalId()}.rows().select();
}
else
{
oTable_{$this->oField->GetGlobalId()}.rows().deselect();
}
updateRemoveButtonState_{$this->oField->GetGlobalId()}();
});
};
EOF
);
@@ -232,6 +319,8 @@ EOF
}
$('#{$this->oField->GetGlobalId()}').val(JSON.stringify(aObjectIds));
// Updating items count
updateItemCount();
})
.always(function(oData){
// Hiding loader
@@ -251,6 +340,8 @@ EOF
}
$('#{$this->oField->GetGlobalId()}').val(JSON.stringify(aObjectIds));
// Updating items count
updateItemCount();
}
}
});
@@ -291,55 +382,13 @@ EOF
var bIsDisabled = (Object.keys(oSelectedItems_{$this->oField->GetGlobalId()}).length == 0);
$('#{$sButtonRemoveId}').prop('disabled', bIsDisabled);
};
// - Directly on the table
oTable_{$this->oField->GetGlobalId()}.off('select').on('select', function(oEvent, dt, type, indexes){
var aData = oTable_{$this->oField->GetGlobalId()}.rows(indexes).data().toArray();
// Checking input
$('#{$sTableId} tbody tr[role="row"].selected td:first-child input').prop('checked', true);
// Saving values in temp array
for(var i in aData)
{
var iItemId = aData[i].id;
if(!(iItemId in oSelectedItems_{$this->oField->GetGlobalId()}))
{
oSelectedItems_{$this->oField->GetGlobalId()}[iItemId] = aData[i].name;
}
}
// Updating remove button
updateRemoveButtonState_{$this->oField->GetGlobalId()}();
});
oTable_{$this->oField->GetGlobalId()}.off('deselect').on('deselect', function(oEvent, dt, type, indexes){
var aData = oTable_{$this->oField->GetGlobalId()}.rows(indexes).data().toArray();
// Checking input
$('#{$sTableId} tbody tr[role="row"]:not(.selected) td:first-child input').prop('checked', false);
// Saving values in temp array
for(var i in aData)
{
var iItemId = aData[i].id;
if(iItemId in oSelectedItems_{$this->oField->GetGlobalId()})
{
delete oSelectedItems_{$this->oField->GetGlobalId()}[iItemId];
}
}
// Unchecking global checkbox
$('#{$this->oField->GetId()}_check_all').prop('checked', false);
// Updating remove button
updateRemoveButtonState_{$this->oField->GetGlobalId()}();
});
// - From the global button
$('#{$this->oField->GetId()}_check_all').off('click').on('click', function(oEvent){
if($(this).prop('checked'))
{
oTable_{$this->oField->GetGlobalId()}.rows().select();
}
else
{
oTable_{$this->oField->GetGlobalId()}.rows().deselect();
}
updateRemoveButtonState_{$this->oField->GetGlobalId()}();
});
// - Item count state handler
var updateItemCount = function()
{
console.log('in fct');
console.log(oTable_{$this->oField->GetGlobalId()}.rows().count());
$('#{$sCollapseTogglerId} > .text').text( oTable_{$this->oField->GetGlobalId()}.rows().count() );
};
// Handles items remove/add
$('#{$sButtonRemoveId}').off('click').on('click', function(){