Skip to content

Provide topLinks on Edit pages (CO-2512) #46

Merged
merged 1 commit into from
Oct 27, 2022
Merged
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
2 changes: 2 additions & 0 deletions app/src/View/Helper/MenuHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public function getMenuOrder($action) {
'Edit' => 10, // edit
'Duplicate' => 15, // content_copy
'Default' => 20, // link - default starting order for arbitrary action menu items
'Add' => 80, // add
'Delete' => 100 // delete
);

Expand All @@ -73,6 +74,7 @@ public function getMenuIcon($action) {
}

$icon = array(
'Add' => 'add_circle',
'View' => 'visibility',
'Edit' => 'edit',
'Duplicate' => 'content_copy',
Expand Down
14 changes: 5 additions & 9 deletions app/templates/AttributeMappings/columns.inc
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,10 @@ $indexColumns = [

$topLinks = [
[
'label' => '<em class="material-icons" aria-hidden="true">file_download</em> ' .
__('match.op.AttributeMappings.install.nicknames.en'),
'link' => [
'action' => 'install',
'?' => [
'mapping' => 'nicknames.en'
]
],
'class' => 'buildbutton'
'action' => 'install',
'query' => ['?' => ['mapping' => 'nicknames.en']],
'class' => 'buildbutton',
'icon' => 'file_download',
'label' => __('match.op.AttributeMappings.install.nicknames.en')
]
];
141 changes: 141 additions & 0 deletions app/templates/Standard/add-edit-view.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,147 @@
<div class="pageTitle">
<h1><?= $vv_title; ?></h1>
</div>

<?php if(
$action == 'edit' &&
(!empty($topLinks) ||
(isset($vv_permissions['duplicate']) && $vv_permissions['duplicate']) ||
$vv_permissions['delete'])): ?>
<?php
// topLinks menu dropdown / button listing
$action_args = array();
$action_args['vv_attr_mdl'] = "Edit";
$action_args['vv_attr_id'] = $vv_obj->id;
$linkArgs = [$vv_obj->id];

// $linkFilter is used for models that belong to a specific parent model (eg: co_id)
$linkFilter = [];


if(!empty($vv_primary_link) && !empty($this->request->getQuery($vv_primary_link))) {
$linkFilter = ['?' => [$vv_primary_link => $this->request->getQuery($vv_primary_link)]];
$linkArgs = array_merge_recursive($linkArgs, $linkFilter);
}

// Insert additional actions as per the .inc file
if(!empty($topLinks)) {
if(!isset($entity->status) || $entity->status == StatusEnum::Active) {
$actionOrderDefault = $this->Menu->getMenuOrder('Default');
foreach($topLinks as $a) {
if($vv_permissions[ $a['action'] ]) {
$actionOrder = !empty($a['order']) ? $a['order'] : $actionOrderDefault++;
$actionIcon = !empty($a['icon']) ? $a['icon'] : $this->Menu->getMenuIcon('Default');
$actionClass = !empty($a['class']) ? $a['class'] : '';
$actionUrl = '';
$actionLabel = '';
$actionOnClick = []; // used for confirmation dialog

// Generate the link text and urls:

// If we have a .confirm text, we need to generate a confirm dialog box
$confirmKey = 'match.op.'.$a['action'].'.confirm';
$confirmTxt = __($confirmKey);

if($confirmTxt != $confirmKey) {
// We found the localized string
$actionPostBtnArray = array_merge_recursive(['action' => $a['action']], $linkArgs);
$actionUrl = $this->Url->build(array_merge_recursive(['action' => $a['action']], $linkArgs));
// XXX should be configurable which field we put in, maybe displayField?
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => 'javascript:void(0);',
'label' => __('match.op.' . $a['action']),
'class' => !empty($actionClass) ? $actionClass . ' nospin' : 'nospin',
'onclick' => array(
'dg_bd_txt' => __($confirmKey, [$entity->id]), // dialog body text
'dg_post_btn_array' => $actionPostBtnArray, // postButton array for building the postButton
'dg_url' => $actionUrl, // action url for building a unique ID
'dg_conf_btn' => __('match.op.confirm'), // dialog confirm button text
'dg_cancel_btn' => __('match.op.cancel'), // dialog cancel button text
'dg_title' => __('match.op.confirm'), // dialog box title
'dg_bd_txt_repl_str' => '' // dialog body text replacement strings
),
);
} elseif(!empty($a['controller'])) {
// We're linking into a related controller
$queryParams = [ $tableFK => $entity->id ];

if(!empty($a['query']) && is_callable($a['query'])) {
$queryParams = $a['query']($vv_cur_mg->id, $entity);
}

$actionLabel = __('match.ct.' . Inflector::camelize(Inflector::pluralize($a['controller'])), [99]);
$actionUrl = $this->Url->build([
'controller' => $a['controller'],
'action' => $a['action'],
'?' => $queryParams
]);
} else {
$actionLabel = __('match.op.' . $a['action']);
$actionUrl = $this->Url->build(
array_merge_recursive(['action' => $a['action']], $linkArgs)
);
}

// If a specific label is sent in the config, use it instead
if(!empty($a['label'])) {
$actionLabel = $a['label'];
}

// Set the action link configuration
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => $actionUrl,
'label' => $actionLabel,
'class' => $actionClass,
'onclick' => $actionOnClick
);
}
}
}
}

