From 7e488ad13450af51540e731f7323df8818040a21 Mon Sep 17 00:00:00 2001 From: Dominik Klein Date: Fri, 23 Jul 2021 21:44:18 +0000 Subject: [PATCH] Fixes #2886 - Text Editor deletes text unrecoverably if quicktext was canceled with Ctrl+Backspace. --- Gemfile | 4 ++ Gemfile.lock | 2 + .../app/lib/base/jquery.textmodule.js | 47 +++++++++++++++---- spec/system/examples/text_modules_examples.rb | 21 +++++++++ 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 05c4b6059..c092c4f27 100644 --- a/Gemfile +++ b/Gemfile @@ -223,6 +223,10 @@ group :development, :test do # Slack helper for testing gem 'slack-ruby-client', require: false + + # Can be used to detect for example the current + # operating system in tests, to handle things differently. + gem 'os' end # Want to extend Zammad with additional gems? diff --git a/Gemfile.lock b/Gemfile.lock index 38a5415e2..b99b7184a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -394,6 +394,7 @@ GEM omniauth (~> 1.5) omniauth-oauth2 (>= 1.4.0) openssl (2.2.0) + os (1.1.1) overcommit (0.58.0) childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) @@ -710,6 +711,7 @@ DEPENDENCIES omniauth-twitter omniauth-weibo-oauth2 openssl + os overcommit pg (= 0.21.0) pry-rails diff --git a/app/assets/javascripts/app/lib/base/jquery.textmodule.js b/app/assets/javascripts/app/lib/base/jquery.textmodule.js index c73905761..04bcc1637 100644 --- a/app/assets/javascripts/app/lib/base/jquery.textmodule.js +++ b/app/assets/javascripts/app/lib/base/jquery.textmodule.js @@ -27,6 +27,7 @@ this.collection = [] this.active = false this.buffer = '' + this.oldElementText = '' // check if ce exists if ( $.data(element, 'plugin_ce') ) { @@ -55,10 +56,11 @@ } Plugin.prototype.onKeydown = function (e) { - //console.log("onKeydown", this.isActive()) + // Saves the old element text for some special situations. + this.oldElementText = this.$element.text() + // navigate through item if (this.isActive()) { - // esc if (e.keyCode === 27) { e.preventDefault() @@ -133,7 +135,7 @@ // reduce buffer, in case close it // backspace - if (e.keyCode === 8 && this.buffer) { + if (e.keyCode === 8 && !( e.ctrlKey || e.metaKey ) && this.buffer) { var trigger = this.findTrigger(this.buffer) // backspace + buffer === :: -> close textmodule @@ -162,19 +164,47 @@ Plugin.prototype.onKeypress = function (e) { this.log('BUFF', this.buffer, e.keyCode, String.fromCharCode(e.which)) - // gets the character and keycode from event // this event does not have keyCode and which value set // so we take char and set those values to not break the flow // if originalEvent.data is null that means a non char key is pressed like delete, space if(e.originalEvent && e.originalEvent.data) { - var char = e.originalEvent.data; - var keyCode = char.charCodeAt(0); - e.keyCode = e.which = keyCode; + var char = e.originalEvent.data + var keyCode = char.charCodeAt(0) + e.keyCode = e.which = keyCode } // ignore invalid key codes if search is opened (issue #3637) - if (this.isActive() && e.keyCode === undefined) return + if (this.isActive() && e.keyCode === undefined) { + + // Check if the trigger still exists in the new text, after a special key was pressed, otherwise + // close the collection. + var indexOfBuffer = this.oldElementText.indexOf(this.buffer) + var trigger = this.findTrigger(this.buffer) + + if (this.buffer && indexOfBuffer !== -1 && trigger) { + foundCurrentBuffer = this.$element.text().substr(indexOfBuffer, this.buffer.length) + + if ( this.$element.text().substr(indexOfBuffer, trigger.trigger.length) !== trigger.trigger ) { + this.close(true) + } + + // Check on how many characters the trigger needs to be reduced, in the case it's not the same. + else if ( foundCurrentBuffer !== this.buffer ) { + var existingLength = 0 + for (var i = 0; i < this.buffer.length; i++) { + if (this.buffer.charAt(i) !== foundCurrentBuffer.charAt(i)) { + existingLength = i + break + } + } + + this.buffer = this.buffer.substr(0, existingLength) + this.result(trigger) + } + } + return + } // skip on shift + arrow_keys if (_.contains([16, 37, 38, 39, 40], e.keyCode)) return @@ -186,7 +216,6 @@ } var newChar = String.fromCharCode(e.which) - // observe other keys if (this.hasAvailableTriggers(this.buffer)) { if(this.hasAvailableTriggers(this.buffer + newChar)) { diff --git a/spec/system/examples/text_modules_examples.rb b/spec/system/examples/text_modules_examples.rb index 3613b7446..3b79e89b8 100644 --- a/spec/system/examples/text_modules_examples.rb +++ b/spec/system/examples/text_modules_examples.rb @@ -19,6 +19,27 @@ RSpec.shared_examples 'text modules' do |path:| end end + it 'does not break after usage of Ctrl/Command+Backspace' do + visit path + within(:active_content) do + find(:richtext).send_keys(':') + find(:richtext).send_keys(':') + find(:richtext).send_keys('bur') + + # The click is needed to get the focus back to the field for chrome. + find(:richtext).click + if OS.mac? + find(:richtext).send_keys(%i[command backspace]) + else + find(:richtext).send_keys(%i[control backspace]) + end + + find(:richtext).send_keys('Some other text') + find(:richtext).send_keys(:enter) + expect(find(:richtext)).to have_text 'Some other text' + end + end + it 'does not show when send :enter:' do visit path within(:active_content) do