<?php
/**
* This file display the automation diagram view
*
* This file is part of the b2evolution/evocms project - {@link http://b2evolution.net/}.
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}.
* Parts of this file are copyright (c)2005 by Daniel HAHLER - {@link http://thequod.de/contact}.
*
* @package admin
*/
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
global $edited_Automation, $admin_url;
// Get data of all steps for diagram view:
$steps = $edited_Automation->get_diagram_steps_data();
// Check if current automation is active:
$is_automation_active = ( $edited_Automation->get( 'status' ) == 'active' );
// Display a button to play/pause current Automation:
if( $is_automation_active )
{ // To pause:
echo action_icon( T_('Pause'), 'pause',
$admin_url.'?ctrl=automations&tab='.get_param( 'tab' ).'&action=status_paused&autm_ID='.$edited_Automation->ID.'&'.url_crumb( 'automation' ),
' '.T_('Pause'), 3, 4, array( 'class' => 'btn btn-danger' ) )
.' <span class="red">('.T_('RUNNING').')</span>';
}
else
{ // To play:
echo action_icon( T_('Play'), 'play',
$admin_url.'?ctrl=automations&tab='.get_param( 'tab' ).'&action=status_active&autm_ID='.$edited_Automation->ID.'&'.url_crumb( 'automation' ),
' '.T_('Play'), 3, 4, array( 'class' => 'btn btn-success' ) )
.' <span class="orange">('.T_('PAUSED').')</span>';
}
if( count( $steps ) > 0 )
{ // Display a button to reset a diagram layout to default positions:
echo '<a href="'.$admin_url.'?ctrl=automations&action=reset_diagram&autm_ID='.$edited_Automation->ID.'&'.url_crumb( 'automationstep' ).'"'
.' class="btn btn-default pull-right" style="margin-left:5px"'
.' onclick="return confirm( \''.TS_('Are you sure you want to reset step positions to the default layout?').'\' )">'
.T_('Reset layout')
.'</a>';
}
echo '<a href="'.$admin_url.'?ctrl=automations&action=reset_diagram&autm_ID='.$edited_Automation->ID.'&'.url_crumb( 'automationstep' ).'"'
.' class="btn btn-primary pull-right"'
.' onclick="return evo_add_new_automation_step()">'
.get_icon( 'new' ).' '.T_('New step')
.'</a>';
// Print out HTML boxes for steps and Initialise steps data to build connectors between steps by JS code below:
echo '<div>';
echo '<div class="evo_panzoom__buttons">
<button class="btn btn-default btn-sm evo_panzoom_btn_in"><span class="fa fa-plus"></span></button><br>
<button class="btn btn-default btn-sm evo_panzoom_btn_out"><span class="fa fa-minus"></span></button><br>
<button class="btn btn-default btn-sm evo_panzoom_btn_reset"><span class="fa fa-repeat"></span></button>
</div>';
echo '<div id="evo_automation__diagram_panzoom">';
echo '<div id="evo_automation__diagram_canvas" class="jtk-surface jtk-surface-nopan clear">';
foreach( $steps as $step )
{
// Print box of step with data:
echo '<div'.get_field_attribs_as_string( $step['attrs'] ).'>'
.'<b>#'.$step['order'].' '.step_get_type_title( $step['type'] ).':</b><br>'
.$step['label']
.'</div>'."\n";
}
echo '</div>';
echo '</div>';
echo '</div>';
// Initialize JavaScript to build and open window:
echo_modalwindow_js();
?>
<script>
function evo_add_new_automation_step()
{
openModalWindow( '<span class="loader_img loader_file_edit absolute_center" title="<?php echo T_('Loading...'); ?>"></span>',
'80%', '', true,
'<?php echo TS_('New step').get_manual_link( 'automation-step-form' ); ?>',
'<?php echo TS_('Record'); ?>', true, true );
jQuery.ajax(
{
type: 'POST',
url: '<?php echo $admin_url; ?>',
data:
{
'ctrl': 'automations',
'action': 'new_step',
'tab': 'diagram',
'autm_ID': <?php echo $edited_Automation->ID; ?>,
'display_mode': 'js',
},
success: function( result )
{
openModalWindow( result, '80%', '',true,
'<?php echo TS_('New step').get_manual_link( 'automation-step-form' ); ?>',
'<?php echo TS_('Record'); ?>', false, true );
}
} );
return false;
}
jQuery( document ).ready( function()
{ // CSS fix to make diagram canvas full height:
var min_step_bottom_position = 0;
jQuery( '.evo_automation__diagram_step_box' ).each( function()
{ // Find the most bottom step:
var step_bottom_position = jQuery( this ).position().top + jQuery( this ).height();
if( min_step_bottom_position < step_bottom_position )
{
min_step_bottom_position = step_bottom_position;
}
} );
jQuery( '#evo_automation__diagram_canvas' ).css( 'height', min_step_bottom_position + 100 );
// Open modal window to edit the automation step:
jQuery( document ).on( 'click', '.evo_automation__diagram_step_box', function()
{
if( typeof( evo_automation__diagram_step_is_dragging ) != 'undefined' && evo_automation__diagram_step_is_dragging )
{ // Ignore event "mouseup" of the end of the dragging:
evo_automation__diagram_step_is_dragging = false;
return false;
}
openModalWindow( '<span class="loader_img loader_file_edit absolute_center" title="<?php echo T_('Loading...'); ?>"></span>',
'80%', '', true,
'<?php echo TS_('Step').get_manual_link( 'automation-step-form' ); ?>',
'<?php echo TS_('Save Changes!'); ?>', true, true );
jQuery.ajax(
{
type: 'POST',
url: '<?php echo $admin_url; ?>',
data:
{
'ctrl': 'automations',
'action': 'edit_step',
'tab': 'diagram',
'step_ID': jQuery( this ).attr( 'id' ).replace( 'step_', '' ),
'display_mode': 'js',
},
success: function( result )
{
openModalWindow( result, '80%', '',true,
'<?php echo TS_('Step').get_manual_link( 'automation-step-form' ); ?>',
'<?php echo TS_('Save Changes!'); ?>', false, true );
}
} );
} );
} );
jsPlumb.ready( function ()
{
var instance = jsPlumb.getInstance(
{
DragOptions: { cursor: 'pointer', zIndex: 2000 },
Container: 'evo_automation__diagram_canvas',
<?php echo $is_automation_active ? 'ConnectionsDetachable: false,' : ''; ?>
} );
// General properties for connectors and source points:
var point_source = {
endpoint: 'Dot',
paintStyle: { radius: 7 },
hoverPaintStyle: { radius: 10 },
isSource: <?php echo $is_automation_active ? 'false' : 'true'; ?>,
connector: [ 'Flowchart', { gap: 5, cornerRadius: 10, alwaysRespectStubs: true } ],
connectorStyle: {
strokeWidth: 4,
joinstyle: 'round',
outlineStroke: 'white',
outlineWidth: 1
},
connectorHoverStyle: { strokeWidth: 7 },
connectorOverlays: [
[ 'Arrow', {
location: 1,
visible:true,
id:'ARROW'
} ],
[ 'Label', {
location: 0.3,
id: 'label',
} ]
]
};
// "YES" green connector and source point:
var point_source_yes = jQuery.extend( true, {}, point_source );
point_source_yes.connectionType = 'yes';
point_source_yes.paintStyle.fill = point_source_yes.connectorStyle.stroke = '#61bd4f';
point_source_yes.connector[1].stub = [70, 70];
point_source_yes.connectorOverlays[0][1].width = 20;
point_source_yes.connectorOverlays[0][1].length = 20;
point_source_yes.connectorOverlays[1][1].cssClass = 'jtk-label jtk-label-yes';
// "NO" blue connector and source point:
var point_source_no = jQuery.extend( true, {}, point_source );
point_source_no.connectionType = 'no';
point_source_no.paintStyle.fill = point_source_no.connectorStyle.stroke = '#0079bf';
point_source_no.connector[1].stub = [50, 50];
point_source_no.connectorOverlays[0][1].width = 15;
point_source_no.connectorOverlays[0][1].length = 15;
point_source_no.connectorOverlays[1][1].cssClass = 'jtk-label jtk-label-no';
point_source_no.connectorOverlays[1][1].location = 0.55;
// "ERROR" red connector and source point:
var point_source_error = jQuery.extend( true, {}, point_source );
point_source_error.connectionType = 'error';
point_source_error.paintStyle.fill = point_source_error.connectorStyle.stroke = '#eb5a46';
point_source_error.connector[1].stub = [30, 30];
point_source_error.connectorOverlays[0][1].width = 10;
point_source_error.connectorOverlays[0][1].length = 10;
point_source_error.connectorOverlays[1][1].cssClass = 'jtk-label jtk-label-error';
point_source_error.connectorOverlays[1][1].location = 0.5;
// Target black point:
var point_target = {
endpoint: 'Dot',
paintStyle: { fill: '#000', radius: 7 },
hoverPaintStyle: { radius: 10 },
maxConnections: -1,
isTarget: true
};
// Initialise listen events:
instance.batch( function ()
{
// listen for new connections; initialise them the same way we initialise the connections at startup.
instance.bind( 'connection', function( connInfo, originalEvent )
{
connInfo.connection.getOverlay( 'label' ).setLabel( jQuery( '#' + connInfo.sourceId ).data( 'info-' + connInfo.sourceEndpoint.connectionType ) );
} );
// Make all step boxes draggable:
instance.draggable( jsPlumb.getSelector( '.evo_automation__diagram_step_box' ),
{
grid: [20, 20],
start: function( e )
{ // Set a flag to know we are dragging the automation step instead of a clicking:
evo_automation__diagram_step_is_dragging = true;
},
stop: function( e )
{ // Store the changed step box position in DB by AJAX:
jQuery.ajax(
{
type: 'POST',
url: '<?php echo $admin_url; ?>',
data:
{
'ctrl': 'automations',
'action': 'update_step_position',
'step_ID': e.el.id.replace( 'step_', '' ),
'pos': e.pos,
'crumb_automationstep': '<?php echo get_crumb( 'automationstep' ); ?>',
}
} );
}
} );
instance.bind( 'connectionDrag', function (connection)
{ // Store vars to know what connector has been dragged in the event "connectionDragStop" below:
b2evo_diagram_source_step_ID = connection.sourceId.replace( /^step_/, '' );
b2evo_diagram_connection_type = connection.endpoints[0].connectionType;
b2evo_diagram_target_step_ID = ( connection.target === null || ! connection.targetId.match( /^step_/g ) ? 0 : connection.targetId.replace( /^step_/, '' ) );
} );
instance.bind( 'connectionDragStop', function (connection)
{
// Get new target step ID:
var updated_target_step_ID = ( connection.target === null || ! connection.targetId.match( /^step_/g ) ? 0 : connection.targetId.replace( /^step_/, '' ) );
if( b2evo_diagram_target_step_ID != updated_target_step_ID )
{ // If the target step has been really changed to another:
jQuery.ajax(
{ // Store the changed steps connection in DB by AJAX:
type: 'POST',
url: '<?php echo $admin_url; ?>',
data:
{
'ctrl': 'automations',
'action': 'update_step_connection',
'step_ID': b2evo_diagram_source_step_ID,
'connection_type': b2evo_diagram_connection_type,
'target_step_ID': updated_target_step_ID,
'crumb_automationstep': '<?php echo get_crumb( 'automationstep' ); ?>',
}
} );
}
} );
<?php
if( $is_automation_active )
{ // Display an alert message if user tries to change a connector for active Automation:
?>
instance.bind( 'endpointClick', function()
{ // Display an alert message if user tries to change a connector for active Automation:
alert( '<?php echo TS_('You should pause this Automation in order to edit it.'); ?>' );
} );
<?php } ?>
} );
var evo_jsplumb_init_step_box = function( step_box_ID )
{
if( jQuery( '#' + step_box_ID ).data( 'info-yes' ) != undefined )
{ // Add "YES" red source point:
instance.addEndpoint( step_box_ID, point_source_yes, { anchor: [ 0.33, 1, 0, 1 ], uuid: step_box_ID + '_yes' } );
}
if( jQuery( '#' + step_box_ID ).data( 'info-no' ) != undefined )
{ // Add "NO" blue source point:
instance.addEndpoint( step_box_ID, point_source_no, { anchor: [ 0.67, 1, 0, 1 ], uuid: step_box_ID + '_no' } );
}
if( jQuery( '#' + step_box_ID ).data( 'info-error' ) != undefined )
{ // Add "ERROR" red source point:
instance.addEndpoint( step_box_ID, point_source_error, { anchor: 'RightMiddle', uuid: step_box_ID + '_error' } );
}
// Add target black point:
instance.addEndpoint( step_box_ID, point_target, { anchor: 'TopCenter', uuid: step_box_ID } );
// Make whole step box is a target place to connect:
instance.makeTarget( step_box_ID, { anchor: 'TopCenter', endpoint: 'Blank' } );
};
// Initialise step boxes:
<?php
foreach( $steps as $step_ID => $step )
{
echo 'evo_jsplumb_init_step_box( \'step_'.$step_ID.'\' );'."\n\t";
}
?>
// Initialise connections between steps:
<?php
foreach( $steps as $step_ID => $step )
{
foreach( $step['next_steps'] as $next_step_type => $next_step_ID )
{
echo 'instance.connect( { uuids: [\'step_'.$step_ID.'_'.$next_step_type.'\', \'step_'.$next_step_ID.'\'] } );'."\n\t";
}
}
?>
// Initialise pan & zoom for diagram:
$panzoom = jQuery( '#evo_automation__diagram_panzoom' ).panzoom(
{
$zoomIn: jQuery( '.evo_panzoom_btn_in' ),
$zoomOut: jQuery( '.evo_panzoom_btn_out' ),
$reset: jQuery( '.evo_panzoom_btn_reset' ),
minScale: 0.1,
maxScale: 2,
increment: 0.1,
cursor: '',
onStart: function() { jQuery( '#evo_automation__diagram_canvas' ).css( 'cursor', 'move' ) },
onEnd: function() { jQuery( '#evo_automation__diagram_canvas' ).css( 'cursor', '' ) },
} );
} );
</script>