// Duplicate
if(isset($vv_permissions['duplicate']) && $vv_permissions['duplicate']) {
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Duplicate'),
'icon' => $this->Menu->getMenuIcon('Duplicate'),
'url' => $this->Url->build(array_merge_recursive(['action' => 'duplicate'], $linkArgs)),
'label' => __('match.op.duplicate')
);
}

// Delete
if($vv_permissions['delete']) {
$actionPostBtnArray = array_merge_recursive(['action' => 'delete'], $linkArgs);
$actionUrl = $this->Url->build(array_merge_recursive(['action' => 'delete'], $linkArgs));
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Delete'),
'icon' => $this->Menu->getMenuIcon('Delete'),
'url' => 'javascript:void(0);',
'label' => __('match.op.delete'),
'class' => 'deletebutton nospin',
'onclick' => array(
'dg_bd_txt' => __('match.op.delete.confirm', [$vv_obj->id]),
'dg_post_btn_array' => $actionPostBtnArray,
'dg_url' => $actionUrl,
'dg_conf_btn' => __('match.op.remove'),
'dg_cancel_btn' => __('match.op.cancel'),
'dg_title' => __('match.op.remove'),
'dg_bd_txt_repl_str' => ''
),
);
}

if(!empty($action_args['vv_actions'])) {
print '<div id="topLinks" class="field-actions">';
print $this->element('menuAction', $action_args);
print '</div>';
}
?>
<?php endif; ?>
</div>

