chg: [generic] Added Modal from URL support
- Support Form submission - Success / Fail callbacks - Modal reloading in case of validation errorspull/37/head
parent
ae0272a62c
commit
f9bf1c6f55
|
@ -110,6 +110,9 @@ class AppController extends Controller
|
|||
$this->ACL->checkAccess();
|
||||
$this->set('menu', $this->ACL->getMenu());
|
||||
$this->set('ajax', $this->request->is('ajax'));
|
||||
if (!empty($this->request->getHeader('X-Request-Html-On-Failure'))) {
|
||||
$this->ajax_with_html_on_failure = true;
|
||||
}
|
||||
$this->request->getParam('prefix');
|
||||
$this->set('darkMode', !empty(Configure::read('Cerebrate.dark')));
|
||||
}
|
||||
|
|
|
@ -81,13 +81,16 @@ class CRUDComponent extends Component
|
|||
$patchEntityParams['fields'] = $params['fields'];
|
||||
}
|
||||
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
|
||||
if ($this->Table->save($data)) {
|
||||
$savedData = $this->Table->save($data);
|
||||
if ($savedData !== false) {
|
||||
$message = __('{0} added.', $this->ObjectAlias);
|
||||
if (!empty($input['metaFields'])) {
|
||||
$this->saveMetaFields($data->id, $input);
|
||||
}
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($data, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->Controller->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
if (!empty($params['displayOnSuccess'])) {
|
||||
|
@ -103,6 +106,7 @@ class CRUDComponent extends Component
|
|||
}
|
||||
}
|
||||
} else {
|
||||
$this->Controller->isFailResponse = true;
|
||||
$validationMessage = $this->prepareValidationError($data);
|
||||
$message = __(
|
||||
'{0} could not be added.{1}',
|
||||
|
@ -110,7 +114,8 @@ class CRUDComponent extends Component
|
|||
empty($validationMessage) ? '' : ' ' . __('Reason:{0}', $validationMessage)
|
||||
);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->Controller->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationMessage);
|
||||
} else {
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@ class UsersController extends AppController
|
|||
$this->CRUD->add();
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
} else if ($this->ParamHandler->isAjax() && $this->request->is(['post', 'put'])) {
|
||||
if (empty($this->isFailResponse) || empty($this->ajax_with_html_on_failure)) {
|
||||
return $this->ajaxResponsePayload;
|
||||
}
|
||||
}
|
||||
$dropdownData = [
|
||||
'role' => $this->Users->Roles->find('list', [
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
- use these to define dynamic form fields, or anything that will feed into the regular fields via JS population
|
||||
* - submit: The submit button itself. By default it will simply submit to the form as defined via the 'model' field
|
||||
*/
|
||||
$this->Form->setConfig('errorClass', 'is-invalid');
|
||||
$modelForForm = empty($data['model']) ?
|
||||
h(\Cake\Utility\Inflector::singularize(\Cake\Utility\Inflector::classify($this->request->getParam('controller')))) :
|
||||
h($data['model']);
|
||||
|
@ -35,11 +36,14 @@
|
|||
'select' => '<select name="{{name}}" {{attrs}}>{{content}}</select>',
|
||||
'checkbox' => '<input type="checkbox" name="{{name}}" value="{{value}}"{{attrs}}>',
|
||||
'checkboxFormGroup' => '{{label}}',
|
||||
'formGroup' => '<div class="col-sm-2 col-form-label" {{attrs}}>{{label}}</div><div class="col-sm-10">{{input}}</div>',
|
||||
'formGroup' => '<div class="col-sm-2 col-form-label" {{attrs}}>{{label}}</div><div class="col-sm-10">{{input}}{{error}}</div>',
|
||||
'nestingLabel' => '{{hidden}}<div class="col-sm-2 col-form-label">{{text}}</div><div class="col-sm-10">{{input}}</div>',
|
||||
'option' => '<option value="{{value}}"{{attrs}}>{{text}}</option>',
|
||||
'optgroup' => '<optgroup label="{{label}}"{{attrs}}>{{content}}</optgroup>',
|
||||
'select' => '<select name="{{name}}"{{attrs}}>{{content}}</select>'
|
||||
'select' => '<select name="{{name}}"{{attrs}}>{{content}}</select>',
|
||||
'error' => '<div class="error-message invalid-feedback d-block">{{content}}</div>',
|
||||
'errorList' => '<ul>{{content}}</ul>',
|
||||
'errorItem' => '<li>{{text}}</li>',
|
||||
];
|
||||
if (!empty($data['fields'])) {
|
||||
foreach ($data['fields'] as $fieldData) {
|
||||
|
@ -49,6 +53,7 @@
|
|||
}
|
||||
}
|
||||
// we reset the template each iteration as individual fields might override the defaults.
|
||||
$this->Form->setConfig($default_template);
|
||||
$this->Form->setTemplates($default_template);
|
||||
if (isset($fieldData['requirements']) && !$fieldData['requirements']) {
|
||||
continue;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
echo sprintf(
|
||||
'%s',
|
||||
sprintf(
|
||||
'<button id="submitButton" class="btn btn-primary" onClick="%s" autofocus>%s</button>',
|
||||
"$('#form-" . h($formRandomValue) . "').submit()",
|
||||
'<button id="submitButton" class="btn btn-primary" data-form-id="%s" autofocus>%s</button>',
|
||||
'#form-' . h($formRandomValue),
|
||||
__('Submit')
|
||||
)
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
if (!isset($data['requirement']) || $data['requirement']) {
|
||||
if (!empty($data['popover_url'])) {
|
||||
$onClick = sprintf(
|
||||
'onClick="populateAndLoadModal(%s)"',
|
||||
'onClick="openModalFromURL(%s)"',
|
||||
sprintf("'%s'", h($data['popover_url']))
|
||||
);
|
||||
}
|
||||
|
@ -67,3 +67,11 @@
|
|||
);
|
||||
}
|
||||
?>
|
||||
|
||||
<script>
|
||||
function openModalFromURL(url) {
|
||||
UI.modalFromURL(url, (data) => {
|
||||
UI.reload('<?= $this->Url->build(['action' => 'index']); ?>', $('#table-container-<?= $tableRandomValue ?>'), $('#table-container-<?= $tableRandomValue ?> table.table'))
|
||||
})
|
||||
}
|
||||
</script>
|
|
@ -2,7 +2,7 @@
|
|||
if (!isset($data['requirement']) || $data['requirement']) {
|
||||
$elements = '';
|
||||
foreach ($data['children'] as $element) {
|
||||
$elements .= $this->element('/genericElements/ListTopBar/element_' . (empty($element['type']) ? 'simple' : h($element['type'])), array('data' => $element));
|
||||
$elements .= $this->element('/genericElements/ListTopBar/element_' . (empty($element['type']) ? 'simple' : h($element['type'])), array('data' => $element, 'tableRandomValue' => $tableRandomValue));
|
||||
}
|
||||
echo sprintf(
|
||||
'<div %s class="btn-group mr-2" role="group" aria-label="button-group">%s</div>',
|
||||
|
|
|
@ -66,7 +66,7 @@ $cakeDescription = 'Cerebrate';
|
|||
</div>
|
||||
</main>
|
||||
<div id="mainModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mediumModalLabel" aria-hidden="true"></div>
|
||||
<div id="mainToastContainer" style="position: absolute; top: 15px; right: 15px;"></div>
|
||||
<div id="mainToastContainer" style="position: absolute; top: 15px; right: 15px; z-index: 1080"></div>
|
||||
<div id="mainModalContainer"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
class AJAXApi {
|
||||
static genericRequestHeaders = new Headers({
|
||||
static genericRequestHeaders = {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
});
|
||||
};
|
||||
static genericRequestConfigGET = {
|
||||
headers: AJAXApi.genericRequestHeaders
|
||||
headers: new Headers(Object.assign({}, AJAXApi.genericRequestHeaders))
|
||||
}
|
||||
static genericRequestConfigPOST = {
|
||||
headers: AJAXApi.genericRequestHeaders,
|
||||
headers: new Headers(Object.assign({}, AJAXApi.genericRequestHeaders)),
|
||||
redirect: 'manual',
|
||||
method: 'POST',
|
||||
}
|
||||
static renderHTMLOnFailureHeader = {
|
||||
name: 'X-Request-HTML-On-Failure',
|
||||
value: '1'
|
||||
}
|
||||
|
||||
static defaultOptions = {
|
||||
provideFeedback: true,
|
||||
statusNode: false,
|
||||
renderedHTMLOnFailureRequested: false,
|
||||
errorToast: {
|
||||
delay: 10000
|
||||
}
|
||||
}
|
||||
options = {}
|
||||
loadingOverlay = false
|
||||
|
@ -23,12 +31,15 @@ class AJAXApi {
|
|||
this.mergeOptions(options)
|
||||
}
|
||||
|
||||
provideFeedback(options, isError=false) {
|
||||
if (this.options.provideFeedback) {
|
||||
UI.toast(options)
|
||||
} else {
|
||||
if (isError) {
|
||||
console.error(options.body)
|
||||
provideFeedback(toastOptions, isError=false, skip=false) {
|
||||
const alteredToastOptions = isError ? Object.assign({}, AJAXApi.defaultOptions.errorToast, toastOptions) : toastOptions
|
||||
if (!skip) {
|
||||
if (this.options.provideFeedback) {
|
||||
UI.toast(alteredToastOptions)
|
||||
} else {
|
||||
if (isError) {
|
||||
console.error(alteredToastOptions.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,13 +67,19 @@ class AJAXApi {
|
|||
return tmpApi.fetchForm(url, constAlteredOptions.skipRequestHooks)
|
||||
}
|
||||
|
||||
static async quickPostForm(form, dataToMerge={}, options={}) {
|
||||
const constAlteredOptions = Object.assign({}, {}, options)
|
||||
const tmpApi = new AJAXApi(constAlteredOptions)
|
||||
return tmpApi.postForm(form, dataToMerge, constAlteredOptions.skipRequestHooks)
|
||||
}
|
||||
|
||||
static async quickFetchAndPostForm(url, dataToMerge={}, options={}) {
|
||||
const constAlteredOptions = Object.assign({}, {}, options)
|
||||
const tmpApi = new AJAXApi(constAlteredOptions)
|
||||
return tmpApi.fetchAndPostForm(url, dataToMerge, constAlteredOptions.skipRequestHooks)
|
||||
}
|
||||
|
||||
async fetchURL(url, skipRequestHooks=false) {
|
||||
async fetchURL(url, skipRequestHooks=false, skipFeedback=false) {
|
||||
if (!skipRequestHooks) {
|
||||
this.beforeRequest()
|
||||
}
|
||||
|
@ -76,14 +93,14 @@ class AJAXApi {
|
|||
this.provideFeedback({
|
||||
variant: 'success',
|
||||
title: 'URL fetched',
|
||||
});
|
||||
}, false, skipFeedback);
|
||||
toReturn = data;
|
||||
} catch (error) {
|
||||
this.provideFeedback({
|
||||
variant: 'danger',
|
||||
title: 'There has been a problem with the operation',
|
||||
body: error
|
||||
}, true);
|
||||
}, true, skipFeedback);
|
||||
toReturn = Promise.reject(error);
|
||||
} finally {
|
||||
if (!skipRequestHooks) {
|
||||
|
@ -93,7 +110,7 @@ class AJAXApi {
|
|||
return toReturn
|
||||
}
|
||||
|
||||
async fetchForm(url, skipRequestHooks=false) {
|
||||
async fetchForm(url, skipRequestHooks=false, skipFeedback=false) {
|
||||
if (!skipRequestHooks) {
|
||||
this.beforeRequest()
|
||||
}
|
||||
|
@ -116,7 +133,74 @@ class AJAXApi {
|
|||
variant: 'danger',
|
||||
title: 'There has been a problem with the operation',
|
||||
body: error
|
||||
}, true);
|
||||
}, true, skipFeedback);
|
||||
toReturn = Promise.reject(error);
|
||||
} finally {
|
||||
if (!skipRequestHooks) {
|
||||
this.afterRequest()
|
||||
}
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
|
||||
async postForm(form, dataToMerge={}, skipRequestHooks=false, skipFeedback=false) {
|
||||
if (!skipRequestHooks) {
|
||||
this.beforeRequest()
|
||||
}
|
||||
let toReturn
|
||||
let feedbackShown = false
|
||||
try {
|
||||
try {
|
||||
let formData = new FormData(form)
|
||||
formData = AJAXApi.mergeFormData(formData, dataToMerge)
|
||||
let requestConfig = AJAXApi.genericRequestConfigPOST
|
||||
if (this.options.renderedHTMLOnFailureRequested) {
|
||||
requestConfig.headers.append(AJAXApi.renderHTMLOnFailureHeader.name, AJAXApi.renderHTMLOnFailureHeader.value)
|
||||
}
|
||||
let options = {
|
||||
...requestConfig,
|
||||
body: formData,
|
||||
};
|
||||
const response = await fetch(form.action, options);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok')
|
||||
}
|
||||
const clonedResponse = response.clone()
|
||||
try {
|
||||
const data = await response.json()
|
||||
if (data.success) {
|
||||
this.provideFeedback({
|
||||
variant: 'success',
|
||||
body: data.message
|
||||
}, false, skipFeedback);
|
||||
toReturn = data;
|
||||
} else {
|
||||
this.provideFeedback({
|
||||
variant: 'danger',
|
||||
title: 'There has been a problem with the operation',
|
||||
body: data.errors
|
||||
}, true, skipFeedback);
|
||||
feedbackShown = true
|
||||
toReturn = Promise.reject(data.errors);
|
||||
}
|
||||
} catch (error) { // could not parse JSON
|
||||
if (this.options.renderedHTMLOnFailureRequested) {
|
||||
const data = await clonedResponse.text();
|
||||
toReturn = {
|
||||
success: 0,
|
||||
html: data,
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.provideFeedback({
|
||||
variant: 'danger',
|
||||
title: 'There has been a problem with the operation',
|
||||
body: error
|
||||
}, true, feedbackShown);
|
||||
toReturn = Promise.reject(error);
|
||||
}
|
||||
} catch (error) {
|
||||
toReturn = Promise.reject(error);
|
||||
} finally {
|
||||
if (!skipRequestHooks) {
|
||||
|
@ -132,41 +216,8 @@ class AJAXApi {
|
|||
}
|
||||
let toReturn
|
||||
try {
|
||||
const form = await this.fetchForm(url, true);
|
||||
try {
|
||||
let formData = new FormData(form)
|
||||
formData = AJAXApi.mergeFormData(formData, dataToMerge)
|
||||
let options = {
|
||||
...AJAXApi.genericRequestConfigPOST,
|
||||
body: formData,
|
||||
};
|
||||
const response = await fetch(form.action, options);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok')
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
this.provideFeedback({
|
||||
variant: 'success',
|
||||
body: data.message
|
||||
});
|
||||
toReturn = data;
|
||||
} else {
|
||||
this.provideFeedback({
|
||||
variant: 'danger',
|
||||
title: 'There has been a problem with the operation',
|
||||
body: data.errors
|
||||
}, true);
|
||||
toReturn = Promise.reject(error);
|
||||
}
|
||||
} catch (error) {
|
||||
this.provideFeedback({
|
||||
variant: 'danger',
|
||||
title: 'There has been a problem with the operation',
|
||||
body: error
|
||||
}, true);
|
||||
toReturn = Promise.reject(error);
|
||||
}
|
||||
const form = await this.fetchForm(url, true, true);
|
||||
toReturn = await this.postForm(form, dataToMerge, true, true)
|
||||
} catch (error) {
|
||||
toReturn = Promise.reject(error);
|
||||
} finally {
|
||||
|
|
|
@ -16,6 +16,22 @@ class UIFactory {
|
|||
return theModal
|
||||
}
|
||||
|
||||
/* Display a modal based on provided options */
|
||||
modalFromURL (url, successCallback, failCallback) {
|
||||
return AJAXApi.quickFetchURL(url).then((modalHTML) => {
|
||||
const theModal = new ModalFactory({
|
||||
rawHTML: modalHTML,
|
||||
replaceFormSubmissionByAjax: true,
|
||||
successCallback: successCallback !== undefined ? successCallback : () => {},
|
||||
failCallback: failCallback !== undefined ? failCallback : (errorMessage) => {},
|
||||
});
|
||||
theModal.makeModal(modalHTML)
|
||||
theModal.show()
|
||||
theModal.$modal.data('modalObject', theModal)
|
||||
return theModal
|
||||
})
|
||||
}
|
||||
|
||||
/* Fetch HTML from the provided URL and override content of $container. $statusNode allows to specify another HTML node to display the loading */
|
||||
reload (url, $container, $statusNode=null) {
|
||||
$container = $($container)
|
||||
|
@ -26,7 +42,7 @@ class UIFactory {
|
|||
AJAXApi.quickFetchURL(url, {
|
||||
statusNode: $statusNode[0]
|
||||
}).then((data) => {
|
||||
$container[0].outerHTML = data
|
||||
$container.replaceWith(data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +159,7 @@ class ModalFactory {
|
|||
titleHtml: false,
|
||||
body: false,
|
||||
bodyHtml: false,
|
||||
rawHTML: false,
|
||||
variant: '',
|
||||
modalClass: [],
|
||||
headerClass: [],
|
||||
|
@ -160,6 +177,8 @@ class ModalFactory {
|
|||
error: function() {},
|
||||
shownCallback: function() {},
|
||||
hiddenCallback: function() {},
|
||||
successCallback: function() {},
|
||||
replaceFormSubmissionByAjax: false
|
||||
}
|
||||
|
||||
static availableType = [
|
||||
|
@ -190,6 +209,9 @@ class ModalFactory {
|
|||
})
|
||||
.on('shown.bs.modal', function () {
|
||||
that.options.shownCallback()
|
||||
if (that.options.replaceFormSubmissionByAjax) {
|
||||
that.replaceFormSubmissionByAjax()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -203,11 +225,11 @@ class ModalFactory {
|
|||
}
|
||||
|
||||
isValid() {
|
||||
return this.options.title !== false || this.options.body !== false || this.options.titleHtml !== false || this.options.bodyHtml !== false
|
||||
return this.options.title !== false || this.options.body !== false || this.options.titleHtml !== false || this.options.bodyHtml !== false || this.options.rawHTML !== false
|
||||
}
|
||||
|
||||
buildModal() {
|
||||
var $modal = $('<div class="modal fade" tabindex="-1" aria-hidden="true"/>')
|
||||
const $modal = $('<div class="modal fade" tabindex="-1" aria-hidden="true"/>')
|
||||
if (this.options.id !== false) {
|
||||
$modal.attr('id', this.options.id)
|
||||
$modal.attr('aria-labelledby', this.options.id)
|
||||
|
@ -215,37 +237,42 @@ class ModalFactory {
|
|||
if (this.options.modalClass !== false) {
|
||||
$modal.addClass(this.options.modalClass)
|
||||
}
|
||||
var $modalDialog = $('<div class="modal-dialog"/>')
|
||||
var $modalContent = $('<div class="modal-content"/>')
|
||||
if (this.options.title !== false || this.options.titleHtml !== false) {
|
||||
var $modalHeader = $('<div class="modal-header"/>')
|
||||
var $modalHeaderText
|
||||
if (this.options.titleHtml !== false) {
|
||||
$modalHeaderText = $('<div/>').html(this.options.titleHtml);
|
||||
} else {
|
||||
$modalHeaderText = $('<h5 class="modal-title"/>').text(this.options.title)
|
||||
let $modalDialog
|
||||
if (this.options.rawHTML) {
|
||||
$modalDialog = $(this.options.rawHTML)
|
||||
} else {
|
||||
$modalDialog = $('<div class="modal-dialog"/>')
|
||||
const $modalContent = $('<div class="modal-content"/>')
|
||||
if (this.options.title !== false || this.options.titleHtml !== false) {
|
||||
const $modalHeader = $('<div class="modal-header"/>')
|
||||
let $modalHeaderText
|
||||
if (this.options.titleHtml !== false) {
|
||||
$modalHeaderText = $('<div/>').html(this.options.titleHtml);
|
||||
} else {
|
||||
$modalHeaderText = $('<h5 class="modal-title"/>').text(this.options.title)
|
||||
}
|
||||
$modalHeader.append($modalHeaderText, ModalFactory.getCloseButton())
|
||||
$modalContent.append($modalHeader)
|
||||
}
|
||||
$modalHeader.append($modalHeaderText, ModalFactory.getCloseButton())
|
||||
$modalContent.append($modalHeader)
|
||||
}
|
||||
|
||||
if (this.options.body !== false || this.options.bodyHtml !== false) {
|
||||
var $modalBody = $('<div class="modal-body"/>')
|
||||
var $modalBodyText
|
||||
if (this.options.bodyHtml !== false) {
|
||||
$modalBodyText = $('<div/>').html(this.options.bodyHtml);
|
||||
} else {
|
||||
$modalBodyText = $('<div/>').text(this.options.body)
|
||||
|
||||
if (this.options.body !== false || this.options.bodyHtml !== false) {
|
||||
const $modalBody = $('<div class="modal-body"/>')
|
||||
let $modalBodyText
|
||||
if (this.options.bodyHtml !== false) {
|
||||
$modalBodyText = $('<div/>').html(this.options.bodyHtml);
|
||||
} else {
|
||||
$modalBodyText = $('<div/>').text(this.options.body)
|
||||
}
|
||||
$modalBody.append($modalBodyText)
|
||||
$modalContent.append($modalBody)
|
||||
}
|
||||
$modalBody.append($modalBodyText)
|
||||
$modalContent.append($modalBody)
|
||||
|
||||
const $modalFooter = $('<div class="modal-footer"/>')
|
||||
$modalFooter.append(this.getFooterBasedOnType())
|
||||
$modalContent.append($modalFooter)
|
||||
|
||||
$modalDialog.append($modalContent)
|
||||
}
|
||||
|
||||
var $modalFooter = $('<div class="modal-footer"/>')
|
||||
$modalFooter.append(this.getFooterBasedOnType())
|
||||
$modalContent.append($modalFooter)
|
||||
|
||||
$modalDialog.append($modalContent)
|
||||
$modal.append($modalDialog)
|
||||
return $modal
|
||||
}
|
||||
|
@ -270,49 +297,81 @@ class ModalFactory {
|
|||
getFooterConfirm() {
|
||||
let variant = this.options.type.split('-')[1]
|
||||
variant = variant !== undefined ? variant : 'primary'
|
||||
return [
|
||||
$('<button type="button" class="btn btn-secondary" data-dismiss="modal"></button>')
|
||||
const $buttonCancel = $('<button type="button" class="btn btn-secondary" data-dismiss="modal"></button>')
|
||||
.text(this.options.cancelText)
|
||||
.click(
|
||||
(evt) => {
|
||||
this.options.cancel(() => { this.hide() }, this, evt)
|
||||
}
|
||||
)
|
||||
.attr('data-dismiss', (this.options.closeManually || !this.options.closeOnSuccess) ? '' : 'modal'),
|
||||
$('<button type="button" class="btn"></button>')
|
||||
.attr('data-dismiss', (this.options.closeManually || !this.options.closeOnSuccess) ? '' : 'modal')
|
||||
|
||||
const $buttonConfirm = $('<button type="button" class="btn"></button>')
|
||||
.addClass('btn-' + variant)
|
||||
.text(this.options.confirmText)
|
||||
.click(
|
||||
(evt) => {
|
||||
let confirmFunction = this.options.confirm
|
||||
if (this.options.APIConfirm) {
|
||||
const tmpApi = new AJAXApi({
|
||||
statusNode: evt.target
|
||||
})
|
||||
confirmFunction = () => { return this.options.APIConfirm(tmpApi) }
|
||||
}
|
||||
let confirmResult = confirmFunction(() => { this.hide() }, this, evt)
|
||||
if (confirmResult === undefined) {
|
||||
this.hide()
|
||||
} else {
|
||||
confirmResult.then(() => {
|
||||
if (this.options.closeOnSuccess) {
|
||||
this.hide()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.options.error(() => { this.hide() }, this, evt)
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
.click(this.getConfirmationHandlerFunction())
|
||||
.attr('data-dismiss', (this.options.closeManually || this.options.closeOnSuccess) ? '' : 'modal')
|
||||
]
|
||||
return [$buttonCancel, $buttonConfirm]
|
||||
}
|
||||
|
||||
static getCloseButton() {
|
||||
return $(ModalFactory.closeButtonHtml)
|
||||
}
|
||||
|
||||
getConfirmationHandlerFunction() {
|
||||
return (evt) => {
|
||||
let confirmFunction = this.options.confirm
|
||||
if (this.options.APIConfirm) {
|
||||
const tmpApi = new AJAXApi({
|
||||
statusNode: evt.target
|
||||
})
|
||||
confirmFunction = () => { return this.options.APIConfirm(tmpApi) }
|
||||
}
|
||||
let confirmResult = confirmFunction(() => { this.hide() }, this, evt)
|
||||
if (confirmResult === undefined) {
|
||||
this.hide()
|
||||
} else {
|
||||
confirmResult.then((data) => {
|
||||
if (this.options.closeOnSuccess) {
|
||||
this.hide()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.options.error(() => { this.hide() }, this, evt)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
replaceFormSubmissionByAjax() {
|
||||
const $submitButton = this.$modal.find('.modal-footer #submitButton')
|
||||
const formID = $submitButton.data('form-id')
|
||||
let $form
|
||||
if (formID) {
|
||||
$form = $(formID)
|
||||
} else {
|
||||
$form = this.$modal.find('form')
|
||||
}
|
||||
|
||||
this.options.APIConfirm = (tmpApi) => {
|
||||
tmpApi.mergeOptions({renderedHTMLOnFailureRequested: true})
|
||||
return tmpApi.postForm($form[0])
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
this.options.successCallback(data)
|
||||
} else { // Validation error, replace modal content with new html
|
||||
this.$modal.html(data.html)
|
||||
this.replaceFormSubmissionByAjax()
|
||||
return Promise.reject('Validation error');
|
||||
}
|
||||
})
|
||||
.catch((errorMessage, response) => {
|
||||
this.options.failCallback(errorMessage)
|
||||
return Promise.reject(errorMessage);
|
||||
})
|
||||
}
|
||||
$submitButton.click(this.getConfirmationHandlerFunction())
|
||||
}
|
||||
}
|
||||
|
||||
class OverlayFactory {
|
||||
|
|
Loading…
Reference in New Issue