Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions calls/call_service_plan_runsheet.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/**
* Returns a service's items as [categoryid, title] JSON. Used by the service editor 'Copy from previous' preview.
*/
class Call_Service_Plan_Runsheet extends Call
{
function run()
{
if (!$GLOBALS['user_system']->havePerm(PERM_VIEWSERVICE)) $this->failReturningJson("You don't have permission to view services");

$service_id = (int)array_get($_REQUEST, 'serviceid');
$service = new Service((int)$service_id);
if (!$service || !$service->id) $this->failReturningJson('Service not found');

// Get items for the service (including headings as separate rows)
$items = $service->getItems();

$out = array();
foreach ($items as $item) {
// If this is a heading row, render the heading text
if (!empty($item['heading_text'])) {
$rendered = $item['heading_text'];
} else {
// Normal item: render the runsheet title with keywords substituted
$titleTemplate = $item['runsheet_title_format'];
if (strlen($titleTemplate) > 0) {
$rendered = $service->replaceItemKeywords($titleTemplate, $item);
$rendered = $service->replaceKeywords($rendered);
} else {
// Fallback to the stored title if no template is provided
$rendered = $item['title'];
}
}

$out[] = array(
'categoryid' => $item['categoryid'],
'title' => $rendered
);
}

header('Content-Type: application/json');
echo json_encode($out);
}

public
function failReturningJson($errMsg): void
{
header('Content-Type: application/json');
echo json_encode(array('error' => $errMsg));
exit();
}
}
4 changes: 1 addition & 3 deletions include/general.php
Original file line number Diff line number Diff line change
Expand Up @@ -389,13 +389,11 @@ class="<?php echo $classes; ?>"
$height = array_get($params, 'height', min(count($params['options']), 4));
if (count($params['options']) < 4) $height = 0;
if (substr($name, -2) != '[]') $name .= '[]';
$style = '';
if ($height > 0) $style = 'height: '.($height*1.7).'em';
$classes .= ' multi-select';
// the empty onclick below is to make labels work on iOS
// see https://stackoverflow.com/questions/5421659/html-label-command-doesnt-work-in-iphone-browser
?>
<div class="<?php echo $classes; ?>" style="<?php echo $style; ?>" tabindex="0" onclick="" <?php echo $attrs; ?> >
<div class="<?php echo $classes; ?>" tabindex="0" onclick="" <?php echo $attrs; ?> >
<?php
foreach ($params['options'] as $k => $v) {
$checked_exp = in_array("$k", $our_val, true) ? ' checked="checked"' : '';
Expand Down
103 changes: 103 additions & 0 deletions resources/js/jethro.js
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,109 @@ JethroServiceProgram.copyServiceDetails = function(sourceCell, targetCell) {



// Implements 'Copy from previous' previewing when editing a service
var JethroServicePlannerCopier = (function($) {
// private variables
var $serviceSelect;
var $preview;

// -----------------------------
// Private helpers
// -----------------------------

function renderPreview(items) {
$preview.empty();
var newtable = "<table class='table table-bordered table-condensed no-autofocus'>";
$.each(items, function(_, it) {
newtable += "<tr data-componentid='" + (it.categoryid ? it.categoryid : '!') +
"' class='service-item'><td class='item'>" +
it.title + "</td></tr>";
});
newtable += "</table>";
$preview.append(newtable);
}

function loadCopiedServicePreview(serviceId) {
if (!serviceId) {
$preview.html('<em>Preview will appear here after selecting a previous service.</em>');
return;
}
var url = '?call=service_plan_runsheet&serviceid=' + encodeURIComponent(serviceId);
$.getJSON(url, function(data) {
if (Array.isArray(data)) {
renderPreview(data);
updateCopiedServicePreviewSelectedItems();
} else {
$preview.html('<em>Unable to load preview.</em>');
}
}).fail(function() {
$preview.html('<em>Error loading preview.</em>');
});
}


// Update visibility of preview rows based on selected category checkboxes
function updateCopiedServicePreviewSelectedItems() {
var checked = $('input[name="copy_category_ids[]"]:checked').map(function() {
return String($(this).val());
}).get();

var $rows = $preview.find('tr[data-componentid]');
if ($rows.length === 0) return;

if (checked.length === 0) {
$rows.addClass("muted");
return;
}

$rows.each(function() {
var $r = $(this);
var compid = String($r.data('componentid'));
if (checked.indexOf(compid) !== -1) {
$r.removeClass("muted");
} else {
$r.addClass("muted");;
}
});
}

// 'Copy from previous' Helper Public API
return {
init: function() {
$serviceSelect = $('[name=copy_service_id]'); // Which previous service to (maybe) copy
$preview = $('#copy-previous-preview'); // Previewer div

// 'Items to copy' checkboxes change handler
$('input[name="copy_category_ids[]"]').on('change', function() {
updateCopiedServicePreviewSelectedItems();
});

if ($serviceSelect.length) {
// 'Service to copy from' select-list change handler
$serviceSelect.on('change', function() {
loadCopiedServicePreview($(this).val());
});
// Preload the default selected service
if ($serviceSelect.val()) {
loadCopiedServicePreview($serviceSelect.val());
}
}

// When the 'Copy from previous' modal opens, auto-focus the 'Service to copy from' select list
$('#copy-previous-modal').on('shown', function () {
$('[name="copy_service_id"]').focus();
});
}
};

})(jQuery);







var JethroServicePlanner = {};

JethroServicePlanner.draggedComp = null;
Expand Down
89 changes: 49 additions & 40 deletions views/view_8_services.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function processView()
$action = $_REQUEST['action'];
switch ($action) {
case "copy":
if (!empty($_REQUEST['copy_service_id'])) {
if (!empty($_REQUEST['copy_service_id']) && !empty($_REQUEST['copy_category_ids'])) {
$fromService = new Service((int)$_REQUEST['copy_service_id']);
if (!$fromService) {
trigger_error("Service ".(int)$_REQUEST['copy_service_id']." not found - could not copy");
Expand All @@ -69,7 +69,8 @@ function processView()
unset($newItems[$k]);
}
}
$this->service->saveItems($newItems);
// Add $newItems from copied service to our existing items
$this->service->saveItems(array_merge($this->service->getItems(), $newItems));
// Retain lock and stay in editing mode
}
break;
Expand Down Expand Up @@ -182,7 +183,12 @@ function printView()
<?php
$this->service->printRunSheetPersonnelFlexi();
if ($this->editing) {
?>
?>
<script>
$(function() {
JethroServicePlannerCopier.init();
});
</script>
<div class="row-fluid" id="service-planner">
<?php
$this->printRunSheetEditor();
Expand Down Expand Up @@ -251,19 +257,13 @@ private function printRunSheetEditor()
?>
<div class="span6">
<h3>
<?php
if (empty($items)) {
?>
<span class="pull-right">
<small>
<a href="#" data-toggle="modal" data-target="#copy-previous-modal">
<i class="icon-share"></i><?php echo _('Copy from previous'); ?>
</a>
</small>
</span>
<?php
}
?>
Run Sheet
</h3>
<form method="post" id="service-planner-form" data-lock-length="<?php echo db_object::getLockLength() ?>">
Expand Down Expand Up @@ -440,20 +440,24 @@ private function printRunSheetEditor()
</div>

<!-- copy-from-previous modal -->
<div class="modal hide fade-in" id="copy-previous-modal" role="dialog">
<div class="modal modal-wide hide fade-in" id="copy-previous-modal" role="dialog">
<form method="post">
<div class="modal-header">
<h4>Copy items from another service</h4>
</div>
<div class="modal-body form-horizontal">
<div class="control-group">
<label class="control-label">
Service to copy from
</label>
<div class="controls">
<div class="row-fluid">
<div class="span6">
<div class="control-group">
<label class="control-label">
Service to copy from
</label>
<div class="controls">
<?php
$options = Array();
$selectedID = NULL;
// If we just copied stuff from a service, make that service the default 'Service to copy from'
if (!empty($_REQUEST['copy_service_id'])) $selectedID = $_REQUEST['copy_service_id'];
$services = $GLOBALS['system']->getDBObjectData('service', Array('>date' => date('Y-m-d', strtotime('-1 year'))), 'AND', 'date DESC');
$dummyService = new Service();
foreach ($services as $id => $s) {
Expand All @@ -469,34 +473,40 @@ private function printRunSheetEditor()
}
print_widget('copy_service_id', Array('type' => 'select', 'options' => $options), $selectedID);
?>
</div>
</div>
<!-- Modal bg is white and table is transparent, so give previewed service items a yellow bg -->
<div id="copy-previous-preview" style='background-color: #ffffe0;'></div>
</div>
</div>
<div class="control-group">
<label class="control-label">
Items to copy
</label>
<div class="controls">
<?php
$cats = $GLOBALS['system']->getDBOBjectData('service_component_category', Array());
foreach ($cats as $id => $c) {
$cat_options[$id] = $c['category_name'];
}
$cat_options['!'] = 'Ad hoc items';
$params = Array(
'type' => 'select',
'options' => $cat_options,
'allow_multiple' => TRUE,
'height' => 5,
);
print_widget('copy_category_ids[]', $params, '*');
?>
<div class="span6">
<div class="control-group">
<label class="control-label">
Items to copy
</label>
<div class="controls">
<?php
$cats = $GLOBALS['system']->getDBOBjectData('service_component_category', Array());
foreach ($cats as $id => $c) {
$cat_options[$id] = $c['category_name'];
}
$cat_options['!'] = 'Ad hoc items';
$params = Array(
'type' => 'select',
'options' => $cat_options,
'allow_multiple' => TRUE,
'height' => count($cat_options),
);
print_widget('copy_category_ids[]', $params, '*');
?>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="action" value="copy" action="submit" class="btn">Copy items</button>
<input class="btn" type="button" value="Cancel" data-dismiss="modal"/>
</div>
<div class="modal-footer">
<button type="submit" name="action" value="copy" action="submit" class="btn">Copy items</button>
<input class="btn" type="button" value="Cancel" data-dismiss="modal"/>
</div>
</form>
</div>
<?php
Expand Down Expand Up @@ -773,4 +783,3 @@ private function getNextServiceDate()

}
}