From e247042cb8b8d0d6345af036605a1f7b33b2e9cd Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Tue, 14 Jul 2020 16:58:18 +0800 Subject: [PATCH] Reveal sensitive field if part of an AJAX request The sensitive field currently does not work with AJAX requests correctly if it is unrevealed - it sends the hidden placeholder instead of the real value with AJAX requests. This change allows the sensitive field to intercept AJAX requests on elements within the same form, and reveals the field. Once revealed, it then replays the AJAX request on the original element, which should then pick up the sensitive field's true value in the form data. --- .../sensitive/assets/js/sensitive.js | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/modules/backend/formwidgets/sensitive/assets/js/sensitive.js b/modules/backend/formwidgets/sensitive/assets/js/sensitive.js index 69251304cd..00a4a6556f 100644 --- a/modules/backend/formwidgets/sensitive/assets/js/sensitive.js +++ b/modules/backend/formwidgets/sensitive/assets/js/sensitive.js @@ -16,6 +16,7 @@ this.options = options this.clean = Boolean(this.$el.data('clean')) this.hidden = true + this.triggerElement = null this.$input = this.$el.find('[data-input]').first() this.$toggle = this.$el.find('[data-toggle]').first() @@ -50,6 +51,9 @@ if (this.$copy.length) { this.$copy.on('click', this.proxy(this.onCopy)) } + + $(window).on('ajaxSetup', this.proxy(this.onAjaxSetup)) + $(window).on('oc.beforeRequest', this.proxy(this.onBeforeRequest)) } Sensitive.prototype.dispose = function () { @@ -64,6 +68,9 @@ this.$copy.off('click', this.proxy(this.onCopy)) } + $(window).off('ajaxSetup', this.proxy(this.onAjaxSetup)) + $(window).off('oc.beforeRequest', this.proxy(this.onBeforeRequest)) + this.$input = this.$toggle = this.$icon = this.$loader = null this.$el = null @@ -126,6 +133,54 @@ } } + Sensitive.prototype.onAjaxSetup = function (event, context) { + // Don't track AJAX request if it is for revealing the value + if (context.handler === this.options.eventHandler) { + return + } + // Don't track AJAX requests if this field has been revealed + if (!this.clean) { + return + } + // Only track trigger elements if the AJAX request is for an element in the same form as this input + if (!this.$el.closest('form').is($(event.target).closest('form'))) { + return + } + + this.triggerElement = event.target + } + + Sensitive.prototype.onBeforeRequest = function (event, context) { + var that = this, + deferred = $.Deferred() + + // Don't track AJAX request if it is for revealing the value + if (context.handler === this.options.eventHandler) { + return + } + // Don't track AJAX requests if this field has been revealed + if (!this.clean) { + return + } + // Only defer AJAX requests for elements in the same form as this input + if (!this.triggerElement || !this.$el.closest('form').is($(this.triggerElement).closest('form'))) { + return + } + + // Prevent the initial AJAX request and re-call it after revealing the value + event.preventDefault() + + deferred.then(function () { + if (!that.hidden) { + that.toggleVisibility() + } + + $(that.triggerElement).request() + }) + + this.reveal(deferred) + } + Sensitive.prototype.toggleVisibility = function() { if (this.hidden) { this.$input.attr('type', 'text')