diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index 8c183774..f4a1d9c8 100644 --- a/PHPCI/Controller/BuildController.php +++ b/PHPCI/Controller/BuildController.php @@ -129,6 +129,12 @@ class BuildController extends \PHPCI\Controller } $build = $this->buildStore->getById($buildId); + + if (!$build) { + $this->response->setResponseCode(404); + return '404 - Not Found'; + } + $this->buildStore->delete($build); header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId()); diff --git a/PHPCI/View/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index e38d8580..09cdd09b 100644 --- a/PHPCI/View/BuildsTable.phtml +++ b/PHPCI/View/BuildsTable.phtml @@ -73,7 +73,7 @@ switch($build->getStatus()) diff --git a/PHPCI/View/Home/index.phtml b/PHPCI/View/Home/index.phtml index 68a0f26f..5e48573c 100644 --- a/PHPCI/View/Home/index.phtml +++ b/PHPCI/View/Home/index.phtml @@ -58,8 +58,10 @@ \ No newline at end of file diff --git a/PHPCI/View/Project/view.phtml b/PHPCI/View/Project/view.phtml index 762e476a..036f9837 100644 --- a/PHPCI/View/Project/view.phtml +++ b/PHPCI/View/Project/view.phtml @@ -92,7 +92,9 @@ $(function() { $('#delete-project').on('click', function (e) { e.preventDefault(); - confirmDelete("project/delete/getId(); ?>"); + confirmDelete( + "project/delete/getId(); ?>", "Project" + ).onCloseConfirmed = function () {window.location = '/'}; }); }) diff --git a/PHPCI/View/User/index.phtml b/PHPCI/View/User/index.phtml index bcdcb7f1..86d6c61d 100644 --- a/PHPCI/View/User/index.phtml +++ b/PHPCI/View/User/index.phtml @@ -50,7 +50,7 @@ diff --git a/public/assets/js/phpci.js b/public/assets/js/phpci.js index d662825b..7cf07458 100644 --- a/public/assets/js/phpci.js +++ b/public/assets/js/phpci.js @@ -1,18 +1,235 @@ +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind + * for the details of code below + */ +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () { + }, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + /** * Used for delete buttons in the system, just to prevent accidental clicks. */ -function confirmDelete(url) -{ - if(confirm('Are you sure you want to delete this?')) - { - window.location.href = url; - } - else - { - return false; - } +function confirmDelete(url, subject, reloadAfter) { + + var dialog = new PHPCIConfirmDialog({ + message: subject + ' will be permanently deleted. Are you sure?', + confirmBtnCaption: 'Delete', + /* + confirm-btn click handler + */ + confirmed: function (e) { + var dialog = this; + e.preventDefault(); + + /* + Call delete URL + */ + $.ajax({ + url: url, + 'success': function (data) { + if (reloadAfter) { + dialog.onClose = function () { + window.location.reload(); + }; + } + + dialog.showStatusMessage('Successfully deleted!', 1000); + }, + 'error': function (data) { + dialog.showStatusMessage('Deletion failed! Server says "' + data.statusText + '"'); + } + }); + } + }); + + dialog.show(); + return dialog; } +/** + * PHPCIConfirmDialog constructor options object + * @type {{message: string, title: string, confirmBtnCaption: string, cancelBtnCaption: string, confirmed: Function}} + */ +var PHPCIConfirmDialogOptions = { + message: 'The action will be performed and cannot be undone. Are you sure?', + title: 'Confirmation Dialog', + confirmBtnCaption: 'Ok', + cancelBtnCaption: 'Cancel', + confirmed: function (e) { + this.close(); + } +}; + +var PHPCIConfirmDialog = Class.extend({ + /** + * @private + * @var {bool} Determines whether the dialog has been confirmed + */ + confirmed: false, + + /** + * @param {PHPCIConfirmDialogOptions} options + */ + init: function (options) { + + options = options ? $.extend(PHPCIConfirmDialogOptions, options) : PHPCIConfirmDialogOptions; + + if (!$('#confirm-dialog').length) { + /* + Add the dialog html to a page on first use. No need to have it there before first use. + */ + $('body').append( + '' + ); + } + + /* + Define dialog controls + */ + this.$dialog = $('#confirm-dialog'); + this.$cancelBtn = this.$dialog.find('div.modal-footer button.btn-default'); + this.$confirmBtn = this.$dialog.find('div.modal-footer button.btn-primary'); + this.$title = this.$dialog.find('h4.modal-title'); + this.$body = this.$dialog.find('div.modal-body'); + + /* + Initialize its values + */ + this.$title.html(options.title ? options.title : PHPCIConfirmDialogOptions.title); + this.$body.html(options.message ? options.message : PHPCIConfirmDialogOptions.message); + this.$confirmBtn.html( + options.confirmBtnCaption ? options.confirmBtnCaption : PHPCIConfirmDialogOptions.confirmBtnCaption + ); + + this.$cancelBtn.html( + options.cancelBtnCaption ? options.cancelBtnCaption : PHPCIConfirmDialogOptions.cancelBtnCaption + ); + + /* + Events + */ + this.confirmBtnClick = options.confirmed; + + /* + Re-bind handlers + */ + this.$confirmBtn.unbind('click'); + this.$confirmBtn.click(this.onConfirm.bind(this)); + + this.$confirmBtn.unbind('hidden.bs.modal'); + + /* + Bind the close event of the dialog to the set of onClose* methods + */ + this.$dialog.on('hidden.bs.modal', function () {this.onClose()}.bind(this)); + this.$dialog.on('hidden.bs.modal', function () { + if (this.confirmed) { + this.onCloseConfirmed(); + } else { + this.onCloseCanceled(); + } + }.bind(this)); + + /* + Restore state if was changed previously + */ + this.$cancelBtn.show(); + this.$confirmBtn.show(); + this.confirmed = false; + }, + + /** + * Show dialog + */ + show: function () { + this.$dialog.modal('show'); + }, + + /** + * Hide dialog + */ + close: function () { + this.$dialog.modal('hide'); + }, + + onConfirm: function (e) { + this.confirmed = true; + $(this).attr('disabled', 'disabled'); + this.confirmBtnClick(e); + }, + + /** + * Called only when confirmed dialog was closed + */ + onCloseConfirmed: function () {}, + + /** + * Called only when canceled dialog was closed + */ + onCloseCanceled: function () {}, + + /** + * Called always when the dialog was closed + */ + onClose: function () {}, + + showStatusMessage: function (message, closeTimeout) { + this.$confirmBtn.hide(); + this.$cancelBtn.html('Close'); + + /* + Status message + */ + this.$body.html(message); + + if (closeTimeout) { + window.setTimeout(function () { + /* + Hide the dialog + */ + this.close(); + }.bind(this), closeTimeout); + } + } +}); + /** * Used to initialise the project form: */