diff options
4 files changed, 66 insertions, 6 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css index 0d3570a21fd..96eedfcb7a9 100644 --- a/bitbake/lib/toaster/toastergui/static/css/default.css +++ b/bitbake/lib/toaster/toastergui/static/css/default.css @@ -249,6 +249,18 @@ code { color: #333; background-color: transparent; } /* Style the special no results message in the custom image details page */ [id^="no-results-special-"] > .alert-warning > ol { margin-top: 10px; } +/* style the loading spinner in the new custom image dialog */ +#create-new-custom-image-btn [data-role="loading-state"] { + padding-left: 16px; +} + +/* icon has to be absolutely positioned, otherwise the spin animation doesn't work */ +#create-new-custom-image-btn [data-role="loading-state"] .icon-spinner { + position: absolute; + left: 26px; + bottom: 26px; +} + /* Style the content of modal dialogs */ .modal-footer { text-align: left; } .date-filter-controls { margin-top: 10px; } diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index eafe70ddee4..b8bf1a2a3fc 100644 --- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js +++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js @@ -421,8 +421,23 @@ var libtoaster = (function () { }); } + // if true, the loading spinner for Ajax requests will be displayed + // if requests take more than 1200ms + var ajaxLoadingTimerEnabled = true; + + // turn on the page-level loading spinner for Ajax requests + function _enableAjaxLoadingTimer() { + ajaxLoadingTimerEnabled = true; + } + + // turn off the page-level loading spinner for Ajax requests + function _disableAjaxLoadingTimer() { + ajaxLoadingTimerEnabled = false; + } return { + enableAjaxLoadingTimer: _enableAjaxLoadingTimer, + disableAjaxLoadingTimer: _disableAjaxLoadingTimer, reload_params : reload_params, startABuild : _startABuild, cancelABuild : _cancelABuild, @@ -469,7 +484,6 @@ function reload_params(params) { window.location.href = url+"?"+callparams.join('&'); } - /* Things that happen for all pages */ $(document).ready(function() { @@ -628,7 +642,9 @@ $(document).ready(function() { window.clearTimeout(ajaxLoadingTimer); ajaxLoadingTimer = window.setTimeout(function() { - $("#loading-notification").fadeIn(); + if (libtoaster.ajaxLoadingTimerEnabled) { + $("#loading-notification").fadeIn(); + } }, 1200); }); diff --git a/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js b/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js index 8356c02b5a8..dace8e3258d 100644 --- a/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js +++ b/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js @@ -25,7 +25,11 @@ function newCustomImageModalInit(){ var duplicateNameMsg = "An image with this name already exists. Image names must be unique."; var duplicateImageInProjectMsg = "An image with this name already exists in this project." var invalidBaseRecipeIdMsg = "Please select an image to customise."; - + + // set button to "submit" state and enable text entry so user can + // enter the custom recipe name + showSubmitState(); + /* capture clicks on radio buttons inside the modal; when one is selected, * set the recipe on the modal */ @@ -40,6 +44,9 @@ function newCustomImageModalInit(){ }); newCustomImgBtn.click(function(e){ + // disable the button and text entry + showLoadingState(); + e.preventDefault(); var baseRecipeId = imgCustomModal.data('recipe'); @@ -69,12 +76,33 @@ function newCustomImageModalInit(){ } } else { imgCustomModal.modal('hide'); + imgCustomModal.one('hidden.bs.modal', showSubmitState); window.location.replace(ret.url + '?notify=new'); } }); } }); + // enable text entry, show "Create image" button text + function showSubmitState() { + libtoaster.enableAjaxLoadingTimer(); + newCustomImgBtn.find('[data-role="loading-state"]').hide(); + newCustomImgBtn.find('[data-role="submit-state"]').show(); + newCustomImgBtn.removeAttr('disabled'); + nameInput.removeAttr('disabled'); + } + + // disable text entry, show "Creating image..." button text; + // we also disabled the page-level ajax loading spinner while this spinner + // is active + function showLoadingState() { + libtoaster.disableAjaxLoadingTimer(); + newCustomImgBtn.find('[data-role="submit-state"]').hide(); + newCustomImgBtn.find('[data-role="loading-state"]').show(); + newCustomImgBtn.attr('disabled', 'disabled'); + nameInput.attr('disabled', 'disabled'); + } + function showNameError(text){ invalidNameHelp.text(text); invalidNameHelp.show(); @@ -167,6 +195,5 @@ function newCustomImageModalSetRecipes(baseRecipes) { // show the radio button container imageSelector.show(); - - } + } } diff --git a/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html b/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html index 5caa68392c9..d448d3afc12 100644 --- a/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html +++ b/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html @@ -48,7 +48,12 @@ </div> <div class="modal-footer"> - <button id="create-new-custom-image-btn" class="btn btn-primary btn-lg" data-original-title="" title="" disabled>Create custom image</button> + <button id="create-new-custom-image-btn" class="btn btn-primary btn-large" disabled> + <span data-role="submit-state">Create custom image</span> + <span data-role="loading-state" style="display:none"> + <i class="fa-pulse icon-spinner"></i> Creating custom image... + </span> + </button> </div> </div> </div> |