Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,29 @@ public JsCode build() {
return new JsCode(
(withProgress ? """
if (action) {
// Avoid capturing of focus and restoration of focus after action completion with `withProgress` preAction.
// This allows "normal" functioning in cases where link was inserted into app that had focus on some element.
// By "normal" functioning we mean automatic focusing of affirmative button allowing to repeat the action on errors.
// It is of very little value to return focus to previously focused element.
// This is because mostly the link will be opened in new tab / window, and even otherwise the user would have to
// do the action of link pasting into address bar, which means they already lost context of previously focused item.
action.persistActiveElement = () => {};
action.restoreActiveElement = () => {};
// In case where { withProgress: true } option was used, override action completion logic to close the dialog.
const isActionInProgressChanged = action.isActionInProgressChanged.bind(action);
action.isActionInProgressChanged = (function (newValue, oldValue) {
isActionInProgressChanged(newValue, oldValue);
// If action progress has been stopped.
if (newValue === false && oldValue === true) {
self.closeConfirmationDialog();
self.confirmationDialog(dialog => dialog.enableActions(action));
}
}).bind(action);
action.isActionSuccessfulChanged = (newValue, oldValue) => {
// If action has become successful.
if (newValue && !oldValue) {
self.confirmationDialog(dialog => dialog.close());
}
};
}
""" : "") + """
return self.confirm('%s', [%s]%s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,19 @@ Polymer({
observer: 'isActionInProgressChanged'
},

/// Indicates whether the action's recent execution (if any) was successful.
///
/// In the beginning `isActionSuccessful` is false.
/// During action execution up until successful saving (including successful postActionSuccess without any exceptions) it is false.
/// After successful saving (including successful postActionSuccess without any exceptions) it is true.
/// It becomes false again after `isActionInProgress` becomes true.
///
isActionSuccessful: {
type: Boolean,
value: false,
observer: 'isActionSuccessfulChanged'
},

/**
* Indicates whether this action should be disabled.
*/
Expand Down Expand Up @@ -612,9 +625,11 @@ Polymer({
// One exception from that rule: embedded masters in master-with-master -- the flag is configured from MasterWithMasterBuilder API.
master.shouldRefreshParentCentreAfterSave = self.shouldRefreshParentCentreAfterSave;

const restoreStateAfterSave = function () {
const restoreStateAfterSave = function (actionSuccessful) {
if (!self.skipAutomaticActionCompletion) {
// action execution completes
// Mark action as successful if `actionSuccessful`.
self.isActionSuccessful = !!actionSuccessful || false;
// Action execution completes.
self.isActionInProgress = false;

if (master.noUI === true) {
Expand All @@ -624,8 +639,9 @@ Polymer({
};

master.postSaved = function (potentiallySavedOrNewEntity, newBindingEntity) {
const entitySavingSuccessful = potentiallySavedOrNewEntity && potentiallySavedOrNewEntity.isValidWithoutException();
try {
if (potentiallySavedOrNewEntity.isValidWithoutException()) {
if (entitySavingSuccessful) {
if (self.postActionSuccess) {
self.postActionSuccess(potentiallySavedOrNewEntity, self, master);
}
Expand All @@ -636,7 +652,9 @@ Polymer({
}
} catch (e) {
throw enhanceStateRestoration(e, () => {
restoreStateAfterSave();
// Even though `entitySavingSuccessful` may be true, we still consider `isActionSuccessful` false.
// This, for example will leave ConfirmationPreAction.*withProgress opened to be able to repeat the action.
restoreStateAfterSave(false);
master.restoreAfterSave();
});
} finally {
Expand All @@ -653,7 +671,7 @@ Polymer({
}
});
}
restoreStateAfterSave();
restoreStateAfterSave(entitySavingSuccessful);
};

master.postSavedError = function (errorResult) {
Expand Down Expand Up @@ -819,6 +837,11 @@ Polymer({
},

isActionInProgressChanged: function (newValue, oldValue) {
// If action is starting its progress then reset `isActionSuccessful` to `false` (i.e. it is not yet successfull).
if (newValue && !oldValue) {
this.isActionSuccessful = false;
}

if (this._startSpinnerTimer) {
clearTimeout(this._startSpinnerTimer);
}
Expand All @@ -830,6 +853,9 @@ Polymer({
}
},

isActionSuccessfulChanged: function (newValue, oldValue) {
},

_computeIsIconButton: function (uiRole) {
return uiRole === 'ICON';
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,14 @@ const TgEntityCentreTemplateBehaviorImpl = {
}
},

closeConfirmationDialog: function () {
if (!this.$.egi.isEditing()) {
return this._dom().closeConfirmationDialog();
confirmationDialog: function (action) {
if (!this.$.egi.isEditing() && this._dom() && this._dom().confirmationDialog) {
return this._dom().confirmationDialog(action);
}
},

confirm: function (message, buttons, options) {
if (!this.$.egi.isEditing()) {
if (!this.$.egi.isEditing() && this._dom() && this._dom()._confirmationDialog) {
return this._dom()._confirmationDialog().showConfirmationDialog(message, buttons, options);
}
return this._saveOrCancelPromise();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -841,12 +841,12 @@ Polymer({
}, 100);
},

closeConfirmationDialog: function () {
return this.$.confirmationDialog.close();
confirmationDialog: function (action) {
return action(this._confirmationDialog());
},

confirm: function (message, buttons, options) {
return this.$.confirmationDialog.showConfirmationDialog(message, buttons, options);
return this._confirmationDialog().showConfirmationDialog(message, buttons, options);
},

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export const TgConfirmationDialog = Polymer({
dialogModel.rejectDialog();
};

dialogModel._action = function (e) {
dialogModel._action = dialogModel._originalAction = function (e) {
const button = e.model.item;
if (button.confirm) {
// If confirmation dialog has `withProgress` option...
Expand Down Expand Up @@ -232,13 +232,38 @@ export const TgConfirmationDialog = Polymer({
});
},

/// Manually closes confirmation dialog.
/// Resets progress indicator (spinner) and other `withProgress` configuration.
/// Manually closes confirmation dialog (`withProgress` preAction dialogs).
///
close: function () {
dialogModel.$.confirmDialog.close();
},

/// Manually resets progress indicator (spinner) and other configuration (`withProgress` preAction dialogs).
///
/// @param action - optional `tg-ui-action` instance to execute on repeated YES / OK affirmative buttons tapping
///
enableActions: function (action) {
dialogModel.spinnerActive = false;
dialogModel.$.confirmDialog.noCancelOnEscKey = false;
// Automatic auto-focusing of button does not occur, because it only occurs when <paper-dialog> opens.
// Find the button manually and focus it to be able to use keyboard Enter key multiple times without tapping.
const firstAutoFocusButton = dialogModel.$.confirmDialog.querySelector('[autofocus]');
firstAutoFocusButton && firstAutoFocusButton.focus();

if (action) {
// Override YES / OK affirmative buttons tapping to actually perform an action.
// Previous preAction promise is already rejected and resolving it again in `_action` will not trigger `.then(...)` processing.
dialogModel._action = function (e) {
// Perform original logic including making buttons disabled and starting spinner.
dialogModel._originalAction(e);
const button = e.model.item;
// In case of affirmative button do the next logic after original promise resolution
// (see `tg-ui-action.postMasterInfoRetrieve`).
if (button.confirm) {
action.showDialog(action);
}
};
}
}

});
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,13 @@ Polymer({
console.log("The dialog is already opened and should be closed be being used again.");
if (customAction) {
customAction.restoreActionState();
// At this stage of action execution `isActionInProgress` is false.
// It gets assigned to true in `_onExecuted` below.
// However, some custom logic may be needed in `isActionInProgressChanged` when action execution failed
// due to other opened dialog present.
// Let's forcefully do that logic here. It is not harmfull because original logic only turns off spinner,
// which isn't active at a time of this error.
customAction.isActionInProgressChanged(false, true);
}
} else {
const self = this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1580,9 +1580,9 @@ const TgEntityMasterBehaviorImpl = {
}));
},

closeConfirmationDialog: function () {
if (this.$ && this.$.masterDom && this.$.masterDom.closeConfirmationDialog) {
return this.$.masterDom.closeConfirmationDialog();
confirmationDialog: function (action) {
if (this.$ && this.$.masterDom && this.$.masterDom.confirmationDialog) {
return this.$.masterDom.confirmationDialog(action);
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ Polymer({
this.$.actionContainer.addEventListener('layout-finished', this._actionBarLayoutFinished);
},

closeConfirmationDialog: function () {
return this.$.confirmationDialog.close();
confirmationDialog: function (action) {
return action(this.$.confirmationDialog);
},

confirm: function (message, buttons, options) {
Expand Down