mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-23 19:26:33 +00:00
fix(GUI): backdrop click error on modals (#601)
When the user clicks on the backdrop of a modal, the modal promise gets rejected, therefore triggering our application error handler. UI Bootstrap provides a way to disable the backdrop completely, but doesn't provide a way to allow a backdrop click to simply close the modal rather than rejecting it, as if an issue happened. To mitigate this issue, and still preserve the backdrop functionality, we created `ModalService`, which abstracts the messy details of calling `$uibModal`, and has custom logic to ignore "backdrop click" errors. Change-Type: patch Changelog-Entry: Fix "backdrop click" uncaught errors on modals. Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
parent
2d1b2ccf6e
commit
d72364115d
@ -23,7 +23,7 @@
|
|||||||
const angular = require('angular');
|
const angular = require('angular');
|
||||||
const MODULE_NAME = 'Etcher.Components.DriveSelector';
|
const MODULE_NAME = 'Etcher.Components.DriveSelector';
|
||||||
const DriveSelector = angular.module(MODULE_NAME, [
|
const DriveSelector = angular.module(MODULE_NAME, [
|
||||||
require('angular-ui-bootstrap'),
|
require('../modal/modal'),
|
||||||
require('../../models/drives'),
|
require('../../models/drives'),
|
||||||
require('../../models/selection-state'),
|
require('../../models/selection-state'),
|
||||||
require('../../utils/byte-size/byte-size')
|
require('../../utils/byte-size/byte-size')
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = function($uibModal, $q) {
|
module.exports = function(ModalService, $q) {
|
||||||
|
|
||||||
let modal = null;
|
let modal = null;
|
||||||
|
|
||||||
@ -34,11 +34,9 @@ module.exports = function($uibModal, $q) {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
this.open = () => {
|
this.open = () => {
|
||||||
modal = $uibModal.open({
|
modal = ModalService.open({
|
||||||
animation: true,
|
template: './components/drive-selector/templates/drive-selector-modal.tpl.html',
|
||||||
templateUrl: './components/drive-selector/templates/drive-selector-modal.tpl.html',
|
controller: 'DriveSelectorController as modal'
|
||||||
controller: 'DriveSelectorController as modal',
|
|
||||||
size: 'sm'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return modal.result;
|
return modal.result;
|
||||||
|
31
lib/gui/components/modal/modal.js
Normal file
31
lib/gui/components/modal/modal.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 Resin.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module Etcher.Components.Modal
|
||||||
|
*/
|
||||||
|
|
||||||
|
const angular = require('angular');
|
||||||
|
const MODULE_NAME = 'Etcher.Components.Modal';
|
||||||
|
const Modal = angular.module(MODULE_NAME, [
|
||||||
|
require('angular-ui-bootstrap')
|
||||||
|
]);
|
||||||
|
|
||||||
|
Modal.service('ModalService', require('./services/modal'));
|
||||||
|
|
||||||
|
module.exports = MODULE_NAME;
|
74
lib/gui/components/modal/services/modal.js
Normal file
74
lib/gui/components/modal/services/modal.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 Resin.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = function($uibModal, $q) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Open a modal
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @param {Object} options - options
|
||||||
|
* @param {String} options.template - template path
|
||||||
|
* @param {String} options.controller - controller
|
||||||
|
* @param {String} [options.size='sm'] - modal size
|
||||||
|
* @param {Object} options.resolve - modal resolves
|
||||||
|
* @returns {Object} modal
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ModalService.open({
|
||||||
|
* template: './path/to/modal.tpl.html',
|
||||||
|
* controller: 'DriveSelectorController as modal',
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
this.open = (options = {}) => {
|
||||||
|
|
||||||
|
_.defaults(options, {
|
||||||
|
size: 'sm'
|
||||||
|
});
|
||||||
|
|
||||||
|
const modal = $uibModal.open({
|
||||||
|
animation: true,
|
||||||
|
templateUrl: options.template,
|
||||||
|
controller: options.controller,
|
||||||
|
size: options.size,
|
||||||
|
resolve: options.resolve
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
close: modal.close,
|
||||||
|
result: $q((resolve, reject) => {
|
||||||
|
modal.result
|
||||||
|
.then(resolve)
|
||||||
|
.catch((error) => {
|
||||||
|
|
||||||
|
// For some annoying reason, UI Bootstrap Modal rejects
|
||||||
|
// the result reason if the user clicks on the backdrop
|
||||||
|
// (e.g: the area surrounding the modal).
|
||||||
|
if (error !== 'backdrop click') {
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
})
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
module.exports = function($uibModal) {
|
module.exports = function(ModalService) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Open the tooltip modal
|
* @summary Open the tooltip modal
|
||||||
@ -37,9 +37,8 @@ module.exports = function($uibModal) {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
this.show = (options) => {
|
this.show = (options) => {
|
||||||
return $uibModal.open({
|
return ModalService.open({
|
||||||
animation: true,
|
template: './components/tooltip-modal/templates/tooltip-modal.tpl.html',
|
||||||
templateUrl: './components/tooltip-modal/templates/tooltip-modal.tpl.html',
|
|
||||||
controller: 'TooltipModalController as modal',
|
controller: 'TooltipModalController as modal',
|
||||||
size: 'tooltip-modal',
|
size: 'tooltip-modal',
|
||||||
resolve: {
|
resolve: {
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
const angular = require('angular');
|
const angular = require('angular');
|
||||||
const MODULE_NAME = 'Etcher.Components.TooltipModal';
|
const MODULE_NAME = 'Etcher.Components.TooltipModal';
|
||||||
const TooltipModal = angular.module(MODULE_NAME, [
|
const TooltipModal = angular.module(MODULE_NAME, [
|
||||||
require('angular-ui-bootstrap')
|
require('../modal/modal')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
TooltipModal.controller('TooltipModalController', require('./controllers/tooltip-modal'));
|
TooltipModal.controller('TooltipModalController', require('./controllers/tooltip-modal'));
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const etcherLatestVersion = require('etcher-latest-version');
|
const etcherLatestVersion = require('etcher-latest-version');
|
||||||
|
|
||||||
module.exports = function($uibModal, $http, $q, UPDATE_NOTIFIER_SLEEP_TIME, ManifestBindService, SettingsModel) {
|
module.exports = function($http, $q, ModalService, UPDATE_NOTIFIER_SLEEP_TIME, ManifestBindService, SettingsModel) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Get the latest available Etcher version
|
* @summary Get the latest available Etcher version
|
||||||
@ -111,9 +111,8 @@ module.exports = function($uibModal, $http, $q, UPDATE_NOTIFIER_SLEEP_TIME, Mani
|
|||||||
* UpdateNotifierService.notify();
|
* UpdateNotifierService.notify();
|
||||||
*/
|
*/
|
||||||
this.notify = () => {
|
this.notify = () => {
|
||||||
return $uibModal.open({
|
return ModalService.open({
|
||||||
animation: true,
|
template: './components/update-notifier/templates/update-notifier-modal.tpl.html',
|
||||||
templateUrl: './components/update-notifier/templates/update-notifier-modal.tpl.html',
|
|
||||||
controller: 'UpdateNotifierController as modal',
|
controller: 'UpdateNotifierController as modal',
|
||||||
size: 'update-notifier'
|
size: 'update-notifier'
|
||||||
}).result;
|
}).result;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
const angular = require('angular');
|
const angular = require('angular');
|
||||||
const MODULE_NAME = 'Etcher.Components.UpdateNotifier';
|
const MODULE_NAME = 'Etcher.Components.UpdateNotifier';
|
||||||
const UpdateNotifier = angular.module(MODULE_NAME, [
|
const UpdateNotifier = angular.module(MODULE_NAME, [
|
||||||
require('angular-ui-bootstrap'),
|
require('../modal/modal'),
|
||||||
require('../../models/settings'),
|
require('../../models/settings'),
|
||||||
require('../../utils/manifest-bind/manifest-bind'),
|
require('../../utils/manifest-bind/manifest-bind'),
|
||||||
require('../../os/open-external/open-external')
|
require('../../os/open-external/open-external')
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
module.exports = function($uibModal, SettingsModel) {
|
module.exports = function(ModalService, SettingsModel) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Refresh current settings
|
* @summary Refresh current settings
|
||||||
@ -62,9 +62,8 @@ module.exports = function($uibModal, SettingsModel) {
|
|||||||
return this.refreshSettings();
|
return this.refreshSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
$uibModal.open({
|
ModalService.open({
|
||||||
animation: true,
|
template: './pages/settings/templates/settings-dangerous-modal.tpl.html',
|
||||||
templateUrl: './pages/settings/templates/settings-dangerous-modal.tpl.html',
|
|
||||||
controller: 'SettingsDangerousModalController as modal',
|
controller: 'SettingsDangerousModalController as modal',
|
||||||
size: 'settings-dangerous-modal',
|
size: 'settings-dangerous-modal',
|
||||||
resolve: {
|
resolve: {
|
||||||
|
@ -24,6 +24,7 @@ const angular = require('angular');
|
|||||||
const MODULE_NAME = 'Etcher.Pages.Settings';
|
const MODULE_NAME = 'Etcher.Pages.Settings';
|
||||||
const SettingsPage = angular.module(MODULE_NAME, [
|
const SettingsPage = angular.module(MODULE_NAME, [
|
||||||
require('angular-ui-router'),
|
require('angular-ui-router'),
|
||||||
|
require('../../components/modal/modal'),
|
||||||
require('../../models/settings')
|
require('../../models/settings')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user