[BUGFIX] Abort slug proposal request on rapid typing 08/59808/2
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Tue, 26 Feb 2019 15:07:05 +0000 (16:07 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Fri, 1 Mar 2019 13:33:15 +0000 (14:33 +0100)
If an editor enters a manual slug into the slug field, an AJAX request
per keystroke is sent. The patch now aborts requests in case the input
changes while the previous request has not finished yet.

Resolves: #87796
Releases: master, 9.5
Change-Id: Ib61ea0197bcf7f2a85d27c89e08e8fa448fea224
Reviewed-on: https://review.typo3.org/c/59808
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Jürgen Venne <venne@schaffrath-digital.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Jürgen Venne <venne@schaffrath-digital.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SlugElement.ts
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SlugElement.js

index 0908467..d055606 100644 (file)
@@ -65,6 +65,7 @@ class SlugElement {
   private $readOnlyField: JQuery = null;
   private $inputField: JQuery = null;
   private $hiddenField: JQuery = null;
+  private xhr: JQueryXHR = null;
   private readonly fieldsToListenOn: { [key: string]: string } = {};
 
   constructor(selector: string, options: FieldOptions) {
@@ -148,7 +149,10 @@ class SlugElement {
     } else {
       input.manual = this.$inputField.val();
     }
-    $.post(
+    if (this.xhr !== null && this.xhr.readyState !== 4) {
+      this.xhr.abort();
+    }
+    this.xhr = $.post(
       TYPO3.settings.ajaxUrls.record_slug_suggest,
       {
         values: input,
index b58cf7a..8d8e77b 100644 (file)
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","jquery"],function(e,l,n){"use strict";var i,t,d,s;return(t=i||(i={})).toggleButton=".t3js-form-field-slug-toggle",t.recreateButton=".t3js-form-field-slug-recreate",t.inputField=".t3js-form-field-slug-input",t.readOnlyField=".t3js-form-field-slug-readonly",t.hiddenField=".t3js-form-field-slug-hidden",(s=d||(d={})).AUTO="auto",s.RECREATE="recreate",s.MANUAL="manual",function(){function e(e,l){var t=this;this.options=null,this.$fullElement=null,this.manuallyChanged=!1,this.$readOnlyField=null,this.$inputField=null,this.$hiddenField=null,this.fieldsToListenOn={},this.options=l,this.fieldsToListenOn=this.options.listenerFieldNames||{},n(function(){t.$fullElement=n(e),t.$inputField=t.$fullElement.find(i.inputField),t.$readOnlyField=t.$fullElement.find(i.readOnlyField),t.$hiddenField=t.$fullElement.find(i.hiddenField),t.registerEvents()})}return e.prototype.registerEvents=function(){var e=this,l=Object.keys(this.getAvailableFieldsForProposalGeneration()).map(function(l){return e.fieldsToListenOn[l]});l.length>0?("new"===this.options.command&&n(this.$fullElement).on("keyup",l.join(","),function(){e.manuallyChanged||e.sendSlugProposal(d.AUTO)}),n(this.$fullElement).on("click",i.recreateButton,function(l){l.preventDefault(),e.$readOnlyField.hasClass("hidden")&&(e.$readOnlyField.toggleClass("hidden",!1),e.$inputField.toggleClass("hidden",!0)),e.sendSlugProposal(d.RECREATE)})):n(this.$fullElement).find(i.recreateButton).addClass("disabled").prop("disabled",!0),n(this.$inputField).on("keyup",function(){e.manuallyChanged=!0,e.sendSlugProposal(d.MANUAL)}),n(this.$fullElement).on("click",i.toggleButton,function(l){l.preventDefault();var n=e.$readOnlyField.hasClass("hidden");e.$readOnlyField.toggleClass("hidden",!n),e.$inputField.toggleClass("hidden",n),n?(e.manuallyChanged=!1,e.$hiddenField.val(e.$readOnlyField.val()),e.$fullElement.find(".t3js-form-proposal-accepted").addClass("hidden"),e.$fullElement.find(".t3js-form-proposal-different").addClass("hidden")):e.$hiddenField.val(e.$inputField.val())})},e.prototype.sendSlugProposal=function(e){var l=this,i={};e===d.AUTO||e===d.RECREATE?n.each(this.getAvailableFieldsForProposalGeneration(),function(e,l){i[e]=n('[data-formengine-input-name="'+l+'"]').val()}):i.manual=this.$inputField.val(),n.post(TYPO3.settings.ajaxUrls.record_slug_suggest,{values:i,mode:e,tableName:this.options.tableName,pageId:this.options.pageId,parentPageId:this.options.parentPageId,recordId:this.options.recordId,language:this.options.language,fieldName:this.options.fieldName,command:this.options.command,signature:this.options.signature},function(n){n.hasConflicts?(l.$fullElement.find(".t3js-form-proposal-accepted").addClass("hidden"),l.$fullElement.find(".t3js-form-proposal-different").removeClass("hidden").find("span").text(n.proposal)):(l.$fullElement.find(".t3js-form-proposal-accepted").removeClass("hidden").find("span").text(n.proposal),l.$fullElement.find(".t3js-form-proposal-different").addClass("hidden")),l.$hiddenField.val()!==n.proposal&&l.$fullElement.find("input").trigger("change"),e===d.AUTO||e===d.RECREATE?(l.$readOnlyField.val(n.proposal),l.$hiddenField.val(n.proposal)):l.$hiddenField.val(n.proposal)},"json")},e.prototype.getAvailableFieldsForProposalGeneration=function(){var e={};return n.each(this.fieldsToListenOn,function(l,i){n('[data-formengine-input-name="'+i+'"]').length>0&&(e[l]=i)}),e},e}()});
\ No newline at end of file
+define(["require","exports","jquery"],function(e,l,n){"use strict";var t,i,d,s;return(i=t||(t={})).toggleButton=".t3js-form-field-slug-toggle",i.recreateButton=".t3js-form-field-slug-recreate",i.inputField=".t3js-form-field-slug-input",i.readOnlyField=".t3js-form-field-slug-readonly",i.hiddenField=".t3js-form-field-slug-hidden",(s=d||(d={})).AUTO="auto",s.RECREATE="recreate",s.MANUAL="manual",function(){function e(e,l){var i=this;this.options=null,this.$fullElement=null,this.manuallyChanged=!1,this.$readOnlyField=null,this.$inputField=null,this.$hiddenField=null,this.xhr=null,this.fieldsToListenOn={},this.options=l,this.fieldsToListenOn=this.options.listenerFieldNames||{},n(function(){i.$fullElement=n(e),i.$inputField=i.$fullElement.find(t.inputField),i.$readOnlyField=i.$fullElement.find(t.readOnlyField),i.$hiddenField=i.$fullElement.find(t.hiddenField),i.registerEvents()})}return e.prototype.registerEvents=function(){var e=this,l=Object.keys(this.getAvailableFieldsForProposalGeneration()).map(function(l){return e.fieldsToListenOn[l]});l.length>0?("new"===this.options.command&&n(this.$fullElement).on("keyup",l.join(","),function(){e.manuallyChanged||e.sendSlugProposal(d.AUTO)}),n(this.$fullElement).on("click",t.recreateButton,function(l){l.preventDefault(),e.$readOnlyField.hasClass("hidden")&&(e.$readOnlyField.toggleClass("hidden",!1),e.$inputField.toggleClass("hidden",!0)),e.sendSlugProposal(d.RECREATE)})):n(this.$fullElement).find(t.recreateButton).addClass("disabled").prop("disabled",!0),n(this.$inputField).on("keyup",function(){e.manuallyChanged=!0,e.sendSlugProposal(d.MANUAL)}),n(this.$fullElement).on("click",t.toggleButton,function(l){l.preventDefault();var n=e.$readOnlyField.hasClass("hidden");e.$readOnlyField.toggleClass("hidden",!n),e.$inputField.toggleClass("hidden",n),n?(e.manuallyChanged=!1,e.$hiddenField.val(e.$readOnlyField.val()),e.$fullElement.find(".t3js-form-proposal-accepted").addClass("hidden"),e.$fullElement.find(".t3js-form-proposal-different").addClass("hidden")):e.$hiddenField.val(e.$inputField.val())})},e.prototype.sendSlugProposal=function(e){var l=this,t={};e===d.AUTO||e===d.RECREATE?n.each(this.getAvailableFieldsForProposalGeneration(),function(e,l){t[e]=n('[data-formengine-input-name="'+l+'"]').val()}):t.manual=this.$inputField.val(),null!==this.xhr&&4!==this.xhr.readyState&&this.xhr.abort(),this.xhr=n.post(TYPO3.settings.ajaxUrls.record_slug_suggest,{values:t,mode:e,tableName:this.options.tableName,pageId:this.options.pageId,parentPageId:this.options.parentPageId,recordId:this.options.recordId,language:this.options.language,fieldName:this.options.fieldName,command:this.options.command,signature:this.options.signature},function(n){n.hasConflicts?(l.$fullElement.find(".t3js-form-proposal-accepted").addClass("hidden"),l.$fullElement.find(".t3js-form-proposal-different").removeClass("hidden").find("span").text(n.proposal)):(l.$fullElement.find(".t3js-form-proposal-accepted").removeClass("hidden").find("span").text(n.proposal),l.$fullElement.find(".t3js-form-proposal-different").addClass("hidden")),l.$hiddenField.val()!==n.proposal&&l.$fullElement.find("input").trigger("change"),e===d.AUTO||e===d.RECREATE?(l.$readOnlyField.val(n.proposal),l.$hiddenField.val(n.proposal)):l.$hiddenField.val(n.proposal)},"json")},e.prototype.getAvailableFieldsForProposalGeneration=function(){var e={};return n.each(this.fieldsToListenOn,function(l,t){n('[data-formengine-input-name="'+t+'"]').length>0&&(e[l]=t)}),e},e}()});
\ No newline at end of file