<?php
Expand Down
140 changes: 108 additions & 32 deletions app/templates/Standard/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,41 +90,117 @@ function _column_key($modelsName, $c, $tz=null) {
</div>

<?php if($vv_permissions['add']): ?>
<ul id="topLinks">
<li>
<?php
$addLink = array_merge($linkFilter, ['action' => 'add']);

// Allow model-specific overrides of the add link. If false,
// the override doesn't want the add link to render.
if(isset($addLinkFilter) && is_callable($addLinkFilter)) {
$addLink = $addLinkFilter($addLink, $this->request);
}
?>
<?= $addLink
? $this->Html->link('<em class="material-icons" aria-hidden="true">add_circle</em> ' .
__('match.op.add.a', __('match.ct.'.$vv_modelname, [1])),
$addLink,
['escape' => false])
: ""
?>
</li>
<?php
if(!empty($topLinks)) {
foreach($topLinks as $t) {
if($vv_permissions[ $t['link']['action'] ]) {
print '<li>' .
$this->Html->link(
$t['label'],
array_merge_recursive($linkFilter, $t['link']),
['escape' => false, 'class' => $t['class']]
) . '
</li>';
<?php
// topLinks menu dropdown / button listing
$action_args = array();
$action_args['vv_attr_mdl'] = "IndexTopLinks";

// Insert additional actions as per the .inc file
if(!empty($topLinks)) {
if(!isset($entity->status) || $entity->status == StatusEnum::Active) {
$actionOrderDefault = $this->Menu->getMenuOrder('Default');
foreach($topLinks as $a) {
if($vv_permissions[ $a['action'] ]) {
$actionOrder = !empty($a['order']) ? $a['order'] : $actionOrderDefault++;
$actionIcon = !empty($a['icon']) ? $a['icon'] : $this->Menu->getMenuIcon('Default');
$actionClass = !empty($a['class']) ? $a['class'] : '';
$actionUrl = '';
$actionLabel = '';
$actionOnClick = []; // used for confirmation dialog

// Generate the link text and urls:

// If we have a .confirm text, we need to generate a confirm dialog box
$confirmKey = 'match.op.'.$a['action'].'.confirm';
$confirmTxt = __($confirmKey);

if($confirmTxt != $confirmKey) {
// We found the localized string
$actionPostBtnArray = ['action' => $a['action']];
$actionUrl = $this->Url->build(['action' => $a['action']]);
// XXX should be configurable which field we put in, maybe displayField?
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => 'javascript:void(0);',
'label' => __('match.op.' . $a['action']),
'class' => !empty($actionClass) ? $actionClass . ' nospin' : 'nospin',
'onclick' => array(
'dg_bd_txt' => __($confirmKey, [$entity->id]), // dialog body text
'dg_post_btn_array' => $actionPostBtnArray, // postButton array for building the postButton
'dg_url' => $actionUrl, // action url for building a unique ID
'dg_conf_btn' => __('match.op.confirm'), // dialog confirm button text
'dg_cancel_btn' => __('match.op.cancel'), // dialog cancel button text
'dg_title' => __('match.op.confirm'), // dialog box title
'dg_bd_txt_repl_str' => '' // dialog body text replacement strings
),
);
} elseif(!empty($a['controller'])) {
// We're linking into a related controller
$queryParams = [ $tableFK => $entity->id ];

if(!empty($a['query']) && is_callable($a['query'])) {
$queryParams = $a['query']($vv_cur_mg->id, $entity);
}

$actionLabel = __('match.ct.' . Inflector::camelize(Inflector::pluralize($a['controller'])), [99]);
$actionUrl = $this->Url->build([
'controller' => $a['controller'],
'action' => $a['action'],
'?' => $queryParams
]);
} else {
$actionLabel = __('match.op.' . $a['action']);
$urlAttrs = ['action' => $a['action']];
$urlAttrs = array_merge_recursive($linkFilter, $urlAttrs);
if(!empty($a['query'])) {
$urlAttrs = array_merge_recursive($urlAttrs,$a['query']);
}
$actionUrl = $this->Url->build($urlAttrs);
}

// If a specific label is sent in the config, use it instead
if(!empty($a['label'])) {
$actionLabel = $a['label'];
}

// Set the action link configuration
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => $actionUrl,
'label' => $actionLabel,
'class' => $actionClass,
'onclick' => $actionOnClick
);
}
}
?>
</ul>
}
}

// Add
$addLink = array_merge($linkFilter, ['action' => 'add']);

// Allow model-specific overrides of the add link. If false,
// the override doesn't want the add link to render.
if(isset($addLinkFilter) && is_callable($addLinkFilter)) {
$addLink = $addLinkFilter($addLink, $this->request);
}

$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Add'),
'icon' => $this->Menu->getMenuIcon('Add'),
'url' => $this->Url->build($addLink),
'label' => __('match.op.add.a', __('match.ct.'.$vv_modelname, [1]))
);

// Output the topLinks
if(!empty($action_args['vv_actions'])) {
print '<div id="topLinks" class="field-actions">';
print $this->element('menuAction', $action_args);
print '</div>';
}
?>
<?php endif; ?>
</div>
<?php if(!empty($indexBanners)): ?>
Expand Down
8 changes: 5 additions & 3 deletions app/webroot/css/co-base.css
Original file line number Diff line number Diff line change
Expand Up @@ -477,13 +477,12 @@ body.logged-in #top-menu {
#topLinks {
margin: 1.5em 0 -1.5em 0;
padding: 0;
font-size: 0.9em;
}
#topLinks li {
list-style: none;
display: inline-block;
margin: 0.5em;
padding: 0 0.5em;
margin: 0.5em 0;
padding: 0;
}
#topLinks a {
text-decoration: none;
Expand All @@ -498,6 +497,9 @@ body.logged-in #top-menu {
#main #topLinks a:hover {
text-decoration: underline;
}
#topLinks a.dropdown-item.deletebutton {
color: var(--cmg-color-red-002);
}
/* INNER CONTENT - for non-table-based layouts */
#content {
padding: 1em 1.5em;
Expand Down
1 change: 1 addition & 0 deletions app/webroot/css/co-responsive.css
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
.field-actions .dropdown-menu {
position: static;
display: inline-block;
min-width: 0;
font-size: 0.9em;
border: none;
background-color: transparent;
Expand Down