chg: Added support of displayOnSuccess, non-dismissable modals and some
house cleaningpull/37/head
parent
41ca17ef36
commit
691032551b
|
@ -17,7 +17,7 @@ class AuthKeysController extends AppController
|
|||
public function index()
|
||||
{
|
||||
$this->CRUD->index([
|
||||
'filters' => ['users.username', 'authkey', 'comment', 'users.id'],
|
||||
'filters' => ['Users.username', 'authkey', 'comment', 'Users.id'],
|
||||
'quickFilters' => ['authkey', 'comment'],
|
||||
'contain' => ['Users'],
|
||||
'exclude_fields' => ['authkey']
|
||||
|
@ -45,7 +45,9 @@ class AuthKeysController extends AppController
|
|||
$this->CRUD->add([
|
||||
'displayOnSuccess' => 'authkey_display'
|
||||
]);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
$responsePayload = $this->CRUD->getResponsePayload([
|
||||
'displayOnSuccess' => 'authkey_display'
|
||||
]);
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use Cake\Controller\Component;
|
|||
use Cake\Error\Debugger;
|
||||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Inflector;
|
||||
use Cake\View\ViewBuilder;
|
||||
|
||||
class CRUDComponent extends Component
|
||||
{
|
||||
|
@ -108,17 +109,16 @@ class CRUDComponent extends Component
|
|||
$this->saveMetaFields($data->id, $input);
|
||||
}
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($data, 'json');
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->Controller->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
|
||||
if (!empty($params['displayOnSuccess'])) {
|
||||
$displayOnSuccess = $this->renderViewInVariable($params['displayOnSuccess'], ['entity' => $data]);
|
||||
$this->Controller->ajaxResponsePayload = $this->Controller->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message, ['displayOnSuccess' => $displayOnSuccess]);
|
||||
} else {
|
||||
$this->Controller->ajaxResponsePayload = $this->Controller->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
|
||||
}
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
if (!empty($params['displayOnSuccess'])) {
|
||||
$this->Controller->set('entity', $data);
|
||||
$this->Controller->set('referer', $this->Controller->referer());
|
||||
$this->Controller->render($params['displayOnSuccess']);
|
||||
return;
|
||||
}
|
||||
if (empty($params['redirect'])) {
|
||||
$this->Controller->redirect(['action' => 'view', $data->id]);
|
||||
} else {
|
||||
|
@ -503,4 +503,12 @@ class CRUDComponent extends Component
|
|||
return $this->Table->find()->distinct([$field])->all()->extract($field)->toList();
|
||||
}
|
||||
}
|
||||
|
||||
private function renderViewInVariable($templateRelativeName, $data)
|
||||
{
|
||||
$builder = new ViewBuilder();
|
||||
$builder->disableAutoLayout()->setTemplate("{$this->TableAlias}/{$templateRelativeName}");
|
||||
$view = $builder->build($data);
|
||||
return $view->render();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -420,7 +420,7 @@ class RestResponseComponent extends Component
|
|||
return $this->__sendResponse($response, 200, $format);
|
||||
}
|
||||
|
||||
public function ajaxSuccessResponse($ObjectAlias, $action, $entity, $message)
|
||||
public function ajaxSuccessResponse($ObjectAlias, $action, $entity, $message, $additionalData=[])
|
||||
{
|
||||
$action = $this->__dissectAdminRouting($action);
|
||||
$response = [
|
||||
|
@ -429,6 +429,9 @@ class RestResponseComponent extends Component
|
|||
'data' => $entity->toArray(),
|
||||
'url' => $this->__generateURL($action, $ObjectAlias, $entity->id)
|
||||
];
|
||||
if (!empty($additionalData)) {
|
||||
$response['additionalData'] = $additionalData;
|
||||
}
|
||||
return $this->viewData($response);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<h4><?= __('Authkey created'); ?></h4>
|
||||
<p><?= __('Please make sure that you note down the authkey below, this is the only time the authkey is shown in plain text, so make sure you save it. If you lose the key, simply remove the entry and generate a new one.'); ?></p>
|
||||
<p><?=__('Cerebrate will use the first and the last 4 digit for identification purposes.')?></p>
|
||||
<p><?= sprintf('%s: <span class="text-weight-bold">%s</span>', __('Authkey'), h($entity->authkey_raw)) ?></p>
|
||||
<a href="<?= $referer ?>" class="btn btn-primary"><?= __('I have noted down my key, take me back now') ?></a>
|
||||
<?php
|
||||
echo $this->element('genericElements/genericModal', [
|
||||
'title' => __('Authkey created'),
|
||||
'body' => sprintf(
|
||||
'<p>%s</p><p>%s</p><p>%s</p>',
|
||||
__('Please make sure that you note down the authkey below, this is the only time the authkey is shown in plain text, so make sure you save it. If you lose the key, simply remove the entry and generate a new one.'),
|
||||
__('Cerebrate will use the first and the last 4 digit for identification purposes.'),
|
||||
sprintf('%s: <span class="font-weight-bold">%s</span>', __('Authkey'), h($entity->authkey_raw))
|
||||
),
|
||||
'actionButton' => sprintf('<button" class="btn btn-primary" data-dismiss="modal">%s</button>', __('I have noted down my key, take me back now')),
|
||||
'noCancel' => true,
|
||||
'staticBackdrop' => true,
|
||||
]);
|
||||
|
|
|
@ -10,7 +10,6 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
'data' => [
|
||||
'type' => 'simple',
|
||||
'text' => __('Add authentication key'),
|
||||
'class' => 'btn btn-primary',
|
||||
'popover_url' => '/authKeys/add'
|
||||
]
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="modal-dialog <?= empty($class) ? '' : h($class) ?>" role="document">
|
||||
<div class="modal-dialog <?= empty($class) ? '' : h($class) ?>" <?= !empty($staticBackdrop) ? 'data-backdrop="static"' : ''?> role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><?= h($title) ?></h5>
|
||||
|
@ -10,7 +10,9 @@
|
|||
<?= $body ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary cancel-button" data-dismiss="modal"><?= __('Cancel') ?></button>
|
||||
<?php if (empty($noCancel)): ?>
|
||||
<button type="button" class="btn btn-secondary cancel-button" data-dismiss="modal"><?= __('Cancel') ?></button>
|
||||
<?php endif; ?>
|
||||
<?= $actionButton ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -34,7 +34,7 @@ class UIFactory {
|
|||
modalFromURL(url, POSTSuccessCallback, POSTFailCallback) {
|
||||
return AJAXApi.quickFetchURL(url).then((modalHTML) => {
|
||||
const theModal = new ModalFactory({
|
||||
rawHTML: modalHTML,
|
||||
rawHtml: modalHTML,
|
||||
POSTSuccessCallback: POSTSuccessCallback !== undefined ? POSTSuccessCallback : () => {},
|
||||
POSTFailCallback: POSTFailCallback !== undefined ? POSTFailCallback : (errorMessage) => {},
|
||||
});
|
||||
|
@ -46,31 +46,43 @@ class UIFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create and display a modal where the modal's content is fetched from the provided URL. Reload the table after a successful operation
|
||||
* Creates and displays a modal where the modal's content is fetched from the provided URL. Reloads the table after a successful operation and handles displayOnSuccess option
|
||||
* @param {string} url - The URL from which the modal's content should be fetched
|
||||
* @param {string} tableId - The table ID which should be reloaded on success
|
||||
* @return {Promise<Object>} Promise object resolving to the ModalFactory object
|
||||
*/
|
||||
openModalFromURL(url, reloadUrl=false, tableId=false) {
|
||||
return UI.modalFromURL(url, () => {
|
||||
return UI.modalFromURL(url, (data) => {
|
||||
let reloaded = false
|
||||
if (reloadUrl === false || tableId === false) { // Try to get information from the DOM
|
||||
let $elligibleTable = $('table.table')
|
||||
let currentModel = location.pathname.split('/')[1]
|
||||
if ($elligibleTable.length == 1 && currentModel.length > 0) {
|
||||
let $container = $elligibleTable.closest('div[id^="table-container-"]')
|
||||
if ($container.length == 1) {
|
||||
return UI.reload(`/${currentModel}/index`, $container, $elligibleTable)
|
||||
UI.reload(`/${currentModel}/index`, $container, $elligibleTable)
|
||||
reloaded = true
|
||||
} else {
|
||||
$container = $elligibleTable.closest('div[id^="single-view-table-container-"]')
|
||||
if ($container.length == 1) {
|
||||
return UI.reload(location.pathname, $container, $elligibleTable)
|
||||
UI.reload(location.pathname, $container, $elligibleTable)
|
||||
reloaded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return UI.reload(reloadUrl, $(`#table-container-${tableId}`), $(`#table-container-${tableId} table.table`))
|
||||
UI.reload(reloadUrl, $(`#table-container-${tableId}`), $(`#table-container-${tableId} table.table`))
|
||||
reloaded = true
|
||||
}
|
||||
if (data.additionalData !== undefined && data.additionalData.displayOnSuccess !== undefined) {
|
||||
UI.modal({
|
||||
rawHtml: data.additionalData.displayOnSuccess
|
||||
})
|
||||
} else {
|
||||
if (!reloaded) {
|
||||
location.reload()
|
||||
}
|
||||
}
|
||||
location.reload()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -247,7 +259,7 @@ class ModalFactory {
|
|||
*/
|
||||
constructor(options) {
|
||||
this.options = Object.assign({}, ModalFactory.defaultOptions, options)
|
||||
if (this.options.rawHTML) {
|
||||
if (this.options.rawHtml && options.POSTSuccessCallback !== undefined) {
|
||||
this.attachSubmitButtonListener = true
|
||||
}
|
||||
if (options.type === undefined && options.cancel !== undefined) {
|
||||
|
@ -256,6 +268,9 @@ class ModalFactory {
|
|||
this.bsModalOptions = {
|
||||
show: true
|
||||
}
|
||||
if (this.options.backdropStatic) {
|
||||
this.bsModalOptions['backdrop'] = 'static'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,11 +320,12 @@ class ModalFactory {
|
|||
* @property {string=('sm'|'lg'|'xl'|'')} size - The size of the modal
|
||||
* @property {boolean} centered - Should the modal be vertically centered
|
||||
* @property {boolean} scrollable - Should the modal be scrollable
|
||||
* @property {boolean} backdropStatic - When set, the modal will not close when clicking outside it.
|
||||
* @property {string} title - The title's content of the modal
|
||||
* @property {string} titleHtml - The raw HTML title's content of the modal
|
||||
* @property {string} body - The body's content of the modal
|
||||
* @property {string} bodyHtml - The raw HTML body's content of the modal
|
||||
* @property {string} rawHTML - The raw HTML of the whole modal. If provided, will override any other content
|
||||
* @property {string} rawHtml - The raw HTML of the whole modal. If provided, will override any other content
|
||||
* @property {string=('primary'|'secondary'|'success'|'danger'|'warning'|'info'|'light'|'dark'|'white'|'transparent')} variant - The variant of the modal
|
||||
* @property {string} modalClass - Classes to be added to the modal's container
|
||||
* @property {string} headerClass - Classes to be added to the modal's header
|
||||
|
@ -334,11 +350,12 @@ class ModalFactory {
|
|||
size: 'md',
|
||||
centered: false,
|
||||
scrollable: false,
|
||||
backdropStatic: false,
|
||||
title: '',
|
||||
titleHtml: false,
|
||||
body: false,
|
||||
bodyHtml: false,
|
||||
rawHTML: false,
|
||||
rawHtml: false,
|
||||
variant: '',
|
||||
modalClass: '',
|
||||
headerClass: '',
|
||||
|
@ -375,6 +392,8 @@ class ModalFactory {
|
|||
if (this.isValid()) {
|
||||
this.$modal = this.buildModal()
|
||||
$('#mainModalContainer').append(this.$modal)
|
||||
} else {
|
||||
console.log('Modal not valid')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,6 +412,8 @@ class ModalFactory {
|
|||
that.findSubmitButtonAndAddListener()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.log('Modal not valid')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,7 +434,7 @@ class ModalFactory {
|
|||
isValid() {
|
||||
return this.options.title !== false || this.options.titleHtml !== false ||
|
||||
this.options.body !== false || this.options.bodyHtml !== false ||
|
||||
this.options.rawHTML !== false
|
||||
this.options.rawHtml !== false
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -430,8 +451,11 @@ class ModalFactory {
|
|||
$modal.addClass(this.options.modalClass)
|
||||
}
|
||||
let $modalDialog
|
||||
if (this.options.rawHTML) {
|
||||
$modalDialog = $(this.options.rawHTML)
|
||||
if (this.options.rawHtml) {
|
||||
$modalDialog = $(this.options.rawHtml)
|
||||
if ($modalDialog.data('backdrop') == 'static') {
|
||||
this.bsModalOptions['backdrop'] = 'static'
|
||||
}
|
||||
} else {
|
||||
$modalDialog = $('<div class="modal-dialog"/>')
|
||||
const $modalContent = $('<div class="modal-content"/>')
|
||||
|
@ -564,14 +588,12 @@ class ModalFactory {
|
|||
}
|
||||
|
||||
this.options.APIConfirm = (tmpApi) => {
|
||||
tmpApi.mergeOptions({forceHTMLOnValidationFailure: true})
|
||||
return tmpApi.postForm($form[0])
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
this.options.POSTSuccessCallback(data)
|
||||
} else { // Validation error, replace modal content with new html
|
||||
this.$modal.html(data.html)
|
||||
this.findSubmitButtonAndAddListener()
|
||||
} else { // Validation error
|
||||
this.injectFormValidationFeedback(form, data.errors)
|
||||
return Promise.reject('Validation error');
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue